diff --git a/.gitignore b/.gitignore index 0030d75a8..f7849967c 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,4 @@ bundle/* *.user util/*.lib util/*.exp +submodules/CHKSUMS.tmp diff --git a/DEVEL/Developer.txt b/DEVEL/Developer.txt index 61ba15f94..c7d7683c9 100644 --- a/DEVEL/Developer.txt +++ b/DEVEL/Developer.txt @@ -65,10 +65,8 @@ A. If you have never set up git on this machine before: git config --global user.name "MY NAME" git config --global user.email USER@EXAMPLE.COM You probably want to set up a credential cache. - macOS (10 - 12): + macOS (10 or greater): git config --global credential.helper osxkeychain - Windows: - git config --global credential.helper store Linux: (This will vary by distribution.) cd /usr/share/doc/git/contrib/credentail/libsecret @@ -78,7 +76,13 @@ A. If you have never set up git on this machine before: OR sudo yum install git-credential-libsecret git config --global credential.helper /usr/libexec/git-core/git-credential-libsecret - + Windows: (The following three assume that Git for Windows is already installed on + the underlying Windows system https://git-scm.com/download/win): + git config --global credential.helper store + MSYS2 UCRT64 bash shell: + git config --global credential.helper "/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe" + Windows Subsystem for Linux 2 (WSL2) bash shell: + git config --global credential.helper "/mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe" B. Specify the prefix for variable substitution: (This assumes you are not a member of DevTeam or any variant's development team. If you are, this may be wrong. Look for more specific documentation. diff --git a/dat/symbols b/dat/symbols index c979cf48b..af6c04ade 100644 --- a/dat/symbols +++ b/dat/symbols @@ -1,4 +1,4 @@ -# NetHack 3.7 symbols $NHDT-Date: 1709388512 2024/03/02 14:08:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.32 $ +# NetHack 3.7 symbols $NHDT-Date: 1725052751 2024/08/30 21:19:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.36 $ # Copyright (c) 2006 by Michael Allison # NetHack may be freely redistributed. See license for details. # @@ -627,10 +627,10 @@ start: curses S_bars: \xfc # meta-|, not-equals sign (was '#') S_tree: \xe7 # meta-g, plus or minus sign S_room: \xfe # meta-z, centered dot - S_engroom: \xee # epsilon - S_corr: \xe1 # meta-a, solid block - S_litcorr: \xe1 # meta-a, solid block - S_engrcorr: \xe1 # meta-a, solid block + # S_engroom: \xee # epsilon [\xee is actually cross wall] + S_corr: \xe1 # meta-a, checkerboard + S_litcorr: \xe1 # meta-a, checkerboard + S_engrcorr: \xe1 # meta-a, checkerboard S_ice: \xfe # meta-z, centered dot S_vodbridge: \xfe # meta-z, centered dot S_hodbridge: \xfe # meta-z, centered dot @@ -702,8 +702,8 @@ start: DECgraphics S_tlwall: \xf5 # meta-u, T left S_trwall: \xf4 # meta-t, T right S_ndoor: \xfe # meta-~, centered dot - S_vodoor: \xe1 # meta-a, solid block - S_hodoor: \xe1 # meta-a, solid block + S_vodoor: \xe1 # meta-a, checkerboard + S_hodoor: \xe1 # meta-a, checkerboard S_bars: \xfc # meta-|, not-equals (used to be pi) S_tree: \xe7 # meta-g, plus-or-minus S_room: \xfe # meta-~, centered dot diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 0d0232850..d55d3c6c4 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -46,7 +46,7 @@ .ds f0 \*(vr .ds f1 \" empty .\"DO NOT REMOVE NH_DATESUB .ds f2 DATE(%B %-d, %Y) -.ds f2 April 12, 2024 +.ds f2 August 11, 2024 . .\" A note on some special characters: .\" \(lq = left double quote @@ -455,69 +455,89 @@ option. The map (rest of the screen) .pg The rest of the screen is the map of the level as you have explored it -so far. Each symbol on the screen represents something. You can set -various graphics options to change some of the symbols the game uses; -otherwise, the game will use default symbols. Here is a list of what the -default symbols mean: -.lp "\\- and | " -The walls of a room, or an open door. Or a grave (|). -.lp . -The floor of a room, ice, or a doorless doorway. -.lp # -A corridor, or iron bars, or a tree, or possibly a kitchen sink (if -your dungeon has sinks), or a drawbridge. -.lp > +so far. +Each symbol on the screen represents something. +You can set various graphics options to change some of the symbols the +game uses; otherwise, the game will use default symbols. +Here is a list of what the default symbols mean: +.lp \f(CR\\-\fP +The horizontal or corner walls of a room, or an open east/west door. +.lp \f(CR|\fP +The vertical walls of a room, or an open north/south door, or a grave. +.lp \f(CR.\fP +The floor of a room, or ice, or a doorless doorway, or the span of an +open drawbridge. +.lp \f(CR#\fP +A corridor, or iron bars, or a tree, or the portcullis of a closed +drawbridge. +.lp "" +Note: engravings in corridors also appear as \f(CR#\fP but are shown in +a different color from normal corridor locations. +.lp \f(CR>\fP Stairs down: a way to the next level. -.lp < +.lp \f(CR<\fP Stairs up: a way to the previous level. -.lp + +.lp \f(CR+\fP A closed door, or a spellbook containing a spell you may be able to learn. -.lp @ -Your character or a human. -.lp $ +.lp \f(CR@\fP +Your character or a human or an elf. +.lp \f(CR$\fP A pile of gold. -.lp \(ha \" ^ +.lp \f(CR\(ha\fP \" \(ha == 'hat' == full sized caret ^ A trap (once you have detected it). -.lp ) +.lp \f(CR)\fP A weapon. -.lp [ +.lp \f(CR[\fP A suit or piece of armor. -.lp % +.lp \f(CR%\fP Something edible (not necessarily healthy). -.lp ? +.lp \f(CR?\fP A scroll. -.lp / +.lp \f(CR/\fP A wand. -.lp = +.lp \f(CR=\fP A ring. -.lp ! +.lp \f(CR!\fP A potion. -.lp ( +.lp \f(CR(\fP A useful item (pick-axe, key, lamp...). -.lp \(dq \" \(dq == double quote +.lp \f(CR\(dq\fP \" \(dq == double quote An amulet or a spider web. -.lp * +.lp \f(CR*\fP A gem or rock (possibly valuable, possibly worthless). -.lp \` -A boulder or statue. -.lp 0 +.lp \f(CR\`\fP +A boulder or statue or an engraving on the floor of a room. +.lp "" +Note: statues are displayed as if they were the monsters they depict +so won't appear as a \fIgrave accent\fP (aka \fIback-tick\fP). +.lp \f(CR0\fP An iron ball. -.lp _ +.lp \f(CR_\fP An altar, or an iron chain. -.lp { -A fountain. -.lp } -A pool of water or moat or a pool of lava. -.lp \\\\ +.lp \f(CR{\fP +A fountain or a sink. +.lp \f(CR}\fP +A pool of water or moat or a wall of water +or a pool of lava or a wall of lava. +.lp \f(CR\\\\\fP An opulent throne. -.lp "a-zA-Z and other symbols" +.lp "\f(CRa\fP-\f(CRz\fP\ \ \fIand\fP" +.lp "\f(CRA\fP-\f(CRH\fP\f(CRJ\fP-\f(CRZ\fP\ \ \fIand\fP" +.lp "\f(CR@&\(aq:;\fP" \" \(aq == apostrophe / single quote Letters and certain other symbols represent the various inhabitants -of the Mazes of Menace. Watch out, they can be nasty and vicious. +of the Mazes of Menace. +Watch out, they can be nasty and vicious. Sometimes, however, they can be helpful. -.lp I -This marks the last known location of an invisible or otherwise unseen -monster. Note that the monster could have moved. -The \(oqF\(cq and \(oqm\(cq commands may be useful here. +.lp \f(CRI\fP +Rather than a specific type of monster, this marks the last known +location of an invisible or otherwise unseen monster. +Note that the monster could have moved. +The \(oqs\(cq, \(oqF\(cq, and \(oqm\(cq commands may be useful here. +.lp \f(CR1\fP-\f(CR5\fP +The digits 1 through 5 may be displayed, marking unseen monsters sensed +via the \fIWarning\fP attribute. +Less dangerous monsters are indicated by lower values, more dangerous by +higher values. .pg You need not memorize all these symbols; you can ask the game what any symbol represents with the \(oq/\(cq command (see the next section for @@ -1676,6 +1696,9 @@ In normal play you can view the explored portion of the current level's map without monsters; without monsters and objects; or without monsters, objects, and traps. .lp "" +If there are visible clouds of gas in view, they are treated like traps +when deciding whether to show them or the floor underneath them. +.lp "" In explore mode, you can choose to view the full map rather than just its explored portion. In debug mode there are additional choices. @@ -3442,6 +3465,8 @@ Blind from birth. Deaf from birth. .PL Nudist Never wore any armor. +.PL Pauper +Started out with no possessions. .PL Ascended Delivered the Amulet to its final destination. .PE @@ -3478,7 +3503,7 @@ instrument played closely enough\(embut not too close!\(emto the Castle level's drawbridge or can be given to you via prayer boon. .pg -\fIBlind\fP, \fIDeaf\fP, and \fINudist\fP are also conducts, and they can only be +\fIBlind\fP, \fIDeaf\fP, \fINudist\fP, and \FIPauper\fP are also conducts, and they can only be enabled by setting the correspondingly named option in NETHACKOPTIONS or run-time configuration file prior to game start. In the case of \fIBlind\fP and \fIDeaf\fP, the option also enforces the conduct. @@ -4303,7 +4328,8 @@ symbols for the various object types. Any omitted types are filled in at the end from the previous order. .lp paranoid_confirmation A space separated list of specific situations where alternate -prompting is desired. The default is \(lqparanoid_confirmation:pray swim trap\(rq. +prompting is desired. +The default is \(lqparanoid_confirmation:pray swim trap\(rq. .PS Were-change .PL Confirm for any prompts which are set to require \(lqyes\(rq rather than \(oqy\(cq, @@ -4337,6 +4363,8 @@ than immediately praying; on by default; .PL trap require \(oqy\(cq to confirm an attempt to move into or onto a known trap, unless doing so is considered to be harmless; +when enabled, this confirmation is also used for moving into visible +gas cloud regions; (to require \(lqyes\(rq rather than just \(oqy\(cq, set Confirm too); confirmation can be skipped by using the \(oq\f(CRm\fP\(cq movement prefix; .PL swim @@ -4353,7 +4381,7 @@ commands even when wearing just one applicable item; .PL all turn on all of the above. .PE -By default, the pray and swim choices are enabled, the others disabled. +By default, the pray, swim, and trap choices are enabled, the others disabled. To disable them without setting any of the other choices, use \f(CRparanoid_confirmation:none\fP. To keep them enabled while setting any of the others, you can @@ -4370,6 +4398,8 @@ use the \(oq\f(CR+\fP\(cq form and list entries to be added by their name and entries to be removed by \(oq\f(CR!\fP\(cq and name. The positive (no \(oq!\(cq) and negative (with \(oq!\(cq) entries can be intermixed. +.lp pauper +Start the character with no possessions (default false). Persistent. .lp perm_invent If true, always display your current inventory in a window (default false). .lp "" diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 57d69e381..74e6c6884 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -48,7 +48,7 @@ \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.7.0 by Mike Stephenson and others)} %DO NOT REMOVE NH_DATESUB \date{DATE(%B %-d, %Y)} -\date{April 12, 2024} +\date{August 11, 2024} \maketitle @@ -514,92 +514,85 @@ game will use default symbols. Here is a list of what the default symbols mean: \blist{} -%.lp -\item[\tb{- {\rm and} |}] -The walls of a room, or an open door. Or a grave ({\tt |}). -%.lp +\item[\tb{-}] +The horizontal or corner walls of a room, or an open east/west door. +\item[\tb{|}] +The vertical walls of a room, or an open north/south door, or a grave. \item[\tb{.}] -The floor of a room, ice, or a doorless doorway. -%.lp +The floor of a room, or ice, or a doorless doorway, or the span of an +open drawbridge. \item[\tb{\#}] -A corridor, or iron bars, or a tree, or possibly a kitchen sink (if -your dungeon has sinks), or a drawbridge. -%.lp +A corridor, or iron bars, or a tree, or the portcullis of a closed +drawbridge.\\ +%.lp "" +Note: engravings in corridors also appear as \# but are shown in +a different color from normal corridor locations. \item[\tb{>}] Stairs down: a way to the next level. -%.lp \item[\tb{<}] Stairs up: a way to the previous level. -%.lp \item[\tb{+}] A closed door, or a spellbook containing a spell you may be able to learn. -%.lp \item[\tb{@}] -Your character or a human. -%.lp +Your character or a human or an elf. \item[\tb{\$}] A pile of gold. -%.lp \item[\tb{\^}] A trap (once you have detected it). -%.lp \item[\tb{)}] A weapon. -%.lp \item[\tb{[}] A suit or piece of armor. -%.lp \item[\tb{\%}] Something edible (not necessarily healthy). -%.lp \item[\tb{?}] A scroll. -%.lp \item[\tb{/}] A wand. -%.lp \item[\tb{=}] A ring. -%.lp \item[\tb{!}] A potion. -%.lp \item[\tb{(}] A useful item (pick-axe, key, lamp \ldots). -%.lp \item[\tb{"}] An amulet or a spider web. -%.lp \item[\tb{*}] A gem or rock (possibly valuable, possibly worthless). -%.lp \item[\tb{\`}] -A boulder or statue. -%.lp +A boulder or statue or an engraving on the floor of a room.\\ +%.lp "" +Note: statues are displayed as if they were the monsters they depict +so won't appear as a {\it grave accent\/} (aka {\it back-tick}). \item[\tb{0}] An iron ball. -%.lp \item[\tb{\verb+_+}] An altar, or an iron chain. -%.lp \item[\tb{\{}] -A fountain. -%.lp +A fountain or a sink. \item[\tb{\}}] -A pool of water or moat or a pool of lava. -%.lp +A pool of water or moat or a wall of water +or a pool of lava or a wall of lava. \item[\tb{$\backslash$}] An opulent throne. -%.lp -\item[\tb{a-zA-Z {\rm \& other symbols}}] +\item[\tb{a-z}] {\normalfont and}] +\item[\tb{A-HJ-Z}] {\normalfont and}] +%should probably change \item[\tb{@\&\verb+'+:;}] to \item[\tb{\verb+@&':;+}] +\item[\tb{@\&\verb+'+:;}] Letters and certain other symbols represent the various inhabitants -of the Mazes of Menace. Watch out, they can be nasty and vicious. +of the Mazes of Menace. +Watch out, they can be nasty and vicious. Sometimes, however, they can be helpful. -%.lp \item[\tb{I}] -This marks the last known location of an invisible or otherwise unseen -monster. Note that the monster could have moved. -The `{\tt F}' and `{\tt m}' commands may be useful here. +Rather than a specific type of monster, this marks the last known +location of an invisible or otherwise unseen monster. +Note that the monster could have moved. +The `{\tt s}', `{\tt F}', and `{\tt m}' commands may be useful here. +\item[\tb{1-5}] +The digits 1 through 5 may be displayed, marking unseen monsters sensed +via the {\it Warning\/} attribute. +Less dangerous monsters are indicated by lower values, more dangerous by +higher values. \elist %.pg @@ -1812,6 +1805,9 @@ In normal play you can view the explored portion of the current level's map without monsters; without monsters and objects; or without monsters, objects, and traps.\\ %.lp "" +If there are visible clouds of gas in view, they are treated like traps +when deciding whether to show them or the floor underneath them.\\ +%.lp "" In explore mode, you can choose to view the full map rather than just its explored portion. In debug mode there are additional choices.\\ @@ -3735,6 +3731,8 @@ Blind from birth. Deaf from birth. \item[{\tt Nudist}] Never wore any armor. +\item[{\tt Pauper}] +Started out with no possessions. \item[{\tt Ascended}] Delivered the Amulet to its final destination. \elist @@ -3781,7 +3779,7 @@ enough---but not too close!---to the Castle level's drawbridge or can be given to you via prayer boon. %.pg -{\it Blind\/}, {\it Deaf\/}, and {\it Nudist\/} are also conducts, and they can only be +{\it Blind\/}, {\it Deaf\/}, {\it Nudist\/}, and {\it Pauper\/} are also conducts, and they can only be enabled by setting the correspondingly named option in {\tt NETHACKOPTIONS} or run-time configuration file prior to game start. In the case of {\it Blind\/} and {\it Deaf\/}, the option also enforces the conduct. @@ -4760,6 +4758,8 @@ than immediately praying; on by default; \item[{\tt trap~~~}] require `{\tt y}' to confirm an attempt to move into or onto a known trap, unless doing so is considered to be harmless; +when enabled, this confirmation is also used for moving into visible +gas cloud regions; (to require ``yes'' rather than just `y', set Confirm too); confirmation can be skipped by using the `{\tt m}' movement prefix; \item[{\tt swim~~~}] @@ -4778,7 +4778,7 @@ turn on all of the above. \elist %.ei %.ed -By default, the pray and swim choices are enabled, the others disabled. +By default, the pray, swim, and trap choices are enabled, the others disabled. To disable them without setting any of the other choices, use ``{\it paranoid\verb+_+confirmation:none}''. To keep them enabled while setting any of the others, you can @@ -4796,6 +4796,9 @@ and entries to be removed by `{\tt !}' and name. The positive (no `!') and negative (with `!') entries can be intermixed. %.lp +\item[\ib{pauper}] +Start the character with no possessions (default false). Persistent. +%.lp \item[\ib{perm\verb+_+invent}] If true, always display your current inventory in a window (default is false). %.lp "" diff --git a/doc/Guidebook.txt b/doc/Guidebook.txt index 0e08d3e33..26ff90445 100644 --- a/doc/Guidebook.txt +++ b/doc/Guidebook.txt @@ -15,7 +15,7 @@ Original version - Eric S. Raymond (Edited and expanded for NetHack 3.7.0 by Mike Stephenson and others) - February 29, 2024 + July 29, 2024 @@ -126,7 +126,7 @@ - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -192,7 +192,7 @@ NetHack continues this fine tradition. Unlike text adventure games - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -258,7 +258,7 @@ - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -324,7 +324,7 @@ - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -390,7 +390,7 @@ The number of turns elapsed so far, displayed if you have the - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -450,13 +450,13 @@ game uses; otherwise, the game will use default symbols. Here is a list of what the default symbols mean: - - and | - The walls of a room, or an open door. Or a grave (|). + - The horizontal or corner walls of a room, or an open east/west + door. - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -466,10 +466,17 @@ - . The floor of a room, ice, or a doorless doorway. + | The vertical walls of a room, or an open north/south door, or a + grave. - # A corridor, or iron bars, or a tree, or possibly a kitchen sink - (if your dungeon has sinks), or a drawbridge. + . The floor of a room, or ice, or a doorless doorway, or the span + of an open drawbridge. + + # A corridor, or iron bars, or a tree, or the portcullis of a + closed drawbridge. + + Note: engravings in corridors also appear as # but are shown in a + different color from normal corridor locations. > Stairs down: a way to the next level. @@ -478,7 +485,7 @@ + A closed door, or a spellbook containing a spell you may be able to learn. - @ Your character or a human. + @ Your character or a human or an elf. $ A pile of gold. @@ -504,25 +511,18 @@ * A gem or rock (possibly valuable, possibly worthless). - ` A boulder or statue. + ` A boulder or statue or an engraving on the floor of a room. + + Note: statues are displayed as if they were the monsters they de- + pict so won't appear as a grave accent (aka back-tick). 0 An iron ball. _ An altar, or an iron chain. - { A fountain. - - } A pool of water or moat or a pool of lava. - - \ An opulent throne. - - a-zA-Z and other symbols - Letters and certain other symbols represent the various inhabi- - tants of the Mazes of Menace. Watch out, they can be nasty and - vicious. Sometimes, however, they can be helpful. - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -532,63 +532,63 @@ - I This marks the last known location of an invisible or otherwise - unseen monster. Note that the monster could have moved. The `F' - and `m' commands may be useful here. + { A fountain or a sink. - You need not memorize all these symbols; you can ask the game - what any symbol represents with the `/' command (see the next section + } A pool of water or moat or a wall of water or a pool of lava or a + wall of lava. + + \ An opulent throne. + + a-z and + + A-Z and + + @&':; + Letters and certain other symbols represent the various inhabi- + tants of the Mazes of Menace. Watch out, they can be nasty and + vicious. Sometimes, however, they can be helpful. + + I Rather than a specific type of monster, this marks the last known + location of an invisible or otherwise unseen monster. Note that + the monster could have moved. The `s', `F', and `m' commands may + be useful here. + + 1-5 The digits 1 through 5 may be displayed, marking unseen monsters + sensed via the Warning attribute. Less dangerous monsters are + indicated by lower values, more dangerous by higher values. + + You need not memorize all these symbols; you can ask the game + what any symbol represents with the `/' command (see the next section for more info). 4. Commands - Commands can be initiated by typing one or two characters to - which the command is bound to, or typing the command name in the ex- - tended commands entry. Some commands, like "search", do not require - that any more information be collected by NetHack. Other commands - might require additional information, for example a direction, or an - object to be used. For those commands that require additional infor- + Commands can be initiated by typing one or two characters to + which the command is bound to, or typing the command name in the ex- + tended commands entry. Some commands, like "search", do not require + that any more information be collected by NetHack. Other commands + might require additional information, for example a direction, or an + object to be used. For those commands that require additional infor- mation, NetHack will present you with either a menu of choices or with a command line prompt requesting information. Which you are presented with will depend chiefly on how you have set the menustyle option. - For example, a common question, in the form "What do you want to - use? [a-zA-Z ?*]", asks you to choose an object you are carrying. - Here, "a-zA-Z" are the inventory letters of your possible choices. - Typing `?' gives you an inventory list of these items, so you can see - what each letter refers to. In this example, there is also a `*' in- - dicating that you may choose an object not on the list, if you wanted - to use something unexpected. Typing a `*' lists your entire inven- + For example, a common question, in the form "What do you want to + use? [a-zA-Z ?*]", asks you to choose an object you are carrying. + Here, "a-zA-Z" are the inventory letters of your possible choices. + Typing `?' gives you an inventory list of these items, so you can see + what each letter refers to. In this example, there is also a `*' in- + dicating that you may choose an object not on the list, if you wanted + to use something unexpected. Typing a `*' lists your entire inven- tory, so you can see the inventory letters of every object you're car- - rying. Finally, if you change your mind and decide you don't want to + rying. Finally, if you change your mind and decide you don't want to do this command after all, you can press the ESC key to abort the com- mand. - You can put a number before some commands to repeat them that - many times; for example, "10s" will search ten times. If you have the - number_pad option set, you must type `n' to prefix a count, so the ex- - ample above would be typed "n10s" instead. Commands for which counts - make no sense ignore them. In addition, movement commands can be pre- - fixed for greater control (see below). To cancel a count or a prefix, - press the ESC key. - - The list of commands is rather long, but it can be read at any - time during the game through the `?' command, which accesses a menu of - helpful texts. Here are the default key bindings for your reference: - - ? Help menu: display one of several help texts available. - - / The "whatis" command, to tell what a symbol represents. You may - choose to specify a location or type a symbol (or even a whole - word) to explain. Specifying a location is done by moving the - cursor to a particular spot on the map and then pressing one of - `.', `,', `;', or `:'. `.' will explain the symbol at the chosen - location, conditionally check for "More info?" depending upon - whether the help option is on, and then you will be asked to pick - another location; `,' will explain the symbol but skip any - NetHack 3.7.0 February 29, 2024 + + NetHack 3.7.0 July 29, 2024 @@ -598,38 +598,72 @@ - additional information, then let you pick another location; `;' - will skip additional info and also not bother asking you to - choose another location to examine; `:' will show additional - info, if any, without asking for confirmation. When picking a - location, pressing the ESC key will terminate this command, or - pressing `?' will give a brief reminder about how it works. + You can put a number before some commands to repeat them that + many times; for example, "10s" will search ten times. If you have the + number_pad option set, you must type `n' to prefix a count, so the ex- + ample above would be typed "n10s" instead. Commands for which counts + make no sense ignore them. In addition, movement commands can be pre- + fixed for greater control (see below). To cancel a count or a prefix, + press the ESC key. + + The list of commands is rather long, but it can be read at any + time during the game through the `?' command, which accesses a menu of + helpful texts. Here are the default key bindings for your reference: + + ? Help menu: display one of several help texts available. + + / The "whatis" command, to tell what a symbol represents. You may + choose to specify a location or type a symbol (or even a whole + word) to explain. Specifying a location is done by moving the + cursor to a particular spot on the map and then pressing one of + `.', `,', `;', or `:'. `.' will explain the symbol at the chosen + location, conditionally check for "More info?" depending upon + whether the help option is on, and then you will be asked to pick + another location; `,' will explain the symbol but skip any addi- + tional information, then let you pick another location; `;' will + skip additional info and also not bother asking you to choose an- + other location to examine; `:' will show additional info, if any, + without asking for confirmation. When picking a location, press- + ing the ESC key will terminate this command, or pressing `?' will + give a brief reminder about how it works. If the autodescribe option is on, a short description of what you see at each location is shown as you move the cursor. Typing `#' - while picking a location will toggle that option on or off. The - whatis_coord option controls whether the short description in- + while picking a location will toggle that option on or off. The + whatis_coord option controls whether the short description in- cludes map coordinates. - Specifying a name rather than a location always gives any addi- + Specifying a name rather than a location always gives any addi- tional information available about that name. - You may also request a description of nearby monsters, all mon- - sters currently displayed, nearby objects, or all objects. The - whatis_coord option controls which format of map coordinate is + You may also request a description of nearby monsters, all mon- + sters currently displayed, nearby objects, or all objects. The + whatis_coord option controls which format of map coordinate is included with their descriptions. & Tell what a command does. - < Go up to the previous level (if you are on a staircase or lad- + < Go up to the previous level (if you are on a staircase or lad- der). > Go down to the next level (if you are on a staircase or ladder). [yuhjklbn] - Go one step in the direction indicated (see Figure 3). If you + Go one step in the direction indicated (see Figure 3). If you sense or remember a monster there, you will fight the monster in- - stead. Only these one-step movement commands cause you to fight + stead. Only these one-step movement commands cause you to fight + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 11 + + + monsters; the others (below) are "safe." +----------------------------------------------------------------+ | y k u 7 8 9 | @@ -648,39 +682,27 @@ remember a monster there). A few non-movement commands use the `m' prefix to request operat- - ing via menu (to temporarily override the menustyle:traditional - option). Primarily useful for `,' (pickup) when there is only - one class of objects present (where there won't be any "what - kinds of objects?" prompt, so no opportunity to answer `m' at - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 11 - - - + ing via menu (to temporarily override the menustyle:traditional + option). Primarily useful for `,' (pickup) when there is only + one class of objects present (where there won't be any "what + kinds of objects?" prompt, so no opportunity to answer `m' at that prompt). The prefix will make "#travel" command show a menu of interesting - targets in sight. It can also be used with the `\' (known, show + targets in sight. It can also be used with the `\' (known, show a list of all discovered objects) and the ``' (knownclass, show a list of discovered objects in a particular class) commands to of- - fer a menu of several sorting alternatives (which sets a new + fer a menu of several sorting alternatives (which sets a new value for the sortdiscoveries option); also for "#vanquished" and "#genocided" commands to offer a sorting menu. - A few other commands (eat food, offer sacrifice, apply tinning- - kit, drink/quaff, dip, tip container) use the `m' prefix to skip - checking for applicable objects on the floor and go straight to - checking inventory, or (for "#loot" to remove a saddle), skip + A few other commands (eat food, offer sacrifice, apply tinning- + kit, drink/quaff, dip, tip container) use the `m' prefix to skip + checking for applicable objects on the floor and go straight to + checking inventory, or (for "#loot" to remove a saddle), skip containers and go straight to adjacent monsters. - In debug mode (aka "wizard mode"), the `m' prefix may also be + In debug mode (aka "wizard mode"), the `m' prefix may also be used with the "#teleport" and "#wizlevelport" commands. F[yuhjklbn] @@ -690,37 +712,15 @@ Prefix: move until something interesting is found. G[yuhjklbn] or +[yuhjklbn] - Prefix: similar to `g', but forking of corridors is not consid- + Prefix: similar to `g', but forking of corridors is not consid- ered interesting. - Note: + means holding the or key - down like while typing and releasing , then releas- - ing . ^ is used as shorthand elsewhere in the - Guidebook to mean the same thing. Control characters are case- - insensitive so ^x and ^X are the same. - - M[yuhjklbn] - Old versions supported `M' as a movement prefix which combined - the effect of `m' with +. That is no longer - supported as a prefix but similar effect can be achieved by using - `m' and G in combination. m can also be used in com- - bination with g, +, or - +. - - _ Travel to a map location via a shortest-path algorithm. - - The shortest path is computed over map locations the hero knows - about (e.g. seen or previously traversed). If there is no known - path, a guess is made instead. Stops on most of the same condi- - tions as the `G' prefix, but without picking up objects, so im- - plicitly forces the `m' prefix. For ports with mouse support, - the command is also invoked when a mouse-click takes place on a - location other than the current position. + Note: + means holding the or key + down like while typing and releasing , then releas- + ing . ^ is used as shorthand elsewhere in the - - - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -730,18 +730,39 @@ + Guidebook to mean the same thing. Control characters are case- + insensitive so ^x and ^X are the same. + + M[yuhjklbn] + Old versions supported `M' as a movement prefix which combined + the effect of `m' with +. That is no longer + supported as a prefix but similar effect can be achieved by using + `m' and G in combination. m can also be used in com- + bination with g, +, or + +. + + _ Travel to a map location via a shortest-path algorithm. + + The shortest path is computed over map locations the hero knows + about (e.g. seen or previously traversed). If there is no known + path, a guess is made instead. Stops on most of the same condi- + tions as the `G' prefix, but without picking up objects, so im- + plicitly forces the `m' prefix. For ports with mouse support, + the command is also invoked when a mouse-click takes place on a + location other than the current position. + . Wait or rest, do nothing for one turn. Precede with the `m' pre- - fix to wait for a turn even next to a hostile monster, if + fix to wait for a turn even next to a hostile monster, if safe_wait is on. a Apply (use) a tool (pick-axe, key, lamp...). - If used on a wand, that wand will be broken, releasing its magic + If used on a wand, that wand will be broken, releasing its magic in the process. Confirmation is required. A Remove one or more worn items, such as armor. - Use `T' (take off) to take off only one piece of armor or `R' + Use `T' (take off) to take off only one piece of armor or `R' (remove) to take off only one accessory. ^A Repeat the previous command. @@ -762,10 +783,23 @@ In answer to the question + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 13 + + + "What kinds of things do you want to drop? [!%= BUCXPaium]" - you should type zero or more object symbols possibly followed by - `a' and/or `i' and/or `u' and/or `m'. In addition, one or more + you should type zero or more object symbols possibly followed by + `a' and/or `i' and/or `u' and/or `m'. In addition, one or more of the blessed/uncursed/cursed groups may be typed. DB - drop all objects known to be blessed. @@ -779,34 +813,22 @@ Dm - use a menu to pick which object(s) to drop. D%u - drop only unpaid food. - The last example shows a combination. There are four categories + The last example shows a combination. There are four categories of object filtering: class (`!' for potions, `?' for scrolls, and so on), shop status (`u' for unpaid, in other words, owned by the shop), bless/curse state (`B', `U', `C', and `X' as shown above), and novelty (`P', recently picked up items; controlled by picking - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 13 - - - up or dropping things rather than by any time factor). - If you specify more than one value in a category (such as "!?" + If you specify more than one value in a category (such as "!?" for potions and scrolls or "BU" for blessed and uncursed), an in- - ventory object will meet the criteria if it matches any of the + ventory object will meet the criteria if it matches any of the specified values (so "!?" means `!' or `?'). If you specify more than one category, an inventory object must meet each of the cat- egory criteria (so "%u" means class `%' and unpaid `u'). Lastly, - you may specify multiple values within multiple categories: - "!?BU" will select all potions and scrolls which are known to be - blessed or uncursed. (In versions prior to 3.6, filter combina- + you may specify multiple values within multiple categories: + "!?BU" will select all potions and scrolls which are known to be + blessed or uncursed. (In versions prior to 3.6, filter combina- tions behaved differently.) ^D Kick something (usually a door). @@ -815,44 +837,22 @@ Normally checks for edible item(s) on the floor, then if none are found or none are chosen, checks for edible item(s) in inventory. - Precede `e' with the `m' prefix to bypass attempting to eat any- + Precede `e' with the `m' prefix to bypass attempting to eat any- thing off the floor. - If you attempt to eat while already satiated, you might choke to - death. If you risk it, you will be asked whether to "continue - eating?" if you survive the first bite. You can set the para- - noid_confirmation:eating option to require a response of yes in- + If you attempt to eat while already satiated, you might choke to + death. If you risk it, you will be asked whether to "continue + eating?" if you survive the first bite. You can set the para- + noid_confirmation:eating option to require a response of yes in- stead of just y. E Engrave a message on the floor. E- - write in the dust with your fingers. - Engraving the word "Elbereth" will cause most monsters to not at- - tack you hand-to-hand (but if you attack, you will rub it out); - this is often useful to give yourself a breather. - - f Fire (shoot or throw) one of the objects placed in your quiver - (or quiver sack, or that you have at the ready). You may select - ammunition with a previous `Q' command, or let the computer pick - something appropriate if autoquiver is true. If your wielded - weapon has the throw-and-return property, your quiver is empty, - and autoquiver is false, you will throw that wielded weapon in- - stead of filling the quiver. This will also automatically use a - polearm if wielded. If fireassist is true, firing will automati- - cally try to wield a launcher (for example, a bow or a sling) - matching the ammo in the quiver; this might take multiple turns, - and get interrupted by a monster. Remember to swap back to your - main melee weapon afterwards. - - See also `t' (throw) for more general throwing and shooting. - - i List your inventory (everything you're carrying). - - - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -862,8 +862,29 @@ - I List selected parts of your inventory, usually be specifying the - character for a particular set of objects, like `[' for armor or + Engraving the word "Elbereth" will cause most monsters to not at- + tack you hand-to-hand (but if you attack, you will rub it out); + this is often useful to give yourself a breather. + + f Fire (shoot or throw) one of the objects placed in your quiver + (or quiver sack, or that you have at the ready). You may select + ammunition with a previous `Q' command, or let the computer pick + something appropriate if autoquiver is true. If your wielded + weapon has the throw-and-return property, your quiver is empty, + and autoquiver is false, you will throw that wielded weapon in- + stead of filling the quiver. This will also automatically use a + polearm if wielded. If fireassist is true, firing will automati- + cally try to wield a launcher (for example, a bow or a sling) + matching the ammo in the quiver; this might take multiple turns, + and get interrupted by a monster. Remember to swap back to your + main melee weapon afterwards. + + See also `t' (throw) for more general throwing and shooting. + + i List your inventory (everything you're carrying). + + I List selected parts of your inventory, usually be specifying the + character for a particular set of objects, like `[' for armor or `!' for potions. I* - list all gems in inventory; @@ -880,45 +901,24 @@ O Set options. - A menu showing the current option values will be displayed. You + A menu showing the current option values will be displayed. You can change most values simply by selecting the menu entry for the - given option (ie, by typing its letter or clicking upon it, de- - pending on your user interface). For the non-boolean choices, a - further menu or prompt will appear once you've closed this menu. - The available options are listed later in this Guidebook. Op- - tions are usually set before the game rather than with the `O' - command; see the section on options below. Precede `O' with the + given option (ie, by typing its letter or clicking upon it, de- + pending on your user interface). For the non-boolean choices, a + further menu or prompt will appear once you've closed this menu. + The available options are listed later in this Guidebook. Op- + tions are usually set before the game rather than with the `O' + command; see the section on options below. Precede `O' with the `m' prefix to show advanced options. ^O Show overview. - Shortcut for "#overview": list interesting dungeon levels vis- + Shortcut for "#overview": list interesting dungeon levels vis- ited. - (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.) - - p Pay your shopping bill. - - P Put on an accessory (ring, amulet, or blindfold). - - This command may also be used to wear armor. The prompt for - which inventory item to use will only list accessories, but - choosing an unlisted item of armor will attempt to wear it. (See - the `W' command below. It lists armor as the inventory choices - but will accept an accessory and attempt to put that on.) - - ^P Repeat previous message. - - Subsequent `^P's repeat earlier messages. For some interfaces, - the behavior can be varied via the msg_window option. - - q Quaff (drink) something (potion, water, etc). - - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -928,12 +928,33 @@ - When there is a fountain or sink present, it asks whether to + (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.) + + p Pay your shopping bill. + + P Put on an accessory (ring, amulet, or blindfold). + + This command may also be used to wear armor. The prompt for + which inventory item to use will only list accessories, but + choosing an unlisted item of armor will attempt to wear it. (See + the `W' command below. It lists armor as the inventory choices + but will accept an accessory and attempt to put that on.) + + ^P Repeat previous message. + + Subsequent `^P's repeat earlier messages. For some interfaces, + the behavior can be varied via the msg_window option. + + q Quaff (drink) something (potion, water, etc). + + When there is a fountain or sink present, it asks whether to drink from that. If that is declined, then it offers a chance to - choose a potion from inventory. Precede `q' with the `m' prefix + choose a potion from inventory. Precede `q' with the `m' prefix to skip asking about drinking from a fountain or sink. - Q Select an object for your quiver, quiver sack, or just generally + Q Select an object for your quiver, quiver sack, or just generally at the ready (only one of these is available at a time). You can then throw this (or one of these) using the `f' command. @@ -946,45 +967,24 @@ be removed without asking, but you can set the paranoid_confirma- tion:Remove option to require a prompt. - This command may also be used to take off armor. The prompt for - which inventory item to remove only lists worn accessories, but + This command may also be used to take off armor. The prompt for + which inventory item to remove only lists worn accessories, but an item of worn armor can be chosen. (See the `T' command below. It lists armor as the inventory choices but will accept an acces- sory and attempt to remove it.) ^R Redraw the screen. - s Search for secret doors and traps around you. It usually takes - several tries to find something. Precede with the `m' prefix to + s Search for secret doors and traps around you. It usually takes + several tries to find something. Precede with the `m' prefix to search for a turn even next to a hostile monster, if safe_wait is on. - Can also be used to figure out whether there is still a monster + Can also be used to figure out whether there is still a monster at an adjacent "remembered, unseen monster" marker. - S Save the game (which suspends play and exits the program). The - saved game will be restored automatically the next time you play - using the same character name. - In normal play, once a saved game is restored the file used to - hold the saved data is deleted. In explore mode, once restora- - tion is accomplished you are asked whether to keep or delete the - file. Keeping the file makes it feasible to play for a while - then quit without saving and later restore again. - - There is no "save current game state and keep playing" command, - not even in explore mode where saved game files can be kept and - re-used. - - t Throw an object or shoot a projectile. - - There's no separate "shoot" command. If you throw an arrow while - wielding a bow, you are shooting that arrow and any weapon skill - bonus or penalty for bow applies. If you throw an arrow while - not wielding a bow, you are throwing it by hand and it will - - - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -994,24 +994,44 @@ - generally be less effective than when shot. + S Save the game (which suspends play and exits the program). The + saved game will be restored automatically the next time you play + using the same character name. + + In normal play, once a saved game is restored the file used to + hold the saved data is deleted. In explore mode, once restora- + tion is accomplished you are asked whether to keep or delete the + file. Keeping the file makes it feasible to play for a while + then quit without saving and later restore again. + + There is no "save current game state and keep playing" command, + not even in explore mode where saved game files can be kept and + re-used. + + t Throw an object or shoot a projectile. + + There's no separate "shoot" command. If you throw an arrow while + wielding a bow, you are shooting that arrow and any weapon skill + bonus or penalty for bow applies. If you throw an arrow while + not wielding a bow, you are throwing it by hand and it will gen- + erally be less effective than when shot. See also `f' (fire) for throwing or shooting an item pre-selected via the `Q' (quiver) command, with some extra assistance. T Take off armor. - If you're wearing more than one piece, you'll be prompted for + If you're wearing more than one piece, you'll be prompted for which one to take off. (Note that this treats a cloak covering a suit and/or a shirt, or a suit covering a shirt, as if the under- - lying items weren't there.) When you're only wearing one, then - by default it will be taken off without asking, but you can set + lying items weren't there.) When you're only wearing one, then + by default it will be taken off without asking, but you can set the paranoid_confirmation:Remove option to require a prompt. - This command may also be used to remove accessories. The prompt + This command may also be used to remove accessories. The prompt for which inventory item to take off only lists worn armor, but a - worn accessory can be chosen. (See the `R' command above. It - lists accessories as the inventory choices but will accept an + worn accessory can be chosen. (See the `R' command above. It + lists accessories as the inventory choices but will accept an item of armor and attempt to take it off.) ^T Teleport, if you have the ability. @@ -1024,33 +1044,13 @@ w- - wield nothing, use your bare (or gloved) hands. - Some characters can wield two weapons at once; use the `X' com- + Some characters can wield two weapons at once; use the `X' com- mand (or the "#twoweapon" extended command) to do so. - W Wear armor. - - This command may also be used to put on an accessory (ring, - amulet, or blindfold). The prompt for which inventory item to - use will only list armor, but choosing an unlisted accessory will - attempt to put it on. (See the `P' command above. It lists ac- - cessories as the inventory choices but will accept an item of ar- - mor and attempt to wear it.) - - x Exchange your wielded weapon with the item in your alternate - weapon slot. - - The latter is used as your secondary weapon when engaging in two- - weapon combat. Note that if one of these slots is empty, the ex- - change still takes place. - - X Toggle two-weapon combat, if your character can do it. Also - available via the "#twoweapon" extended command. - - (In versions prior to 3.6 this keystroke ran the command to - switch from normal play to "explore mode", also known as - NetHack 3.7.0 February 29, 2024 + + NetHack 3.7.0 July 29, 2024 @@ -1060,8 +1060,28 @@ - "discovery mode", which has now been moved to "#exploremode" and - M-X.) + W Wear armor. + + This command may also be used to put on an accessory (ring, + amulet, or blindfold). The prompt for which inventory item to + use will only list armor, but choosing an unlisted accessory will + attempt to put it on. (See the `P' command above. It lists ac- + cessories as the inventory choices but will accept an item of ar- + mor and attempt to wear it.) + + x Exchange your wielded weapon with the item in your alternate + weapon slot. + + The latter is used as your secondary weapon when engaging in two- + weapon combat. Note that if one of these slots is empty, the ex- + change still takes place. + + X Toggle two-weapon combat, if your character can do it. Also + available via the "#twoweapon" extended command. + + (In versions prior to 3.6 this keystroke ran the command to + switch from normal play to "explore mode", also known as "discov- + ery mode", which has now been moved to "#exploremode" and M-X.) ^X Display basic information about your character. @@ -1090,6 +1110,22 @@ : Look at what is here. + + + __________ + (R)UNIX is a registered trademark of The Open Group. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 18 + + + ; Show what type of thing a visible symbol corresponds to. , Pick up some things from the floor beneath you. @@ -1110,22 +1146,6 @@ ( Tell what tools you are using. - - - __________ - (R)UNIX is a registered trademark of The Open Group. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 18 - - - * Tell what equipment you are using. Combines the preceding five type-specific commands into one. @@ -1160,6 +1180,18 @@ Allows scrolling with the menu_first_page, menu_previous_page, menu_next_page, and menu_last_page keys (`^', `<', `>', `|' by + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 19 + + + default). Some interfaces also support menu_shift_left and menu_shift_right keys (`{' and `}' by default). Use the Return (aka Enter) or Escape key to resume play. @@ -1179,19 +1211,6 @@ command. If that happens, you can use the extended command "#terrain" instead. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 19 - - - # Perform an extended command. @@ -1227,6 +1246,18 @@ ent slot. In that situation, moving (no count given) a compati- ble stack will merge if either stack has a name when the other doesn't and give that name to the result, while splitting (count + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 20 + + + given) will ignore the source stack's name when deciding whether to merge with the destination stack. @@ -1246,18 +1277,6 @@ If used on a wand, that wand will be broken, releasing its magic in the process. Confirmation is required. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 20 - - - #attributes Show your attributes. Default key is `^X'. @@ -1293,6 +1312,18 @@ See the section below entitled "Conduct" for details. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 21 + + + #debugfuzzer Start the fuzz tester. Debug mode only. @@ -1312,18 +1343,6 @@ #droptype Drop specific item types. Default key is `D'. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 21 - - - #eat Eat something. Default key is `e'. The `m' prefix skips eating items on the floor. @@ -1360,6 +1379,17 @@ mode and debug mode it also shows types which have become ex- tinct. + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 22 + + + The display order is the same as is used by #vanquished. The `m' prefix brings up a menu of available sorting orders, and doing that for either #genocided or #vanquished changes the order for @@ -1377,20 +1407,8 @@ is `;'. #help - Show the help menu. Default key is `?', and also `h' if - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 22 - - - - number_pad is on. + Show the help menu. Default key is `?', and also `h' if num- + ber_pad is on. #herecmdmenu Show a menu of possible actions directed at your current loca- @@ -1425,6 +1443,19 @@ #known Show what object types have been discovered. Default key is `\'. + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 23 + + + The `m' prefix allows assigning a new value to the sortdiscover- ies option to control the order in which the discoveries are dis- played. @@ -1444,18 +1475,6 @@ #look Look at what is here, under you. Default key is `:'. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 23 - - - #lookaround Describe what you can see, or remember, of your surroundings. @@ -1491,6 +1510,18 @@ Show and change option settings. Default key is `O'. Precede with the `m' prefix to show advanced options. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 24 + + + #optionsfull Show advanced game option settings. No default key. Precede with the `m' prefix to execute the simpler options command. @@ -1511,17 +1542,6 @@ This will also force all visited levels to be displayed rather than just the "interesting" subset. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 24 - - - Autocompletes. Default keys are `^O', and `M-O'. #panic @@ -1556,6 +1576,18 @@ (Hint: entering the dungeon alive is treated as having received help. You probably shouldn't start off a new game by praying right away.) Since using this command by accident can cause + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 25 + + + trouble, there is an option to make you confirm your intent be- fore praying. It is enabled by default, and you can reset the paranoid_confirmation option to disable it. @@ -1575,19 +1607,6 @@ #quit Quit the program without saving your game. Autocompletes. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 25 - - - Since using this command by accident would throw away the current game, you are asked to confirm your intent before quitting. De- fault response is n (no); continue playing. To really quit, re- @@ -1624,6 +1643,17 @@ Ride (or stop riding) a saddled creature. Autocompletes. De- fault key is `M-R'. + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 26 + + + #rub Rub a lamp or a stone. Autocompletes. Default key is `M-r'. @@ -1641,21 +1671,9 @@ Save the game and exit the program. Default key is `S'. #saveoptions - Save configuration options to the config file. This will - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 26 - - - - overwrite the file, removing all comments, so if you have manu- - ally edited the config file, don't use this. + Save configuration options to the config file. This will over- + write the file, removing all comments, so if you have manually + edited the config file, don't use this. #search Search for traps and secret doors around you. Default key is @@ -1690,6 +1708,18 @@ Will display the result in a message if there is one tool in use (worn blindfold or towel or lenses, lit lamp(s) and/or candle(s), + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 27 + + + leashes attached to pets). Will display a menu if there are more than one or if the command is preceded by the `m' prefix. @@ -1709,17 +1739,6 @@ ration file. Use the shell command `exit' to return to the game. Default key is `!'. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 27 - - - #showgold Report the gold in your inventory, including gold you know about in containers you're carrying. If you are inside a shop, report @@ -1754,6 +1773,19 @@ #takeoff Take off one piece of armor. Default key is `T'. + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 28 + + + #takeoffall Remove all armor. Default key is `A'. @@ -1773,19 +1805,6 @@ Autocompletes. Default key is `' or `' (see Del above). - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 28 - - - #therecmdmenu Show a menu of possible actions directed at a location next to you. The menu is limited to a subset of the likeliest actions, @@ -1822,6 +1841,17 @@ #turn Turn undead away. Autocompletes. Default key is `M-t'. + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 29 + + + #twoweapon Toggle two-weapon combat on or off. Autocompletes. Default key is `X', and also `M-2' if number_pad is off. @@ -1839,19 +1869,6 @@ #up Go up a staircase. Default key is `<'. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 29 - - - #vanquished List vanquished monsters by type and count. @@ -1889,6 +1906,18 @@ the running copy was built from sources (not the version's re- lease date). Default key is `v'. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 30 + + + #vision Show vision array. Autocompletes. Debug mode only. @@ -1906,18 +1935,6 @@ Show what type of thing a symbol corresponds to. Default key is `/'. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 30 - - - #wield Wield a weapon. Default key is `w'. @@ -1955,6 +1972,18 @@ #wizkill Remove monsters from play by just pointing at them. By default the hero gets credit or blame for killing the targets. Precede + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 31 + + + this command with the `m' prefix to override that. Autocom- pletes. Debug mode only. @@ -1973,17 +2002,6 @@ Also displays first, second, and last random engravings, epi- taphs, and hallucinatory monsters. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 31 - - - Autocompletes. Debug mode only. #wizseenv @@ -2020,6 +2038,18 @@ On Windows and MS-DOS, the "Alt" key can be used in this fashion. On other systems, if typing "Alt" plus another key transmits a two character sequence consisting of an Escape followed by the other key, + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 32 + + + you may set the altmeta option to have NetHack combine them into meta+. (This combining action only takes place when NetHack is expecting a command to execute, not when accepting input to name some- @@ -2037,19 +2067,6 @@ M-2 #twoweapon (unless the number_pad option is enabled) - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 32 - - - M-a #adjust M-A #annotate @@ -2086,6 +2103,19 @@ M-R #ride + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 33 + + + M-s #sit M-t #turn @@ -2104,18 +2134,6 @@ - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 33 - - - If the number_pad option is on, some additional letter commands are available: @@ -2152,6 +2170,18 @@ doors; you can walk right through. Others have doors in them, which may be open, closed, or locked. To open a closed door, use the `o' (open) command; to close it again, use the `c' (close) command. By + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 34 + + + default the autoopen option is enabled, so simply attempting to walk onto a closed door's location will attempt to open it without needing `o'. Opening via autoopen will not work if you are confused or @@ -2170,18 +2200,6 @@ tool, you'll be asked whether to use it on the door's lock. Alterna- tively, you can break a closed door (whether locked or not) down by kicking it via the `^D' (kick) command. Kicking down a door destroys - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 34 - - - it and makes a lot of noise which might wake sleeping monsters. Some closed doors are booby-trapped and will explode if an at- @@ -2218,6 +2236,18 @@ the trap is also within line-of-sight (whether you can see at the time or not). There is also other magic which can reveal traps. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 35 + + + Monsters can fall prey to traps, too, which can potentially be used as a defensive strategy. Unfortunately traps can be harmful to your pet(s) as well. Monsters, including pets, usually will avoid @@ -2236,18 +2266,6 @@ to another level, but one which is always below the current level. Usually that will be the next level down but it can be farther. Un- like (level) teleporters, the destination level of a particular trap - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 35 - - - door or hole is persistent, so falling into one will bring you to the same level each time--though not necessarily the same spot on the level. Magic portals behave similarly, but with some additional vari- @@ -2283,6 +2301,19 @@ tion for information about getting feedback for your actions in Sokoban. + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 36 + + + 5.3. Stairs and ladders (`<', `>') In general, each level in the dungeon will have a staircase going @@ -2302,18 +2333,6 @@ created (from scratch for most random levels, from a template for some "special" levels, or loaded from the remains of an earlier game for a "bones" level as briefly described below). Monsters are only active - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 36 - - - on the current level; those on other levels are essentially placed into stasis. @@ -2349,6 +2368,18 @@ usually claim ownership without offering any compensation. You'll have to buy it back if you want to reclaim it. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 37 + + + Shopkeepers sometime run out of money. When that happens, you'll be offered credit instead of gold when you try to sell something. Credit can be used to pay for purchases, but it is only good in the @@ -2367,19 +2398,6 @@ Several aspects of shop behavior might be unexpected. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 37 - - - * The price of a given item can vary due to a variety of factors. * A shopkeeper treats the spot immediately inside the door as if it @@ -2417,6 +2435,17 @@ movement direction to step on objects without attempting auto-pickup and without giving feedback about them. + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 38 + + + The mention_walls option controls whether you get feedback if you try to walk into a wall or solid stone or off the edge of the map. Normally nothing happens (unless the hero is blind and no wall is @@ -2434,18 +2463,6 @@ doors are. Assuming that you're able to do so, moving onto water or lava or ice will give feedback if not yet on that type of terrain but not repeat it (unless there has been some intervening message) when - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 38 - - - moving from water to another water spot, or lava to lava, or ice to ice. Moving off of any of those back onto "normal" terrain will give one message too, unless there is feedback about one or more objects, @@ -2482,6 +2499,19 @@ The slight strangeness of this level is a feature, not a bug.... + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 39 + + + 6. Monsters Monsters you cannot see are not displayed on the screen. Beware! @@ -2501,17 +2531,6 @@ get to choose what you'll say), but chatting with some monsters such as a shopkeeper or the Oracle of Delphi can produce useful results. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 39 - - - 6.1. Fighting If you see a monster and you wish to fight it, just attempt to @@ -2547,6 +2566,18 @@ Your pet also gains experience from killing monsters, and can grow over time, gaining hit points and doing more damage. Initially, + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 40 + + + your pet may even be better at killing things than you, which makes pets useful for low-level characters. @@ -2566,18 +2597,6 @@ has had to resort to magic and wizardry in order to forge the al- liance. Once you do have the beast under your control however, you can easily climb in and out of the saddle with the "#ride" command. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 40 - - - Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. @@ -2613,6 +2632,18 @@ However, if you encounter a monster which you can't see or sense--perhaps it is invisible and has just tapped you on the noggin-- + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 41 + + + a special "remembered, unseen monster" marker will be displayed at the location where you think it is. That will persist until you have proven that there is no monster there, even if the unseen monster @@ -2632,18 +2663,6 @@ As you add items to your inventory, you also add the weight of that object to your load. The amount that you can carry depends on - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 41 - - - your strength and your constitution. The stronger and sturdier you are, the less the additional load will affect you. There comes a point, though, when the weight of all of that stuff you are carrying @@ -2679,6 +2698,18 @@ an object which has already been named, specifying a space as the value will remove the prior name instead of assigning a new one. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 42 + + + 7.1. Curses and Blessings Any object that you find may be cursed, even if the object is @@ -2698,18 +2729,6 @@ uncursed. They could just as easily have been described as unblessed, but the uncursed designation is what you will see within the game. A "glass half full versus glass half empty" situation; make of that what - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 42 - - - you will. There are magical means of bestowing or removing curses upon ob- @@ -2745,6 +2764,18 @@ There are wielded weapons, like maces and swords, and thrown weapons, like arrows and spears. To hit monsters with a weapon, you + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 43 + + + must wield it and attack them, or throw it at them. You can simply elect to throw a spear. To shoot an arrow, you should first wield a bow, then throw the arrow. Crossbows shoot crossbow bolts. Slings @@ -2764,18 +2795,6 @@ ficiency (see below). The monster's armor class--a general defense rating, not necessarily due to wearing of armor--is a factor too; also, some monsters are particularly vulnerable to certain types of - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 43 - - - weapons. Many weapons can be wielded in one hand; some require both hands. @@ -2811,6 +2830,18 @@ You can throw just about anything via the `t' command. It will prompt for the item to throw; picking `?' will list things in your in- ventory which are considered likely to be thrown, or picking `*' will + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 44 + + + list your entire inventory. After you've chosen what to throw, you will be prompted for a direction rather than for a specific target. The distance something can be thrown depends mainly on the type of ob- @@ -2830,18 +2861,6 @@ You can simplify the throwing operation by using the `Q' command to select your preferred "missile", then using the `f' command to throw it. You'll be prompted for a direction as above, but you don't - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 44 - - - have to specify which item to throw each time you use `f'. There is also an option, autoquiver, which has NetHack choose another item to automatically fill your quiver (or quiver sack, or have at the ready) @@ -2878,6 +2897,17 @@ you progress through a game, depending on your role, your experience level, and use of the weapons. + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 45 + + + For the purposes of proficiency, weapons have been divided up into various groups such as daggers, broadswords, and polearms. Each role has a limit on what level of proficiency a character can achieve @@ -2896,18 +2926,6 @@ barehanded combat or martial arts skill beyond expert to "master" or "grand master". - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 45 - - - Use of a weapon in which you're restricted or unskilled will in- cur a modest penalty in the chance to hit a monster and also in the amount of damage done when you do hit; at basic level, there is no @@ -2944,6 +2962,18 @@ the correct weapon, use `w', `x', `w' to first wield the intended sec- ondary, swap it to off hand, and then wield the primary. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 46 + + + The whole process can be simplified via use of the pushweapon op- tion. When it is enabled, then using `w' to wield something causes the currently wielded weapon to become your alternate weapon. So the @@ -2962,18 +2992,6 @@ yourself from their blows. Some types of armor offer better protec- tion than others. Your armor class is a measure of this protection. Armor class (AC) is measured as in AD&D, with 10 being the equivalent - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 46 - - - of no armor, and lower numbers meaning better armor. Each suit of ar- mor which exists in AD&D gives the same protection in NetHack. @@ -3010,6 +3028,18 @@ pieces of armor usually have negative enchantments (minuses) in addi- tion to being unremovable. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 47 + + + Many types of armor are subject to some kind of damage like rust. Such damage can be repaired. Some types of armor may inhibit spell casting. @@ -3028,18 +3058,6 @@ Food is necessary to survive. If you go too long without eating you will faint, and eventually die of starvation. Some types of food - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 47 - - - will spoil, and become unhealthy to eat, if not protected. Food stored in ice boxes or tins ("cans") will usually stay fresh, but ice boxes are heavy, and tins take a while to open. @@ -3076,6 +3094,18 @@ appearing in your system mailbox, you must let NetHack know where to look for new mail by setting the "MAIL" environment variable to the file name of your mailbox. You may also want to set the "MAILREADER" + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 48 + + + environment variable to the file name of your favorite reader, so NetHack can shell to it when you read the scroll. On versions of NetHack where mail is randomly generated internal to the game, these @@ -3095,17 +3125,6 @@ at them. It is also sometimes very useful to dip ("#dip") an object into a potion. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 48 - - - The command to drink a potion is `q' (quaff). 7.7. Wands (`/') @@ -3139,6 +3158,20 @@ The command to use a wand is `z' (zap). To break one, use the `a' (apply) command. + + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 49 + + + 7.8. Rings (`=') Rings are very useful items, since they are relatively permanent @@ -3160,18 +3193,6 @@ The commands to use rings are `P' (put on) and `R' (remove). `A', `W', and `T' can also be used; see Amulets. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 49 - - - 7.9. Spellbooks (`+') Spellbooks are tomes of mighty magic. When studied with the `r' @@ -3204,11 +3225,23 @@ become proficient (to varying degrees), spells are similarly grouped. Successfully casting a spell exercises its skill group; using the "#enhance" command to advance a sufficiently exercised skill will af- - fect all spells within the group. Advanced skill may increase the po- - tency of spells, reduce their risk of failure during casting attempts, - and improve the accuracy of the estimate for how much longer they will - be retained in your memory. Skill slots are shared with weapons - skills. (See also the section on "Weapon proficiency".) + fect all spells within the group. Advanced skill may increase the + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 50 + + + + potency of spells, reduce their risk of failure during casting at- + tempts, and improve the accuracy of the estimate for how much longer + they will be retained in your memory. Skill slots are shared with + weapons skills. (See also the section on "Weapon proficiency".) Casting a spell also requires flexible movement, and wearing var- ious types of armor may interfere with that. @@ -3226,18 +3259,6 @@ ple, lamps burn out after a while. Other tools are containers, which objects can be placed into or taken out of. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 50 - - - Some tools (such as a blindfold) can be worn and can be put on and removed like other accessories (rings, amulets); see Amulets. Other tools (such as pick-axe) can be wielded as weapons in addition @@ -3271,6 +3292,18 @@ example, the 3 refers to number of stacks of compatible items, not to the total number of individual items. So a sack holding 2 sky blue potions, 7 arrows, and 350 gold pieces would be described as having 3 + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 51 + + + items rather than 10 or 359. And you would need to have 3 unused in- ventory slots available in order to take everything out (for the case where the items you remove don't combine into bigger stacks with @@ -3289,21 +3322,6 @@ tents into another container. (As of this writing, the other con- tainer must be carried rather than on the floor.) - - - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 51 - - - 7.11. Amulets (`"') Amulets are very similar to rings, and often more powerful. Like @@ -3340,6 +3358,18 @@ Boulders occasionally block your path. You can push one forward (by attempting to walk onto its spot) when nothing blocks its path, or you can smash it into a pile of small rocks with breaking magic or a + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 52 + + + pick-axe. It is possible to move onto a boulder's location if certain conditions are met; ordinarily one of those conditions is that pushing it any further be blocked. Using the move-without-picking-up prefix @@ -3358,18 +3388,6 @@ shown as ``' but by the letter representing the monster they depict instead. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 52 - - - 7.14. Gold (`$') Gold adds to your score, and you can buy things in shops with it. @@ -3404,6 +3422,20 @@ enabled in order to show an item differently when it is the top one of a pile. + + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 53 + + + 8. Conduct As if winning NetHack were not difficult enough, certain players @@ -3425,17 +3457,6 @@ your god for help with starvation does not violate any food challenges either. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 53 - - - A strict vegan diet is one which avoids any food derived from an- imals. The primary source of nutrition is fruits and vegetables. The corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are @@ -3469,6 +3490,18 @@ corpse. Please note that the term "vegan" is used here only in the context of diet. You are still free to choose not to use or wear items derived from animals (e.g. leather, dragon hide, bone, horns, + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 54 + + + coral), but the game will not keep track of this for you. Also note that "milky" potions may be a translucent white, but they do not con- tain milk, so they are compatible with a vegan diet. Slime molds or @@ -3491,17 +3524,6 @@ and kick weapons; use a wand, spell, or other type of item; or fight with your hands and feet. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 54 - - - In NetHack, a pacifist refuses to cause the death of any other monster (i.e. if you would get experience for the death). This is a particularly difficult challenge, although it is still possible to @@ -3533,8 +3555,20 @@ you can be better informed about whether or not to avoid repeating those actions in the future. (Note: the Sokoban conduct will only be displayed if you have entered the Sokoban branch of the dungeon during - the current game. Once that has happened, it becomes part of dis- - closed conduct even if you haven't done anything interesting there. + the current game. Once that has happened, it becomes part of + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 55 + + + + disclosed conduct even if you haven't done anything interesting there. Ending the game with "never broke the Sokoban rules" conduct is most meaningful if you also manage to perform the "obtained the Sokoban prize" achievement (see Achievements below).) @@ -3555,19 +3589,6 @@ to make a wish for an item, you may choose "nothing" if you want to decline. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 55 - - - 8.1. Achievements End of game disclosure will also display various achievements @@ -3601,6 +3622,18 @@ Invocation - Gained access to the bottommost level of Gehennom. Amulet - Acquired the fabled Amulet of Yendor. Endgame - Reached the Elemental Planes. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 56 + + + Astral - Reached the Astral Plane level. Blind - Blind from birth. Deaf - Deaf from birth. @@ -3622,18 +3655,6 @@ There's no guaranteed Novel so the achievement to read one might not always be attainable (except perhaps by wishing). Similarly, the Big Room level is not always present. Unlike with the Novel, there's - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 56 - - - no way to wish for this opportunity. The "special items" hidden in Mines' End and Sokoban are not @@ -3667,6 +3688,18 @@ Options may be set in a number of ways. Within the game, the `O' command allows you to view all options and change most of them. You can also set options automatically by placing them in a configuration + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 57 + + + file, or in the NETHACKOPTIONS environment variable. Some versions of NetHack also have front-end programs that allow you to set options be- fore starting the game or a global configuration for system adminis- @@ -3689,17 +3722,6 @@ "%USERPROFILE%\NetHack\". If you have not created the configuration file, NetHack will create one for you using the default template file. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 57 - - - On MS-DOS, it is "defaults.nh" in the same folder as nethack.exe. Any line in the configuration file starting with `#' is treated @@ -3732,6 +3754,18 @@ tiple options separated by commas in a single OPTIONS directive. (Comma separated options are processed from right to left.) + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 58 + + + Example: OPTIONS=dogname:Fido @@ -3754,18 +3788,6 @@ The location that bones files are kept. Defaults to HACKDIR, must be writable. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 58 - - - LOCKDIR The location that file synchronization locks are stored. Defaults to HACKDIR, must be writable. @@ -3799,6 +3821,17 @@ BIND=^X:getpos.autodescribe + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 59 + + + CHOOSE Chooses at random one of the comma-separated parameters as an active section name. Lines in other sections are ignored. @@ -3820,18 +3853,6 @@ MENUCOLOR Highlight menu lines with different colors. See the "Configuring - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 59 - - - Menu Colors" section. MSGTYPE @@ -3864,31 +3885,10 @@ line, up to a maximum of 128 lines. Each line is processed by the function that handles wishing. - Example: - - WIZKIT=~/wizkit.txt - Here is an example of configuration file contents: - - - - - - - - - - - - - - - - - - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -3898,6 +3898,14 @@ + Example: + + WIZKIT=~/wizkit.txt + + + + Here is an example of configuration file contents: + # Set your character's role, race, gender, and alignment. OPTIONS=role:Valkyrie, race:Human, gender:female, align:lawful # @@ -3944,17 +3952,9 @@ The NETHACKOPTIONS value is effectively the same as a single OP- TIONS directive in a configuration file. The "OPTIONS=" prefix is im- plied and comma separated options are processed from right to left. - Other types of configuration directives such as BIND or MSGTYPE are - not allowed. - - Instead of a comma-separated list of options, NETHACKOPTIONS can - be set to the full name of a configuration file you want to use. If - that full name doesn't start with a slash, precede it with `@' (at- - sign) to let NetHack know that the rest is intended as a file name. - If it does start with `/', the at-sign is optional. - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -3964,6 +3964,15 @@ + Other types of configuration directives such as BIND or MSGTYPE are + not allowed. + + Instead of a comma-separated list of options, NETHACKOPTIONS can + be set to the full name of a configuration file you want to use. If + that full name doesn't start with a slash, precede it with `@' (at- + sign) to let NetHack know that the rest is intended as a file name. + If it does start with `/', the at-sign is optional. + 9.4. Customization options Here are explanations of what the various options do. Character @@ -4010,17 +4019,8 @@ See pickup_types and also autopickup_exception for ways to refine the behavior. - Note: prior to version 3.7.0, the default for autopickup was on. - autoquiver - This option controls what happens when you attempt the `f' (fire) - command when nothing is quivered or readied (default false). When - true, the computer will fill your quiver or quiver sack or make - ready some suitable weapon. Note that it will not take into account - the blessed/cursed status, enchantment, damage, or quality of the - - - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -4030,6 +4030,14 @@ + Note: prior to version 3.7.0, the default for autopickup was on. + + autoquiver + This option controls what happens when you attempt the `f' (fire) + command when nothing is quivered or readied (default false). When + true, the computer will fill your quiver or quiver sack or make + ready some suitable weapon. Note that it will not take into account + the blessed/cursed status, enchantment, damage, or quality of the weapon; you are free to manually fill your quiver or quiver sack or make ready with the `Q' command instead. If no weapon is found or the option is false, the `t' (throw) command is executed instead. @@ -4076,17 +4084,9 @@ boulder Set the character used to display boulders (default is the "large - rock" class symbol, ``'). - - catname - Name your starting cat (for example "catname:Morris"). Cannot be - set with the `O' command. - - character - Synonym for "role" to pick the type of your character (for example - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -4096,6 +4096,14 @@ + rock" class symbol, ``'). + + catname + Name your starting cat (for example "catname:Morris"). Cannot be + set with the `O' command. + + character + Synonym for "role" to pick the type of your character (for example "character:Monk"). See role for more details. checkpoint @@ -4143,16 +4151,8 @@ + - disclose it without prompting; - - do not disclose it and do not prompt. - The listings of vanquished monsters and of genocided types can be - sorted, so there are two additional choices for `v' and `g': - ? - prompt you and default to ask on the prompt; - # - disclose it without prompting, ask for sort order. - - Asking refers to picking one of the orderings from a menu. The `+' - - - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -4162,9 +4162,16 @@ - disclose without prompting choice, or being prompted and answering - `y' rather than `a', will default to showing monsters in the order - specified by the sortvanquished option. + The listings of vanquished monsters and of genocided types can + be sorted, so there are two additional choices for `v' and `g': + + ? - prompt you and default to ask on the prompt; + # - disclose it without prompting, ask for sort order. + + 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 order specified by the sortvanquished option. Omitted categories are implicitly added with `n' prefix. Specified categories with omitted prefix implicitly use `+' prefix. Order of @@ -4209,16 +4216,9 @@ fixinv An object's inventory letter sticks to it when it's dropped (default - on). If this is off, dropping an object shifts all the remaining - inventory letters. Persistent. - - force_invmenu - Commands asking for an inventory item show a menu instead of a text - query with possible menu letters. Default is off. - - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -4228,6 +4228,13 @@ + on). If this is off, dropping an object shifts all the remaining + inventory letters. Persistent. + + force_invmenu + Commands asking for an inventory item show a menu instead of a text + query with possible menu letters. Default is off. + fruit Name a fruit after something you enjoy eating (for example "fruit:mango") (default "slime mold"). Basically a nostalgic whimsy @@ -4275,16 +4282,9 @@ highlight pets and setting it will turn the hilite_pet option on or off as warranted. - hilite_pile - Visually distinguish piles of objects from individual objects (de- - fault off). The behavior of this option depends on the type of win- - dowing you use. In text windowing, text highlighting or inverse - video is often used; with tiles, generally displays a small plus- - symbol beside the object on the top of the pile. - - NetHack 3.7.0 February 29, 2024 + NetHack 3.7.0 July 29, 2024 @@ -4294,9 +4294,34 @@ + hilite_pile + Visually distinguish piles of objects from individual objects (de- + fault off). The behavior of this option depends on the type of win- + dowing you use. In text windowing, text highlighting or inverse + video is often used; with tiles, generally displays a small plus- + symbol beside the object on the top of the pile. + hitpointbar - Show a hit point bar graph behind your name and title. Only avail- - able for TTY and Windows GUI, and only when statushilites is on. + Show a hit point bar graph behind your name and title in the status + display (default off). + + The "curses" interface supports it even if the status highlighting + feature has been disabled when building the program. The "tty" and + "mswin" (aka "Windows GUI") interfaces support it only if status + highlighting is left enabled when building. You don't need to set + up any highlighting rules in order to display the bar. If there is + one for hitpoints in effect and it specifies color, that color will + be used for the bar. However if it specifies video attributes, they + will be ignored in favor of inverse. For tty and curses, blink will + also be used if the current hitpoint value is at or below the criti- + cal HP threshold. + + The "Qt" interface also supports hitpointbar, by drawing a solid bar + above the name and title with a hard-coded color scheme. (As of + this writing, having the bar enabled unintentionally inhibits resiz- + ing the status panel. To resize that, use the #optionsfull command + to toggle the hitpointbar option off, perform the resize while it's + off, then use the same command to toggle it back on.) horsename Name your starting horse (for example "horsename:Trigger"). Cannot @@ -4323,6 +4348,18 @@ lootabc When using a menu to interact with a container, use the old `a', `b', and `c' keyboard shortcuts rather than the mnemonics `o', `i', + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 67 + + + and `b' (default off). Persistent. mail @@ -4349,17 +4386,6 @@ Enable coloring menu lines (default off). See "Configuring Menu Colors" on how to configure the colors. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 67 - - - menustyle Controls the method used when you need to choose various objects (in response to the Drop (aka droptype) command, for instance). The @@ -4388,6 +4414,18 @@ menu_first_page Key to jump to the first page in a menu. Default `^'. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 68 + + + menu_headings Controls how the headings in a menu are highlighted. Takes a text attribute, or text color and attribute separated by ampersand. For @@ -4414,18 +4452,6 @@ Do not clear the screen before drawing menus, and align menus to the right edge of the screen. Only for the tty port. (default on) - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 68 - - - menu_previous_page Key to go to the previous menu page. Default `<'. @@ -4453,6 +4479,19 @@ Show a message when hero notices a monster movement (default is off). + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 69 + + + monpolycontrol Prompt for new form whenever any monster changes shape (default off). Debug mode only. @@ -4480,18 +4519,6 @@ rently it is only supported for tty (all four choices) and for curses (`f' and `r' choices, default `r'). The possible values are: - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 69 - - - 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; @@ -4520,6 +4547,17 @@ null Send padding nulls to the terminal (default on). Persistent. + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 70 + + + number_pad Use digit keys instead of letters to move (default 0 or off). Valid settings are: @@ -4547,21 +4585,10 @@ taining the symbols for the various object types. Any omitted types are filled in at the end from the previous order. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 70 - - - paranoid_confirmation A space separated list of specific situations where alternate prompting is desired. The default is "paranoid_confirmation:pray - swim". + swim trap". Confirm - for any prompts which are set to require "yes" rather than `y', also require "no" to reject instead of ac- @@ -4585,6 +4612,18 @@ immediately praying; on by default; (to require "yes" rather than just `y', set Confirm too); trap - require `y' to confirm an attempt to move into or onto + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 71 + + + a known trap, unless doing so is considered to be harmless; (to require "yes" rather than just `y', set Confirm too); confirmation can be skipped by using the @@ -4612,18 +4651,6 @@ and remove some old ones, you can use multiple paranoid_confirmation option settings, or you can use the `+' form and list entries to be added by their name and entries to be removed by `!' and name. The - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 71 - - - positive (no `!') and negative (with `!') entries can be intermixed. perm_invent @@ -4650,6 +4677,19 @@ Note: if gold has been equipped in quiver/ammo-pouch then it will be included for all despite that mode normally omitting gold. + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 72 + + + petattr Specifies one or more text highlighting attributes to use when show- ing pets on the map. Effectively a superset of the hilite_pet bool- @@ -4678,18 +4718,6 @@ pickup_types or match an autopickup exception. Default is on. Per- sistent. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 72 - - - pickup_thrown If this option is on and autopickup is also on, try to pick up things that you threw, even if they aren't in pickup_types or match @@ -4716,6 +4744,18 @@ which the message "there are few/several/many objects here" is given instead of showing a popup list of those objects. A value of 0 means "no limit" (always list the objects); a value of 1 effectively + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 73 + + + means "never show the objects" since the pile size will always be at least that big; default value is 5. Persistent. @@ -4735,6 +4775,9 @@ wise for the `a' (apply) command if it causes the applied item to become wielded. Persistent. + query_menu + Use a menu when asked specific yes/no queries, instead of a prompt. + quick_farsight When set, usually prevents the "you sense your surroundings" message where play pauses to allow you to browse the map whenever clairvoy- @@ -4743,19 +4786,6 @@ ance spell where pausing to examine revealed objects or monsters is less intrusive. Default is off. Persistent. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 73 - - - race Selects your race (for example, race:human). Choices are human, dwarf, elf, gnome, and orc but most roles restrict which of the non- @@ -4780,6 +4810,18 @@ option or its value(s) with `!' or "no". Examples: + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 74 + + + OPTIONS=role:!arc !bar !kni OPTIONS=!role:arc bar kni @@ -4810,18 +4852,6 @@ crawl - like walk, but pause briefly after each step. This option only affects the game's screen display, not the actual - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 74 - - - results of moving. The default is "run"; versions prior to 3.4.1 used "teleport" only. Whether or not the effect is noticeable will depend upon the window port used or on the type of terminal. Per- @@ -4845,6 +4875,19 @@ the first letter of each category (`t', `a', or `o') is necessary. Persistent. + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 75 + + + showdamage Whenever your character takes damage, show a message of the damage taken, and the amount of hit points left. @@ -4876,18 +4919,6 @@ silent Suppress terminal beeps (default on). Persistent. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 75 - - - sortdiscoveries Controls the sorting behavior for the output of the `\' and ``' com- mands. Persistent. @@ -4911,6 +4942,18 @@ Controls the sorting behavior of the pickup lists for inventory and #loot commands and some others. Persistent. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 76 + + + The possible values are: full - always sort the lists; @@ -4943,17 +4986,6 @@ prefix before either the #vanquished command or the #genocided com- mand. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 76 - - - sounds Allow sounds to be emitted from an integrated sound library (default on). @@ -4977,6 +5009,17 @@ Allow updates to the status lines at the bottom of the screen (de- fault true). + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 77 + + + suppress_alert This option may be set to a NetHack version level to suppress alert notification messages about feature changes for that and prior ver- @@ -5008,18 +5051,6 @@ Put the ending display in a NetHack window instead of on stdout (de- fault off). Setting this option makes the score list visible when a windowing version of NetHack is started without a parent window, but - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 77 - - - it no longer leaves the score list around after game end on a termi- nal or emulating window. @@ -5043,6 +5074,18 @@ The possible settings are: + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 78 + + + c - compass ("east" or "3s" or "2n,4w"); f - full compass ("east" or "3south" or "2north,4west"); m - map (map column x=0 is not used); @@ -5074,18 +5117,6 @@ next and previous targets, use a menu instead to pick a target. (default off) - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 78 - - - whatis_moveskip When getting a location on the map, and using shifted movement keys or meta-digit keys to fast-move, instead of moving 8 units at a @@ -5108,6 +5139,19 @@ Augment object descriptions with their objects' weight (default off). Debug mode only. + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 79 + + + zerocomp When writing out a save file, perform zero-comp compression of the contents. Not all ports support zero-comp compression. It has no ef- @@ -5140,18 +5184,6 @@ (letters and punctuation) rather than tiles graphics. In some cases, characters can be augmented with line-drawing symbols; use the symset option to select a symbol set such as DECgraphics or - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 79 - - - IBMgraphics if your display supports them. Setting ascii_map to True forces tiled_map to be False. @@ -5173,8 +5205,20 @@ windows. font_message - If NetHack can, it should use a font by the chosen name for the mes- - sage window. + If NetHack can, it should use a font by the chosen name for the + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 80 + + + + message window. font_status If NetHack can, it should use a font by the chosen name for the sta- @@ -5206,18 +5250,6 @@ guicolor Use color text and/or highlighting attributes when displaying some non-map data (such as menu selector letters). Curses interface - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 80 - - - only; default is on. large_font @@ -5240,6 +5272,18 @@ mance of the tile graphics, but uses more memory. (default on). Cannot be set with the `O' command. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 81 + + + scroll_amount If NetHack can, it should scroll the display by this number of cells when the hero reaches the scroll_margin. @@ -5273,17 +5317,6 @@ The curses interface does likewise if the align_status option is set to top or bottom but ignores statuslines when set to left or right. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 81 - - - The Qt interface already displays more than 3 lines for status so uses the statuslines value differently. A value of 3 renders status in the Qt interface's original format, with the status window spread @@ -5306,6 +5339,17 @@ Specify the name of an alternative tile file to override the de- fault. + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 82 + + + Note: the X11 interface uses X resources rather than NetHack's op- tions to select an alternate tile file. See NetHack.ad, the sample X "application defaults" file. @@ -5338,18 +5382,6 @@ persistent inventory window if enabled. Curses interface only. Ac- ceptable values are - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 82 - - - 0 - off, never show borders 1 - on, always show borders 2 - auto, on if display is at least (24+2)x(80+2) [default] @@ -5369,21 +5401,34 @@ umns. windowcolors - If NetHack can, it should display windows with the specified fore- - ground/background colors. Windows GUI only. The format is + If NetHack can, it should display all windows of a particular style + with the specified foreground and background colors. Windows GUI + and curses windowport only. The format is - OPTION=windowcolors:wintype foreground/background - 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 (active- - border, activecaption, appworkspace, background, btnface, btnshadow, - btntext, captiontext, graytext, greytext, highlight, highlighttext, - inactiveborder, inactivecaption, menu, menutext, scrollbar, window, - windowframe, windowtext). + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 83 + + + + OPTION=windowcolors:style foreground/background + + where style is one of "menu", "message", "status", or "text", and + foreground and background are colors, either numeric (hash sign fol- + lowed by three pairs of hexadecimal digits, #rrggbb), one of the + named colors (black, red, green, brown, blue, magenta, cyan, orange, + bright-green, yellow, bright-blue, bright-magenta, bright-cyan, + white, gray, purple, silver, maroon, fuchsia, lime, olive, navy, + teal, aqua), or (for Windows only) one of Windows UI colors (true- + black, activeborder, activecaption, appworkspace, background, btn- + face, btnshadow, btntext, captiontext, graytext, greytext, high- + light, highlighttext, inactiveborder, inactivecaption, menu, menu- + text, scrollbar, window, windowframe, windowtext). wraptext If NetHack can, it should wrap long lines of text if they don't fit @@ -5405,17 +5450,6 @@ and is only needed if your browser cannot handle arbitrarily long URLs. - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 83 - - - 9.7. Platform-specific Customization options Here are explanations of options that are used by specific plat- @@ -5436,6 +5470,18 @@ prior to a command--preceded by n if the number_pad option is set-- is also subject to this conversion, so attempting to abort the count by typing ESC will leave NetHack waiting for another character to + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 84 + + + complete the two character sequence. Type a second ESC to finish cancelling such a count. At other prompts a single ESC suffices. @@ -5469,19 +5515,6 @@ tempts "vesa", then "vga", and finally sets "default" if neither of those modes works. Cannot be set with the `O' command. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 84 - - - video_height Set the VGA mode resolution height (MS-DOS only, with video:vesa) @@ -5501,6 +5534,20 @@ cult to read, try adjusting these scales; if this does not correct the problem, try !color. Cannot be set with the `O' command. + + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 85 + + + 9.8. Regular Expressions Regular expressions are normally POSIX extended regular expres- @@ -5536,18 +5583,6 @@ they appear in your configuration file, thus allowing a later rule to override an earlier rule. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 85 - - - Exceptions can be set with the `O' command, but because they are not included in your configuration file, they won't be in effect if you save and then restore your game. autopickup_exception rules and not @@ -5564,6 +5599,21 @@ autopickup. The last example results in the exclusion of items known to be cursed from autopickup. + + + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 86 + + + 9.10. Changing Key Bindings It is possible to change the default key bindings of some special @@ -5602,18 +5652,6 @@ count Prefix key to start a count, to repeat a command this many times. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 86 - - - With number_pad only. Default is `n'. getdir.help @@ -5630,6 +5668,18 @@ getdir.self When asked for a direction, the key to target yourself. Default is + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 87 + + + `.'. getdir.self2 @@ -5667,19 +5717,6 @@ When asked for a location, the key to go to previous closest mon- ster. Default is `M'. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 87 - - - getpos.obj.next When asked for a location, the key to go to next closest object. Default is `o'. @@ -5698,6 +5735,17 @@ meta-digit keys to fast-move around, move by skipping the same glyphs instead of by 8 units. Default is `*'. + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 88 + + + getpos.filter When asked for a location, change the filtering mode when using one of the next or previous keys to cycle through targets. Toggles be- @@ -5733,19 +5781,6 @@ When asked for a location, the key to go to next closest unexplored location. Default is `x'. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 88 - - - getpos.unexplored.prev When asked for a location, the key to go to previous closest unex- plored location. Default is `X'. @@ -5762,6 +5797,21 @@ When asked for a location, the key to go to previous closest valid location. Default is `Z'. + + + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 89 + + + 9.11. Configuring Message Types You can change the way the messages are shown in the message @@ -5800,18 +5850,6 @@ Some platforms allow you to define colors used in menu lines when the line matches a user-defined pattern. At this time the tty, - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 89 - - - curses, win32tty and win32gui interfaces support this. In general, the configuration file entries to describe the menu @@ -5828,6 +5866,18 @@ The pattern should be a regular expression. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 90 + + + Allowed colors are black, red, green, brown, blue, magenta, cyan, gray, orange, light-green, yellow, light-blue, light-magenta, light- cyan, and white. And no-color, the default foreground color, which @@ -5866,18 +5916,6 @@ The following configuration file entries are relevant to mapping user sounds to messages: - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 90 - - - SOUNDDIR The directory that houses the sound files to be played. @@ -5894,6 +5932,18 @@ volume - the volume to be set while playing the sound file; sound index - optional; the index corresponding to a sound file. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 91 + + + The pattern should be a regular expression. For example: @@ -5932,18 +5982,6 @@ Allowed colors are black, red, green, brown, blue, magenta, cyan, gray, orange, light-green, yellow, light-blue, light-magenta, light- - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 91 - - - cyan, and white. And "no-color", the default foreground color on the display, which is not necessarily the same as black or white or any of the other colors. @@ -5959,12 +5997,24 @@ Note that the display may substitute or ignore particular at- tributes depending upon its capabilities, and in general may interpret the attributes any way it wants. For example, on some display systems - a request for bold might yield blink or vice versa. On others, issu- - ing an attribute request while another is already set up will replace - the earlier attribute rather than combine with it. Since NetHack is- - sues attribute requests sequentially (at least with the tty interface) - rather than all at once, the only way a situation like that can be - controlled is to specify just one attribute. + a request for bold might yield blink or vice versa. On others, + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 92 + + + + issuing an attribute request while another is already set up will re- + place the earlier attribute rather than combine with it. Since + NetHack issues attribute requests sequentially (at least with the tty + interface) rather than all at once, the only way a situation like that + can be controlled is to specify just one attribute. You can adjust the appearance of the following status fields: title dungeon-level experience-level @@ -5998,18 +6048,6 @@ * "always" will set the default attributes for that field. - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 92 - - - * "up", "down" set the field attributes for when the field value changes upwards or downwards. This attribute times out after statushilites turns. @@ -6026,6 +6064,18 @@ prefixed with `<=' or `>=', it also matches when value is below or above the percentage. Use prefix `<' or `>' to match when strictly below or above. (The numeric limit is relaxed + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 93 + + + slightly for those: >-1% and <101% are allowed.) Only four fields support percentage rules. Percentages for "hitpoints" and "power" are straightforward; they're based on the corre- @@ -6063,19 +6113,6 @@ The in-game options menu can help you determine the correct syn- tax for a configuration file. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 93 - - - The whole feature can be disabled by setting option statushilites to 0. @@ -6094,6 +6131,17 @@ + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 94 + + + 9.15. Modifying NetHack Symbols NetHack can load entire symbol sets from the symbol file. @@ -6129,19 +6177,6 @@ [ S_armor (suit or piece of armor) [ S_armour (suit or piece of armor) ^ S_arrow_trap (arrow trap) - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 94 - - - 0 S_ball (iron ball) # S_bars (iron bars) B S_bat (bat or bird) @@ -6160,6 +6195,19 @@ C S_centaur (centaur) _ S_chain (iron chain) # S_cloud (cloud) + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 95 + + + c S_cockatrice (cockatrice) $ S_coin (pile of coins) # S_corr (corridor) @@ -6195,19 +6243,6 @@ S_ghost (ghost) H S_giant (giant humanoid) G S_gnome (gnome) - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 95 - - - ' S_golem (golem) | S_grave (grave) g S_gremlin (gremlin) @@ -6226,6 +6261,19 @@ J S_jabberwock (jabberwock) j S_jelly (jelly) k S_kobold (kobold) + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 96 + + + K S_kop (Keystone Kop) ^ S_land_mine (land mine) } S_lava (molten lava) @@ -6261,19 +6309,6 @@ r S_rodent (rodent) ^ S_rolling_boulder_trap (rolling boulder trap) . S_room (floor of a room) - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 96 - - - / S_rslant (diagonal beam [zap animation]) ^ S_rust_trap (rust trap) R S_rustmonst (rust monster or disenchanter) @@ -6292,6 +6327,19 @@ S_stone (solid rock) ] S_strange_obj (strange object) - S_sw_bc (swallow bottom center) + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 97 + + + \ S_sw_bl (swallow bottom left) / S_sw_br (swallow bottom right) | S_sw_ml (swallow middle left) @@ -6327,19 +6375,6 @@ - S_vodoor (open door in vertical wall) v S_vortex (vortex) | S_vwall (vertical wall) - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 97 - - - / S_wand (wand) } S_water (water) ) S_weapon (weapon) @@ -6359,6 +6394,18 @@ * Several symbols in this table appear to be blank. They are the space character, except for S_pet_override and S_hero_override which + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 98 + + + don't have any default value and can only be used if enabled in the "sysconf" file. @@ -6393,20 +6440,8 @@ The list of acceptable glyphid's can be produced by nethack --dumpg- lyphids. Individual NetHack glyphs can be specified using the G_ pre- fix, or you can use an S_ symbol for a glyphid and store the custom - representation for all NetHack glyphs that would map to that - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 98 - - - - particular symbol. + representation for all NetHack glyphs that would map to that particu- + lar symbol. You will need to select a symset with a UTF8 handler to enable the display of the customizations, such as the Enhanced symset. @@ -6425,6 +6460,18 @@ an idea what the screen layout is like. You'll also need to be able to locate the PC cursor. It is always where your character is located. Merely searching for an @-sign will not always find your character + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 99 + + + since there are other humanoids represented by the same sign. Your screen-reader should also have a function which gives you the row and column of your review cursor and the PC cursor. These co-ordinates @@ -6459,19 +6506,6 @@ paranoid_confirmation:swim Prevent walking into water or lava. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 99 - - - accessiblemsg Adds direction or location information to messages. @@ -6493,6 +6527,17 @@ Give feedback messages when walking towards a wall or when travel command was interrupted. + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 100 + + + whatis_coord:compass When targeting with cursor, describe the cursor position with coor- dinates relative to your character. @@ -6526,18 +6571,6 @@ WIZARDS = A space-separated list of user names 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 - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 100 - - - mode. SHELLERS = A list of users who are allowed to use the shell escape @@ -6559,6 +6592,18 @@ BONESFORMAT = A list of up to two bones file formats separated by space. The first format in the list will written as well as read. + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 101 + + + The second format will be read only if no bones files in the first format exist. Valid choices are "historical" for binary writing of entire structs, "lendian" for binary writing of each field in lit- @@ -6591,19 +6636,6 @@ POINTSMIN = Minimum number of points to get an entry in the score file. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 101 - - - PERS_IS_UID = 0 or 1 to use user names or numeric userids, respec- tively, to identify unique people for the score file. @@ -6626,6 +6658,18 @@ available if your game is compiled with DUMPLOG. Allows the follow- ing placeholders: + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 102 + + + %% - literal `%' %v - version (eg. "3.7.0-0") %u - game UID @@ -6657,23 +6701,11 @@ 10. Scoring NetHack maintains a list of the top scores or scorers on your ma- - chine, depending on how it is set up. In the latter case, each - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 102 - - - - account on the machine can post only one non-winning score on this - list. If you score higher than someone else on this list, or better - your previous score, you will be inserted in the proper place under - your current name. How many scores are kept can also be set up when + chine, depending on how it is set up. In the latter case, each ac- + count on the machine can post only one non-winning score on this list. + If you score higher than someone else on this list, or better your + previous score, you will be inserted in the proper place under your + current name. How many scores are kept can also be set up when NetHack is compiled. Your score is chiefly based upon how much experience you gained, @@ -6689,6 +6721,21 @@ If you just want to see what the current top players/games list is, you can type nethack -s all on most versions. + + + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 103 + + + 11. Explore mode NetHack is an intricate and difficult game. Novices might falter @@ -6723,19 +6770,6 @@ start a game in debug mode when not allowed or not available will re- sult in falling back to explore mode instead. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 103 - - - 12. Credits The original hack game was modeled on the Berkeley UNIX rogue @@ -6756,6 +6790,18 @@ on UNIX systems by posting that to Usenet newsgroup net.sources (later renamed comp.sources) releasing version 1.0 in December of 1984, then versions 1.0.1, 1.0.2, and finally 1.0.3 in July of 1985. Usenet + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 104 + + + newsgroup net.games.hack (later renamed rec.games.hack, eventually re- placed by rec.games.roguelike.nethack) was created for discussing it. @@ -6790,18 +6836,6 @@ Meluch, Stephen Spackman and Pierre Martineau designed overlay code for PC NetHack 3.0. Johnny Lee ported NetHack 3.0 to the Macintosh. Along with various other Dungeoneers, they continued to enhance the - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 104 - - - PC, Macintosh, and Amiga ports through the later revisions of 3.0. Version 3.0 went through ten relatively rapidly released "patch- @@ -6821,6 +6855,19 @@ quests, a new endgame and many other new features, and produced NetHack 3.1. Version 3.1.0 was released in January of 1993. + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 105 + + + Ken Lorber, Gregg Wonderly and Greg Olson, with help from Richard Addison, Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for the Amiga. @@ -6856,18 +6903,6 @@ Team which rechristened them "tiles", original usage which has subse- quently been picked up by various other games. NetHack's tiles sup- port was then implemented on other platforms (initially MS-DOS but - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 105 - - - eventually Windows, Qt, and X11 too). The 3.2 NetHack Development Team, comprised of Michael Allison, @@ -6887,6 +6922,18 @@ Version 3.2 proved to be more stable than previous versions. Many bugs were fixed, abuses eliminated, and game features tuned for + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 106 + + + better game play. During the lifespan of NetHack 3.1 and 3.2, several enthusiasts @@ -6922,18 +6969,6 @@ trieval of old character names to use for random ghost and statue names in the current game.) - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 106 - - - The 3.3 NetHack Development Team, consisting of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lorber, Dean Luick, Pat @@ -6952,6 +6987,19 @@ growing bug list, 3.3 proved stable enough to last for more than a year and a half. + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 107 + + + The 3.4 NetHack Development Team initially consisted of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo, Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul @@ -6987,19 +7035,6 @@ Christian "Marvin" Bressler maintained 3.4 for the Atari after he resurrected it for 3.3.1. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 107 - - - The release of NetHack 3.4.3 in December 2003 marked the begin- ning of a long release hiatus. 3.4.3 proved to be a remarkably stable version that provided continued enjoyment by the community for more @@ -7019,6 +7054,18 @@ on that code snapshot would be retired and never used in an official NetHack release. An announcement was posted on the NetHack Develop- ment Team's official nethack.org website to that effect, stating that + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 108 + + + there would never be a 3.4.4, 3.5, or 3.5.0 official release version. In January 2015, preparation began for the release of NetHack @@ -7053,19 +7100,6 @@ Kompel, Dion Nicolaas, Derek S. Ray and Yitzhak Sapir maintained the port of NetHack 3.6 for Microsoft Windows. - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 108 - - - Pat Rankin attempted to keep the VMS port running for NetHack 3.6, hindered by limited access. Kevin Smolkowski has updated and tested it for the most recent version of OpenVMS (V8.4 as of this @@ -7085,6 +7119,19 @@ In early May 2019, another 320 bug fixes along with some enhance- ments and the adopted curses window port, were released as 3.6.2. + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 109 + + + Bart House, who had contributed to the game as a porting team participant for decades, joined the NetHack Development Team in late May 2019. @@ -7119,19 +7166,6 @@ vnull.net (gone for now, but not forgotten). - - - - NetHack 3.7.0 February 29, 2024 - - - - - - NetHack Guidebook 109 - - - 12.2. Dungeoneers From time to time, some depraved individual out there in netland @@ -7151,6 +7185,19 @@ Benson I. Margulies Johnny Lee Ralf Brown Bill Dyer Jon W{tte Ray Chason Boudewijn Waijers Jonathan Handler Richard Addison + + + + NetHack 3.7.0 July 29, 2024 + + + + + + NetHack Guidebook 110 + + + Bruce Cox Joshua Delahunty Richard Beigel Bruce Holloway Karl Garrison Richard P. Hughey Bruce Mewborne Keizo Yamamoto Rob Menke @@ -7188,7 +7235,26 @@ of their respective holders. - NetHack 3.7.0 February 29, 2024 + + + + + + + + + + + + + + + + + + + + NetHack 3.7.0 July 29, 2024 diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 23782811f..8ff5c8116 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1445 $ $NHDT-Date: 1718303201 2024/06/13 18:26:41 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1472 $ $NHDT-Date: 1725143669 2024/08/31 22:34:29 $ General Fixes and Modified Features ----------------------------------- @@ -1162,6 +1162,8 @@ prevent hug attacks and touch or engulf attacks for wrap, stick-to, and vortices, a few others) or against worm tails wand of speed gives temporary speed, potion gives intrinsic some monsters (riders, shopkeepers, priests, quest leader) can break boulders +if hero owes shop for a boulder and shopkeeper breaks it, continue to bill hero + for the boulder rather than switching to the resulting rocks corpse-eating monsters will go out of their way to eat corpses on the floor warnings via impossible() would be unseen if message suppression via ESC at --More-- prompt was in effect @@ -1401,6 +1403,7 @@ gold thrown or kicked at a sleeping monster with the 'greedy' attribute gets neglected to report that target monster was awakened in the process hero movement affects the water bubble movement direction pets and peacefuls avoid a location hero just kicked +pets avoid a possible boulder pushing location in sokoban shopkeepers bill you for using their bear trap or land mine when engraving with a stack of eligible weapons, split one off the stack and dull it rather than dull the whole stack @@ -1422,6 +1425,48 @@ if hero is on scroll of scare monster or Elbereth, werecreature switching from "n ESC c" wasn't treated as "n M-c" because reading the 'n' changed program_state.input_state from commandInp to otherInp, preventing special ESC handling; not an issue when number_pad was Off +a 3.6 fix to avoid a potential "object lost" panic when drinking potions had + unintended side-effect of making used up potions on shop's bill become + separate bill entries all with count 1 despite having come from same + unpaid stack; affected Ix inventory listing and itemized shop billing +buying shop items which include any unpaid ones inside containers would reveal + them even when the containers hadn't been opened (obj->cknown==0); + recent change to pay via menu made the problem become more visible; + shopping has been changed such that buying anything that is inside a + container requires that the whole container be bought as a unit +using #loot -> 'i'n to put multiple items into a shop-owned container would + ask whether to sell each item to the shop, and was prepared to accept + 'a' to sell the current one plus all the rest beyond it, or to accept + 'q' to not sell the current one or any beyond it, but the sell vs + don't-sell state was being reset for each item so 'a' and 'q' didn't + stick beyond the current one +join wall "spines" with walls of water and lava +some theft messages by nymphs force "she", others use default monster naming + which yields "it" when unseen; change the latter to "someone" which + still differs from "she" in a series of messages but isn't as jarring +if a nymph stole worn armor and got killed (perhaps by pet) before hero's next + turn, feedback would be "You finish taking off your suit." regardless + of the type of armor being taken off +when setting an option interactively [via O or 3.7's mO], if the particular + option uses a prompt to get a line of input (for compounds: 'fruit', + 'scores', most numeric ones), input was treated as a comma-separated + list of option[:value] rather than just the new value of that option +when there was a trap on a no-dig level, the floor beneath it was always + "too hard to dig into", making it impossible to remove the trap +the #terrain command didn't know how to cope with visible gas/cloud regions; + treat as traps as far as player choice of whether to show or hide; + if/when a spot contains both region and trap, show the trap +region expiration reported "the gas cloud around you dissipates" even when the + hero was swallowed +region expiration could report "the gas cloud around you dissipates" and also + "you see a gas cloud dissipate" for the same cloud spot +reduce shopkeeper's innate speed from 18 to 16 so that a hasted shopkeeper + doesn't always get 2 moves per turn +when a secret corridor was discovered by wand of secret door detection or by + wizard mode ^E and converted into a regular corridor, if there was a + formerly embedded object at the spot, presence of the object would be + forgotten unless within range of a light source +when poly'd into a giant, kicking a closed door always succeeds in breaking it Fixes to 3.7.0-x General Problems Exposed Via git Repository @@ -1967,6 +2012,23 @@ fix regression of a post-3.6 fix: if 2 Wizards of Yendor were in play and 1 sometimes a repeat count from the preceding command carried over to most recent one when using do-again (^A); if the most recent one was an extended command, the spurious repeat was for '#' +if peaceful monsters react when seeing hero attack a peaceful monster, don't + have quest guardians run away; also, quest leader only becomes angry + if the monster being attacked is a quest guardian +farlook of water/lava location listed wall of lava before molten lava; because + of that, lava was omitted ("molten" suppressed to reduce vebosity, + resulting in "lava" which got skipped as substring of "wall of lava") +having #terrain display gas cloud regions as if they were traps didn't work + for monsters in such regions that are shown when adjacent to hero or + sensed via ESP +when a monster within a gas cloud was displayed on the map because the hero + was next to it, it remained displayed if hero moved away +eating a pyrolisk egg on the floor triggered an "object lost" panic +core object creation and the curses interface's window handling both became + confused by the 'pauper' option/conduct because they assumed that invent + being Null meant that the game hadn't started yet +wizards were discovering unread spellbooks whenever any skill was advanced; do so + only when a spell skill is advanced Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository @@ -2505,6 +2567,8 @@ paranoid_confirm:swim to prevent accidental dunking into dangerous liquids; paranoid_confirm:trap to confirm entering a known trap unless it is harmless; like revised paranoid_confirm:pray, requires y/n response; add paranoid_confirm:Confirm to require yes/no instead +extend 'paranoid_confirm:trap' to request confirmation when entering visible + gas cloud regions paranoid_confirm:Autoall to confirm picking 'A' in menustyle:Full filter menu looking at a monster will indicate whether it is asleep, and waking up a monster yields a message @@ -2538,6 +2602,8 @@ for ranger characters, shooting any type of arrow while wielding the Longbow change the #vanquished command from debug-only to general user command add 'sortvanquished' option to be able to set the preferred sort order without using 'm #vanquished' and to have it persist across save/restore +when sorting vanquished monsters by monster class, treat the Riders as a + separate class from major demons add #genocided command have 'I u' mention whether there are any unpaid items on the floor (unusual but not impossible); it doesn't itemize them or show shop price @@ -2606,6 +2672,9 @@ if hero is punished or tethered to a buried iron ball and has no inventory (or during streaming video 'query_menu' option to use a menu when asked certain yes/no questions pyrolisk eggs explode when broken +pauper-option to start the character with no possessions +wand of secret door detection, spell of detect unseen, and wizard mode ^E now + flash the cursor at each location where detection finds something Platform- and/or Interface-Specific New Features diff --git a/include/align.h b/include/align.h index 538ac4047..0ccaf0e4d 100644 --- a/include/align.h +++ b/include/align.h @@ -14,7 +14,7 @@ typedef struct align { /* alignment & record */ } align; /* bounds for "record" -- respect initial alignments of 10 */ -#define ALIGNLIM (10L + (gm.moves / 200L)) +#define ALIGNLIM (10L + (svm.moves / 200L)) #define A_NONE (-128) /* the value range of type */ diff --git a/include/context.h b/include/context.h index 167885d6c..ab9baf3bb 100644 --- a/include/context.h +++ b/include/context.h @@ -142,7 +142,7 @@ struct context_info { * 3: FH, 4: ff+, 5: ff-, 6: FF+, 7: FF-, * 8: travel */ unsigned startingpet_mid; /* monster id number for initial pet */ - int current_fruit; /* fruit->fid corresponding to gp.pl_fruit[] */ + int current_fruit; /* fruit->fid corresponding to svp.pl_fruit[] */ int mysteryforce; /* adjusts how often "mysterious force" kicks in */ int rndencode; /* randomized escape sequence introducer */ int warnlevel; /* threshold (digit) to warn about unseen mons */ diff --git a/include/decl.h b/include/decl.h index 2b1cff207..1a63ea1a6 100644 --- a/include/decl.h +++ b/include/decl.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 decl.h $NHDT-Date: 1706079834 2024/01/24 07:03:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.355 $ */ +/* NetHack 3.7 decl.h $NHDT-Date: 1720074483 2024/07/04 06:28:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.373 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2007. */ /* NetHack may be freely redistributed. See license for details. */ @@ -194,13 +194,9 @@ struct instance_globals_b { #endif /* decl.c */ - int bases[MAXOCLASSES + 1]; coord bhitpos; /* place where throw or zap hits or stops */ struct obj *billobjs; /* objects not yet paid for */ - /* dungeon.c */ - branch *branches; /* dungeon branch list */ - /* files.c */ char bones[BONESSIZE]; @@ -212,7 +208,6 @@ struct instance_globals_b { /* mkmaze.c */ lev_region bughack; /* for preserving the insect legs when wallifying * baalz level */ - struct bubble *bbubbles; /* pickup.c */ boolean bucx_filter; @@ -253,7 +248,6 @@ struct instance_globals_c { #ifdef DEF_PAGER const char *catmore; /* external pager; from getenv() or DEF_PAGER */ #endif - struct context_info context; /* dog.c */ char catname[PL_PSIZ]; @@ -317,12 +311,7 @@ struct instance_globals_d { long domove_succeeded; #define DOMOVE_WALK 0x00000001 #define DOMOVE_RUSH 0x00000002 - dungeon dungeons[MAXDUNGEON]; /* ini'ed by init_dungeon() */ - dest_area dndest; boolean defer_see_monsters; - struct dgn_topology dungeon_topology; - int doors_alloc; /* doors-array allocated size */ - coord *doors; /* array of door locations */ /* dig.c */ boolean did_dig_msg; @@ -341,9 +330,6 @@ struct instance_globals_d { /* mon.c */ boolean disintegested; - /* o_init.c */ - short disco[NUM_OBJECTS]; - /* objname.c */ /* distantname used by distant_name() to pass extra information to xname_flags(); it would be much cleaner if this were a parameter, @@ -372,7 +358,6 @@ struct instance_globals_e { struct bubble *ebubbles; /* new stuff */ - struct exclusion_zone *exclusion_zones; int early_raw_messages; /* if raw_prints occurred early prior to gb.beyond_savefile_load */ @@ -457,7 +442,6 @@ struct instance_globals_h { /* decl.c */ const char *hname; /* name of the game (argv[0] of main) */ - int hackpid; /* current process id */ #if defined(MICRO) || defined(WIN32) char hackdir[PATHLEN]; /* where rumors, help, record are */ #endif /* MICRO || WIN32 */ @@ -479,7 +463,6 @@ struct instance_globals_i { /* decl.c */ int in_doagain; - coord inv_pos; boolean in_mklev; boolean in_steed_dismounting; struct obj *invent; @@ -525,7 +508,6 @@ struct instance_globals_k { /* decl.c */ struct obj *kickedobj; /* object in flight due to kicking */ - struct kinfo killer; /* read.c */ boolean known; @@ -540,9 +522,6 @@ struct instance_globals_l { cmdcount_nht last_command_count; /* decl.c (before being incorporated into instance_globals_*) */ - schar lastseentyp[COLNO][ROWNO]; /* last seen/touched dungeon typ */ - struct linfo level_info[MAXLINFO]; - dlevel_t level; /* level map */ #if defined(UNIX) || defined(VMS) int locknum; /* max num of simultaneous users */ #endif @@ -620,20 +599,15 @@ struct instance_globals_m { struct multishot m_shot; boolean mrg_to_wielded; /* weapon picked is merged with wielded one */ struct menucoloring *menu_colorings; - long moves; /* turn counter */ struct obj *migrating_objs; /* objects moving to another dungeon level */ /* dog.c */ struct monst *mydogs; /* monsters that went down/up together with @ */ struct monst *migrating_mons; /* monsters moving to another level */ - struct mvitals mvitals[NUMMONS]; /* dokick.c */ struct rm *maploc; - /* dungeon.c */ - mapseen *mapseenchn; /*DUNGEON_OVERVIEW*/ - /* mhitu.c */ int mhitu_dieroll; @@ -682,15 +656,11 @@ struct instance_globals_n { /* decl.c */ const char *nomovemsg; - int nroom; int nsubroom; /* dokick.c */ struct rm nowhere; - /* dungeon.c */ - int n_dgns; /* number of dungeons (also used in mklev.c and do.c) */ - /* files.c */ int nesting; int no_sound_notified; /* run-time option processing: warn once if built @@ -713,9 +683,6 @@ struct instance_globals_n { /* questpgr.c */ char nambuf[CVT_BUF_SIZE]; - /* region.c */ - int n_regions; - /* restore.c */ int n_ids_mapped; @@ -779,7 +746,6 @@ struct instance_globals_o { /* rumors.c */ int oracle_flg; /* -1=>don't use, 0=>need init, 1=>init done */ - unsigned oracle_cnt; /* oracles are handled differently from rumors... */ unsigned long *oracle_loc; /* uhitm.c */ @@ -799,13 +765,9 @@ struct instance_globals_p { int polearm_range_max; /* decl.c */ - char plname[PL_NSIZ]; /* player name */ int plnamelen; /* length of plname[] if that came from getlogin() */ - char pl_character[PL_CSIZ]; char pl_race; /* character's race */ - char pl_fruit[PL_FSIZ]; struct plinemsg_type *plinemsg_types; - struct sinfo program_state; /* flags describing game's current state */ /* dog.c */ int petname_used; /* user preferred pet name has been used */ @@ -849,18 +811,12 @@ struct instance_globals_p { struct instance_globals_q { - /* quest.c */ - struct q_score quest_status; - boolean havestate; unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_r { - /* decl.c */ - struct mkroom rooms[(MAXNROFROOMS + 1) * 2]; - /* symbols.c */ nhsym rogue_syms[SYM_MAX]; /* loaded rogue symbols */ @@ -895,11 +851,9 @@ struct instance_globals_s { messages in artifact_hit() */ /* decl.c */ - s_level * sp_levchn; stairway *stairs; int smeq[MAXNROFROOMS + 1]; boolean stoned; /* done to monsters hit by 'c' */ - struct spell spl_book[MAXSPELL + 1]; struct mkroom *subrooms; /* do.c */ @@ -937,6 +891,7 @@ struct instance_globals_s { boolean simple_options_help; /* pickup.c */ + boolean sellobj_first; /* True => need sellobj_state(); False => don't */ boolean shop_filter; /* pline.c */ @@ -957,7 +912,7 @@ struct instance_globals_s { /* spells.c */ int spl_sortmode; /* index into spl_sortchoices[] */ - int *spl_orderindx; /* array of gs.spl_book[] indices */ + int *spl_orderindx; /* array of svs.spl_book[] indices */ /* steal.c */ unsigned int stealoid; /* object to be stolen */ @@ -976,7 +931,6 @@ struct instance_globals_t { struct trapinfo trapinfo; /* decl.c */ - char tune[6]; schar tbx; /* mthrowu: target x */ schar tby; /* mthrowu: target y */ char toplines[TBUFSZ]; @@ -1011,7 +965,6 @@ struct instance_globals_t { /* timeout.c */ /* ordered timer list */ struct fe *timer_base; /* "active" */ - unsigned long timer_id; /* topten.c */ winid toptenwin; @@ -1029,7 +982,6 @@ struct instance_globals_u { boolean update_all; /* decl.c */ - dest_area updest; boolean unweapon; /* role.c */ @@ -1114,9 +1066,6 @@ struct instance_globals_x { /* lock.c */ struct xlock_s xlock; - /* mkmaze.c */ - int xmin, xmax; /* level boundaries x */ - /* objnam.c */ char *xnamep; /* obuf[] returned by xname(), for use in doname() for * bounds checking; differs from xname() return value @@ -1136,9 +1085,6 @@ struct instance_globals_y { int y_maze_max; struct monst youmonst; - /* mkmaze.c */ - int ymin, ymax; /* level boundaries y */ - /* pline.c */ /* work buffer for You(), &c and verbalize() */ char *you_buf; @@ -1168,6 +1114,126 @@ struct instance_globals_z { unsigned long magic; /* validate that structure layout is preserved */ }; +struct instance_globals_saved_b { + /* dungeon.c */ + branch *branches; /* dungeon branch list */ + /* mkmaze.c */ + struct bubble *bbubbles; + /* o_init.c */ + int bases[MAXOCLASSES + 2]; /* make bases[MAXOCLASSES+1] available */ +}; + +struct instance_globals_saved_c { + /* decl.c */ + struct context_info context; +}; + +struct instance_globals_saved_d { + /* dungeon.c */ + dungeon dungeons[MAXDUNGEON]; /* ini'ed by init_dungeon() */ + struct dgn_topology dungeon_topology; + /* decl.c */ + dest_area dndest; + coord *doors; /* array of door locations */ + int doors_alloc; /* doors-array allocated size */ + /* o_init.c */ + short disco[NUM_OBJECTS]; +}; + +struct instance_globals_saved_e { + /* decl.c */ + struct exclusion_zone *exclusion_zones; +}; + +struct instance_globals_saved_h { + /* decl.c */ + int hackpid; /* current process id */ +}; + +struct instance_globals_saved_i { + /* decl.c */ + coord inv_pos; +}; + +struct instance_globals_saved_k { + /* decl.c */ + struct kinfo killer; +}; + +struct instance_globals_saved_l { + /* decl.c */ + schar lastseentyp[COLNO][ROWNO]; /* last seen/touched dungeon typ */ + dlevel_t level; /* level map */ + struct linfo level_info[MAXLINFO]; +}; + +struct instance_globals_saved_m { + /* dungeon.c */ + mapseen *mapseenchn; /*DUNGEON_OVERVIEW*/ + /* decl.c */ + long moves; /* turn counter */ + struct mvitals mvitals[NUMMONS]; +}; + +struct instance_globals_saved_n { + /* dungeon.c */ + int n_dgns; /* number of dungeons (also used in mklev.c and do.c) */ + /* mkroom.c */ + int nroom; + /* region.c */ + int n_regions; +}; + +struct instance_globals_saved_o { + /* rumors.c */ + unsigned oracle_cnt; /* oracles are handled differently from rumors... */ +}; + +struct instance_globals_saved_p { + /* decl.c */ + char plname[PL_NSIZ]; /* player name */ + char pl_character[PL_CSIZ]; + char pl_fruit[PL_FSIZ]; +}; + +struct instance_globals_saved_q { + /* quest.c */ + struct q_score quest_status; +}; + +struct instance_globals_saved_r { + /* mkroom.c */ + struct mkroom rooms[(MAXNROFROOMS + 1) * 2]; +}; + +struct instance_globals_saved_s { + /* decl.c */ + struct spell spl_book[MAXSPELL + 1]; + s_level *sp_levchn; +}; + +struct instance_globals_saved_t { + /* decl.c */ + char tune[6]; + /* timeout.c */ + unsigned long timer_id; +}; + +struct instance_globals_saved_u { + /* decl.c */ + dest_area updest; +}; + +struct instance_globals_saved_x { + /* mkmaze.c */ + int xmin, xmax; /* level boundaries x */ +}; + +struct instance_globals_saved_y { + /* mkmaze.c */ + int ymin, ymax; /* level boundaries y */ +}; + extern struct instance_globals_a ga; extern struct instance_globals_b gb; extern struct instance_globals_c gc; @@ -1194,6 +1260,26 @@ extern struct instance_globals_w gw; extern struct instance_globals_x gx; extern struct instance_globals_y gy; extern struct instance_globals_z gz; +extern struct instance_globals_saved_b svb; +extern struct instance_globals_saved_c svc; +extern struct instance_globals_saved_d svd; +extern struct instance_globals_saved_e sve; +extern struct instance_globals_saved_h svh; +extern struct instance_globals_saved_i svi; +extern struct instance_globals_saved_k svk; +extern struct instance_globals_saved_l svl; +extern struct instance_globals_saved_m svm; +extern struct instance_globals_saved_n svn; +extern struct instance_globals_saved_o svo; +extern struct instance_globals_saved_p svp; +extern struct instance_globals_saved_q svq; +extern struct instance_globals_saved_r svr; +extern struct instance_globals_saved_s svs; +extern struct instance_globals_saved_t svt; +extern struct instance_globals_saved_u svu; +extern struct instance_globals_saved_x svx; +extern struct instance_globals_saved_y svy; +extern struct sinfo program_state; /* flags describing game's current state */ struct const_globals { const struct obj zeroobj; /* used to zero out a struct obj */ diff --git a/include/defsym.h b/include/defsym.h index f51fd96ae..3370f6d2d 100644 --- a/include/defsym.h +++ b/include/defsym.h @@ -1,8 +1,7 @@ -/* NetHack 3.7 defsym.h */ +/* NetHack 3.7 defsym.h $NHDT-Date: 1720565306 2024/07/09 22:48:26 $ $NHDT-Branch: NetHack-3.7 $ $NHDT-Revision: 1.24 $ */ /* Copyright (c) 2016 by Pasi Kallinen */ /* NetHack may be freely redistributed. See license for details. */ - /* This header is included in multiple places to produce different code depending on its use. Its purpose is to @@ -131,6 +130,7 @@ PCHAR2(35, '\\', S_throne, "throne", "opulent throne", HI_GOLD) PCHAR( 36, '{', S_sink, "sink", CLR_WHITE) PCHAR( 37, '{', S_fountain, "fountain", CLR_BRIGHT_BLUE) + /* the S_pool symbol is used for both POOL terrain and MOAT terrain */ PCHAR2(38, '}', S_pool, "pool", "water", CLR_BLUE) PCHAR( 39, '.', S_ice, "ice", CLR_CYAN) PCHAR( 40, '}', S_lava, "molten lava", CLR_RED) @@ -145,6 +145,8 @@ "raised drawbridge", CLR_BROWN) PCHAR( 46, ' ', S_air, "air", CLR_CYAN) PCHAR( 47, '#', S_cloud, "cloud", CLR_GRAY) + /* the S_water symbol is used for WATER terrain: wall of water in the + dungeon and Plane of Water in the endgame */ PCHAR( 48, '}', S_water, "water", CLR_BRIGHT_BLUE) /* end dungeon characters */ /* */ diff --git a/include/display.h b/include/display.h index 649ca6837..e15f06285 100644 --- a/include/display.h +++ b/include/display.h @@ -19,7 +19,7 @@ * Returns the head of the list of objects that the player can see * at location (x,y). [Vestige of unimplemented invisible objects.] */ -#define vobj_at(x, y) (gl.level.objects[x][y]) +#define vobj_at(x, y) (svl.level.objects[x][y]) /* * sensemon() @@ -63,7 +63,7 @@ */ #define _mon_warning(mon) \ (Warning && !(mon)->mpeaceful && (mdistu(mon) < 100) \ - && (((int) ((mon)->m_lev / 4)) >= gc.context.warnlevel)) + && (((int) ((mon)->m_lev / 4)) >= svc.context.warnlevel)) /* * mon_visible() @@ -820,7 +820,7 @@ enum glyph_offsets { expression but there will always be sequence points in between */ #define obj_is_piletop(obj) \ ((obj)->where == OBJ_FLOOR \ - && (go.otg_otmp = gl.level.objects[(obj)->ox][(obj)->oy]->nexthere) != 0 \ + && (go.otg_otmp = svl.level.objects[(obj)->ox][(obj)->oy]->nexthere) != 0 \ && ((obj)->otyp != BOULDER || go.otg_otmp->otyp == BOULDER)) /* used to hide info such as potion and gem color when not seen yet; stones and rock are excluded for gem class; LAST_SPELL includes blank diff --git a/include/dungeon.h b/include/dungeon.h index 11efc6053..60b3cd6ab 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -246,7 +246,7 @@ typedef struct mapseen { struct mapseen_rooms { Bitfield(seen, 1); Bitfield(untended, 1); /* flag for shop without shk */ - } msrooms[(MAXNROFROOMS + 1) * 2]; /* same size as gr.rooms[] */ + } msrooms[(MAXNROFROOMS + 1) * 2]; /* same size as svr.rooms[] */ /* dead heroes; might not have graves or ghosts */ struct cemetery *final_resting_place; /* same as level.bonesinfo */ } mapseen; diff --git a/include/extern.h b/include/extern.h index 5391be599..d9a91b52f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 extern.h $NHDT-Date: 1718303205 2024/06/13 18:26:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1426 $ */ +/* NetHack 3.7 extern.h $NHDT-Date: 1723580890 2024/08/13 20:28:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1435 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -428,7 +428,6 @@ extern void end_of_input(void); #endif extern char readchar(void); extern char readchar_poskey(coordxy *, coordxy *, int *); -extern void sanity_check(void); extern char* key2txt(uchar, char *); extern char yn_function(const char *, const char *, char, boolean); extern char paranoid_ynq(boolean, const char *, boolean); @@ -499,7 +498,9 @@ extern int wiz_mgender(void); extern int dig_typ(struct obj *, coordxy, coordxy); extern boolean is_digging(void); extern int holetime(void); -extern boolean dig_check(struct monst *, boolean, coordxy, coordxy); +extern enum digcheck_result dig_check(struct monst *, coordxy, coordxy); +extern void digcheck_fail_message(enum digcheck_result, struct monst *, + coordxy, coordxy); extern void digactualhole(coordxy, coordxy, struct monst *, int); extern boolean dighole(boolean, boolean, coord *); extern int use_pick_axe(struct obj *) NONNULLARG1; @@ -650,6 +651,7 @@ extern char *Some_Monnam(struct monst *) NONNULLARG1; extern char *noname_monnam(struct monst *, int) NONNULLARG1; extern char *m_monnam(struct monst *) NONNULLARG1; extern char *y_monnam(struct monst *) NONNULLARG1; +extern char *YMonnam(struct monst *) NONNULLARG1; extern char *Adjmonnam(struct monst *, const char *) NONNULLARG1; extern char *Amonnam(struct monst *) NONNULLARG1; extern char *a_monnam(struct monst *) NONNULLARG1; @@ -1755,7 +1757,7 @@ extern void kill_genocided_monsters(void); extern void golemeffects(struct monst *, int, int); extern boolean angry_guards(boolean); extern void pacify_guards(void); -extern void decide_to_shapeshift(struct monst *, int) NONNULLARG1; +extern void decide_to_shapeshift(struct monst *) NONNULLARG1; extern boolean vamp_stone(struct monst *) NONNULLARG1; extern void check_gear_next_turn(struct monst *) NONNULLARG1; extern void copy_mextra(struct monst *, struct monst *); @@ -1850,6 +1852,7 @@ extern void m_break_boulder(struct monst *, coordxy, coordxy) NONNULLARG1; extern int dochug(struct monst *) NONNULLARG1; extern boolean m_digweapon_check(struct monst *, coordxy, coordxy) NONNULLARG1; extern boolean m_avoid_kicked_loc(struct monst *, coordxy, coordxy) NONNULLARG1; +extern boolean m_avoid_soko_push_loc(struct monst *, coordxy, coordxy) NONNULLARG1; extern int m_move(struct monst *, int) NONNULLARG1; extern int m_move_aggress(struct monst *, coordxy, coordxy) NONNULLARG1; extern void dissolve_bars(coordxy, coordxy); @@ -2153,6 +2156,7 @@ extern char *Tobjnam(struct obj *, const char *) NONNULL NONNULLARG1; extern char *otense(struct obj *, const char *) NONNULL NONNULLARG12; extern char *vtense(const char *, const char *) NONNULL NONNULLARG2; extern char *Doname2(struct obj *) NONNULL NONNULLARG1; +extern char *paydoname(struct obj *) NONNULL NONNULLARG1; extern char *yname(struct obj *) NONNULL NONNULLARG1; extern char *Yname2(struct obj *) NONNULL NONNULLARG1; extern char *ysimple_name(struct obj *) NONNULL NONNULLARG1; @@ -2570,6 +2574,9 @@ extern boolean in_out_region(coordxy, coordxy); extern boolean m_in_out_region(struct monst *, coordxy, coordxy) NONNULLARG1; extern void update_player_regions(void); extern void update_monster_region(struct monst *) NONNULLARG1; +extern int reg_damg(NhRegion *) NONNULLARG1; +extern boolean any_visible_region(void); +extern void visible_region_summary(winid); extern NhRegion *visible_region_at(coordxy, coordxy); extern void show_region(NhRegion *, coordxy, coordxy) NONNULLARG1; extern void save_regions(NHFILE *) NONNULLARG1; @@ -3742,6 +3749,7 @@ extern void wizcustom_callback(winid win, int glyphnum, char *id); extern int wiz_display_macros(void); extern int wiz_mon_diff(void); #endif +extern void sanity_check(void); /* ### worm.c ### */ diff --git a/include/flag.h b/include/flag.h index abcadc11f..95c7943a8 100644 --- a/include/flag.h +++ b/include/flag.h @@ -234,7 +234,7 @@ struct instance_flags { boolean query_menu; /* use a menu for yes/no queries */ boolean showdamage; boolean debug_fuzzer; /* fuzz testing */ - boolean defer_plname; /* X11 hack: askname() might not set gp.plname */ + boolean defer_plname; /* X11 hack: askname() might not set svp.plname */ boolean herecmd_menu; /* use menu when mouseclick on yourself */ boolean invis_goldsym; /* gold symbol is ' '? */ boolean in_lua; /* executing a lua script */ diff --git a/include/hack.h b/include/hack.h index b385fc37f..1d6e457d5 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 hack.h $NHDT-Date: 1717878594 2024/06/08 20:29:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.257 $ */ +/* NetHack 3.7 hack.h $NHDT-Date: 1724094288 2024/08/19 19:04:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.261 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -327,6 +327,28 @@ struct _create_particular_data { boolean sleeping, saddled, invisible, hidden; }; +/* dig_check() results */ + +enum digcheck_result { + DIGCHECK_PASSED = 1, + DIGCHECK_PASSED_DESTROY_TRAP = 2, + DIGCHECK_PASSED_PITONLY = 3, + DIGCHECK_FAILED = 4, + DIGCHECK_FAIL_ONSTAIRS = DIGCHECK_FAILED, + DIGCHECK_FAIL_ONLADDER, + DIGCHECK_FAIL_THRONE, + DIGCHECK_FAIL_ALTAR, + DIGCHECK_FAIL_AIRLEVEL, + DIGCHECK_FAIL_WATERLEVEL, + DIGCHECK_FAIL_TOOHARD, + DIGCHECK_FAIL_UNDESTROYABLETRAP, + DIGCHECK_FAIL_CANTDIG, + DIGCHECK_FAIL_BOULDER, + DIGCHECK_FAIL_OBJ_POOL_OR_TRAP +}; + + + /* Dismount: causes for why you are no longer riding */ enum dismount_types { DISMOUNT_GENERIC = 0, @@ -372,40 +394,40 @@ struct dgn_topology { /* special dungeon levels for speed */ /* macros for accessing the dungeon levels by their old names */ /* clang-format off */ -#define oracle_level (gd.dungeon_topology.d_oracle_level) -#define bigroom_level (gd.dungeon_topology.d_bigroom_level) -#define rogue_level (gd.dungeon_topology.d_rogue_level) -#define medusa_level (gd.dungeon_topology.d_medusa_level) -#define stronghold_level (gd.dungeon_topology.d_stronghold_level) -#define valley_level (gd.dungeon_topology.d_valley_level) -#define wiz1_level (gd.dungeon_topology.d_wiz1_level) -#define wiz2_level (gd.dungeon_topology.d_wiz2_level) -#define wiz3_level (gd.dungeon_topology.d_wiz3_level) -#define juiblex_level (gd.dungeon_topology.d_juiblex_level) -#define orcus_level (gd.dungeon_topology.d_orcus_level) -#define baalzebub_level (gd.dungeon_topology.d_baalzebub_level) -#define asmodeus_level (gd.dungeon_topology.d_asmodeus_level) -#define portal_level (gd.dungeon_topology.d_portal_level) -#define sanctum_level (gd.dungeon_topology.d_sanctum_level) -#define earth_level (gd.dungeon_topology.d_earth_level) -#define water_level (gd.dungeon_topology.d_water_level) -#define fire_level (gd.dungeon_topology.d_fire_level) -#define air_level (gd.dungeon_topology.d_air_level) -#define astral_level (gd.dungeon_topology.d_astral_level) -#define tower_dnum (gd.dungeon_topology.d_tower_dnum) -#define sokoban_dnum (gd.dungeon_topology.d_sokoban_dnum) -#define mines_dnum (gd.dungeon_topology.d_mines_dnum) -#define quest_dnum (gd.dungeon_topology.d_quest_dnum) -#define tutorial_dnum (gd.dungeon_topology.d_tutorial_dnum) -#define qstart_level (gd.dungeon_topology.d_qstart_level) -#define qlocate_level (gd.dungeon_topology.d_qlocate_level) -#define nemesis_level (gd.dungeon_topology.d_nemesis_level) -#define knox_level (gd.dungeon_topology.d_knox_level) -#define mineend_level (gd.dungeon_topology.d_mineend_level) -#define sokoend_level (gd.dungeon_topology.d_sokoend_level) +#define oracle_level (svd.dungeon_topology.d_oracle_level) +#define bigroom_level (svd.dungeon_topology.d_bigroom_level) +#define rogue_level (svd.dungeon_topology.d_rogue_level) +#define medusa_level (svd.dungeon_topology.d_medusa_level) +#define stronghold_level (svd.dungeon_topology.d_stronghold_level) +#define valley_level (svd.dungeon_topology.d_valley_level) +#define wiz1_level (svd.dungeon_topology.d_wiz1_level) +#define wiz2_level (svd.dungeon_topology.d_wiz2_level) +#define wiz3_level (svd.dungeon_topology.d_wiz3_level) +#define juiblex_level (svd.dungeon_topology.d_juiblex_level) +#define orcus_level (svd.dungeon_topology.d_orcus_level) +#define baalzebub_level (svd.dungeon_topology.d_baalzebub_level) +#define asmodeus_level (svd.dungeon_topology.d_asmodeus_level) +#define portal_level (svd.dungeon_topology.d_portal_level) +#define sanctum_level (svd.dungeon_topology.d_sanctum_level) +#define earth_level (svd.dungeon_topology.d_earth_level) +#define water_level (svd.dungeon_topology.d_water_level) +#define fire_level (svd.dungeon_topology.d_fire_level) +#define air_level (svd.dungeon_topology.d_air_level) +#define astral_level (svd.dungeon_topology.d_astral_level) +#define tower_dnum (svd.dungeon_topology.d_tower_dnum) +#define sokoban_dnum (svd.dungeon_topology.d_sokoban_dnum) +#define mines_dnum (svd.dungeon_topology.d_mines_dnum) +#define quest_dnum (svd.dungeon_topology.d_quest_dnum) +#define tutorial_dnum (svd.dungeon_topology.d_tutorial_dnum) +#define qstart_level (svd.dungeon_topology.d_qstart_level) +#define qlocate_level (svd.dungeon_topology.d_qlocate_level) +#define nemesis_level (svd.dungeon_topology.d_nemesis_level) +#define knox_level (svd.dungeon_topology.d_knox_level) +#define mineend_level (svd.dungeon_topology.d_mineend_level) +#define sokoend_level (svd.dungeon_topology.d_sokoend_level) /* clang-format on */ -#define dunlev_reached(x) (gd.dungeons[(x)->dnum].dunlev_ureached) +#define dunlev_reached(x) (svd.dungeons[(x)->dnum].dunlev_ureached) #define MAXLINFO (MAXDUNGEON * MAXLEVEL) enum lua_theme_group { @@ -783,6 +805,7 @@ struct sinfo { int in_parseoptions; /* in parseoptions */ int in_role_selection; /* role/race/&c selection menus in progress */ int in_getlin; /* inside interface getlin routine */ + int in_sanity_check; /* for impossible() during sanity checking */ int config_error_ready; /* config_error_add is ready, available */ int beyond_savefile_load; /* set when past savefile loading */ #ifdef PANICLOG @@ -1072,10 +1095,10 @@ typedef struct { #define MATCH_WARN_OF_MON(mon) \ (Warn_of_mon \ - && ((gc.context.warntype.obj & (mon)->data->mflags2) != 0 \ - || (gc.context.warntype.polyd & (mon)->data->mflags2) != 0 \ - || (gc.context.warntype.species \ - && (gc.context.warntype.species == (mon)->data)))) + && ((svc.context.warntype.obj & (mon)->data->mflags2) != 0 \ + || (svc.context.warntype.polyd & (mon)->data->mflags2) != 0 \ + || (svc.context.warntype.species \ + && (svc.context.warntype.species == (mon)->data)))) typedef uint32_t mmflags_nht; /* makemon MM_ flags */ @@ -1116,6 +1139,7 @@ typedef uint32_t mmflags_nht; /* makemon MM_ flags */ #define MHID_PREFIX 1 /* include ", mimicking " prefix */ #define MHID_ARTICLE 2 /* include "a " or "an " after prefix */ #define MHID_ALTMON 4 /* if mimicking a monster, include that */ +#define MHID_REGION 8 /* include region when mon is in one */ /* flags for make_corpse() and mkcorpstat(); 0..7 are recorded in obj->spe */ #define CORPSTAT_NONE 0x00 diff --git a/include/integer.h b/include/integer.h index 435da8ad3..32a3b3266 100644 --- a/include/integer.h +++ b/include/integer.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 integer.h $NHDT-Date: 1717967331 2024/06/09 21:08:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 integer.h $NHDT-Date: 1720397754 2024/07/08 00:15:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) 2016 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ @@ -110,4 +110,9 @@ typedef uint64_t uint64; ? (L) * 10L + (D) \ : -1L) +/* add a and b, return max long value if overflow would have occurred; + assumes that both a and b are non-negative; caller should apply + cast(s) to (long) in the arguments if any are needed */ +#define nowrap_add(a,b) ((a) <= (LONG_MAX - (b)) ? ((a) + (b)) : LONG_MAX) + #endif /* INTEGER_H */ diff --git a/include/mextra.h b/include/mextra.h index 13ba7f254..1942f9dc7 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 mextra.h $NHDT-Date: 1596498545 2020/08/03 23:49:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ */ +/* NetHack 3.7 mextra.h $NHDT-Date: 1720717969 2024/07/11 17:12:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.40 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -113,7 +113,6 @@ struct epri { struct bill_x { unsigned bo_id; boolean useup; - boolean queuedpay; long price; /* price per unit */ long bquan; /* amount used up */ }; @@ -123,8 +122,8 @@ struct eshk { long credit; /* amount credited to customer */ long debit; /* amount of debt for using unpaid items */ long loan; /* shop-gold picked (part of debit) */ - int shoptype; /* the value of gr.rooms[shoproom].rtype */ - schar shoproom; /* index in gr.rooms; set by inshop() */ + int shoptype; /* the value of svr.rooms[shoproom].rtype */ + schar shoproom; /* index in svr.rooms; set by inshop() */ schar unused; /* to force alignment for stupid compilers */ boolean following; /* following customer since he owes us sth */ boolean surcharge; /* angry shk inflates prices */ diff --git a/include/mkroom.h b/include/mkroom.h index a7889f272..39fb09976 100644 --- a/include/mkroom.h +++ b/include/mkroom.h @@ -40,10 +40,10 @@ struct shclass { const char *const *shknms; /* list of shopkeeper names for this type */ }; -/* the normal rooms on the current level are described in gr.rooms[0..n] for +/* the normal rooms on the current level are described in svr.rooms[0..n] for * some n= gr.rooms && (x) < gr.rooms + MAXNROFROOMS) +#define IS_ROOM_PTR(x) ((x) >= svr.rooms && (x) < svr.rooms + MAXNROFROOMS) #define IS_ROOM_INDEX(x) ((x) >= 0 && (x) < MAXNROFROOMS) #define IS_SUBROOM_PTR(x) \ ((x) >= gs.subrooms && (x) < gs.subrooms + MAXNROFROOMS) #define IS_SUBROOM_INDEX(x) ((x) > MAXNROFROOMS && (x) <= (MAXNROFROOMS * 2)) -#define ROOM_INDEX(x) ((x) - gr.rooms) +#define ROOM_INDEX(x) ((x) - svr.rooms) #define SUBROOM_INDEX(x) ((x) - gs.subrooms) -#define IS_LAST_ROOM_PTR(x) (ROOM_INDEX(x) == gn.nroom) +#define IS_LAST_ROOM_PTR(x) (ROOM_INDEX(x) == svn.nroom) #define IS_LAST_SUBROOM_PTR(x) (!gn.nsubroom || SUBROOM_INDEX(x) == gn.nsubroom) #endif /* MKROOM_H */ diff --git a/include/monflag.h b/include/monflag.h index e5d4f4ece..43400fea9 100644 --- a/include/monflag.h +++ b/include/monflag.h @@ -204,7 +204,7 @@ enum ms_sounds { passed to mkclass() as if it dealt with mons[].geno bits */ #define G_IGNORE 0x8000 /* for mkclass(), ignore G_GENOD|G_EXTINCT */ -/* for gm.mvitals[].mvflags (variant during game), along with G_NOCORPSE */ +/* for svm.mvitals[].mvflags (variant during game), along with G_NOCORPSE */ #define G_KNOWN 0x04 /* have been encountered */ #define G_GENOD 0x02 /* have been genocided */ #define G_EXTINCT 0x01 /* population control; create no more */ diff --git a/include/monst.h b/include/monst.h index 4c0c19531..a7f39c18e 100644 --- a/include/monst.h +++ b/include/monst.h @@ -212,7 +212,7 @@ struct monst { /* dead monsters stay on the fmon list until dmonsfree() at end of turn */ #define DEADMONSTER(mon) ((mon)->mhp < 1) -#define is_starting_pet(mon) ((mon)->m_id == gc.context.startingpet_mid) +#define is_starting_pet(mon) ((mon)->m_id == svc.context.startingpet_mid) #define is_vampshifter(mon) \ ((mon)->cham == PM_VAMPIRE || (mon)->cham == PM_VAMPIRE_LEADER \ || (mon)->cham == PM_VLAD_THE_IMPALER) @@ -226,7 +226,7 @@ struct monst { #define mundisplaceable(mon) \ ((mon)->ispriest || (mon)->isshk \ || (mon)->isgd || (mon)->data == &mons[PM_ORACLE] \ - || (mon)->m_id == gq.quest_status.leader_m_id) + || (mon)->m_id == svq.quest_status.leader_m_id) /* mimic appearances that block vision/light */ #define is_lightblocker_mappear(mon) \ diff --git a/include/monsters.h b/include/monsters.h index 3c7a8a0fd..e1987f8db 100644 --- a/include/monsters.h +++ b/include/monsters.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 monsters.h $NHDT-Date: 1705092146 2024/01/12 20:42:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.119 $ */ +/* NetHack 3.7 monsters.h $NHDT-Date: 1723945838 2024/08/18 01:50:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.124 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2693,8 +2693,17 @@ | M2_SHAPESHIFTER, M3_INFRAVISIBLE, 11, HI_DOMESTIC, DOPPELGANGER), + /* 3.7: shopkeepers used to have speed 18, but if/when they were + hasted they always got 2 moves per turn and had a tendency to move + away from blocking the door and then move right back; since they + might start with a potion of speed and drink that as soon as the + hero gets close, once inside the shop the hero could have trouble + getting out again; also, being slowed still guaranteed one move + per turn; reduce their innate speed from 18 to 16 for a hasted + speed of 22 rather than 24 and slowed speed of 11 rather than 12; + they will still block the shop door, but not as tenaciously */ MON(NAM("shopkeeper"), S_HUMAN, - LVL(12, 18, 0, 50, 0), G_NOGEN, + LVL(12, 16, 0, 50, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 4, 4), ATTK(AT_WEAP, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SELL, MZ_HUMAN), 0, 0, diff --git a/include/obj.h b/include/obj.h index 08d11dcf8..abdd3c735 100644 --- a/include/obj.h +++ b/include/obj.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 obj.h $NHDT-Date: 1633802062 2021/10/09 17:54:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.94 $ */ +/* NetHack 3.7 obj.h $NHDT-Date: 1718999845 2024/06/21 19:57:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.116 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -82,6 +82,8 @@ struct obj { #define OBJ_ONBILL 7 /* object on shk bill */ #define OBJ_LUAFREE 8 /* object has been dealloc'd, but is ref'd by lua */ #define OBJ_DELETED 9 /* object is marked for deletion by dobjsfree() */ + /* note: OBJ_xxx values are used in obj_state_names[] in mkobj.c + so adding, removing, or renumbering these needs to change that too */ #define NOBJ_STATES 10 xint16 timed; /* # of fuses (timers) attached to this obj */ @@ -300,14 +302,14 @@ struct obj { /* Eggs and other food */ #define MAX_EGG_HATCH_TIME 200 /* longest an egg can remain unhatched */ #define stale_egg(egg) \ - ((gm.moves - (egg)->age) > (2 * MAX_EGG_HATCH_TIME)) + ((svm.moves - (egg)->age) > (2 * MAX_EGG_HATCH_TIME)) #define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN) /* note: sometimes eggs and tins have special corpsenm values that shouldn't be used as an index into mons[] */ -#define polyfodder(obj) \ +#define polyfood(obj) \ (ofood(obj) && (obj)->corpsenm >= LOW_PM \ && (pm_to_cham((obj)->corpsenm) != NON_PM \ - || dmgtype(&mons[(obj)->corpsenm], AD_POLY))) + || dmgtype(&mons[(obj)->corpsenm], AD_POLY))) #define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH) #define mhealup(obj) (ofood(obj) && (obj)->corpsenm == PM_NURSE) #define Is_pudding(o) \ @@ -418,8 +420,8 @@ struct obj { || (o)->otyp == AMULET_OF_UNCHANGING) /* achievement tracking; 3.6.x did this differently */ -#define is_mines_prize(o) ((o)->o_id == gc.context.achieveo.mines_prize_oid) -#define is_soko_prize(o) ((o)->o_id == gc.context.achieveo.soko_prize_oid) +#define is_mines_prize(o) ((o)->o_id == svc.context.achieveo.mines_prize_oid) +#define is_soko_prize(o) ((o)->o_id == svc.context.achieveo.soko_prize_oid) /* is_art() is now a function in artifact.c */ /* #define is_art(o,art) ((o) && (o)->oartifact == (art)) */ diff --git a/include/optlist.h b/include/optlist.h index 00b954c60..08288fd08 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -548,6 +548,9 @@ static int optfn_##a(int, int, boolean, char *, char *); NHOPTC(paranoid_confirmation, Advanced, 28, opt_in, set_in_game, Yes, Yes, Yes, Yes, "prayconfirm", "extra prompting in certain situations") + NHOPTB(pauper, Advanced, 0, opt_in, set_in_config, + Off, Yes, No, No, NoAlias, &u.uroleplay.pauper, Term_False, + "start your character without any items") NHOPTB(perm_invent, Advanced, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &iflags.perm_invent, Term_Off, "show persistent inventory window") diff --git a/include/patchlevel.h b/include/patchlevel.h index 6bbe25e57..ec66ac797 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 patchlevel.h $NHDT-Date: 1703294869 2023/12/23 01:27:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.249 $ */ +/* NetHack 3.7 patchlevel.h $NHDT-Date: 1720717988 2024/07/11 17:13:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.261 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 103 +#define EDITLEVEL 107 /* * Development status possibilities. diff --git a/include/permonst.h b/include/permonst.h index 436da22eb..6942ae247 100644 --- a/include/permonst.h +++ b/include/permonst.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 permonst.h $NHDT-Date: 1596498555 2020/08/03 23:49:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ +/* NetHack 3.7 permonst.h $NHDT-Date: 1721844081 2024/07/24 18:01:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.25 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -11,14 +11,14 @@ enum monnums { #include "monsters.h" #undef MONS_ENUM NUMMONS, - NON_PM = -1, /* "not a monster */ - LOW_PM = NON_PM + 1, /* first monster in mons */ - LEAVESTATUE = NON_PM - 1, /* leave statue instead of corpse; - * there are two lower values assigned - * in end.c so that (x == LEAVESTATUE) - * will test FALSE in bones.c: - * (NON_PM - 2) for no corpse - * (NON_PM - 3) for no corpse, no grave */ + NON_PM = -1, /* "not a monster" */ + LOW_PM = NON_PM + 1, /* first monster in mons */ + LEAVESTATUE = NON_PM - 1, /* leave statue instead of corpse; + * there are two lower values assigned + * in end.c so that (x == LEAVESTATUE) + * will test FALSE in bones.c: + * (NON_PM - 2) for no corpse + * (NON_PM - 3) for no corpse, no grave */ HIGH_PM = NUMMONS - 1, SPECIAL_PM = PM_LONG_WORM_TAIL /* [normal] < ~ < [special] */ /* mons[SPECIAL_PM] through mons[NUMMONS-1], inclusive, are diff --git a/include/rm.h b/include/rm.h index 4c5dd546c..61e6f013d 100644 --- a/include/rm.h +++ b/include/rm.h @@ -107,7 +107,7 @@ enum levl_typ_types { #define IS_DOOR(typ) ((typ) == DOOR) #define IS_DOORJOIN(typ) (IS_ROCK(typ) || (typ) == IRONBARS) #define IS_TREE(typ) \ - ((typ) == TREE || (gl.level.flags.arboreal && (typ) == STONE)) + ((typ) == TREE || (svl.level.flags.arboreal && (typ) == STONE)) #define ACCESSIBLE(typ) ((typ) >= DOOR) /* good position */ #define IS_ROOM(typ) ((typ) >= ROOM) /* ROOM, STAIRS, furniture.. */ #define ZAP_POS(typ) ((typ) >= POOL) @@ -374,7 +374,7 @@ struct damage { an existing bones level; if so, most recent victim will be first in list */ struct cemetery { struct cemetery *next; /* next struct is previous dead character... */ - /* "gp.plname" + "-ROLe" + "-RACe" + "-GENder" + "-ALIgnment" + \0 */ + /* "svp.plname" + "-ROLe" + "-RACe" + "-GENder" + "-ALIgnment" + \0 */ char who[PL_NSIZ + 4 * (1 + 3) + 1]; /* death reason, same as in score/log file */ char how[100 + 1]; /* [DTHSZ+1] */ @@ -441,9 +441,9 @@ typedef struct { /* * Macros for compatibility with old code. Someday these will go away. */ -#define levl gl.level.locations -#define fobj gl.level.objlist -#define fmon gl.level.monlist +#define levl svl.level.locations +#define fobj svl.level.objlist +#define fmon svl.level.monlist /* * Covert a trap number into the defsym graphics array. @@ -453,45 +453,45 @@ typedef struct { #define trap_to_defsym(t) (S_arrow_trap + (t) - 1) #define defsym_to_trap(d) ((d) - S_arrow_trap + 1) -#define OBJ_AT(x, y) (gl.level.objects[x][y] != (struct obj *) 0) +#define OBJ_AT(x, y) (svl.level.objects[x][y] != (struct obj *) 0) /* * Macros for encapsulation of level.monsters references. */ #if 0 /* these wouldn't allow buried monster and surface monster at same location */ #define MON_AT(x, y) \ - (gl.level.monsters[x][y] && !gl.level.monsters[x][y]->mburied) + (svl.level.monsters[x][y] && !svl.level.monsters[x][y]->mburied) #define MON_BURIED_AT(x, y) \ - (gl.level.monsters[x][y] && gl.level.monsters[x][y]->mburied) + (svl.level.monsters[x][y] && svl.level.monsters[x][y]->mburied) #define m_at(x, y) \ - (MON_AT(x, y) ? gl.level.monsters[x][y] : (struct monst *) 0) + (MON_AT(x, y) ? svl.level.monsters[x][y] : (struct monst *) 0) #define m_buried_at(x, y) \ - (MON_BURIED_AT(x, y) ? gl.level.monsters[x][y] : (struct monst *) 0) + (MON_BURIED_AT(x, y) ? svl.level.monsters[x][y] : (struct monst *) 0) #else /* without 'mburied' */ -#define MON_AT(x, y) (gl.level.monsters[x][y] != (struct monst *) 0) -#define m_at(x, y) (gl.level.monsters[x][y]) +#define MON_AT(x, y) (svl.level.monsters[x][y] != (struct monst *) 0) +#define m_at(x, y) (svl.level.monsters[x][y]) #define m_buried_at(x, y) ((struct monst *) 0) #endif #ifdef EXTRA_SANITY_CHECKS #define place_worm_seg(m, x, y) \ do { \ - if (gl.level.monsters[x][y] && gl.level.monsters[x][y] != m) \ + if (svl.level.monsters[x][y] && svl.level.monsters[x][y] != m) \ impossible("place_worm_seg over mon"); \ - gl.level.monsters[x][y] = m; \ + svl.level.monsters[x][y] = m; \ } while(0) #define remove_monster(x, y) \ do { \ - if (!gl.level.monsters[x][y]) \ + if (!svl.level.monsters[x][y]) \ impossible("no monster to remove"); \ - gl.level.monsters[x][y] = (struct monst *) 0; \ + svl.level.monsters[x][y] = (struct monst *) 0; \ } while(0) #else -#define place_worm_seg(m, x, y) gl.level.monsters[x][y] = m -#define remove_monster(x, y) gl.level.monsters[x][y] = (struct monst *) 0 +#define place_worm_seg(m, x, y) svl.level.monsters[x][y] = m +#define remove_monster(x, y) svl.level.monsters[x][y] = (struct monst *) 0 #endif /* restricted movement, potential luck penalties */ -#define Sokoban gl.level.flags.sokoban_rules +#define Sokoban svl.level.flags.sokoban_rules /* * These prototypes are in extern.h but some of the code which uses them diff --git a/include/spell.h b/include/spell.h index 66208434c..9299282e2 100644 --- a/include/spell.h +++ b/include/spell.h @@ -28,9 +28,9 @@ enum spellknowledge { #define ALL_MAP 0x1 #define ALL_SPELLS 0x2 -#define decrnknow(spell) gs.spl_book[spell].sp_know-- -#define spellid(spell) gs.spl_book[spell].sp_id -#define spellknow(spell) gs.spl_book[spell].sp_know +#define decrnknow(spell) svs.spl_book[spell].sp_know-- +#define spellid(spell) svs.spl_book[spell].sp_id +#define spellknow(spell) svs.spl_book[spell].sp_know /* how much Pw a spell of level lvl costs to cast? */ #define SPELL_LEV_PW(lvl) ((lvl) * 5) diff --git a/include/sym.h b/include/sym.h index 44efaffe7..d965ec2ff 100644 --- a/include/sym.h +++ b/include/sym.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 sym.h */ +/* NetHack 3.7 sym.h $NHDT-Date: $ $NHDT-Branch: $ $NHDT-Revision: $ */ /* Copyright (c) 2016 by Pasi Kallinen */ /* NetHack may be freely redistributed. See license for details. */ @@ -105,6 +105,7 @@ struct symsetentry { #define is_cmap_water(i) ((i) == S_pool || (i) == S_water) #define is_cmap_lava(i) ((i) == S_lava || (i) == S_lavawall) #define is_cmap_stairs(i) ((i) >= S_upstair && (i) <= S_brdnladder) +#define is_cmap_engraving(i) ((i) == S_engroom || (i) == S_engrcorr) /* misc symbol definitions */ enum misc_symbols { diff --git a/include/you.h b/include/you.h index 8efaea587..cd734ca42 100644 --- a/include/you.h +++ b/include/you.h @@ -162,6 +162,7 @@ struct u_roleplay { boolean blind; /* permanently blind */ boolean nudist; /* has not worn any armor, ever */ boolean deaf; /* permanently deaf */ + boolean pauper; /* no starting inventory */ long numbones; /* # of bones files loaded */ }; diff --git a/outdated/sys/amiga/amirip.c b/outdated/sys/amiga/amirip.c index ddfd405ee..b14689f80 100644 --- a/outdated/sys/amiga/amirip.c +++ b/outdated/sys/amiga/amirip.c @@ -185,7 +185,7 @@ time_t when; SetDrMd(rp, JAM1); /* Put name on stone */ - Sprintf(buf, "%s", gp.plname); + Sprintf(buf, "%s", svp.plname); buf[STONE_LINE_LEN] = 0; tomb_text(buf); diff --git a/outdated/sys/amiga/winamenu.c b/outdated/sys/amiga/winamenu.c index 31c7deeb2..013e3c792 100644 --- a/outdated/sys/amiga/winamenu.c +++ b/outdated/sys/amiga/winamenu.c @@ -357,7 +357,7 @@ menu_item **retmip; nw->Screen = HackScreen; if (win == WIN_INVEN) { - sprintf(title, "%s the %s's Inventory", gp.plname, gp.pl_character); + sprintf(title, "%s the %s's Inventory", svp.plname, svp.pl_character); nw->Title = title; if (lastinvent.MaxX != 0) { nw->LeftEdge = lastinvent.MinX; diff --git a/outdated/sys/amiga/winami.c b/outdated/sys/amiga/winami.c index f80490a83..fc860d603 100644 --- a/outdated/sys/amiga/winami.c +++ b/outdated/sys/amiga/winami.c @@ -438,10 +438,10 @@ amii_askname() amii_getlin("Who are you?", plnametmp); } while (strlen(plnametmp) == 0); - strncpy(gp.plname, plnametmp, PL_NSIZ - 1); /* Avoid overflowing plname[] */ - gp.plname[PL_NSIZ - 1] = 0; + strncpy(svp.plname, plnametmp, PL_NSIZ - 1); /* Avoid overflowing plname[] */ + svp.plname[PL_NSIZ - 1] = 0; - if (*gp.plname == '\33') { + if (*svp.plname == '\33') { clearlocks(); exit_nhwindows(NULL); nh_terminate(0); @@ -475,9 +475,9 @@ amii_player_selection() #if 0 /* Don't query the user ... instead give random character -jhsa */ #if 0 /* OBSOLETE */ - if( *gp.pl_character ){ - gp.pl_character[ 0 ] = toupper( gp.pl_character[ 0 ] ); - if( strchr( pl_classes, gp.pl_character[ 0 ] ) ) + if( *svp.pl_character ){ + svp.pl_character[ 0 ] = toupper( svp.pl_character[ 0 ] ); + if( strchr( pl_classes, svp.pl_character[ 0 ] ) ) return; } #endif @@ -531,19 +531,19 @@ amii_player_selection() case VANILLAKEY: if( strchr( pl_classes, toupper( code ) ) ) { - gp.pl_character[0] = toupper( code ); + svp.pl_character[0] = toupper( code ); aredone = 1; } else if( code == ' ' || code == '\n' || code == '\r' ) { flags.initrole = randrole(FALSE); #if 0 /* OBSOLETE */ - strcpy( gp.pl_character, roles[ rnd( 11 ) ] ); + strcpy( svp.pl_character, roles[ rnd( 11 ) ] ); #endif aredone = 1; amii_clear_nhwindow( WIN_BASE ); CloseShWindow( cwin ); - RandomWindow( gp.pl_character ); + RandomWindow( svp.pl_character ); return; } else if( code == 'q' || code == 'Q' ) @@ -563,15 +563,15 @@ amii_player_selection() case 1: /* Random Character */ flags.initrole = randrole(FALSE); #if 0 /* OBSOLETE */ - strcpy( gp.pl_character, roles[ rnd( 11 ) ] ); + strcpy( svp.pl_character, roles[ rnd( 11 ) ] ); #endif amii_clear_nhwindow( WIN_BASE ); CloseShWindow( cwin ); - RandomWindow( gp.pl_character ); + RandomWindow( svp.pl_character ); return; default: - gp.pl_character[0] = gd->GadgetID; + svp.pl_character[0] = gd->GadgetID; break; } aredone = 1; diff --git a/outdated/sys/be/bemain.c b/outdated/sys/be/bemain.c index a480c9e1a..cf29af809 100644 --- a/outdated/sys/be/bemain.c +++ b/outdated/sys/be/bemain.c @@ -132,14 +132,14 @@ whoami(void) */ char *s; - if (*gp.plname) + if (*svp.plname) return; if (s = nh_getenv("USER")) { - (void) strncpy(gp.plname, s, sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, s, sizeof(svp.plname) - 1); return; } if (s = nh_getenv("LOGNAME")) { - (void) strncpy(gp.plname, s, sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, s, sizeof(svp.plname) - 1); return; } } @@ -177,11 +177,11 @@ process_options(int argc, char **argv) #endif case 'u': if (argv[0][2]) - (void) strncpy(gp.plname, argv[0] + 2, sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, argv[0] + 2, sizeof(svp.plname) - 1); else if (argc > 1) { argc--; argv++; - (void) strncpy(gp.plname, argv[0], sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, argv[0], sizeof(svp.plname) - 1); } else raw_print("Player name expected after -u"); break; @@ -236,15 +236,15 @@ getlock(void) { int fd; - Sprintf(gl.lock, "%d%s", getuid(), gp.plname); + Sprintf(gl.lock, "%d%s", getuid(), svp.plname); regularize(gl.lock); set_levelfile_name(gl.lock, 0); fd = creat(gl.lock, FCMASK); if (fd == -1) { error("cannot creat lock file."); } else { - if (write(fd, (genericptr_t) &gh.hackpid, sizeof(gh.hackpid)) - != sizeof(gh.hackpid)) { + if (write(fd, (genericptr_t) &svh.hackpid, sizeof(svh.hackpid)) + != sizeof(svh.hackpid)) { error("cannot write lock"); } if (close(fd) == -1) { diff --git a/outdated/sys/mac/macfile.c b/outdated/sys/mac/macfile.c index bdf400b60..ce0d0e69d 100644 --- a/outdated/sys/mac/macfile.c +++ b/outdated/sys/mac/macfile.c @@ -228,7 +228,7 @@ macopen(const char *name, int flags, long fileType) Handle name; Str255 plnamep; - C2P(gp.plname, plnamep); + C2P(svp.plname, plnamep); name = (Handle)NewString(plnamep); if (name) replace_resource(name, 'STR ', PLAYER_NAME_RES_ID, diff --git a/outdated/sys/mac/macmain.c b/outdated/sys/mac/macmain.c index 5ffa3b72c..cd624543d 100644 --- a/outdated/sys/mac/macmain.c +++ b/outdated/sys/mac/macmain.c @@ -225,7 +225,7 @@ process_openfile(short src_vol, long src_dir, Str255 fName, OSType ftype) Handle name = Get1Resource('STR ', PLAYER_NAME_RES_ID); if (name) { Str255 save_f_p; - P2C(*(StringHandle) name, gp.plname); + P2C(*(StringHandle) name, svp.plname); set_savefile_name(TRUE); C2P(fqname(gs.SAVEF, SAVEPREFIX, 0), save_f_p); force_hdelete(theDirs.dataRefNum, theDirs.dataDirID, diff --git a/outdated/sys/mac/macmenu.c b/outdated/sys/mac/macmenu.c index 74d06fc33..497f9b53a 100644 --- a/outdated/sys/mac/macmenu.c +++ b/outdated/sys/mac/macmenu.c @@ -493,8 +493,8 @@ mac_askname() SetPortDialogPort(askdialog); /* Initialize the name text item */ - ask_restring(gp.plname, str); - if (gp.plname[0]) { + ask_restring(svp.plname, str); + if (svp.plname[0]) { GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); SetDialogItemText(handle, str); } @@ -502,8 +502,8 @@ mac_askname() { Str32 pName; pName [0] = 0; - if (gp.plname && gp.plname [0]) { - strcpy ((char *) pName, gp.plname); + if (svp.plname && svp.plname [0]) { + strcpy ((char *) pName, svp.plname); c2pstr ((char *) pName); } else { Handle h; @@ -548,7 +548,7 @@ mac_askname() if (flags.initrole >= 0) currrole = flags.initrole; /* Check for backward compatibility */ - else if ((currrole = str2role(gp.pl_character)) < 0) + else if ((currrole = str2role(svp.pl_character)) < 0) currrole = randrole(FALSE); /* Initialize the race popup menu */ @@ -735,8 +735,8 @@ mac_askname() GetDialogItemText(handle, str); if (str[0] > PL_NSIZ - 1) str[0] = PL_NSIZ - 1; - BlockMove(&str[1], gp.plname, str[0]); - gp.plname[str[0]] = '\0'; + BlockMove(&str[1], svp.plname, str[0]); + svp.plname[str[0]] = '\0'; /* Destroy the dialog */ for (i = RSRC_ASK_ROLE; i <= RSRC_ASK_MODE; i++) { @@ -758,14 +758,14 @@ mac_askname() break; case 2: /* Debug */ wizard = 1; - strcpy(gp.plname, WIZARD_NAME); + strcpy(svp.plname, WIZARD_NAME); break; default: /* Quit */ ExitToShell(); } /* Process the role */ - strcpy(gp.pl_character, roles[currrole].name.m); + strcpy(svp.pl_character, roles[currrole].name.m); flags.initrole = currrole; /* Process the race */ diff --git a/outdated/sys/mac/macunix.c b/outdated/sys/mac/macunix.c index a0b5c0d02..f590cfeff 100644 --- a/outdated/sys/mac/macunix.c +++ b/outdated/sys/mac/macunix.c @@ -24,7 +24,7 @@ getlock(void) int fd; int pid = getpid(); /* Process ID */ - Sprintf(gl.lock, "%d%s", getuid(), gp.plname); + Sprintf(gl.lock, "%d%s", getuid(), svp.plname); set_levelfile_name(gl.lock, 0); if ((fd = open(gl.lock, O_RDWR | O_EXCL | O_CREAT, LEVL_TYPE)) == -1) { diff --git a/outdated/sys/wince/mhdlg.c b/outdated/sys/wince/mhdlg.c index 60ce3f65d..b56923222 100644 --- a/outdated/sys/wince/mhdlg.c +++ b/outdated/sys/wince/mhdlg.c @@ -459,7 +459,7 @@ plselInitDialog(HWND hWnd) TCHAR wbuf[BUFSZ]; /* set player name */ - SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(gp.plname, wbuf, sizeof(wbuf))); + SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(svp.plname, wbuf, sizeof(wbuf))); /* check flags for consistency */ if (flags.initrole >= 0) { diff --git a/outdated/sys/wince/mhinput.c b/outdated/sys/wince/mhinput.c index 8758324e7..a7b169342 100644 --- a/outdated/sys/wince/mhinput.c +++ b/outdated/sys/wince/mhinput.c @@ -39,7 +39,7 @@ mswin_have_input() return #ifdef SAFERHANGUP /* we always have input (ESC) if hangup was requested */ - gp.program_state.done_hup || + program_state.done_hup || #endif (nhi_read_pos != nhi_write_pos); } @@ -69,7 +69,7 @@ mswin_input_pop() #ifdef SAFERHANGUP /* always return ESC when hangup was requested */ - if (gp.program_state.done_hup) { + if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; hangup_event.kbd.ch = '\033'; @@ -98,7 +98,7 @@ mswin_input_peek() #ifdef SAFERHANGUP /* always return ESC when hangup was requested */ - if (gp.program_state.done_hup) { + if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; hangup_event.kbd.ch = '\033'; diff --git a/outdated/sys/wince/mhmain.c b/outdated/sys/wince/mhmain.c index cd2a0865a..2c98410ec 100644 --- a/outdated/sys/wince/mhmain.c +++ b/outdated/sys/wince/mhmain.c @@ -826,7 +826,7 @@ mswin_layout_main_window(HWND changed_child) /* show command window only if it exists and the game is ready (plname is set) */ if (GetNHApp()->bCmdPad && cmd_size.cx > 0 && cmd_size.cy > 0 - && *gp.plname) { + && *svp.plname) { MoveWindow(GetNHApp()->hCmdWnd, cmd_org.x, cmd_org.y, cmd_size.cx, cmd_size.cy, TRUE); ShowWindow(GetNHApp()->hCmdWnd, SW_SHOW); diff --git a/outdated/sys/wince/mhmenu.c b/outdated/sys/wince/mhmenu.c index 8db3afdcc..4aa5f19f4 100644 --- a/outdated/sys/wince/mhmenu.c +++ b/outdated/sys/wince/mhmenu.c @@ -533,7 +533,7 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) if (!data->text.text) { data->text.text = mswin_init_text_buffer( - gp.program_state.gameover ? FALSE : GetNHApp()->bWrapText); + program_state.gameover ? FALSE : GetNHApp()->bWrapText); if (!data->text.text) break; } diff --git a/outdated/sys/wince/mhstatus.c b/outdated/sys/wince/mhstatus.c index 41f4e5d1b..7cdcc0b5c 100644 --- a/outdated/sys/wince/mhstatus.c +++ b/outdated/sys/wince/mhstatus.c @@ -182,7 +182,7 @@ FormatStatusString(char *text, int format) int hp, hpmax; int cap = near_capacity(); - Strcpy(text, gp.plname); + Strcpy(text, svp.plname); if ('a' <= text[0] && text[0] <= 'z') text[0] += 'A' - 'a'; text[10] = 0; @@ -253,7 +253,7 @@ FormatStatusString(char *text, int format) /* forth line */ if (flags.time) - Sprintf(nb = eos(nb), "T:%ld ", gm.moves); + Sprintf(nb = eos(nb), "T:%ld ", svm.moves); if (strcmp(hu_stat[u.uhs], " ")) { Strcat(text, hu_stat[u.uhs]); diff --git a/outdated/sys/wince/mhtext.c b/outdated/sys/wince/mhtext.c index 4dfcf6575..a6b813507 100644 --- a/outdated/sys/wince/mhtext.c +++ b/outdated/sys/wince/mhtext.c @@ -39,7 +39,7 @@ mswin_init_text_window() ZeroMemory(data, sizeof(NHTextWindow)); data->window_text = mswin_init_text_buffer( - gp.program_state.gameover ? FALSE : GetNHApp()->bWrapText); + program_state.gameover ? FALSE : GetNHApp()->bWrapText); SetWindowLong(ret, GWL_USERDATA, (LONG) data); return ret; } diff --git a/outdated/sys/wince/mswproc.c b/outdated/sys/wince/mswproc.c index 45de197f5..e84dab8e1 100644 --- a/outdated/sys/wince/mswproc.c +++ b/outdated/sys/wince/mswproc.c @@ -646,7 +646,7 @@ mswin_askname(void) { logDebug("mswin_askname()\n"); - if (mswin_getlin_window("who are you?", gp.plname, PL_NSIZ) == IDCANCEL) { + if (mswin_getlin_window("who are you?", svp.plname, PL_NSIZ) == IDCANCEL) { bail("bye-bye"); /* not reached */ } diff --git a/outdated/sys/wince/winhack.c b/outdated/sys/wince/winhack.c index 2e1f9266a..72f225a5f 100644 --- a/outdated/sys/wince/winhack.c +++ b/outdated/sys/wince/winhack.c @@ -226,8 +226,8 @@ gotlock: if (fd == -1) { error("cannot creat lock file (%s.)", fq_lock); } else { - if (write(fd, (char *) &gh.hackpid, sizeof(gh.hackpid)) - != sizeof(gh.hackpid)) { + if (write(fd, (char *) &svh.hackpid, sizeof(svh.hackpid)) + != sizeof(svh.hackpid)) { error("cannot write lock (%s)", fq_lock); } if (close(fd) == -1) { diff --git a/outdated/win/Qt3/qt3_win.cpp b/outdated/win/Qt3/qt3_win.cpp index 2233b3823..483761cfd 100644 --- a/outdated/win/Qt3/qt3_win.cpp +++ b/outdated/win/Qt3/qt3_win.cpp @@ -1031,9 +1031,9 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : QButtonGroup* namebox = new QButtonGroup(1,Horizontal,"Name",this); QLineEdit* name = new QLineEdit(namebox); - name->setMaxLength(sizeof(gp.plname)-1); - if ( strncmp(gp.plname,"player",6) && strncmp(gp.plname,"games",5) ) - name->setText(gp.plname); + name->setMaxLength(sizeof(svp.plname)-1); + if ( strncmp(svp.plname,"player",6) && strncmp(svp.plname,"games",5) ) + name->setText(svp.plname); connect(name, SIGNAL(textChanged(const QString&)), this, SLOT(selectName(const QString&)) ); name->setFocus(); @@ -1189,7 +1189,7 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : void NetHackQtPlayerSelector::selectName(const QString& n) { - strncpy(gp.plname,n.latin1(),sizeof(gp.plname)-1); + strncpy(svp.plname,n.latin1(),sizeof(svp.plname)-1); } void NetHackQtPlayerSelector::selectRole() @@ -2535,7 +2535,7 @@ void NetHackQtStatusWindow::updateStats() encumber.setLabel(enc); encumber.show(); } - Strcpy(buf, gp.plname); + Strcpy(buf, svp.plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a'; Strcat(buf, " the "); if (u.mtimedone) { @@ -2598,7 +2598,7 @@ void NetHackQtStatusWindow::updateStats() align.setLabel("Lawful"); } - if (::flags.time) time.setLabel("Time:",(long)gm.moves); + if (::flags.time) time.setLabel("Time:",(long)svm.moves); else time.setLabel(""); #ifdef SCORE_ON_BOTL if (::flags.showscore) { @@ -3310,7 +3310,7 @@ static char** rip_line=0; long year; /* Put name on stone */ - Sprintf(rip_line[NAME_LINE], "%s", gp.plname); + Sprintf(rip_line[NAME_LINE], "%s", svp.plname); /* Put $ on stone */ Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money); @@ -4037,7 +4037,7 @@ void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event) void NetHackQtMainWindow::closeEvent(QCloseEvent* e) { - if ( gp.program_state.something_worth_saving ) { + if ( program_state.something_worth_saving ) { switch ( QMessageBox::information( this, "NetHack", "This will end your NetHack session", "&Save", "&Cancel", 0, 1 ) ) @@ -4629,7 +4629,7 @@ void NetHackQtBind::qt_askname() NetHackQtSavedGameSelector sgsel((const char**)saved); ch = sgsel.choose(); if ( ch >= 0 ) - strcpy(gp.plname,saved[ch]); + strcpy(svp.plname,saved[ch]); } free_saved_games(saved); @@ -4849,7 +4849,7 @@ void NetHackQtBind::qt_update_inventory() if (main) main->updateInventory(); /* doesn't work yet - if (gp.program_state.something_worth_saving && iflags.perm_invent) + if (program_state.something_worth_saving && iflags.perm_invent) display_inventory(NULL, FALSE); */ } @@ -4903,14 +4903,14 @@ int NetHackQtBind::qt_nhgetch() // while (keybuffer.Empty() #ifdef SAFERHANGUP - && !gp.program_state.done_hup + && !program_state.done_hup #endif ) { qApp->enter_loop(); } #ifdef SAFERHANGUP - if (gp.program_state.done_hup && keybuffer.Empty()) return '\033'; + if (program_state.done_hup && keybuffer.Empty()) return '\033'; #endif return keybuffer.GetAscii(); } @@ -4924,13 +4924,13 @@ int NetHackQtBind::qt_nh_poskey(int *x, int *y, int *mod) // while (keybuffer.Empty() && clickbuffer.Empty() #ifdef SAFERHANGUP - && !gp.program_state.done_hup + && !program_state.done_hup #endif ) { qApp->enter_loop(); } #ifdef SAFERHANGUP - if (gp.program_state.done_hup && keybuffer.Empty()) return '\033'; + if (program_state.done_hup && keybuffer.Empty()) return '\033'; #endif if (!keybuffer.Empty()) { return keybuffer.GetAscii(); @@ -5179,7 +5179,7 @@ bool NetHackQtBind::notify(QObject *receiver, QEvent *event) bool result=QApplication::notify(receiver,event); #ifdef SAFERHANGUP - if (gp.program_state.done_hup) { + if (program_state.done_hup) { keybuffer.Put('\033'); qApp->exit_loop(); return TRUE; diff --git a/outdated/win/gem/wingem.c b/outdated/win/gem/wingem.c index 5ed289070..df8d1d81c 100644 --- a/outdated/win/gem/wingem.c +++ b/outdated/win/gem/wingem.c @@ -501,7 +501,7 @@ Gem_player_selection() void Gem_askname() { - strncpy(gp.plname, mar_ask_name(), PL_NSIZ); + strncpy(svp.plname, mar_ask_name(), PL_NSIZ); } void @@ -1074,7 +1074,7 @@ time_t when; } /* Follows same algorithm as genl_outrip() */ /* Put name on stone */ - Sprintf(rip_line[NAME_LINE], "%s", gp.plname); + Sprintf(rip_line[NAME_LINE], "%s", svp.plname); /* Put $ on stone */ Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money); /* Put together death description */ diff --git a/outdated/win/gnome/gnbind.c b/outdated/win/gnome/gnbind.c index 49ed10251..6fb043e21 100644 --- a/outdated/win/gnome/gnbind.c +++ b/outdated/win/gnome/gnbind.c @@ -354,7 +354,7 @@ gnome_askname() /* Ask for a name and stuff the response into plname, a nethack global */ ret = ghack_ask_string_dialog("What is your name?", "gandalf", - "GnomeHack", gp.plname); + "GnomeHack", svp.plname); /* Quit if they want to quit... */ if (ret == -1) { @@ -907,7 +907,7 @@ gnome_nhgetch() g_askingQuestion = 1; /* Process events until a key press event arrives. */ while (g_numKeys == 0) { - if (gp.program_state.done_hup) + if (program_state.done_hup) return '\033'; gtk_main_iteration(); } @@ -945,7 +945,7 @@ gnome_nh_poskey(int *x, int *y, int *mod) g_askingQuestion = 0; /* Process events until a key or map-click arrives. */ while (g_numKeys == 0 && g_numClicks == 0) { - if (gp.program_state.done_hup) + if (program_state.done_hup) return '\033'; gtk_main_iteration(); } @@ -1169,7 +1169,7 @@ gnome_outrip(winid wid, int how, time_t when) long year; /* Put name on stone */ - Sprintf(buf, "%s\n", gp.plname); + Sprintf(buf, "%s\n", svp.plname); Strcat(ripString, buf); /* Put $ on stone */ diff --git a/outdated/win/gnome/gnstatus.c b/outdated/win/gnome/gnstatus.c index 0ac29823a..045b40fa6 100644 --- a/outdated/win/gnome/gnstatus.c +++ b/outdated/win/gnome/gnstatus.c @@ -440,7 +440,7 @@ ghack_status_window_update_stats() long umoney; /* First, fill in the player name and the dungeon level */ - strcpy(buf, gp.plname); + strcpy(buf, svp.plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A' - 'a'; strcat(buf, " the "); @@ -662,7 +662,7 @@ ghack_status_window_update_stats() } if (flags.time) { - sprintf(buf, "Time:%ld", gm.moves); + sprintf(buf, "Time:%ld", svm.moves); gtk_label_set(GTK_LABEL(timeLabel), buf); } else gtk_label_set(GTK_LABEL(timeLabel), ""); diff --git a/src/allmain.c b/src/allmain.c index 86a0aeb9e..058e7e905 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 allmain.c $NHDT-Date: 1704225560 2024/01/02 19:59:20 $ $NHDT-Branch: keni-luabits2 $:$NHDT-Revision: 1.238 $ */ +/* NetHack 3.7 allmain.c $NHDT-Date: 1723833610 2024/08/16 18:40:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.258 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -71,15 +71,15 @@ moveloop_preamble(boolean resuming) } if (!resuming) { /* new game */ - gp.program_state.beyond_savefile_load = 1; /* for TTY_PERM_INVENT */ - gc.context.rndencode = rnd(9000); + program_state.beyond_savefile_load = 1; /* for TTY_PERM_INVENT */ + svc.context.rndencode = rnd(9000); set_wear((struct obj *) 0); /* for side-effects of starting gear */ reset_justpicked(gi.invent); (void) pickup(1); /* autopickup at initial location */ /* only matters if someday a character is able to start with clairvoyance (wizard with cornuthaum perhaps?); without this, first "random" occurrence would always kick in on turn 1 */ - gc.context.seer_turn = (long) rnd(30); + svc.context.seer_turn = (long) rnd(30); /* give hero initial movement points; new game only--for restore, pending movement points were included in the save file */ u.umovement = NORMAL_SPEED; @@ -98,9 +98,9 @@ moveloop_preamble(boolean resuming) } u.uz0.dlevel = u.uz.dlevel; - gc.context.move = 0; + svc.context.move = 0; - gp.program_state.in_moveloop = 1; + program_state.in_moveloop = 1; /* for perm_invent preset at startup, display persistent inventory after invent is fully populated and the in_moveloop flag has been set */ if (iflags.perm_invent) @@ -166,7 +166,7 @@ moveloop_core(void) boolean monscanmove = FALSE; #ifdef SAFERHANGUP - if (gp.program_state.done_hup) + if (program_state.done_hup) end_of_input(); #endif get_nh_event(); @@ -176,26 +176,26 @@ moveloop_core(void) dobjsfree(); - if (gc.context.bypasses) + if (svc.context.bypasses) clear_bypasses(); if (iflags.sanity_check || iflags.debug_fuzzer) sanity_check(); - if (gc.context.move) { + if (svc.context.move) { /* actual time passed */ u.umovement -= NORMAL_SPEED; do { /* hero can't move this turn loop */ mvl_wtcap = encumber_msg(); - gc.context.mon_moving = TRUE; + svc.context.mon_moving = TRUE; do { monscanmove = movemon(); if (u.umovement >= NORMAL_SPEED) break; /* it's now your turn */ } while (monscanmove); - gc.context.mon_moving = FALSE; + svc.context.mon_moving = FALSE; if (!monscanmove && u.umovement < NORMAL_SPEED) { /* both hero and monsters are out of steam this round */ @@ -222,7 +222,7 @@ moveloop_core(void) u_calc_moveamt(mvl_wtcap); settrack(); - gm.moves++; + svm.moves++; /* * Never allow 'moves' to grow big enough to wrap. * We don't care what the maximum possible 'long int' @@ -231,16 +231,16 @@ moveloop_core(void) * When imposing the limit, use a mystic decimal value * instead of a magic binary one such as 0x7fffffffL. */ - if (gm.moves >= 1000000000L) { + if (svm.moves >= 1000000000L) { display_nhwindow(WIN_MESSAGE, TRUE); urgent_pline("The dungeon capitulates."); done(ESCAPED); } /* 'moves' is misnamed; it represents turns; hero_seq is a value that is distinct every time the hero moves */ - gh.hero_seq = gm.moves << 3; + gh.hero_seq = svm.moves << 3; - if (flags.time && !gc.context.run) + if (flags.time && !svc.context.run) disp.time_botl = TRUE; /* 'moves' just changed */ /********************************/ @@ -277,8 +277,8 @@ moveloop_core(void) /* moving around while encumbered is hard work */ if (mvl_wtcap > MOD_ENCUMBER && u.umoved) { - if (!(mvl_wtcap < EXT_ENCUMBER ? gm.moves % 30 - : gm.moves % 10)) { + if (!(mvl_wtcap < EXT_ENCUMBER ? svm.moves % 30 + : svm.moves % 10)) { overexert_hp(); } } @@ -320,7 +320,8 @@ moveloop_core(void) } } - if (!gl.level.flags.noautosearch && Searching && gm.multi >= 0) + if (Searching && !svl.level.flags.noautosearch + && gm.multi >= 0) (void) dosearch0(1); if (Warning) warnreveal(); @@ -349,7 +350,7 @@ moveloop_core(void) /* vision will be updated as bubbles move */ if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) movebubbles(); - else if (gl.level.flags.fumaroles) + else if (svl.level.flags.fumaroles) fumaroles(); /* when immobile, count is in turns */ @@ -382,13 +383,13 @@ moveloop_core(void) if (iflags.hilite_delta) status_eval_next_unhilite(); #endif - if (gm.moves >= gc.context.seer_turn) { + if (svm.moves >= svc.context.seer_turn) { if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz) && !BClairvoyant) do_vicinity_map((struct obj *) 0); /* we maintain this counter even when clairvoyance isn't taking place; on average, go again 30 turns from now */ - gc.context.seer_turn = gm.moves + (long) rn1(31, 15); /*15..45*/ + svc.context.seer_turn = svm.moves + (long) rn1(31, 15); /*15..45*/ /* [it used to be that on every 15th turn, there was a 50% chance of farsight, so it could happen as often as every 15 turns or theoretically never happen at all; but when @@ -417,7 +418,7 @@ moveloop_core(void) clear_splitobjs(); find_ac(); - if (!gc.context.mv || Blind) { + if (!svc.context.mv || Blind) { /* redo monsters if hallu or wearing a helm of telepathy */ if (Hallucination) { /* update screen randomly */ see_monsters(); @@ -425,11 +426,14 @@ moveloop_core(void) see_traps(); if (u.uswallow) swallowed(0); - } else if (Unblind_telepat) { + } else if (Unblind_telepat || Warning || Warn_of_mon + /* this is needed for the case where you saw a monster + due to being next to it while it's in a gas cloud + and then you moved away; it should no longer be seen + when that happens, even if it hasn't moved */ + || any_visible_region()) { /* TODO: optimize this */ see_monsters(); - } else if (Warning || Warn_of_mon) - see_monsters(); - + } if (gv.vision_full_recalc) vision_recalc(0); /* vision! */ } @@ -443,7 +447,7 @@ moveloop_core(void) m_everyturn_effect(&gy.youmonst); - gc.context.move = 1; + svc.context.move = 1; if (gm.multi >= 0 && go.occupation) { #if defined(MICRO) || defined(WIN32CON) @@ -485,10 +489,10 @@ moveloop_core(void) runmode_delay_output(); if (!gm.multi) { /* lookaround may clear multi */ - gc.context.move = 0; + svc.context.move = 0; return; } - if (gc.context.mv) { + if (svc.context.mv) { if (gm.multi < COLNO && !--gm.multi) end_running(TRUE); domove(); @@ -509,10 +513,10 @@ moveloop_core(void) if (gv.vision_full_recalc) vision_recalc(0); /* vision! */ /* when running in non-tport mode, this gets done through domove() */ - if ((!gc.context.run || flags.runmode == RUN_TPORT) - && (gm.multi && (!gc.context.travel ? !(gm.multi % 7) - : !(gm.moves % 7L)))) { - if (flags.time && gc.context.run) + if ((!svc.context.run || flags.runmode == RUN_TPORT) + && (gm.multi && (!svc.context.travel ? !(gm.multi % 7) + : !(svm.moves % 7L)))) { + if (flags.time && svc.context.run) disp.botl = TRUE; /* [should this be flush_screen() instead?] */ display_nhwindow(WIN_MAP, FALSE); @@ -564,7 +568,7 @@ regen_pw(int wtcap) { if (u.uen < u.uenmax && ((wtcap < MOD_ENCUMBER - && (!(gm.moves % ((MAXULEV + 8 - u.ulevel) + && (!(svm.moves % ((MAXULEV + 8 - u.ulevel) * (Role_if(PM_WIZARD) ? 3 : 4) / 6)))) || Energy_regeneration)) { int upper = (int) (ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1; @@ -597,10 +601,10 @@ regen_hp(int wtcap) /* eel out of water loses hp, similar to monster eels; as hp gets lower, rate of further loss slows down */ if (u.mh > 1 && !Regeneration && rn2(u.mh) > rn2(8) - && (!Half_physical_damage || !(gm.moves % 2L))) + && (!Half_physical_damage || !(svm.moves % 2L))) heal = -1; } else if (u.mh < u.mhmax) { - if (U_CAN_REGEN() || (encumbrance_ok && !(gm.moves % 20L))) + if (U_CAN_REGEN() || (encumbrance_ok && !(svm.moves % 20L))) heal = 1; } if (heal) { @@ -726,14 +730,14 @@ newgame(void) /* make sure welcome messages are given before noticing monsters */ notice_mon_off(); disp.botlx = TRUE; - gc.context.ident = 1; - gc.context.warnlevel = 1; - gc.context.next_attrib_check = 600L; /* arbitrary first setting */ - gc.context.tribute.enabled = TRUE; /* turn on 3.6 tributes */ - gc.context.tribute.tributesz = sizeof(struct tribute_info); + svc.context.ident = 1; + svc.context.warnlevel = 1; + svc.context.next_attrib_check = 600L; /* arbitrary first setting */ + svc.context.tribute.enabled = TRUE; /* turn on 3.6 tributes */ + svc.context.tribute.tributesz = sizeof(struct tribute_info); for (i = LOW_PM; i < NUMMONS; i++) - gm.mvitals[i].mvflags = mons[i].geno & G_NOCORPSE; + svm.mvitals[i].mvflags = mons[i].geno & G_NOCORPSE; init_objects(); /* must be before u_init() */ @@ -748,7 +752,7 @@ newgame(void) * any artifacts */ u_init(); - l_nhcore_init(); /* create a Lua state that lasts until the end of the game */ + l_nhcore_init(); /* create a Lua state that lasts until end of game */ reset_glyphmap(gm_newgame); #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); @@ -781,7 +785,7 @@ newgame(void) #ifdef INSURANCE save_currentstate(); #endif - gp.program_state.something_worth_saving++; /* useful data now exists */ + program_state.something_worth_saving++; /* useful data now exists */ /* Success! */ welcome(TRUE); @@ -825,20 +829,21 @@ welcome(boolean new_game) /* false => restoring an old game */ Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL])); if (!gu.urole.name.f && (new_game - ? (gu.urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE) - : currentgend != flags.initgend)) + ? (gu.urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE) + : currentgend != flags.initgend)) Sprintf(eos(buf), " %s", genders[currentgend].adj); Sprintf(eos(buf), " %s %s", gu.urace.adj, - (currentgend && gu.urole.name.f) ? gu.urole.name.f : gu.urole.name.m); + (currentgend && gu.urole.name.f) ? gu.urole.name.f + : gu.urole.name.m); pline(new_game ? "%s %s, welcome to NetHack! You are a%s." : "%s %s, the%s, welcome back to NetHack!", - Hello((struct monst *) 0), gp.plname, buf); + Hello((struct monst *) 0), svp.plname, buf); if (new_game) { /* guarantee that 'major' event category is never empty */ livelog_printf(LL_ACHIEVE, "%s the%s entered the dungeon", - gp.plname, buf); + svp.plname, buf); } else { /* if restoring in Gehennom, give same hot/smoky message as when first entering it */ @@ -895,7 +900,7 @@ do_positionbar(void) staticfn void interrupt_multi(const char *msg) { - if (gm.multi > 0 && !gc.context.travel && !gc.context.run) { + if (gm.multi > 0 && !svc.context.travel && !svc.context.run) { nomul(0); if (flags.verbose && msg) Norep("%s", msg); @@ -1239,11 +1244,13 @@ dump_enums(void) objclass_syms_dump, arti_enum_dump, }; - static const char *const pfx[NUM_ENUM_DUMPS] = { "PM_", "", "", - "", "", "", "", - "", "", "" }; + static const char *const pfx[NUM_ENUM_DUMPS] = { + "PM_", "", "", "", "", "", "", "", "", "" + }; /* 0 = dump numerically only, 1 = add 'char' comment */ - static const int dumpflgs[NUM_ENUM_DUMPS] = { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 }; + static const int dumpflgs[NUM_ENUM_DUMPS] = { + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 + }; static int szd[NUM_ENUM_DUMPS] = { SIZE(monsdump), SIZE(objdump), SIZE(omdump), SIZE(defsym_cmap_dump), SIZE(defsym_mon_syms_dump), diff --git a/src/apply.c b/src/apply.c index 7988bbce4..2edc474f2 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 apply.c $NHDT-Date: 1708126533 2024/02/16 23:35:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.437 $ */ +/* NetHack 3.7 apply.c $NHDT-Date: 1720128162 2024/07/04 21:22:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.449 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -331,8 +331,8 @@ use_stethoscope(struct obj *obj) if (!getdir((char *) 0)) return ECMD_CANCEL; - res = (gh.hero_seq == gc.context.stethoscope_seq) ? ECMD_TIME : ECMD_OK; - gc.context.stethoscope_seq = gh.hero_seq; + res = (gh.hero_seq == svc.context.stethoscope_seq) ? ECMD_TIME : ECMD_OK; + svc.context.stethoscope_seq = gh.hero_seq; gb.bhitpos.x = u.ux, gb.bhitpos.y = u.uy; /* tentative, reset below */ gn.notonhead = u.uswallow; @@ -716,7 +716,8 @@ m_unleash(struct monst *mtmp, boolean feedback) if (feedback) { if (canseemon(mtmp)) - pline_mon(mtmp, "%s pulls free of %s leash!", Monnam(mtmp), mhis(mtmp)); + pline_mon(mtmp, "%s pulls free of %s leash!", + Monnam(mtmp), mhis(mtmp)); else Your("leash falls slack."); } @@ -946,7 +947,8 @@ check_leash(coordxy x, coordxy y) if (!DEADMONSTER(mtmp)) u.uconduct.killer = save_pacifism; } else { - pline_mon(mtmp, "%s is choked by the leash!", Monnam(mtmp)); + pline_mon(mtmp, "%s is choked by the leash!", + Monnam(mtmp)); /* tameness eventually drops to 1 here (never 0) */ if (mtmp->mtame && rn2(mtmp->mtame)) mtmp->mtame--; @@ -1207,9 +1209,9 @@ use_bell(struct obj **optr) } else if (ordinary) { if (obj->cursed && !rn2(4) /* note: once any of them are gone, we stop all of them */ - && !(gm.mvitals[PM_WOOD_NYMPH].mvflags & G_GONE) - && !(gm.mvitals[PM_WATER_NYMPH].mvflags & G_GONE) - && !(gm.mvitals[PM_MOUNTAIN_NYMPH].mvflags & G_GONE) + && !(svm.mvitals[PM_WOOD_NYMPH].mvflags & G_GONE) + && !(svm.mvitals[PM_WATER_NYMPH].mvflags & G_GONE) + && !(svm.mvitals[PM_MOUNTAIN_NYMPH].mvflags & G_GONE) && (mtmp = makemon(mkclass(S_NYMPH, 0), u.ux, u.uy, NO_MINVENT | MM_NOMSG)) != 0) { You("summon %s!", a_monnam(mtmp)); @@ -1253,7 +1255,7 @@ use_bell(struct obj **optr) } else if (invoking) { pline("%s an unsettling shrill sound...", Tobjnam(obj, "issue")); - obj->age = gm.moves; + obj->age = svm.moves; learno = TRUE; wakem = TRUE; @@ -1427,7 +1429,8 @@ use_candle(struct obj **optr) else if (!otmp->lamplit && was_lamplit) pline("%s out.", (obj->quan > 1L) ? "They go" : "It goes"); if (obj->unpaid) { - struct monst *shkp VOICEONLY = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); + struct monst *shkp VOICEONLY + = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); SetVoice(shkp, 0, 80, 0); verbalize("You %s %s, you bought %s!", @@ -1589,7 +1592,8 @@ catch_lit(struct obj *obj) if (obj->otyp == POT_OIL) makeknown(obj->otyp); if (carried(obj) && obj->unpaid && costly_spot(u.ux, u.uy)) { - struct monst *shkp VOICEONLY = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); + struct monst *shkp VOICEONLY + = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); /* if it catches while you have it, then it's your tough luck */ check_unpaid(obj); @@ -1669,7 +1673,8 @@ use_lamp(struct obj *obj) if (obj->unpaid && costly_spot(u.ux, u.uy) && obj->age == 20L * (long) objects[obj->otyp].oc_cost) { const char *ithem = (obj->quan > 1L) ? "them" : "it"; - struct monst *shkp VOICEONLY = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); + struct monst *shkp VOICEONLY + = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); SetVoice(shkp, 0, 80, 0); verbalize("You burn %s, you bought %s!", ithem, ithem); @@ -2046,8 +2051,7 @@ jump(int magic) /* 0=Physical, otherwise skill level */ if (!is_valid_jump_pos(cc.x, cc.y, magic, TRUE)) { return ECMD_FAIL; } else if (u.usteed && u_at(cc.x, cc.y)) { - pline("%s isn't capable of jumping in place.", - upstart(y_monnam(u.usteed))); + pline("%s isn't capable of jumping in place.", YMonnam(u.usteed)); return ECMD_FAIL; } else { coord uc; @@ -2391,7 +2395,7 @@ fig_transform(anything *arg, long timeout) impossible("null figurine in fig_transform()"); return; } - silent = (timeout != gm.moves); /* happened while away */ + silent = (timeout != svm.moves); /* happened while away */ okay_spot = get_obj_location(figurine, &cc.x, &cc.y, 0); if (figurine->where == OBJ_INVENT || figurine->where == OBJ_MINVENT) okay_spot = enexto(&cc, cc.x, cc.y, &mons[figurine->corpsenm]); @@ -2406,7 +2410,7 @@ fig_transform(anything *arg, long timeout) mtmp = make_familiar(figurine, cc.x, cc.y, TRUE); if (mtmp) { char and_vanish[BUFSZ]; - struct obj *mshelter = gl.level.objects[mtmp->mx][mtmp->my]; + struct obj *mshelter = svl.level.objects[mtmp->mx][mtmp->my]; /* [m_monnam() yields accurate mon type, overriding hallucination] */ Sprintf(monnambuf, "%s", an(m_monnam(mtmp))); @@ -2535,7 +2539,7 @@ use_figurine(struct obj **optr) return ECMD_OK; } if (!getdir((char *) 0)) { - gc.context.move = gm.multi = 0; + svc.context.move = gm.multi = 0; return ECMD_CANCEL; } x = u.ux + u.dx; @@ -3018,7 +3022,7 @@ use_whip(struct obj *obj) /* Have a shot at snaring something on the floor. A flyer can reach the floor so could just pick an item up, but allow snagging by whip too. */ - otmp = gl.level.objects[u.ux][u.uy]; + otmp = svl.level.objects[u.ux][u.uy]; if (otmp && otmp->otyp == CORPSE && (otmp->corpsenm == PM_HORSE || otmp->corpsenm == little_to_big(PM_HORSE) /* warhorse */ @@ -3340,7 +3344,7 @@ use_pole(struct obj *obj, boolean autohit) int res = ECMD_OK, typ, max_range, min_range, glyph; coord cc; struct monst *mtmp; - struct monst *hitm = gc.context.polearm.hitmon; + struct monst *hitm = svc.context.polearm.hitmon; /* Are you allowed to use the pole? */ if (u.uswallow) { @@ -3421,19 +3425,19 @@ use_pole(struct obj *obj, boolean autohit) return ECMD_FAIL; } - gc.context.polearm.hitmon = (struct monst *) 0; + svc.context.polearm.hitmon = (struct monst *) 0; /* Attack the monster there */ gb.bhitpos = cc; if ((mtmp = m_at(gb.bhitpos.x, gb.bhitpos.y)) != (struct monst *) 0) { if (attack_checks(mtmp, uwep)) /* can attack proceed? */ /* no, abort the attack attempt; result depends on res: 1 => polearm became wielded, 0 => already wielded; - gc.context.move: 1 => discovered hidden monster at target spot, + svc.context.move: 1 => discovered hidden monster at target spot, 0 => answered 'n' to "Really attack?" prompt */ - return res | (gc.context.move ? ECMD_TIME : ECMD_OK); + return res | (svc.context.move ? ECMD_TIME : ECMD_OK); if (overexertion()) return ECMD_TIME; /* burn nutrition; maybe pass out */ - gc.context.polearm.hitmon = mtmp; + svc.context.polearm.hitmon = mtmp; check_caitiff(mtmp); gn.notonhead = (gb.bhitpos.x != mtmp->mx || gb.bhitpos.y != mtmp->my); (void) thitmonst(mtmp, uwep); @@ -3733,7 +3737,7 @@ use_grapple(struct obj *obj) /* FIXME -- untrap needs to deal with non-adjacent traps */ break; case 1: /* Object */ - if ((otmp = gl.level.objects[cc.x][cc.y]) != 0) { + if ((otmp = svl.level.objects[cc.x][cc.y]) != 0) { You("snag an object from the %s!", surface(cc.x, cc.y)); (void) pickup_object(otmp, 1L, FALSE); /* If pickup fails, leave it alone */ @@ -3945,7 +3949,7 @@ do_break_wand(struct obj *obj) if (obj->otyp == WAN_DIGGING) { schar typ; - if (dig_check(BY_OBJECT, FALSE, x, y)) { + if (dig_check(BY_OBJECT, x, y) < DIGCHECK_FAILED) { if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) { /* normally, pits and holes don't anger guards, but they * do if it's a wall or door that's being dug */ @@ -3992,7 +3996,7 @@ do_break_wand(struct obj *obj) (void) bhitm(mon, obj); /* if (disp.botl) bot(); */ } - if (affects_objects && gl.level.objects[x][y]) { + if (affects_objects && svl.level.objects[x][y]) { (void) bhitpile(obj, bhito, x, y, 0); if (disp.botl) bot(); /* potion effects */ @@ -4010,7 +4014,7 @@ do_break_wand(struct obj *obj) * of obj->bypass in the zap code to accomplish that last case * since it's also used by retouch_equipment() for polyself.) */ - if (affects_objects && gl.level.objects[x][y]) { + if (affects_objects && svl.level.objects[x][y]) { (void) bhitpile(obj, bhito, x, y, 0); if (disp.botl) bot(); /* potion effects */ diff --git a/src/artifact.c b/src/artifact.c index 7bbad3c62..a693bc159 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -14,7 +14,7 @@ * the contents, just the total size. */ -staticfn struct artifact *get_artifact(struct obj *) NONNULL; /* never returns null */ +staticfn struct artifact *get_artifact(struct obj *) NONNULL; /* #define get_artifact(o) \ (((o) && ((o)->artifact > 0 && (o)->artifact < AFTER_LAST_ARTIFACT)) \ @@ -510,7 +510,7 @@ restrict_name(struct obj *otmp, const char *name) if (!objects[otyp].oc_name_known && (odesc = OBJ_DESCR(objects[otyp])) != 0) { obj_shuffle_range(otyp, &lo, &hi); - for (i = gb.bases[ocls]; i < NUM_OBJECTS; i++) { + for (i = svb.bases[ocls]; i < NUM_OBJECTS; i++) { if (objects[i].oc_class != ocls) break; if (!objects[i].oc_name_known @@ -705,7 +705,7 @@ set_artifact_intrinsic(struct obj *otmp, boolean on, long wp_mask) * when restoring a game */ (void) make_hallucinated((long) !on, - gp.program_state.restoring ? FALSE : TRUE, + program_state.restoring ? FALSE : TRUE, wp_mask); } if (spfx & SPFX_ESP) { @@ -738,10 +738,10 @@ set_artifact_intrinsic(struct obj *otmp, boolean on, long wp_mask) if (spec_m2(otmp)) { if (on) { EWarn_of_mon |= wp_mask; - gc.context.warntype.obj |= spec_m2(otmp); + svc.context.warntype.obj |= spec_m2(otmp); } else { EWarn_of_mon &= ~wp_mask; - gc.context.warntype.obj &= ~spec_m2(otmp); + svc.context.warntype.obj &= ~spec_m2(otmp); } see_monsters(); } else { @@ -1695,7 +1695,7 @@ arti_invoke(struct obj *obj) if (oart->inv_prop > LAST_PROP) { /* It's a special power, not "just" a property */ - if (obj->age > gm.moves) { + if (obj->age > svm.moves) { /* the artifact is tired :-) */ You_feel("that %s %s ignoring you.", the(xname(obj)), otense(obj, "are")); @@ -1703,7 +1703,7 @@ arti_invoke(struct obj *obj) obj->age += (long) d(3, 10); return ECMD_TIME; } - obj->age = gm.moves + rnz(100); + obj->age = svm.moves + rnz(100); switch (oart->inv_prop) { case TAMING: { @@ -1802,15 +1802,15 @@ arti_invoke(struct obj *obj) any = cg.zeroany; /* set all bits to zero */ start_menu(tmpwin, MENU_BEHAVE_STANDARD); /* use index+1 (cant use 0) as identifier */ - for (i = num_ok_dungeons = 0; i < gn.n_dgns; i++) { - if (!gd.dungeons[i].dunlev_ureached) + for (i = num_ok_dungeons = 0; i < svn.n_dgns; i++) { + if (!svd.dungeons[i].dunlev_ureached) continue; if (i == tutorial_dnum) /* can't portal into tutorial */ continue; any.a_int = i + 1; add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr, - gd.dungeons[i].dname, MENU_ITEMFLAGS_NONE); + svd.dungeons[i].dname, MENU_ITEMFLAGS_NONE); num_ok_dungeons++; last_ok_dungeon = i; } @@ -1839,10 +1839,10 @@ arti_invoke(struct obj *obj) * The closest level is either the entry or dunlev_ureached. */ newlev.dnum = i; - if (gd.dungeons[i].depth_start >= depth(&u.uz)) - newlev.dlevel = gd.dungeons[i].entry_lev; + if (svd.dungeons[i].depth_start >= depth(&u.uz)) + newlev.dlevel = svd.dungeons[i].entry_lev; else - newlev.dlevel = gd.dungeons[i].dunlev_ureached; + newlev.dlevel = svd.dungeons[i].dunlev_ureached; if (u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev) || newlev.dnum == u.uz.dnum || !next_to_u()) { @@ -1905,7 +1905,7 @@ arti_invoke(struct obj *obj) if (mtmp->data->msound == MS_NEMESIS) continue; - if (In_quest(&u.uz) && !gq.quest_status.killed_nemesis) + if (In_quest(&u.uz) && !svq.quest_status.killed_nemesis) chance += 10; if (is_dprince(mtmp->data)) chance += 2; @@ -1968,7 +1968,7 @@ arti_invoke(struct obj *obj) } else { /* no direction picked */ pline("%s", Never_mind); - obj->age = gm.moves; + obj->age = svm.moves; } break; default: @@ -1980,7 +1980,7 @@ arti_invoke(struct obj *obj) iprop = u.uprops[oart->inv_prop].intrinsic; boolean on = (eprop & W_ARTI) != 0; /* true if prop just set */ - if (on && obj->age > gm.moves) { + if (on && obj->age > svm.moves) { /* the artifact is tired :-) */ u.uprops[oart->inv_prop].extrinsic ^= W_ARTI; You_feel("that %s %s ignoring you.", the(xname(obj)), @@ -1991,7 +1991,7 @@ arti_invoke(struct obj *obj) } else if (!on) { /* when turning off property, determine downtime */ /* arbitrary for now until we can tune this -dlc */ - obj->age = gm.moves + rnz(100); + obj->age = svm.moves + rnz(100); } if ((eprop & ~W_ARTI) || iprop) { @@ -2041,7 +2041,8 @@ finesse_ahriman(struct obj *obj) /* if we aren't levitating or this isn't an artifact which confers levitation via #invoke then freeinv() won't toggle levitation */ - if (!Levitation || (oart = get_artifact(obj)) == &artilist[ART_NONARTIFACT] + if (!Levitation + || (oart = get_artifact(obj)) == &artilist[ART_NONARTIFACT] || oart->inv_prop != LEVITATION || !(ELevitation & W_ARTI)) return FALSE; @@ -2191,7 +2192,7 @@ what_gives(long *abil) for (obj = gi.invent; obj; obj = obj->nobj) { if (obj->oartifact - && (abil != &EWarn_of_mon || gc.context.warntype.obj)) { + && (abil != &EWarn_of_mon || svc.context.warntype.obj)) { const struct artifact *art = get_artifact(obj); if (art != &artilist[ART_NONARTIFACT]) { @@ -2258,7 +2259,9 @@ glow_verb(int count, /* 0 means blind rather than no applicable creatures */ /* use for warning "glow" for Sting, Orcrist, and Grimtooth */ void -Sting_effects(int orc_count) /* new count (warn_obj_cnt is old count); -1 is a flag value */ +Sting_effects( + int orc_count) /* new count (warn_obj_cnt is old count); + * -1 is a flag value */ { if (u_wield_art(ART_STING) || u_wield_art(ART_ORCRIST) @@ -2501,8 +2504,7 @@ staticfn int count_surround_traps(coordxy x, coordxy y) { struct rm *levp; - struct obj *otmp; - struct trap *ttmp; + struct obj *o; coordxy dx, dy; int glyph, ret = 0; @@ -2518,7 +2520,7 @@ count_surround_traps(coordxy x, coordxy y) glyph = glyph_at(dx, dy); if (glyph_is_trap(glyph)) continue; - if ((ttmp = t_at(dx, dy)) != 0) { + if (t_at(dx, dy)) { ++ret; continue; } @@ -2527,8 +2529,8 @@ count_surround_traps(coordxy x, coordxy y) ++ret; continue; } - for (otmp = gl.level.objects[dx][dy]; otmp; otmp = otmp->nexthere) - if (Is_container(otmp) && otmp->otrapped) { + for (o = svl.level.objects[dx][dy]; o; o = o->nexthere) + if (Is_container(o) && o->otrapped) { ++ret; /* we're counting locations, so just */ break; /* count the first one in a pile */ } diff --git a/src/attrib.c b/src/attrib.c index 8ab5618d7..ccd5af9a7 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 attrib.c $NHDT-Date: 1651908297 2022/05/07 07:24:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.86 $ */ +/* NetHack 3.7 attrib.c $NHDT-Date: 1725138479 2024/08/31 21:07:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.127 $ */ /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ @@ -191,7 +191,7 @@ adjattrib( disp.botl = TRUE; if (msgflg <= 0) You_feel("%s%s!", (incr > 1 || incr < -1) ? "very " : "", attrstr); - if (gp.program_state.in_moveloop && (ndx == A_STR || ndx == A_CON)) + if (program_state.in_moveloop && (ndx == A_STR || ndx == A_CON)) (void) encumber_msg(); return TRUE; } @@ -242,7 +242,7 @@ losestr(int num, const char *knam, schar k_format) losehp(dmg, knam, k_format); if (Upolyd) { - /* if still polymorphed, reduce you-as-monst maxHP; never below 1 */ + /* when still poly'd, reduce you-as-monst maxHP; never below 1 */ u.mhmax -= min(dmg, u.mhmax - 1); } else if (!waspolyd) { /* not polymorphed now and didn't rehumanize when taking damage; @@ -387,8 +387,8 @@ poisoned( } if (u.uhp < 1) { - gk.killer.format = kprefix; - Strcpy(gk.killer.name, pkiller); + svk.killer.format = kprefix; + Strcpy(svk.killer.name, pkiller); /* "Poisoned by a poisoned ___" is redundant */ done(strstri(pkiller, "poison") ? DIED : POISONING); } @@ -405,8 +405,10 @@ change_luck(schar n) u.uluck = LUCKMAX; } +/* decide whether there are more blessed luckstones (plus luck-conferring + artifacts) than cursed ones; optionally combine uncursed with blessed */ int -stone_luck(boolean parameter) /* So I can't think up of a good name. So sue me. --KAA */ +stone_luck(boolean include_uncursed) { struct obj *otmp; long bonchance = 0; @@ -415,9 +417,7 @@ stone_luck(boolean parameter) /* So I can't think up of a good name. So sue me. if (confers_luck(otmp)) { if (otmp->cursed) bonchance -= otmp->quan; - else if (otmp->blessed) - bonchance += otmp->quan; - else if (parameter) + else if (otmp->blessed || include_uncursed) bonchance += otmp->quan; } @@ -501,14 +501,14 @@ exercise(int i, boolean inc_or_dec) : "Con", (inc_or_dec) ? "inc" : "dec", AEXE(i)); } - if (gm.moves > 0 && (i == A_STR || i == A_CON)) + if (svm.moves > 0 && (i == A_STR || i == A_CON)) (void) encumber_msg(); } staticfn void exerper(void) { - if (!(gm.moves % 10)) { + if (!(svm.moves % 10)) { /* Hunger Checks */ int hs = (u.uhunger > 1000) ? SATIATED : (u.uhunger > 150) ? NOT_HUNGRY @@ -555,7 +555,7 @@ exerper(void) } /* status checks */ - if (!(gm.moves % 5)) { + if (!(svm.moves % 5)) { debugpline0("exerper: Status checks"); if ((HClairvoyant & (INTRINSIC | TIMEOUT)) && !BClairvoyant) exercise(A_WIS, TRUE); @@ -590,11 +590,11 @@ exerchk(void) /* Check out the periodic accumulations */ exerper(); - if (gm.moves >= gc.context.next_attrib_check) { + if (svm.moves >= svc.context.next_attrib_check) { debugpline1("exerchk: ready to test. multi = %ld.", gm.multi); } /* Are we ready for a test? */ - if (gm.moves >= gc.context.next_attrib_check && !gm.multi) { + if (svm.moves >= svc.context.next_attrib_check && !gm.multi) { debugpline0("exerchk: testing."); /* * Law of diminishing returns (Part II): @@ -658,9 +658,9 @@ exerchk(void) platform-dependent rounding/truncation for negative vals */ AEXE(i) = (abs(ax) / 2) * mod_val; } - gc.context.next_attrib_check += rn1(200, 800); + svc.context.next_attrib_check += rn1(200, 800); debugpline1("exerchk: next check at %ld.", - gc.context.next_attrib_check); + svc.context.next_attrib_check); } } @@ -1072,7 +1072,7 @@ newhp(void) hp += rnd(gu.urole.hpadv.inrnd); if (gu.urace.hpadv.inrnd > 0) hp += rnd(gu.urace.hpadv.inrnd); - if (gm.moves <= 1L) { /* initial hero; skip for polyself to new man */ + if (svm.moves == 0) { /* initial hero; skip for polyself to new man */ /* Initialize alignment stuff */ u.ualign.type = aligns[flags.initalign].value; u.ualign.record = gu.urole.initrecord; diff --git a/src/ball.c b/src/ball.c index fe264eaf8..1ff2cc339 100644 --- a/src/ball.c +++ b/src/ball.c @@ -359,7 +359,7 @@ bc_order(void) || u.uswallow) return BCPOS_DIFFER; - for (obj = gl.level.objects[uball->ox][uball->oy]; obj; + for (obj = svl.level.objects[uball->ox][uball->oy]; obj; obj = obj->nexthere) { if (obj == uchain) return BCPOS_CHAIN; @@ -868,8 +868,6 @@ drag_ball(coordxy x, coordxy y, int *bc_control, return TRUE; } -DISABLE_WARNING_FORMAT_NONLITERAL - /* * drop_ball() * @@ -890,7 +888,7 @@ drop_ball(coordxy x, coordxy y) } if (x != u.ux || y != u.uy) { - static const char *const pullmsg = "The ball pulls you out of the %s!"; + static const char pullmsg[] = "The ball pulls you out of the "; struct trap *t; long side; @@ -898,20 +896,20 @@ drop_ball(coordxy x, coordxy y) && u.utraptype != TT_INFLOOR && u.utraptype != TT_BURIEDBALL) { switch (u.utraptype) { case TT_PIT: - pline(pullmsg, "pit"); + pline("%s%s!", pullmsg, "pit"); break; case TT_WEB: - pline(pullmsg, "web"); + pline("%s%s!", pullmsg, "web"); Soundeffect(se_destroy_web, 30); pline_The("web is destroyed!"); deltrap(t_at(u.ux, u.uy)); break; case TT_LAVA: - pline(pullmsg, hliquid("lava")); + pline("%s%s!", pullmsg, hliquid("lava")); break; case TT_BEARTRAP: side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; - pline(pullmsg, "bear trap"); + pline("%s%s!", pullmsg, "bear trap"); set_wounded_legs(side, rn1(1000, 500)); if (!u.usteed) { Your("%s %s is severely damaged.", @@ -940,7 +938,7 @@ drop_ball(coordxy x, coordxy y) u.ux = x - u.dx; u.uy = y - u.dy; } - gv.vision_full_recalc = 1; /* hero has moved, recalculate vision later */ + gv.vision_full_recalc = 1; /* hero has moved, recalc vision later */ if (Blind) { /* drop glyph under the chain */ @@ -961,8 +959,6 @@ drop_ball(coordxy x, coordxy y) } } -RESTORE_WARNING_FORMAT_NONLITERAL - /* ball&chain cause hero to randomly lose stuff from inventory */ staticfn void litter(void) diff --git a/src/bones.c b/src/bones.c index 2ed70ad91..963c6d8f9 100644 --- a/src/bones.c +++ b/src/bones.c @@ -22,7 +22,7 @@ no_bones_level(d_level *lev) assign_level(lev, &gs.save_dlevel); return (boolean) (((sptr = Is_special(lev)) != 0 && !sptr->boneid) - || !gd.dungeons[lev->dnum].boneid + || !svd.dungeons[lev->dnum].boneid /* no bones on the last or multiway branch levels in any dungeon (level 1 isn't multiway) */ || Is_botlevel(lev) @@ -94,7 +94,7 @@ resetobjs(struct obj *ochain, boolean restore) result depends upon hero's location */ && inside_shop(ox, oy) && *(p = in_rooms(ox, oy, SHOPBASE)) - && tended_shop(&gr.rooms[*p - ROOMOFFSET])); + && tended_shop(&svr.rooms[*p - ROOMOFFSET])); } } else { /* saving */ /* do not zero out o_ids for ghost levels anymore */ @@ -317,7 +317,7 @@ fixuporacle(struct monst *oracle) oracle->mpeaceful = 1; /* for behavior toward next character */ o_ridx = levl[oracle->mx][oracle->my].roomno - ROOMOFFSET; - if (o_ridx >= 0 && gr.rooms[o_ridx].rtype == DELPHI) + if (o_ridx >= 0 && svr.rooms[o_ridx].rtype == DELPHI) return TRUE; /* no fixup needed */ /* @@ -328,14 +328,14 @@ fixuporacle(struct monst *oracle) */ /* find original delphi chamber; should always succeed */ - for (ridx = 0; ridx < SIZE(gr.rooms); ++ridx) - if (gr.rooms[ridx].orig_rtype == DELPHI) + for (ridx = 0; ridx < SIZE(svr.rooms); ++ridx) + if (svr.rooms[ridx].orig_rtype == DELPHI) break; - if (o_ridx != ridx && ridx < SIZE(gr.rooms)) { + if (o_ridx != ridx && ridx < SIZE(svr.rooms)) { /* room found and she's not in it, so try to move her there */ - cc.x = (gr.rooms[ridx].lx + gr.rooms[ridx].hx) / 2; - cc.y = (gr.rooms[ridx].ly + gr.rooms[ridx].hy) / 2; + cc.x = (svr.rooms[ridx].lx + svr.rooms[ridx].hx) / 2; + cc.y = (svr.rooms[ridx].ly + svr.rooms[ridx].hy) / 2; if (enexto(&cc, cc.x, cc.y, oracle->data)) { rloc_to(oracle, cc.x, cc.y); o_ridx = levl[oracle->mx][oracle->my].roomno - ROOMOFFSET; @@ -345,7 +345,7 @@ fixuporacle(struct monst *oracle) same as used to happen before this fixup was introduced] */ } if (ridx == o_ridx) /* if she's in her room, mark it as such */ - gr.rooms[ridx].rtype = DELPHI; + svr.rooms[ridx].rtype = DELPHI; return TRUE; /* keep oracle in new bones file */ } @@ -462,7 +462,7 @@ savebones(int how, time_t when, struct obj *corpse) return; } give_u_to_m_resistances(mtmp); - mtmp = christen_monst(mtmp, gp.plname); + mtmp = christen_monst(mtmp, svp.plname); newsym(u.ux, u.uy); /* ["Your body rises from the dead as an ..." used to be given here, but it has been moved to done() so that @@ -478,7 +478,7 @@ savebones(int how, time_t when, struct obj *corpse) /* embed your possessions in your statue */ otmp = mk_named_object(STATUE, &mons[u.umonnum], u.ux, u.uy, - gp.plname); + svp.plname); drop_upon_death((struct monst *) 0, otmp, u.ux, u.uy); if (!otmp) @@ -495,7 +495,7 @@ savebones(int how, time_t when, struct obj *corpse) gi.in_mklev = FALSE; if (!mtmp) return; - mtmp = christen_monst(mtmp, gp.plname); + mtmp = christen_monst(mtmp, svp.plname); if (corpse) (void) obj_attach_mid(corpse, mtmp->m_id); } @@ -521,8 +521,8 @@ savebones(int how, time_t when, struct obj *corpse) } set_ghostly_objlist(fobj); resetobjs(fobj, FALSE); - set_ghostly_objlist(gl.level.buriedobjlist); - resetobjs(gl.level.buriedobjlist, FALSE); + set_ghostly_objlist(svl.level.buriedobjlist); + resetobjs(svl.level.buriedobjlist, FALSE); /* Hero is no longer on the map. */ u.ux0 = u.ux, u.uy0 = u.uy; @@ -534,7 +534,7 @@ savebones(int how, time_t when, struct obj *corpse) levl[x][y].seenv = 0; levl[x][y].waslit = 0; levl[x][y].glyph = GLYPH_UNEXPLORED; - gl.lastseentyp[x][y] = 0; + svl.lastseentyp[x][y] = 0; } /* Attach bones info to the current level before saving. */ @@ -546,7 +546,7 @@ savebones(int how, time_t when, struct obj *corpse) gender and alignment reflect final values rather than what the character started out as, same as topten and logfile entries */ Sprintf(newbones->who, "%s-%.3s-%.3s-%.3s-%.3s", - gp.plname, gu.urole.filecode, + svp.plname, gu.urole.filecode, gu.urace.filecode, genders[flags.female].filecode, aligns[1 - u.ualign.type].filecode); formatkiller(newbones->how, sizeof newbones->how, how, TRUE); @@ -556,13 +556,13 @@ savebones(int how, time_t when, struct obj *corpse) newbones->bonesknown = FALSE; /* if current character died on a bones level, the cemetery list will have multiple entries, most recent (this dead hero) first */ - newbones->next = gl.level.bonesinfo; - gl.level.bonesinfo = newbones; + newbones->next = svl.level.bonesinfo; + svl.level.bonesinfo = newbones; /* flag these bones if they are being created in wizard mode; they might already be flagged as such, even when we're playing in normal mode, if this level came from a previous bones file */ if (wizard) - gl.level.flags.wizard_bones = 1; + svl.level.flags.wizard_bones = 1; nhfp = create_bonesfile(&u.uz, &bonesid, whynot); if (!nhfp) { @@ -690,7 +690,7 @@ getbones(void) resetobjs(mtmp->minvent, TRUE); } resetobjs(fobj, TRUE); - resetobjs(gl.level.buriedobjlist, TRUE); + resetobjs(svl.level.buriedobjlist, TRUE); fix_shop_damage(); } } @@ -731,7 +731,7 @@ bones_include_name(const char *name) Strcat(buf, "-"); len = strlen(buf); - for (bp = gl.level.bonesinfo; bp; bp = bp->next) { + for (bp = svl.level.bonesinfo; bp; bp = bp->next) { if (!strncmp(bp->who, buf, len)) return TRUE; } diff --git a/src/botl.c b/src/botl.c index c415c554b..21692d4bb 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 botl.c $NHDT-Date: 1694893342 2023/09/16 19:42:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.239 $ */ +/* NetHack 3.7 botl.c $NHDT-Date: 1720397739 2024/07/08 00:15:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.264 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -58,7 +58,7 @@ do_statusline1(void) if (suppress_map_output()) return strcpy(newbot1, ""); - Strcpy(newbot1, gp.plname); + Strcpy(newbot1, svp.plname); if ('a' <= newbot1[0] && newbot1[0] <= 'z') newbot1[0] += 'A' - 'a'; newbot1[10] = 0; @@ -160,7 +160,7 @@ do_statusline2(void) /* time/move counter */ if (flags.time) - Sprintf(tmmv, "T:%ld", gm.moves); + Sprintf(tmmv, "T:%ld", svm.moves); else tmmv[0] = '\0'; tln = strlen(tmmv); @@ -281,7 +281,7 @@ timebot(void) if (gb.bot_disabled) return; /* we're called when disp.time_botl is set and general disp.botl - is clear; disp.time_botl gets set whenever gm.moves changes value + is clear; disp.time_botl gets set whenever svm.moves changes value so there's no benefit in tracking previous value to decide whether to skip update; suppress_map_output() handles program_state.restoring and program_state.done_hup (tty hangup => no further output at all) @@ -423,17 +423,20 @@ long botl_score(void) { long deepest = deepest_lev_reached(FALSE); - long utotal; + long umoney, depthbonus; /* hidden_gold(False): only gold in containers whose contents are known */ - utotal = money_cnt(gi.invent) + hidden_gold(FALSE); - if ((utotal -= u.umoney0) < 0L) - utotal = 0L; - utotal += u.urexp + (50 * (deepest - 1)) - + (deepest > 30 ? 10000 : deepest > 20 ? 1000 * (deepest - 20) : 0); - if (utotal < u.urexp) - utotal = LONG_MAX; /* wrap around */ - return utotal; + umoney = money_cnt(gi.invent) + hidden_gold(FALSE); + /* don't include initial gold; don't impose penalty if it's all gone */ + if ((umoney -= u.umoney0) < 0L) + umoney = 0L; + depthbonus = 50 * (deepest - 1) + + (deepest > 30) ? 10000 + : (deepest > 20) ? 1000 * (deepest - 20) + : 0; + /* neither umoney nor depthbonus can grow unusually big (gold due to + weight); u.urexp might */ + return nowrap_add(u.urexp, umoney + depthbonus); } #endif /* SCORE_ON_BOTL */ @@ -448,7 +451,7 @@ describe_level( int ret = 1; if (Is_knox(&u.uz)) { - Sprintf(buf, "%s", gd.dungeons[u.uz.dnum].dname); + Sprintf(buf, "%s", svd.dungeons[u.uz.dnum].dname); addbranch = FALSE; } else if (In_quest(&u.uz)) { Sprintf(buf, "Home %d", dunlev(&u.uz)); @@ -468,7 +471,7 @@ describe_level( ret = 0; } if (addbranch) { - Sprintf(eos(buf), ", %s", gd.dungeons[u.uz.dnum].dname); + Sprintf(eos(buf), ", %s", svd.dungeons[u.uz.dnum].dname); (void) strsubst(buf, "The ", "the "); } if (addspace) @@ -505,8 +508,8 @@ staticfn void split_clridx(int, int *, int *); staticfn boolean is_ltgt_percentnumber(const char *); staticfn boolean has_ltgt_percentnumber(const char *); staticfn int splitsubfields(char *, char ***, int); -staticfn boolean is_fld_arrayvalues(const char *, const char *const *, int, int, - int *); +staticfn boolean is_fld_arrayvalues(const char *, const char *const *, + int, int, int *); staticfn int query_arrayvalue(const char *, const char *const *, int, int); staticfn void status_hilite_add_threshold(int, struct hilite_s *); staticfn boolean parse_status_hl2(char (*)[QBUFSZ], boolean); @@ -517,7 +520,7 @@ staticfn unsigned long str2conditionbitmask(char *); staticfn boolean parse_condition(char (*)[QBUFSZ], int); staticfn char *hlattr2attrname(int, char *, size_t); staticfn void status_hilite_linestr_add(int, struct hilite_s *, unsigned long, - const char *); + const char *); staticfn void status_hilite_linestr_done(void); staticfn int status_hilite_linestr_countfield(int); staticfn void status_hilite_linestr_gather_conditions(void); @@ -526,7 +529,7 @@ staticfn char *status_hilite2str(struct hilite_s *); staticfn int status_hilite_menu_choose_field(void); staticfn int status_hilite_menu_choose_behavior(int); staticfn int status_hilite_menu_choose_updownboth(int, const char *, boolean, - boolean); + boolean); staticfn boolean status_hilite_menu_add(int); staticfn boolean status_hilite_remove(int); staticfn boolean status_hilite_menu_fld(int); @@ -766,7 +769,7 @@ bot_via_windowport(void) /* * Player name and title. */ - Strcpy(nb = buf, gp.plname); + Strcpy(nb = buf, svp.plname); nb[0] = highc(nb[0]); titl = !Upolyd ? rank() : pmname(&mons[u.umonnum], Ugender); i = (int) (strlen(buf) + sizeof " the " + strlen(titl) - sizeof ""); @@ -870,7 +873,7 @@ bot_via_windowport(void) gb.blstats[idx][BL_EXP].a.a_long = u.uexp; /* Time (moves) */ - gb.blstats[idx][BL_TIME].a.a_long = gm.moves; + gb.blstats[idx][BL_TIME].a.a_long = svm.moves; /* Hunger */ /* note: u.uhs is unsigned, and 3.6.1's STATUS_HILITE defined @@ -1039,7 +1042,7 @@ stat_update_time(void) int fld = BL_TIME; /* Time (moves) */ - gb.blstats[idx][fld].a.a_long = gm.moves; + gb.blstats[idx][fld].a.a_long = svm.moves; gv.valset[fld] = FALSE; eval_notify_windowport_field(fld, gv.valset, idx); @@ -1295,17 +1298,17 @@ eval_notify_windowport_field( } /* Temporary? hack: moveloop()'s prolog for a new game sets - * gc.context.rndencode after the status window has been init'd, + * svc.context.rndencode after the status window has been init'd, * so $:0 has already been encoded and cached by the window * port. Without this hack, gold's \G sequence won't be * recognized and ends up being displayed as-is for 'gu.update_all'. * - * Also, even if gc.context.rndencode hasn't changed and the + * Also, even if svc.context.rndencode hasn't changed and the * gold amount itself hasn't changed, the glyph portion of the * encoding may have changed if a new symset was put into effect. * * \GXXXXNNNN:25 - * XXXX = the gc.context.rndencode portion + * XXXX = the svc.context.rndencode portion * NNNN = the glyph portion * 25 = the gold amount * @@ -1313,10 +1316,10 @@ eval_notify_windowport_field( * not to honor an initial highlight, so force 'gu.update_all = TRUE'. */ if (fld == BL_GOLD - && (gc.context.rndencode != oldrndencode + && (svc.context.rndencode != oldrndencode || gs.showsyms[COIN_CLASS + SYM_OFF_O] != oldgoldsym)) { gu.update_all = TRUE; /* chg = 2; */ - oldrndencode = gc.context.rndencode; + oldrndencode = svc.context.rndencode; oldgoldsym = gs.showsyms[COIN_CLASS + SYM_OFF_O]; } @@ -2020,7 +2023,7 @@ status_eval_next_unhilite(void) struct istat_s *curr; long next_unhilite, this_unhilite; - gb.bl_hilite_moves = gm.moves; /* simplified; at one point we used to + gb.bl_hilite_moves = svm.moves; /* simplified; at one point we used to * try to encode fractional amounts for * multiple moves within same turn */ /* figure out whether an unhilight needs to be performed now */ @@ -2273,7 +2276,7 @@ get_hilite( txtstr = gb.blstats[idx][fldidx].val; if (fldidx == BL_TITLE) /* " the ", skip past " the " */ - txtstr += (strlen(gp.plname) + sizeof " the " - sizeof ""); + txtstr += strlen(svp.plname) + sizeof " the " - sizeof ""; if (hl->rel == TXT_VALUE && hl->textmatch[0]) { if (fuzzymatch(hl->textmatch, txtstr, "\" -_", TRUE)) { rule = hl; @@ -2694,7 +2697,7 @@ parse_status_hl2(char (*s)[QBUFSZ], boolean from_configfile) is_out_of_range); return FALSE; } else if (dt == ANY_LONG - && (hilite.value.a_long < (grt ? -1L : lt ? 1L : 0L))) { + && hilite.value.a_long < (grt ? -1L : lt ? 1L : 0L)) { config_error_add("%s'%s%ld'%s", threshold_value, op, hilite.value.a_long, is_out_of_range); return FALSE; @@ -3506,7 +3509,8 @@ status_hilite_menu_choose_behavior(int fld) if (fld == BL_HP) { any = cg.zeroany; any.a_int = onlybeh = BL_TH_CRITICALHP; - Sprintf(buf, "Highlight critically low %s", initblstats[fld].fldname); + Sprintf(buf, "Highlight critically low %s", + initblstats[fld].fldname); add_menu(tmpwin, &nul_glyphinfo, &any, 'C', 0, ATR_NONE, clr, buf, MENU_ITEMFLAGS_NONE); nopts++; diff --git a/src/cmd.c b/src/cmd.c index ae3b325ae..0d89e11b2 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -215,18 +215,30 @@ set_occupation(int (*fn)(void), const char *txt, cmdcount_nht xtime) void cmdq_print(int q) { - struct _cmd_queue *cq = gc.command_queue[q]; char buf[QBUFSZ]; + struct _cmd_queue *cq = gc.command_queue[q]; pline("CQ:%i", q); while (cq) { switch (cq->typ) { - case CMDQ_KEY: pline("(key:%s)", key2txt(cq->key, buf)); break; - case CMDQ_EXTCMD: pline("(extcmd:#%s)", cq->ec_entry->ef_txt); break; - case CMDQ_DIR: pline("(dir:%i,%i,%i)", cq->dirx, cq->diry, cq->dirz); break; - case CMDQ_USER_INPUT: pline1("(userinput)"); break; - case CMDQ_INT: pline("(int:%i)", cq->intval); break; - default: pline("(ERROR:%i)",cq->typ); break; + case CMDQ_KEY: + pline("(key:%s)", key2txt(cq->key, buf)); + break; + case CMDQ_EXTCMD: + pline("(extcmd:#%s)", cq->ec_entry->ef_txt); + break; + case CMDQ_DIR: + pline("(dir:%i,%i,%i)", cq->dirx, cq->diry, cq->dirz); + break; + case CMDQ_USER_INPUT: + pline("(userinput)"); + break; + case CMDQ_INT: + pline("(int:%i)", cq->intval); + break; + default: + pline("(ERROR:%i)",cq->typ); + break; } cq = cq->next; } @@ -878,7 +890,8 @@ domonability(void) char c = '\0'; if (might_hide && webmaker(uptr)) { - c = yn_function("Hide [h] or spin a web [s]?", hidespinchars, 'q', TRUE); + c = yn_function("Hide [h] or spin a web [s]?", + hidespinchars, 'q', TRUE); if (c == 'q' || c == '\033') return ECMD_OK; } @@ -978,11 +991,11 @@ makemap_prepost(boolean pre, boolean wiztower) if (Is_mineend_level(&u.uz)) { if (remove_achievement(ACH_MINE_PRIZE)) pline(Unachieve, "Mine's-end"); - gc.context.achieveo.mines_prize_oid = 0; + svc.context.achieveo.mines_prize_oid = 0; } else if (Is_sokoend_level(&u.uz)) { if (remove_achievement(ACH_SOKO_PRIZE)) pline(Unachieve, "Soko-prize"); - gc.context.achieveo.soko_prize_oid = 0; + svc.context.achieveo.soko_prize_oid = 0; } } if (Punished) { @@ -992,17 +1005,17 @@ makemap_prepost(boolean pre, boolean wiztower) /* reset lock picking unless it's for a carried container */ maybe_reset_pick((struct obj *) 0); /* reset interrupted digging if it was taking place on this level */ - if (on_level(&gc.context.digging.level, &u.uz)) - (void) memset((genericptr_t) &gc.context.digging, 0, + if (on_level(&svc.context.digging.level, &u.uz)) + (void) memset((genericptr_t) &svc.context.digging, 0, sizeof (struct dig_info)); /* reset cached targets */ iflags.travelcc.x = iflags.travelcc.y = 0; /* travel destination */ - gc.context.polearm.hitmon = (struct monst *) 0; /* polearm target */ + svc.context.polearm.hitmon = (struct monst *) 0; /* polearm target */ /* escape from trap */ reset_utrap(FALSE); check_special_room(TRUE); /* room exit */ - (void) memset((genericptr_t) &gd.dndest, 0, sizeof (dest_area)); - (void) memset((genericptr_t) &gu.updest, 0, sizeof (dest_area)); + (void) memset((genericptr_t) &svd.dndest, 0, sizeof (dest_area)); + (void) memset((genericptr_t) &svu.updest, 0, sizeof (dest_area)); u.ustuck = (struct monst *) 0; u.uswallow = u.uswldtim = 0; set_uinwater(0); /* u.uinwater = 0 */ @@ -1354,10 +1367,10 @@ set_move_cmd(int dir, int run) u.dy = ydir[dir]; /* #reqmenu -prefix disables autopickup during movement */ if (iflags.menu_requested) - gc.context.nopick = 1; - gc.context.travel = gc.context.travel1 = 0; + svc.context.nopick = 1; + svc.context.travel = svc.context.travel1 = 0; if (!gd.domove_attempting && !u.dz) { - gc.context.run = run; + svc.context.run = run; gd.domove_attempting |= (!run ? DOMOVE_WALK : DOMOVE_RUSH); } } @@ -1554,12 +1567,12 @@ do_rush(void) { if ((gd.domove_attempting & DOMOVE_RUSH)) { Norep("Double rush prefix, canceled."); - gc.context.run = 0; + svc.context.run = 0; gd.domove_attempting = 0; return ECMD_CANCEL; } - gc.context.run = 2; + svc.context.run = 2; gd.domove_attempting |= DOMOVE_RUSH; return ECMD_OK; } @@ -1570,12 +1583,12 @@ do_run(void) { if ((gd.domove_attempting & DOMOVE_RUSH)) { Norep("Double run prefix, canceled."); - gc.context.run = 0; + svc.context.run = 0; gd.domove_attempting = 0; return ECMD_CANCEL; } - gc.context.run = 3; + svc.context.run = 3; gd.domove_attempting |= DOMOVE_RUSH; return ECMD_OK; } @@ -1584,14 +1597,14 @@ do_run(void) int do_fight(void) { - if (gc.context.forcefight) { + if (svc.context.forcefight) { Norep("Double fight prefix, canceled."); - gc.context.forcefight = 0; + svc.context.forcefight = 0; gd.domove_attempting = 0; return ECMD_CANCEL; } - gc.context.forcefight = 1; + svc.context.forcefight = 1; gd.domove_attempting |= DOMOVE_WALK; return ECMD_OK; } @@ -1616,7 +1629,7 @@ do_repeat(void) cmdq_clear(CQ_REPEAT); gc.command_queue[CQ_REPEAT] = repeat_copy; iflags.menu_requested = FALSE; - if (gc.context.move) + if (svc.context.move) res = ECMD_TIME; } return res; @@ -1771,7 +1784,7 @@ struct ext_func_tab extcmdlist[] = { doputon, 0, NULL }, { 'q', "quaff", "quaff (drink) something", dodrink, CMD_M_PREFIX, NULL }, - { '\0', "quit", "exit without saving current game", + { '\0', "quit", "exit without saving current game", done2, IFBURIED | AUTOCOMPLETE | GENERALCMD | NOFUZZERCMD, NULL }, { 'Q', "quiver", "select ammunition for quiver", @@ -1820,7 +1833,8 @@ struct ext_func_tab extcmdlist[] = { doprtool, IFBURIED | CMD_M_PREFIX, NULL }, { WEAPON_SYM, "seeweapon", "show the weapon currently wielded", doprwep, IFBURIED | CMD_M_PREFIX, NULL }, - { '!', "shell", "leave game to enter a sub-shell ('exit' to come back)", + { '!', "shell", + "leave game to enter a sub-shell ('exit' to come back)", dosh_core, (IFBURIED | GENERALCMD | NOFUZZERCMD #ifndef SHELL | CMD_NOT_AVAILABLE @@ -1959,56 +1973,56 @@ struct ext_func_tab extcmdlist[] = { dozap, 0, NULL }, /* movement commands will be bound by reset_commands() */ /* move or attack; accept m/g/G/F prefixes */ - { '\0', "movewest", "move west (screen left)", - do_move_west, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, - { '\0', "movenorthwest", "move northwest (screen upper left)", - do_move_northwest, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, - { '\0', "movenorth", "move north (screen up)", - do_move_north, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, - { '\0', "movenortheast", "move northeast (screen upper right)", - do_move_northeast, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, - { '\0', "moveeast", "move east (screen right)", - do_move_east, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, - { '\0', "movesoutheast", "move southeast (screen lower right)", - do_move_southeast, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, - { '\0', "movesouth", "move south (screen down)", - do_move_south, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, - { '\0', "movesouthwest", "move southwest (screen lower left)", - do_move_southwest, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, + { '\0', "movewest", "move west (screen left)", + do_move_west, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, + { '\0', "movenorthwest", "move northwest (screen upper left)", + do_move_northwest, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, + { '\0', "movenorth", "move north (screen up)", + do_move_north, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, + { '\0', "movenortheast", "move northeast (screen upper right)", + do_move_northeast, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, + { '\0', "moveeast", "move east (screen right)", + do_move_east, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, + { '\0', "movesoutheast", "move southeast (screen lower right)", + do_move_southeast, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, + { '\0', "movesouth", "move south (screen down)", + do_move_south, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, + { '\0', "movesouthwest", "move southwest (screen lower left)", + do_move_southwest, MOVEMENTCMD | CMD_MOVE_PREFIXES, NULL }, /* rush; accept m prefix but not g/G/F */ - { '\0', "rushwest", "rush west (screen left)", - do_rush_west, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "rushnorthwest", "rush northwest (screen upper left)", - do_rush_northwest, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "rushnorth", "rush north (screen up)", - do_rush_north, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "rushnortheast", "rush northeast (screen upper right)", - do_rush_northeast, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "rusheast", "rush east (screen right)", - do_rush_east, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "rushsoutheast", "rush southeast (screen lower right)", - do_rush_southeast, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "rushsouth", "rush south (screen down)", - do_rush_south, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "rushsouthwest", "rush southwest (screen lower left)", - do_rush_southwest, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "rushwest", "rush west (screen left)", + do_rush_west, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "rushnorthwest", "rush northwest (screen upper left)", + do_rush_northwest, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "rushnorth", "rush north (screen up)", + do_rush_north, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "rushnortheast", "rush northeast (screen upper right)", + do_rush_northeast, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "rusheast", "rush east (screen right)", + do_rush_east, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "rushsoutheast", "rush southeast (screen lower right)", + do_rush_southeast, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "rushsouth", "rush south (screen down)", + do_rush_south, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "rushsouthwest", "rush southwest (screen lower left)", + do_rush_southwest, MOVEMENTCMD | CMD_M_PREFIX, NULL }, /* run; accept m prefix but not g/G/F */ - { '\0', "runwest", "run west (screen left)", - do_run_west, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "runnorthwest", "run northwest (screen upper left)", - do_run_northwest, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "runnorth", "run north (screen up)", - do_run_north, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "runnortheast", "run northeast (screen upper right)", - do_run_northeast, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "runeast", "run east (screen right)", - do_run_east, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "runsoutheast", "run southeast (screen lower right)", - do_run_southeast, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "runsouth", "run south (screen down)", - do_run_south, MOVEMENTCMD | CMD_M_PREFIX, NULL }, - { '\0', "runsouthwest", "run southwest (screen lower left)", - do_run_southwest, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "runwest", "run west (screen left)", + do_run_west, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "runnorthwest", "run northwest (screen upper left)", + do_run_northwest, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "runnorth", "run north (screen up)", + do_run_north, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "runnortheast", "run northeast (screen upper right)", + do_run_northeast, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "runeast", "run east (screen right)", + do_run_east, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "runsoutheast", "run southeast (screen lower right)", + do_run_southeast, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "runsouth", "run south (screen down)", + do_run_south, MOVEMENTCMD | CMD_M_PREFIX, NULL }, + { '\0', "runsouthwest", "run southwest (screen lower left)", + do_run_southwest, MOVEMENTCMD | CMD_M_PREFIX, NULL }, /* internal commands: only used by game core, not available for user */ { '\0', "clicklook", NULL, doclicklook, INTERNALCMD | MOUSECMD, NULL }, @@ -2181,7 +2195,7 @@ handler_rebind_keys_add(boolean keyfirst) ec = &extcmdlist[i-1]; cmdstr = ec->ef_txt; } -bindit: + bindit: if (!key) { pline("Bind which key? "); key = pgetchar(); @@ -2197,7 +2211,8 @@ bindit: pline("Changed key '%s' from \"%s\" to \"%s\".", key2txt(key, buf2), prevec->ef_txt, cmdstr); } else if (!prevec) { - pline("Bound key '%s' to \"%s\".", key2txt(key, buf2), cmdstr); + pline("Bound key '%s' to \"%s\".", + key2txt(key, buf2), cmdstr); } } else { pline("Key binding failed?!"); @@ -2214,8 +2229,7 @@ handler_rebind_keys(void) menu_item *picks = (menu_item *) 0; int clr = NO_COLOR; -redo_rebind: - + redo_rebind: win = create_nhwindow(NHW_MENU); start_menu(win, MENU_BEHAVE_STANDARD); any = cg.zeroany; @@ -3263,13 +3277,13 @@ rnd_extcmd_idx(void) staticfn void reset_cmd_vars(boolean reset_cmdq) { - gc.context.run = 0; - gc.context.nopick = gc.context.forcefight = FALSE; - gc.context.move = gc.context.mv = FALSE; + svc.context.run = 0; + svc.context.nopick = svc.context.forcefight = FALSE; + svc.context.move = svc.context.mv = FALSE; gd.domove_attempting = 0; gm.multi = 0; iflags.menu_requested = FALSE; - gc.context.travel = gc.context.travel1 = 0; + svc.context.travel = svc.context.travel1 = 0; if (gt.travelmap) { selection_free(gt.travelmap, TRUE); gt.travelmap = NULL; @@ -3290,10 +3304,10 @@ rhack(int key) int (*func)(void) = dummyfunction; iflags.menu_requested = FALSE; - gc.context.nopick = 0; + svc.context.nopick = 0; got_prefix_input: #ifdef SAFERHANGUP - if (gp.program_state.done_hup) + if (program_state.done_hup) end_of_input(); #endif if ((cmdq = cmdq_pop()) != 0) { @@ -3316,14 +3330,19 @@ rhack(int key) /* if there's no command, there's nothing to do except reset */ if (!key || key == (char) 0377 || key == gc.Cmd.spkeys[NHKF_ESC]) { - if (!key || key != gc.Cmd.spkeys[NHKF_ESC]) + if (key == gc.Cmd.spkeys[NHKF_ESC]) + /* don't perform next sanity check if player typed ESC for + the current command, similar to handling for CMD_INSANE + flag below (^P and ^R) */ + iflags.sanity_no_check = iflags.sanity_check; + else nhbell(); reset_cmd_vars(TRUE); return; } /* handle most movement commands */ - gc.context.travel = gc.context.travel1 = 0; + svc.context.travel = svc.context.travel1 = 0; { const struct ext_func_tab *tlist; int res; @@ -3365,7 +3384,8 @@ rhack(int key) pline( "The '%s' prefix should be followed by a movement command%s.", - which, (up || down) ? " other than up or down" : ""); + which, + (up || down) ? " other than up or down" : ""); } res = ECMD_FAIL; prefix_seen = 0; @@ -3427,16 +3447,16 @@ rhack(int key) ; /* just do nothing */ } else if (((gd.domove_attempting & (DOMOVE_RUSH | DOMOVE_WALK)) != 0L) - && !gc.context.travel && !dxdy_moveok()) { + && !svc.context.travel && !dxdy_moveok()) { /* trying to move diagonally as a grid bug */ You_cant("get there from here..."); reset_cmd_vars(TRUE); return; } else if ((gd.domove_attempting & DOMOVE_WALK) != 0L) { if (gm.multi) - gc.context.mv = TRUE; + svc.context.mv = TRUE; domove(); - gc.context.forcefight = 0; + svc.context.forcefight = 0; iflags.menu_requested = FALSE; return; } else if ((gd.domove_attempting & DOMOVE_RUSH) != 0L) { @@ -3445,7 +3465,7 @@ rhack(int key) gm.multi = max(COLNO, ROWNO); u.last_str_turn = 0; } - gc.context.mv = TRUE; + svc.context.mv = TRUE; domove(); iflags.menu_requested = FALSE; return; @@ -3468,7 +3488,7 @@ rhack(int key) /* reset_cmd_vars() sets context.move to False so we might need to change it [back] to True */ if ((res & ECMD_TIME) != 0) { - gc.context.move = TRUE; + svc.context.move = TRUE; if (func != dokick) { /* hero did something else than kicking a location; reset the location, so pets don't avoid it */ @@ -3487,7 +3507,7 @@ rhack(int key) cmdq_clear(CQ_REPEAT); } /* didn't move */ - gc.context.move = FALSE; + svc.context.move = FALSE; gm.multi = 0; return; } @@ -3614,7 +3634,8 @@ getdir(const char *s) if (!cmdq->dirz) { dirsym = gc.Cmd.dirchars[xytod(cmdq->dirx, cmdq->diry)]; } else { - dirsym = gc.Cmd.dirchars[(cmdq->dirz > 0) ? DIR_DOWN : DIR_UP]; + dirsym = gc.Cmd.dirchars[(cmdq->dirz > 0) ? DIR_DOWN + : DIR_UP]; } } else if (cmdq->typ == CMDQ_KEY) { dirsym = cmdq->key; @@ -3628,7 +3649,7 @@ getdir(const char *s) } retry: - gp.program_state.input_state = getdirInp; + program_state.input_state = getdirInp; if (gi.in_doagain || *readchar_queue) dirsym = readchar(); else @@ -3728,7 +3749,7 @@ getdir(const char *s) did_help = help_dir((s && *s == '^') ? dirsym : '\0', gc.Cmd.spkeys[NHKF_ESC], help_requested ? (const char *) 0 - : "Invalid direction key!"); + : "Invalid direction key!"); if (help_requested) goto retry; } @@ -4108,7 +4129,7 @@ there_cmd_menu_self(winid win, coordxy x, coordxy y, int *act UNUSED) #endif if (OBJ_AT(x, y)) { - struct obj *otmp = gl.level.objects[x][y]; + struct obj *otmp = svl.level.objects[x][y]; Sprintf(buf, "Pick up %s", otmp->nexthere ? "items" : doname(otmp)); mcmd_addmenu(win, MCMD_PICKUP, buf), ++K; @@ -4642,7 +4663,7 @@ get_count( unsigned gc_flags) /* control flags: GC_SAVEHIST, GC_ECHOFIRST */ { char qbuf[QBUFSZ]; - int key, save_input_state = gp.program_state.input_state; + int key, save_input_state = program_state.input_state; long cnt = 0L, first = inkey ? (long) (inkey - '0') : 0L; boolean backspaced = FALSE, showzero = TRUE, /* should "Count: 123" go into message history? */ @@ -4664,7 +4685,7 @@ get_count( } else { /* if readchar() has already been called in this loop, it will have reset input_state; put that back to its previous value */ - gp.program_state.input_state = save_input_state; + program_state.input_state = save_input_state; key = readchar(); } @@ -4726,12 +4747,12 @@ parse(void) iflags.in_parse = TRUE; gc.command_count = 0; - gc.context.move = TRUE; /* assume next command will take game time */ + svc.context.move = TRUE; /* assume next command will take game time */ flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */ /* affects readchar() behavior for ESC iff 'altmeta' option is On; is always reset to otherInp by readchar() */ - gp.program_state.input_state = commandInp; + program_state.input_state = commandInp; if (!gc.Cmd.num_pad || (foo = readchar()) == gc.Cmd.spkeys[NHKF_COUNT]) { /* if 'num_pad' is On then readchar() has just reset input_state; @@ -4739,7 +4760,7 @@ parse(void) otherwise "nESC" becomes "nESC" (with not read from keyboard yet) rather than intended count and meta keystroke "nM-" */ - gp.program_state.input_state = commandInp; + program_state.input_state = commandInp; foo = get_count((char *) 0, '\0', LARGEST_INT, &gc.command_count, GC_NOFLAGS); @@ -4785,8 +4806,8 @@ hangup( int sig_unused UNUSED) /* called as signal() handler, so sent * at least one arg */ { - if (gp.program_state.exiting) - gp.program_state.in_moveloop = 0; + if (program_state.exiting) + program_state.in_moveloop = 0; nhwindows_hangup(); #ifdef SAFERHANGUP /* When using SAFERHANGUP, the done_hup flag is tested in rhack @@ -4795,10 +4816,10 @@ hangup( protects against losing objects in the process of being thrown, but also potentially riskier because the disconnected program must continue running longer before attempting a hangup save. */ - gp.program_state.done_hup++; + program_state.done_hup++; /* defer hangup iff game appears to be in progress */ - if (gp.program_state.in_moveloop - && gp.program_state.something_worth_saving) + if (program_state.in_moveloop + && program_state.something_worth_saving) return; #endif /* SAFERHANGUP */ end_of_input(); @@ -4809,16 +4830,16 @@ end_of_input(void) { #ifdef NOSAVEONHANGUP #ifdef INSURANCE - if (flags.ins_chkpt && gp.program_state.something_worth_saving) + if (flags.ins_chkpt && program_state.something_worth_saving) program_state.preserve_locks = 1; /* keep files for recovery */ #endif - gp.program_state.something_worth_saving = 0; /* don't save */ + program_state.something_worth_saving = 0; /* don't save */ #endif #ifndef SAFERHANGUP - if (!gp.program_state.done_hup++) + if (!program_state.done_hup++) #endif - if (gp.program_state.something_worth_saving) + if (program_state.something_worth_saving) (void) dosave0(); if (soundprocs.sound_exit_nhsound) (*soundprocs.sound_exit_nhsound)("end_of_input"); @@ -4869,7 +4890,7 @@ readchar_core(coordxy *x, coordxy *y, int *mod) sym = '\033'; #ifdef ALTMETA } else if (sym == '\033' && iflags.altmeta - && gp.program_state.input_state != otherInp) { + && program_state.input_state != otherInp) { /* iflags.altmeta: treat two character ``ESC c'' as single `M-c' but only when we're called by parse() [possibly via get_count()] or getpos() [to support Alt+digit] or getdir() [for arrow keys @@ -4889,7 +4910,7 @@ readchar_core(coordxy *x, coordxy *y, int *mod) readchar_done: /* next readchar() will be for an ordinary char unless parse() sets this back to non-zero */ - gp.program_state.input_state = otherInp; + program_state.input_state = otherInp; return (char) sym; } @@ -4911,7 +4932,7 @@ readchar_poskey(coordxy *x, coordxy *y, int *mod) { char ch; - gp.program_state.input_state = getposInp; + program_state.input_state = getposInp; ch = readchar_core(x, y, mod); return ch; } @@ -4983,16 +5004,16 @@ dotravel_target(void) iflags.getloc_travelmode = FALSE; - gc.context.travel = 1; - gc.context.travel1 = 1; - gc.context.run = 8; - gc.context.nopick = 1; + svc.context.travel = 1; + svc.context.travel1 = 1; + svc.context.run = 8; + svc.context.nopick = 1; gd.domove_attempting |= DOMOVE_RUSH; if (!gm.multi) gm.multi = max(COLNO, ROWNO); u.last_str_turn = 0; - gc.context.mv = TRUE; + svc.context.mv = TRUE; domove(); return ECMD_TIME; @@ -5005,7 +5026,7 @@ doclicklook(void) if (!isok(gc.clicklook_cc.x, gc.clicklook_cc.y)) return ECMD_OK; - gc.context.move = FALSE; + svc.context.move = FALSE; auto_describe(gc.clicklook_cc.x, gc.clicklook_cc.y); return ECMD_OK; @@ -5152,8 +5173,20 @@ yn_function( dumplogmsg(dumplog_buf); } #endif + /* should not happen but cq.key has been observed to not obey 'resp'; + do this after dumplog has recorded the potentially bad value */ + if (resp && res && !strchr(resp, res)) { + /* this probably needs refinement since caller is expecting something + within 'resp' and ESC won't be (it could be present, but as a flag + for unshown possibilities rather than as acceptable input) */ + int altres = def ? def : '\033'; + + impossible("yn_function() returned '%s'; using '%s' instead", + visctrl(res), visctrl(altres)); + res = altres; + } /* in case we're called via getdir() which sets input_state */ - gp.program_state.input_state = otherInp; + program_state.input_state = otherInp; return res; } diff --git a/src/dbridge.c b/src/dbridge.c index 72c73cb93..8e2f081bd 100644 --- a/src/dbridge.c +++ b/src/dbridge.c @@ -287,8 +287,9 @@ e_at(coordxy x, coordxy y) int entitycnt; for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) - if ((go.occupants[entitycnt].edata) && (go.occupants[entitycnt].ex == x) - && (go.occupants[entitycnt].ey == y)) + if (go.occupants[entitycnt].edata + && go.occupants[entitycnt].ex == x + && go.occupants[entitycnt].ey == y) break; debugpline1("entitycnt = %d", entitycnt); #ifdef D_DEBUG @@ -401,18 +402,18 @@ e_died(struct entity *etmp, int xkill_flags, int how) { if (is_u(etmp)) { if (how == DROWNING) { - gk.killer.name[0] = 0; /* drown() sets its own killer */ + svk.killer.name[0] = 0; /* drown() sets its own killer */ (void) drown(); } else if (how == BURNING) { - gk.killer.name[0] = 0; /* lava_effects() sets own killer */ + svk.killer.name[0] = 0; /* lava_effects() sets own killer */ (void) lava_effects(); } else { coord xy; /* use more specific killer if specified */ - if (!gk.killer.name[0]) { - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, "falling drawbridge"); + if (!svk.killer.name[0]) { + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, "falling drawbridge"); } done(how); /* So, you didn't die */ @@ -432,12 +433,12 @@ e_died(struct entity *etmp, int xkill_flags, int how) } else { int entitycnt; - gk.killer.name[0] = 0; + svk.killer.name[0] = 0; /* fake "digested to death" damage-type suppresses corpse */ #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 (gc.context.mon_moving) + if (svc.context.mon_moving) monkilled(etmp->emon, mk_message(xkill_flags), mk_corpse(xkill_flags)); else /* you caused it */ @@ -570,8 +571,8 @@ do_entity(struct entity *etmp) } else { if (crm->typ == DRAWBRIDGE_DOWN) { if (is_u(etmp)) { - gk.killer.format = NO_KILLER_PREFIX; - Strcpy(gk.killer.name, + svk.killer.format = NO_KILLER_PREFIX; + Strcpy(svk.killer.name, "crushed to death underneath a drawbridge"); } pline("%s crushed underneath the drawbridge.", @@ -690,8 +691,8 @@ do_entity(struct entity *etmp) E_phrase(etmp, "disappear")); } if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, "closing drawbridge"); + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, "closing drawbridge"); e_died(etmp, XKILL_NOMSG, CRUSHING); return; } @@ -723,8 +724,8 @@ do_entity(struct entity *etmp) pline("%s into the %s.", E_phrase(etmp, "fall"), lava ? hliquid("lava") : "moat"); } - gk.killer.format = NO_KILLER_PREFIX; - Strcpy(gk.killer.name, "fell from a drawbridge"); + svk.killer.format = NO_KILLER_PREFIX; + Strcpy(svk.killer.name, "fell from a drawbridge"); e_died(etmp, /* CRUSHING is arbitrary */ XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG), is_pool(etmp->ex, etmp->ey) ? DROWNING @@ -738,8 +739,8 @@ do_entity(struct entity *etmp) staticfn void nokiller(void) { - gk.killer.name[0] = '\0'; - gk.killer.format = 0; + svk.killer.name[0] = '\0'; + svk.killer.format = 0; m_to_e((struct monst *) 0, 0, 0, &go.occupants[0]); m_to_e((struct monst *) 0, 0, 0, &go.occupants[1]); } @@ -947,8 +948,8 @@ destroy_drawbridge(coordxy x, coordxy y) if (e_inview) pline("%s blown apart by flying debris.", E_phrase(etmp2, "are")); - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, "exploding drawbridge"); + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, "exploding drawbridge"); e_died(etmp2, XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG), CRUSHING); /*no corpse*/ @@ -980,8 +981,8 @@ destroy_drawbridge(coordxy x, coordxy y) debugpline1("%s from shrapnel", E_phrase(etmp1, "die")); } } - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, "collapsing drawbridge"); + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, "collapsing drawbridge"); e_died(etmp1, XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG), CRUSHING); /*no corpse*/ diff --git a/src/decl.c b/src/decl.c index eba205fed..08b54e4f7 100644 --- a/src/decl.c +++ b/src/decl.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 decl.c $NHDT-Date: 1706079841 2024/01/24 07:04:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.314 $ */ +/* NetHack 3.7 decl.c $NHDT-Date: 1725138480 2024/08/31 21:08:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.337 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -244,11 +244,8 @@ static const struct instance_globals_b g_init_b = { 0L, /* bl_hilite_moves */ #endif /* decl.c */ - DUMMY, /* bases */ { 0, 0 }, /* bhitpos */ UNDEFINED_PTR, /* billobjs */ - /* dungeon.c */ - UNDEFINED_PTR, /* branches */ /* files.c */ BONESINIT, /* bones */ /* hack.c */ @@ -257,7 +254,6 @@ static const struct instance_globals_b g_init_b = { /* mkmaze.c */ { {COLNO, ROWNO, 0, 0}, {COLNO, ROWNO, 0, 0}, FALSE, FALSE, 0, 0, { 0 } }, /* bughack */ - UNDEFINED_PTR, /* bbubbles */ /* pickup.c */ FALSE, /* bucx_filter */ /* zap.c */ @@ -285,7 +281,6 @@ static const struct instance_globals_c g_init_c = { #ifdef DEF_PAGER NULL, /* catmore */ #endif - DUMMY, /* context */ /* dog.c */ DUMMY, /* catname */ /* end.c */ @@ -326,16 +321,7 @@ static const struct instance_globals_d g_init_d = { 0L, /* done_money */ 0L, /* domove_attempting */ 0L, /* domove_succeeded */ - { { {0},{0},{0},{0}, 0, {0}, 0, 0, 0, 0, 0 } }, /* dungeons */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* dndest */ FALSE, /* defer_see_monsters */ - { {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, - {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, - 0, 0, 0, 0, 0, - {0}, {0}, {0}, - {0}, {0}, {0} }, /* dungeon_topology */ - 0, /* doors_alloc */ - NULL, /* doors */ /* dig.c */ UNDEFINED_VALUE, /* did_dig_msg */ /* do.c */ @@ -348,8 +334,6 @@ static const struct instance_globals_d g_init_d = { 0L, /* done_seq */ /* mon.c */ FALSE, /* disintegested */ - /* o_init.c */ - DUMMY, /* disco */ /* objname.c */ 0, /* distantname */ /* pickup.c */ @@ -369,7 +353,6 @@ static const struct instance_globals_e g_init_e = { /* mkmaze.c */ UNDEFINED_PTR, /* ebubbles */ /* new */ - NULL, /* exclusion_zones */ 0, /* early_raw_messages */ TRUE, /* havestate*/ IVMAGIC /* e_magic to validate that structure layout has been preserved */ @@ -434,7 +417,6 @@ static const struct instance_globals_g g_init_g = { static const struct instance_globals_h g_init_h = { /* decl.c */ NULL, /* hname */ - 0, /* hackpid */ #if defined(MICRO) || defined(WIN32) UNDEFINED_VALUES, /* hackdir */ #endif /* MICRO || WIN32 */ @@ -454,7 +436,6 @@ static const struct instance_globals_h g_init_h = { static const struct instance_globals_i g_init_i = { /* decl.c */ 0, /* in_doagain */ - { 0, 0 } , /* inv_pos */ FALSE, /* in_mklev */ FALSE, /* in_steed_dismounting */ UNDEFINED_PTR, /* invent */ @@ -486,7 +467,6 @@ static const struct instance_globals_k g_init_k = { { 0, 0 }, /* kickedloc */ /* decl.c */ UNDEFINED_PTR, /* kickedobj */ - DUMMY, /* killer */ /* read.c */ UNDEFINED_VALUE, /* known */ TRUE, /* havestate*/ @@ -497,12 +477,6 @@ static const struct instance_globals_l g_init_l = { /* cmd.c */ UNDEFINED_VALUE, /* last_command_count */ /* decl.c */ - { { 0 } }, /* lastseentyp */ - { UNDEFINED_VALUES }, /* level_info */ - { { { UNDEFINED_VALUES } }, /* level.locations */ - { { UNDEFINED_PTR } }, /* level.objects */ - { { UNDEFINED_PTR } }, /* level.monsters */ - NULL, NULL, NULL, NULL, NULL, {0} }, /* level */ #if defined(UNIX) || defined(VMS) 0, /* locknum */ #endif @@ -563,16 +537,12 @@ static const struct instance_globals_m g_init_m = { { 0, 0, STRANGE_OBJECT, FALSE }, /* m_shot */ FALSE, /* mrg_to_wielded */ UNDEFINED_PTR, /* menu_colorings */ - 1L, /* moves; misnamed turn counter */ UNDEFINED_PTR, /* migrating_objs */ /* dog.c */ UNDEFINED_PTR, /* mydogs */ UNDEFINED_PTR, /* migrating_mons */ - { UNDEFINED_VALUES }, /* mvitals */ /* dokick.c */ UNDEFINED_PTR, /* maploc */ - /* dungeon.c */ - UNDEFINED_PTR, /* mapseenchn */ /* mhitu.c */ UNDEFINED_VALUE, /* mhitu_dieroll */ /* mklev.c */ @@ -607,12 +577,9 @@ static const struct instance_globals_n g_init_n = { 0, /* now_or_before_idx */ /* decl.c */ NULL, /* nomovemsg */ - 0, /* nroom */ 0, /* nsubroom */ /* dokick.c */ UNDEFINED_VALUES, /* nowhere */ - /* dungeon.c */ - 0, /* n_dgns */ /* files.c */ 0, /* nesting */ 0, /* no_sound_notified */ @@ -627,8 +594,6 @@ static const struct instance_globals_n g_init_n = { FALSE, /* notonhead */ /* questpgr.c */ UNDEFINED_VALUES, /* nambuf */ - /* region.c */ - 0, /* n_regions */ /* restore.c */ 0, /* n_ids_mapped */ /* sp_lev.c */ @@ -677,7 +642,6 @@ static const struct instance_globals_o g_init_o = { 0L, /* omoves */ /* rumors.c */ 0, /* oracle_flag */ - 0U, /* oracle_cnt */ UNDEFINED_PTR, /* oracle_loc */ /* uhitm.c */ FALSE, /* override_confirmation */ @@ -692,13 +656,9 @@ static const struct instance_globals_p g_init_p = { -1, /* polearm_range_min */ -1, /* polearm_range_max */ /* decl.c */ - DUMMY, /* plname */ 0, /* plnamelen */ - DUMMY, /* pl_character */ '\0', /* pl_race */ - DUMMY, /* pl_fruit */ UNDEFINED_PTR, /* plinemsg_types */ - UNDEFINED_VALUES, /* program_state */ /* dog.c */ 0, /* petname_used */ UNDEFINED_VALUE, /* preferred_pet */ @@ -728,15 +688,11 @@ static const struct instance_globals_p g_init_p = { }; static const struct instance_globals_q g_init_q = { - /* quest.c */ - DUMMY, /* quest_status */ TRUE, /* havestate*/ IVMAGIC /* q_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_r g_init_r = { - /* decl.c */ - { DUMMY }, /* rooms */ /* symbols.c */ DUMMY, /* rogue_syms */ /* extralev.c */ @@ -761,11 +717,9 @@ static const struct instance_globals_s g_init_s = { /* artifact.c */ 0, /* spec_dbon_applies */ /* decl.c */ - UNDEFINED_PTR, /* sp_levchn */ UNDEFINED_PTR, /* stairs */ DUMMY, /* smeq */ FALSE, /* stoned */ - { DUMMY }, /* spl_book */ UNDEFINED_PTR, /* subrooms */ /* do.c */ { 0, 0 }, /* save_dlevel */ @@ -792,6 +746,7 @@ static const struct instance_globals_s g_init_s = { (struct menucoloring *) 0, /* save_colorings */ FALSE, /* simple_options_help */ /* pickup.c */ + FALSE, /* sellobj_first */ FALSE, /* shop_filter */ /* pline.c */ #ifdef DUMPLOG_CORE @@ -819,7 +774,6 @@ static const struct instance_globals_t g_init_t = { /* apply.c */ UNDEFINED_VALUES, /* trapinfo */ /* decl.c */ - DUMMY, /* tune */ 0, /* tbx */ 0, /* tby */ UNDEFINED_VALUES, /* toplines */ @@ -842,7 +796,6 @@ static const struct instance_globals_t g_init_t = { FALSE, /* themeroom_failed */ /* timeout.c */ UNDEFINED_PTR, /* timer_base */ - 1UL, /* timer_id */ /* topten.c */ WIN_ERR, /* toptenwin */ /* uhitm.c */ @@ -856,7 +809,6 @@ static const struct instance_globals_u g_init_u = { /* botl.c */ FALSE, /* update_all */ /* decl.c */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* updest */ FALSE, /* unweapon */ /* role.c */ UNDEFINED_ROLE, /* urole */ @@ -916,9 +868,6 @@ static const struct instance_globals_x g_init_x = { (COLNO - 1) & ~1, /* x_maze_max */ /* lock.c */ UNDEFINED_VALUES, /* xlock */ - /* mkmaze.c */ - UNDEFINED_VALUE, /* xmin */ - UNDEFINED_VALUE, /* xmax */ /* objnam.c */ NULL, /* xnamep */ /* sp_lev.c */ @@ -932,9 +881,6 @@ static const struct instance_globals_y g_init_y = { /* decl.c */ (ROWNO - 1) & ~1, /* y_maze_max */ DUMMY, /* youmonst */ - /* mkmaze.c */ - UNDEFINED_VALUE, /* ymin */ - UNDEFINED_VALUE, /* ymax */ /* pline.c */ NULL, /* you_buf */ 0, /* you_buf_siz */ @@ -954,6 +900,136 @@ static const struct instance_globals_z g_init_z = { IVMAGIC /* z_magic to validate that structure layout has been preserved */ }; +static const struct instance_globals_saved_b init_svb = { + /* dungeon.c */ + UNDEFINED_PTR, /* branches */ + /* mkmaze.c */ + UNDEFINED_PTR, /* bbubbles */ + DUMMY /* bases */ +}; + +static const struct instance_globals_saved_c init_svc = { + /* decl.c */ + DUMMY, /* context */ +}; + +static const struct instance_globals_saved_d init_svd = { + /* dungeon.c */ + { { {0},{0},{0},{0}, 0, {0}, 0, 0, 0, 0, 0 } }, /* dungeons */ + { {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, + {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, + 0, 0, 0, 0, 0, + {0}, {0}, {0}, + {0}, {0}, {0} }, /* dungeon_topology */ + /* decl.c */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* dndest */ + NULL, /* doors */ + 0, /* doors_alloc */ + /* o_init.c */ + DUMMY, /* disco */ +}; + +static const struct instance_globals_saved_e init_sve = { + /* decl.c */ + NULL /* exclusion_zones */ +}; + +static const struct instance_globals_saved_h init_svh = { + /* decl.c */ + 0 /* hackpid */ +}; + +static const struct instance_globals_saved_i init_svi = { + /* decl.c */ + { 0, 0 } /* inv_pos */ +}; + +static const struct instance_globals_saved_k init_svk = { + /* decl.c */ + DUMMY /* killer */ +}; + +static const struct instance_globals_saved_l init_svl = { + /* decl.c */ + { { 0 } }, /* lastseentyp */ + { { { UNDEFINED_VALUES } }, /* level.locations */ + { { UNDEFINED_PTR } }, /* level.objects */ + { { UNDEFINED_PTR } }, /* level.monsters */ + NULL, NULL, NULL, NULL, NULL, {0} }, /* level */ + { UNDEFINED_VALUES } /* level_info */ +}; + +static const struct instance_globals_saved_m init_svm = { + /* dungeon.c */ + UNDEFINED_PTR, /* mapseenchn */ + /* decl.c */ + 0L, /* moves; misnamed turn counter */ + { UNDEFINED_VALUES } /* mvitals */ +}; + +static const struct instance_globals_saved_n init_svn = { + /* dungeon.c */ + 0, /* n_dgns */ + /* mkroom.c */ + 0, /* nroom */ + /* region.c */ + 0 /* n_regions */ +}; + +static const struct instance_globals_saved_o init_svo = { + /* rumors.c */ + 0U /* oracle_cnt */ +}; + +static const struct instance_globals_saved_p init_svp = { + /* decl.c */ + DUMMY, /* plname */ + DUMMY, /* pl_character */ + DUMMY, /* pl_fruit */ +}; + +static const struct instance_globals_saved_q init_svq = { + /* quest.c */ + DUMMY /* quest_status */ +}; + +static const struct instance_globals_saved_r init_svr = { + /* mkroom.c */ + { DUMMY }, /* rooms */ +}; + +static const struct instance_globals_saved_s init_svs = { + /* decl.c */ + { DUMMY }, /* spl_book */ + UNDEFINED_PTR /* sp_levchn */ +}; + +static const struct instance_globals_saved_t init_svt = { + /* decl.c */ + DUMMY, /* tune */ + /* timeout.c */ + 1UL, /* timer_id */ +}; + +static const struct instance_globals_saved_u init_svu = { + /* decl.c */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* updest */ +}; + +static const struct instance_globals_saved_x init_svx = { + /* mkmaze.c */ + UNDEFINED_VALUE, /* xmin */ + UNDEFINED_VALUE /* xmax */ +}; + +static const struct instance_globals_saved_y init_svy = { + /* mkmaze.c */ + UNDEFINED_VALUE, /* ymin */ + UNDEFINED_VALUE /* ymax */ +}; + +static const struct sinfo init_program_state = { 0 }; + #if 0 struct instance_globals g; #endif /* 0 */ @@ -984,6 +1060,26 @@ struct instance_globals_w gw; struct instance_globals_x gx; struct instance_globals_y gy; struct instance_globals_z gz; +struct instance_globals_saved_b svb; +struct instance_globals_saved_c svc; +struct instance_globals_saved_d svd; +struct instance_globals_saved_e sve; +struct instance_globals_saved_h svh; +struct instance_globals_saved_i svi; +struct instance_globals_saved_k svk; +struct instance_globals_saved_l svl; +struct instance_globals_saved_m svm; +struct instance_globals_saved_n svn; +struct instance_globals_saved_o svo; +struct instance_globals_saved_p svp; +struct instance_globals_saved_q svq; +struct instance_globals_saved_r svr; +struct instance_globals_saved_s svs; +struct instance_globals_saved_t svt; +struct instance_globals_saved_u svu; +struct instance_globals_saved_x svx; +struct instance_globals_saved_y svy; +struct sinfo program_state; const struct const_globals cg = { DUMMY, /* zeroobj */ @@ -1041,6 +1137,26 @@ decl_globals_init(void) gx = g_init_x; gy = g_init_y; gz = g_init_z; + svb = init_svb; + svc = init_svc; + svd = init_svd; + sve = init_sve; + svh = init_svh; + svi = init_svi; + svk = init_svk; + svl = init_svl; + svm = init_svm; + svn = init_svn; + svo = init_svo; + svp = init_svp; + svq = init_svq; + svr = init_svr; + svs = init_svs; + svt = init_svt; + svu = init_svu; + svx = init_svx; + svy = init_svy; + program_state = init_program_state; gv.valuables[0].list = gg.gems; gv.valuables[0].size = SIZE(gg.gems); @@ -1083,7 +1199,7 @@ decl_globals_init(void) sfrestinfo = default_sfinfo; sfsaveinfo = default_sfinfo; - gs.subrooms = &gr.rooms[MAXNROFROOMS + 1]; + gs.subrooms = &svr.rooms[MAXNROFROOMS + 1]; ZERO(flags); ZERO(iflags); @@ -1106,11 +1222,11 @@ decl_globals_init(void) /* fields in 'hands_obj' don't matter, just its distinct address */ struct obj hands_obj = DUMMY; -/* gcc 12.2's static analyzer thinks that some fields of gc.context.victual +/* gcc 12.2's static analyzer thinks that some fields of svc.context.victual are uninitialized when compiling 'bite(eat.c)' but that's impossible; it is defined at global scope so guaranteed to be given implicit initialization for fields that aren't explicitly initialized (all of - 'context'); having bite() pass &gc.context.victual to this no-op + 'context'); having bite() pass &svc.context.victual to this no-op eliminates the analyzer's very verbose complaint */ void sa_victual( diff --git a/src/detect.c b/src/detect.c index d5f78f151..1cadedf69 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 detect.c $NHDT-Date: 1715284441 2024/05/09 19:54:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.178 $ */ +/* NetHack 3.7 detect.c $NHDT-Date: 1721684299 2024/07/22 21:38:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.180 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -11,6 +11,16 @@ #include "hack.h" #include "artifact.h" +#ifndef FOUND_FLASH_COUNT +/* for screen alert shown to player when secret door detection or ^E + finds stuff; to use tmp_at() instead of flash_glyph_at(), define as 0; + extra code for tmp_at() will be included and the flash_glyph_at() + calls will execute but won't do anything */ +#define FOUND_FLASH_COUNT 6 +#endif + +struct found_things; + staticfn boolean unconstrain_map(void); staticfn void reconstrain_map(void); staticfn void map_redisplay(void); @@ -20,13 +30,16 @@ staticfn void do_dknown_of(struct obj *); staticfn boolean check_map_spot(coordxy, coordxy, char, unsigned); staticfn boolean clear_stale_map(char, unsigned); staticfn void sense_trap(struct trap *, coordxy, coordxy, int); -staticfn int detect_obj_traps(struct obj *, boolean, int); +staticfn int detect_obj_traps(struct obj *, boolean, int, + struct found_things *) NO_NNARGS; staticfn void display_trap_map(int); staticfn int furniture_detect(void); +staticfn void foundone(coordxy, coordxy, int); staticfn void findone(coordxy, coordxy, genericptr_t); staticfn void openone(coordxy, coordxy, genericptr_t); staticfn int mfind0(struct monst *, boolean); -staticfn int reveal_terrain_getglyph(coordxy, coordxy, unsigned, int, unsigned); +staticfn int reveal_terrain_getglyph(coordxy, coordxy, unsigned, int, + unsigned); /* dummytrap: used when detecting traps finds a door or chest trap; the couple of fields that matter are always re-initialized during use so @@ -36,6 +49,7 @@ static struct trap dummytrap; /* data for enhanced feedback from findone() */ struct found_things { + coord ft_cc; /* for passing extra info to detect_obj_traps() */ uchar num_sdoors; uchar num_scorrs; uchar num_traps; @@ -254,13 +268,13 @@ check_map_spot(coordxy x, coordxy y, char oclass, unsigned material) if (glyph_is_object(glyph)) { /* there's some object shown here */ if (oclass == ALL_CLASSES) { - return !(gl.level.objects[x][y] /* stale if nothing here */ + return !(svl.level.objects[x][y] /* stale if nothing here */ || ((mtmp = m_at(x, y)) != 0 && mtmp->minvent)); } else { if (material && objects[glyph_to_obj(glyph)].oc_material == material) { /* object shown here is of interest because material matches */ - for (otmp = gl.level.objects[x][y]; otmp; + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) if (o_material(otmp, GOLD)) return FALSE; @@ -275,7 +289,7 @@ check_map_spot(coordxy x, coordxy y, char oclass, unsigned material) } if (oclass && objects[glyph_to_obj(glyph)].oc_class == oclass) { /* obj shown here is of interest because its class matches */ - for (otmp = gl.level.objects[x][y]; otmp; + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) if (o_in(otmp, oclass)) return FALSE; @@ -636,7 +650,7 @@ object_detect(struct obj *detector, /* object doing the detecting */ do_dknown_of(obj); } - for (obj = gl.level.buriedobjlist; obj; obj = obj->nobj) { + for (obj = svl.level.buriedobjlist; obj; obj = obj->nobj) { if (!class || o_in(obj, class)) { if (u_at(obj->ox, obj->oy)) ctu++; @@ -684,7 +698,7 @@ object_detect(struct obj *detector, /* object doing the detecting */ /* * Map all buried objects first. */ - for (obj = gl.level.buriedobjlist; obj; obj = obj->nobj) + for (obj = svl.level.buriedobjlist; obj; obj = obj->nobj) if (!class || (otmp = o_in(obj, class)) != 0) { if (class) { if (otmp != obj) { @@ -705,7 +719,7 @@ object_detect(struct obj *detector, /* object doing the detecting */ */ for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) - for (obj = gl.level.objects[x][y]; obj; obj = obj->nexthere) + for (obj = svl.level.objects[x][y]; obj; obj = obj->nexthere) if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0 || (otmp = o_in(obj, boulder)) != 0) { if (class || boulder) { @@ -892,11 +906,12 @@ staticfn int detect_obj_traps( struct obj *objlist, boolean show_them, - int how) /* 1 for misleading map feedback */ + int how, /* 1 for misleading map feedback */ + struct found_things *ft) /* being called by findone() when non-Null */ { struct obj *otmp; coordxy x, y; - int result = OTRAP_NONE; + int trapglyph, result = OTRAP_NONE; /* * TODO? Display locations of unarmed land mine and beartrap objects. @@ -904,17 +919,32 @@ detect_obj_traps( */ dummytrap.ttyp = TRAPPED_CHEST; + trapglyph = ft ? trap_to_glyph(&dummytrap) : GLYPH_NOTHING; for (otmp = objlist; otmp; otmp = otmp->nobj) { - if (Is_box(otmp) && otmp->otrapped - && get_obj_location(otmp, &x, &y, BURIED_TOO | CONTAINED_TOO)) { + x = y = 0; /* lint suppression */ + if ((Is_box(otmp) && otmp->otrapped) || Has_contents(otmp)) { + /* !get_obj_location and !isok should both be impossible here */ + if (!get_obj_location(otmp, &x, &y, BURIED_TOO | CONTAINED_TOO) + || !isok(x, y) + || (ft && (x != ft->ft_cc.x || y != ft->ft_cc.y))) + continue; + } + if (Is_box(otmp) && otmp->otrapped) { result |= u_at(x, y) ? OTRAP_HERE : OTRAP_THERE; + if (ft) { + flash_glyph_at(x, y, trapglyph, FOUND_FLASH_COUNT); + } if (show_them) { dummytrap.tx = x, dummytrap.ty = y; sense_trap(&dummytrap, x, y, how); } + if (ft) { + foundone(x, y, trapglyph); + ft->num_traps++; + } } if (Has_contents(otmp)) - result |= detect_obj_traps(otmp->cobj, show_them, how); + result |= detect_obj_traps(otmp->cobj, show_them, how, ft); } return result; } @@ -924,7 +954,7 @@ display_trap_map(int cursed_src) { struct monst *mon; struct trap *ttmp; - int door, glyph, ter_typ = TER_DETECT | ( cursed_src ? TER_OBJ : TER_TRP ); + int door, glyph, ter_typ = TER_DETECT | (cursed_src ? TER_OBJ : TER_TRP); coord cc; cls(); @@ -933,22 +963,22 @@ display_trap_map(int cursed_src) /* show chest traps first, first buried chests then floor chests, so that subsequent floor trap display will override if both types are present at the same location */ - (void) detect_obj_traps(gl.level.buriedobjlist, TRUE, cursed_src); - (void) detect_obj_traps(fobj, TRUE, cursed_src); + (void) detect_obj_traps(svl.level.buriedobjlist, TRUE, cursed_src, NULL); + (void) detect_obj_traps(fobj, TRUE, cursed_src, NULL); for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon) || (mon->isgd && !mon->mx)) continue; - (void) detect_obj_traps(mon->minvent, TRUE, cursed_src); + (void) detect_obj_traps(mon->minvent, TRUE, cursed_src, NULL); } - (void) detect_obj_traps(gi.invent, TRUE, cursed_src); + (void) detect_obj_traps(gi.invent, TRUE, cursed_src, NULL); for (ttmp = gf.ftrap; ttmp; ttmp = ttmp->ntrap) sense_trap(ttmp, 0, 0, cursed_src); dummytrap.ttyp = TRAPPED_DOOR; for (door = 0; door < gd.doorindex; door++) { - cc = gd.doors[door]; - if (levl[cc.x][cc.y].typ == SDOOR) /* see above */ + cc = svd.doors[door]; + if (levl[cc.x][cc.y].typ == SDOOR) /* can't be trapped; see above */ continue; if (levl[cc.x][cc.y].doormask & D_TRAPPED) { dummytrap.tx = cc.x, dummytrap.ty = cc.y; @@ -997,14 +1027,14 @@ trap_detect( found = TRUE; } /* chest traps (might be buried or carried) */ - if ((tr = detect_obj_traps(fobj, FALSE, 0)) != OTRAP_NONE) { + if ((tr = detect_obj_traps(fobj, FALSE, 0, NULL)) != OTRAP_NONE) { if (tr & OTRAP_THERE) { display_trap_map(cursed_src); return 0; } found = TRUE; } - if ((tr = detect_obj_traps(gl.level.buriedobjlist, FALSE, 0)) + if ((tr = detect_obj_traps(svl.level.buriedobjlist, FALSE, 0, NULL)) != OTRAP_NONE) { if (tr & OTRAP_THERE) { display_trap_map(cursed_src); @@ -1015,7 +1045,8 @@ trap_detect( for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon) || (mon->isgd && !mon->mx)) continue; - if ((tr = detect_obj_traps(mon->minvent, FALSE, 0)) != OTRAP_NONE) { + if ((tr = detect_obj_traps(mon->minvent, FALSE, 0, NULL)) + != OTRAP_NONE) { if (tr & OTRAP_THERE) { display_trap_map(cursed_src); return 0; @@ -1023,11 +1054,11 @@ trap_detect( found = TRUE; } } - if (detect_obj_traps(gi.invent, FALSE, 0) != OTRAP_NONE) + if (detect_obj_traps(gi.invent, FALSE, 0, NULL) != OTRAP_NONE) found = TRUE; /* door traps */ for (door = 0; door < gd.doorindex; door++) { - cc = gd.doors[door]; + cc = svd.doors[door]; /* levl[][].doormask and .wall_info both overlay levl[][].flags; the bit in doormask for D_TRAPPED is also a bit in wall_info; secret doors use wall_info so can't be marked as trapped */ @@ -1362,7 +1393,7 @@ show_map_spot(coordxy x, coordxy y, boolean cnf) * opposite to how normal vision behaves. */ oldglyph = glyph_at(x, y); - if (gl.level.flags.hero_memory) { + if (svl.level.flags.hero_memory) { magic_map_background(x, y, 0); newsym(x, y); /* show it, if not blocked */ } else { @@ -1375,7 +1406,7 @@ show_map_spot(coordxy x, coordxy y, boolean cnf) map_engraving(ep, 1); } else if (glyph_is_trap(oldglyph) || glyph_is_object(oldglyph)) { show_glyph(x, y, oldglyph); - if (gl.level.flags.hero_memory) + if (svl.level.flags.hero_memory) lev->glyph = oldglyph; } } @@ -1395,7 +1426,7 @@ do_mapping(void) for (zy = 0; zy < ROWNO; zy++) show_map_spot(zx, zy, Confusion); - if (!gl.level.flags.hero_memory || unconstrained) { + if (!svl.level.flags.hero_memory || unconstrained) { flush_screen(1); /* flush temp screen */ /* browse_map() instead of display_nhwindow(WIN_MAP, TRUE) */ browse_map(TER_DETECT | TER_MAP | TER_TRP | TER_OBJ, @@ -1472,7 +1503,7 @@ do_vicinity_map( if (OBJ_AT(zx, zy)) { /* not vobj_at(); this is not vision-based access; unlike object detection, we don't notice buried items */ - otmp = gl.level.objects[zx][zy]; + otmp = svl.level.objects[zx][zy]; if (extended) otmp->dknown = 1; map_object(otmp, TRUE); @@ -1489,7 +1520,7 @@ do_vicinity_map( the map and we're not doing extended/blessed clairvoyance (hence must be swallowed or underwater), show "unseen creature" unless map already displayed a monster here */ - if ((unconstrained || !gl.level.flags.hero_memory) + if ((unconstrained || !svl.level.flags.hero_memory) && !extended && (zx != u.ux || zy != u.uy) && !glyph_is_monster(oldglyph)) map_invisible(zx, zy); @@ -1512,7 +1543,7 @@ do_vicinity_map( if (random_farsight && flags.quick_farsight) mdetected = odetected = FALSE; - if (!gl.level.flags.hero_memory || unconstrained + if (!svl.level.flags.hero_memory || unconstrained || mdetected || odetected) { flush_screen(1); /* flush temp screen */ /* the getpos() prompt from browse_map() is only shown when @@ -1568,58 +1599,113 @@ cvt_sdoor_to_door(struct rm *lev) lev->doormask = newmask; } -/* find something at one location; it should find all somethings there +/* update the map for something which has just been found by wand of secret + door detection or wizard mode ^E; will be called multiple times during a + single operation if multiple things of interest are discovered */ +staticfn void +foundone(coordxy zx, coordxy zy, int glyph) +{ + if (glyph_is_cmap(glyph) || glyph_is_unexplored(glyph)) + levl[zx][zy].seenv = SVALL; + + if (!Blind) { + seenV save_viz = gv.viz_array[zy][zx]; + + gv.viz_array[zy][zx] = COULD_SEE | IN_SIGHT; + newsym(zx, zy); + gv.viz_array[zy][zx] = save_viz; + } + +#if FOUND_FLASH_COUNT == 0 + /* + * This works [for non-monsters at present] but flash_glyph_at() + * seems preferrable because the tmp_at() variation requires that + * the player respond to --More-- at the end, the flash_glyph + * variation doesn't. + */ + tmp_at(DISP_CHANGE, glyph); + tmp_at(zx, zy); +#endif +} + +/* find something at one location; this should find all somethings there since it is used for magical detection rather than physical searching */ staticfn void findone(coordxy zx, coordxy zy, genericptr_t whatfound) { - struct trap *ttmp; - struct monst *mtmp; + struct rm *lev = &levl[zx][zy]; + struct trap *ttmp = t_at(zx, zy); + struct monst *mtmp = m_at(zx, zy); struct found_things *found_p = (struct found_things *) whatfound; - /* - * This used to use if/else-if/else-if/else/end-if but that only - * found the first hidden thing at the location. Two hidden things - * at the same spot is uncommon, but it's possible for an undetected - * monster to be hiding at the location of an unseen trap. - */ + if (mtmp && (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx))) + mtmp = (struct monst *) NULL; + found_p->ft_cc.x = zx; /* needed by detect_obj_traps() */ + found_p->ft_cc.y = zy; - if (levl[zx][zy].typ == SDOOR) { - cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */ + if (lev->typ == SDOOR) { + nhsym sym = lev->horizontal ? S_hcdoor : S_vcdoor; + + flash_glyph_at(zx, zy, cmap_to_glyph(sym), FOUND_FLASH_COUNT); + cvt_sdoor_to_door(lev); /* set lev->typ = DOOR */ magic_map_background(zx, zy, 0); - newsym(zx, zy); + foundone(zx, zy, back_to_glyph(zx, zy)); found_p->num_sdoors++; - } else if (levl[zx][zy].typ == SCORR) { - levl[zx][zy].typ = CORR; + } else if (lev->typ == SCORR) { + flash_glyph_at(zx, zy, cmap_to_glyph(S_corr), FOUND_FLASH_COUNT); + lev->typ = CORR; unblock_point(zx, zy); magic_map_background(zx, zy, 0); - newsym(zx, zy); + foundone(zx, zy, cmap_to_glyph(S_corr)); found_p->num_scorrs++; } - if ((ttmp = t_at(zx, zy)) != 0 && !ttmp->tseen + if (ttmp && !ttmp->tseen /* [shouldn't successful 'find' reveal and activate statue traps?] */ && ttmp->ttyp != STATUE_TRAP) { + flash_glyph_at(zx, zy, trap_to_glyph(ttmp), FOUND_FLASH_COUNT); ttmp->tseen = 1; - newsym(zx, zy); + foundone(zx, zy, trap_to_glyph(ttmp)); found_p->num_traps++; } + if (closed_door(zx, zy) && (lev->doormask & D_TRAPPED) != 0) { + dummytrap.ttyp = TRAPPED_DOOR; + dummytrap.tx = zx, dummytrap.ty = zy; + flash_glyph_at(zx, zy, trap_to_glyph(&dummytrap), FOUND_FLASH_COUNT); + dummytrap.tseen = 1; + map_trap(&dummytrap, 1); + sense_trap(&dummytrap, zx, zy, 0); /* handles Hallucination */ + foundone(zx, zy, trap_to_glyph(&dummytrap)); + found_p->num_traps++; + } + /* trapped chests */ + (void) detect_obj_traps(svl.level.buriedobjlist, TRUE, 0, found_p); + (void) detect_obj_traps(fobj, TRUE, 0, found_p); + if (mtmp) + (void) detect_obj_traps(mtmp->minvent, TRUE, 0, found_p); + if (u_at(zx, zy)) + (void) detect_obj_traps(gi.invent, TRUE, 0, found_p); - if ((mtmp = m_at(zx, zy)) != 0 - /* brings hidden monster out of hiding even if already sensed */ - && (!canspotmon(mtmp) || mtmp->mundetected || M_AP_TYPE(mtmp))) { + if (mtmp && (!canspotmon(mtmp) || mtmp->mundetected || M_AP_TYPE(mtmp))) { if (M_AP_TYPE(mtmp)) { + flash_glyph_at(zx, zy, mon_to_glyph(mtmp, rn2_on_display_rng), + FOUND_FLASH_COUNT); seemimic(mtmp); + /*foundone(zx, zy, mon_to_glyph(mtmp, rn2_on_display_rng);*/ found_p->num_mons++; } else if (mtmp->mundetected && (is_hider(mtmp->data) || hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)) { + flash_glyph_at(zx, zy, mon_to_glyph(mtmp, rn2_on_display_rng), + FOUND_FLASH_COUNT); mtmp->mundetected = 0; + /*foundone(zx, zy, mon_to_glyph(mtmp, rn2_on_display_rng);*/ newsym(zx, zy); found_p->num_mons++; } - if (!glyph_is_invisible(levl[zx][zy].glyph)) { + if (!glyph_is_invisible(lev->glyph)) { if (!canspotmon(mtmp)) { + flash_glyph_at(zx, zy, GLYPH_INVISIBLE, FOUND_FLASH_COUNT); map_invisible(zx, zy); found_p->num_invis++; } @@ -1627,6 +1713,8 @@ findone(coordxy zx, coordxy zy, genericptr_t whatfound) found_p->num_kept_invis++; } } else if (unmap_invisible(zx, zy)) { + /* flash the invisible monster glyph because it is already gone */ + flash_glyph_at(zx, zy, GLYPH_INVISIBLE, FOUND_FLASH_COUNT); found_p->num_cleared_invis++; } } @@ -1639,7 +1727,7 @@ openone(coordxy zx, coordxy zy, genericptr_t num) int *num_p = (int *) num; if (OBJ_AT(zx, zy)) { - for (otmp = gl.level.objects[zx][zy]; otmp; otmp = otmp->nexthere) { + for (otmp = svl.level.objects[zx][zy]; otmp; otmp = otmp->nexthere) { if (Is_box(otmp) && otmp->olocked) { otmp->olocked = 0; (*num_p)++; @@ -1701,9 +1789,22 @@ findit(void) char buf[BUFSZ]; struct found_things found; + /* + * findit() -> do_clear_area(findone) -> findone() -> foundone() + * is used to notify player where various things have been found. + * Changing FOUND_FLASH_COUNT to 0 will switch to tmp_at() to + * highlight all discoveries for the current operation, but requires + * player to respond to --More-- when done. Neither allows browsing + * the map via getpos() autodescribe (until after it has reverted to + * normal display, where found traps might be covered by objects). + */ + if (u.uswallow) return 0; +#if FOUND_FLASH_COUNT == 0 /* _COUNT > 0 doesn't need to init tmp_at() */ + tmp_at(DISP_ALL, GLYPH_NOTHING); +#endif (void) memset((genericptr_t) &found, 0, sizeof found); do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (genericptr_t) &found); /* count that controls "reveal" punctuation; 0..4 */ @@ -1739,6 +1840,12 @@ findit(void) Strcat(buf, "a trap"); num += found.num_traps; } + +#if FOUND_FLASH_COUNT == 0 + int tmp_num; + tmp_num = num; /* sdoors, scorrs, and traps call tmp_at() */ +#endif + if (found.num_mons) { if (*buf) Strcat(buf, (k > 2) ? ", and " : " and "); @@ -1753,10 +1860,10 @@ findit(void) if (found.num_invis) { if (found.num_invis > 1) - Sprintf(buf, "%d%s invisible monsters", found.num_invis, + Sprintf(buf, "%d%s unseen monsters", found.num_invis, found.num_kept_invis ? " other" : ""); else - Sprintf(buf, "%s invisible monster", + Sprintf(buf, "%s unseen monster", found.num_kept_invis ? "another" : "an"); You("detect %s!", buf); num += found.num_invis; @@ -1771,6 +1878,16 @@ findit(void) } /* note: num_kept_invis is not included in the final result */ + if (!num) + You("don't find anything."); +#if FOUND_FLASH_COUNT == 0 + else if (tmp_num) { + flush_screen(1); + display_nhwindow(WIN_MAP, TRUE); + } + tmp_at(DISP_END, GLYPH_NOTHING); /* note: outside of 'if (tmp_num) { }' */ +#endif + return num; } @@ -1914,7 +2031,7 @@ dosearch0(int aflag) /* intrinsic autosearch vs explicit searching */ if (u_at(x, y)) continue; - if (Blind && !aflag) + if (!aflag && (Blind || visible_region_at(x, y))) feel_location(x, y); if (levl[x][y].typ == SDOOR) { if (rnl(7 - fund)) @@ -2022,6 +2139,11 @@ premap_detect(void) } } +/* used to see under visible gas/cloud regions; caller must declare cmaptmp */ +#define glyph_is_gascloud(glyph) \ + (glyph_is_cmap(glyph) && ((cmaptmp = glyph_to_cmap(glyph)) == S_cloud \ + || cmaptmp == S_poisoncloud)) + staticfn int reveal_terrain_getglyph( coordxy x, coordxy y, @@ -2029,26 +2151,30 @@ reveal_terrain_getglyph( int default_glyph, unsigned which_subset) { + struct trap *t; + struct monst *mtmp; int glyph, levl_glyph; uchar seenv; boolean keep_traps = (which_subset & TER_TRP) != 0, keep_objs = (which_subset & TER_OBJ) != 0, keep_mons = (which_subset & TER_MON) != 0, full = (which_subset & TER_FULL) != 0; - struct monst *mtmp; - struct trap *t; /* for 'full', show the actual terrain for the entire level, otherwise what the hero remembers for seen locations with monsters, objects, and/or traps removed as caller dictates */ - seenv = (full || gl.level.flags.hero_memory) + seenv = (full || svl.level.flags.hero_memory) ? levl[x][y].seenv : cansee(x, y) ? SVALL : 0; if (full) { levl[x][y].seenv = SVALL; glyph = back_to_glyph(x, y); levl[x][y].seenv = seenv; } else { - levl_glyph = gl.level.flags.hero_memory ? levl[x][y].glyph + int cmaptmp = 0; /* used by glyph_is_gascloud() macro */ + NhRegion *reg = visible_region_at(x, y); + boolean was_mon = FALSE; + + levl_glyph = svl.level.flags.hero_memory ? levl[x][y].glyph : seenv ? back_to_glyph(x, y) : default_glyph; /* glyph_at() returns the displayed glyph, which might @@ -2057,24 +2183,45 @@ reveal_terrain_getglyph( the invisible monster glyph, which is handled like an object, replacing any object or trap at its spot) */ glyph = !swallowed ? glyph_at(x, y) : levl_glyph; - if (keep_mons && u_at(x, y) && swallowed) + if (keep_mons && u_at(x, y) && swallowed) { glyph = mon_to_glyph(u.ustuck, rn2_on_display_rng); - else if (((glyph_is_monster(glyph) - || glyph_is_warning(glyph)) && !keep_mons) - || glyph_is_swallow(glyph)) + } else if ((!keep_mons && (glyph_is_monster(glyph) + || glyph_is_warning(glyph))) + || glyph_is_swallow(glyph)) { glyph = levl_glyph; - if (((glyph_is_object(glyph) && !keep_objs) + was_mon = TRUE; + } + if (((!keep_objs && glyph_is_object(glyph)) || glyph_is_invisible(glyph)) && keep_traps && !covers_traps(x, y)) { if ((t = t_at(x, y)) != 0 && t->tseen) glyph = trap_to_glyph(t); } - if ((glyph_is_object(glyph) && !keep_objs) - || (glyph_is_trap(glyph) && !keep_traps) + if ((!keep_objs && glyph_is_object(glyph)) + /* we either show both traps and visible regions (trap if both + are present at the same spot) or neither traps nor regions */ + || (!keep_traps && (glyph_is_trap(glyph) + || (reg && glyph_is_gascloud(glyph)))) + || (reg && was_mon) || glyph_is_invisible(glyph)) { if (!seenv) { - glyph = default_glyph; - } else if (gl.lastseentyp[x][y] == levl[x][y].typ) { + /* it's possible to have a visible region shown at an + otherwise unexplored location (cast stinking cloud + through unexplored corridor into lit room, then approach + far enough to be adjacent to the cloud without having + seen the corridor underneath it) */ + glyph = !reg ? default_glyph : GLYPH_UNEXPLORED; + } else if (keep_traps && reg + && (glyph_is_gascloud(glyph) || was_mon)) { + t = t_at(x, y); + /* we need reg->glyph here when there's a monster shown + at a region spot; the region glyph isn't the remembered + background glyph or the current glyph */ + glyph = (t && t->tseen) ? trap_to_glyph(t) : reg->glyph; + /* FIXME? what about objects temporarily hidden by regions? + when objects are being shown, shouldn't showing them take + precedence over showing the region, just like traps? */ + } else if (svl.lastseentyp[x][y] == levl[x][y].typ) { glyph = back_to_glyph(x, y); } else { /* look for a mimic here posing as furniture; @@ -2098,7 +2245,7 @@ reveal_terrain_getglyph( * doormask==D_OPEN for an open door remembered as a wall. */ save_spot = levl[x][y]; - levl[x][y].typ = gl.lastseentyp[x][y]; + levl[x][y].typ = svl.lastseentyp[x][y]; if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR) xy_set_wall_state(x, y); /* levl[x][y].wall_info */ glyph = back_to_glyph(x, y); @@ -2115,17 +2262,21 @@ reveal_terrain_getglyph( return glyph; } +#undef glyph_is_gascloud + #ifdef DUMPLOG void dump_map(void) { + char buf[COLBUFSZ]; coordxy x, y; int glyph, skippedrows, lastnonblank; - unsigned subset = TER_MAP | TER_TRP | TER_OBJ | TER_MON; - int default_glyph = cmap_to_glyph(gl.level.flags.arboreal ? S_tree - : S_stone); - char buf[COLBUFSZ]; boolean blankrow, toprow; + unsigned subset = TER_MAP | TER_TRP | TER_OBJ | TER_MON; + /* cmap_to_glyph() evaluates its argument multiple times, so pull the + tree vs stone conditional out of it */ + nhsym default_sym = svl.level.flags.arboreal ? S_tree : S_stone; + int default_glyph = cmap_to_glyph(default_sym); /* * Squeeze out excess vertical space when dumping the map. @@ -2197,7 +2348,7 @@ reveal_terrain( if (unconstrain_map()) docrt(); - default_glyph = cmap_to_glyph(gl.level.flags.arboreal ? S_tree + default_glyph = cmap_to_glyph(svl.level.flags.arboreal ? S_tree : S_stone); for (x = 1; x < COLNO; x++) @@ -2237,4 +2388,6 @@ reveal_terrain( return; } +#undef FOUND_FLASH_COUNT + /*detect.c*/ diff --git a/src/dig.c b/src/dig.c index 7ec2b59ad..ed0879683 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dig.c $NHDT-Date: 1709928001 2024/03/08 20:00:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.211 $ */ +/* NetHack 3.7 dig.c $NHDT-Date: 1724613307 2024/08/25 19:15:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.219 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -187,7 +187,7 @@ dig_typ(struct obj *otmp, coordxy x, coordxy y) : IS_TREE(levl[x][y].typ) ? (ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE) : (ispick && IS_ROCK(levl[x][y].typ) - && (!gl.level.flags.arboreal + && (!svl.level.flags.arboreal || IS_WALL(levl[x][y].typ))) ? DIGTYP_ROCK : DIGTYP_UNDIGGABLE); @@ -205,82 +205,124 @@ is_digging(void) #define BY_YOU (&gy.youmonst) #define BY_OBJECT ((struct monst *) 0) -boolean -dig_check(struct monst *madeby, boolean verbose, coordxy x, coordxy y) +enum digcheck_result +dig_check(struct monst *madeby, coordxy x, coordxy y) { struct trap *ttmp = t_at(x, y); - const char *verb = - (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in"; if (On_stairs(x, y)) { stairway *stway = stairway_at(x, y); if (stway->isladder) { - if (verbose) - pline_The("ladder resists your effort."); - } else if (verbose) - pline_The("stairs are too hard to %s.", verb); - return FALSE; + return DIGCHECK_FAIL_ONLADDER; + } else { + return DIGCHECK_FAIL_ONSTAIRS; + } } else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) { - if (verbose) - pline_The("throne is too hard to break apart."); - return FALSE; + return DIGCHECK_FAIL_THRONE; } else if (IS_ALTAR(levl[x][y].typ) && (madeby != BY_OBJECT || (altarmask_at(x, y) & AM_SANCTUM) != 0)) { - if (verbose) - pline_The("altar is too hard to break apart."); - return FALSE; + return DIGCHECK_FAIL_ALTAR; } else if (Is_airlevel(&u.uz)) { - if (verbose) - You("cannot %s thin air.", verb); - return FALSE; + return DIGCHECK_FAIL_AIRLEVEL; } else if (Is_waterlevel(&u.uz)) { - if (verbose) - pline_The("%s splashes and subsides.", hliquid("water")); - return FALSE; + return DIGCHECK_FAIL_WATERLEVEL; } else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR - && (levl[x][y].wall_info & W_NONDIGGABLE) != 0) - || (ttmp - && (undestroyable_trap(ttmp->ttyp) - || (!Can_dig_down(&u.uz) && !levl[x][y].candig)))) { - if (verbose) - pline_The("%s here is too hard to %s.", surface(x, y), verb); - return FALSE; + && (levl[x][y].wall_info & W_NONDIGGABLE) != 0)) { + return DIGCHECK_FAIL_TOOHARD; + } else if (ttmp && undestroyable_trap(ttmp->ttyp)) { + return DIGCHECK_FAIL_UNDESTROYABLETRAP; + } else if (!Can_dig_down(&u.uz) && !levl[x][y].candig) { + if (ttmp) { + if (!is_hole(ttmp->ttyp) && !is_pit(ttmp->ttyp)) + return DIGCHECK_PASSED_DESTROY_TRAP; + else + return DIGCHECK_FAIL_CANTDIG; + } else { + return DIGCHECK_PASSED_PITONLY; + } } else if (sobj_at(BOULDER, x, y)) { - if (verbose) - There("isn't enough room to %s here.", verb); - return FALSE; + return DIGCHECK_FAIL_BOULDER; } else if (madeby == BY_OBJECT /* the block against existing traps is mainly to prevent broken wands from turning holes into pits */ && (ttmp || is_pool_or_lava(x, y))) { /* digging by player handles pools separately */ - return FALSE; + return DIGCHECK_FAIL_OBJ_POOL_OR_TRAP; + } + return DIGCHECK_PASSED; +} + +void +digcheck_fail_message(enum digcheck_result digresult, struct monst *madeby, + coordxy x, coordxy y) +{ + const char *verb = + (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in"; + + if (digresult < DIGCHECK_FAILED) + return; + + switch (digresult) { + case DIGCHECK_FAIL_AIRLEVEL: + You("cannot %s thin air.", verb); + break; + case DIGCHECK_FAIL_ALTAR: + pline_The("altar is too hard to break apart."); + break; + case DIGCHECK_FAIL_BOULDER: + There("isn't enough room to %s here.", verb); + break; + case DIGCHECK_FAIL_ONLADDER: + pline_The("ladder resists your effort."); + break; + case DIGCHECK_FAIL_ONSTAIRS: + pline_The("stairs are too hard to %s.", verb); + break; + case DIGCHECK_FAIL_THRONE: + pline_The("throne is too hard to break apart."); + break; + case DIGCHECK_FAIL_CANTDIG: + case DIGCHECK_FAIL_TOOHARD: + case DIGCHECK_FAIL_UNDESTROYABLETRAP: + pline_The("%s here is too hard to %s.", surface(x, y), verb); + break; + case DIGCHECK_FAIL_WATERLEVEL: + pline_The("%s splashes and subsides.", hliquid("water")); + break; + case DIGCHECK_FAIL_OBJ_POOL_OR_TRAP: + case DIGCHECK_PASSED: + case DIGCHECK_PASSED_PITONLY: + case DIGCHECK_PASSED_DESTROY_TRAP: + break; } - return TRUE; } staticfn int dig(void) { struct rm *lev; - coordxy dpx = gc.context.digging.pos.x, dpy = gc.context.digging.pos.y; + coordxy dpx = svc.context.digging.pos.x, dpy = svc.context.digging.pos.y; boolean ispick = uwep && is_pick(uwep); const char *verb = (!uwep || is_pick(uwep)) ? "dig into" : "chop through"; + enum digcheck_result dcresult = DIGCHECK_PASSED; lev = &levl[dpx][dpy]; /* perhaps a nymph stole your pick-axe while you were busy digging */ /* or perhaps you teleported away */ if (u.uswallow || !uwep || (!ispick && !is_axe(uwep)) - || !on_level(&gc.context.digging.level, &u.uz) - || ((gc.context.digging.down ? (dpx != u.ux || dpy != u.uy) + || !on_level(&svc.context.digging.level, &u.uz) + || ((svc.context.digging.down ? (dpx != u.ux || dpy != u.uy) : !next2u(dpx, dpy)))) return 0; - if (gc.context.digging.down) { - if (!dig_check(BY_YOU, TRUE, u.ux, u.uy)) + if (svc.context.digging.down) { + dcresult = dig_check(BY_YOU, u.ux, u.uy); + if (dcresult >= DIGCHECK_FAILED) { + digcheck_fail_message(dcresult, BY_YOU, u.ux, u.uy); return 0; - } else { /* !gc.context.digging.down */ + } + } else { /* !svc.context.digging.down */ if (IS_TREE(lev->typ) && !may_dig(dpx, dpy) && dig_typ(uwep, dpx, dpy) == DIGTYP_TREE) { pline("This tree seems to be petrified."); @@ -322,21 +364,22 @@ dig(void) return 0; } - gc.context.digging.effort += + svc.context.digging.effort += 10 + rn2(5) + abon() + uwep->spe - greatest_erosion(uwep) + u.udaminc; if (Race_if(PM_DWARF)) - gc.context.digging.effort *= 2; - if (gc.context.digging.down) { + svc.context.digging.effort *= 2; + if (svc.context.digging.down) { struct trap *ttmp = t_at(dpx, dpy); - if (gc.context.digging.effort > 250 || (ttmp && ttmp->ttyp == HOLE)) { + if (svc.context.digging.effort > 250 + || (ttmp && ttmp->ttyp == HOLE)) { (void) dighole(FALSE, FALSE, (coord *) 0); - (void) memset((genericptr_t) &gc.context.digging, 0, - sizeof gc.context.digging); + (void) memset((genericptr_t) &svc.context.digging, 0, + sizeof svc.context.digging); return 0; /* done with digging */ } - if (gc.context.digging.effort <= 50 + if (svc.context.digging.effort <= 50 || (ttmp && (ttmp->ttyp == TRAPDOOR || is_pit(ttmp->ttyp)))) { return 1; } else if (ttmp && (ttmp->ttyp == LANDMINE @@ -345,8 +388,8 @@ dig(void) hero should have used #untrap first */ dotrap(ttmp, FORCETRAP); /* restart completely from scratch if we resume digging */ - (void) memset((genericptr_t) &gc.context.digging, 0, - sizeof gc.context.digging); + (void) memset((genericptr_t) &svc.context.digging, 0, + sizeof svc.context.digging); return 0; } else if (ttmp && ttmp->ttyp == BEAR_TRAP && u.utrap) { if (rnl(7) > (Fumbling ? 1 : 4)) { @@ -368,7 +411,18 @@ dig(void) reset_utrap(TRUE); /* release from trap, maybe Lev or Fly */ } /* we haven't made any progress toward a pit yet */ - gc.context.digging.effort = 0; + svc.context.digging.effort = 0; + return 0; + } else if (ttmp && dcresult == DIGCHECK_PASSED_DESTROY_TRAP) { + const char *ttmpname = trapname(ttmp->ttyp, FALSE); + + if (ispick) + You("destroy %s with %s.", + ttmp->tseen ? the(ttmpname) : an(ttmpname), + yobjnam(uwep, (const char *) 0)); + deltrap(ttmp); + /* we haven't made any progress toward a pit yet */ + svc.context.digging.effort = 0; return 0; } @@ -379,13 +433,13 @@ dig(void) /* make pit at */ if (dighole(TRUE, FALSE, (coord *) 0)) { - gc.context.digging.level.dnum = 0; - gc.context.digging.level.dlevel = -1; + svc.context.digging.level.dnum = 0; + svc.context.digging.level.dlevel = -1; } return 0; } - if (gc.context.digging.effort > 100) { + if (svc.context.digging.effort > 100) { const char *digtxt, *dmgtxt = (const char *) 0; struct obj *obj; boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE); @@ -436,9 +490,10 @@ dig(void) add_damage(dpx, dpy, SHOP_WALL_DMG); dmgtxt = "damage"; } - if (gl.level.flags.is_maze_lev) { + if (svl.level.flags.is_maze_lev) { lev->typ = ROOM, lev->flags = 0; - } else if (gl.level.flags.is_cavernous_lev && !in_town(dpx, dpy)) { + } else if (svl.level.flags.is_cavernous_lev + && !in_town(dpx, dpy)) { lev->typ = CORR, lev->flags = 0; } else { lev->typ = DOOR, lev->doormask = D_NODOOR; @@ -463,7 +518,7 @@ dig(void) if (!does_block(dpx, dpy, &levl[dpx][dpy])) unblock_point(dpx, dpy); /* vision: can see through */ feel_newsym(dpx, dpy); - if (digtxt && !gc.context.digging.quiet) + if (digtxt && !svc.context.digging.quiet) pline1(digtxt); /* after newsym */ if (dmgtxt) pay_for_damage(dmgtxt, FALSE); @@ -489,10 +544,10 @@ dig(void) newsym(dpx, dpy); } cleanup: - gc.context.digging.lastdigtime = gm.moves; - gc.context.digging.quiet = FALSE; - gc.context.digging.level.dnum = 0; - gc.context.digging.level.dlevel = -1; + svc.context.digging.lastdigtime = svm.moves; + svc.context.digging.quiet = FALSE; + svc.context.digging.level.dnum = 0; + svc.context.digging.level.dlevel = -1; return 0; } else { /* not enough effort has been spent yet */ static const char *const d_target[6] = { "", "rock", "statue", @@ -549,7 +604,7 @@ holetime(void) { if (go.occupation != dig || !*u.ushops) return -1; - return ((250 - gc.context.digging.effort) / 20); + return ((250 - svc.context.digging.effort) / 20); } /* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */ @@ -636,11 +691,12 @@ digactualhole(coordxy x, coordxy y, struct monst *madeby, int ttyp) surface_type = surface(x, y); } shopdoor = IS_DOOR(lev->typ) && *in_rooms(x, y, SHOPBASE); - oldobjs = gl.level.objects[x][y]; + oldobjs = svl.level.objects[x][y]; + ttmp = maketrap(x, y, ttyp); if (!ttmp) return; - newobjs = gl.level.objects[x][y]; + newobjs = svl.level.objects[x][y]; ttmp->madeby_u = heros_fault; ttmp->tseen = 0; if (cansee(x, y)) @@ -810,7 +866,7 @@ liquid_flow( if (fillmsg) pline(fillmsg, hliquid(typ == LAVAPOOL ? "lava" : "water")); /* handle object damage before hero damage; affects potential bones */ - if ((objchain = gl.level.objects[x][y]) != 0) { + if ((objchain = svl.level.objects[x][y]) != 0) { if (typ == LAVAPOOL) fire_damage_chain(objchain, TRUE, TRUE, x, y); else @@ -836,7 +892,8 @@ dighole(boolean pit_only, boolean by_magic, coord *cc) schar typ, old_typ; coordxy dig_x, dig_y; boolean nohole, retval = FALSE; - + enum digcheck_result dig_check_result; + if (!cc) { dig_x = u.ux; dig_y = u.uy; @@ -849,7 +906,10 @@ dighole(boolean pit_only, boolean by_magic, coord *cc) ttmp = t_at(dig_x, dig_y); lev = &levl[dig_x][dig_y]; - nohole = (!Can_dig_down(&u.uz) && !lev->candig); + dig_check_result = dig_check(BY_YOU, dig_x, dig_y); + /* nohole = (!Can_dig_down(&u.uz) && !lev->candig); */ + nohole = (dig_check_result == DIGCHECK_FAIL_CANTDIG + || dig_check_result == DIGCHECK_FAIL_TOOHARD); old_typ = lev->typ; if ((ttmp && (undestroyable_trap(ttmp->ttyp) || nohole)) @@ -952,7 +1012,9 @@ dighole(boolean pit_only, boolean by_magic, coord *cc) } /* finally we get to make a hole */ - if (nohole || pit_only) + if (nohole || pit_only + || dig_check_result == DIGCHECK_PASSED_DESTROY_TRAP + || dig_check_result == DIGCHECK_PASSED_PITONLY) digactualhole(dig_x, dig_y, BY_YOU, PIT); else digactualhole(dig_x, dig_y, BY_YOU, HOLE); @@ -1220,32 +1282,33 @@ use_pick_axe2(struct obj *obj) "cutting the tree" }; gd.did_dig_msg = FALSE; - gc.context.digging.quiet = FALSE; - if (gc.context.digging.pos.x != rx - || gc.context.digging.pos.y != ry - || !on_level(&gc.context.digging.level, &u.uz) - || gc.context.digging.down) { + svc.context.digging.quiet = FALSE; + if (svc.context.digging.pos.x != rx + || svc.context.digging.pos.y != ry + || !on_level(&svc.context.digging.level, &u.uz) + || svc.context.digging.down) { if (flags.autodig && dig_target == DIGTYP_ROCK - && !gc.context.digging.down - && u_at(gc.context.digging.pos.x, gc.context.digging.pos.y) - && (gm.moves <= gc.context.digging.lastdigtime + 2 - && gm.moves >= gc.context.digging.lastdigtime)) { + && !svc.context.digging.down + && u_at(svc.context.digging.pos.x, + svc.context.digging.pos.y) + && (svm.moves <= svc.context.digging.lastdigtime + 2 + && svm.moves >= svc.context.digging.lastdigtime)) { /* avoid messages if repeated autodigging */ gd.did_dig_msg = TRUE; - gc.context.digging.quiet = TRUE; + svc.context.digging.quiet = TRUE; } - gc.context.digging.down = gc.context.digging.chew = FALSE; - gc.context.digging.warned = FALSE; - gc.context.digging.pos.x = rx; - gc.context.digging.pos.y = ry; - assign_level(&gc.context.digging.level, &u.uz); - gc.context.digging.effort = 0; - if (!gc.context.digging.quiet) + svc.context.digging.down = svc.context.digging.chew = FALSE; + svc.context.digging.warned = FALSE; + svc.context.digging.pos.x = rx; + svc.context.digging.pos.y = ry; + assign_level(&svc.context.digging.level, &u.uz); + svc.context.digging.effort = 0; + if (!svc.context.digging.quiet) You("start %s.", d_action[dig_target]); } else { - You("%s %s.", gc.context.digging.chew ? "begin" : "continue", + You("%s %s.", svc.context.digging.chew ? "begin" : "continue", d_action[dig_target]); - gc.context.digging.chew = FALSE; + svc.context.digging.chew = FALSE; } set_occupation(dig, verbing, 0); } @@ -1273,16 +1336,17 @@ use_pick_axe2(struct obj *obj) surface(u.ux, u.uy)); u_wipe_engr(3); } else { - if (gc.context.digging.pos.x != u.ux || gc.context.digging.pos.y != u.uy - || !on_level(&gc.context.digging.level, &u.uz) - || !gc.context.digging.down) { - gc.context.digging.chew = FALSE; - gc.context.digging.down = TRUE; - gc.context.digging.warned = FALSE; - gc.context.digging.pos.x = u.ux; - gc.context.digging.pos.y = u.uy; - assign_level(&gc.context.digging.level, &u.uz); - gc.context.digging.effort = 0; + if (svc.context.digging.pos.x != u.ux + || svc.context.digging.pos.y != u.uy + || !on_level(&svc.context.digging.level, &u.uz) + || !svc.context.digging.down) { + svc.context.digging.chew = FALSE; + svc.context.digging.down = TRUE; + svc.context.digging.warned = FALSE; + svc.context.digging.pos.x = u.ux; + svc.context.digging.pos.y = u.uy; + assign_level(&svc.context.digging.level, &u.uz); + svc.context.digging.effort = 0; You("start %s downward.", verbing); if (*u.ushops) { shopdig(0); @@ -1324,7 +1388,7 @@ watch_dig(struct monst *mtmp, coordxy x, coordxy y, boolean zap) if (mtmp) { SetVoice(mtmp, 0, 80, 0); - if (zap || gc.context.digging.warned) { + if (zap || svc.context.digging.warned) { verbalize("Halt, vandal! You're under arrest!"); (void) angry_guards(!!Deaf); } else { @@ -1339,7 +1403,7 @@ watch_dig(struct monst *mtmp, coordxy x, coordxy y, boolean zap) else str = "fountain"; verbalize("Hey, stop damaging that %s!", str); - gc.context.digging.warned = TRUE; + svc.context.digging.warned = TRUE; } if (is_digging()) stop_occupation(); @@ -1409,9 +1473,9 @@ mdig_tunnel(struct monst *mtmp) } if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) add_damage(mtmp->mx, mtmp->my, 0L); - if (gl.level.flags.is_maze_lev) { + if (svl.level.flags.is_maze_lev) { here->typ = ROOM, here->flags = 0; - } else if (gl.level.flags.is_cavernous_lev + } else if (svl.level.flags.is_cavernous_lev && !in_town(mtmp->mx, mtmp->my)) { here->typ = CORR, here->flags = 0; } else { @@ -1549,7 +1613,7 @@ zap_dig(void) /* normal case: digging across the level */ shopdoor = shopwall = FALSE; - maze_dig = gl.level.flags.is_maze_lev && !Is_earthlevel(&u.uz); + maze_dig = svl.level.flags.is_maze_lev && !Is_earthlevel(&u.uz); zx = u.ux + u.dx; zy = u.uy + u.dy; if (u.utrap && u.utraptype == TT_PIT @@ -1654,7 +1718,7 @@ zap_dig(void) shopwall = TRUE; } watch_dig((struct monst *) 0, zx, zy, TRUE); - if (gl.level.flags.is_cavernous_lev && !in_town(zx, zy)) { + if (svl.level.flags.is_cavernous_lev && !in_town(zx, zy)) { room->typ = CORR, room->flags = 0; } else { room->typ = DOOR, room->doormask = D_NODOOR; @@ -1829,7 +1893,7 @@ buried_ball(coord *cc) * criterium (within 2 steps of tethered hero's present location) * it will find an arbitrary one rather than the one which used * to be uball. Once 3.6.{0,1} save file compatibility is broken, - * we should add gc.context.buriedball_oid and then we can find the + * we should add svc.context.buriedball_oid and then we can find the * actual former uball, which might be extra heavy or christened * or not the one buried directly underneath the target spot. * @@ -1841,7 +1905,7 @@ buried_ball(coord *cc) of u.utraptype is no longer meaningful; if u.utrap is still set then u.utraptype needs to be for buried ball */ if (!u.utrap || u.utraptype == TT_BURIEDBALL) { - for (otmp = gl.level.buriedobjlist; otmp; otmp = otmp->nobj) { + for (otmp = svl.level.buriedobjlist; otmp; otmp = otmp->nobj) { if (otmp->otyp != HEAVY_IRON_BALL) continue; /* if found at the target spot, we're done */ @@ -1994,11 +2058,11 @@ bury_objs(int x, int y) costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && costly_spot(x, y)); - if (gl.level.objects[x][y] != (struct obj *) 0) { + if (svl.level.objects[x][y] != (struct obj *) 0) { debugpline2("bury_objs: at <%d,%d>", x, y); } - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp2) { - if (costly && !gc.context.mon_moving) { + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp2) { + if (costly && !svc.context.mon_moving) { loss += stolen_value(otmp, x, y, (boolean) shkp->mpeaceful, TRUE); if (otmp->oclass != COIN_CLASS) otmp->no_charge = 1; @@ -2028,7 +2092,7 @@ unearth_objs(int x, int y) cc.x = x; cc.y = y; bball = buried_ball(&cc); - for (otmp = gl.level.buriedobjlist; otmp; otmp = otmp2) { + for (otmp = svl.level.buriedobjlist; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->ox == x && otmp->oy == y) { if (bball && otmp == bball @@ -2230,30 +2294,28 @@ wiz_debug_cmd_bury(void) for (y = u.uy - 1; y <= u.uy + 1; y++) { if (!isok(x, y)) continue; - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) ++before; bury_objs(x, y); + + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) + ++after; } - if (before == 0) { /* there was nothing here */ + diff = before - after; + if (before == 0) + /* there was nothing here */ pline("No objects here or adjacent to bury."); - } else { - 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; - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp->nexthere) - ++after; - } - diff = before - after; - /* will be 0 if only unburiable objects (The Amulet, &c) are present; - if uball got buried, uchain went away--count that as being buried */ - if (diff == 0) - pline("No objects buried."); - else - pline("%d object%s buried.", diff, plur(diff)); - } + else if (diff == 0) + /* before and after will be the same if only unburiable objects are + present (The Amulet, invocation items, Rider corpses, uchain when + uball doesn't get buried: carried or floor beyond burial range) */ + pline("No objects buried."); + else + /* usual case; if uball got buried, uchain went away and won't be + counted as buried */ + pline("%d object%s buried.", diff, plur(diff)); return ECMD_OK; } #endif /* DEBUG */ diff --git a/src/display.c b/src/display.c index 16f92f19a..71ce67766 100644 --- a/src/display.c +++ b/src/display.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 display.c $NHDT-Date: 1707462961 2024/02/09 07:16:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.231 $ */ +/* NetHack 3.7 display.c $NHDT-Date: 1723834773 2024/08/16 18:59:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.244 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -125,13 +125,13 @@ staticfn void show_mon_or_warn(coordxy, coordxy, int); staticfn void display_monster(coordxy, coordxy, - struct monst *, int, boolean) NONNULLPTRS; + struct monst *, int, boolean) NONNULLPTRS; staticfn int swallow_to_glyph(int, int); staticfn void display_warning(struct monst *) NONNULLARG1; -staticfn boolean next_to_gas(struct monst *, coordxy, coordxy) NONNULLARG1; - +staticfn boolean mon_overrides_region(struct monst *, coordxy, coordxy); staticfn int check_pos(coordxy, coordxy, int); -staticfn void get_bkglyph_and_framecolor(coordxy x, coordxy y, int *, uint32 *); +staticfn void get_bkglyph_and_framecolor(coordxy x, coordxy y, int *, + uint32 *); staticfn int tether_glyph(coordxy, coordxy); staticfn void mimic_light_blocking(struct monst *) NONNULLARG1; @@ -141,10 +141,10 @@ staticfn boolean more_than_one(coordxy, coordxy, coordxy, coordxy, coordxy); #endif staticfn int set_twall(coordxy, coordxy, coordxy, coordxy, - coordxy, coordxy, coordxy, coordxy); + coordxy, coordxy, coordxy, coordxy); staticfn int set_wall(coordxy, coordxy, int); staticfn int set_corn(coordxy, coordxy, coordxy, coordxy, - coordxy, coordxy, coordxy, coordxy); + coordxy, coordxy, coordxy, coordxy); staticfn int set_crosswall(coordxy, coordxy); staticfn void set_seenv(struct rm *, coordxy, coordxy, coordxy, coordxy); staticfn void t_warn(struct rm *); @@ -248,7 +248,8 @@ magic_map_background(coordxy x, coordxy y, int show) else if (lev->typ == CORR && glyph == cmap_to_glyph(S_litcorr)) glyph = cmap_to_glyph(S_corr); } - if (gl.level.flags.hero_memory) + if (svl.level.flags.hero_memory + && (glyph_is_unexplored(lev->glyph) || glyph_is_cmap(lev->glyph))) lev->glyph = glyph; if (show) show_glyph(x, y, glyph); @@ -279,7 +280,7 @@ map_background(coordxy x, coordxy y, int show) { int glyph = back_to_glyph(x, y); - if (gl.level.flags.hero_memory) + if (svl.level.flags.hero_memory) levl[x][y].glyph = glyph; if (show) show_glyph(x, y, glyph); @@ -297,7 +298,7 @@ map_trap(struct trap *trap, int show) coordxy x = trap->tx, y = trap->ty; int glyph = trap_to_glyph(trap); - if (gl.level.flags.hero_memory) + if (svl.level.flags.hero_memory) levl[x][y].glyph = glyph; if (show) show_glyph(x, y, glyph); @@ -314,7 +315,7 @@ map_engraving(struct engr *ep, int show) coordxy x = ep->engr_x, y = ep->engr_y; int glyph = engraving_to_glyph(ep); - if (gl.level.flags.hero_memory) + if (svl.level.flags.hero_memory) levl[x][y].glyph = glyph; if (show) show_glyph(x, y, glyph); @@ -350,7 +351,7 @@ map_object(struct obj *obj, int show) } } - if (gl.level.flags.hero_memory) { + if (svl.level.flags.hero_memory) { /* MRKR: While hallucinating, statues are seen as random monsters */ /* but remembered as random objects. */ @@ -377,7 +378,7 @@ void map_invisible(coordxy x, coordxy y) { if (x != u.ux || y != u.uy) { /* don't display I at hero's location */ - if (gl.level.flags.hero_memory) + if (svl.level.flags.hero_memory) levl[x][y].glyph = GLYPH_INVISIBLE; show_glyph(x, y, GLYPH_INVISIBLE); } @@ -410,7 +411,7 @@ unmap_object(coordxy x, coordxy y) struct trap *trap; struct engr *ep; - if (!gl.level.flags.hero_memory) + if (!svl.level.flags.hero_memory) return; if ((trap = t_at(x, y)) != 0 && trap->tseen && !covers_traps(x, y)) { @@ -442,10 +443,11 @@ unmap_object(coordxy x, coordxy y) * Internal to display.c, this is a #define for speed. */ #define _map_location(x, y, show) \ - { \ - struct obj *obj; \ - struct trap *trap; \ + do { \ + struct obj *obj; \ + struct trap *trap; \ struct engr *ep; \ + NhRegion *_ml_reg; \ \ if ((obj = vobj_at(x, y)) && !covers_objects(x, y)) \ map_object(obj, show); \ @@ -459,7 +461,9 @@ unmap_object(coordxy x, coordxy y) map_background(x, y, show); \ \ update_lastseentyp(x, y); \ - } + if (show && !Blind && (_ml_reg = visible_region_at(x, y)) != 0) \ + show_region(_ml_reg, x, y); \ + } while (0) void map_location(coordxy x, coordxy y, int show) @@ -545,7 +549,7 @@ display_monster( if (!sensed) { show_glyph(x, y, glyph); /* override real topology with mimic's fake one */ - gl.lastseentyp[x][y] = cmap_to_type(sym); + svl.lastseentyp[x][y] = cmap_to_type(sym); } break; } @@ -651,23 +655,41 @@ warning_of(struct monst *mon) return wl; } -/* returns True if mon is adjacent and would be seen if vision wasn't - blocked by being in a gas cloud (implicit; caller has already checked) */ +/* used by newsym() to decide whether to show a monster or a visible gas + cloud region when both are at the same spot; caller deals with region */ staticfn boolean -next_to_gas( - struct monst *mon, +mon_overrides_region( + struct monst *mon, /* might be Null */ coordxy mx, coordxy my) /* won't match mon->mx,my if long worm's tail */ { - int r = (u.xray_range > 1) ? u.xray_range : 1; + int r; - if (distu(mx, my) > r * (r + 1)) + /* this is redundant because newsym() doesn't call us when swallowed */ + if (u.uswallow && (!mon || mon != u.ustuck)) return FALSE; - /* decide whether monster at could be seen without couldsee() - because the gas cloud inhibits that (don't need to check infravision - when monster is adjacent) */ - if (Blind || !_mon_visible(mon)) - return FALSE; - return TRUE; + + if (mon) { + /* when not a worm tail, show mon if sensed rather than seen */ + if (mx == mon->mx && my == mon->my + && (sensemon(mon) || mon_warning(mon))) + return TRUE; + + /* even if worm tail; + check whether the spot is adjacent and 'mon' would be visible + there if the gas cloud wasn't interfering with normal vision; + _mon_visible() handles mon->mundetected; don't need to check + infravision when monster is adjacent */ + r = (u.xray_range > 1) ? u.xray_range : 1; + if (!Blind && _mon_visible(mon) + && M_AP_TYPE(mon) != M_AP_FURNITURE + && M_AP_TYPE(mon) != M_AP_OBJECT + && distu(mx, my) <= r * (r + 1)) + return TRUE; + } + + /* if not overriding region for current mon, propagate "remembered, + unseen monster" */ + return glyph_is_invisible(levl[mx][my].glyph) ? TRUE : FALSE; } /* map or status window might not be ready for output during level creation @@ -676,10 +698,10 @@ next_to_gas( boolean suppress_map_output(void) { - if (gi.in_mklev || gp.program_state.saving || gp.program_state.restoring) + if (gi.in_mklev || program_state.saving || program_state.restoring) return TRUE; #ifdef HANGUPHANDLING - if (gp.program_state.done_hup) + if (program_state.done_hup) return TRUE; #endif return FALSE; @@ -842,14 +864,14 @@ feel_location(coordxy x, coordxy y) */ if (uchain && uchain->where == OBJ_FLOOR && uchain->ox == x && uchain->oy == y - && gl.level.objects[x][y] == uchain) + && svl.level.objects[x][y] == uchain) u.bc_felt |= BC_CHAIN; else u.bc_felt &= ~BC_CHAIN; /* do not feel the chain */ if (uball && uball->where == OBJ_FLOOR && uball->ox == x && uball->oy == y - && gl.level.objects[x][y] == uball) + && svl.level.objects[x][y] == uball) u.bc_felt |= BC_BALL; else u.bc_felt &= ~BC_BALL; /* do not feel the ball */ @@ -865,7 +887,7 @@ feel_location(coordxy x, coordxy y) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); } /* draw monster on top if we can sense it */ - if ((x != u.ux || y != u.uy) && (mon = m_at(x, y)) != 0 && sensemon(mon)) + if (!u_at(x, y) && (mon = m_at(x, y)) != 0 && sensemon(mon)) display_monster(x, y, mon, (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)) ? PHYSICALLY_SEEN @@ -933,18 +955,18 @@ newsym(coordxy x, coordxy y) * seen when there's no gas region. * * FIXME: - * The adjacency checking here works when the hero is outside - * the region and the monster is inside, and when they're both - * inside, but not when the hero is inside and monster outside - * (because 'reg' will be Null for mon's ). Checking - * whether hero is inside a region for every newsym() seems - * excessive. The hero is usually blind when in a gas cloud - * so the problem is less noticeable then it might otherwise be. + * The adjacency checking [in mon_overrides_region()] works + * when the hero is outside the region and the monster is + * inside, and when they're both inside, but not when the + * hero is inside and monster outside (because 'reg' will be + * Null for mon's ). Checking whether hero is inside + * a region for every newsym() seems excessive. The hero is + * usually blind when in a gas cloud so the problem is less + * noticeable then it might otherwise be. */ if (reg && (ACCESSIBLE(lev->typ) || (reg->visible && is_pool_or_lava(x, y)))) { - if (!(mon && (((sensemon(mon) || mon_warning(mon)) && !worm_tail) - || next_to_gas(mon, x, y)))) { /* even if tail */ + if (!mon_overrides_region(mon, x, y)) { show_region(reg, x, y); return; } @@ -960,6 +982,8 @@ newsym(coordxy x, coordxy y) if (see_self) display_self(); } else { + boolean show = FALSE; + see_it = mon && (mon_visible(mon) || (!worm_tail && (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)))); @@ -972,7 +996,7 @@ newsym(coordxy x, coordxy y) if (tt == BEAR_TRAP || is_pit(tt) || tt == WEB) trap->tseen = 1; } - _map_location(x, y, 0); /* map under the monster */ + _map_location(x, y, show); /* map under the monster */ /* also gets rid of any invisibility glyph */ display_monster(x, y, mon, see_it ? PHYSICALLY_SEEN : DETECTED, @@ -1099,6 +1123,8 @@ tether_glyph(coordxy x, coordxy y) * * DISP_BEAM - Display the given glyph at each location, but do not erase * any until the close call. + * DISP_ALL - Same as DISP_BEAM except glyph is shown at the specified + * spot even when that spot can't be seen. * DISP_TETHER - Display a tether glyph at each location, and the tethered * object at the farthest location, but do not erase any * until the return trip or close. @@ -1255,8 +1281,8 @@ flash_glyph_at(coordxy x, coordxy y, int tg, int rpt) rpt *= 2; /* two loop iterations per 'count' */ glyph[0] = tg; - glyph[1] = (gl.level.flags.hero_memory) ? levl[x][y].glyph - : back_to_glyph(x, y); + glyph[1] = (svl.level.flags.hero_memory) ? levl[x][y].glyph + : back_to_glyph(x, y); /* even iteration count (guaranteed) ends with glyph[1] showing; caller might want to override that, but no newsym() calls here in case caller has tinkered with location visibility */ @@ -1456,7 +1482,7 @@ see_monsters(void) if (mon->wormno) see_wsegs(mon); if (Warn_of_mon - && (gc.context.warntype.obj & mon->data->mflags2) != 0L) + && (svc.context.warntype.obj & mon->data->mflags2) != 0L) new_warn_obj_cnt++; } @@ -1566,7 +1592,8 @@ see_traps(void) } /* glyph, ttychar, framecolor, - { glyphflags, { NO_COLOR, sym.symidx }, customcolor, color256idx, tileidx, u } */ + { glyphflags, { NO_COLOR, sym.symidx }, + customcolor, color256idx, tileidx, u } */ static glyph_info no_ginfo = { NO_GLYPH, ' ', NO_COLOR, { MG_BADXY, { NO_COLOR, 0 }, @@ -1658,10 +1685,10 @@ docrt_flags(int refresh_flags) redrawonly = (refresh_flags & docrtRefresh) != 0, nocls = (refresh_flags & docrtNocls) != 0; - if (!u.ux || gp.program_state.in_docrt) + if (!u.ux || program_state.in_docrt) return; /* display isn't ready yet */ - gp.program_state.in_docrt = TRUE; + program_state.in_docrt = TRUE; if (redrawonly) { redraw_map(FALSE); @@ -1713,7 +1740,7 @@ docrt_flags(int refresh_flags) disp.botlx = TRUE; /* force a redraw of the bottom lines */ /* note: caller needs to call bot() to actually redraw status */ } - gp.program_state.in_docrt = FALSE; + program_state.in_docrt = FALSE; } /* for panning beyond a clipped region; resend the current map data to @@ -1949,17 +1976,18 @@ show_glyph(coordxy x, coordxy y, int glyph) oldglyph = gg.gbuf[y][x].glyphinfo.glyph; if (a11y.glyph_updates && !a11y.mon_notices_blocked - && !gp.program_state.in_docrt - && !gp.program_state.in_getlev + && !program_state.in_docrt + && !program_state.in_getlev && (oldglyph != glyph || gg.gbuf[y][x].gnew)) { int c = glyph_to_cmap(glyph); + if ((glyph_is_nothing(oldglyph) || glyph_is_unexplored(oldglyph) || is_cmap_furniture(c)) && !is_cmap_wall(c) && !is_cmap_room(c)) { if ((a11y.mon_notices && glyph_is_monster(glyph)) || (glyph_is_monster(oldglyph)) || u_at(x, y)) { - /* nothing */ + ; /* nothing */ } else { show_glyph_change = TRUE; } @@ -2059,7 +2087,8 @@ clear_glyph_buffer(void) || giptr->gm.sym.color != nul_gbuf.glyphinfo.gm.sym.color || giptr->gm.glyphflags != nul_gbuf.glyphinfo.gm.glyphflags - || giptr->gm.customcolor != nul_gbuf.glyphinfo.gm.customcolor + || giptr->gm.customcolor + != nul_gbuf.glyphinfo.gm.customcolor || giptr->gm.tileidx != nul_gbuf.glyphinfo.gm.tileidx) #else nul_gbuf.gnew = (giptr->ttychar != ' ' @@ -2165,7 +2194,7 @@ flush_screen(int cursor_on_u) return; /* if already flushing then return */ flushing = 1; #ifdef HANGUPHANDLING - if (gp.program_state.done_hup) + if (program_state.done_hup) return; #endif @@ -2184,9 +2213,11 @@ flush_screen(int cursor_on_u) if (gptr->gnew || (gw.wsettings.map_frame_color != NO_COLOR && bkglyphinfo.framecolor != NO_COLOR)) { - map_glyphinfo(x, y, bkglyph, 0, &bkglyphinfo); /* won't touch framecolor */ + /* map_glyphinfo() won't touch framecolor */ + map_glyphinfo(x, y, bkglyph, 0, &bkglyphinfo); print_glyph(WIN_MAP, x, y, - Glyphinfo_at(x, y, gptr->glyphinfo.glyph), &bkglyphinfo); + Glyphinfo_at(x, y, gptr->glyphinfo.glyph), + &bkglyphinfo); gptr->gnew = 0; } } @@ -2228,7 +2259,7 @@ back_to_glyph(coordxy x, coordxy y) switch (ptr->typ) { case SCORR: case STONE: - idx = gl.level.flags.arboreal ? S_tree : S_stone; + idx = svl.level.flags.arboreal ? S_tree : S_stone; break; case ROOM: idx = S_room; @@ -2379,7 +2410,7 @@ swallow_to_glyph(int mnum, int loc) * * Change the given zap direction and beam type into a glyph. Each beam * type has four glyphs, one for each of the symbols below. The order of - * the zap symbols [0-3] as defined in rm.h are: + * the zap symbols [0-3] as defined in defsym.h are: * * | S_vbeam ( 0, 1) or ( 0,-1) * - S_hbeam ( 1, 0) or (-1, 0) @@ -2446,7 +2477,7 @@ get_bkglyph_and_framecolor( switch (lev->typ) { case SCORR: case STONE: - idx = gl.level.flags.arboreal ? S_tree : S_stone; + idx = svl.level.flags.arboreal ? S_tree : S_stone; break; case ROOM: idx = S_room; @@ -2482,7 +2513,7 @@ get_bkglyph_and_framecolor( } if (!cansee(x, y) && (!lev->waslit || flags.dark_room)) { - /* Floor spaces are dark if unlit. Corridors are dark if unlit. */ + /* Floor spaces and corridors are dark if unlit. */ if (lev->typ == CORR && idx == S_litcorr) idx = S_corr; else if (idx == S_room) @@ -2624,8 +2655,8 @@ int wallcolors[sokoban_walls + 1] = { #if 0 #define is_objpile(x, y) \ - (!Hallucination && gl.level.objects[(x)][(y)] \ - && gl.level.objects[(x)][(y)]->nexthere) + (!Hallucination && svl.level.objects[(x)][(y)] \ + && svl.level.objects[(x)][(y)]->nexthere) #endif staticfn int cmap_to_roguecolor(int); @@ -3017,7 +3048,7 @@ reset_glyphmap(enum glyphmap_change_triggers trigger) color = NO_COLOR; gmap->sym.color = color; } - gg.glyph_reset_timestamp = gm.moves; + gg.glyph_reset_timestamp = svm.moves; } /* ------------------------------------------------------------------------ */ @@ -3099,7 +3130,9 @@ set_twall( #else coordxy x0 UNUSED, coordxy y0 UNUSED, #endif - coordxy x1, coordxy y1, coordxy x2, coordxy y2, coordxy x3, coordxy y3) + coordxy x1, coordxy y1, + coordxy x2, coordxy y2, + coordxy x3, coordxy y3) { int wmode, is_1, is_2, is_3; @@ -3137,7 +3170,11 @@ set_wall(coordxy x, coordxy y, int horiz) /* Return a wall mode for a corner wall. (x4,y4) is the "inner" position. */ staticfn int -set_corn(coordxy x1, coordxy y1, coordxy x2, coordxy y2, coordxy x3, coordxy y3, coordxy x4, coordxy y4) +set_corn( + coordxy x1, coordxy y1, + coordxy x2, coordxy y2, + coordxy x3, coordxy y3, + coordxy x4, coordxy y4) { coordxy wmode, is_1, is_2, is_3, is_4; diff --git a/src/do.c b/src/do.c index 779e7eca3..591537f12 100644 --- a/src/do.c +++ b/src/do.c @@ -200,7 +200,7 @@ flooreffects(struct obj *obj, coordxy x, coordxy y, const char *verb) might have been thrown by a giant or launched by a rolling boulder trap triggered by a monster or dropped by a scroll of earth read by a monster */ - if (gc.context.mon_moving) { + if (svc.context.mon_moving) { /* normally we'd use ohitmon() but it can call drop_throw() which calls flooreffects() */ damage = dmgval(obj, mtmp); @@ -304,10 +304,10 @@ flooreffects(struct obj *obj, coordxy x, coordxy y, const char *verb) (void) obj_meld(&globbyobj, &otmp); } res = (boolean) !globbyobj; - } else if (gc.context.mon_moving && IS_ALTAR(levl[x][y].typ) + } else if (svc.context.mon_moving && IS_ALTAR(levl[x][y].typ) && cansee(x,y)) { doaltarobj(obj); - } else if (obj->oclass == POTION_CLASS && gl.level.flags.temperature > 0 + } else if (obj->oclass == POTION_CLASS && svl.level.flags.temperature > 0 && (levl[x][y].typ == ROOM || levl[x][y].typ == CORR)) { /* Potions are sometimes destroyed when landing on very hot ground. The basic odds are 50% for nonblessed potions and @@ -359,7 +359,7 @@ doaltarobj(struct obj *obj) if (obj->oclass != COIN_CLASS) { /* KMH, conduct */ - if (!gc.context.mon_moving && !u.uconduct.gnostic++) + if (!svc.context.mon_moving && !u.uconduct.gnostic++) livelog_printf(LL_CONDUCT, "eschewed atheism, by dropping %s on an altar", doname(obj)); @@ -403,7 +403,7 @@ polymorph_sink(void) return; sinklooted = levl[u.ux][u.uy].looted != 0; - /* gl.level.flags.nsinks--; // set_levltyp() will update this */ + /* svl.level.flags.nsinks--; // set_levltyp() will update this */ levl[u.ux][u.uy].flags = 0; switch (rn2(4)) { default: @@ -547,7 +547,7 @@ dosinkring(struct obj *obj) break; case RIN_HUNGER: ideed = FALSE; - for (otmp = gl.level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { + for (otmp = svl.level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (otmp != uball && otmp != uchain && !obj_resists(otmp, 1, 99)) { @@ -822,7 +822,7 @@ dropz(struct obj *obj, boolean with_impact) impact_disturbs_zombies(obj, with_impact); if (obj == uball) drop_ball(u.ux, u.uy); - else if (gl.level.flags.has_shop) + else if (svl.level.flags.has_shop) sellobj(obj, u.ux, u.uy); stackobj(obj); if (Blind && Levitation) @@ -850,7 +850,7 @@ engulfer_digests_food(struct obj *obj) if (obj->otyp == CORPSE) { could_petrify = touch_petrifies(&mons[obj->corpsenm]); - could_poly = polyfodder(obj); + could_poly = polyfood(obj); could_grow = (obj->corpsenm == PM_WRAITH); could_heal = (obj->corpsenm == PM_NURSE); } else if (obj->otyp == GLOB_OF_GREEN_SLIME) { @@ -900,7 +900,7 @@ obj_no_longer_held(struct obj *obj) */ if (!obj->oerodeproof || !rn2(10)) { /* if monsters aren't moving, assume player is responsible */ - if (!gc.context.mon_moving && !gp.program_state.gameover) + if (!svc.context.mon_moving && !program_state.gameover) costly_alteration(obj, COST_DEGRD); obj->otyp = WORM_TOOTH; obj->oerodeproof = 0; @@ -1133,8 +1133,8 @@ dodown(void) for (obj = gi.invent; obj; obj = obj->nobj) { if (obj->oartifact && artifact_has_invprop(obj, LEVITATION)) { - if (obj->age < gm.moves) - obj->age = gm.moves; + if (obj->age < svm.moves) + obj->age = svm.moves; obj->age += rnz(100); } } @@ -1201,7 +1201,8 @@ dodown(void) return ECMD_TIME; } else if (!trap || !is_hole(trap->ttyp) || !Can_fall_thru(&u.uz) || !trap->tseen) { - if (flags.autodig && !gc.context.nopick && uwep && is_pick(uwep)) { + if (flags.autodig && !svc.context.nopick + && uwep && is_pick(uwep)) { return use_pick_axe2(uwep); } else { You_cant("go down here%s.", @@ -1348,7 +1349,7 @@ save_currentstate(void) { NHFILE *nhfp; - gp.program_state.in_checkpoint++; + program_state.in_checkpoint++; if (flags.ins_chkpt) { /* write out just-attained level, with pets and everything */ nhfp = currentlevel_rewrite(); @@ -1363,7 +1364,7 @@ save_currentstate(void) /* write out non-level state */ savestateinlock(); - gp.program_state.in_checkpoint--; + program_state.in_checkpoint--; } #endif @@ -1468,7 +1469,7 @@ goto_level( char whynot[BUFSZ]; int dist = depth(newlevel) - depth(&u.uz); boolean do_fall_dmg = FALSE; - schar prev_temperature = gl.level.flags.temperature; + schar prev_temperature = svl.level.flags.temperature; if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel)) newlevel->dlevel = dunlevs_in_dungeon(newlevel); @@ -1512,7 +1513,7 @@ goto_level( */ if (Inhell && up && u.uhave.amulet && !newdungeon && !portal && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) { - if (!rn2(4 + gc.context.mysteryforce)) { + if (!rn2(4 + svc.context.mysteryforce)) { int odds = 3 + (int) u.ualign.type, /* 2..4 */ diff = (odds <= 1) ? 0 : rn2(odds); /* paranoia */ @@ -1532,7 +1533,7 @@ goto_level( that drops faster, on average, when being sent down farther so while the impact is reduced for everybody compared to earlier versions, it is reduced least for chaotics, most for lawfuls */ - gc.context.mysteryforce += rn2(diff + 2); /* L:0-4, N:0-3, C:0-2 */ + svc.context.mysteryforce += rn2(diff + 2); /* L:0-4,N:0-3,C:0-2 */ if (on_level(newlevel, &u.uz)) { (void) safe_teleds(TELEDS_NO_FLAGS); @@ -1577,7 +1578,7 @@ goto_level( maybe_reset_pick((struct obj *) 0); reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */ iflags.travelcc.x = iflags.travelcc.y = 0; /* travel destination cache */ - gc.context.polearm.hitmon = (struct monst *) 0; /* polearm target */ + svc.context.polearm.hitmon = (struct monst *) 0; /* polearm target */ /* digging context is level-aware and can actually be resumed if hero returns to the previous level without any intervening dig */ @@ -1628,7 +1629,7 @@ goto_level( if (!leaving_tutorial || ledger_to_dnum(l_idx) == tutorial_dnum) delete_levelfile(l_idx); /* mark #overview data for all dungeon branches as uninteresting */ - for (l_idx = 0; l_idx < gn.n_dgns; ++l_idx) + for (l_idx = 0; l_idx < svn.n_dgns; ++l_idx) if (!leaving_tutorial || l_idx == tutorial_dnum) remdun_mapseen(l_idx); /* get rid of mons & objs scheduled to migrate to discarded levels */ @@ -1659,18 +1660,18 @@ goto_level( stairway_free_all(); /* set default level change destination areas */ /* the special level code may override these */ - (void) memset((genericptr_t) &gu.updest, 0, sizeof gu.updest); - (void) memset((genericptr_t) &gd.dndest, 0, sizeof gd.dndest); + (void) memset((genericptr_t) &svu.updest, 0, sizeof svu.updest); + (void) memset((genericptr_t) &svd.dndest, 0, sizeof svd.dndest); - if (!(gl.level_info[new_ledger].flags & LFILE_EXISTS)) { + if (!(svl.level_info[new_ledger].flags & LFILE_EXISTS)) { /* entering this level for first time; make it now */ - if (gl.level_info[new_ledger].flags & (VISITED)) { + if (svl.level_info[new_ledger].flags & (VISITED)) { impossible("goto_level: returning to discarded level?"); - gl.level_info[new_ledger].flags &= ~(VISITED); + svl.level_info[new_ledger].flags &= ~(VISITED); } mklev(); new = TRUE; /* made the level */ - familiar = bones_include_name(gp.plname); + familiar = bones_include_name(svp.plname); } else { /* returning to previously visited level; reload it */ nhfp = open_levelfile(new_ledger, whynot); @@ -1681,7 +1682,7 @@ goto_level( reseed_random(rn2); reseed_random(rn2_on_display_rng); minit(); /* ZEROCOMP */ - getlev(nhfp, gh.hackpid, new_ledger); + getlev(nhfp, svh.hackpid, new_ledger); close_nhfile(nhfp); oinit(); /* reassign level dependent obj probabilities */ } @@ -1803,7 +1804,7 @@ goto_level( /* initial movement of bubbles just before vision_recalc */ if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) movebubbles(); - else if (gl.level.flags.fumaroles) + else if (svl.level.flags.fumaroles) fumaroles(); /* Reset the screen. */ @@ -1865,7 +1866,7 @@ goto_level( onquest(); /* might be reaching locate|goal level */ } else if (Is_knox(&u.uz)) { /* alarm stops working once Croesus has died */ - if (new || !gm.mvitals[PM_CROESUS].died) { + if (new || !svm.mvitals[PM_CROESUS].died) { You("have penetrated a high security area!"); Soundeffect(se_alarm, 100); pline("An alarm sounds!"); @@ -1890,7 +1891,7 @@ goto_level( /* main dungeon message from your quest leader */ if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") && !(u.uevent.qcompleted || u.uevent.qexpelled - || gq.quest_status.leader_is_dead)) { + || svq.quest_status.leader_is_dead)) { /* [TODO: copy of same TODO below; if an achievement for receiving quest call from leader gets added, that should come after logging new level entry] */ @@ -1960,11 +1961,11 @@ goto_level( void hellish_smoke_mesg(void) { - if (gl.level.flags.temperature) + if (svl.level.flags.temperature) pline("It is %s here.", - gl.level.flags.temperature > 0 ? "hot" : "cold"); + svl.level.flags.temperature > 0 ? "hot" : "cold"); - if (In_hell(&u.uz) && gl.level.flags.temperature > 0) + if (In_hell(&u.uz) && svl.level.flags.temperature > 0) You("%s smoke...", olfaction(gy.youmonst.data) ? "smell" : "sense"); } @@ -1973,8 +1974,8 @@ hellish_smoke_mesg(void) staticfn void temperature_change_msg(schar prev_temperature) { - if (prev_temperature != gl.level.flags.temperature) { - if (gl.level.flags.temperature) + if (prev_temperature != svl.level.flags.temperature) { + if (svl.level.flags.temperature) hellish_smoke_mesg(); else if (prev_temperature > 0) pline_The("heat %s gone.", @@ -1989,7 +1990,8 @@ temperature_change_msg(schar prev_temperature) void maybe_lvltport_feedback(void) { - if (gd.dfr_post_msg && !strncmpi(gd.dfr_post_msg, "You materialize", 15)) { + if (gd.dfr_post_msg + && !strncmpi(gd.dfr_post_msg, "You materialize", 15)) { /* "You materialize on a different level." */ pline("%s", gd.dfr_post_msg); free((genericptr_t) gd.dfr_post_msg), gd.dfr_post_msg = 0; @@ -2011,8 +2013,10 @@ final_level(void) /* change levels at the end of this turn, after monsters finish moving */ void -schedule_goto(d_level *tolev, int utotype_flags, - const char *pre_msg, const char *post_msg) +schedule_goto( + d_level *tolev, + int utotype_flags, + const char *pre_msg, const char *post_msg) { /* UTOTYPE_DEFERRED is used, so UTOTYPE_NONE can trigger deferred_goto() */ u.utotype = utotype_flags | UTOTYPE_DEFERRED; @@ -2096,9 +2100,9 @@ revive_corpse(struct obj *corpse) struct monst *mtmp2; container = corpse->ocontainer; - mtmp2 = get_container_location(container, &container_where, (int *) 0); - /* container_where is the outermost container's location even if - * nested */ + mtmp2 = get_container_location(container, &container_where, + (int *) 0); + /* container_where is outermost container's location even if nested */ if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2; } @@ -2238,7 +2242,7 @@ revive_mon(anything *arg, long timeout UNUSED) if (!obj_has_timer(body, ROT_CORPSE)) You_feel("%sless hassled.", is_rider(mptr) ? "much " : ""); action = ROT_CORPSE; - when = (long) d(5, 50) - (gm.moves - body->age); + when = (long) d(5, 50) - (svm.moves - body->age); if (when < 1L) when = 1L; } @@ -2254,7 +2258,7 @@ zombify_mon(anything *arg, long timeout) struct obj *body = arg->a_obj; int zmon = zombie_form(&mons[body->corpsenm]); - if (zmon != NON_PM && !(gm.mvitals[zmon].mvflags & G_GENOD)) { + if (zmon != NON_PM && !(svm.mvitals[zmon].mvflags & G_GENOD)) { if (has_omid(body)) free_omid(body); if (has_omonst(body)) diff --git a/src/do_name.c b/src/do_name.c index c1574618a..82c486451 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 do_name.c $NHDT-Date: 1708126536 2024/02/16 23:35:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.307 $ */ +/* NetHack 3.7 do_name.c $NHDT-Date: 1720895738 2024/07/13 18:35:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.320 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -220,7 +220,7 @@ do_mgivenname(void) mtmp = u.usteed; } else { pline("This %s creature is called %s and cannot be renamed.", - beautiful(), gp.plname); + beautiful(), svp.plname); return; } } else @@ -769,7 +769,7 @@ const char * rndghostname(void) { return rn2(7) ? ROLL_FROM(ghostnames) - : (const char *) gp.plname; + : (const char *) svp.plname; } /* @@ -790,6 +790,7 @@ rndghostname(void) * a_monnam: a newt it an invisible orc Fido * m_monnam: newt xan orc Fido * y_monnam: your newt your xan your invisible orc Fido + * YMonnam: Your newt Your xan Your invisible orc Fido * noname_monnam(mon,article): * article newt art xan art invisible orc art dog */ @@ -839,7 +840,7 @@ x_monnam( if (mtmp == &gy.youmonst) return strcpy(buf, "you"); /* ignore article, "invisible", &c */ - if (gp.program_state.gameover) + if (program_state.gameover) suppress |= SUPPRESS_HALLUCINATION; if (article == ARTICLE_YOUR && !mtmp->mtame) article = ARTICLE_THE; @@ -857,7 +858,7 @@ x_monnam( do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION); do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE); do_it = !canspotmon(mtmp) && article != ARTICLE_YOUR - && !gp.program_state.gameover && mtmp != u.usteed + && !program_state.gameover && mtmp != u.usteed && !engulfing_u(mtmp) && !(suppress & SUPPRESS_IT); do_saddle = !(suppress & SUPPRESS_SADDLE); do_mappear = mappear_as_mon && !(suppress & SUPPRESS_MAPPEARANCE); @@ -870,8 +871,11 @@ x_monnam( /* unseen monsters, etc.; usually "it" but sometimes more specific; when hallucinating, the more specific values might be inverted */ if (do_it) { + /* !is_animal excludes all Y; !mindless excludes Z, M, \' */ + boolean s_one = humanoid(mdat) && !is_animal(mdat) && !mindless(mdat); + Strcpy(buf, !augment_it ? "it" - : (!do_hallu ? humanoid(mdat) : !rn2(2)) ? "someone" + : (!do_hallu ? s_one : !rn2(2)) ? "someone" : "something"); return buf; } @@ -1061,7 +1065,7 @@ Monnam(struct monst *mtmp) char *bp = mon_nam(mtmp); *bp = highc(*bp); - return bp; + return bp; } char * @@ -1070,7 +1074,7 @@ noit_Monnam(struct monst *mtmp) char *bp = noit_mon_nam(mtmp); *bp = highc(*bp); - return bp; + return bp; } char * @@ -1079,7 +1083,7 @@ Some_Monnam(struct monst *mtmp) char *bp = some_mon_nam(mtmp); *bp = highc(*bp); - return bp; + return bp; } /* return "a dog" rather than "Fido", honoring hallucination and visibility */ @@ -1113,6 +1117,16 @@ y_monnam(struct monst *mtmp) return x_monnam(mtmp, prefix, (char *) 0, suppression_flag, FALSE); } +/* y_monnam() for start of sentence */ +char * +YMonnam(struct monst *mtmp) +{ + char *bp = y_monnam(mtmp); + + *bp = highc(*bp); + return bp; +} + char * Adjmonnam(struct monst *mtmp, const char *adj) { @@ -1120,7 +1134,7 @@ Adjmonnam(struct monst *mtmp, const char *adj) has_mgivenname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE); *bp = highc(*bp); - return bp; + return bp; } char * @@ -1136,7 +1150,7 @@ Amonnam(struct monst *mtmp) char *bp = a_monnam(mtmp); *bp = highc(*bp); - return bp; + return bp; } /* used for monster ID by the '/', ';', and 'C' commands to block remote @@ -1244,7 +1258,7 @@ minimal_monnam(struct monst *mon, boolean ckloc) fmt_ptr((genericptr_t) mon->data), fmt_ptr((genericptr_t) &mons[NUMMONS])); } else if (ckloc && ptr == &mons[PM_LONG_WORM] && mon->mx - && gl.level.monsters[mon->mx][mon->my] != mon) { + && svl.level.monsters[mon->mx][mon->my] != mon) { Sprintf(outbuf, "%s <%d,%d>", pmname(&mons[PM_LONG_WORM_TAIL], Mgender(mon)), mon->mx, mon->my); @@ -1468,7 +1482,7 @@ const char * hliquid( const char *liquidpref) /* use as-is when not hallucintg (unless empty) */ { - boolean hallucinate = Hallucination && !gp.program_state.gameover; + boolean hallucinate = Hallucination && !program_state.gameover; if (hallucinate || !liquidpref || !*liquidpref) { int indx, count = SIZE(hliquids); diff --git a/src/do_wear.c b/src/do_wear.c index 67c059ef5..51b9059a6 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 do_wear.c $NHDT-Date: 1702017586 2023/12/08 06:39:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.175 $ */ +/* NetHack 3.7 do_wear.c $NHDT-Date: 1720895740 2024/07/13 18:35:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.188 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -98,7 +98,7 @@ toggle_stealth( long oldprop, /* prop[].extrinsic, with obj->owornmask pre-stripped */ boolean on) { - if (on ? gi.initial_don : gc.context.takeoff.cancelled_don) + if (on ? gi.initial_don : svc.context.takeoff.cancelled_don) return; if (!oldprop /* extrinsic stealth from something else */ @@ -140,7 +140,7 @@ toggle_displacement( stripped by caller */ boolean on) { - if (on ? gi.initial_don : gc.context.takeoff.cancelled_don) + if (on ? gi.initial_don : svc.context.takeoff.cancelled_don) return; if (!oldprop /* extrinsic displacement from something else */ @@ -240,14 +240,14 @@ Boots_off(void) int otyp = otmp->otyp; long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_BOOTS; - gc.context.takeoff.mask &= ~W_ARMF; + svc.context.takeoff.mask &= ~W_ARMF; /* For levitation, float_down() returns if Levitation, so we * must do a setworn() _before_ the levitation case. */ setworn((struct obj *) 0, W_ARMF); switch (otyp) { case SPEED_BOOTS: - if (!Very_fast && !gc.context.takeoff.cancelled_don) { + if (!Very_fast && !svc.context.takeoff.cancelled_don) { makeknown(otyp); You_feel("yourself slow down%s.", Fast ? " a bit" : ""); } @@ -257,7 +257,7 @@ Boots_off(void) if ((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) && !Levitation && !Flying && !(is_clinger(gy.youmonst.data) && has_ceiling(&u.uz)) - && !gc.context.takeoff.cancelled_don + && !svc.context.takeoff.cancelled_don /* avoid recursive call to lava_effects() */ && !iflags.in_lava_effects) { /* make boots known in case you survive the drowning */ @@ -274,7 +274,7 @@ Boots_off(void) break; case LEVITATION_BOOTS: if (!oldprop && !HLevitation && !(BLevitation & FROMOUTSIDE) - && !gc.context.takeoff.cancelled_don) { + && !svc.context.takeoff.cancelled_don) { /* lava_effects() sets in_lava_effects and calls Boots_off() so hero is already in midst of floating down */ if (!iflags.in_lava_effects) @@ -293,7 +293,7 @@ Boots_off(void) default: impossible(unknown_type, c_boots, otyp); } - gc.context.takeoff.cancelled_don = FALSE; + svc.context.takeoff.cancelled_don = FALSE; return 0; } @@ -361,7 +361,7 @@ Cloak_off(void) int otyp = otmp->otyp; long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_CLOAK; - gc.context.takeoff.mask &= ~W_ARMC; + svc.context.takeoff.mask &= ~W_ARMC; /* For mummy wrapping, taking it off first resets `Invisible'. */ setworn((struct obj *) 0, W_ARMC); switch (otyp) { @@ -488,7 +488,7 @@ Helmet_on(void) int Helmet_off(void) { - gc.context.takeoff.mask &= ~W_ARMH; + svc.context.takeoff.mask &= ~W_ARMH; switch (uarmh->otyp) { case FEDORA: @@ -502,7 +502,7 @@ Helmet_off(void) disp.botl = TRUE; break; case CORNUTHAUM: - if (!gc.context.takeoff.cancelled_don) { + if (!svc.context.takeoff.cancelled_don) { ABON(A_CHA) += (Role_if(PM_WIZARD) ? -1 : 1); disp.botl = TRUE; } @@ -514,7 +514,7 @@ Helmet_off(void) see_monsters(); return 0; case HELM_OF_BRILLIANCE: - if (!gc.context.takeoff.cancelled_don) + if (!svc.context.takeoff.cancelled_don) adj_abon(uarmh, -uarmh->spe); break; case HELM_OF_OPPOSITE_ALIGNMENT: @@ -527,7 +527,7 @@ Helmet_off(void) impossible(unknown_type, c_helmet, uarmh->otyp); } setworn((struct obj *) 0, W_ARMH); - gc.context.takeoff.cancelled_don = FALSE; + svc.context.takeoff.cancelled_don = FALSE; return 0; } @@ -616,9 +616,9 @@ Gloves_off(void) struct obj *gloves = uarmg; /* needed after uarmg has been set to Null */ long oldprop = u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES; - boolean on_purpose = !gc.context.mon_moving && !uarmg->in_use; + boolean on_purpose = !svc.context.mon_moving && !uarmg->in_use; - gc.context.takeoff.mask &= ~W_ARMG; + svc.context.takeoff.mask &= ~W_ARMG; switch (uarmg->otyp) { case LEATHER_GLOVES: @@ -632,14 +632,14 @@ Gloves_off(void) disp.botl = TRUE; /* taken care of in attrib.c */ break; case GAUNTLETS_OF_DEXTERITY: - if (!gc.context.takeoff.cancelled_don) + if (!svc.context.takeoff.cancelled_don) adj_abon(uarmg, -uarmg->spe); break; default: impossible(unknown_type, c_gloves, uarmg->otyp); } setworn((struct obj *) 0, W_ARMG); - gc.context.takeoff.cancelled_don = FALSE; + svc.context.takeoff.cancelled_don = FALSE; (void) encumber_msg(); /* immediate feedback for GoP */ /* usually can't remove gloves when they're slippery but it can @@ -698,7 +698,7 @@ Shield_on(void) int Shield_off(void) { - gc.context.takeoff.mask &= ~W_ARMS; + svc.context.takeoff.mask &= ~W_ARMS; /* no shield currently requires special handling when taken off, but we keep this uncommented in case somebody adds a new one which does */ @@ -741,7 +741,7 @@ Shirt_on(void) int Shirt_off(void) { - gc.context.takeoff.mask &= ~W_ARMU; + svc.context.takeoff.mask &= ~W_ARMU; /* no shirt currently requires special handling when taken off, but we keep this uncommented in case somebody adds a new one which does */ @@ -786,7 +786,7 @@ dragon_armor_handling( EFast |= W_ARM; } else { EFast &= ~W_ARM; - if (!Very_fast && !gc.context.takeoff.cancelled_don) + if (!Very_fast && !svc.context.takeoff.cancelled_don) You("slow down."); } break; @@ -810,7 +810,7 @@ dragon_armor_handling( case GOLD_DRAGON_SCALES: case GOLD_DRAGON_SCALE_MAIL: (void) make_hallucinated((long) !puton, - gp.program_state.restoring ? FALSE : TRUE, + program_state.restoring ? FALSE : TRUE, W_ARM); break; case ORANGE_DRAGON_SCALES: @@ -875,9 +875,9 @@ Armor_off(void) struct obj *otmp = uarm; boolean was_arti_light = otmp && otmp->lamplit && artifact_light(otmp); - gc.context.takeoff.mask &= ~W_ARM; + svc.context.takeoff.mask &= ~W_ARM; setworn((struct obj *) 0, W_ARM); - gc.context.takeoff.cancelled_don = FALSE; + svc.context.takeoff.cancelled_don = FALSE; /* taking off yellow dragon scales/mail might be fatal; arti_light comes from gold dragon scales/mail so they don't overlap, but @@ -905,9 +905,9 @@ Armor_gone(void) struct obj *otmp = uarm; boolean was_arti_light = otmp && otmp->lamplit && artifact_light(otmp); - gc.context.takeoff.mask &= ~W_ARM; + svc.context.takeoff.mask &= ~W_ARM; setnotworn(uarm); - gc.context.takeoff.cancelled_don = FALSE; + svc.context.takeoff.cancelled_don = FALSE; /* losing yellow dragon scales/mail might be fatal; arti_light comes from gold dragon scales/mail so they don't overlap, but @@ -1022,7 +1022,7 @@ Amulet_on(void) void Amulet_off(void) { - gc.context.takeoff.mask &= ~W_AMUL; + svc.context.takeoff.mask &= ~W_AMUL; switch (uamul->otyp) { case AMULET_OF_ESP: @@ -1252,7 +1252,7 @@ Ring_off_or_gone(struct obj *obj, boolean gone) long mask = (obj->owornmask & W_RING); boolean observable; - gc.context.takeoff.mask &= ~mask; + svc.context.takeoff.mask &= ~mask; if (!(u.uprops[objects[obj->otyp].oc_oprop].extrinsic & mask)) impossible("Strange... I didn't know you had that ring."); if (gone) @@ -1406,7 +1406,7 @@ Blindf_off(struct obj *otmp) impossible("Blindf_off without eyewear?"); return; } - gc.context.takeoff.mask &= ~W_TOOL; + svc.context.takeoff.mask &= ~W_TOOL; setworn((struct obj *) 0, otmp->owornmask); if (!nooffmsg) off_msg(otmp); @@ -1505,7 +1505,7 @@ donning(struct obj *otmp) boolean doffing(struct obj *otmp) { - long what = gc.context.takeoff.what; + long what = svc.context.takeoff.what; boolean result = FALSE; /* 'T' (or 'R' used for armor) sets ga.afternmv, 'A' sets takeoff.what */ @@ -1556,9 +1556,9 @@ cancel_doff(struct obj *obj, long slotmask) * matter whether cancel_don() gets called here--the item has already * been removed by now.] */ - if (!(gc.context.takeoff.mask & I_SPECIAL) && donning(obj)) + if (!(svc.context.takeoff.mask & I_SPECIAL) && donning(obj)) cancel_don(); /* applies to doffing too */ - gc.context.takeoff.mask &= ~slotmask; + svc.context.takeoff.mask &= ~slotmask; } /* despite their names, cancel_don() and cancel_doff() both apply to both @@ -1572,7 +1572,7 @@ cancel_don(void) * every item of the corresponding armor category takes 1 turn to wear, * but check all of them anyway */ - gc.context.takeoff.cancelled_don = (ga.afternmv == Cloak_on + svc.context.takeoff.cancelled_don = (ga.afternmv == Cloak_on || ga.afternmv == Armor_on || ga.afternmv == Shirt_on || ga.afternmv == Helmet_on @@ -1582,8 +1582,8 @@ cancel_don(void) ga.afternmv = (int (*)(void)) 0; gn.nomovemsg = (char *) 0; gm.multi = 0; - gc.context.takeoff.delay = 0; - gc.context.takeoff.what = 0L; + svc.context.takeoff.delay = 0; + svc.context.takeoff.what = 0L; } /* called by steal() during theft from hero; interrupt donning/doffing */ @@ -1701,7 +1701,7 @@ armor_or_accessory_off(struct obj *obj) reset_remarm(); /* clear context.takeoff.mask and context.takeoff.what */ (void) select_off(obj); - if (!gc.context.takeoff.mask) + if (!svc.context.takeoff.mask) return ECMD_OK; /* none of armoroff()/Ring_/Amulet/Blindf_off() use context.takeoff.mask */ reset_remarm(); @@ -1853,7 +1853,8 @@ armoroff(struct obj *otmp) } if (what) { /* sizeof offdelaybuf == 60; increase it if this becomes longer */ - Sprintf(offdelaybuf, "You finish taking off your %s.", what); + Snprintf(offdelaybuf, sizeof offdelaybuf, + "You finish taking off your %s.", what); gn.nomovemsg = offdelaybuf; } } else { @@ -1889,7 +1890,7 @@ armoroff(struct obj *otmp) avoid "You were wearing ____ (being worn)." */ off_msg(otmp); } - gc.context.takeoff.mask = gc.context.takeoff.what = 0L; + svc.context.takeoff.mask = svc.context.takeoff.what = 0L; return 1; } @@ -2285,7 +2286,7 @@ accessory_or_armor_on(struct obj *obj) unmul(""); /* call afternmv, clear it+nomovemsg+multi_reason */ on_msg(obj); } - gc.context.takeoff.mask = gc.context.takeoff.what = 0L; + svc.context.takeoff.mask = svc.context.takeoff.what = 0L; } else { /* not armor */ boolean give_feedback = FALSE; @@ -2668,33 +2669,33 @@ select_off(struct obj *otmp) } if (otmp == uarm) - gc.context.takeoff.mask |= WORN_ARMOR; + svc.context.takeoff.mask |= WORN_ARMOR; else if (otmp == uarmc) - gc.context.takeoff.mask |= WORN_CLOAK; + svc.context.takeoff.mask |= WORN_CLOAK; else if (otmp == uarmf) - gc.context.takeoff.mask |= WORN_BOOTS; + svc.context.takeoff.mask |= WORN_BOOTS; else if (otmp == uarmg) - gc.context.takeoff.mask |= WORN_GLOVES; + svc.context.takeoff.mask |= WORN_GLOVES; else if (otmp == uarmh) - gc.context.takeoff.mask |= WORN_HELMET; + svc.context.takeoff.mask |= WORN_HELMET; else if (otmp == uarms) - gc.context.takeoff.mask |= WORN_SHIELD; + svc.context.takeoff.mask |= WORN_SHIELD; else if (otmp == uarmu) - gc.context.takeoff.mask |= WORN_SHIRT; + svc.context.takeoff.mask |= WORN_SHIRT; else if (otmp == uleft) - gc.context.takeoff.mask |= LEFT_RING; + svc.context.takeoff.mask |= LEFT_RING; else if (otmp == uright) - gc.context.takeoff.mask |= RIGHT_RING; + svc.context.takeoff.mask |= RIGHT_RING; else if (otmp == uamul) - gc.context.takeoff.mask |= WORN_AMUL; + svc.context.takeoff.mask |= WORN_AMUL; else if (otmp == ublindf) - gc.context.takeoff.mask |= WORN_BLINDF; + svc.context.takeoff.mask |= WORN_BLINDF; else if (otmp == uwep) - gc.context.takeoff.mask |= W_WEP; + svc.context.takeoff.mask |= W_WEP; else if (otmp == uswapwep) - gc.context.takeoff.mask |= W_SWAPWEP; + svc.context.takeoff.mask |= W_SWAPWEP; else if (otmp == uquiver) - gc.context.takeoff.mask |= W_QUIVER; + svc.context.takeoff.mask |= W_QUIVER; else impossible("select_off: %s???", doname(otmp)); @@ -2707,9 +2708,9 @@ do_takeoff(void) { struct obj *otmp = (struct obj *) 0; boolean was_twoweap = u.twoweap; - struct takeoff_info *doff = &gc.context.takeoff; + struct takeoff_info *doff = &svc.context.takeoff; - gc.context.takeoff.mask |= I_SPECIAL; /* set flag for cancel_doff() */ + svc.context.takeoff.mask |= I_SPECIAL; /* set flag for cancel_doff() */ if (doff->what == W_WEP) { if (!cursed(uwep)) { setuwep((struct obj *) 0); @@ -2772,7 +2773,7 @@ do_takeoff(void) } else { impossible("do_takeoff: taking off %lx", doff->what); } - gc.context.takeoff.mask &= ~I_SPECIAL; /* clear cancel_doff() flag */ + svc.context.takeoff.mask &= ~I_SPECIAL; /* clear cancel_doff() flag */ return otmp; } @@ -2783,7 +2784,7 @@ take_off(void) { int i; struct obj *otmp; - struct takeoff_info *doff = &gc.context.takeoff; + struct takeoff_info *doff = &svc.context.takeoff; if (doff->what) { if (doff->delay > 0) { @@ -2872,8 +2873,8 @@ take_off(void) void reset_remarm(void) { - gc.context.takeoff.what = gc.context.takeoff.mask = 0L; - gc.context.takeoff.disrobing[0] = '\0'; + svc.context.takeoff.what = svc.context.takeoff.mask = 0L; + svc.context.takeoff.disrobing[0] = '\0'; } /* the #takeoffall command -- remove multiple worn items */ @@ -2882,9 +2883,9 @@ doddoremarm(void) { int result = 0; - if (gc.context.takeoff.what || gc.context.takeoff.mask) { - You("continue %s.", gc.context.takeoff.disrobing); - set_occupation(take_off, gc.context.takeoff.disrobing, 0); + if (svc.context.takeoff.what || svc.context.takeoff.mask) { + You("continue %s.", svc.context.takeoff.disrobing); + set_occupation(take_off, svc.context.takeoff.disrobing, 0); return ECMD_OK; } else if (!uwep && !uswapwep && !uquiver && !uamul && !ublindf && !uleft && !uright && !wearing_armor()) { @@ -2898,9 +2899,9 @@ doddoremarm(void) (unsigned *) 0)) < -1) result = menu_remarm(result); - if (gc.context.takeoff.mask) { - (void) strncpy(gc.context.takeoff.disrobing, - (((gc.context.takeoff.mask & ~W_WEAPONS) != 0) + if (svc.context.takeoff.mask) { + (void) strncpy(svc.context.takeoff.disrobing, + (((svc.context.takeoff.mask & ~W_WEAPONS) != 0) /* default activity for armor and/or accessories, possibly combined with weapons */ ? "disrobing" @@ -2940,7 +2941,7 @@ remarm_swapwep(void) * can't be unwielded even though things * don't work that way... */ reset_remarm(); - gc.context.takeoff.what = gc.context.takeoff.mask = W_SWAPWEP; + svc.context.takeoff.what = svc.context.takeoff.mask = W_SWAPWEP; (void) do_takeoff(); return (!uswapwep || uswapwep->bknown != oldbknown) ? ECMD_TIME : ECMD_OK; } diff --git a/src/dog.c b/src/dog.c index d1f0ae6ae..e349554f4 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dog.c $NHDT-Date: 1700012881 2023/11/15 01:48:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.147 $ */ +/* NetHack 3.7 dog.c $NHDT-Date: 1725227804 2024/09/01 21:56:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.164 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -53,7 +53,7 @@ initedog(struct monst *mtmp) EDOG(mtmp)->dropdist = 10000; EDOG(mtmp)->apport = ACURR(A_CHA); EDOG(mtmp)->whistletime = 0; - EDOG(mtmp)->hungrytime = 1000 + gm.moves; + EDOG(mtmp)->hungrytime = 1000 + svm.moves; EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */ EDOG(mtmp)->ogoal.y = -1; EDOG(mtmp)->abuse = 0; @@ -89,7 +89,7 @@ pick_familiar_pm(struct obj *otmp, boolean quietly) /* activating a figurine provides one way to exceed the maximum number of the target critter created--unless it has a special limit (erinys, Nazgul) */ - if ((gm.mvitals[mndx].mvflags & G_EXTINCT) + if ((svm.mvitals[mndx].mvflags & G_EXTINCT) && mbirth_limit(mndx) != MAXMONNO) { if (!quietly) /* have just been given "You @@ -186,6 +186,7 @@ make_familiar(struct obj *otmp, coordxy x, coordxy y, boolean quietly) return mtmp; } +/* used exclusively for hero's starting pet */ struct monst * makedog(void) { @@ -219,13 +220,22 @@ makedog(void) mtmp = makemon(&mons[pettype], u.ux, u.uy, MM_EDOG); if (!mtmp) - return ((struct monst *) 0); /* pets were genocided */ + return ((struct monst *) 0); /* pets were genocided [how?] */ - gc.context.startingpet_mid = mtmp->m_id; - /* Horses already wear a saddle */ - if (pettype == PM_PONY && !!(otmp = mksobj(SADDLE, TRUE, FALSE))) { - otmp->dknown = otmp->bknown = otmp->rknown = 1; - put_saddle_on_mon(otmp, mtmp); + if (!svc.context.startingpet_mid) { + svc.context.startingpet_mid = mtmp->m_id; + if (!u.uroleplay.pauper) { + /* initial horses already wear saddle (unless hero is a pauper) */ + if (pettype == PM_PONY + && (otmp = mksobj(SADDLE, TRUE, FALSE)) != 0) { + /* pseudo initial inventory; saddle is not actually in hero's + * invent so assume that update_inventory() isn't needed */ + fully_identify_obj(otmp); + put_saddle_on_mon(otmp, mtmp); + } + } + } else { + impossible("makedog() when startingpet_mid is already non-zero?"); } if (!gp.petname_used++ && *petname) @@ -238,7 +248,7 @@ makedog(void) staticfn void set_mon_lastmove(struct monst *mtmp) { - mtmp->mlstmv = gm.moves; + mtmp->mlstmv = svm.moves; } /* record `last move time' for all monsters prior to level save so that @@ -432,9 +442,9 @@ mon_arrive(struct monst *mtmp, int when) * specify its final destination. */ - if (mtmp->mlstmv < gm.moves - 1L) { + if (mtmp->mlstmv < svm.moves - 1L) { /* heal monster for time spent in limbo */ - long nmv = gm.moves - 1L - mtmp->mlstmv; + long nmv = svm.moves - 1L - mtmp->mlstmv; mon_catchup_elapsed_time(mtmp, nmv); @@ -489,8 +499,8 @@ mon_arrive(struct monst *mtmp, int when) that we know that the current endgame levels always build upwards and never have any exclusion subregion inside their TELEPORT_REGION settings. */ - xlocale = rn1(gu.updest.hx - gu.updest.lx + 1, gu.updest.lx); - ylocale = rn1(gu.updest.hy - gu.updest.ly + 1, gu.updest.ly); + xlocale = rn1(svu.updest.hx - svu.updest.lx + 1, svu.updest.lx); + ylocale = rn1(svu.updest.hy - svu.updest.ly + 1, svu.updest.ly); break; } /* find the arrival portal */ @@ -529,7 +539,7 @@ mon_arrive(struct monst *mtmp, int when) coord c; /* somexy() handles irregular rooms */ - if (somexy(&gr.rooms[*r - ROOMOFFSET], &c)) + if (somexy(&svr.rooms[*r - ROOMOFFSET], &c)) xlocale = c.x, ylocale = c.y; else xlocale = ylocale = 0; @@ -642,8 +652,8 @@ mon_catchup_elapsed_time( && (carnivorous(mtmp->data) || herbivorous(mtmp->data))) { struct edog *edog = EDOG(mtmp); - if ((gm.moves > edog->hungrytime + 500 && mtmp->mhp < 3) - || (gm.moves > edog->hungrytime + 750)) + if ((svm.moves > edog->hungrytime + 500 && mtmp->mhp < 3) + || (svm.moves > edog->hungrytime + 750)) mtmp->mtame = mtmp->mpeaceful = 0; } @@ -805,7 +815,7 @@ keepdogs( relmon(mtmp, &gm.mydogs); /* mtmp->mx,my retain current value */ mtmp->mx = mtmp->my = 0; /* mx==0 implies migrating */ mtmp->wormno = num_segs; - mtmp->mlstmv = gm.moves; + mtmp->mlstmv = svm.moves; } else if (keep_mon_accessible(mtmp)) { /* we want to be able to find the Wizard when his next resurrection chance comes up, but have him resume his @@ -856,7 +866,7 @@ migrate_to_level( if (In_W_tower(mx, my, &u.uz)) xyflags |= 2; mtmp->wormno = num_segs; - mtmp->mlstmv = gm.moves; + mtmp->mlstmv = svm.moves; mtmp->mtrack[2].x = u.uz.dnum; /* migrating from this dungeon */ mtmp->mtrack[2].y = u.uz.dlevel; /* migrating from this dungeon level */ mtmp->mtrack[1].x = cc ? cc->x : mx; @@ -974,7 +984,7 @@ dogfood(struct monst *mon, struct obj *obj) when starving; they never eat stone-to-flesh'd meat */ if (mptr == &mons[PM_GHOUL]) { if (obj->otyp == CORPSE) - return (peek_at_iced_corpse_age(obj) + 50L <= gm.moves + return (peek_at_iced_corpse_age(obj) + 50L <= svm.moves && !(fx == PM_LIZARD || fx == PM_LICHEN)) ? DOGFOOD : (starving && !vegan(fptr)) ? ACCFOOD : POISON; @@ -995,7 +1005,7 @@ dogfood(struct monst *mon, struct obj *obj) return POISON; return carni ? CADAVER : MANFOOD; case CORPSE: - if ((peek_at_iced_corpse_age(obj) + 50L <= gm.moves + if ((peek_at_iced_corpse_age(obj) + 50L <= svm.moves && !(fx == PM_LIZARD || fx == PM_LICHEN) && mptr->mlet != S_FUNGUS) || (acidic(fptr) && !resists_acid(mon)) @@ -1003,7 +1013,7 @@ dogfood(struct monst *mon, struct obj *obj) return POISON; /* avoid polymorph unless starving or abused (in which case the pet will consider it for a chance to become more powerful) */ - else if (is_shapeshifter(fptr) && mon->mtame > 1 && !starving) + else if (polyfood(obj) && mon->mtame > 1 && !starving) return MANFOOD; else if (vegan(fptr)) return herbi ? CADAVER : MANFOOD; @@ -1117,7 +1127,7 @@ tamedog(struct monst *mtmp, struct obj *obj, boolean givemsg) if (mtmp->mcanmove && !mtmp->mconf && !mtmp->meating && ((tasty = dogfood(mtmp, obj)) == DOGFOOD || (tasty <= ACCFOOD - && EDOG(mtmp)->hungrytime <= gm.moves))) { + && EDOG(mtmp)->hungrytime <= svm.moves))) { /* pet will "catch" and eat this thrown food */ if (canseemon(mtmp)) { boolean big_corpse = @@ -1161,7 +1171,7 @@ tamedog(struct monst *mtmp, struct obj *obj, boolean givemsg) || (obj && dogfood(mtmp, obj) >= MANFOOD)) return FALSE; - if (mtmp->m_id == gq.quest_status.leader_m_id) + if (mtmp->m_id == svq.quest_status.leader_m_id) return FALSE; /* add the pet extension */ @@ -1254,8 +1264,8 @@ wary_dog(struct monst *mtmp, boolean was_dead) edog->killed_by_u = 0; edog->abuse = 0; edog->ogoal.x = edog->ogoal.y = -1; - if (was_dead || edog->hungrytime < gm.moves + 500L) - edog->hungrytime = gm.moves + 500L; + if (was_dead || edog->hungrytime < svm.moves + 500L) + edog->hungrytime = svm.moves + 500L; if (was_dead) { edog->droptime = 0L; edog->dropdist = 10000; diff --git a/src/dogmove.c b/src/dogmove.c index 567ab9808..203403110 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -142,7 +142,7 @@ cursed_object_at(coordxy x, coordxy y) { struct obj *otmp; - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) if (otmp->cursed) return TRUE; return FALSE; @@ -223,8 +223,8 @@ dog_eat(struct monst *mtmp, char objnambuf[BUFSZ], *obj_name; objnambuf[0] = '\0'; - if (edog->hungrytime < gm.moves) - edog->hungrytime = gm.moves; + if (edog->hungrytime < svm.moves) + edog->hungrytime = svm.moves; nutrit = dog_nutrition(mtmp, obj); if (devour) { @@ -309,7 +309,7 @@ dog_eat(struct monst *mtmp, /* It's a reward if it's DOGFOOD and the player dropped/threw it. We know the player had it if invlet is set. -dlc */ if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet) - edog->apport += (int) (200L / ((long) edog->dropdist + gm.moves + edog->apport += (int) (200L / ((long) edog->dropdist + svm.moves - edog->droptime)); if (obj->unpaid) { /* edible item owned by shop has been thrown or kicked @@ -317,7 +317,8 @@ dog_eat(struct monst *mtmp, oprice = unpaid_cost(obj, COST_CONTENTS); pline("That %s will cost you %ld %s.", objnambuf, oprice, currency(oprice)); - /* m_consume_obj->delobj->obfree will handle actual shop billing update */ + /* m_consume_obj -> delobj -> obfree will actual handle shop + billing update */ } m_consume_obj(mtmp, obj); } @@ -342,9 +343,9 @@ dog_starve(struct monst *mtmp) staticfn boolean dog_hunger(struct monst *mtmp, struct edog *edog) { - if (gm.moves > edog->hungrytime + DOG_WEAK) { + if (svm.moves > edog->hungrytime + DOG_WEAK) { if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) { - edog->hungrytime = gm.moves + DOG_WEAK; + edog->hungrytime = svm.moves + DOG_WEAK; /* but not too high; it might polymorph */ } else if (!edog->mhpmax_penalty) { /* starving pets are limited in healing */ @@ -365,7 +366,7 @@ dog_hunger(struct monst *mtmp, struct edog *edog) else You_feel("worried about %s.", y_monnam(mtmp)); stop_occupation(); - } else if (gm.moves > edog->hungrytime + DOG_STARVE + } else if (svm.moves > edog->hungrytime + DOG_STARVE || DEADMONSTER(mtmp)) { dog_starve(mtmp); return TRUE; @@ -401,10 +402,10 @@ dog_invent(struct monst *mtmp, struct edog *edog, int udist) if (edog->apport > 1) edog->apport--; edog->dropdist = udist; /* hpscdi!jon */ - edog->droptime = gm.moves; + edog->droptime = svm.moves; } } else { - if ((obj = gl.level.objects[omx][omy]) != 0 + if ((obj = svl.level.objects[omx][omy]) != 0 && !strchr(nofetch, obj->oclass) #ifdef MAIL_STRUCTURES && obj->otyp != SCR_MAIL @@ -545,7 +546,7 @@ dog_goal( /* follow player if appropriate */ if (gg.gtyp == UNDEF || (gg.gtyp != DOGFOOD && gg.gtyp != APPORT - && gm.moves < edog->hungrytime)) { + && svm.moves < edog->hungrytime)) { gg.gx = u.ux; gg.gy = u.uy; if (after && udist <= 4 && u_at(gg.gx, gg.gy)) @@ -875,7 +876,7 @@ pet_ranged_attk(struct monst *mtmp) if (!mtmp->isminion) { struct edog *dog = EDOG(mtmp); - hungry = (gm.moves > (dog->hungrytime + DOG_HUNGRY)); + hungry = (svm.moves > (dog->hungrytime + DOG_HUNGRY)); } /* Identify the best target in a straight line from the pet; @@ -1015,7 +1016,7 @@ dog_move( else if (j == 1) goto newdogpos; /* eating something */ - whappr = (gm.moves - edog->whistletime < 5); + whappr = (svm.moves - edog->whistletime < 5); } else whappr = 0; @@ -1122,7 +1123,7 @@ dog_move( if ((mstatus & (M_ATTK_HIT | M_ATTK_DEF_DIED)) == M_ATTK_HIT && rn2(4) - && mtmp2->mlstmv != gm.moves + && mtmp2->mlstmv != svm.moves && !onscary(mtmp->mx, mtmp->my, mtmp2) /* monnear check needed: long worms hit on tail */ && monnear(mtmp2, mtmp->mx, mtmp->my)) { @@ -1148,6 +1149,8 @@ dog_move( /* avoid a location hero just kicked */ if (m_avoid_kicked_loc(mtmp, nx, ny)) continue; + if (m_avoid_soko_push_loc(mtmp, nx, ny)) + continue; { /* Dog avoids harmful traps, but perhaps it has to pass one @@ -1177,13 +1180,13 @@ dog_move( /* (minion isn't interested; `cursemsg' stays FALSE) */ if (edog) { boolean can_reach_food = could_reach_item(mtmp, nx, ny); - for (obj = gl.level.objects[nx][ny]; obj; obj = obj->nexthere) { + for (obj = svl.level.objects[nx][ny]; obj; obj = obj->nexthere) { if (obj->cursed) { cursemsg[i] = TRUE; } else if (can_reach_food && (otyp = dogfood(mtmp, obj)) < MANFOOD && (otyp < ACCFOOD - || edog->hungrytime <= gm.moves)) { + || edog->hungrytime <= svm.moves)) { /* Note: our dog likes the food so much that he * might eat it even when it conceals a cursed object */ nix = nx; @@ -1262,7 +1265,7 @@ dog_move( /* describe top item of pile, not necessarily cursed item itself; don't use glyph_at() here--it would return the pet but we want to know whether an object is remembered at this map location */ - struct obj *o = (!Hallucination && gl.level.flags.hero_memory + struct obj *o = (!Hallucination && svl.level.flags.hero_memory && glyph_is_object(levl[nix][niy].glyph)) ? vobj_at(nix, niy) : 0; const char *what = o ? distant_name(o, doname) : something; @@ -1336,7 +1339,10 @@ could_reach_item(struct monst *mon, coordxy nx, coordxy ny) * calls deep. */ staticfn boolean -can_reach_location(struct monst *mon, coordxy mx, coordxy my, coordxy fx, coordxy fy) +can_reach_location( + struct monst *mon, + coordxy mx, coordxy my, + coordxy fx, coordxy fy) { int i, j; int dist; diff --git a/src/dokick.c b/src/dokick.c index 7fcd7f99f..6d3d82cd2 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -126,18 +126,18 @@ staticfn boolean maybe_kick_monster(struct monst *mon, coordxy x, coordxy y) { if (mon) { - boolean save_forcefight = gc.context.forcefight; + boolean save_forcefight = svc.context.forcefight; gb.bhitpos.x = x; gb.bhitpos.y = y; if (!mon->mpeaceful || !canspotmon(mon)) - gc.context.forcefight = TRUE; /* attack even if invisible */ + svc.context.forcefight = TRUE; /* attack even if invisible */ /* kicking might be halted by discovery of hidden monster, by player declining to attack peaceful monster, or by passing out due to encumbrance */ if (attack_checks(mon, (struct obj *) 0) || overexertion()) mon = 0; /* don't kick after all */ - gc.context.forcefight = save_forcefight; + svc.context.forcefight = save_forcefight; } return (boolean) (mon != 0); } @@ -200,7 +200,8 @@ kick_monster(struct monst *mon, coordxy x, coordxy y) continue; kickdieroll = rnd(20); - specialdmg = special_dmgval(&gy.youmonst, mon, W_ARMF, (long *) 0); + specialdmg = special_dmgval(&gy.youmonst, mon, W_ARMF, + (long *) 0); if (mon->data == &mons[PM_SHADE] && !specialdmg) { /* doesn't matter whether it would have hit or missed, and shades have no passive counterattack */ @@ -491,10 +492,11 @@ kick_object(coordxy x, coordxy y, char *kickobjnam) *kickobjnam = '\0'; /* if a pile, the "top" object gets kicked */ - gk.kickedobj = gl.level.objects[x][y]; + gk.kickedobj = svl.level.objects[x][y]; if (gk.kickedobj) { - /* kick object; if doing is fatal, done() will clean up gk.kickedobj */ - Strcpy(kickobjnam, killer_xname(gk.kickedobj)); /* matters iff res==0 */ + /* formatted object name matters iff res==0 */ + Strcpy(kickobjnam, killer_xname(gk.kickedobj)); + /* kick object; if fatal, done() will clean up kickedobj */ res = really_kick_object(x, y); gk.kickedobj = (struct obj *) 0; } @@ -547,9 +549,9 @@ really_kick_object(coordxy x, coordxy y) ; /* hero has been transformed but kick continues */ } else { /* normalize body shape here; foot, not body_part(FOOT) */ - Sprintf(gk.killer.name, "kicking %s barefoot", + Sprintf(svk.killer.name, "kicking %s barefoot", killer_xname(gk.kickedobj)); - instapetrify(gk.killer.name); + instapetrify(svk.killer.name); } } @@ -907,6 +909,8 @@ kick_ouch(coordxy x, coordxy y, const char *kickobjnam) staticfn void kick_door(coordxy x, coordxy y, int avrg_attrib) { + boolean doorbuster; + if (gm.maploc->doormask == D_ISOPEN || gm.maploc->doormask == D_BROKEN || gm.maploc->doormask == D_NODOOR) { kick_dumb(x, y); @@ -920,9 +924,12 @@ kick_door(coordxy x, coordxy y, int avrg_attrib) } exercise(A_DEX, TRUE); + doorbuster = Upolyd && is_giant(gy.youmonst.data); /* door is known to be CLOSED or LOCKED */ - if (rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) { + if (doorbuster + || (rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX)))) { boolean shopdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE; + /* break the door */ if (gm.maploc->doormask & D_TRAPPED) { if (flags.verbose) @@ -1130,7 +1137,7 @@ kick_nondoor(coordxy x, coordxy y, int avrg_attrib) /* nothing, fruit or trouble? 75:23.5:1.5% */ if (rn2(3)) { - if (!rn2(6) && !(gm.mvitals[PM_KILLER_BEE].mvflags & G_GONE)) + if (!rn2(6) && !(svm.mvitals[PM_KILLER_BEE].mvflags & G_GONE)) You_hear("a low buzzing."); /* a warning */ kick_ouch(x, y, ""); return ECMD_TIME; @@ -1200,7 +1207,7 @@ kick_nondoor(coordxy x, coordxy y, int avrg_attrib) exercise(A_DEX, TRUE); return ECMD_TIME; } else if (!(gm.maploc->looted & S_LPUDDING) && !rn2(3) - && !(gm.mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) { + && !(svm.mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) { Soundeffect(se_gushing_sound, 100); if (Blind) { if (!Deaf) @@ -1215,7 +1222,7 @@ kick_nondoor(coordxy x, coordxy y, int avrg_attrib) gm.maploc->looted |= S_LPUDDING; return ECMD_TIME; } else if (!(gm.maploc->looted & S_LDWASHER) && !rn2(3) - && !(gm.mvitals[PM_AMOROUS_DEMON].mvflags & G_GONE)) { + && !(svm.mvitals[PM_AMOROUS_DEMON].mvflags & G_GONE)) { /* can't resist... */ pline("%s returns!", (Blind ? Something : "The dish washer")); if (makemon(&mons[PM_AMOROUS_DEMON], x, y, @@ -1364,12 +1371,12 @@ dokick(void) mtmp = isok(x, y) ? m_at(x, y) : 0; /* might not kick monster if it is hidden and becomes revealed, if it is peaceful and player declines to attack, or if the - hero passes out due to encumbrance with low hp; gc.context.move + hero passes out due to encumbrance with low hp; svc.context.move will be 1 unless player declines to kick peaceful monster */ if (mtmp) { oldglyph = glyph_at(x, y); if (!maybe_kick_monster(mtmp, x, y)) - return (gc.context.move ? ECMD_TIME : ECMD_OK); + return (svc.context.move ? ECMD_TIME : ECMD_OK); } wake_nearby(FALSE); @@ -1417,7 +1424,7 @@ dokick(void) map_invisible(x, y); } /* recoil if floating */ - if ((Is_airlevel(&u.uz) || Levitation) && gc.context.move) { + if ((Is_airlevel(&u.uz) || Levitation) && svc.context.move) { int range; range = @@ -1547,7 +1554,7 @@ impact_drop( isrock = (missile && missile->otyp == ROCK); oct = dct = 0L; - for (obj = gl.level.objects[x][y]; obj; obj = obj2) { + for (obj = svl.level.objects[x][y]; obj; obj = obj2) { obj2 = obj->nexthere; if (obj == missile) continue; @@ -1603,11 +1610,11 @@ impact_drop( You("removed %ld %s worth of goods!", price, currency(price)); if (cansee(shkp->mx, shkp->my)) { if (ESHK(shkp)->customer[0] == 0) - (void) strncpy(ESHK(shkp)->customer, gp.plname, PL_NSIZ); + (void) strncpy(ESHK(shkp)->customer, svp.plname, PL_NSIZ); if (angry) pline("%s is infuriated!", Shknam(shkp)); else - pline("\"%s, you are a thief!\"", gp.plname); + pline("\"%s, you are a thief!\"", svp.plname); } else You_hear("a scream, \"Thief!\""); hot_pursuit(shkp); @@ -1654,7 +1661,7 @@ ship_object(struct obj *otmp, coordxy x, coordxy y, boolean shop_floor_obj) unpaid = is_unpaid(otmp); if (OBJ_AT(x, y)) { - for (obj = gl.level.objects[x][y]; obj; obj = obj->nexthere) { + for (obj = svl.level.objects[x][y]; obj; obj = obj->nexthere) { if (obj == uchain) chainthere = TRUE; else if (obj != otmp) diff --git a/src/dothrow.c b/src/dothrow.c index 34b4c4c2c..87e7bbfd8 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -15,6 +15,7 @@ staticfn struct obj *find_launcher(struct obj *); staticfn int gem_accept(struct monst *, struct obj *); staticfn boolean toss_up(struct obj *, boolean) NONNULLARG1; staticfn void sho_obj_return_to_u(struct obj * obj); +staticfn void throwit_return(boolean); staticfn struct obj *return_throw_to_inv(struct obj *, long, boolean, struct obj *); staticfn void tmiss(struct obj *, struct monst *, boolean); @@ -89,7 +90,7 @@ throw_obj(struct obj *obj, int shotlimit) long wep_mask; boolean twoweap, weakmultishot; int res = ECMD_TIME; - struct obj_split save_osplit = gc.context.objsplit; + struct obj_split save_osplit = svc.context.objsplit; /* ask "in what direction?" */ if (!getdir((char *) 0)) { @@ -140,8 +141,9 @@ throw_obj(struct obj *obj, int shotlimit) /* throwing with one hand, but pluralize since the expression "with your bare hands" sounds better */ makeplural(body_part(HAND))); - Sprintf(gk.killer.name, "throwing %s bare-handed", killer_xname(obj)); - instapetrify(gk.killer.name); + Sprintf(svk.killer.name, "throwing %s bare-handed", + killer_xname(obj)); + instapetrify(svk.killer.name); } if (welded(obj)) { weldmsg(obj); @@ -280,7 +282,7 @@ throw_obj(struct obj *obj, int shotlimit) || obj->o_id == save_osplit.child_oid)) { /* futureproofing: objsplit will have been affected if partial stack was thrown; objects will have been split off stack to throw. */ - gc.context.objsplit = save_osplit; + svc.context.objsplit = save_osplit; (void) unsplitobj(obj); } return res; @@ -579,7 +581,7 @@ void endmultishot(boolean verbose) { if (gm.m_shot.i < gm.m_shot.n) { - if (verbose && !gc.context.mon_moving) { + if (verbose && !svc.context.mon_moving) { You("stop %s after the %d%s %s.", gm.m_shot.s ? "firing" : "throwing", gm.m_shot.i, ordin(gm.m_shot.i), @@ -873,9 +875,9 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y) if (touch_petrifies(mon->data) /* this is a bodily collision, so check for body armor */ && !uarmu && !uarm && !uarmc) { - Sprintf(gk.killer.name, "bumping into %s", + Sprintf(svk.killer.name, "bumping into %s", an(pmname(mon->data, NEUTRAL))); - instapetrify(gk.killer.name); + instapetrify(svk.killer.name); } if (touch_petrifies(gy.youmonst.data) && !which_armor(mon, W_ARMU | W_ARM | W_ARMC)) { @@ -1031,17 +1033,17 @@ mhurtle_step(genericptr_t arg, coordxy x, coordxy y) if ((mtmp = m_at(x, y)) != 0 && mtmp != mon) { if (canseemon(mon) || canseemon(mtmp)) pline("%s bumps into %s.", Monnam(mon), a_monnam(mtmp)); - wakeup(mtmp, !gc.context.mon_moving); + wakeup(mtmp, !svc.context.mon_moving); /* check whether 'mon' is turned to stone by touching 'mtmp' */ if (touch_petrifies(mtmp->data) && !which_armor(mon, W_ARMU | W_ARM | W_ARMC)) { - minstapetrify(mon, !gc.context.mon_moving); + minstapetrify(mon, !svc.context.mon_moving); newsym(mon->mx, mon->my); } /* and whether 'mtmp' is turned to stone by being touched by 'mon' */ if (touch_petrifies(mon->data) && !which_armor(mtmp, W_ARMU | W_ARM | W_ARMC)) { - minstapetrify(mtmp, !gc.context.mon_moving); + minstapetrify(mtmp, !svc.context.mon_moving); newsym(mtmp->mx, mtmp->my); } } else if (u_at(x, y)) { @@ -1057,12 +1059,13 @@ mhurtle_step(genericptr_t arg, coordxy x, coordxy y) } /* and whether hero is turned to stone by being touched by 'mon' */ if (touch_petrifies(mon->data) && !(uarmu || uarm || uarmc)) { - Snprintf(gk.killer.name, sizeof gk.killer.name, "being hit by %s", + Snprintf(svk.killer.name, sizeof svk.killer.name, + "being hit by %s", /* combine m_monnam() and noname_monnam(): "{your,a} hurtling cockatrice" w/o assigned name */ x_monnam(mon, mon->mtame ? ARTICLE_YOUR : ARTICLE_A, "hurtling", EXACT_NAME | SUPPRESS_NAME, FALSE)); - instapetrify(gk.killer.name); + instapetrify(svk.killer.name); newsym(u.ux, u.uy); } } @@ -1134,7 +1137,7 @@ mhurtle(struct monst *mon, int dx, int dy, int range) { coord mc, cc; - wakeup(mon, !gc.context.mon_moving); + wakeup(mon, !svc.context.mon_moving); /* At the very least, debilitate the monster */ mon->movement = 0; mon->mstun = 1; @@ -1345,8 +1348,8 @@ toss_up(struct obj *obj, boolean hitsroof) if (obj->oartifact && !harmless) /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */ - artimsg = artifact_hit((struct monst *) 0, &gy.youmonst, obj, &dmg, - rn1(18, 2)); + artimsg = artifact_hit((struct monst *) 0, &gy.youmonst, obj, + &dmg, rn1(18, 2)); if (!dmg) { /* probably wasn't a weapon; base damage on weight */ dmg = ((int) obj->owt + 99) / 100; @@ -1397,8 +1400,9 @@ toss_up(struct obj *obj, boolean hitsroof) && !(poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM))) { petrify: - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, "elementary physics"); /* what goes up... */ + svk.killer.format = KILLED_BY; + /* what goes up... */ + Strcpy(svk.killer.name, "elementary physics"); You("turn to stone."); if (obj) dropy(obj); /* bypass most of hitfloor() */ @@ -1450,6 +1454,14 @@ sho_obj_return_to_u(struct obj *obj) } } +staticfn void +throwit_return(boolean clear_thrownobj) +{ + iflags.returning_missile = (genericptr_t) 0; + if (clear_thrownobj) + gt.thrownobj = (struct obj *) 0; +} + /* throw an object, NB: obj may be consumed in the process */ void throwit(struct obj *obj, @@ -1460,7 +1472,7 @@ throwit(struct obj *obj, { struct monst *mon; int range, urange; - boolean crossbowing, clear_thrownobj = FALSE, + boolean crossbowing, impaired = (Confusion || Stunned || Blind || Hallucination || Fumbling), tethered_weapon = (obj->otyp == AKLYS && (wep_mask & W_WEP) != 0); @@ -1538,8 +1550,8 @@ throwit(struct obj *obj, } else { hitfloor(obj, TRUE); } - clear_thrownobj = TRUE; - goto throwit_return; + throwit_return(TRUE); + return; } else if (obj->otyp == BOOMERANG && !Underwater) { if (Is_airlevel(&u.uz) || Levitation) @@ -1549,8 +1561,8 @@ throwit(struct obj *obj, if (mon == &gy.youmonst) { /* the thing was caught */ exercise(A_DEX, TRUE); obj = return_throw_to_inv(obj, wep_mask, twoweap, oldslot); - clear_thrownobj = TRUE; - goto throwit_return; + throwit_return(TRUE); + return; } } else { /* crossbow range is independent of strength */ @@ -1625,7 +1637,8 @@ throwit(struct obj *obj, we're about to return */ if (tethered_weapon) tmp_at(DISP_END, 0); - goto throwit_return; + throwit_return(FALSE); + return; } } @@ -1633,8 +1646,8 @@ throwit(struct obj *obj, boolean obj_gone; if (mon->isshk && obj->where == OBJ_MINVENT && obj->ocarry == mon) { - clear_thrownobj = TRUE; - goto throwit_return; /* alert shk caught it */ + throwit_return(TRUE); /* alert shk caught it */ + return; } (void) snuff_candle(obj); gn.notonhead = (gb.bhitpos.x != mon->mx || gb.bhitpos.y != mon->my); @@ -1658,11 +1671,12 @@ throwit(struct obj *obj, tmp_at(DISP_END, 0); } else if (u.uswallow && !iflags.returning_missile) { swallowit: - if (obj != uball) + if (obj != uball) { (void) mpickobj(u.ustuck, obj); /* clears 'gt.thrownobj' */ - else - clear_thrownobj = TRUE; - goto throwit_return; + throwit_return(FALSE); + } else + throwit_return(TRUE); + return; } else { /* Mjollnir must be wielded to be thrown--caller verifies this; aklys must be wielded as primary to return when thrown */ @@ -1712,8 +1726,8 @@ throwit(struct obj *obj, if (!ship_object(obj, u.ux, u.uy, FALSE)) dropy(obj); } - clear_thrownobj = TRUE; - goto throwit_return; + throwit_return(TRUE); + return; } else { if (tethered_weapon) tmp_at(DISP_END, 0); @@ -1742,21 +1756,22 @@ throwit(struct obj *obj, tmp_at(DISP_END, 0); breakmsg(obj, cansee(gb.bhitpos.x, gb.bhitpos.y)); if (breakobj(obj, gb.bhitpos.x, gb.bhitpos.y, TRUE, TRUE)) { - clear_thrownobj = TRUE; - goto throwit_return; + throwit_return(TRUE); + return; } } if (!Deaf && !Underwater) { /* Some sound effects when item lands in water or lava */ if (is_pool(gb.bhitpos.x, gb.bhitpos.y) - || (is_lava(gb.bhitpos.x, gb.bhitpos.y) && !is_flammable(obj))) { + || (is_lava(gb.bhitpos.x, gb.bhitpos.y) + && !is_flammable(obj))) { Soundeffect(se_splash, 50); pline((weight(obj) > 9) ? "Splash!" : "Plop!"); } } if (flooreffects(obj, gb.bhitpos.x, gb.bhitpos.y, "fall")) { - clear_thrownobj = TRUE; - goto throwit_return; + throwit_return(TRUE); + return; } obj_no_longer_held(obj); if (mon && mon->isshk && is_pick(obj)) { @@ -1765,13 +1780,13 @@ throwit(struct obj *obj, if (*u.ushops || obj->unpaid) check_shop_obj(obj, gb.bhitpos.x, gb.bhitpos.y, FALSE); (void) mpickobj(mon, obj); /* may merge and free obj */ - clear_thrownobj = TRUE; - goto throwit_return; + throwit_return(TRUE); + return; } (void) snuff_candle(obj); if (!mon && ship_object(obj, gb.bhitpos.x, gb.bhitpos.y, FALSE)) { - clear_thrownobj = TRUE; - goto throwit_return; + throwit_return(TRUE); + return; } gt.thrownobj = (struct obj *) 0; place_object(obj, gb.bhitpos.x, gb.bhitpos.y); @@ -1797,10 +1812,7 @@ throwit(struct obj *obj, gv.vision_full_recalc = 1; } - throwit_return: - iflags.returning_missile = (genericptr_t) 0; - if (clear_thrownobj) - gt.thrownobj = (struct obj *) 0; + throwit_return(FALSE); return; } @@ -1818,8 +1830,8 @@ return_throw_to_inv( /* if 'obj' is from a stack split, we can put it back by undoing split so there's no chance of merging with some other compatible stack */ - if (obj->o_id == gc.context.objsplit.parent_oid - || obj->o_id == gc.context.objsplit.child_oid) { + if (obj->o_id == svc.context.objsplit.parent_oid + || obj->o_id == svc.context.objsplit.child_oid) { obj->nobj = gi.invent; gi.invent = obj; obj->where = OBJ_INVENT; @@ -1925,7 +1937,7 @@ tmiss(struct obj *obj, struct monst *mon, boolean maybe_wakeup) #define special_obj_hits_leader(obj, mon) \ ((is_quest_artifact(obj) || objects[obj->otyp].oc_unique \ || (obj->otyp == FAKE_AMULET_OF_YENDOR && !obj->known)) \ - && mon->m_id == gq.quest_status.leader_m_id) + && mon->m_id == svq.quest_status.leader_m_id) /* whether or not object should be destroyed when it hits its target */ boolean @@ -1944,7 +1956,7 @@ should_mulch_missile(struct obj *obj) around longer on average. */ chance = 3 + greatest_erosion(obj) - obj->spe; broken = chance > 1 ? rn2(chance) : !rn2(4); - if (obj->blessed && (gc.context.mon_moving ? !rn2(3) : !rnl(4))) + if (obj->blessed && (svc.context.mon_moving ? !rn2(3) : !rnl(4))) broken = FALSE; /* Flint and hard gems don't break easily */ @@ -2614,8 +2626,8 @@ throw_gold(struct obj *obj) You("cannot throw gold at yourself."); /* If we tried to throw part of a stack, force it to merge back together (same as in throw_obj). Essential for gold. */ - if (obj->o_id == gc.context.objsplit.parent_oid - || obj->o_id == gc.context.objsplit.child_oid) + if (obj->o_id == svc.context.objsplit.parent_oid + || obj->o_id == svc.context.objsplit.child_oid) (void) unsplitobj(obj); return ECMD_CANCEL; } @@ -2650,7 +2662,8 @@ throw_gold(struct obj *obj) /* see if the gold has a place to move into */ odx = u.ux + u.dx; ody = u.uy + u.dy; - if (!isok(odx, ody) || !ZAP_POS(levl[odx][ody].typ) || closed_door(odx, ody)) { + if (!isok(odx, ody) + || !ZAP_POS(levl[odx][ody].typ) || closed_door(odx, ody)) { gb.bhitpos.x = u.ux; gb.bhitpos.y = u.uy; } else { diff --git a/src/dungeon.c b/src/dungeon.c index 8b3730bfd..981a880bb 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -38,7 +38,8 @@ staticfn void Fread(genericptr_t, int, int, dlb *); staticfn xint16 dname_to_dnum(const char *); staticfn int find_branch(const char *, struct proto_dungeon *); staticfn xint16 parent_dnum(const char *, struct proto_dungeon *); -staticfn int level_range(xint16, int, int, int, struct proto_dungeon *, int *); +staticfn int level_range(xint16, int, int, int, struct proto_dungeon *, + int *); staticfn xint16 parent_dlevel(const char *, struct proto_dungeon *); staticfn int correct_branch_type(struct tmpbranch *); staticfn branch *add_branch(int, int, struct proto_dungeon *); @@ -85,7 +86,7 @@ staticfn void dumpit(void); staticfn void dumpit(void) { -#define DD gd.dungeons[i] +#define DD svd.dungeons[i] int i; s_level *x; branch *br; @@ -93,7 +94,7 @@ dumpit(void) if (!explicitdebug(__FILE__)) return; - for (i = 0; i < gn.n_dgns; i++) { + for (i = 0; i < svn.n_dgns; i++) { fprintf(stderr, "\n#%d \"%s\" (%s):\n", i, DD.dname, DD.proto); fprintf(stderr, " num_dunlevs %d, dunlev_ureached %d\n", DD.num_dunlevs, DD.dunlev_ureached); @@ -106,7 +107,7 @@ dumpit(void) (void) getchar(); } fprintf(stderr, "\nSpecial levels:\n"); - for (x = gs.sp_levchn; x; x = x->next) { + for (x = svs.sp_levchn; x; x = x->next) { fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs); fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel); fprintf(stderr, "flags:%s%s%s%s\n", @@ -117,7 +118,7 @@ dumpit(void) (void) getchar(); } fprintf(stderr, "\nBranches:\n"); - for (br = gb.branches; br; br = br->next) { + for (br = svb.branches; br; br = br->next) { fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n", br->id, br->type == BR_STAIR ? "stair" @@ -152,48 +153,48 @@ save_dungeon( if (perform_write) { if(nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &gn.n_dgns, sizeof gn.n_dgns); - bwrite(nhfp->fd, (genericptr_t) gd.dungeons, - sizeof(dungeon) * (unsigned) gn.n_dgns); - bwrite(nhfp->fd, (genericptr_t) &gd.dungeon_topology, - sizeof gd.dungeon_topology); - bwrite(nhfp->fd, (genericptr_t) gt.tune, sizeof tune); + bwrite(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns); + bwrite(nhfp->fd, (genericptr_t) svd.dungeons, + sizeof(dungeon) * (unsigned) svn.n_dgns); + bwrite(nhfp->fd, (genericptr_t) &svd.dungeon_topology, + sizeof svd.dungeon_topology); + bwrite(nhfp->fd, (genericptr_t) svt.tune, sizeof tune); } - for (count = 0, curr = gb.branches; curr; curr = curr->next) + for (count = 0, curr = svb.branches; curr; curr = curr->next) count++; if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - for (curr = gb.branches; curr; curr = curr->next) { + for (curr = svb.branches; curr; curr = curr->next) { if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) curr, sizeof *curr); } count = maxledgerno(); if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - bwrite(nhfp->fd, (genericptr_t) gl.level_info, + bwrite(nhfp->fd, (genericptr_t) svl.level_info, (unsigned) count * sizeof (struct linfo)); - bwrite(nhfp->fd, (genericptr_t) &gi.inv_pos, sizeof gi.inv_pos); + bwrite(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos); } - for (count = 0, curr_ms = gm.mapseenchn; curr_ms; + for (count = 0, curr_ms = svm.mapseenchn; curr_ms; curr_ms = curr_ms->next) count++; if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - for (curr_ms = gm.mapseenchn; curr_ms; curr_ms = curr_ms->next) { + for (curr_ms = svm.mapseenchn; curr_ms; curr_ms = curr_ms->next) { save_mapseen(nhfp, curr_ms); } } if (free_data) { - for (curr = gb.branches; curr; curr = next) { + for (curr = svb.branches; curr; curr = next) { next = curr->next; free((genericptr_t) curr); } - gb.branches = 0; - for (curr_ms = gm.mapseenchn; curr_ms; curr_ms = next_ms) { + svb.branches = 0; + for (curr_ms = svm.mapseenchn; curr_ms; curr_ms = next_ms) { next_ms = curr_ms->next; if (curr_ms->custom) free((genericptr_t) curr_ms->custom); @@ -201,7 +202,7 @@ save_dungeon( savecemetery(nhfp, &curr_ms->final_resting_place); free((genericptr_t) curr_ms); } - gm.mapseenchn = 0; + svm.mapseenchn = 0; } } @@ -214,14 +215,14 @@ restore_dungeon(NHFILE *nhfp) mapseen *curr_ms, *last_ms; if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &gn.n_dgns, sizeof gn.n_dgns); - mread(nhfp->fd, (genericptr_t) gd.dungeons, - sizeof (dungeon) * (unsigned) gn.n_dgns); - mread(nhfp->fd, (genericptr_t) &gd.dungeon_topology, - sizeof gd.dungeon_topology); - mread(nhfp->fd, (genericptr_t) gt.tune, sizeof tune); + mread(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns); + mread(nhfp->fd, (genericptr_t) svd.dungeons, + sizeof (dungeon) * (unsigned) svn.n_dgns); + mread(nhfp->fd, (genericptr_t) &svd.dungeon_topology, + sizeof svd.dungeon_topology); + mread(nhfp->fd, (genericptr_t) svt.tune, sizeof tune); } - last = gb.branches = (branch *) 0; + last = svb.branches = (branch *) 0; if (nhfp->structlevel) mread(nhfp->fd, (genericptr_t) &count, sizeof count); @@ -234,7 +235,7 @@ restore_dungeon(NHFILE *nhfp) if (last) last->next = curr; else - gb.branches = curr; + svb.branches = curr; last = curr; } @@ -245,11 +246,11 @@ restore_dungeon(NHFILE *nhfp) panic("level information count larger (%d) than allocated size", count); if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) gl.level_info, + mread(nhfp->fd, (genericptr_t) svl.level_info, (unsigned) count * sizeof (struct linfo)); if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &gi.inv_pos, sizeof gi.inv_pos); + mread(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos); mread(nhfp->fd, (genericptr_t) &count, sizeof count); } @@ -260,7 +261,7 @@ restore_dungeon(NHFILE *nhfp) if (last_ms) last_ms->next = curr_ms; else - gm.mapseenchn = curr_ms; + svm.mapseenchn = curr_ms; last_ms = curr_ms; } } @@ -287,8 +288,8 @@ dname_to_dnum(const char *s) { xint16 i; - for (i = 0; i < gn.n_dgns; i++) - if (!strcmp(gd.dungeons[i].dname, s)) + for (i = 0; i < svn.n_dgns; i++) + if (!strcmp(svd.dungeons[i].dname, s)) return i; panic("Couldn't resolve dungeon number for name \"%s\".", s); @@ -302,7 +303,7 @@ s_level * find_level(const char *s) { s_level *curr; - for (curr = gs.sp_levchn; curr; curr = curr->next) + for (curr = svs.sp_levchn; curr; curr = curr->next) if (!strcmpi(s, curr->proto)) break; return curr; @@ -327,8 +328,8 @@ find_branch( branch *br; const char *dnam; - for (br = gb.branches; br; br = br->next) { - dnam = gd.dungeons[br->end2.dnum].dname; + for (br = svb.branches; br; br = br->next) { + dnam = svd.dungeons[br->end2.dnum].dname; if (!strcmpi(dnam, s) || (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s))) break; @@ -385,7 +386,7 @@ level_range( struct proto_dungeon *pd, int *adjusted_base) { - int lmax = gd.dungeons[dgn].num_dunlevs; + int lmax = svd.dungeons[dgn].num_dunlevs; if (chain >= 0) { /* relative to a special level */ s_level *levtmp = pd->final_lev[chain]; @@ -429,7 +430,7 @@ parent_dlevel(const char *s, struct proto_dungeon *pd) do { if (++i >= num) i = 0; - for (curr = gb.branches; curr; curr = curr->next) + for (curr = svb.branches; curr; curr = curr->next) if ((curr->end1.dnum == dnum && curr->end1.dlevel == base + i) || (curr->end2.dnum == dnum && curr->end2.dlevel == base + i)) break; @@ -468,7 +469,7 @@ insert_branch(branch *new_branch, boolean extract_first) long new_val, curr_val, prev_val; if (extract_first) { - for (prev = 0, curr = gb.branches; curr; + for (prev = 0, curr = svb.branches; curr; prev = curr, curr = curr->next) if (curr == new_branch) break; @@ -478,7 +479,7 @@ insert_branch(branch *new_branch, boolean extract_first) if (prev) prev->next = curr->next; else - gb.branches = curr->next; + svb.branches = curr->next; } new_branch->next = (branch *) 0; @@ -494,7 +495,7 @@ insert_branch(branch *new_branch, boolean extract_first) prev = (branch *) 0; prev_val = -1; new_val = branch_val(new_branch); - for (curr = gb.branches; curr; + for (curr = svb.branches; curr; prev_val = curr_val, prev = curr, curr = curr->next) { curr_val = branch_val(curr); if (prev_val < new_val && new_val <= curr_val) @@ -504,8 +505,8 @@ insert_branch(branch *new_branch, boolean extract_first) new_branch->next = curr; prev->next = new_branch; } else { - new_branch->next = gb.branches; - gb.branches = new_branch; + new_branch->next = svb.branches; + svb.branches = new_branch; } } @@ -521,14 +522,14 @@ add_branch( int branch_num; branch *new_branch; - branch_num = find_branch(gd.dungeons[dgn].dname, pd); + branch_num = find_branch(svd.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]); - new_branch->end1.dnum = parent_dnum(gd.dungeons[dgn].dname, pd); - new_branch->end1.dlevel = parent_dlevel(gd.dungeons[dgn].dname, pd); + new_branch->end1.dnum = parent_dnum(svd.dungeons[dgn].dname, pd); + new_branch->end1.dlevel = parent_dlevel(svd.dungeons[dgn].dname, pd); new_branch->end2.dnum = dgn; new_branch->end2.dlevel = child_entry_level; new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE; @@ -549,15 +550,15 @@ add_level(s_level *new_lev) s_level *prev, *curr; prev = (s_level *) 0; - for (curr = gs.sp_levchn; curr; curr = curr->next) { + for (curr = svs.sp_levchn; curr; curr = curr->next) { if (curr->dlevel.dnum == new_lev->dlevel.dnum && curr->dlevel.dlevel > new_lev->dlevel.dlevel) break; prev = curr; } if (!prev) { - new_lev->next = gs.sp_levchn; - gs.sp_levchn = new_lev; + new_lev->next = svs.sp_levchn; + svs.sp_levchn = new_lev; } else { new_lev->next = curr; prev->next = new_lev; @@ -945,16 +946,16 @@ init_dungeon_set_entry(struct proto_dungeon *pd, int dngidx) * redundant. It is used only here and in print_dungeon(). */ if (dgn_entry < 0) { - gd.dungeons[dngidx].entry_lev = - gd.dungeons[dngidx].num_dunlevs + dgn_entry + 1; - if (gd.dungeons[dngidx].entry_lev <= 0) - gd.dungeons[dngidx].entry_lev = 1; + svd.dungeons[dngidx].entry_lev = + svd.dungeons[dngidx].num_dunlevs + dgn_entry + 1; + if (svd.dungeons[dngidx].entry_lev <= 0) + svd.dungeons[dngidx].entry_lev = 1; } else if (dgn_entry > 0) { - gd.dungeons[dngidx].entry_lev = dgn_entry; - if (gd.dungeons[dngidx].entry_lev > gd.dungeons[dngidx].num_dunlevs) - gd.dungeons[dngidx].entry_lev = gd.dungeons[dngidx].num_dunlevs; + svd.dungeons[dngidx].entry_lev = dgn_entry; + if (svd.dungeons[dngidx].entry_lev > svd.dungeons[dngidx].num_dunlevs) + svd.dungeons[dngidx].entry_lev = svd.dungeons[dngidx].num_dunlevs; } else { /* default */ - gd.dungeons[dngidx].entry_lev = 1; /* defaults to top level */ + svd.dungeons[dngidx].entry_lev = 1; /* defaults to top level */ } } @@ -965,7 +966,7 @@ init_dungeon_set_depth(struct proto_dungeon *pd, int dngidx) schar from_depth; boolean from_up; - br = add_branch(dngidx, gd.dungeons[dngidx].entry_lev, pd); + br = add_branch(dngidx, svd.dungeons[dngidx].entry_lev, pd); /* Get the depth of the connecting end. */ if (br->end1.dnum == dngidx) { @@ -990,9 +991,9 @@ init_dungeon_set_depth(struct proto_dungeon *pd, int dngidx) * * We'll say that portals stay on the same depth. */ - gd.dungeons[dngidx].depth_start = + svd.dungeons[dngidx].depth_start = from_depth + (br->type == BR_PORTAL ? 0 : (from_up ? -1 : 1)) - - (gd.dungeons[dngidx].entry_lev - 1); + - (svd.dungeons[dngidx].entry_lev - 1); } staticfn boolean @@ -1006,7 +1007,8 @@ init_dungeon_dungeons( int dgn_base, dgn_range, dgn_align, dgn_entry, dgn_chance, dgn_flags; dgn_name = get_table_str(L, "name"); - dgn_bonetag = get_table_str_opt(L, "bonetag", emptystr); /* TODO: single char or "none" */ + /* TODO: accept single char or "none" for bonetag */ + dgn_bonetag = get_table_str_opt(L, "bonetag", emptystr); dgn_protoname = get_table_str_opt(L, "protofile", emptystr); dgn_base = get_table_int(L, "base"); dgn_range = get_table_int_opt(L, "range", 0); @@ -1022,7 +1024,7 @@ init_dungeon_dungeons( if (!wizard && dgn_chance && (dgn_chance <= rn2(100))) { debugpline1("IGNORING %s", dgn_name); - gn.n_dgns--; + svn.n_dgns--; free((genericptr_t) dgn_name); free((genericptr_t) dgn_bonetag); free((genericptr_t) dgn_protoname); @@ -1059,47 +1061,50 @@ init_dungeon_dungeons( pd->tmpdungeon[dngidx].chance = dgn_chance; pd->tmpdungeon[dngidx].entry_lev = dgn_entry; - Strcpy(gd.dungeons[dngidx].fill_lvl, dgn_fill); /* FIXME: fill_lvl len */ - Strcpy(gd.dungeons[dngidx].dname, dgn_name); /* FIXME: dname length */ - Strcpy(gd.dungeons[dngidx].proto, dgn_protoname); /* FIXME: proto length */ - Strcpy(gd.dungeons[dngidx].themerms, dgn_themerms); /* FIXME: length */ - gd.dungeons[dngidx].boneid = *dgn_bonetag ? *dgn_bonetag : 0; + /* FIXME: these should have length checks */ + Strcpy(svd.dungeons[dngidx].fill_lvl, dgn_fill); + Strcpy(svd.dungeons[dngidx].dname, dgn_name); + Strcpy(svd.dungeons[dngidx].proto, dgn_protoname); + Strcpy(svd.dungeons[dngidx].themerms, dgn_themerms); + /* FIXME: accept "none", convert that to '\0' */ + svd.dungeons[dngidx].boneid = *dgn_bonetag ? *dgn_bonetag : 0; free((genericptr) dgn_fill); /* free((genericptr) dgn_protoname); -- stored in pd.tmpdungeon[] */ free((genericptr) dgn_bonetag); free((genericptr) dgn_themerms); if (dgn_range) - gd.dungeons[dngidx].num_dunlevs = (xint16) rn1(dgn_range, dgn_base); + svd.dungeons[dngidx].num_dunlevs = (xint16) rn1(dgn_range, dgn_base); else - gd.dungeons[dngidx].num_dunlevs = (xint16) dgn_base; + svd.dungeons[dngidx].num_dunlevs = (xint16) dgn_base; if (!dngidx) { - gd.dungeons[dngidx].ledger_start = 0; - gd.dungeons[dngidx].depth_start = 1; - gd.dungeons[dngidx].dunlev_ureached = 1; + svd.dungeons[dngidx].ledger_start = 0; + svd.dungeons[dngidx].depth_start = 1; + svd.dungeons[dngidx].dunlev_ureached = 1; } else { - gd.dungeons[dngidx].ledger_start = gd.dungeons[dngidx - 1].ledger_start - + gd.dungeons[dngidx - 1].num_dunlevs; - gd.dungeons[dngidx].dunlev_ureached = 0; + svd.dungeons[dngidx].ledger_start + = svd.dungeons[dngidx - 1].ledger_start + + svd.dungeons[dngidx - 1].num_dunlevs; + svd.dungeons[dngidx].dunlev_ureached = 0; } - gd.dungeons[dngidx].flags.hellish = !!(dgn_flags & HELLISH); - gd.dungeons[dngidx].flags.maze_like = !!(dgn_flags & MAZELIKE); - gd.dungeons[dngidx].flags.rogue_like = !!(dgn_flags & ROGUELIKE); - gd.dungeons[dngidx].flags.align = dgn_align; - gd.dungeons[dngidx].flags.unconnected = !!(dgn_flags & UNCONNECTED); + svd.dungeons[dngidx].flags.hellish = !!(dgn_flags & HELLISH); + svd.dungeons[dngidx].flags.maze_like = !!(dgn_flags & MAZELIKE); + svd.dungeons[dngidx].flags.rogue_like = !!(dgn_flags & ROGUELIKE); + svd.dungeons[dngidx].flags.align = dgn_align; + svd.dungeons[dngidx].flags.unconnected = !!(dgn_flags & UNCONNECTED); init_dungeon_set_entry(pd, dngidx); - if (gd.dungeons[dngidx].flags.unconnected) { - gd.dungeons[dngidx].depth_start = 1; + if (svd.dungeons[dngidx].flags.unconnected) { + svd.dungeons[dngidx].depth_start = 1; } else if (dngidx) { /* set depth */ init_dungeon_set_depth(pd, dngidx); } - if (gd.dungeons[dngidx].num_dunlevs > MAXLEVEL) - gd.dungeons[dngidx].num_dunlevs = MAXLEVEL; + if (svd.dungeons[dngidx].num_dunlevs > MAXLEVEL) + svd.dungeons[dngidx].num_dunlevs = MAXLEVEL; return TRUE; } @@ -1111,8 +1116,8 @@ init_castle_tune(void) int i; for (i = 0; i < 5; i++) - gt.tune[i] = 'A' + rn2(7); - gt.tune[5] = 0; + svt.tune[i] = 'A' + rn2(7); + svt.tune[5] = 0; } /* fix up the special level names and locations for quick access */ @@ -1144,12 +1149,12 @@ fixup_level_locations(void) * specify a floating entrance by the fact that its * entrance (end1) has a bogus dnum, namely n_dgns. */ - for (br = gb.branches; br; br = br->next) + for (br = svb.branches; br; br = br->next) if (on_level(&br->end2, &knox_level)) break; if (br) - br->end1.dnum = gn.n_dgns; + br->end1.dnum = svn.n_dgns; /* adjust the branch's position on the list */ insert_branch(br, TRUE); } @@ -1171,8 +1176,8 @@ fixup_level_locations(void) making the dummy level overlay level 1; but the whole reason for having the dummy level is to make earth have depth -1 instead of 0, so adjust the start point to shift endgame up */ - if (dunlevs_in_dungeon(&x->dlevel) > 1 - gd.dungeons[i].depth_start) - gd.dungeons[i].depth_start -= 1; + if (dunlevs_in_dungeon(&x->dlevel) > 1 - svd.dungeons[i].depth_start) + svd.dungeons[i].depth_start -= 1; /* TODO: strip "dummy" out all the way here, so that it's hidden from '#wizwhere' feedback. */ } @@ -1191,7 +1196,7 @@ free_proto_dungeon(struct proto_dungeon *pd) if (pd->tmplevel[i].chainlvl) free((genericptr_t) pd->tmplevel[i].chainlvl); } - for (i = 0; i < gn.n_dgns; i++) { + for (i = 0; i < svn.n_dgns; i++) { free((genericptr_t) pd->tmpdungeon[i].name); free((genericptr_t) pd->tmpdungeon[i].protoname); } @@ -1244,7 +1249,7 @@ init_dungeons(void) if (iflags.window_inited) clear_nhwindow(WIN_MAP); - gs.sp_levchn = (s_level *) 0; + svs.sp_levchn = (s_level *) 0; lua_settop(L, 0); @@ -1253,7 +1258,7 @@ init_dungeons(void) panic("dungeon is not a lua table"); lua_len(L, -1); - gn.n_dgns = (int) lua_tointeger(L, -1); + svn.n_dgns = (int) lua_tointeger(L, -1); lua_pop(L, 1); pd.start = 0; @@ -1265,7 +1270,7 @@ init_dungeons(void) * dungeon arrays. */ - if (gn.n_dgns >= MAXDUNGEON) + if (svn.n_dgns >= MAXDUNGEON) panic("init_dungeons: too many dungeons"); tidx = lua_gettop(L); @@ -1328,7 +1333,7 @@ dunlev(d_level *lev) xint16 dunlevs_in_dungeon(d_level *lev) { - return gd.dungeons[lev->dnum].num_dunlevs; + return svd.dungeons[lev->dnum].num_dunlevs; } /* return the lowest level explored in the game*/ @@ -1354,10 +1359,10 @@ deepest_lev_reached(boolean noquest) d_level tmp; xint16 ret = 0; - for (i = 0; i < gn.n_dgns; i++) { + for (i = 0; i < svn.n_dgns; i++) { if (noquest && i == quest_dnum) continue; - tmp.dlevel = gd.dungeons[i].dunlev_ureached; + tmp.dlevel = svd.dungeons[i].dunlev_ureached; if (tmp.dlevel == 0) continue; tmp.dnum = i; @@ -1372,12 +1377,12 @@ deepest_lev_reached(boolean noquest) xint16 ledger_no(d_level *lev) { - return (xint16) (lev->dlevel + gd.dungeons[lev->dnum].ledger_start); + return (xint16) (lev->dlevel + svd.dungeons[lev->dnum].ledger_start); } /* * The last level in the bookkeeping list of level is the bottom of the last - * dungeon in the gd.dungeons[] array. + * dungeon in the svd.dungeons[] array. * * Maxledgerno() -- which is the max number of levels in the bookkeeping * list, should not be confused with dunlevs_in_dungeon(lev) -- which @@ -1388,8 +1393,8 @@ ledger_no(d_level *lev) xint16 maxledgerno(void) { - return (xint16) (gd.dungeons[gn.n_dgns - 1].ledger_start - + gd.dungeons[gn.n_dgns - 1].num_dunlevs); + return (xint16) (svd.dungeons[svn.n_dgns - 1].ledger_start + + svd.dungeons[svn.n_dgns - 1].num_dunlevs); } DISABLE_WARNING_UNREACHABLE_CODE @@ -1401,10 +1406,10 @@ ledger_to_dnum(xint16 ledgerno) xint16 i; /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */ - for (i = 0; i < gn.n_dgns; i++) - if (gd.dungeons[i].ledger_start < ledgerno - && (ledgerno - <= gd.dungeons[i].ledger_start + gd.dungeons[i].num_dunlevs)) + for (i = 0; i < svn.n_dgns; i++) + if (svd.dungeons[i].ledger_start < ledgerno + && ledgerno <= (svd.dungeons[i].ledger_start + + svd.dungeons[i].num_dunlevs)) return i; panic("level number out of range [ledger_to_dnum(%d)]", (int) ledgerno); @@ -1419,7 +1424,7 @@ xint16 ledger_to_dlev(xint16 ledgerno) { return (xint16) (ledgerno - - gd.dungeons[ledger_to_dnum(ledgerno)].ledger_start); + - svd.dungeons[ledger_to_dnum(ledgerno)].ledger_start); } /* returns the depth of a level, in floors below the surface @@ -1427,7 +1432,7 @@ ledger_to_dlev(xint16 ledgerno) schar depth(d_level *lev) { - return (schar) (gd.dungeons[lev->dnum].depth_start + lev->dlevel - 1); + return (schar) (svd.dungeons[lev->dnum].depth_start + lev->dlevel - 1); } /* are "lev1" and "lev2" actually the same? */ @@ -1444,7 +1449,7 @@ Is_special(d_level *lev) { s_level *levtmp; - for (levtmp = gs.sp_levchn; levtmp; levtmp = levtmp->next) + for (levtmp = svs.sp_levchn; levtmp; levtmp = levtmp->next) if (on_level(lev, &levtmp->dlevel)) return levtmp; @@ -1460,7 +1465,7 @@ Is_branchlev(d_level *lev) { branch *curr; - for (curr = gb.branches; curr; curr = curr->next) { + for (curr = svb.branches; curr; curr = curr->next) { if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2)) return curr; } @@ -1471,14 +1476,14 @@ Is_branchlev(d_level *lev) boolean builds_up(d_level *lev) { - dungeon *dptr = &gd.dungeons[lev->dnum]; + dungeon *dptr = &svd.dungeons[lev->dnum]; branch *br; if (dptr->num_dunlevs > 1) return (boolean) (dptr->entry_lev == dptr->num_dunlevs); - /* else, single-level branch; find the branch connection that connects this + /* else, single-level branch; find branch connection that connects this * dungeon from a parent dungeon and determine whether it builds up from * that */ - for (br = gb.branches; br; br = br->next) { + for (br = svb.branches; br; br = br->next) { if (on_level(lev, &br->end2)) { return br->end1_up; } @@ -1583,20 +1588,20 @@ u_on_rndspot(int upflag) destination instead of its enclosing region. Note: up vs down doesn't matter in this case because both specify the same exclusion area. */ - place_lregion(gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy, + place_lregion(svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy, 0, 0, 0, 0, LR_DOWNTELE, (d_level *) 0); else if (up) - place_lregion(gu.updest.lx, gu.updest.ly, - gu.updest.hx, gu.updest.hy, - gu.updest.nlx, gu.updest.nly, - gu.updest.nhx, gu.updest.nhy, + place_lregion(svu.updest.lx, svu.updest.ly, + svu.updest.hx, svu.updest.hy, + svu.updest.nlx, svu.updest.nly, + svu.updest.nhx, svu.updest.nhy, LR_UPTELE, (d_level *) 0); else - place_lregion(gd.dndest.lx, gd.dndest.ly, - gd.dndest.hx, gd.dndest.hy, - gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy, + place_lregion(svd.dndest.lx, svd.dndest.ly, + svd.dndest.hx, svd.dndest.hy, + svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy, LR_DOWNTELE, (d_level *) 0); /* might have just left solid rock and unblocked levitation */ @@ -1606,13 +1611,13 @@ u_on_rndspot(int upflag) boolean Is_botlevel(d_level *lev) { - return (boolean) (lev->dlevel == gd.dungeons[lev->dnum].num_dunlevs); + return (boolean) (lev->dlevel == svd.dungeons[lev->dnum].num_dunlevs); } boolean Can_dig_down(d_level *lev) { - return (boolean) (!gl.level.flags.hardfloor + return (boolean) (!svl.level.flags.hardfloor && !Is_botlevel(lev) && !Invocation_lev(lev)); } @@ -1645,7 +1650,7 @@ Can_rise_up(coordxy x, coordxy y, d_level *lev) || (Is_wiz1_level(lev) && In_W_tower(x, y, lev))) return FALSE; return (boolean) (lev->dlevel > 1 - || (gd.dungeons[lev->dnum].entry_lev == 1 + || (svd.dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 && stway && stway->up)); } @@ -1771,10 +1776,10 @@ get_level(d_level *newlevel, int levnum) if (levnum <= 0) { /* can only currently happen in endgame */ levnum = u.uz.dlevel; - } else if (levnum > (gd.dungeons[dgn].depth_start - + gd.dungeons[dgn].num_dunlevs - 1)) { + } else if (levnum > (svd.dungeons[dgn].depth_start + + svd.dungeons[dgn].num_dunlevs - 1)) { /* beyond end of dungeon, jump to last level */ - levnum = gd.dungeons[dgn].num_dunlevs; + levnum = svd.dungeons[dgn].num_dunlevs; } else { /* The desired level is in this dungeon or a "higher" one. */ @@ -1782,7 +1787,7 @@ get_level(d_level *newlevel, int levnum) * Branch up the tree until we reach a dungeon that contains the * levnum. */ - if (levnum < gd.dungeons[dgn].depth_start) { + if (levnum < svd.dungeons[dgn].depth_start) { do { /* * Find the parent dungeon of this dungeon. @@ -1790,18 +1795,18 @@ get_level(d_level *newlevel, int levnum) * This assumes that end2 is always the "child" and it is * unique. */ - for (br = gb.branches; br; br = br->next) + for (br = svb.branches; br; br = br->next) if (br->end2.dnum == dgn) break; if (!br) panic("get_level: can't find parent dungeon"); dgn = br->end1.dnum; - } while (levnum < gd.dungeons[dgn].depth_start); + } while (levnum < svd.dungeons[dgn].depth_start); } /* We're within the same dungeon; calculate the level. */ - levnum = levnum - gd.dungeons[dgn].depth_start + 1; + levnum = levnum - svd.dungeons[dgn].depth_start + 1; } newlevel->dnum = dgn; @@ -1839,7 +1844,7 @@ dungeon_branch(const char *s) dnum = dname_to_dnum(s); /* Find the branch that connects to dungeon i's branch. */ - for (br = gb.branches; br; br = br->next) + for (br = svb.branches; br; br = br->next) if (br->end2.dnum == dnum) break; @@ -1888,24 +1893,24 @@ In_W_tower(coordxy x, coordxy y, d_level *lev) { if (!On_W_tower_level(lev)) return FALSE; - if (!gd.dndest.nlx) { + if (!svd.dndest.nlx) { impossible("No boundary for Wizard's Tower?"); return FALSE; } /* * Both of the exclusion regions for arriving via level teleport * (from above or below) define the tower's boundary. - * assert( gu.updest.nIJ == gd.dndest.nIJ for I={l|h},J={x|y} ); + * assert( svu.updest.nIJ == svd.dndest.nIJ for I={l|h},J={x|y} ); */ - return (boolean) within_bounded_area(x, y, gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy); + return (boolean) within_bounded_area(x, y, svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy); } /* are you in one of the Hell levels? */ boolean In_hell(d_level *lev) { - return (boolean) (gd.dungeons[lev->dnum].flags.hellish); + return (boolean) (svd.dungeons[lev->dnum].flags.hellish); } /* sets *lev to be the gateway to Gehennom... */ @@ -1969,9 +1974,9 @@ induced_align(int pct) if (rn2(100) < pct) return lev->flags.align; - if (gd.dungeons[u.uz.dnum].flags.align) + if (svd.dungeons[u.uz.dnum].flags.align) if (rn2(100) < pct) - return gd.dungeons[u.uz.dnum].flags.align; + return svd.dungeons[u.uz.dnum].flags.align; al = rn2(3) - 1; return Align2amask(al); @@ -1981,7 +1986,7 @@ boolean Invocation_lev(d_level *lev) { return (boolean) (In_hell(lev) - && lev->dlevel == gd.dungeons[lev->dnum].num_dunlevs - 1); + && lev->dlevel == svd.dungeons[lev->dnum].num_dunlevs - 1); } /* use instead of depth() wherever a degree of difficulty is made @@ -2004,7 +2009,7 @@ level_difficulty(void) they were easier; adjust for the extra effort involved in going down to the entrance and then up to the location */ if (builds_up(&u.uz)) - res += 2 * (gd.dungeons[u.uz.dnum].entry_lev - u.uz.dlevel + 1); + res += 2 * (svd.dungeons[u.uz.dnum].entry_lev - u.uz.dlevel + 1); /* * 'Proof' by example: suppose the entrance to sokoban is * on dungeon level 9, leading up to bottom sokoban level @@ -2104,7 +2109,7 @@ lev_by_name(const char *nam) /* either wizard mode or else seen and not forgotten; note: used to be '(flags & (FORGOTTEN|VISITED)) == VISITED' back when amnesia could cause levels to be forgotten */ - && (wizard || (gl.level_info[idx].flags & (VISITED)) == VISITED)) { + && (wizard || (svl.level_info[idx].flags & VISITED) == VISITED)) { lev = depth(&dlev); } } else { /* not a specific level; try branch names */ @@ -2116,9 +2121,10 @@ lev_by_name(const char *nam) if (idx >= 0) { idxtoo = (idx >> 8) & 0x00FF; idx &= 0x00FF; - /* either wizard mode, or else _both_ sides of branch seen */ - if (wizard || (((gl.level_info[idx].flags & (VISITED)) == VISITED) - && ((gl.level_info[idxtoo].flags & (VISITED)) + /* either wizard mode, or else _both_ sides of branch seen; */ + /* (flags & VISITED)==VISITED: see comment about amnesia above */ + if (wizard || (((svl.level_info[idx].flags & VISITED) == VISITED) + && ((svl.level_info[idxtoo].flags & VISITED) == VISITED))) { if (ledger_to_dnum(idxtoo) == u.uz.dnum) idx = idxtoo; @@ -2138,13 +2144,13 @@ staticfn boolean unplaced_floater(struct dungeon *dptr) { branch *br; - int idx = (int) (dptr - gd.dungeons); + int idx = (int) (dptr - svd.dungeons); /* if other floating branches are added, this will need to change */ if (idx != knox_level.dnum) return FALSE; - for (br = gb.branches; br; br = br->next) - if (br->end1.dnum == gn.n_dgns && br->end2.dnum == idx) + for (br = svb.branches; br; br = br->next) + if (br->end1.dnum == svn.n_dgns && br->end2.dnum == idx) return TRUE; return FALSE; } @@ -2232,13 +2238,13 @@ print_branch( char buf[BUFSZ]; /* This assumes that end1 is the "parent". */ - for (br = gb.branches; br; br = br->next) { + for (br = svb.branches; br; br = br->next) { if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel && br->end1.dlevel <= upper_bound) { Sprintf(buf, "%c %s to %s: %d", bymenu ? chr_u_on_lvl(&br->end1) : ' ', br_string(br->type), - gd.dungeons[br->end2.dnum].dname, depth(&br->end1)); + svd.dungeons[br->end2.dnum].dname, depth(&br->end1)); if (bymenu) tport_menu(win, buf, lchoices_p, &br->end1, unreachable_level(&br->end1, FALSE)); @@ -2268,7 +2274,7 @@ print_dungeon(boolean bymenu, schar *rlev, xint16 *rdgn) lchoices.menuletter = 'a'; } - for (i = 0, dptr = gd.dungeons; i < gn.n_dgns; i++, dptr++) { + for (i = 0, dptr = svd.dungeons; i < svn.n_dgns; i++, dptr++) { if (bymenu && In_endgame(&u.uz) && i != astral_level.dnum) continue; unplaced = unplaced_floater(dptr); @@ -2299,7 +2305,7 @@ print_dungeon(boolean bymenu, schar *rlev, xint16 *rdgn) * Circle through the special levels to find levels that are in * this dungeon. */ - for (slev = gs.sp_levchn, last_level = 0; slev; slev = slev->next) { + for (slev = svs.sp_levchn, last_level = 0; slev; slev = slev->next) { if (slev->dlevel.dnum != i) continue; @@ -2311,7 +2317,7 @@ print_dungeon(boolean bymenu, schar *rlev, xint16 *rdgn) chr_u_on_lvl(&slev->dlevel), slev->proto, depth(&slev->dlevel)); if (Is_stronghold(&slev->dlevel)) - Sprintf(eos(buf), " (tune %s)", gt.tune); + Sprintf(eos(buf), " (tune %s)", svt.tune); if (bymenu) tport_menu(win, buf, &lchoices, &slev->dlevel, unreachable_level(&slev->dlevel, unplaced)); @@ -2345,15 +2351,15 @@ print_dungeon(boolean bymenu, schar *rlev, xint16 *rdgn) } /* Print out floating branches (if any). */ - for (first = TRUE, br = gb.branches; br; br = br->next) { - if (br->end1.dnum == gn.n_dgns) { + for (first = TRUE, br = svb.branches; br; br = br->next) { + if (br->end1.dnum == svn.n_dgns) { if (first) { putstr(win, 0, ""); putstr(win, 0, "Floating branches"); first = FALSE; } Sprintf(buf, " %s to %s", br_string(br->type), - gd.dungeons[br->end2.dnum].dname); + svd.dungeons[br->end2.dnum].dname); putstr(win, 0, buf); } } @@ -2362,7 +2368,7 @@ print_dungeon(boolean bymenu, schar *rlev, xint16 *rdgn) if (Invocation_lev(&u.uz)) { putstr(win, 0, ""); Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)", - gi.inv_pos.x, gi.inv_pos.y, u.ux, u.uy); + svi.inv_pos.x, svi.inv_pos.y, u.ux, u.uy); putstr(win, 0, buf); } else { struct trap *trap; @@ -2416,7 +2422,7 @@ recbranch_mapseen(d_level *source, d_level *dest) return; /* we only care about forward branches */ - for (br = gb.branches; br; br = br->next) { + for (br = svb.branches; br; br = br->next) { if (on_level(source, &br->end1) && on_level(dest, &br->end2)) break; if (on_level(source, &br->end2) && on_level(dest, &br->end1)) @@ -2539,7 +2545,7 @@ donamelevel(void) void free_exclusions(void) { - struct exclusion_zone *ez = ge.exclusion_zones; + struct exclusion_zone *ez = sve.exclusion_zones; while (ez) { struct exclusion_zone *nxtez = ez->next; @@ -2547,7 +2553,7 @@ free_exclusions(void) free(ez); ez = nxtez; } - ge.exclusion_zones = (struct exclusion_zone *) 0; + sve.exclusion_zones = (struct exclusion_zone *) 0; } void @@ -2556,13 +2562,13 @@ save_exclusions(NHFILE *nhfp) struct exclusion_zone *ez; int nez; - for (nez = 0, ez = ge.exclusion_zones; ez; ez = ez->next, ++nez) + for (nez = 0, ez = sve.exclusion_zones; ez; ez = ez->next, ++nez) ; if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &nez, sizeof nez); - for (ez = ge.exclusion_zones; ez; ez = ez->next) { + for (ez = sve.exclusion_zones; ez; ez = ez->next) { if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &ez->zonetype, sizeof ez->zonetype); @@ -2586,14 +2592,15 @@ load_exclusions(NHFILE *nhfp) while (nez-- > 0) { ez = (struct exclusion_zone *) alloc(sizeof *ez); if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &ez->zonetype, sizeof ez->zonetype); + mread(nhfp->fd, (genericptr_t) &ez->zonetype, + sizeof ez->zonetype); mread(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx); mread(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly); mread(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx); mread(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy); } - ez->next = ge.exclusion_zones; - ge.exclusion_zones = ez; + ez->next = sve.exclusion_zones; + sve.exclusion_zones = ez; } } @@ -2603,7 +2610,7 @@ find_mapseen(d_level *lev) { mapseen *mptr; - for (mptr = gm.mapseenchn; mptr; mptr = mptr->next) + for (mptr = svm.mapseenchn; mptr; mptr = mptr->next) if (on_level(&(mptr->lev), lev)) break; @@ -2615,7 +2622,7 @@ find_mapseen_by_str(const char *s) { mapseen *mptr; - for (mptr = gm.mapseenchn; mptr; mptr = mptr->next) + for (mptr = svm.mapseenchn; mptr; mptr = mptr->next) if (mptr->custom && !strcmpi(s, mptr->custom)) break; @@ -2629,8 +2636,8 @@ rm_mapseen(int ledger_num) mapseen *mptr, *mprev = (mapseen *) 0; struct cemetery *bp, *bpnext; - for (mptr = gm.mapseenchn; mptr; mprev = mptr, mptr = mptr->next) - if (gd.dungeons[mptr->lev.dnum].ledger_start + mptr->lev.dlevel + for (mptr = svm.mapseenchn; mptr; mprev = mptr, mptr = mptr->next) + if (svd.dungeons[mptr->lev.dnum].ledger_start + mptr->lev.dlevel == ledger_num) break; @@ -2651,7 +2658,7 @@ rm_mapseen(int ledger_num) mprev->next = mptr->next; free(mptr); } else { - gm.mapseenchn = mptr->next; + svm.mapseenchn = mptr->next; free(mptr); } } @@ -2662,7 +2669,7 @@ save_mapseen(NHFILE *nhfp, mapseen *mptr) branch *curr; int brindx; - for (brindx = 0, curr = gb.branches; curr; curr = curr->next, ++brindx) + for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx) if (curr == mptr->br) break; if (nhfp->structlevel) @@ -2698,7 +2705,7 @@ load_mapseen(NHFILE *nhfp) if (nhfp->structlevel) mread(nhfp->fd, (genericptr_t) &branchnum, sizeof branchnum); - for (brindx = 0, curr = gb.branches; curr; curr = curr->next, ++brindx) + for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx) if (brindx == branchnum) break; load->br = curr; @@ -2743,7 +2750,7 @@ overview_stats( mapseen *mptr = find_mapseen(&u.uz); ocount = bcount = acount = osize = bsize = asize = 0L; - for (mptr = gm.mapseenchn; mptr; mptr = mptr->next) { + for (mptr = svm.mapseenchn; mptr; mptr = mptr->next) { ++ocount; osize += (long) sizeof *mptr; for (ce = mptr->final_resting_place; ce; ce = ce->next) { @@ -2786,7 +2793,7 @@ remdun_mapseen(int dnum) { mapseen *mptr, **mptraddr; - mptraddr = &gm.mapseenchn; + mptraddr = &svm.mapseenchn; while ((mptr = *mptraddr) != 0) { if (mptr->lev.dnum == dnum) { #if 1 /* use this... */ @@ -2819,22 +2826,24 @@ init_mapseen(d_level *lev) explicitly initialize pointers to null */ init->next = 0, init->br = 0, init->custom = 0; init->final_resting_place = 0; - /* gl.lastseentyp[][] is reused for each level, so get rid of + /* svl.lastseentyp[][] is reused for each level, so get rid of previous level's data */ - (void) memset((genericptr_t) gl.lastseentyp, 0, sizeof gl.lastseentyp); + (void) memset((genericptr_t) svl.lastseentyp, 0, sizeof svl.lastseentyp); init->lev.dnum = lev->dnum; init->lev.dlevel = lev->dlevel; /* walk until we get to the place where we should insert init */ - for (mptr = gm.mapseenchn, prev = 0; mptr; prev = mptr, mptr = mptr->next) + for (mptr = svm.mapseenchn, prev = 0; mptr; + prev = mptr, mptr = mptr->next) { if (mptr->lev.dnum > init->lev.dnum || (mptr->lev.dnum == init->lev.dnum && mptr->lev.dlevel > init->lev.dlevel)) break; + } if (!prev) { - init->next = gm.mapseenchn; - gm.mapseenchn = init; + init->next = svm.mapseenchn; + svm.mapseenchn = init; } else { mptr = prev->next; prev->next = init; @@ -2891,7 +2900,7 @@ interest_mapseen(mapseen *mptr) && (mptr->flags.knownbones || wizard)) || mptr->custom || mptr->br || (mptr->lev.dlevel - == gd.dungeons[mptr->lev.dnum].dunlev_ureached)); + == svd.dungeons[mptr->lev.dnum].dunlev_ureached)); } /* update the lastseentyp at x,y */ @@ -2906,7 +2915,7 @@ update_lastseentyp(coordxy x, coordxy y) if ((mtmp = m_at(x, y)) != 0 && M_AP_TYPE(mtmp) == M_AP_FURNITURE && canseemon(mtmp)) ltyp = cmap_to_type(mtmp->mappearance); - gl.lastseentyp[x][y] = ltyp; + svl.lastseentyp[x][y] = ltyp; } /* for some cases where deferred update needs to be done immediately; @@ -2915,7 +2924,7 @@ int update_mapseen_for(coordxy x, coordxy y) { recalc_mapseen(); /* whole level */ - return gl.lastseentyp[x][y]; + return svl.lastseentyp[x][y]; } /* count mapseen feature from lastseentyp at x,y */ @@ -2927,7 +2936,7 @@ count_feat_lastseentyp( int count; unsigned atmp; - switch (gl.lastseentyp[x][y]) { + switch (svl.lastseentyp[x][y]) { #if 0 /* levels that have these tend of have a lot of them */ /* * FIXME? due to theme rooms, lots of levels have an increased @@ -3069,7 +3078,7 @@ recalc_mapseen(void) if (mptr->flags.unreachable) { mptr->flags.unreachable = 0; /* reached it; Eye of the Aethiopica? */ if (In_quest(&u.uz)) { - mapseen *mptrtmp = gm.mapseenchn; + mapseen *mptrtmp = svm.mapseenchn; /* when quest was unreachable due to ejection and portal removal, getting back to it via arti-invoke should revive annotation @@ -3098,9 +3107,9 @@ recalc_mapseen(void) && u.uevent.qcalled && !(u.uevent.qcompleted || u.uevent.qexpelled - || gq.quest_status.leader_is_dead)); + || svq.quest_status.leader_is_dead)); mptr->flags.questing = (on_level(&u.uz, &qstart_level) - && gq.quest_status.got_quest); + && svq.quest_status.got_quest); /* flags.msanctum, .valley, and .vibrating_square handled below */ /* track rooms the hero is in */ @@ -3108,9 +3117,9 @@ recalc_mapseen(void) ridx = (unsigned) uroom - ROOMOFFSET; mptr->msrooms[ridx].seen = 1; mptr->msrooms[ridx].untended = - (gr.rooms[ridx].rtype >= SHOPBASE) + (svr.rooms[ridx].rtype >= SHOPBASE) ? (!(mtmp = shop_keeper(uroom)) || !inhishop(mtmp)) - : (gr.rooms[ridx].rtype == TEMPLE) + : (svr.rooms[ridx].rtype == TEMPLE) ? (!(mtmp = findpriest(uroom)) || !inhistemple(mtmp)) : 0; } @@ -3120,28 +3129,28 @@ recalc_mapseen(void) */ for (i = 0; i < SIZE(mptr->msrooms); ++i) { if (mptr->msrooms[i].seen) { - if (gr.rooms[i].rtype >= SHOPBASE) { + if (svr.rooms[i].rtype >= SHOPBASE) { if (mptr->msrooms[i].untended) mptr->feat.shoptype = SHOPBASE - 1; else if (!mptr->feat.nshop) - mptr->feat.shoptype = gr.rooms[i].rtype; - else if (mptr->feat.shoptype != (unsigned) gr.rooms[i].rtype) + mptr->feat.shoptype = svr.rooms[i].rtype; + else if (mptr->feat.shoptype != (unsigned) svr.rooms[i].rtype) mptr->feat.shoptype = 0; count = mptr->feat.nshop + 1; if (count <= 3) mptr->feat.nshop = count; - } else if (gr.rooms[i].rtype == TEMPLE) { + } else if (svr.rooms[i].rtype == TEMPLE) { /* altar and temple alignment handled below */ count = mptr->feat.ntemple + 1; if (count <= 3) mptr->feat.ntemple = count; - } else if (gr.rooms[i].orig_rtype == DELPHI) { + } else if (svr.rooms[i].orig_rtype == DELPHI) { mptr->flags.oracle = 1; } } } - /* Update gl.lastseentyp with typ if and only if it is in sight or the + /* Update svl.lastseentyp with typ if and only if it is in sight or the * hero can feel it on their current location (i.e. not levitating). * This *should* give the "last known typ" for each dungeon location. * (At the very least, it's a better assumption than determining what @@ -3152,7 +3161,7 @@ recalc_mapseen(void) * we could track "features" and then update them all here, and keep * track of when new features are created or destroyed, but this * seemed the most elegant, despite adding more data to struct rm. - * [3.6.0: we're using gl.lastseentyp[][] rather than level.locations + * [3.6.0: we're using svl.lastseentyp[][] rather than level.locations * to track the features seen.] * * Although no current windowing systems (can) do this, this would add @@ -3208,11 +3217,11 @@ recalc_mapseen(void) || !oth_mptr->flags.msanctum); } - if (gl.level.bonesinfo && !mptr->final_resting_place) { + if (svl.level.bonesinfo && !mptr->final_resting_place) { /* clone the bonesinfo so we aren't dependent upon this level being in memory */ bonesaddr = &mptr->final_resting_place; - bp = gl.level.bonesinfo; + bp = svl.level.bonesinfo; do { *bonesaddr = (struct cemetery *) alloc(sizeof **bonesaddr); **bonesaddr = *bp; @@ -3225,14 +3234,15 @@ recalc_mapseen(void) guarantee of either a grave or a ghost, so we go by whether the current hero has seen the map location where each old one died */ for (bp = mptr->final_resting_place; bp; bp = bp->next) - if (gl.lastseentyp[bp->frpx][bp->frpy]) { + if (svl.lastseentyp[bp->frpx][bp->frpy]) { bp->bonesknown = TRUE; mptr->flags.knownbones = 1; } } /*ARGUSED*/ -/* valley and sanctum levels get automatic annotation once temple is entered */ +/* valley and sanctum levels get automatic annotation once their temple + is entered */ void mapseen_temple( struct monst *priest UNUSED) /* not used; might be useful someday */ @@ -3321,7 +3331,7 @@ traverse_mapseenchn( mapseen *mptr; boolean showheader; - for (mptr = gm.mapseenchn; mptr; mptr = mptr->next) { + for (mptr = svm.mapseenchn; mptr; mptr = mptr->next) { if (viewendgame ^ In_endgame(&mptr->lev)) continue; @@ -3437,7 +3447,7 @@ tunesuffix( char tmp[BUFSZ]; if (u.uevent.uheard_tune == 2) - Sprintf(tmp, "notes \"%s\"", gt.tune); + Sprintf(tmp, "notes \"%s\"", svt.tune); else Strcpy(tmp, "5-note tune"); Snprintf(outbuf, bsz, " (play %s to open or close drawbridge)", tmp); @@ -3503,22 +3513,22 @@ print_mapseen( if (dnum == quest_dnum || dnum == knox_level.dnum) depthstart = 1; else - depthstart = gd.dungeons[dnum].depth_start; + depthstart = svd.dungeons[dnum].depth_start; if (printdun) { - if (gd.dungeons[dnum].dunlev_ureached == gd.dungeons[dnum].entry_lev + if (svd.dungeons[dnum].dunlev_ureached == svd.dungeons[dnum].entry_lev /* suppress the negative numbers in the endgame */ || In_endgame(&mptr->lev)) - Sprintf(buf, "%s:", gd.dungeons[dnum].dname); + Sprintf(buf, "%s:", svd.dungeons[dnum].dname); else if (builds_up(&mptr->lev)) Sprintf(buf, "%s: levels %d up to %d", - gd.dungeons[dnum].dname, - depthstart + gd.dungeons[dnum].entry_lev - 1, - depthstart + gd.dungeons[dnum].dunlev_ureached - 1); + svd.dungeons[dnum].dname, + depthstart + svd.dungeons[dnum].entry_lev - 1, + depthstart + svd.dungeons[dnum].dunlev_ureached - 1); else Sprintf(buf, "%s: levels %d to %d", - gd.dungeons[dnum].dname, depthstart, - depthstart + gd.dungeons[dnum].dunlev_ureached - 1); + svd.dungeons[dnum].dname, depthstart, + depthstart + svd.dungeons[dnum].dunlev_ureached - 1); add_menu_heading(win, buf); } @@ -3650,7 +3660,7 @@ print_mapseen( /* print out branches */ if (mptr->br) { Sprintf(buf, "%s%s to %s", PREFIX, br_string2(mptr->br), - gd.dungeons[mptr->br->end2.dnum].dname); + svd.dungeons[mptr->br->end2.dnum].dname); /* Since mapseen objects are printed out in increasing order * of dlevel, clarify which level this branch is going to diff --git a/src/eat.c b/src/eat.c index 8868f89d9..9f2498b77 100644 --- a/src/eat.c +++ b/src/eat.c @@ -261,10 +261,10 @@ choke(struct obj *food) return; } You("stuff yourself and then vomit voluminously."); - morehungry(Hunger ? (u.uhunger - 60) : 1000); /* you just got *very* sick! */ + morehungry(Hunger ? (u.uhunger - 60) : 1000); /* just got very sick! */ vomit(); } else { - gk.killer.format = KILLED_BY_AN; + svk.killer.format = KILLED_BY_AN; /* * Note all "killer"s below read "Choked on %s" on the * high score list & tombstone. So plan accordingly. @@ -272,14 +272,14 @@ choke(struct obj *food) if (food) { You("choke over your %s.", foodword(food)); if (food->oclass == COIN_CLASS) { - Strcpy(gk.killer.name, "very rich meal"); + Strcpy(svk.killer.name, "very rich meal"); } else { - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, killer_xname(food)); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, killer_xname(food)); } } else { You("choke over it."); - Strcpy(gk.killer.name, "quick snack"); + Strcpy(svk.killer.name, "quick snack"); } You("die..."); done(CHOKING); @@ -290,7 +290,7 @@ choke(struct obj *food) staticfn void recalc_wt(void) { - struct obj *piece = gc.context.victual.piece; + struct obj *piece = svc.context.victual.piece; if (!piece) { impossible("recalc_wt without piece"); @@ -298,7 +298,7 @@ recalc_wt(void) } debugpline1("Old weight = %d", piece->owt); debugpline2("Used time = %d, Req'd time = %d", - gc.context.victual.usedtime, gc.context.victual.reqtime); + svc.context.victual.usedtime, svc.context.victual.reqtime); piece->owt = weight(piece); debugpline1("New weight = %d", piece->owt); } @@ -310,9 +310,9 @@ reset_eat(void) /* we only set a flag here - the actual reset process is done after * the round is spent eating. */ - if (gc.context.victual.eating && !gc.context.victual.doreset) { + if (svc.context.victual.eating && !svc.context.victual.doreset) { debugpline0("reset_eat..."); - gc.context.victual.doreset = 1; + svc.context.victual.doreset = 1; } return; } @@ -336,9 +336,9 @@ obj_nutrition(struct obj *otmp) staticfn int adj_victual_nutrition(void) { - int otyp = gc.context.victual.piece->otyp; + int otyp = svc.context.victual.piece->otyp; /* note: adj_victual_nutrition() is only called when 'nmod' is negative */ - int nut = -gc.context.victual.nmod; /* convert 'nmod' to positive */ + int nut = -svc.context.victual.nmod; /* convert 'nmod' to positive */ assert(nut > 0); if (otyp == LEMBAS_WAFER) { @@ -394,8 +394,8 @@ touchfood(struct obj *otmp) void food_disappears(struct obj *obj) { - if (obj == gc.context.victual.piece) - gc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ + if (obj == svc.context.victual.piece) + svc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ if (obj->timed) obj_stop_timers(obj); @@ -407,13 +407,13 @@ food_disappears(struct obj *obj) void food_substitution(struct obj *old_obj, struct obj *new_obj) { - if (old_obj == gc.context.victual.piece) { - gc.context.victual.piece = new_obj; - gc.context.victual.o_id = new_obj->o_id; + if (old_obj == svc.context.victual.piece) { + svc.context.victual.piece = new_obj; + svc.context.victual.o_id = new_obj->o_id; } - if (old_obj == gc.context.tin.tin) { - gc.context.tin.tin = new_obj; - gc.context.tin.o_id = new_obj->o_id; + if (old_obj == svc.context.tin.tin) { + svc.context.tin.tin = new_obj; + svc.context.tin.o_id = new_obj->o_id; } } @@ -421,20 +421,20 @@ staticfn void do_reset_eat(void) { debugpline0("do_reset_eat..."); - if (gc.context.victual.piece) { + if (svc.context.victual.piece) { struct obj *otmp; - gc.context.victual.o_id = 0; - otmp = touchfood(gc.context.victual.piece); - gc.context.victual.piece = otmp; + svc.context.victual.o_id = 0; + otmp = touchfood(svc.context.victual.piece); + svc.context.victual.piece = otmp; if (otmp) { - gc.context.victual.o_id = otmp->o_id; + svc.context.victual.o_id = otmp->o_id; recalc_wt(); } } - gc.context.victual.fullwarn - = gc.context.victual.eating - = gc.context.victual.doreset + svc.context.victual.fullwarn + = svc.context.victual.eating + = svc.context.victual.doreset = 0; /* Do not set canchoke to FALSE; if we continue eating the same object * we need to know if canchoke was set when they started eating it the @@ -477,7 +477,7 @@ eating_dangerous_corpse(int res) int mnum; if (go.occupation == eatfood - && (food = gc.context.victual.piece) != 0 + && (food = svc.context.victual.piece) != 0 && food->otyp == CORPSE && (mnum = food->corpsenm) >= LOW_PM && (carried(food) || obj_here(food, u.ux, u.uy))) { @@ -517,7 +517,7 @@ maybe_extend_timed_resist(int prop) staticfn int eatfood(void) { - struct obj *food = gc.context.victual.piece; + struct obj *food = svc.context.victual.piece; if (food && !carried(food) && !obj_here(food, u.ux, u.uy)) food = 0; @@ -526,10 +526,10 @@ eatfood(void) do_reset_eat(); return 0; } - if (!gc.context.victual.eating) + if (!svc.context.victual.eating) return 0; - if (++gc.context.victual.usedtime <= gc.context.victual.reqtime) { + if (++svc.context.victual.usedtime <= svc.context.victual.reqtime) { if (bite()) return 0; return 1; /* still busy */ @@ -542,7 +542,7 @@ eatfood(void) staticfn void done_eating(boolean message) { - struct obj *piece = gc.context.victual.piece; + struct obj *piece = svc.context.victual.piece; piece->in_use = TRUE; go.occupation = 0; /* do this early, so newuhs() knows we're done */ @@ -568,7 +568,7 @@ done_eating(boolean message) else useupf(piece, 1L); - gc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ + svc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ } void @@ -660,9 +660,9 @@ eat_brains( return M_ATTK_MISS; } else if (is_rider(pd)) { pline("Ingesting that is fatal."); - Sprintf(gk.killer.name, "unwisely ate the brain of %s", + Sprintf(svk.killer.name, "unwisely ate the brain of %s", pmname(pd, Mgender(mdef))); - gk.killer.format = NO_KILLER_PREFIX; + svk.killer.format = NO_KILLER_PREFIX; done(DIED); /* life-saving needed to reach here */ exercise(A_WIS, FALSE); @@ -692,8 +692,8 @@ eat_brains( static NEARDATA const char brainlessness[] = "brainlessness"; if (Lifesaved) { - Strcpy(gk.killer.name, brainlessness); - gk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, brainlessness); + svk.killer.format = KILLED_BY; done(DIED); /* amulet of life saving has now been used up */ pline("Unfortunately your brain is still gone."); @@ -703,8 +703,8 @@ eat_brains( } else { Your("last thought fades away."); } - Strcpy(gk.killer.name, brainlessness); - gk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, brainlessness); + svk.killer.format = KILLED_BY; done(DIED); /* can only get here when in wizard or explore mode and user has explicitly chosen not to die; arbitrarily boost intelligence */ @@ -756,9 +756,9 @@ maybe_cannibal(int pm, boolean allowmsg) /* when poly'd into a mind flayer, multiple tentacle hits in one turn cause multiple digestion checks to occur; avoid giving multiple luck penalties for the same attack */ - if (gm.moves == ate_brains) + if (svm.moves == ate_brains) return FALSE; - ate_brains = gm.moves; /* ate_anything, not just brains... */ + ate_brains = svm.moves; /* ate_anything, not just brains... */ if (!CANNIBAL_ALLOWED() /* non-cannibalistic heroes shouldn't eat own species ever @@ -788,13 +788,13 @@ cprefx(int pm) if (!Stone_resistance && !(poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM))) { - Sprintf(gk.killer.name, "tasting %s meat", + Sprintf(svk.killer.name, "tasting %s meat", mons[pm].pmnames[NEUTRAL]); - gk.killer.format = KILLED_BY; + svk.killer.format = KILLED_BY; You("turn to stone."); done(STONING); - if (gc.context.victual.piece) - gc.context.victual.eating = 0; + if (svc.context.victual.piece) + svc.context.victual.eating = 0; return; /* lifesaved */ } } @@ -821,9 +821,9 @@ cprefx(int pm) case PM_PESTILENCE: case PM_FAMINE: { pline("Eating that is instantly fatal."); - Sprintf(gk.killer.name, "unwisely ate the body of %s", + Sprintf(svk.killer.name, "unwisely ate the body of %s", mons[pm].pmnames[NEUTRAL]); - gk.killer.format = NO_KILLER_PREFIX; + svk.killer.format = NO_KILLER_PREFIX; done(DIED); /* life-saving needed to reach here */ exercise(A_WIS, FALSE); @@ -831,10 +831,10 @@ cprefx(int pm) 3.7: this used to assume that such tins were impossible but they can be wished for in wizard mode; they can't make it to normal play though because bones creation empties them */ - if (gc.context.victual.piece /* Null for tins */ - && gc.context.victual.piece->otyp == CORPSE /* paranoia */ - && revive_corpse(gc.context.victual.piece)) - gc.context.victual = zero_victual; /* victual.piece=0, .o_id=0 */ + if (svc.context.victual.piece /* Null for tins */ + && svc.context.victual.piece->otyp == CORPSE /* paranoia */ + && revive_corpse(svc.context.victual.piece)) + svc.context.victual = zero_victual; /* victual.piece=0, .o_id=0 */ return; } case PM_GREEN_SLIME: @@ -1177,13 +1177,14 @@ cpostfx(int pm) tmp += 20; if (gy.youmonst.data->mlet != S_MIMIC && !Unchanging) { char buf[BUFSZ]; + const char *tempshape = !Hallucination ? "a pile of gold" + : "an orange"; if (!u.uconduct.polyselfs++) /* you're changing form */ livelog_printf(LL_CONDUCT, "changed form for the first time by mimicking %s", - Hallucination ? "an orange" : "a pile of gold"); - You_cant("resist the temptation to mimic %s.", - Hallucination ? "an orange" : "a pile of gold"); + tempshape); + You_cant("resist the temptation to mimic %s.", tempshape); /* A pile of gold can't ride. */ if (u.usteed) dismount_steed(DISMOUNT_FELL); @@ -1357,18 +1358,18 @@ violated_vegetarian(void) return; } -/* common code to check and possibly charge for 1 gc.context.tin.tin, - * will split() gc.context.tin.tin if necessary */ +/* common code to check and possibly charge for 1 svc.context.tin.tin, + * will split() svc.context.tin.tin if necessary */ staticfn struct obj * costly_tin(int alter_type) /* COST_xxx */ { - struct obj *tin = gc.context.tin.tin; + struct obj *tin = svc.context.tin.tin; if (carried(tin) ? tin->unpaid : (costly_spot(tin->ox, tin->oy) && !tin->no_charge)) { if (tin->quan > 1L) { - tin = gc.context.tin.tin = splitobj(tin, 1L); - gc.context.tin.o_id = tin->o_id; + tin = svc.context.tin.tin = splitobj(tin, 1L); + svc.context.tin.o_id = tin->o_id; } costly_alteration(tin, alter_type); } @@ -1490,7 +1491,7 @@ consume_tin(const char *mesg) { const char *what; int which, mnum, r; - struct obj *tin = gc.context.tin.tin; + struct obj *tin = svc.context.tin.tin; r = tin_variety(tin, FALSE); if (tin->otrapped || (tin->cursed && r != HOMEMADE_TIN && !rn2(8))) { @@ -1540,7 +1541,7 @@ consume_tin(const char *mesg) } /* in case stop_occupation() was called on previous meal */ - gc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ + svc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ You("consume %s %s.", tintxts[r].txt, mons[mnum].pmnames[NEUTRAL]); @@ -1622,8 +1623,8 @@ consume_tin(const char *mesg) useup(tin); else useupf(tin, 1L); - gc.context.tin.tin = (struct obj *) 0; - gc.context.tin.o_id = 0; + svc.context.tin.tin = (struct obj *) 0; + svc.context.tin.o_id = 0; } /* called during each move whilst opening a tin */ @@ -1631,15 +1632,15 @@ staticfn int opentin(void) { /* perhaps it was stolen (although that should cause interruption) */ - if (!carried(gc.context.tin.tin) - && (!obj_here(gc.context.tin.tin, u.ux, u.uy) + if (!carried(svc.context.tin.tin) + && (!obj_here(svc.context.tin.tin, u.ux, u.uy) || !can_reach_floor(TRUE))) return 0; /* %% probably we should use tinoid */ - if (gc.context.tin.usedtime++ >= 50) { + if (svc.context.tin.usedtime++ >= 50) { You("give up your attempt to open the tin."); return 0; } - if (gc.context.tin.usedtime < gc.context.tin.reqtime) + if (svc.context.tin.usedtime < svc.context.tin.reqtime) return 1; /* still busy */ consume_tin("You succeed in opening the tin."); @@ -1665,7 +1666,8 @@ start_tin(struct obj *otmp) access); 1 turn delay case is non-deterministic: getting interrupted and retrying might yield another 1 turn delay or might open immediately on 2nd (or 3rd, 4th, ...) try */ - tmp = (uwep && uwep->blessed && uwep->otyp == TIN_OPENER) ? 0 : rn2(2); + tmp = (uwep && uwep->blessed && uwep->otyp == TIN_OPENER) ? 0 + : rn2(2); if (!tmp) mesg = "The tin opens like magic!"; else @@ -1711,13 +1713,13 @@ start_tin(struct obj *otmp) tmp = rn1(1 + 500 / ((int) (ACURR(A_DEX) + ACURRSTR)), 10); } - gc.context.tin.tin = otmp; - gc.context.tin.o_id = otmp->o_id; + svc.context.tin.tin = otmp; + svc.context.tin.o_id = otmp->o_id; if (!tmp) { consume_tin(mesg); /* begin immediately */ } else { - gc.context.tin.reqtime = tmp; - gc.context.tin.usedtime = 0; + svc.context.tin.reqtime = tmp; + svc.context.tin.usedtime = 0; set_occupation(opentin, "opening the tin", 0); } return; @@ -1811,7 +1813,7 @@ eatcorpse(struct obj *otmp) if (!nonrotting_corpse(mnum)) { long age = peek_at_iced_corpse_age(otmp); - rotted = (gm.moves - age) / (10L + rn2(20)); + rotted = (svm.moves - age) / (10L + rn2(20)); if (otmp->cursed) rotted += 2L; else if (otmp->blessed) @@ -1870,7 +1872,7 @@ eatcorpse(struct obj *otmp) } /* delay is weight dependent */ - gc.context.victual.reqtime + svc.context.victual.reqtime = 3 + ((!glob ? mons[mnum].cwt : otmp->owt) >> 6); if (!tp && !nonrotting_corpse(mnum) && (otmp->orotten || !rn2(7))) { @@ -1956,17 +1958,17 @@ start_eating(struct obj *otmp, boolean already_partly_eaten) several such so we don't need to copy the first result before calling it a second time */ fmt_ptr((genericptr_t) otmp), - fmt_ptr((genericptr_t) gc.context.victual.piece)); - debugpline1("reqtime = %d", gc.context.victual.reqtime); + fmt_ptr((genericptr_t) svc.context.victual.piece)); + debugpline1("reqtime = %d", svc.context.victual.reqtime); debugpline1("(original reqtime = %d)", objects[otmp->otyp].oc_delay); - debugpline1("nmod = %d", gc.context.victual.nmod); + debugpline1("nmod = %d", svc.context.victual.nmod); debugpline1("oeaten = %d", otmp->oeaten); - gc.context.victual.fullwarn = gc.context.victual.doreset = 0; - gc.context.victual.eating = 1; + svc.context.victual.fullwarn = svc.context.victual.doreset = 0; + svc.context.victual.eating = 1; if (otmp->otyp == CORPSE || otmp->globby) { - cprefx(gc.context.victual.piece->corpsenm); - if (!gc.context.victual.piece || !gc.context.victual.eating) { + cprefx(svc.context.victual.piece->corpsenm); + if (!svc.context.victual.piece || !svc.context.victual.eating) { /* rider revived, or hero died and was lifesaved */ return; } @@ -1976,7 +1978,7 @@ start_eating(struct obj *otmp, boolean already_partly_eaten) if (bite()) { /* survived choking, finish off food that's nearly done; need this to handle cockatrice eggs, fortune cookies, etc */ - if (++gc.context.victual.usedtime >= gc.context.victual.reqtime) { + if (++svc.context.victual.usedtime >= svc.context.victual.reqtime) { /* don't want done_eating() to issue gn.nomovemsg if it is due to vomit() called by bite() */ save_nomovemsg = gn.nomovemsg; @@ -1989,9 +1991,9 @@ start_eating(struct obj *otmp, boolean already_partly_eaten) return; } - if (++gc.context.victual.usedtime >= gc.context.victual.reqtime) { + if (++svc.context.victual.usedtime >= svc.context.victual.reqtime) { /* print "finish eating" message if they just resumed -dlc */ - done_eating((gc.context.victual.reqtime > 1 + done_eating((svc.context.victual.reqtime > 1 || already_partly_eaten) ? TRUE : FALSE); return; } @@ -2004,7 +2006,7 @@ start_eating(struct obj *otmp, boolean already_partly_eaten) boolean eating_glob(struct obj *glob) { - return (go.occupation == eatfood && glob == gc.context.victual.piece); + return (go.occupation == eatfood && glob == svc.context.victual.piece); } /* scare nearby monster when hero eats garlic */ @@ -2028,7 +2030,10 @@ fprefx(struct obj *otmp) switch (otmp->otyp) { case EGG: if (otmp->corpsenm == PM_PYROLISK) { - useup(otmp); + if (carried(otmp)) + useup(otmp); + else + useupf(otmp, 1L); explode(u.ux, u.uy, -11, d(3, 6), 0, EXPL_FIERY); return FALSE; } else if (stale_egg(otmp)) { @@ -2065,7 +2070,7 @@ fprefx(struct obj *otmp) /* not cannibalism, but we use similar criteria for deciding whether to be sickened by this meal */ if (rn2(2) && !CANNIBAL_ALLOWED()) - make_vomiting((long) rn1(gc.context.victual.reqtime, 14), + make_vomiting((long) rn1(svc.context.victual.reqtime, 14), FALSE); } break; @@ -2085,14 +2090,14 @@ fprefx(struct obj *otmp) goto give_feedback; case CLOVE_OF_GARLIC: if (is_undead(gy.youmonst.data)) { - make_vomiting((long) rn1(gc.context.victual.reqtime, 5), FALSE); + make_vomiting((long) rn1(svc.context.victual.reqtime, 5), FALSE); break; } iter_mons(garlic_breath); /*FALLTHRU*/ default: if (otmp->otyp == SLIME_MOLD && !otmp->cursed - && otmp->spe == gc.context.current_fruit) { + && otmp->spe == svc.context.current_fruit) { pline("My, this is a %s %s!", Hallucination ? "primo" : "yummy", singular(otmp, xname)); @@ -2335,13 +2340,13 @@ eataccessory(struct obj *otmp) staticfn void eatspecial(void) { - struct obj *otmp = gc.context.victual.piece; + struct obj *otmp = svc.context.victual.piece; /* lesshungry wants an occupation to handle choke messages correctly */ set_occupation(eatfood, "eating non-food", 0); - lesshungry(gc.context.victual.nmod); + lesshungry(svc.context.victual.nmod); go.occupation = 0; - gc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ + svc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ if (otmp->oclass == COIN_CLASS) { if (carried(otmp)) @@ -2471,8 +2476,8 @@ fpostfx(struct obj *otmp) setuhpmax(u.uhpmax + 1); u.uhp = u.uhpmax; } else if (u.uhp <= 0) { - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, "rotten lump of royal jelly"); + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, "rotten lump of royal jelly"); done(POISONING); } } @@ -2486,9 +2491,10 @@ fpostfx(struct obj *otmp) && !(poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM))) { if (!Stoned) { - Sprintf(gk.killer.name, "%s egg", + Sprintf(svk.killer.name, "%s egg", mons[otmp->corpsenm].pmnames[NEUTRAL]); - make_stoned(5L, (char *) 0, KILLED_BY_AN, gk.killer.name); + make_stoned(5L, (char *) 0, KILLED_BY_AN, + svk.killer.name); } } /* note: no "tastes like chicken" message for eggs */ @@ -2577,7 +2583,7 @@ edibility_prompts(struct obj *otmp) /* worst case rather than random in this calculation to force prompt */ - rotted = (gm.moves - age) / (10L + 0 /* was rn2(20) */); + rotted = (svm.moves - age) / (10L + 0 /* was rn2(20) */); if (otmp->cursed) rotted += 2L; else if (otmp->blessed) @@ -2659,12 +2665,12 @@ doeat_nonfood(struct obj *otmp) boolean nodelicious = FALSE; int material; - gc.context.victual.reqtime = 1; - gc.context.victual.piece = otmp; - gc.context.victual.o_id = otmp->o_id; + svc.context.victual.reqtime = 1; + svc.context.victual.piece = otmp; + svc.context.victual.o_id = otmp->o_id; /* Don't split it, we don't need to if it's 1 move */ - gc.context.victual.usedtime = 0; - gc.context.victual.canchoke = (u.uhs == SATIATED); + svc.context.victual.usedtime = 0; + svc.context.victual.canchoke = (u.uhs == SATIATED); /* Note: gold weighs 1 pt. for each 1000 pieces (see pickup.c) so gold and non-gold is consistent. */ if (otmp->oclass == COIN_CLASS) @@ -2681,8 +2687,8 @@ doeat_nonfood(struct obj *otmp) nodelicious = TRUE; } #endif - gc.context.victual.nmod = basenutrit; - gc.context.victual.eating = 1; /* needed for lesshungry() */ + svc.context.victual.nmod = basenutrit; + svc.context.victual.eating = 1; /* needed for lesshungry() */ if (!u.uconduct.food++) { ll_conduct++; @@ -2694,15 +2700,15 @@ doeat_nonfood(struct obj *otmp) || material == DRAGON_HIDE || material == WAX) { if (!u.uconduct.unvegan++ && !ll_conduct) { livelog_printf(LL_CONDUCT, - "consumed animal products for the first time, by eating %s", - an(food_xname(otmp, FALSE))); + "consumed animal products for the first time, by eating %s", + an(food_xname(otmp, FALSE))); ll_conduct++; } if (material != WAX) { if (!u.uconduct.unvegetarian && !ll_conduct) livelog_printf(LL_CONDUCT, - "tasted meat by-products for the first time, by eating %s", - an(food_xname(otmp, FALSE))); + "tasted meat by-products for the first time, by eating %s", + an(food_xname(otmp, FALSE))); violated_vegetarian(); } } @@ -2841,9 +2847,9 @@ doeat(void) return doeat_nonfood(otmp); - if (otmp == gc.context.victual.piece) { - boolean one_bite_left - = (gc.context.victual.usedtime + 1 >= gc.context.victual.reqtime); + if (otmp == svc.context.victual.piece) { + boolean one_bite_left = (svc.context.victual.usedtime + 1 + >= svc.context.victual.reqtime); /* If they weren't able to choke, they don't suddenly become able to * choke just because they were interrupted. On the other hand, if @@ -2851,12 +2857,12 @@ doeat(void) * they shouldn't be able to choke now. */ if (u.uhs != SATIATED) - gc.context.victual.canchoke = 0; - gc.context.victual.o_id = 0; + svc.context.victual.canchoke = 0; + svc.context.victual.o_id = 0; otmp = touchfood(otmp); if (otmp) { - gc.context.victual.piece = otmp; - gc.context.victual.o_id = otmp->o_id; + svc.context.victual.piece = otmp; + svc.context.victual.o_id = otmp->o_id; } else { do_reset_eat(); } @@ -2889,9 +2895,9 @@ doeat(void) already_partly_eaten = otmp->oeaten ? TRUE : FALSE; otmp = touchfood(otmp); if (otmp) { - gc.context.victual.piece = otmp; - gc.context.victual.o_id = otmp->o_id; - gc.context.victual.usedtime = 0; + svc.context.victual.piece = otmp; + svc.context.victual.o_id = otmp->o_id; + svc.context.victual.usedtime = 0; } else { do_reset_eat(); return ECMD_TIME; @@ -2907,7 +2913,7 @@ doeat(void) if (tmp == 2) { /* used up */ - gc.context.victual = zero_victual; /* victual.piece=0, .o_id=0 */ + svc.context.victual = zero_victual; /* victual.piece=0, .o_id=0 */ return ECMD_TIME; } else if (tmp) dont_start = TRUE; @@ -2944,10 +2950,10 @@ doeat(void) break; } - gc.context.victual.reqtime = objects[otmp->otyp].oc_delay; + svc.context.victual.reqtime = objects[otmp->otyp].oc_delay; if (otmp->otyp != FORTUNE_COOKIE && (otmp->cursed || (!nonrotting_food(otmp->otyp) - && (gm.moves - otmp->age) + && (svm.moves - otmp->age) > (otmp->blessed ? 50L : 30L) && (otmp->orotten || !rn2(7))))) { if (rottenfood(otmp)) { @@ -2962,7 +2968,7 @@ doeat(void) } } else { You("%s %s.", - (gc.context.victual.reqtime == 1) ? "eat" : "begin eating", + (svc.context.victual.reqtime == 1) ? "eat" : "begin eating", doname(otmp)); } } @@ -2972,30 +2978,30 @@ doeat(void) debugpline3( "before rounddiv: victual.reqtime == %d, oeaten == %d, basenutrit == %d", - gc.context.victual.reqtime, otmp->oeaten, basenutrit); + svc.context.victual.reqtime, otmp->oeaten, basenutrit); - gc.context.victual.reqtime + svc.context.victual.reqtime = (basenutrit == 0) ? 0 - : rounddiv(gc.context.victual.reqtime * (long) otmp->oeaten, + : rounddiv(svc.context.victual.reqtime * (long) otmp->oeaten, basenutrit); debugpline1("after rounddiv: victual.reqtime == %d", - gc.context.victual.reqtime); + svc.context.victual.reqtime); /* * calculate the modulo value (nutrit. units per round eating) * note: this isn't exact - you actually lose a little nutrition due * to this method. * TODO: add in a "remainder" value to be given at the end of the meal. */ - if (gc.context.victual.reqtime == 0 || otmp->oeaten == 0) + if (svc.context.victual.reqtime == 0 || otmp->oeaten == 0) /* possible if most has been eaten before */ - gc.context.victual.nmod = 0; - else if ((int) otmp->oeaten >= gc.context.victual.reqtime) - gc.context.victual.nmod = -((int) otmp->oeaten - / gc.context.victual.reqtime); + svc.context.victual.nmod = 0; + else if ((int) otmp->oeaten >= svc.context.victual.reqtime) + svc.context.victual.nmod = -((int) otmp->oeaten + / svc.context.victual.reqtime); else - gc.context.victual.nmod = gc.context.victual.reqtime % otmp->oeaten; - gc.context.victual.canchoke = (u.uhs == SATIATED); + svc.context.victual.nmod = svc.context.victual.reqtime % otmp->oeaten; + svc.context.victual.canchoke = (u.uhs == SATIATED); if (!dont_start) start_eating(otmp, already_partly_eaten); @@ -3054,25 +3060,25 @@ staticfn int bite(void) { /* hack to pacify static analyzer incorporated into gcc 12.2 */ - sa_victual(&gc.context.victual); + sa_victual(&svc.context.victual); - if (gc.context.victual.canchoke && u.uhunger >= 2000) { - choke(gc.context.victual.piece); + if (svc.context.victual.canchoke && u.uhunger >= 2000) { + choke(svc.context.victual.piece); return 1; } - if (gc.context.victual.doreset) { + if (svc.context.victual.doreset) { do_reset_eat(); return 0; } gf.force_save_hs = TRUE; - if (gc.context.victual.nmod < 0) { - lesshungry(adj_victual_nutrition(/*-gc.context.victual.nmod*/)); - consume_oeaten(gc.context.victual.piece, - gc.context.victual.nmod); /* -= -nmod */ - } else if (gc.context.victual.nmod > 0 - && (gc.context.victual.usedtime % gc.context.victual.nmod)) { + if (svc.context.victual.nmod < 0) { + lesshungry(adj_victual_nutrition(/*-svc.context.victual.nmod*/)); + consume_oeaten(svc.context.victual.piece, + svc.context.victual.nmod); /* -= -nmod */ + } else if (svc.context.victual.nmod > 0 + && (svc.context.victual.usedtime % svc.context.victual.nmod)) { lesshungry(1); - consume_oeaten(gc.context.victual.piece, -1); /* -= 1 */ + consume_oeaten(svc.context.victual.piece, -1); /* -= 1 */ } gf.force_save_hs = FALSE; recalc_wt(); @@ -3109,7 +3115,7 @@ gethungry(void) * Also causes melee-induced hunger to vary from turn-based hunger * instead of just replicating that. */ - accessorytime = rn2(20); /* rn2(20) replaces (int) (gm.moves % 20L) */ + accessorytime = rn2(20); /* rn2(20) replaces (int) (svm.moves % 20L) */ if (accessorytime % 2) { /* odd */ /* Regeneration uses up food, unless due to an artifact */ if ((HRegeneration & ~FROMFORM) @@ -3215,12 +3221,12 @@ lesshungry(int num) debugpline1("lesshungry(%d)", num); u.uhunger += num; if (u.uhunger >= 2000) { - if (!iseating || gc.context.victual.canchoke) { + if (!iseating || svc.context.victual.canchoke) { if (iseating) { - choke(gc.context.victual.piece); + choke(svc.context.victual.piece); reset_eat(); } else { - choke((go.occupation == opentin) ? gc.context.tin.tin : 0); + choke((go.occupation == opentin) ? svc.context.tin.tin : 0); /* no reset_eat() */ } } @@ -3229,18 +3235,18 @@ lesshungry(int num) * warns when you're about to choke. */ if (u.uhunger >= 1500 && !Hunger - && (!gc.context.victual.eating - || (gc.context.victual.eating - && !gc.context.victual.fullwarn))) { + && (!svc.context.victual.eating + || (svc.context.victual.eating + && !svc.context.victual.fullwarn))) { pline("You're having a hard time getting all of it down."); gn.nomovemsg = "You're finally finished."; - if (!gc.context.victual.eating) { + if (!svc.context.victual.eating) { gm.multi = -2; } else { - gc.context.victual.fullwarn = 1; - if (gc.context.victual.canchoke - && (gc.context.victual.reqtime - - gc.context.victual.usedtime) > 1) { + svc.context.victual.fullwarn = 1; + if (svc.context.victual.canchoke + && (svc.context.victual.reqtime + - svc.context.victual.usedtime) > 1) { /* food with one bite left will not survive a stop */ if (!paranoid_query(ParanoidEating, "Continue eating?")) { reset_eat(); @@ -3360,8 +3366,8 @@ newuhs(boolean incr) disp.botl = TRUE; bot(); You("die from starvation."); - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, "starvation"); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, "starvation"); done(STARVING); /* if we return, we lifesaved, and that calls newuhs */ return; @@ -3425,8 +3431,8 @@ newuhs(boolean incr) bot(); if ((Upolyd ? u.mh : u.uhp) < 1) { You("die from hunger and exhaustion."); - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, "exhaustion"); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, "exhaustion"); done(STARVING); return; } @@ -3562,12 +3568,12 @@ floorfood( pline("%s but you %s eat them.", qbuf, nodig ? "cannot" : "are too full to"); } else { - Strcat(qbuf, ((!gc.context.digging.chew - || gc.context.digging.pos.x != u.ux - || gc.context.digging.pos.y != u.uy - || !on_level(&gc.context.digging.level, &u.uz)) + Strcat(qbuf, (!svc.context.digging.chew + || !u_at(svc.context.digging.pos.x, + svc.context.digging.pos.y) + || !on_level(&svc.context.digging.level, &u.uz)) ? "; eat them?" - : "; resume eating them?")); + : "; resume eating them?"); c = yn_function(qbuf, ynqchars, 'n', TRUE); } if (c == 'y') @@ -3593,7 +3599,7 @@ floorfood( } /* Is there some food (probably a heavy corpse) here on the ground? */ - for (otmp = gl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { + for (otmp = svl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { if (corpsecheck ? (otmp->otyp == CORPSE && (corpsecheck == 1 || tinnable(otmp))) @@ -3752,7 +3758,7 @@ consume_oeaten(struct obj *obj, int amt) * victual handling mechanism from scratch using a less complex * model. Alternatively, this routine could call done_eating() * or food_disappears() but its callers would need revisions to - * cope with gc.context.victual.piece unexpectedly going away. + * cope with svc.context.victual.piece unexpectedly going away. * * Multi-turn eating operates by setting the food's oeaten field * to its full nutritional value and then running a counter which @@ -3786,8 +3792,8 @@ consume_oeaten(struct obj *obj, int amt) /* mustn't let partly-eaten drop all the way to 0 or the item would become restored to untouched; set to no bites left */ if (obj->oeaten == 0) { - if (obj == gc.context.victual.piece) /* always true unless wishing */ - gc.context.victual.reqtime = gc.context.victual.usedtime; + if (obj == svc.context.victual.piece) /* always true unless wishing */ + svc.context.victual.reqtime = svc.context.victual.usedtime; obj->oeaten = 1; /* smallest possible positive value */ } } @@ -3799,10 +3805,10 @@ maybe_finished_meal(boolean stopping) { /* in case consume_oeaten() has decided that the food is all gone */ if (go.occupation == eatfood - && gc.context.victual.usedtime >= gc.context.victual.reqtime) { + && svc.context.victual.usedtime >= svc.context.victual.reqtime) { if (stopping) go.occupation = 0; /* for do_reset_eat */ - /* eatfood() calls done_eating() to use up gc.context.victual.piece */ + /* eatfood() calls done_eating() to use up svc.context.victual.piece */ (void) eatfood(); return TRUE; } @@ -3820,9 +3826,9 @@ cant_finish_meal(struct obj *corpse) * left for another bite. revive() needs continued access to the * corpse and will delete it when done. */ - if (go.occupation == eatfood && gc.context.victual.piece == corpse) { + if (go.occupation == eatfood && svc.context.victual.piece == corpse) { /* normally performed by done_eating() */ - gc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ + svc.context.victual = zero_victual; /* victual.piece = 0, .o_id = 0 */ if (!corpse->oeaten) corpse->oeaten = 1; /* [see consume_oeaten()] */ @@ -3845,7 +3851,7 @@ Popeye(int threat) if (go.occupation != opentin) return FALSE; - otin = gc.context.tin.tin; + otin = svc.context.tin.tin; /* make sure hero still has access to tin */ if (!carried(otin) && (!obj_here(otin, u.ux, u.uy) || !can_reach_floor(TRUE))) @@ -3865,7 +3871,7 @@ Popeye(int threat) && (mndx == PM_LIZARD || acidic(&mons[mndx]))); /* polymorph into a fiery monster */ case SLIMED: - return (boolean) polyfodder(otin); + return (boolean) polyfood(otin); /* no tins can cure these (yet?) */ case SICK: case VOMITING: diff --git a/src/end.c b/src/end.c index 48e017d7c..d50420ea2 100644 --- a/src/end.c +++ b/src/end.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 end.c $NHDT-Date: 1711735821 2024/03/29 18:10:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.313 $ */ +/* NetHack 3.7 end.c $NHDT-Date: 1720397752 2024/07/08 00:15:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.315 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -15,10 +15,6 @@ #endif #include "dlb.h" - -/* add b to long a, convert wraparound to max value */ -#define nowrap_add(a, b) (a = ((a + b) < 0 ? LONG_MAX : (a + b))) - #ifndef NO_SIGNAL staticfn void done_intr(int); # if defined(UNIX) || defined(VMS) || defined(__EMX__) @@ -47,7 +43,7 @@ ATTRNORETURN extern void nethack_exit(int) NORETURN; #define nethack_exit exit #endif -#define done_stopprint gp.program_state.stopprint +#define done_stopprint program_state.stopprint /* * The order of these needs to match the macros in hack.h. @@ -179,7 +175,7 @@ staticfn void done_hangup(int sig) { #ifdef HANGUPHANDLING - gp.program_state.done_hup++; + program_state.done_hup++; #endif sethanguphandler((void (*)(int)) SIG_IGN); done_intr(sig); @@ -205,19 +201,19 @@ done_in_by(struct monst *mtmp, int how) You((how == STONING) ? "turn to stone..." : "die..."); mark_synch(); /* flush buffered screen output */ buf[0] = '\0'; - gk.killer.format = KILLED_BY_AN; + svk.killer.format = KILLED_BY_AN; /* "killed by the high priest of Crom" is okay, "killed by the high priest" alone isn't */ if ((mptr->geno & G_UNIQ) != 0 && !(imitator && !mimicker) && !(mptr == &mons[PM_HIGH_CLERIC] && !mtmp->ispriest)) { if (!type_is_pname(mptr)) Strcat(buf, "the "); - gk.killer.format = KILLED_BY; + svk.killer.format = KILLED_BY; } /* _the_ ghost of Dudley */ if (mptr == &mons[PM_GHOST] && has_mgivenname(mtmp)) { Strcat(buf, "the "); - gk.killer.format = KILLED_BY; + svk.killer.format = KILLED_BY; } (void) monhealthdescr(mtmp, TRUE, eos(buf)); if (mtmp->minvis) @@ -268,7 +264,7 @@ done_in_by(struct monst *mtmp, int how) : mtmp->female ? "Ms. " : "Mr. "; Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm); - gk.killer.format = KILLED_BY; + svk.killer.format = KILLED_BY; } else if (mtmp->ispriest || mtmp->isminion) { /* m_monnam() suppresses "the" prefix plus "invisible", and it overrides the effect of Hallucination on priestname() */ @@ -279,7 +275,7 @@ done_in_by(struct monst *mtmp, int how) Sprintf(eos(buf), " called %s", MGIVENNAME(mtmp)); } - Strcpy(gk.killer.name, buf); + Strcpy(svk.killer.name, buf); /* might need to fix up multi_reason if 'mtmp' caused the reason */ if (gm.multi_reason @@ -334,7 +330,7 @@ done_in_by(struct monst *mtmp, int how) /* this could happen if a high-end vampire kills the hero when ordinary vampires are genocided; ditto for wraiths */ if (u.ugrave_arise >= LOW_PM - && (gm.mvitals[u.ugrave_arise].mvflags & G_GENOD)) + && (svm.mvitals[u.ugrave_arise].mvflags & G_GENOD)) u.ugrave_arise = NON_PM; done(how); @@ -395,7 +391,7 @@ panic VA_DECL(const char *, str) VA_START(str); VA_INIT(str, char *); - if (gp.program_state.panicking++) + if (program_state.panicking++) NH_abort(NULL); /* avoid loops - this should never happen*/ gb.bot_disabled = TRUE; @@ -408,9 +404,9 @@ panic VA_DECL(const char *, str) iflags.window_inited = FALSE; /* they're gone; force raw_print()ing */ } - raw_print(gp.program_state.gameover + raw_print(program_state.gameover ? "Postgame wrapup disrupted." - : !gp.program_state.something_worth_saving + : !program_state.something_worth_saving ? "Program initialization has failed." : "Suddenly, the dungeon collapses."); #ifndef MICRO @@ -418,11 +414,11 @@ panic VA_DECL(const char *, str) if (!wizard) raw_printf("Report the following error to \"%s\" or at \"%s\".", DEVTEAM_EMAIL, DEVTEAM_URL); - else if (gp.program_state.something_worth_saving) + else if (program_state.something_worth_saving) raw_print("\nError save file being written.\n"); #else /* !NOTIFY_NETHACK_BUGS */ if (!wizard) { - const char *maybe_rebuild = !gp.program_state.something_worth_saving + const char *maybe_rebuild = !program_state.something_worth_saving ? "." : "\nand it may be possible to rebuild."; @@ -441,7 +437,7 @@ panic VA_DECL(const char *, str) /* XXX can we move this above the prints? Then we'd be able to * suppress "it may be possible to rebuild" based on dosave0() * or say it's NOT possible to rebuild. */ - if (gp.program_state.something_worth_saving && !iflags.debug_fuzzer) { + if (program_state.something_worth_saving && !iflags.debug_fuzzer) { set_error_savefile(); if (dosave0()) { /* os/win port specific recover instructions */ @@ -570,7 +566,7 @@ dump_everything( /* character name and basic role info */ Sprintf(pbuf, "%s, %s %s %s %s", - gp.plname, aligns[1 - u.ualign.type].adj, + svp.plname, aligns[1 - u.ualign.type].adj, genders[flags.female].adj, gu.urace.adj, (flags.female && gu.urole.name.f) ? gu.urole.name.f : gu.urole.name.m); @@ -719,7 +715,7 @@ savelife(int how) make_sick(0L, (char *) 0, FALSE, SICK_ALL); } gn.nomovemsg = "You survived that attempt on your life."; - gc.context.move = 0; + svc.context.move = 0; gm.multi = -1; /* can't move again during the current turn */ /* in case being life-saved is immediately followed by being killed @@ -735,7 +731,7 @@ savelife(int how) u.ugrave_arise = NON_PM; HUnchanging = 0L; curs_on_u(); - if (!gc.context.mon_moving) + if (!svc.context.mon_moving) endmultishot(FALSE); if (u.uswallow) { /* might drop hero onto a trap that kills her all over again */ @@ -914,7 +910,7 @@ artifact_score( value = arti_cost(otmp); /* zorkmid value */ points = value * 5 / 2; /* score value */ if (counting) { - nowrap_add(u.urexp, points); + u.urexp = nowrap_add(u.urexp, points); } else { discover_object(otmp->otyp, TRUE, FALSE); otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; @@ -941,8 +937,7 @@ fuzzer_savelife(int how) * Some debugging code pulled out of done() to unclutter it. * 'done_seq' is maintained in done(). */ - if (!gp.program_state.panicking - && how != PANICKED && how != TRICKED) { + if (!program_state.panicking && how != PANICKED && how != TRICKED) { savelife(how); /* periodically restore characteristics plus lost experience @@ -987,14 +982,17 @@ fuzzer_savelife(int how) } } /* clear stale cause of death info after life-saving */ - gk.killer.name[0] = '\0'; - gk.killer.format = 0; + svk.killer.name[0] = '\0'; + svk.killer.format = 0; - /* Guard against getting stuck in a loop if we die in one of + /* + * Guard against getting stuck in a loop if we die in one of * the few ways where life-saving isn't effective (cited case * was burning in lava when the level was too full to allow - * teleporting to safety). Deal with it by recreating - * the level, if we're in wizmode */ + * teleporting to safety). Deal with it by recreating the level + * if we're in wizmode (always the case for debug_fuzzer unless + * player has used a debugger to fiddle with 'iflags' bits). + */ if (gd.done_seq++ > gh.hero_seq + 100L) { if (!wizard) return FALSE; /* can't deal with it */ @@ -1013,19 +1011,19 @@ done(int how) boolean survive = FALSE; if (how == TRICKED) { - if (gk.killer.name[0]) { - paniclog("trickery", gk.killer.name); - gk.killer.name[0] = '\0'; + if (svk.killer.name[0]) { + paniclog("trickery", svk.killer.name); + svk.killer.name[0] = '\0'; } if (wizard) { You("are a very tricky wizard, it seems."); - gk.killer.format = KILLED_BY_AN; /* reset to 0 */ + svk.killer.format = KILLED_BY_AN; /* reset to 0 */ return; } } - if (gp.program_state.panicking + if (program_state.panicking #ifdef HANGUPHANDLING - || gp.program_state.done_hup + || program_state.done_hup #endif || (how == QUIT && done_stopprint)) { /* skip status update if panicking or disconnected @@ -1049,13 +1047,13 @@ done(int how) return; } - if (how == ASCENDED || (!gk.killer.name[0] && how == GENOCIDED)) - gk.killer.format = NO_KILLER_PREFIX; + if (how == ASCENDED || (!svk.killer.name[0] && how == GENOCIDED)) + svk.killer.format = NO_KILLER_PREFIX; /* Avoid killed by "a" burning or "a" starvation */ - if (!gk.killer.name[0] && (how == STARVING || how == BURNING)) - gk.killer.format = KILLED_BY; - if (!gk.killer.name[0] || how >= PANICKED) - Strcpy(gk.killer.name, deaths[how]); + if (!svk.killer.name[0] && (how == STARVING || how == BURNING)) + svk.killer.format = KILLED_BY; + if (!svk.killer.name[0] || how >= PANICKED) + Strcpy(svk.killer.name, deaths[how]); if (how < PANICKED) { u.umortality++; @@ -1098,7 +1096,7 @@ done(int how) /* if hangup has occurred, the only possible answer to a paranoid query is 'no'; we want 'no' as the default for "Die?" but can't accept it more than once if there's no user supplying it */ - && !(gp.program_state.done_hup && gd.done_seq++ == gh.hero_seq) + && !(program_state.done_hup && gd.done_seq++ == gh.hero_seq) #endif && !paranoid_query(ParanoidDie, "Die?")) { pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die"); @@ -1108,8 +1106,8 @@ done(int how) } if (survive) { - gk.killer.name[0] = '\0'; - gk.killer.format = KILLED_BY_AN; /* reset to 0 */ + svk.killer.name[0] = '\0'; + svk.killer.format = KILLED_BY_AN; /* reset to 0 */ return; } really_done(how); @@ -1132,11 +1130,11 @@ really_done(int how) /* * The game is now over... */ - gp.program_state.gameover = 1; + program_state.gameover = 1; /* in case of a subsequent panic(), there's no point trying to save */ - gp.program_state.something_worth_saving = 0; + program_state.something_worth_saving = 0; #ifdef HANGUPHANDLING - if (gp.program_state.done_hup) + if (program_state.done_hup) done_stopprint++; #endif /* render vision subsystem inoperative */ @@ -1144,7 +1142,7 @@ really_done(int how) /* maybe use up active invent item(s), place thrown/kicked missile, deal with ball and chain possibly being temporarily off the map */ - if (!gp.program_state.panicking) + if (!program_state.panicking) done_object_cleanup(); /* in case we're panicking; normally cleared by done_object_cleanup() */ iflags.perm_invent = FALSE; @@ -1174,7 +1172,7 @@ really_done(int how) * On those rare occasions you get hosed immediately, go out * smiling... :-) -3. */ - if (gm.moves <= 1 && how < PANICKED && !done_stopprint) + if (svm.moves <= 1 && how < PANICKED && !done_stopprint) pline("Do not pass Go. Do not collect 200 %s.", currency(200L)); if (have_windows) @@ -1206,19 +1204,19 @@ really_done(int how) have been genocided: genocide could occur after hero is already infected or hero could eat a glob of one created before genocide; don't try to arise as one if they're gone */ - && !(gm.mvitals[PM_GREEN_SLIME].mvflags & G_GENOD)) + && !(svm.mvitals[PM_GREEN_SLIME].mvflags & G_GENOD)) u.ugrave_arise = PM_GREEN_SLIME; if (how == QUIT) { - gk.killer.format = NO_KILLER_PREFIX; + svk.killer.format = NO_KILLER_PREFIX; if (u.uhp < 1) { how = DIED; u.umortality++; /* skipped above when how==QUIT */ - Strcpy(gk.killer.name, "quit while already on Charon's boat"); + Strcpy(svk.killer.name, "quit while already on Charon's boat"); } } if (how == ESCAPED || how == PANICKED) - gk.killer.format = NO_KILLER_PREFIX; + svk.killer.format = NO_KILLER_PREFIX; fixup_death(how); /* actually, fixup gm.multi_reason */ @@ -1293,14 +1291,14 @@ really_done(int how) /* grave creation should be after disclosure so it doesn't have this grave in the current level's features for #overview */ if (bones_ok && u.ugrave_arise == NON_PM - && !(gm.mvitals[u.umonnum].mvflags & G_NOCORPSE)) { + && !(svm.mvitals[u.umonnum].mvflags & G_NOCORPSE)) { /* Base corpse on race when not poly'd since original u.umonnum is based on role, and all role monsters are human. */ int mnum = !Upolyd ? gu.urace.mnum : u.umonnum, was_already_grave = IS_GRAVE(levl[u.ux][u.uy].typ); - corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, gp.plname); - Sprintf(pbuf, "%s, ", gp.plname); + corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, svp.plname); + Sprintf(pbuf, "%s, ", svp.plname); formatkiller(eos(pbuf), sizeof pbuf - Strlen(pbuf), how, TRUE); make_grave(u.ux, u.uy, pbuf); if (IS_GRAVE(levl[u.ux][u.uy].typ) && !was_already_grave) @@ -1324,7 +1322,7 @@ really_done(int how) tmp += 50L * (long) (deepest - 1); if (deepest > 20) tmp += 1000L * (long) ((deepest > 30) ? 10 : deepest - 20); - nowrap_add(u.urexp, tmp); + u.urexp = nowrap_add(u.urexp, tmp); /* ascension gives a score bonus iff offering to original deity */ if (how == ASCENDED && u.ualign.type == u.ualignbase[A_ORIGINAL]) { @@ -1333,7 +1331,7 @@ really_done(int how) tmp = (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL]) ? u.urexp : (u.urexp / 2L); - nowrap_add(u.urexp, tmp); + u.urexp = nowrap_add(u.urexp, tmp); } } @@ -1395,16 +1393,16 @@ really_done(int how) } #endif if (u.uhave.amulet) { - Strcat(gk.killer.name, " (with the Amulet)"); + Strcat(svk.killer.name, " (with the Amulet)"); } else if (how == ESCAPED) { if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */ - Strcat(gk.killer.name, " (in celestial disgrace)"); + Strcat(svk.killer.name, " (in celestial disgrace)"); else if (carrying(FAKE_AMULET_OF_YENDOR)) - Strcat(gk.killer.name, " (with a fake Amulet)"); + Strcat(svk.killer.name, " (with a fake Amulet)"); /* don't bother counting to see whether it should be plural */ } - Sprintf(pbuf, "%s %s the %s...", Goodbye(), gp.plname, + Sprintf(pbuf, "%s %s the %s...", Goodbye(), svp.plname, (how != ASCENDED) ? (const char *) ((flags.female && gu.urole.name.f) ? gu.urole.name.f @@ -1431,7 +1429,7 @@ really_done(int how) if (val->list[i].count != 0L) { tmp = val->list[i].count * (long) objects[val->list[i].typ].oc_cost; - nowrap_add(u.urexp, tmp); + u.urexp = nowrap_add(u.urexp, tmp); } /* count the points for artifacts */ @@ -1444,7 +1442,7 @@ really_done(int how) while (mtmp) { Sprintf(eos(pbuf), " and %s", mon_nam(mtmp)); if (mtmp->mtame) - nowrap_add(u.urexp, mtmp->mhp); + u.urexp = nowrap_add(u.urexp, mtmp->mhp); mtmp = mtmp->nmon; } /* [it might be more robust to create a housecat and add it to @@ -1453,7 +1451,7 @@ really_done(int how) int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]); mhp = d(m_lev, 8); - nowrap_add(u.urexp, mhp); + u.urexp = nowrap_add(u.urexp, mhp); Strcat(eos(pbuf), " and Schroedinger's cat"); } dump_forward_putstr(endwin, 0, pbuf, done_stopprint); @@ -1515,7 +1513,7 @@ really_done(int how) (u.uz.dlevel < 0) ? "passed away" : ends[how]); } else { /* more conventional demise */ - const char *where = gd.dungeons[u.uz.dnum].dname; + const char *where = svd.dungeons[u.uz.dnum].dname; if (Is_astralevel(&u.uz)) where = "The Astral Plane"; @@ -1530,7 +1528,7 @@ really_done(int how) } Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney, - plur(umoney), gm.moves, plur(gm.moves)); + plur(umoney), svm.moves, plur(svm.moves)); dump_forward_putstr(endwin, 0, pbuf, done_stopprint); Sprintf(pbuf, "You were level %d with a maximum of %d hit point%s when you %s.", @@ -1624,7 +1622,7 @@ container_contents( | (flags.sortpack ? SORTLOOT_PACK : 0)); sortedcobj = sortloot(&box->cobj, sortflags, FALSE, (boolean (*)(OBJ_P)) 0); - for (srtc = sortedcobj; ((obj = srtc->obj) != 0); ++srtc) { + for (srtc = sortedcobj; (obj = srtc->obj) != 0; ++srtc) { if (identified) { discover_object(obj->otyp, TRUE, FALSE); obj->known = obj->bknown = obj->dknown @@ -1661,7 +1659,7 @@ container_contents( ATTRNORETURN void nh_terminate(int status) { - gp.program_state.in_moveloop = 0; /* won't be returning to normal play */ + program_state.in_moveloop = 0; /* won't be returning to normal play */ l_nhcore_call(NHCORE_GAME_EXIT); #ifdef MAC @@ -1669,7 +1667,7 @@ nh_terminate(int status) #endif /* don't bother to try to release memory if we're in panic mode, to avoid trouble in case that happens to be due to memory problems */ - if (!gp.program_state.panicking) { + if (!program_state.panicking) { freedynamicdata(); dlb_cleanup(); l_nhcore_done(); @@ -1683,10 +1681,10 @@ nh_terminate(int status) */ /* don't call exit() if already executing within an exit handler; that would cancel any other pending user-mode handlers */ - if (gp.program_state.exiting) + if (program_state.exiting) return; #endif - gp.program_state.exiting = 1; + program_state.exiting = 1; nethack_exit(status); } @@ -1701,13 +1699,13 @@ delayed_killer(int id, int format, const char *killername) k = (struct kinfo *) alloc(sizeof (struct kinfo)); (void) memset((genericptr_t) k, 0, sizeof (struct kinfo)); k->id = id; - k->next = gk.killer.next; - gk.killer.next = k; + k->next = svk.killer.next; + svk.killer.next = k; } k->format = format; Strcpy(k->name, killername ? killername : ""); - gk.killer.name[0] = 0; + svk.killer.name[0] = 0; } struct kinfo * @@ -1715,7 +1713,7 @@ find_delayed_killer(int id) { struct kinfo *k; - for (k = gk.killer.next; k != (struct kinfo *) 0; k = k->next) { + for (k = svk.killer.next; k != (struct kinfo *) 0; k = k->next) { if (k->id == id) break; } @@ -1725,11 +1723,11 @@ find_delayed_killer(int id) void dealloc_killer(struct kinfo *kptr) { - struct kinfo *prev = &gk.killer, *k; + struct kinfo *prev = &svk.killer, *k; if (kptr == (struct kinfo *) 0) return; - for (k = gk.killer.next; k != (struct kinfo *) 0; k = k->next) { + for (k = svk.killer.next; k != (struct kinfo *) 0; k = k->next) { if (k == kptr) break; prev = k; @@ -1750,16 +1748,16 @@ save_killers(NHFILE *nhfp) struct kinfo *kptr; if (perform_bwrite(nhfp)) { - for (kptr = &gk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { + for (kptr = &svk.killer; kptr; kptr = kptr->next) { if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) kptr, sizeof(struct kinfo)); + bwrite(nhfp->fd, (genericptr_t) kptr, sizeof (struct kinfo)); } } if (release_data(nhfp)) { - while (gk.killer.next) { - kptr = gk.killer.next->next; - free((genericptr_t) gk.killer.next); - gk.killer.next = kptr; + while (svk.killer.next) { + kptr = svk.killer.next->next; + free((genericptr_t) svk.killer.next); + svk.killer.next = kptr; } } } @@ -1769,7 +1767,7 @@ restore_killers(NHFILE *nhfp) { struct kinfo *kptr; - for (kptr = &gk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { + for (kptr = &svk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { if (nhfp->structlevel) mread(nhfp->fd, (genericptr_t) kptr, sizeof(struct kinfo)); if (kptr->next) { @@ -1906,9 +1904,11 @@ NH_abort(char *why USED_FOR_CRASHREPORT) gdb_prio++; if (gdb_prio > libc_prio) { - (void) (NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc())); + (void) (NH_panictrace_gdb() + || (libc_prio && NH_panictrace_libc())); } else { - (void) (NH_panictrace_libc() || (gdb_prio && NH_panictrace_gdb())); + (void) (NH_panictrace_libc() + || (gdb_prio && NH_panictrace_gdb())); } #else /* VMS */ diff --git a/src/engrave.c b/src/engrave.c index 4d76ffe94..8105efeec 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -248,7 +248,7 @@ sengr_at(const char *s, coordxy x, coordxy y, boolean strict) { struct engr *ep = engr_at(x, y); - if (ep && ep->engr_type != HEADSTONE && ep->engr_time <= gm.moves) { + if (ep && ep->engr_type != HEADSTONE && ep->engr_time <= svm.moves) { if (strict ? !strcmpi(ep->engr_txt[actual_text], s) : (strstri(ep->engr_txt[actual_text], s) != 0)) return ep; @@ -355,7 +355,7 @@ read_engr_at(coordxy x, coordxy y) You("%s: \"%s\".", (Blind) ? "feel the words" : "read", et); Strcpy(ep->engr_txt[remembered_text], ep->engr_txt[actual_text]); ep->eread = 1; - if (gc.context.run > 0) + if (svc.context.run > 0) nomul(0); } } @@ -642,7 +642,7 @@ doengrave_sfx_item_WAN(struct _doengrave_ctx *de) ? "Chips fly out from the headstone." : de->frosted ? "Ice chips fly up from the ice surface!" - : (gl.level.locations[u.ux][u.uy].typ + : (svl.level.locations[u.ux][u.uy].typ == DRAWBRIDGE_DOWN) ? "Splinters fly up from the bridge." : "Gravel flies up from the floor."); @@ -1006,7 +1006,7 @@ doengrave(void) if (*de->buf) { struct engr *tmp_ep; - make_engr_at(u.ux, u.uy, de->buf, gm.moves, de->type); + make_engr_at(u.ux, u.uy, de->buf, svm.moves, de->type); tmp_ep = engr_at(u.ux, u.uy); if (!Blind) { if (tmp_ep != 0) { @@ -1167,13 +1167,13 @@ doengrave(void) de->disprefresh = TRUE; } - Strcpy(gc.context.engraving.text, de->ebuf); - gc.context.engraving.nextc = gc.context.engraving.text; - gc.context.engraving.stylus = de->otmp; - gc.context.engraving.type = de->type; - gc.context.engraving.pos.x = u.ux; - gc.context.engraving.pos.y = u.uy; - gc.context.engraving.actionct = 0; + Strcpy(svc.context.engraving.text, de->ebuf); + svc.context.engraving.nextc = svc.context.engraving.text; + svc.context.engraving.stylus = de->otmp; + svc.context.engraving.type = de->type; + svc.context.engraving.pos.x = u.ux; + svc.context.engraving.pos.y = u.uy; + svc.context.engraving.actionct = 0; set_occupation(engrave, "engraving", 0); if (de->post_engr_text[0]) @@ -1186,8 +1186,8 @@ doengrave(void) } /* Engraving will always take at least one action via being run as an - * occupation, so do not count this setup as taking time. */ -doengr_exit: + occupation, so do not count this setup as taking time. */ + doengr_exit: if (de->disprefresh) newsym(u.ux, u.uy); retval = de->ret; @@ -1203,31 +1203,31 @@ engrave(void) char buf[BUFSZ]; /* holds the post-this-action engr text, including * anything already there */ const char *finishverb; /* "You finish [foo]." */ - struct obj * stylus; /* shorthand for gc.context.engraving.stylus */ - boolean firsttime = (gc.context.engraving.actionct == 0); + struct obj * stylus; /* shorthand for svc.context.engraving.stylus */ + boolean firsttime = (svc.context.engraving.actionct == 0); int rate = 10; /* # characters that can be engraved in this action */ boolean truncate = FALSE; - boolean neweng = (gc.context.engraving.actionct == 0); + boolean neweng = (svc.context.engraving.actionct == 0); - boolean carving = (gc.context.engraving.type == ENGRAVE - || gc.context.engraving.type == HEADSTONE); + boolean carving = (svc.context.engraving.type == ENGRAVE + || svc.context.engraving.type == HEADSTONE); boolean dulling_wep, marker; char *endc; /* points at character 1 beyond the last character to engrave * this action */ int i, space_left; - if (gc.context.engraving.pos.x != u.ux - || gc.context.engraving.pos.y != u.uy) { /* teleported? */ + if (svc.context.engraving.pos.x != u.ux + || svc.context.engraving.pos.y != u.uy) { /* teleported? */ You("are unable to continue engraving."); return 0; } /* Stylus might have been taken out of inventory and destroyed somehow. * Not safe to dereference stylus until after this. */ - if (gc.context.engraving.stylus == &hands_obj) { /* bare finger */ + if (svc.context.engraving.stylus == &hands_obj) { /* bare finger */ stylus = (struct obj *) 0; } else { for (stylus = gi.invent; stylus; stylus = stylus->nobj) { - if (stylus == gc.context.engraving.stylus) + if (stylus == svc.context.engraving.stylus) break; } if (!stylus) { @@ -1239,14 +1239,14 @@ engrave(void) dulling_wep = (carving && stylus && stylus->oclass == WEAPON_CLASS && (stylus->otyp != ATHAME || stylus->cursed)); marker = (stylus && stylus->otyp == MAGIC_MARKER - && gc.context.engraving.type == MARK); + && svc.context.engraving.type == MARK); - gc.context.engraving.actionct++; + svc.context.engraving.actionct++; /* sanity checks */ if (dulling_wep && !is_blade(stylus)) { impossible("carving with non-bladed weapon"); - } else if (gc.context.engraving.type == MARK && !marker) { + } else if (svc.context.engraving.type == MARK && !marker) { impossible("making graffiti with non-marker stylus"); } @@ -1263,7 +1263,7 @@ engrave(void) /* Step 2: Compute last character that can be engraved this action. */ i = rate; - for (endc = gc.context.engraving.nextc; *endc && i > 0; endc++) { + for (endc = svc.context.engraving.nextc; *endc && i > 0; endc++) { if (*endc != ' ') { i--; } @@ -1278,7 +1278,7 @@ engrave(void) if (stylus->quan > 1L) { if (firsttime) pline("One of %s gets dull.", yname(stylus)); - stylus = gc.context.engraving.stylus = splitobj(stylus, 1L); + stylus = svc.context.engraving.stylus = splitobj(stylus, 1L); /* if stack is wielded or quivered, the split-off one isn't */ stylus->owornmask = 0L; splitstack = TRUE; @@ -1295,7 +1295,7 @@ engrave(void) * engrave "Elbereth" all at once. * However, you can engrave "Elb", then "ere", then "th", by taking * advantage of the rounding down. */ - if (gc.context.engraving.actionct % 2 == 1) { /* 1st,3rd,... action */ + if (svc.context.engraving.actionct % 2 == 1) { /* 1st,3rd,... action */ /* deduct a point on 1st, 3rd, 5th, ... turns, unless this is the * last character being engraved (a rather convoluted way to round * down), but always deduct a point on the 1st turn to prevent @@ -1308,7 +1308,7 @@ engrave(void) impossible("<= -3 weapon valid for engraving"); } truncate = TRUE; - } else if (*endc || gc.context.engraving.actionct == 1) { + } else if (*endc || svc.context.engraving.actionct == 1) { stylus->spe -= 1; dulled = TRUE; } @@ -1340,7 +1340,7 @@ engrave(void) } } - switch (gc.context.engraving.type) { + switch (svc.context.engraving.type) { default: finishverb = "your weird engraving"; break; @@ -1371,9 +1371,9 @@ engrave(void) Strcpy(buf, oep->engr_txt[actual_text]); space_left = (int) (sizeof buf - strlen(buf) - 1U); - if (endc - gc.context.engraving.nextc > space_left) { + if (endc - svc.context.engraving.nextc > space_left) { You("run out of room to write."); - endc = gc.context.engraving.nextc + space_left; + endc = svc.context.engraving.nextc + space_left; truncate = TRUE; } @@ -1381,25 +1381,25 @@ engrave(void) * can't go any further. */ if (truncate && *endc != '\0') { *endc = '\0'; - You("are only able to write \"%s\".", gc.context.engraving.text); + You("are only able to write \"%s\".", svc.context.engraving.text); } else { /* input was not truncated; stylus may still have worn out on the last * character, though */ truncate = FALSE; } - (void) strncat(buf, gc.context.engraving.nextc, - min(space_left, endc - gc.context.engraving.nextc)); - make_engr_at(u.ux, u.uy, buf, gm.moves - gm.multi, - gc.context.engraving.type); + (void) strncat(buf, svc.context.engraving.nextc, + min(space_left, endc - svc.context.engraving.nextc)); + make_engr_at(u.ux, u.uy, buf, svm.moves - gm.multi, + svc.context.engraving.type); oep = engr_at(u.ux, u.uy); if (oep) oep->eread = 1; if (*endc) { - gc.context.engraving.nextc = endc; + svc.context.engraving.nextc = endc; if (neweng) { - newsym(gc.context.engraving.pos.x, gc.context.engraving.pos.y); + newsym(svc.context.engraving.pos.x, svc.context.engraving.pos.y); } return 1; /* not yet finished this turn */ } else { /* finished engraving */ @@ -1413,12 +1413,12 @@ engrave(void) /* only print this if engraving took multiple actions */ You("finish %s.", finishverb); } - gc.context.engraving.text[0] = '\0'; - gc.context.engraving.nextc = (char *) 0; - gc.context.engraving.stylus = (struct obj *) 0; + svc.context.engraving.text[0] = '\0'; + svc.context.engraving.nextc = (char *) 0; + svc.context.engraving.stylus = (struct obj *) 0; } if (neweng) - newsym(gc.context.engraving.pos.x, gc.context.engraving.pos.y); + newsym(svc.context.engraving.pos.x, svc.context.engraving.pos.y); return 0; } @@ -1521,7 +1521,7 @@ rest_engravings(NHFILE *nhfp) /* mark as finished for bones levels -- no problem for * normal levels as the player must have finished engraving * to be able to move again */ - ep->engr_time = gm.moves; + ep->engr_time = svm.moves; } } diff --git a/src/exper.c b/src/exper.c index 55cbef056..d55f9abab 100644 --- a/src/exper.c +++ b/src/exper.c @@ -231,9 +231,9 @@ losexp( SoundAchievement(0, sa2_xpleveldown, 0); } else { /* u.ulevel==1 */ if (drainer) { - gk.killer.format = KILLED_BY; - if (gk.killer.name != drainer) - Strcpy(gk.killer.name, drainer); + svk.killer.format = KILLED_BY; + if (svk.killer.name != drainer) + Strcpy(svk.killer.name, drainer); done(DIED); } /* no drainer or lifesaved */ diff --git a/src/explode.c b/src/explode.c index c2b76bf4a..f87c6008d 100644 --- a/src/explode.c +++ b/src/explode.c @@ -296,9 +296,9 @@ explode( */ if (olet == MON_EXPLODE && !you_exploding) { - /* when explode() is called recursively, gk.killer.name might change so - we need to retain a copy of the current value for this explosion */ - str = strcpy(killr_buf, gk.killer.name); + /* when explode() is called recursively, svk.killer.name might change + so retain a copy of the current value for this explosion */ + str = strcpy(killr_buf, svk.killer.name); do_hallu = (Hallucination && (strstri(str, "'s explosion") || strstri(str, "s' explosion"))); @@ -468,7 +468,7 @@ explode( * with an explosion attack, leave them (and their gear) * unharmed, to avoid punishing them from using such * polyforms creatively */ - if (!gc.context.mon_moving && you_exploding) + if (!svc.context.mon_moving && you_exploding) uhurt = 0; } else if (inside_engulfer) { /* for inside_engulfer, only is affected */ @@ -477,7 +477,7 @@ explode( /* Affect the floor unless the player caused the explosion * from inside their engulfer. */ - if (!(u.uswallow && !gc.context.mon_moving)) + if (!(u.uswallow && !svc.context.mon_moving)) (void) zap_over_floor(xx, yy, type, &shopdamage, FALSE, exploding_wand_typ); @@ -515,19 +515,19 @@ explode( } if ((explmask[i][j] & EXPL_MON) != 0) { - /* damage from ring/wand explosion isn't itself - * electrical in nature, nor is damage from freezing potion - * really cold in nature, nor is damage from boiling potion - * or exploding oil; only burning items damage is the "same - * type" as the explosion. Because this is imperfect and - * marginal (burning items only deal 1 damage), ignore it - * for golemeffects(). */ + /* Damage from ring/wand explosion isn't itself + * electrical in nature, nor is damage from freezing + * potion really cold in nature, nor is damage from + * boiling potion or exploding oil; only burning items + * damage is the "same type" as the explosion. Because + * this is imperfect and marginal (burning items only + * deal 1 damage), ignore it for golemeffects(). */ golemeffects(mtmp, (int) adtyp, dam); mtmp->mhp -= itemdmg; /* item destruction dmg */ } else { - /* call resist with 0 and do damage manually so 1) we can + /* Call resist with 0 and do damage manually so 1) we can * get out the message before doing the damage, and 2) we - * can call mondied, not killed, if it's not your blast + * can call mondied, not killed, if it's not your blast. */ int mdam = dam; @@ -557,7 +557,7 @@ explode( && completelyburns(mtmp->data)) ? XKILL_NOCORPSE : 0); - if (!gc.context.mon_moving) { + if (!svc.context.mon_moving) { xkilled(mtmp, XKILL_GIVEMSG | xkflg); } else if (mdef && mtmp == mdef) { /* 'mdef' killed self trying to cure being turned @@ -579,7 +579,7 @@ explode( adtyp = AD_RBRE; /* no corpse */ monkilled(mtmp, "", (int) adtyp); } - } else if (!gc.context.mon_moving) { + } else if (!svc.context.mon_moving) { /* all affected monsters, even if mdef is set */ setmangry(mtmp, TRUE); } @@ -644,26 +644,26 @@ explode( } else { if (olet == MON_EXPLODE) { if (generic) /* explosion was unseen; str=="explosion", */ - ; /* gk.killer.name=="gas spore's explosion". */ - else if (str != gk.killer.name && str != hallu_buf) - Strcpy(gk.killer.name, str); - gk.killer.format = KILLED_BY_AN; + ; /* svk.killer.name=="gas spore's explosion". */ + else if (str != svk.killer.name && str != hallu_buf) + Strcpy(svk.killer.name, str); + svk.killer.format = KILLED_BY_AN; } else if (olet == TRAP_EXPLODE) { - gk.killer.format = NO_KILLER_PREFIX; - Snprintf(gk.killer.name, sizeof gk.killer.name, + svk.killer.format = NO_KILLER_PREFIX; + Snprintf(svk.killer.name, sizeof svk.killer.name, "caught %sself in a %s", uhim(), str); } else if (type >= 0 && olet != SCROLL_CLASS) { - gk.killer.format = NO_KILLER_PREFIX; - Snprintf(gk.killer.name, sizeof gk.killer.name, + svk.killer.format = NO_KILLER_PREFIX; + Snprintf(svk.killer.name, sizeof svk.killer.name, "caught %sself in %s own %s", uhim(), uhis(), str); } else { - gk.killer.format = (!strcmpi(str, "tower of flame") + svk.killer.format = (!strcmpi(str, "tower of flame") || !strcmpi(str, "fireball")) ? KILLED_BY_AN : KILLED_BY; - Strcpy(gk.killer.name, str); + Strcpy(svk.killer.name, str); } if (iflags.last_msg == PLNMSG_CAUGHT_IN_EXPLOSION || iflags.last_msg == PLNMSG_TOWER_OF_FLAME) /*seffects()*/ @@ -745,7 +745,8 @@ scatter(coordxy sx, coordxy sy, /* location of objects to scatter */ if (shop_origin) credit_report(shkp, 0, TRUE); /* establish baseline, without msgs */ - while ((otmp = (individual_object ? obj : gl.level.objects[sx][sy])) != 0) { + while ((otmp = (individual_object ? obj + : svl.level.objects[sx][sy])) != 0) { if (otmp == uball || otmp == uchain) { boolean waschain = (otmp == uchain); @@ -917,7 +918,8 @@ scatter(coordxy sx, coordxy sy, /* location of objects to scatter */ retrieve the item and drop it back inside the shop, the owed charges will only be reduced at that point by the lesser shopkeeper buying-price. - The non-gold situation will likely get adjusted further. + The non-gold situation will likely get adjusted + further. */ if (stmp->obj->otyp == GOLD_PIECE) { addtobill(stmp->obj, FALSE, FALSE, TRUE); @@ -1006,12 +1008,14 @@ adtyp_to_expltype(const int adtyp) } } -/* A monster explodes in a way that produces a real explosion (e.g. a sphere or - * gas spore, not a yellow light or similar). +/* A monster explodes in a way that produces a real explosion (e.g. a sphere + * or gas spore, not a yellow light or similar). * This is some common code between explmu() and explmm(). */ void -mon_explodes(struct monst *mon, struct attack *mattk) +mon_explodes( + struct monst *mon, + struct attack *mattk) { int dmg; int type; @@ -1029,8 +1033,9 @@ mon_explodes(struct monst *mon, struct attack *mattk) type = PHYS_EXPL_TYPE; } else if (mattk->adtyp >= AD_MAGM && mattk->adtyp <= AD_SPC2) { - /* The -1, +20, *-1 math is to set it up as a 'monster breath' type for - * the explosions (it isn't, but this is the closest analogue). */ + /* The -1, +20, *-1 math is to set it up as a 'monster breath' type + * for the explosions (it isn't, but this is the closest analogue). */ + /* FIXME: there are macros for kind of thing... */ type = -((mattk->adtyp - 1) + 20); } else { @@ -1039,23 +1044,23 @@ mon_explodes(struct monst *mon, struct attack *mattk) } /* Kill it now so it won't appear to be caught in its own explosion. - * Must check to see if already dead - which happens if this is called from - * an AT_BOOM attack upon death. */ + * Must check to see if already dead - which happens if this is called + * from an AT_BOOM attack upon death. */ if (!DEADMONSTER(mon)) { mondead(mon); } /* This might end up killing you, too; you never know... * also, it is used in explode() messages */ - Sprintf(gk.killer.name, "%s explosion", + Sprintf(svk.killer.name, "%s explosion", s_suffix(pmname(mon->data, Mgender(mon)))); - gk.killer.format = KILLED_BY_AN; + svk.killer.format = KILLED_BY_AN; explode(mon->mx, mon->my, type, dmg, MON_EXPLODE, adtyp_to_expltype(mattk->adtyp)); /* reset killer */ - gk.killer.name[0] = '\0'; + svk.killer.name[0] = '\0'; } /*explode.c*/ diff --git a/src/extralev.c b/src/extralev.c index a6c733ff6..971bf08c1 100644 --- a/src/extralev.c +++ b/src/extralev.c @@ -60,7 +60,7 @@ roguecorr(coordxy x, coordxy y, int dir) fromy += 7 * y; if (!IS_WALL(levl[fromx][fromy].typ)) impossible("down: no wall at %d,%d?", fromx, fromy); - dodoor(fromx, fromy, &gr.rooms[gr.r[x][y].nroom]); + dodoor(fromx, fromy, &svr.rooms[gr.r[x][y].nroom]); levl[fromx][fromy].doormask = D_NODOOR; fromy++; } @@ -82,7 +82,7 @@ roguecorr(coordxy x, coordxy y, int dir) toy += 7 * y; if (!IS_WALL(levl[tox][toy].typ)) impossible("up: no wall at %d,%d?", tox, toy); - dodoor(tox, toy, &gr.rooms[gr.r[x][y].nroom]); + dodoor(tox, toy, &svr.rooms[gr.r[x][y].nroom]); levl[tox][toy].doormask = D_NODOOR; toy--; } @@ -102,7 +102,7 @@ roguecorr(coordxy x, coordxy y, int dir) fromy += 7 * y; if (!IS_WALL(levl[fromx][fromy].typ)) impossible("down: no wall at %d,%d?", fromx, fromy); - dodoor(fromx, fromy, &gr.rooms[gr.r[x][y].nroom]); + dodoor(fromx, fromy, &svr.rooms[gr.r[x][y].nroom]); levl[fromx][fromy].doormask = D_NODOOR; fromx++; } @@ -124,7 +124,7 @@ roguecorr(coordxy x, coordxy y, int dir) toy += 7 * y; if (!IS_WALL(levl[tox][toy].typ)) impossible("left: no wall at %d,%d?", tox, toy); - dodoor(tox, toy, &gr.rooms[gr.r[x][y].nroom]); + dodoor(tox, toy, &svr.rooms[gr.r[x][y].nroom]); levl[tox][toy].doormask = D_NODOOR; tox--; } @@ -211,13 +211,13 @@ makeroguerooms(void) */ #define here gr.r[x][y] - gn.nroom = 0; + svn.nroom = 0; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { /* Note: we want to insure at least 1 room. So, if the * first 8 are all dummies, force the last to be a room. */ - if (!rn2(5) && (gn.nroom || (x < 2 && y < 2))) { + if (!rn2(5) && (svn.nroom || (x < 2 && y < 2))) { /* Arbitrary: dummy rooms may only go where real * ones do. */ @@ -232,19 +232,19 @@ makeroguerooms(void) /* boundaries of room floor */ here.rlx = rnd(23 - here.dx + 1); here.rly = rnd(((y == 2) ? 5 : 4) - here.dy + 1); - gn.nroom++; + svn.nroom++; } here.doortable = 0; } miniwalk(rn2(3), rn2(3)); - gn.nroom = 0; + svn.nroom = 0; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { if (here.real) { /* Make a room */ coordxy lowx, lowy, hix, hiy; - gr.r[x][y].nroom = gn.nroom; - gs.smeq[gn.nroom] = gn.nroom; + gr.r[x][y].nroom = svn.nroom; + gs.smeq[svn.nroom] = svn.nroom; lowx = 1 + 26 * x + here.rlx; lowy = 7 * y + here.rly; @@ -292,9 +292,9 @@ makerogueghost(void) struct mkroom *croom; coordxy x, y; - if (!gn.nroom) + if (!svn.nroom) return; /* Should never happen */ - croom = &gr.rooms[rn2(gn.nroom)]; + croom = &svr.rooms[rn2(svn.nroom)]; x = somex(croom); y = somey(croom); if (!(ghost = makemon(&mons[PM_GHOST], x, y, NO_MM_FLAGS))) diff --git a/src/files.c b/src/files.c index 5771bc118..e522bc4e0 100644 --- a/src/files.c +++ b/src/files.c @@ -318,7 +318,8 @@ fname_encode( (void) sprintf(op, "%c%02X", quotechar, *sp); op += 3; cnt += 3; - } else if ((strchr(legal, *sp) != 0) || (strchr(hexdigits, *sp) != 0)) { + } else if ((strchr(legal, *sp) != 0) + || (strchr(hexdigits, *sp) != 0)) { *op++ = *sp; *op = '\0'; cnt++; @@ -632,7 +633,7 @@ create_levelfile(int lev, char errbuf[]) #endif /* MICRO || WIN32 */ if (nhfp->fd >= 0) - gl.level_info[lev].flags |= LFILE_EXISTS; + svl.level_info[lev].flags |= LFILE_EXISTS; else if (errbuf) /* failure explanation */ Sprintf(errbuf, "Cannot create file \"%s\" for level %d (errno %d).", @@ -690,10 +691,10 @@ delete_levelfile(int lev) * Level 0 might be created by port specific code that doesn't * call create_levfile(), so always assume that it exists. */ - if (lev == 0 || (gl.level_info[lev].flags & LFILE_EXISTS)) { + if (lev == 0 || (svl.level_info[lev].flags & LFILE_EXISTS)) { set_levelfile_name(gl.lock, lev); (void) unlink(fqname(gl.lock, LEVELPREFIX, 0)); - gl.level_info[lev].flags &= ~LFILE_EXISTS; + svl.level_info[lev].flags &= ~LFILE_EXISTS; } } @@ -703,7 +704,7 @@ clearlocks(void) int x; #ifdef HANGUPHANDLING - if (gp.program_state.preserve_locks) + if (program_state.preserve_locks) return; #endif #ifndef NO_SIGNAL @@ -713,7 +714,7 @@ clearlocks(void) #endif #endif /* NO_SIGNAL */ /* can't access maxledgerno() before dungeons are created -dlc */ - for (x = (gn.n_dgns ? maxledgerno() : 0); x >= 0; x--) + for (x = (svn.n_dgns ? maxledgerno() : 0); x >= 0; x--) delete_levelfile(x); /* not all levels need be present */ } @@ -782,7 +783,7 @@ set_bonesfile_name(char *file, d_level *lev) dptr = eos(file); /* when this naming scheme was adopted, 'filecode' was one letter; 3.3.0 turned it into a three letter string for quest levels */ - Sprintf(dptr, "%c%s", gd.dungeons[lev->dnum].boneid, + Sprintf(dptr, "%c%s", svd.dungeons[lev->dnum].boneid, In_quest(lev) ? gu.urole.filecode : "0"); if ((sptr = Is_special(lev)) != 0) Sprintf(eos(dptr), ".%c", sptr->boneid); @@ -944,7 +945,7 @@ compress_bonesfile(void) /* ---------- BEGIN SAVE FILE HANDLING ----------- */ -/* set savefile name in OS-dependent manner from pre-existing gp.plname, +/* set savefile name in OS-dependent manner from pre-existing svp.plname, * avoiding troublesome characters */ void set_savefile_name(boolean regularize_it) @@ -958,21 +959,21 @@ set_savefile_name(boolean regularize_it) #endif #ifdef VMS - Sprintf(gs.SAVEF, "[.save]%d%s", getuid(), gp.plname); + Sprintf(gs.SAVEF, "[.save]%d%s", getuid(), svp.plname); regoffset = 7; indicator_spot = 1; postappend = ";1"; #endif #if defined(WIN32) if (regularize_it) { - static const char okchars[] = - "*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-."; + static const char okchars[] + = "*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-."; const char *legal = okchars; ++legal; /* skip '*' wildcard character */ - (void) fname_encode(legal, '%', gp.plname, tmp, sizeof tmp); + (void) fname_encode(legal, '%', svp.plname, tmp, sizeof tmp); } else { - Sprintf(tmp, "%s", gp.plname); + Sprintf(tmp, "%s", svp.plname); } if (strlen(tmp) < (SAVESIZE - 1)) Strcpy(gs.SAVEF, tmp); @@ -982,7 +983,7 @@ set_savefile_name(boolean regularize_it) regularize_it = FALSE; #endif #ifdef UNIX - Sprintf(gs.SAVEF, "save/%d%s", (int) getuid(), gp.plname); + Sprintf(gs.SAVEF, "save/%d%s", (int) getuid(), svp.plname); regoffset = 5; indicator_spot = 2; #endif @@ -990,7 +991,7 @@ set_savefile_name(boolean regularize_it) if (strlen(gs.SAVEP) < (SAVESIZE - 1)) Strcpy(gs.SAVEF, gs.SAVEP); if (strlen(gs.SAVEF) < (SAVESIZE - 1)) - (void) strncat(gs.SAVEF, gp.plname, (SAVESIZE - strlen(gs.SAVEF))); + (void) strncat(gs.SAVEF, svp.plname, (SAVESIZE - strlen(gs.SAVEF))); #endif #if defined(MICRO) && !defined(VMS) && !defined(WIN32) && !defined(MSDOS) if (strlen(gs.SAVEP) < (SAVESIZE - 1)) @@ -1003,11 +1004,11 @@ set_savefile_name(boolean regularize_it) { int i = strlen(gs.SAVEP); #ifdef AMIGA - /* gp.plname has to share space with gs.SAVEP and ".sav" */ - (void) strncat(gs.SAVEF, gp.plname, + /* svp.plname has to share space with gs.SAVEP and ".sav" */ + (void) strncat(gs.SAVEF, svp.plname, FILENAME - i - strlen(SAVE_EXTENSION)); #else - (void) strncat(gs.SAVEF, gp.plname, 8); + (void) strncat(gs.SAVEF, svp.plname, 8); #endif regoffset = i; } @@ -1049,7 +1050,8 @@ set_savefile_name(boolean regularize_it) } #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) if (overflow) - impossible("set_savefile_name() couldn't complete without overflow %d", + impossible("set_savefile_name() couldn't complete" + " without overflow %d", overflow); #endif } @@ -1101,7 +1103,7 @@ create_savefile(void) nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_SAVEFILE; nhfp->mode = WRITING; - if (gp.program_state.in_self_recover || do_historical) { + if (program_state.in_self_recover || do_historical) { do_historical = TRUE; /* force it */ nhfp->structlevel = TRUE; nhfp->fieldlevel = FALSE; @@ -1155,7 +1157,7 @@ open_savefile(void) nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_SAVEFILE; nhfp->mode = READING; - if (gp.program_state.in_self_recover || do_historical) { + if (program_state.in_self_recover || do_historical) { do_historical = TRUE; /* force it */ nhfp->structlevel = TRUE; nhfp->fieldlevel = FALSE; @@ -1337,7 +1339,7 @@ get_saved_games(void) char **files = 0; int i, count_failures = 0; - Strcpy(gp.plname, "*"); + Strcpy(svp.plname, "*"); set_savefile_name(FALSE); #if defined(ZLIB_COMP) Strcat(gs.SAVEF, COMPRESS_EXTENSION); @@ -1372,7 +1374,7 @@ get_saved_games(void) if (r) { /* rename file if it is not named as expected */ - Strcpy(gp.plname, r); + Strcpy(svp.plname, r); set_savefile_name(TRUE); fq_new_save = fqname(gs.SAVEF, SAVEPREFIX, 0); fq_old_save = fqname(files[i], SAVEPREFIX, 1); @@ -1434,7 +1436,7 @@ get_saved_games(void) } #endif #ifdef VMS - Strcpy(gp.plname, "*"); + Strcpy(svp.plname, "*"); set_savefile_name(FALSE); j = vms_get_saved_games(gs.SAVEF, &result); #endif /* VMS */ @@ -1875,7 +1877,7 @@ static struct flock sflock; /* for unlocking, same as above */ #endif #if defined(HANGUPHANDLING) -#define HUP if (!gp.program_state.done_hup) +#define HUP if (!program_state.done_hup) #else #define HUP #endif @@ -1946,7 +1948,8 @@ lock_file(const char *filename, int whichprefix, #ifdef USE_FCNTL lockfd = open(filename, O_RDWR); if (lockfd == -1) { - HUP raw_printf("Cannot open file %s. Is NetHack installed correctly?", + HUP raw_printf("Cannot open file %s. " + " Is NetHack installed correctly?", filename); gn.nesting--; return FALSE; @@ -1970,8 +1973,8 @@ lock_file(const char *filename, int whichprefix, #ifdef USE_FCNTL if (retryct--) { - HUP raw_printf( - "Waiting for release of fcntl lock on %s. (%d retries left.)", + HUP raw_printf("Waiting for release of fcntl lock on %s. " + " (%d retries left.)", filename, retryct); sleep(1); } else { @@ -1987,7 +1990,8 @@ lock_file(const char *filename, int whichprefix, switch (errnosv) { /* George Barbanis */ case EEXIST: if (retryct--) { - HUP raw_printf("Waiting for access to %s. (%d retries left).", + HUP raw_printf("Waiting for access to %s. " + " (%d retries left).", filename, retryct); #if defined(SYSV) || defined(ULTRIX) || defined(VMS) (void) @@ -2022,8 +2026,8 @@ lock_file(const char *filename, int whichprefix, /* take a wild guess at the underlying cause */ HUP perror(lockname); HUP raw_printf("Cannot lock %s.", filename); - HUP raw_printf( - "(Perhaps you are running NetHack from inside the distribution package?)."); + HUP raw_printf("(Perhaps you are running NetHack from" + " inside the distribution package?)."); gn.nesting--; return FALSE; default: @@ -2174,8 +2178,8 @@ do_write_config_file(void) wait_synch(); pline("Some settings are not saved!"); wait_synch(); - pline( - "All manual customization and comments are removed from the file!"); + pline("All manual customization and comments are removed" + " from the file!"); wait_synch(); } #define overwrite_prompt "Overwrite config file %.*s?" @@ -2534,7 +2538,8 @@ handle_config_section(char *buf) } if (*sect) { /* got a section name */ gc.config_section_current = dupstr(sect); - debugpline1("set config section: '%s'", gc.config_section_current); + debugpline1("set config section: '%s'", + gc.config_section_current); } else { /* empty section name => end of sections */ free_config_sections(); debugpline0("unset config section"); @@ -2728,7 +2733,7 @@ cnf_line_TROUBLEDIR(char *bufp) staticfn boolean cnf_line_NAME(char *bufp) { - (void) strncpy(gp.plname, bufp, PL_NSIZ - 1); + (void) strncpy(svp.plname, bufp, PL_NSIZ - 1); return TRUE; } @@ -2981,8 +2986,8 @@ cnf_line_MAX_STATUENAME_RANK(char *bufp) int n = atoi(bufp); if (n < 1) { - config_error_add( - "Illegal value in MAX_STATUENAME_RANK (minimum is 1)"); + config_error_add("Illegal value in MAX_STATUENAME_RANK" + " (minimum is 1)"); n = 10; } sysopt.tt_oname_maxrank = n; @@ -2998,8 +3003,8 @@ cnf_line_LIVELOG(char *bufp) long L = strtol(bufp, NULL, 0); if (L < 0L || L > 0xffffL) { - config_error_add( - "Illegal value for LIVELOG (must be between 0 and 0xFFFF)."); + config_error_add("Illegal value for LIVELOG" + " (must be between 0 and 0xFFFF)."); return 0; } sysopt.livelog = L; @@ -3109,8 +3114,8 @@ cnf_line_PORTABLE_DEVICE_PATHS(char *bufp) int n = atoi(bufp); if (n < 0 || n > 1) { - config_error_add( - "Illegal value in PORTABLE_DEVICE_PATHS (not 0,1)"); + config_error_add("Illegal value in PORTABLE_DEVICE_PATHS" + " (not 0 or 1)"); n = 0; } sysopt.portable_device_paths = n; @@ -3447,7 +3452,7 @@ config_error_init(boolean from_file, const char *sourcename, boolean secure) tmp->next = config_error_data; config_error_data = tmp; - gp.program_state.config_error_ready = TRUE; + program_state.config_error_ready = TRUE; } staticfn boolean @@ -3513,7 +3518,7 @@ config_erradd(const char *buf) punct = c_eos((char *) buf) - 1; /* eos(buf)-1 is valid */ punct = strchr(".!?", *punct) ? "" : "."; - if (!gp.program_state.config_error_ready) { + if (!program_state.config_error_ready) { /* either very early, where pline() will use raw_print(), or player gave bad value when prompted by interactive 'O' command */ pline("%s%s%s", !iflags.window_inited ? "config_error_add: " : "", @@ -3575,7 +3580,7 @@ config_error_done(void) } config_error_data = tmp->next; free(tmp); - gp.program_state.config_error_ready = (config_error_data != 0); + program_state.config_error_ready = (config_error_data != 0); return n; } @@ -3733,7 +3738,8 @@ parse_conf_buf(struct _cnf_parser_state *p, boolean (*proc)(char *arg)) char *bufp = find_optparam(p->buf); if (!bufp) { - config_error_add("Format is CHOOSE=section1,section2,..."); + config_error_add("Format is CHOOSE=section1" + ",section2,..."); p->rv = FALSE; free(p->buf), p->buf = (char *) 0; return; @@ -3915,8 +3921,8 @@ fopen_wizkit_file(void) else if (errno != ENOENT) { /* e.g., problems when setuid NetHack can't search home * directory restricted to user */ - raw_printf("Couldn't open default gw.wizkit file %s (%d).", tmp_wizkit, - errno); + raw_printf("Couldn't open default gw.wizkit file %s (%d).", + tmp_wizkit, errno); wait_synch(); } #endif @@ -3978,14 +3984,14 @@ read_wizkit(void) if (!wizard || !(fp = fopen_wizkit_file())) return; - gp.program_state.wizkit_wishing = 1; + program_state.wizkit_wishing = 1; config_error_init(TRUE, "WIZKIT", FALSE); parse_conf_file(fp, proc_wizkit_line); (void) fclose(fp); config_error_done(); - gp.program_state.wizkit_wishing = 0; + program_state.wizkit_wishing = 0; return; } @@ -4047,7 +4053,7 @@ read_sym_file(int which_set) clear_symsetentry(which_set, TRUE); config_error_done(); - /* If name was defined, it was invalid. Then we're loading fallback */ + /* If name was defined, it was invalid. Then we're loading fallback */ if (gs.symset[which_set].name) { gs.symset[which_set].explicitly = FALSE; return 0; @@ -4087,8 +4093,8 @@ check_recordfile(const char *dir UNUSED_if_not_OS2_CODEVIEW) if (fd >= 0) { #ifdef VMS /* must be stream-lf to use UPDATE_RECORD_IN_PLACE */ if (!file_is_stmlf(fd)) { - raw_printf( - "Warning: scoreboard file '%s' is not in stream_lf format", + raw_printf("Warning: scoreboard file '%s'" + " is not in stream_lf format", fq_record); wait_synch(); } @@ -4195,13 +4201,13 @@ paniclog( #ifdef PANICLOG FILE *lfile; - if (!gp.program_state.in_paniclog) { - gp.program_state.in_paniclog = 1; + if (!program_state.in_paniclog) { + program_state.in_paniclog = 1; lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX); if (lfile) { #ifdef PANICLOG_FMT2 (void) fprintf(lfile, "%ld %s: %s %s\n", - ubirthday, (gp.plname[0] ? gp.plname : "(none)"), + ubirthday, (svp.plname[0] ? svp.plname : "(none)"), type, reason); #else char buf[BUFSZ]; @@ -4216,7 +4222,7 @@ paniclog( #endif /* !PANICLOG_FMT2 */ (void) fclose(lfile); } - gp.program_state.in_paniclog = 0; + program_state.in_paniclog = 0; } #endif /* PANICLOG */ return; @@ -4280,16 +4286,18 @@ recover_savefile(void) } if (read(gnhfp->fd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) { raw_printf("\n%s\n%s\n", - "Checkpoint data incompletely written or subsequently clobbered.", + "Checkpoint data incompletely written" + " or subsequently clobbered.", "Recovery impossible."); close_nhfile(gnhfp); return FALSE; } if (read(gnhfp->fd, (genericptr_t) &savelev, sizeof(savelev)) != sizeof(savelev)) { - raw_printf( - "\nCheckpointing was not in effect for %s -- recovery impossible.\n", - gl.lock); + raw_printf("\n%s %s %s\n", + "Checkpointing was not in effect for", + gl.lock, + "-- recovery impossible."); close_nhfile(gnhfp); return FALSE; } @@ -4304,7 +4312,8 @@ recover_savefile(void) || (read(gnhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) || (read(gnhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ) - || (read(gnhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz)) { + || (read(gnhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) + != pltmpsiz)) { raw_printf("\nError reading %s -- can't recover.\n", gl.lock); close_nhfile(gnhfp); return FALSE; @@ -4323,9 +4332,9 @@ recover_savefile(void) /* * Set a flag for the savefile routines to know the * circumstances and act accordingly: - * gp.program_state.in_self_recover + * program_state.in_self_recover */ - gp.program_state.in_self_recover = TRUE; + program_state.in_self_recover = TRUE; set_savefile_name(TRUE); snhfp = create_savefile(); if (!snhfp) { @@ -4433,11 +4442,11 @@ recover_savefile(void) close_nhfile(gnhfp); close_nhfile(snhfp); close_nhfile(lnhfp); - gp.program_state.in_self_recover = FALSE; + program_state.in_self_recover = FALSE; delete_savefile(); return FALSE; } - /* we don't clear gp.program_state.in_self_recover here, we + /* we don't clear program_state.in_self_recover here, we leave it as a flag to reload the structlevel savefile in the caller. The caller should then clear it. */ return TRUE; @@ -4789,7 +4798,7 @@ reveal_paths(void) #define TITLESCOPE 2 #define PASSAGESCOPE 3 -#define MAXPASSAGES SIZE(gc.context.novel.pasg) /* 20 */ +#define MAXPASSAGES SIZE(svc.context.novel.pasg) /* 20 */ staticfn int choose_passage(int, unsigned); @@ -4807,32 +4816,33 @@ choose_passage(int passagecnt, /* total of available passages */ /* if a different book or we've used up all the passages already, reset in order to have all 'passagecnt' passages available */ - if (oid != gc.context.novel.id || gc.context.novel.count == 0) { + if (oid != svc.context.novel.id || svc.context.novel.count == 0) { int i, range = passagecnt, limit = MAXPASSAGES; - gc.context.novel.id = oid; + svc.context.novel.id = oid; if (range <= limit) { /* collect all of the N indices */ - gc.context.novel.count = passagecnt; + svc.context.novel.count = passagecnt; for (idx = 0; idx < MAXPASSAGES; idx++) - gc.context.novel.pasg[idx] = (xint16) ((idx < passagecnt) + svc.context.novel.pasg[idx] = (xint16) ((idx < passagecnt) ? idx + 1 : 0); } else { /* collect MAXPASSAGES of the N indices */ - gc.context.novel.count = MAXPASSAGES; + svc.context.novel.count = MAXPASSAGES; for (idx = i = 0; i < passagecnt; ++i, --range) if (range > 0 && rn2(range) < limit) { - gc.context.novel.pasg[idx++] = (xint16) (i + 1); + svc.context.novel.pasg[idx++] = (xint16) (i + 1); --limit; } } } - idx = rn2(gc.context.novel.count); - res = (int) gc.context.novel.pasg[idx]; + idx = rn2(svc.context.novel.count); + res = (int) svc.context.novel.pasg[idx]; /* move the last slot's passage index into the slot just used and reduce the number of passages available */ - gc.context.novel.pasg[idx] = gc.context.novel.pasg[--gc.context.novel.count]; + svc.context.novel.pasg[idx] + = svc.context.novel.pasg[--svc.context.novel.count]; return res; } @@ -5061,10 +5071,10 @@ livelog_add(long ll_type, const char *str) "gender=%s" LLOG_SEP "align=%s" LLOG_SEP "turns=%ld" LLOG_SEP "starttime=%ld" LLOG_SEP "curtime=%ld" LLOG_SEP "message=%s" LLOG_EOL, - (ll_type & sysopt.livelog), gp.plname, + (ll_type & sysopt.livelog), svp.plname, gu.urole.filecode, gu.urace.filecode, genders[gindx].filecode, aligns[aindx].filecode, - gm.moves, timet_to_seconds(ubirthday), + svm.moves, timet_to_seconds(ubirthday), timet_to_seconds(now), str); (void) fclose(livelogfile); unlock_file(LIVELOGFILE); diff --git a/src/fountain.c b/src/fountain.c index 0ca38f795..848adfbfb 100644 --- a/src/fountain.c +++ b/src/fountain.c @@ -40,7 +40,7 @@ dowatersnakes(void) int num = rn1(5, 2); struct monst *mtmp; - if (!(gm.mvitals[PM_WATER_MOCCASIN].mvflags & G_GONE)) { + if (!(svm.mvitals[PM_WATER_MOCCASIN].mvflags & G_GONE)) { if (!Blind) { pline("An endless stream of %s pours forth!", Hallucination ? makeplural(rndmonnam(NULL)) : "snakes"); @@ -65,7 +65,7 @@ dowaterdemon(void) { struct monst *mtmp; - if (!(gm.mvitals[PM_WATER_DEMON].mvflags & G_GONE)) { + if (!(svm.mvitals[PM_WATER_DEMON].mvflags & G_GONE)) { if ((mtmp = makemon(&mons[PM_WATER_DEMON], u.ux, u.uy, MM_NOMSG)) != 0) { if (!Blind) @@ -95,7 +95,7 @@ dowaternymph(void) { struct monst *mtmp; - if (!(gm.mvitals[PM_WATER_NYMPH].mvflags & G_GONE) + if (!(svm.mvitals[PM_WATER_NYMPH].mvflags & G_GONE) && (mtmp = makemon(&mons[PM_WATER_NYMPH], u.ux, u.uy, MM_NOMSG)) != 0) { if (!Blind) @@ -152,7 +152,7 @@ gush(coordxy x, coordxy y, genericptr_t poolcnt) levl[x][y].flags = 0; /* No kelp! */ del_engr_at(x, y); - water_damage_chain(gl.level.objects[x][y], TRUE); + water_damage_chain(svl.level.objects[x][y], TRUE); if ((mtmp = m_at(x, y)) != 0) (void) minliquid(mtmp); @@ -407,7 +407,8 @@ dipfountain(struct obj *obj) if (u.ualign.type != A_LAWFUL) { /* Ha! Trying to cheat her. */ - pline("A freezing mist rises from the %s and envelopes the sword.", + pline("A freezing mist rises from the %s" + " and envelopes the sword.", hliquid("water")); pline_The("fountain disappears!"); curse(obj); @@ -613,7 +614,7 @@ drinksink(void) /* boiling water burns considered fire damage */ break; case 3: - if (gm.mvitals[PM_SEWER_RAT].mvflags & G_GONE) + if (svm.mvitals[PM_SEWER_RAT].mvflags & G_GONE) pline_The("sink seems quite dirty."); else { mtmp = makemon(&mons[PM_SEWER_RAT], u.ux, u.uy, MM_NOMSG); @@ -655,7 +656,7 @@ drinksink(void) break; case 7: pline_The("%s moves as though of its own will!", hliquid("water")); - if ((gm.mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE) + if ((svm.mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE) || !makemon(&mons[PM_WATER_ELEMENTAL], u.ux, u.uy, MM_NOMSG)) pline("But it quiets down."); break; diff --git a/src/getpos.c b/src/getpos.c index c6c9aa78b..1e0c813d2 100644 --- a/src/getpos.c +++ b/src/getpos.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 getpos.c $NHDT-Date: 1708126536 2024/02/16 23:35:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.307 $ */ +/* NetHack 3.7 getpos.c $NHDT-Date: 1723875487 2024/08/17 06:18:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ */ /*-Copyright (c) Pasi Kallinen, 2023. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1033,7 +1033,11 @@ getpos(coord *ccp, boolean force, const char *goal) || c == (int) gs.showsyms[sidx] /* have '^' match webs and vibrating square or any other trap that uses something other than '^' */ - || (c == '^' && is_cmap_trap(sidx))) + || (c == '^' && is_cmap_trap(sidx)) + /* have room engraving character (default '`') + match corridor engravings (default '#') too */ + || (c == gs.showsyms[S_engroom] + && is_cmap_engraving(sidx))) matching[sidx] = (char) ++k; } if (k) { @@ -1054,7 +1058,7 @@ getpos(coord *ccp, boolean force, const char *goal) goto foundc; /* next, try glyph that's remembered here (might be trap or object) */ - if (gl.level.flags.hero_memory + if (svl.level.flags.hero_memory /* !terrainmode: don't move to remembered trap or object if not currently shown */ && !iflags.terrainmode) { @@ -1064,7 +1068,7 @@ getpos(coord *ccp, boolean force, const char *goal) goto foundc; } /* last, try actual terrain here (shouldn't - we be using gl.lastseentyp[][] instead?) */ + we be using svl.lastseentyp[][] instead?) */ if (levl[tx][ty].seenv) { k = back_to_glyph(tx, ty); if (glyph_is_cmap(k) diff --git a/src/glyphs.c b/src/glyphs.c index 416cb98be..93d065b00 100644 --- a/src/glyphs.c +++ b/src/glyphs.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 glyphs.c */ +/* NetHack 3.7 glyphs.c TODO: add NHDT branch/date/revision tags */ /* Copyright (c) Michael Allison, 2021. */ /* NetHack may be freely redistributed. See license for details. */ @@ -82,7 +82,8 @@ to_custom_symset_entry_callback(int glyph, struct find_struct *findwhat) static int glyphnag = 0; if (!glyphnag++) - config_error_add("Unimplemented customization feature, ignoring for now"); + config_error_add("Unimplemented customization feature," + " ignoring for now"); } } #endif @@ -94,7 +95,8 @@ to_custom_symset_entry_callback(int glyph, struct find_struct *findwhat) static int colornag = 0; if (!colornag++) - config_error_add("Unimplemented customization feature, ignoring for now"); + config_error_add("Unimplemented customization feature," + " ignoring for now"); } } } @@ -208,7 +210,8 @@ glyph_find_core(const char *id, struct find_struct *findwhat) break; case find_pm: if (glyph_is_monster(glyph) - && monsym(&mons[glyph_to_mon(glyph)]) == findwhat->val) + && monsym(&mons[glyph_to_mon(glyph)]) + == findwhat->val) do_callback = TRUE; break; case find_oc: @@ -517,7 +520,7 @@ apply_customizations( if (sc->custtype == custom_nhcolor) { gmap = &glyphmap[details->content.ccolor.glyphidx]; (void) set_map_customcolor(gmap, - details->content.ccolor.nhcolor); + details->content.ccolor.nhcolor); } } details = details->next; @@ -683,7 +686,8 @@ find_matching_customization( enum customization_types custtype, enum graphics_sets which_set) { - struct symset_customization *gdc = &gs.sym_customizations[which_set][custtype]; + struct symset_customization *gdc + = &gs.sym_customizations[which_set][custtype]; if ((gdc->custtype == custtype) && gdc->customization_name && (strcmp(customization_name, gdc->customization_name) == 0)) diff --git a/src/hack.c b/src/hack.c index 1432a06d9..2b9ca664c 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 hack.c $NHDT-Date: 1715022473 2024/05/06 19:07:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.447 $ */ +/* NetHack 3.7 hack.c $NHDT-Date: 1723410639 2024/08/11 21:10:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.452 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,11 +9,13 @@ /* #define DEBUG */ /* uncomment for debugging */ staticfn boolean could_move_onto_boulder(coordxy, coordxy); +staticfn void moverock_done(coordxy, coordxy); staticfn int moverock(void); staticfn void dosinkfall(void); staticfn boolean findtravelpath(int); staticfn boolean trapmove(coordxy, coordxy, struct trap *); -staticfn int QSORTCALLBACK notice_mons_cmp(const genericptr, const genericptr); +staticfn int QSORTCALLBACK notice_mons_cmp(const genericptr, + const genericptr) NONNULLPTRS; staticfn schar u_simple_floortyp(coordxy, coordxy); staticfn boolean swim_move_danger(coordxy, coordxy); staticfn boolean domove_bump_mon(struct monst *, int) NONNULLARG1; @@ -43,7 +45,7 @@ staticfn boolean doorless_door(coordxy, coordxy); staticfn void maybe_wail(void); staticfn boolean water_turbulence(coordxy *, coordxy *); -#define IS_SHOP(x) (gr.rooms[x].rtype >= SHOPBASE) +#define IS_SHOP(x) (svr.rooms[x].rtype >= SHOPBASE) /* XXX: if more sources of water walking than just boots are added, cause_known(insight.c) should be externified and used for this */ @@ -100,7 +102,7 @@ revive_nasty(coordxy x, coordxy y, const char *msg) coord cc; boolean revived = FALSE; - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp2) { + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (otmp->otyp == CORPSE && (is_rider(&mons[otmp->corpsenm]) @@ -152,6 +154,15 @@ could_move_onto_boulder(coordxy sx, coordxy sy) return squeezeablylightinvent(); } +staticfn void +moverock_done(coordxy sx, coordxy sy) +{ + struct obj *otmp; + for (otmp = svl.level.objects[sx][sy]; otmp; otmp = otmp->nexthere) + if (otmp->otyp == BOULDER) + otmp->next_boulder = 0; /* resume normal xname() for this obj */ +} + staticfn int moverock(void) { @@ -161,7 +172,6 @@ moverock(void) struct monst *mtmp, *shkp; const char *what; boolean costly, firstboulder = TRUE; - int res = 0; sx = u.ux + u.dx, sy = u.uy + u.dy; /* boulder starting position */ while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) { @@ -170,8 +180,8 @@ moverock(void) pline("That feels like a boulder."); map_object(otmp, TRUE); nomul(0); - res = -1; - goto moverock_done; + moverock_done(sx, sy); + return -1; } /* when otmp->next_boulder is 1, xname() will format it as @@ -184,7 +194,7 @@ moverock(void) firstboulder = FALSE; /* make sure that this boulder is visible as the top object */ - if (otmp != gl.level.objects[sx][sy]) + if (otmp != svl.level.objects[sx][sy]) movobj(otmp, sx, sy); rx = u.ux + 2 * u.dx; /* boulder destination position */ @@ -195,8 +205,9 @@ moverock(void) poly'd into a giant or squeezes under/beside it if small/light enough but is a no-op in other circumstances unless move attempt reveals an unseen boulder or lack of remembered, unseen monster */ - if (gc.context.nopick) { + if (svc.context.nopick) { int oldglyph = glyph_at(sx, sy); /* before feel_location() */ + int res; feel_location(sx, sy); /* same for all 3 if/else-if/else cases */ if (throws_rocks(gy.youmonst.data)) { @@ -218,10 +229,11 @@ moverock(void) /* use a move if hero learns something; see test_move() for how/why 'context.door_opened' is being dragged into this */ if (glyph_at(sx, sy) != oldglyph) - gc.context.door_opened = gc.context.move = TRUE; + svc.context.door_opened = svc.context.move = TRUE; res = -1; /* don't move to , so no soko guilt */ } - goto moverock_done; /* stop further push attempts */ + moverock_done(sx, sy); /* stop further push attempts */ + return res; } if (Levitation || Is_airlevel(&u.uz)) { /* FIXME? behavior in an air bubble on the water level should @@ -232,8 +244,8 @@ moverock(void) feel_location(sx, sy); You("don't have enough leverage to push %s.", the(xname(otmp))); /* Give them a chance to climb over it? */ - res = -1; - goto moverock_done; + moverock_done(sx, sy); + return -1; } if (verysmall(gy.youmonst.data) && !u.usteed) { if (Blind) @@ -261,8 +273,8 @@ moverock(void) if (revive_nasty(rx, ry, "You sense movement on the other side.")) { - res = -1; - goto moverock_done; + moverock_done(sx, sy); + return -1; } if (mtmp && !noncorporeal(mtmp->data) @@ -307,6 +319,7 @@ moverock(void) if (ttmp) { int newlev = 0; /* lint suppression */ d_level dest; + int res; /* if a trap operates on the boulder, don't attempt to move any others at this location; return -1 @@ -336,7 +349,8 @@ moverock(void) if (cansee(rx, ry)) newsym(rx, ry); res = sobj_at(BOULDER, sx, sy) ? -1 : 0; - goto moverock_done; + moverock_done(sx, sy); + return res; } break; case SPIKED_PIT: @@ -353,7 +367,8 @@ moverock(void) if (mtmp && !Blind) newsym(rx, ry); res = sobj_at(BOULDER, sx, sy) ? -1 : 0; - goto moverock_done; + moverock_done(sx, sy); + return res; case HOLE: case TRAPDOOR: Soundeffect(se_kerplunk_boulder_gone, 40); @@ -377,7 +392,8 @@ moverock(void) if (cansee(rx, ry)) newsym(rx, ry); res = sobj_at(BOULDER, sx, sy) ? -1 : 0; - goto moverock_done; + moverock_done(sx, sy); + return res; case LEVEL_TELEP: /* 20% chance of picking current level; 100% chance for that if in single-level branch (Knox) or in endgame */ @@ -389,7 +405,7 @@ moverock(void) case TELEP_TRAP: if (u.usteed) pline("%s pushes %s and suddenly it disappears!", - upstart(y_monnam(u.usteed)), the(xname(otmp))); + YMonnam(u.usteed), the(xname(otmp))); else You("push %s and suddenly it disappears!", the(xname(otmp))); @@ -408,7 +424,8 @@ moverock(void) } seetrap(ttmp); res = sobj_at(BOULDER, sx, sy) ? -1 : 0; - goto moverock_done; + moverock_done(sx, sy); + return res; default: break; /* boulder not affected by this trap */ } @@ -435,11 +452,11 @@ moverock(void) unlike with Norep(), intervening messages don't cause it to repeat, only doing something else in the meantime */ if (otmp->o_id != gb.bldrpush_oid) { - gb.bldrpushtime = gm.moves + 1L; + gb.bldrpushtime = svm.moves + 1L; gb.bldrpush_oid = otmp->o_id; } - givemesg = (gm.moves > gb.bldrpushtime + 2L - || gm.moves < gb.bldrpushtime); + givemesg = (svm.moves > gb.bldrpushtime + 2L + || svm.moves < gb.bldrpushtime); what = givemesg ? the(xname(otmp)) : 0; if (!u.usteed) { easypush = throws_rocks(gy.youmonst.data); @@ -450,10 +467,9 @@ moverock(void) exercise(A_STR, TRUE); } else { if (givemesg) - pline("%s moves %s.", - upstart(y_monnam(u.usteed)), what); + pline("%s moves %s.", YMonnam(u.usteed), what); } - gb.bldrpushtime = gm.moves; + gb.bldrpushtime = svm.moves; } /* Move the boulder *after* the message. */ @@ -467,13 +483,24 @@ moverock(void) } else { newsym(sx, sy); } - /* maybe adjust bill if boulder was pushed across shop boundary */ + /* maybe adjust bill if boulder was pushed across shop boundary; + normally otmp->unpaid would not apply because otmp isn't in + hero's inventory, but addtobill() sets it and subfrombill() + clears it */ if (costly && !costly_spot(rx, ry)) { + /* pushing from inside shop to its boundary (or free spot) */ addtobill(otmp, FALSE, FALSE, FALSE); } else if (!costly && costly_spot(rx, ry) && otmp->unpaid && ((shkp = shop_keeper(*in_rooms(rx, ry, SHOPBASE))) != 0) && onshopbill(otmp, shkp, TRUE)) { + /* this can happen if hero pushes boulder from farther inside + shop into shop's free spot (which will add it to the bill), + then teleports or Passes_walls to doorway (without exiting + the shop), and then pushes the boulder from the free spot + back into the shop; it's contingent upon the shopkeeper not + "muttering an incantation" to fracture the boulder while it + is unpaid at the free spot */ subfrombill(otmp, shkp); } else if (otmp->unpaid && (shkp = find_objowner(otmp, sx, sy)) != 0 @@ -489,7 +516,7 @@ moverock(void) what = the(xname(otmp)); if (u.usteed) pline("%s tries to move %s, but cannot.", - upstart(y_monnam(u.usteed)), what); + YMonnam(u.usteed), what); else You("try to move %s, but in vain.", what); if (Blind) @@ -506,7 +533,7 @@ moverock(void) && (inv_cnt(FALSE) < invlet_basic || !carrying(BOULDER))), willpickup = (canpickup - && (flags.pickup && !gc.context.nopick) + && (flags.pickup && !svc.context.nopick) && autopick_testobj(otmp, TRUE)); if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { @@ -531,30 +558,25 @@ moverock(void) Sokoban rules because on next step you could go past it without pushing it to plug a pit or hole */ sokoban_guilt(); - break; } - break; + moverock_done(sx, sy); + return 0; } if (could_move_onto_boulder(sx, sy)) { pline( "However, you can squeeze yourself into a small opening."); sokoban_guilt(); - break; + moverock_done(sx, sy); + return 0; } else { - res = -1; - goto moverock_done; + moverock_done(sx, sy); + return -1; } } } - res = 0; - - moverock_done: - for (otmp = gl.level.objects[sx][sy]; otmp; otmp = otmp->nexthere) - if (otmp->otyp == BOULDER) - otmp->next_boulder = 0; /* resume normal xname() for this obj */ - - return res; + moverock_done(sx, sy); + return 0; } /* @@ -570,8 +592,8 @@ still_chewing(coordxy x, coordxy y) struct obj *boulder = sobj_at(BOULDER, x, y); const char *digtxt = (char *) 0, *dmgtxt = (char *) 0; - if (gc.context.digging.down) /* not continuing previous dig (w/ pick-axe) */ - (void) memset((genericptr_t) &gc.context.digging, 0, + if (svc.context.digging.down) /* not continuing prev dig (w/ pick-axe) */ + (void) memset((genericptr_t) &svc.context.digging, 0, sizeof (struct dig_info)); if (!boulder @@ -592,18 +614,18 @@ still_chewing(coordxy x, coordxy y) You("are too full to eat the bars."); nomul(0); return 1; - } else if (!gc.context.digging.chew - || gc.context.digging.pos.x != x - || gc.context.digging.pos.y != y - || !on_level(&gc.context.digging.level, &u.uz)) { - gc.context.digging.down = FALSE; - gc.context.digging.chew = TRUE; - gc.context.digging.warned = FALSE; - gc.context.digging.pos.x = x; - gc.context.digging.pos.y = y; - assign_level(&gc.context.digging.level, &u.uz); + } else if (!svc.context.digging.chew + || svc.context.digging.pos.x != x + || svc.context.digging.pos.y != y + || !on_level(&svc.context.digging.level, &u.uz)) { + svc.context.digging.down = FALSE; + svc.context.digging.chew = TRUE; + svc.context.digging.warned = FALSE; + svc.context.digging.pos.x = x; + svc.context.digging.pos.y = y; + assign_level(&svc.context.digging.level, &u.uz); /* solid rock takes more work & time to dig through */ - gc.context.digging.effort = + svc.context.digging.effort = (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc; You("start chewing %s %s.", (boulder || IS_TREE(lev->typ) || lev->typ == IRONBARS) @@ -620,10 +642,10 @@ still_chewing(coordxy x, coordxy y) : "door"); watch_dig((struct monst *) 0, x, y, FALSE); return 1; - } else if ((gc.context.digging.effort += (30 + u.udaminc)) <= 100) { + } else if ((svc.context.digging.effort += (30 + u.udaminc)) <= 100) { if (flags.verbose) You("%s chewing on the %s.", - gc.context.digging.chew ? "continue" : "begin", + svc.context.digging.chew ? "continue" : "begin", boulder ? "boulder" : IS_TREE(lev->typ) @@ -633,7 +655,7 @@ still_chewing(coordxy x, coordxy y) : (lev->typ == IRONBARS) ? "bars" : "door"); - gc.context.digging.chew = TRUE; + svc.context.digging.chew = TRUE; watch_dig((struct monst *) 0, x, y, FALSE); return 1; } @@ -664,7 +686,7 @@ still_chewing(coordxy x, coordxy y) || sobj_at(BOULDER, x, y)) { block_point(x, y); /* delobj will unblock the point */ /* reset dig state */ - (void) memset((genericptr_t) &gc.context.digging, 0, + (void) memset((genericptr_t) &svc.context.digging, 0, sizeof (struct dig_info)); return 1; } @@ -675,9 +697,9 @@ still_chewing(coordxy x, coordxy y) dmgtxt = "damage"; } digtxt = "chew a hole in the wall."; - if (gl.level.flags.is_maze_lev) { + if (svl.level.flags.is_maze_lev) { lev->typ = ROOM; - } else if (gl.level.flags.is_cavernous_lev && !in_town(x, y)) { + } else if (svl.level.flags.is_cavernous_lev && !in_town(x, y)) { lev->typ = CORR; } else { lev->typ = DOOR; @@ -736,7 +758,7 @@ still_chewing(coordxy x, coordxy y) You1(digtxt); /* after newsym */ if (dmgtxt) pay_for_damage(dmgtxt, FALSE); - (void) memset((genericptr_t) &gc.context.digging, 0, + (void) memset((genericptr_t) &svc.context.digging, 0, sizeof (struct dig_info)); return 0; } @@ -784,7 +806,7 @@ dosinkfall(void) losehp(Maybe_Half_Phys(dmg), fell_on_sink, NO_KILLER_PREFIX); exercise(A_DEX, FALSE); selftouch("Falling, you"); - for (obj = gl.level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) + for (obj = svl.level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) { You("fell on %s.", doname(obj)); losehp(Maybe_Half_Phys(rnd(3)), fell_on_sink, @@ -902,7 +924,7 @@ boolean invocation_pos(coordxy x, coordxy y) { return (boolean) (Invocation_lev(&u.uz) - && x == gi.inv_pos.x && y == gi.inv_pos.y); + && x == svi.inv_pos.x && y == svi.inv_pos.y); } /* return TRUE if (dx,dy) is an OK place to move; @@ -918,7 +940,7 @@ test_move( struct rm *tmpr = &levl[x][y]; struct rm *ust; - gc.context.door_opened = FALSE; + svc.context.door_opened = FALSE; /* * Check for physical obstacles. First, the place we are going. */ @@ -948,11 +970,12 @@ test_move( You("cannot pass through the bars."); return FALSE; } - } else if (tunnels(gy.youmonst.data) && !needspick(gy.youmonst.data)) { + } else if (tunnels(gy.youmonst.data) + && !needspick(gy.youmonst.data)) { /* Eat the rock. */ if (mode == DO_MOVE && still_chewing(x, y)) return FALSE; - } else if (flags.autodig && !gc.context.run && !gc.context.nopick + } else if (flags.autodig && !svc.context.run && !svc.context.nopick && uwep && is_pick(uwep)) { /* MRKR: Automatic digging when wielding the appropriate tool */ if (mode == DO_MOVE) @@ -960,25 +983,25 @@ test_move( return FALSE; } else { if (mode == DO_MOVE) { - if (is_db_wall(x, y)) + if (is_db_wall(x, y)) { pline("That drawbridge is up!"); - /* sokoban restriction stays even after puzzle is solved */ - else if (Passes_walls && !may_passwall(x, y) - && In_sokoban(&u.uz)) + } else if (Passes_walls && !may_passwall(x, y) + && In_sokoban(&u.uz)) { + /* soko restriction stays even after puzzle is solved */ pline_The("Sokoban walls resist your ability."); - else if (flags.mention_walls) { + } else if (flags.mention_walls) { char buf[BUFSZ]; - coord cc; - int sym = 0; - const char *firstmatch = 0; + int glyph = back_to_glyph(x, y), + sym = glyph_is_cmap(glyph) ? glyph_to_cmap(glyph) + : -1; - cc.x = x, cc.y = y; - do_screen_description(cc, TRUE, sym, buf, &firstmatch, - NULL); - if (!strcmp(firstmatch, "stone")) - Sprintf(buf, "solid stone"); + if (sym == S_stone) + Strcpy(buf, "solid stone"); + else if (sym >= 0) + Strcpy(buf, an(defsyms[sym].explanation)); else - Sprintf(buf, "%s", an(firstmatch)); + Sprintf(buf, "impossible [background glyph=%d]", + glyph); pline_dir(xytod(dx, dy), "It's %s.", buf); } } @@ -1007,10 +1030,10 @@ test_move( if (amorphous(gy.youmonst.data)) You("try to ooze under the door," " but can't squeeze your possessions through."); - if (flags.autoopen && !gc.context.run + if (flags.autoopen && !svc.context.run && !Confusion && !Stunned && !Fumbling) { - gc.context.door_opened - = gc.context.move + svc.context.door_opened + = svc.context.move = (doopen_indir(x, y) == ECMD_TIME ? 1 : 0); } else if (x == ux || y == uy) { if (Blind || Stunned || ACURR(A_DEX) < 10 @@ -1027,7 +1050,7 @@ test_move( we haven't opened a door but we're going to return False and without having 'door_opened' set, 'move' would get reset by caller */ - gc.context.door_opened = gc.context.move = TRUE; + svc.context.door_opened = svc.context.move = TRUE; /* since we've just lied about successfully moving, we need to manually stop running */ nomul(0); @@ -1075,13 +1098,13 @@ test_move( } else if (dx && dy && worm_cross(ux, uy, x, y)) { /* consecutive long worm segments are at and */ if (mode == DO_MOVE) - pline("%s is in your way.", Monnam(m_at(ux, y))); + pline("%s is in your way.", YMonnam(m_at(ux, y))); return FALSE; } /* Pick travel path that does not require crossing a trap. * Avoid water and lava using the usual running rules. * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */ - if (gc.context.run == 8 && (mode != DO_MOVE) && !u_at(x, y)) { + if (svc.context.run == 8 && (mode != DO_MOVE) && !u_at(x, y)) { struct trap *t = t_at(x, y); if (t && t->tseen && t->ttyp != VIBRATING_SQUARE) @@ -1117,7 +1140,7 @@ test_move( } if (sobj_at(BOULDER, x, y) && (Sokoban || !Passes_walls)) { - if (mode != TEST_TRAV && gc.context.run >= 2 + if (mode != TEST_TRAV && svc.context.run >= 2 && !(Blind || Hallucination) && !could_move_onto_boulder(x, y)) { if (mode == DO_MOVE && flags.mention_walls) pline_dir(xytod(dx,dy), "A boulder blocks your path."); @@ -1171,7 +1194,7 @@ findtravelpath(int mode) if (!gt.travelmap) gt.travelmap = selection_new(); /* if travel to adjacent, reachable location, use normal movement rules */ - if ((mode == TRAVP_TRAVEL || mode == TRAVP_VALID) && gc.context.travel1 + if ((mode == TRAVP_TRAVEL || mode == TRAVP_VALID) && svc.context.travel1 /* was '&& distmin(u.ux, u.uy, u.tx, u.ty) == 1' */ && next2u(u.tx, u.ty) /* one step away */ /* handle restricted diagonals */ @@ -1187,7 +1210,7 @@ findtravelpath(int mode) return TRUE; } if (mode == TRAVP_TRAVEL) - gc.context.run = 8; + svc.context.run = 8; } if (u.tx != u.ux || u.ty != u.uy) { coordxy travel[COLNO][ROWNO]; @@ -1300,22 +1323,24 @@ findtravelpath(int mode) || (!Blind && couldsee(nx, ny)))) { if (nx == ux && ny == uy) { if (mode == TRAVP_TRAVEL || mode == TRAVP_VALID) { - boolean visited = - selection_getpoint(x, y, gt.travelmap); + boolean visited + = selection_getpoint(x, y, gt.travelmap); u.dx = x - ux; u.dy = y - uy; if (mode == TRAVP_TRAVEL - && ((x == u.tx && y == u.ty) || visited)) { + && ((x == u.tx && y == u.ty) + || visited)) { nomul(0); /* reset run so domove run checks work */ - gc.context.run = 8; + svc.context.run = 8; if (visited) You("stop, unsure which way to go."); else iflags.travelcc.x = iflags.travelcc.y = 0; } - selection_setpoint(u.ux, u.uy, gt.travelmap, 1); + selection_setpoint(u.ux, u.uy, + gt.travelmap, 1); return TRUE; } } else if (!travel[nx][ny]) { @@ -1669,7 +1694,8 @@ notice_all_mons(boolean reset) } if (i) { - qsort((genericptr_t) arr, (size_t) i, sizeof *arr, notice_mons_cmp); + qsort((genericptr_t) arr, (size_t) i, sizeof *arr, + notice_mons_cmp); for (j = 0; j < i; j++) notice_mon(arr[j]); @@ -1697,7 +1723,7 @@ disturb_buried_zombies(coordxy x, coordxy y) struct obj *otmp; long t; - for (otmp = gl.level.buriedobjlist; otmp; otmp = otmp->nobj) { + for (otmp = svl.level.buriedobjlist; otmp; otmp = otmp->nobj) { if (otmp->otyp == CORPSE && otmp->timed && otmp->ox >= x - 1 && otmp->ox <= x + 1 && otmp->oy >= y - 1 && otmp->oy <= y + 1 @@ -1746,8 +1772,8 @@ handle_tip(int tip) if (!flags.tips) return; - if (tip >= 0 && tip < NUM_TIPS && !gc.context.tips[tip]) { - gc.context.tips[tip] = TRUE; + if (tip >= 0 && tip < NUM_TIPS && !svc.context.tips[tip]) { + svc.context.tips[tip] = TRUE; switch (tip) { case TIP_ENHANCE: pline("(Use the #enhance command to advance them.)"); @@ -1794,9 +1820,9 @@ swim_move_danger(coordxy x, coordxy y) continue to move over lava if already doing so */ || (is_lava(x, y) && !Known_lwalking && !is_lava(u.ux, u.uy)) || liquid_wall) { - if (gc.context.nopick) { + if (svc.context.nopick) { /* moving with m-prefix */ - gc.context.tips[TIP_SWIM] = TRUE; + svc.context.tips[TIP_SWIM] = TRUE; return FALSE; } else if (ParanoidSwim || liquid_wall) { You("avoid %s into the %s.", @@ -1821,7 +1847,7 @@ domove_bump_mon(struct monst *mtmp, int glyph) * attack_check(), which still wastes a turn, but prints a * different message and makes the player remember the monster. */ - if (gc.context.nopick && !gc.context.travel + if (svc.context.nopick && !svc.context.travel && (canspotmon(mtmp) || glyph_is_invisible(glyph) || glyph_is_warning(glyph))) { if (M_AP_TYPE(mtmp) && !Protection_from_shape_changers @@ -1855,7 +1881,7 @@ domove_attackmon_at( * This is different from ceiling hiders, who aren't handled in * do_attack(). */ - if (gc.context.forcefight || !mtmp->mundetected || sensemon(mtmp) + if (svc.context.forcefight || !mtmp->mundetected || sensemon(mtmp) || ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) && !is_safemon(mtmp))) { /* target monster might decide to switch places with you... */ @@ -1883,7 +1909,7 @@ domove_attackmon_at( staticfn boolean domove_fight_ironbars(coordxy x, coordxy y) { - if (gc.context.forcefight && levl[x][y].typ == IRONBARS && uwep) { + if (svc.context.forcefight && levl[x][y].typ == IRONBARS && uwep) { struct obj *obj = uwep; unsigned breakflags = (BRK_BY_HERO | BRK_FROM_INV | BRK_MELEE); @@ -1910,7 +1936,7 @@ domove_fight_web(coordxy x, coordxy y) { struct trap *trap = t_at(x, y); - if (gc.context.forcefight && trap && trap->ttyp == WEB && trap->tseen) { + if (svc.context.forcefight && trap && trap->ttyp == WEB && trap->tseen) { int wtype = uwep_skill_type(), /* minus_2: restricted or unskilled: -1, basic: 0, skilled: 1, expert: 2, master: 3, grandmaster: 4 */ @@ -2009,20 +2035,20 @@ domove_swap_with_pet(struct monst *mtmp, coordxy x, coordxy y) didnt_move = TRUE; } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) { /* can't swap places when pet can't move to your spot */ - You("stop. %s can't move diagonally.", upstart(y_monnam(mtmp))); + You("stop. %s can't move diagonally.", YMonnam(mtmp)); didnt_move = TRUE; } else if (u_with_boulder && !(verysmall(mtmp->data) && (!mtmp->minvent || curr_mon_load(mtmp) <= 600))) { /* can't swap places when pet won't fit there with the boulder */ You("stop. %s won't fit into the same spot that you're at.", - upstart(y_monnam(mtmp))); + YMonnam(mtmp)); didnt_move = TRUE; } else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0) && bad_rock(mtmp->data, u.ux0, y) && (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { /* can't swap places when pet won't fit thru the opening */ - You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); + You("stop. %s won't fit through.", YMonnam(mtmp)); didnt_move = TRUE; } else if (mtmp->mpeaceful && mtmp->mtrapped) { /* all mtame are also mpeaceful, so this affects pets too */ @@ -2034,8 +2060,7 @@ domove_swap_with_pet(struct monst *mtmp, coordxy x, coordxy y) feeltrap(trap); /* show on map once mtmp is out of the way */ which = just_an(anbuf, what); /* "a " or "an " */ } - You("stop. %s can't move out of %s%s.", - upstart(y_monnam(mtmp)), which, what); + You("stop. %s can't move out of %s%s.", YMonnam(mtmp), which, what); handle_tip(TIP_UNTRAP_MON); didnt_move = TRUE; } else if (mtmp->mpeaceful @@ -2043,9 +2068,8 @@ domove_swap_with_pet(struct monst *mtmp, coordxy x, coordxy y) || t_at(u.ux0, u.uy0) != NULL || mundisplaceable(mtmp))) { /* displacing peaceful into unsafe or trapped space, or trying to - displace quest leader, Oracle, shopkeeper, priest, or vault guard */ - You("stop. %s doesn't want to swap places.", - upstart(y_monnam(mtmp))); + displace quest leader, Oracle, shk, priest, or vault guard */ + You("stop. %s doesn't want to swap places.", YMonnam(mtmp)); didnt_move = TRUE; } else { mtmp->mtrapped = 0; @@ -2089,7 +2113,7 @@ domove_swap_with_pet(struct monst *mtmp, coordxy x, coordxy y) if (!u.uconduct.killer++) livelog_printf(LL_CONDUCT, "killed for the first time"); mndx = monsndx(mtmp->data); - tmp = experience(mtmp, (int) gm.mvitals[mndx].died); + tmp = experience(mtmp, (int) svm.mvitals[mndx].died); more_experienced(tmp, 0); newexplevel(); /* will decide if you go up */ } @@ -2127,9 +2151,10 @@ domove_fight_empty(coordxy x, coordxy y) * because m_at() might find a vault guard there */ /* specifying 'F' with no monster wastes a turn */ - if (gc.context.forcefight + if (svc.context.forcefight /* remembered an 'I' && didn't use a move command */ - || (glyph_is_invisible(glyph) && !m_at(x, y) && !gc.context.nopick)) { + || (glyph_is_invisible(glyph) && !m_at(x, y) + && !svc.context.nopick)) { struct obj *boulder = 0; boolean explo = (Upolyd && attacktype(gy.youmonst.data, AT_EXPL)), solid = (off_edge || (!accessible(x, y) @@ -2153,7 +2178,7 @@ domove_fight_empty(coordxy x, coordxy y) /* force fight at boulder/statue or wall/door while wielding pick: start digging to break the boulder or wall */ - if (gc.context.forcefight + if (svc.context.forcefight /* can we dig? */ && uwep && dig_typ(uwep, x, y) /* should we dig? */ @@ -2209,7 +2234,7 @@ domove_fight_empty(coordxy x, coordxy y) nomul(0); if (explo) { struct attack *attk - = attacktype_fordmg(gy.youmonst.data, AT_EXPL, AD_ANY); + = attacktype_fordmg(gy.youmonst.data, AT_EXPL, AD_ANY); /* no monster has been attacked so we have bypassed explum() */ wake_nearto(u.ux, u.uy, 7 * 7); /* same radius as explum() */ @@ -2353,8 +2378,8 @@ avoid_moving_on_liquid( if ((levl[x][y].typ == levl[u.ux][u.uy].typ /* or you are using shift-dir running and the transition isn't dangerous... */ - || (gc.context.run < 2 && (!is_lava(x, y) || in_air)) - || gc.context.travel) + || (svc.context.run < 2 && (!is_lava(x, y) || in_air)) + || svc.context.travel) /* and you know you won't fall in */ && (in_air || Known_lwalking || (is_pool(x, y) && Known_wwalking)) && !(IS_WATERWALL(levl[x][y].typ) || levl[x][y].typ == LAVAWALL)) { @@ -2377,15 +2402,15 @@ avoid_moving_on_liquid( staticfn boolean avoid_running_into_trap_or_liquid(coordxy x, coordxy y) { - boolean would_stop = (gc.context.run >= 2); - if (!gc.context.run) + boolean would_stop = (svc.context.run >= 2); + if (!svc.context.run) return FALSE; if (avoid_moving_on_trap(x,y, would_stop) || (Blind && avoid_moving_on_liquid(x,y, would_stop))) { nomul(0); if (would_stop) - gc.context.move = 0; + svc.context.move = 0; return would_stop; } return FALSE; @@ -2396,7 +2421,7 @@ staticfn boolean move_out_of_bounds(coordxy x, coordxy y) { if (!isok(x, y)) { - if (gc.context.forcefight) + if (svc.context.forcefight) return domove_fight_empty(x, y); if (flags.mention_walls) { @@ -2415,7 +2440,7 @@ move_out_of_bounds(coordxy x, coordxy y) directionname(xytod(dx, dy))); } nomul(0); - gc.context.move = 0; + svc.context.move = 0; return TRUE; } return FALSE; @@ -2460,7 +2485,7 @@ escape_from_sticky_mon(coordxy x, coordxy y) */ mtmp = u.ustuck; set_ustuck((struct monst *) 0); - You("release %s.", mon_nam(mtmp)); + You("release %s.", y_monnam(mtmp)); } else { /* If holder is asleep or paralyzed: * 37.5% chance of getting away, @@ -2478,7 +2503,7 @@ escape_from_sticky_mon(coordxy x, coordxy y) pull_free: mtmp = u.ustuck; set_ustuck((struct monst *) 0); - You("pull free from %s.", mon_nam(mtmp)); + You("pull free from %s.", y_monnam(mtmp)); break; case 3: if (!u.ustuck->mcanmove) { @@ -2490,7 +2515,7 @@ escape_from_sticky_mon(coordxy x, coordxy y) default: if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) goto pull_free; - You("cannot escape from %s!", mon_nam(u.ustuck)); + You("cannot escape from %s!", y_monnam(u.ustuck)); nomul(0); return TRUE; } @@ -2521,19 +2546,20 @@ domove_core(void) { struct monst *mtmp; struct rm *tmpr; + NhRegion *newreg, *oldreg; coordxy x, y; struct trap *trap = NULL; int glyph; coordxy chainx = 0, chainy = 0, - ballx = 0, bally = 0; /* ball&chain new positions */ + ballx = 0, bally = 0; /* ball&chain new positions */ int bc_control = 0; /* control for ball&chain */ boolean cause_delay = FALSE, /* dragging ball will skip a move */ displaceu = FALSE; /* involuntary swap */ - if (gc.context.travel) { + if (svc.context.travel) { if (!findtravelpath(TRAVP_TRAVEL)) (void) findtravelpath(TRAVP_GUESS); - gc.context.travel1 = 0; + svc.context.travel1 = 0; } if (carrying_too_much()) @@ -2574,13 +2600,13 @@ domove_core(void) /* Don't attack if you're running, and can see it */ /* It's fine to displace pets, though */ /* We should never get here if forcefight */ - if (gc.context.run && ((!Blind && mon_visible(mtmp) + if (svc.context.run && ((!Blind && mon_visible(mtmp) && ((M_AP_TYPE(mtmp) != M_AP_FURNITURE && M_AP_TYPE(mtmp) != M_AP_OBJECT) || Protection_from_shape_changers)) || sensemon(mtmp))) { nomul(0); - gc.context.move = 0; + svc.context.move = 0; return; } } @@ -2597,7 +2623,7 @@ domove_core(void) /* don't stop travel when displacing pets; if the displace fails for some reason, do_attack() in uhitm.c will stop travel rather than domove */ - if (!is_safemon(mtmp) || gc.context.forcefight) + if (!is_safemon(mtmp) || svc.context.forcefight) nomul(0); if (domove_bump_mon(mtmp, glyph)) @@ -2627,11 +2653,47 @@ domove_core(void) if (u_rooted()) return; - /* maybe ask player for confirmation before walking into known traps */ - if (ParanoidTrap && (trap = t_at(x, y)) != 0 && trap->tseen - && (!gc.context.nopick || gc.context.run) - && !Stunned && !Confusion + /* treat entering a visible gas cloud region like entering a trap; + there could be a known trap as well as a region at the target spot; + if so, ask about entring the region first; even though this could + lead to two consecutive confirmation prompts, the situation seems to + be too uncommon to warrant a separate case with combined trap+region + confirmation */ + if (ParanoidTrap && !Blind && !Stunned && !Confusion && !Hallucination + /* skip if player used 'm' prefix or is moving recklessly */ + && (!svc.context.nopick || svc.context.run) + /* check for region(s) */ + && (newreg = visible_region_at(x, y)) != 0 + && ((oldreg = visible_region_at(u.ux, u.uy)) == 0 + /* if moving from one region into another, only ask for + confirmation if the one potentially being entered inflicts + damage (poison gas) and the one being exited doesn't (vapor) */ + || (reg_damg(newreg) > 0 && reg_damg(oldreg) == 0)) + /* check whether attempted move will be viable */ && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) + /* we don't override confirmation for poison resistance since the + region also hinders hero's vision even if/when no damage is done */ + ) { + char qbuf[QBUFSZ]; + + Snprintf(qbuf, sizeof qbuf, "%s into that %s cloud?", + locomotion(gy.youmonst.data, "step"), + (reg_damg(newreg) > 0) ? "poison gas" : "vapor"); + if (!paranoid_query(ParanoidConfirm, upstart(qbuf))) { + nomul(0); + svc.context.move = 0; + return; + } + } + /* maybe ask player for confirmation before walking into known traps */ + if (ParanoidTrap && !Stunned && !Confusion + /* skip if player used 'm' prefix or is moving recklessly */ + && (!svc.context.nopick || svc.context.run) + /* check for discovered trap */ + && (trap = t_at(x, y)) != 0 && trap->tseen + /* check whether attempted move will be viable */ + && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) + /* override confirmation if the trap is harmless to the hero */ && (immune_to_trap(&gy.youmonst, trap->ttyp) != TRAP_CLEARLY_IMMUNE /* Hallucination: all traps still show as ^, but the hero can't tell what they are, so treat as dangerous */ @@ -2662,7 +2724,7 @@ domove_core(void) yes/no if it is */ if (!paranoid_query(ParanoidConfirm, qbuf)) { nomul(0); - gc.context.move = 0; + svc.context.move = 0; return; } } @@ -2680,8 +2742,8 @@ domove_core(void) } if (!test_move(u.ux, u.uy, x - u.ux, y - u.uy, DO_MOVE)) { - if (!gc.context.door_opened) { - gc.context.move = 0; + if (!svc.context.door_opened) { + svc.context.move = 0; nomul(0); } return; @@ -2689,7 +2751,7 @@ domove_core(void) /* Is it dangerous to swim in water or lava? */ if (swim_move_danger(x, y)) { - gc.context.move = 0; + svc.context.move = 0; nomul(0); return; } @@ -2722,7 +2784,8 @@ domove_core(void) if (mtmp) { if (displaceu) { - boolean noticed_it = (canspotmon(mtmp) || glyph_is_invisible(glyph) + boolean noticed_it = (canspotmon(mtmp) + || glyph_is_invisible(glyph) || glyph_is_warning(glyph)); remove_monster(u.ux, u.uy); @@ -2733,15 +2796,15 @@ domove_core(void) mtmp->mux = u.ux, mtmp->muy = u.uy; pline("%s swaps places with you...", - !noticed_it ? Something : Monnam(mtmp)); + !noticed_it ? Something : YMonnam(mtmp)); if (!canspotmon(mtmp)) map_invisible(u.ux0, u.uy0); /* monster chose to swap places; hero doesn't get any credit or blame if something bad happens to it */ - gc.context.mon_moving = 1; + svc.context.mon_moving = 1; if (!minliquid(mtmp)) (void) mintrap(mtmp, NO_TRAP_FLAGS); - gc.context.mon_moving = 0; + svc.context.mon_moving = 0; /* * If safepet at destination then move the pet to the hero's @@ -2757,7 +2820,7 @@ domove_core(void) && !(is_hider(mtmp->data) && mtmp->mundetected)) { if (!domove_swap_with_pet(mtmp, x, y)) { u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ - /* could skip this bit since we're about to call u_on_newpos() */ + /* could skip this since we're about to call u_on_newpos() */ if (u.usteed) u.usteed->mx = u.ux, u.usteed->my = u.uy; } @@ -2770,8 +2833,8 @@ domove_core(void) u_on_newpos(u.ux, u.uy); reset_occupations(); - if (gc.context.run) { - if (gc.context.run < 8) + if (svc.context.run) { + if (svc.context.run < 8) if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) || IS_FURNITURE(tmpr->typ)) nomul(0); @@ -2831,13 +2894,13 @@ domove_core(void) void runmode_delay_output(void) { - if ((gc.context.run || gm.multi) && flags.runmode != RUN_TPORT) { + if ((svc.context.run || gm.multi) && flags.runmode != RUN_TPORT) { /* for tport mode, don't display anything until we've stopped; for normal (leap) mode, update display every 7th step (relative to turn counter; ought to be to start of running); for walk and crawl (visual debugging) modes, update the display after every step */ - if (flags.runmode != RUN_LEAP || !(gm.moves % 7L)) { + if (flags.runmode != RUN_LEAP || !(svm.moves % 7L)) { /* moveloop() suppresses time_botl when running */ disp.time_botl = flags.time; curs_on_u(); @@ -2890,7 +2953,7 @@ overexertion(void) position, but is now called by do_attack() so that it doesn't execute if you decline to attack a peaceful monster */ gethungry(); - if ((gm.moves % 3L) != 0L && near_capacity() >= HVY_ENCUMBER) { + if ((svm.moves % 3L) != 0L && near_capacity() >= HVY_ENCUMBER) { overexert_hp(); } return (boolean) (gm.multi < 0); /* might have fainted (forced to sleep) */ @@ -3222,7 +3285,7 @@ staticfn boolean furniture_present(int furniture, int roomno) { int x, y, lx, ly, hx, hy; - struct mkroom *sroom = &gr.rooms[roomno]; + struct mkroom *sroom = &svr.rooms[roomno]; ly = sroom->ly, hy = sroom->hy; lx = sroom->lx; hx = sroom->hx; @@ -3244,7 +3307,7 @@ in_rooms(coordxy x, coordxy y, int typewanted) #define goodtype(rno) \ (!typewanted \ - || (typefound = gr.rooms[rno - ROOMOFFSET].rtype) == typewanted \ + || (typefound = svr.rooms[rno - ROOMOFFSET].rtype) == typewanted \ || (typewanted == SHOPBASE && typefound > SHOPBASE)) switch (rno = levl[x][y].roomno) { @@ -3306,14 +3369,14 @@ in_town(coordxy x, coordxy y) struct mkroom *sroom; boolean has_subrooms = FALSE; - if (!gl.level.flags.has_town) + if (!svl.level.flags.has_town) return FALSE; /* * See if (x,y) is in a room with subrooms, if so, assume it's the * town. If there are no subrooms, the whole level is in town. */ - for (sroom = &gr.rooms[0]; sroom->hx > 0; sroom++) { + for (sroom = &svr.rooms[0]; sroom->hx > 0; sroom++) { if (sroom->nsubrooms > 0) { has_subrooms = TRUE; if (inside_room(sroom, x, y)) @@ -3385,10 +3448,10 @@ check_special_room(boolean newlev) * TODO: change the minetn variants which don't include any town * boundary to have such. */ - if (gl.level.flags.has_town && !gc.context.achieveo.minetn_reached + if (svl.level.flags.has_town && !svc.context.achieveo.minetn_reached && In_mines(&u.uz) && in_town(u.ux, u.uy)) { record_achievement(ACH_TOWN); - gc.context.achieveo.minetn_reached = TRUE; + svc.context.achieveo.minetn_reached = TRUE; } if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */ @@ -3399,7 +3462,7 @@ check_special_room(boolean newlev) u_entered_shop(u.ushops_entered); for (ptr = &u.uentered[0]; *ptr; ptr++) { - int roomno = *ptr - ROOMOFFSET, rt = gr.rooms[roomno].rtype; + int roomno = *ptr - ROOMOFFSET, rt = svr.rooms[roomno].rtype; boolean msg_given = TRUE; /* Did we just enter some other special room? */ @@ -3454,10 +3517,10 @@ check_special_room(boolean newlev) if (oracle) { SetVoice(oracle, 0, 80, 0); if (!oracle->mpeaceful) - verbalize("You're in Delphi, %s.", gp.plname); + verbalize("You're in Delphi, %s.", svp.plname); else verbalize("%s, %s, welcome to Delphi!", - Hello((struct monst *) 0), gp.plname); + Hello((struct monst *) 0), svp.plname); } else msg_given = FALSE; break; @@ -3474,30 +3537,30 @@ check_special_room(boolean newlev) room_discovered(roomno); if (rt != 0) { - gr.rooms[roomno].rtype = OROOM; + svr.rooms[roomno].rtype = OROOM; if (!search_special(rt)) { /* No more room of that type */ switch (rt) { case COURT: - gl.level.flags.has_court = 0; + svl.level.flags.has_court = 0; break; case SWAMP: - gl.level.flags.has_swamp = 0; + svl.level.flags.has_swamp = 0; break; case MORGUE: - gl.level.flags.has_morgue = 0; + svl.level.flags.has_morgue = 0; break; case ZOO: - gl.level.flags.has_zoo = 0; + svl.level.flags.has_zoo = 0; break; case BARRACKS: - gl.level.flags.has_barracks = 0; + svl.level.flags.has_barracks = 0; break; case TEMPLE: - gl.level.flags.has_temple = 0; + svl.level.flags.has_temple = 0; break; case BEEHIVE: - gl.level.flags.has_beehive = 0; + svl.level.flags.has_beehive = 0; break; } } @@ -3649,7 +3712,7 @@ lookaround(void) return; } - if (Blind || gc.context.run == 0) + if (Blind || svc.context.run == 0) return; for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) { @@ -3669,11 +3732,11 @@ lookaround(void) && mon_visible(mtmp)) { /* running movement and not a hostile monster */ /* OR it blocks our move direction and we're not traveling */ - if ((gc.context.run != 1 && !is_safemon(mtmp)) - || (infront && !gc.context.travel)) { + if ((svc.context.run != 1 && !is_safemon(mtmp)) + || (infront && !svc.context.travel)) { if (flags.mention_walls) pline_xy(x, y, "%s blocks your path.", - upstart(a_monnam(mtmp))); + upstart(a_monnam(mtmp))); goto stop; } } @@ -3686,8 +3749,9 @@ lookaround(void) continue; /* stop for traps, sometimes */ - if (avoid_moving_on_trap(x, y, (infront && gc.context.run > 1))) { - if (gc.context.run == 1) + if (avoid_moving_on_trap(x, y, + (infront && svc.context.run > 1))) { + if (svc.context.run == 1) goto bcorr; /* if you must */ if (infront) goto stop; @@ -3702,22 +3766,22 @@ lookaround(void) /* ignore if diagonal */ if (x != u.ux && y != u.uy) continue; - if (gc.context.run != 1 && !gc.context.travel) { + if (svc.context.run != 1 && !svc.context.travel) { if (flags.mention_walls) { set_msg_xy(x, y); You("stop in front of the door."); } goto stop; } - /* we're orthogonal to a closed door, consider it a corridor */ + /* orthogonal to a closed door, consider it a corridor */ goto bcorr; } else if (levl[x][y].typ == CORR) { /* corridor */ bcorr: if (levl[u.ux][u.uy].typ != ROOM) { /* running or traveling */ - if (gc.context.run == 1 || gc.context.run == 3 - || gc.context.run == 8) { + if (svc.context.run == 1 || svc.context.run == 3 + || svc.context.run == 8) { /* distance from x,y to location we're moving to */ i = dist2(x, y, u.ux + u.dx, u.uy + u.dy); /* ignore if not on or directly adjacent to it */ @@ -3745,9 +3809,9 @@ lookaround(void) goto stop; continue; } else { /* e.g. objects or trap or stairs */ - if (gc.context.run == 1) + if (svc.context.run == 1) goto bcorr; - if (gc.context.run == 8) + if (svc.context.run == 8) continue; if (mtmp) continue; /* d */ @@ -3760,12 +3824,12 @@ lookaround(void) return; } /* end for loops */ - if (corrct > 1 && gc.context.run == 2) { + if (corrct > 1 && svc.context.run == 2) { if (flags.mention_walls) pline_The("corridor widens here."); goto stop; } - if ((gc.context.run == 1 || gc.context.run == 3 || gc.context.run == 8) + if ((svc.context.run == 1 || svc.context.run == 3 || svc.context.run == 8) && !noturn && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1))) { /* make sure that we do not turn too far */ @@ -3869,13 +3933,13 @@ end_running(boolean and_travel) { /* moveloop() suppresses time_botl when context.run is non-zero; when running stops, update 'time' even if other botl status is unchanged */ - if (flags.time && gc.context.run) + if (flags.time && svc.context.run) disp.time_botl = TRUE; - gc.context.run = 0; + svc.context.run = 0; /* 'context.mv' isn't travel but callers who want to end travel all clear it too */ if (and_travel) - gc.context.travel = gc.context.travel1 = gc.context.mv = 0; + svc.context.travel = svc.context.travel1 = svc.context.mv = 0; if (gt.travelmap) { selection_free(gt.travelmap, TRUE); gt.travelmap = NULL; @@ -3942,10 +4006,10 @@ maybe_wail(void) SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES, TELEPORT_CONTROL, STEALTH, FAST, INVIS }; - if (gm.moves <= gw.wailmsg + 50) + if (svm.moves <= gw.wailmsg + 50) return; - gw.wailmsg = gm.moves; + gw.wailmsg = svm.moves; if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) { const char *who; int i, powercnt; @@ -4028,9 +4092,9 @@ losehp(int n, const char *knam, schar k_format) if (u.uhp > u.uhpmax) u.uhpmax = u.uhp; /* perhaps n was negative */ if (u.uhp < 1) { - gk.killer.format = k_format; - if (gk.killer.name != knam) /* the thing that killed you */ - Strcpy(gk.killer.name, knam ? knam : ""); + svk.killer.format = k_format; + if (svk.killer.name != knam) /* the thing that killed you */ + Strcpy(svk.killer.name, knam ? knam : ""); urgent_pline("You die..."); done(DIED); } else if (n > 0 && u.uhp * 10 < u.uhpmax) { diff --git a/src/insight.c b/src/insight.c index 8d44962d3..c1cb1a698 100644 --- a/src/insight.c +++ b/src/insight.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 insight.c $NHDT-Date: 1713334807 2024/04/17 06:20:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.112 $ */ +/* NetHack 3.7 insight.c $NHDT-Date: 1724094296 2024/08/19 19:04:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.115 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -106,7 +106,8 @@ static struct ll_achieve_msg achieve_msg [] = { #define you_are(attr, ps) enl_msg(You_, are, were, (attr), (ps)) #define you_have(attr, ps) enl_msg(You_, have, had, (attr), (ps)) #define you_can(attr, ps) enl_msg(You_, can, could, (attr), (ps)) -#define you_have_been(goodthing) enl_msg(You_, have_been, were, (goodthing), "") +#define you_have_been(goodthing) \ + enl_msg(You_, have_been, were, (goodthing), "") #define you_have_never(badthing) \ enl_msg(You_, have_never, never, (badthing), "") #define you_have_X(something) \ @@ -363,7 +364,7 @@ enlightenment( if (ge.en_via_menu) start_menu(ge.en_win, MENU_BEHAVE_STANDARD); - Strcpy(tmpbuf, gp.plname); + Strcpy(tmpbuf, svp.plname); *tmpbuf = highc(*tmpbuf); /* same adjustment as bottom line */ /* as in background_enlightenment, when poly'd we need to use the saved gender in u.mfemale rather than the current you-as-monster gender */ @@ -512,7 +513,7 @@ background_enlightenment(int unused_mode UNUSED, int final) way sooner (in other words, didn't start that way) */ ? (!final ? "now " : "belatedly ") /* atheist (ignored in very early game) */ - : (!u.uconduct.gnostic && gm.moves > 1000L) + : (!u.uconduct.gnostic && svm.moves > 1000L) ? "nominally " /* lastly, normal case */ : "", @@ -577,13 +578,13 @@ background_enlightenment(int unused_mode UNUSED, int final) !strncmp(tmpbuf, "Plane", 5) ? "Elemental " : "", tmpbuf); } else if (Is_knox(&u.uz)) { /* this gives away the fact that the knox branch is only 1 level */ - Sprintf(buf, "on the %s level", gd.dungeons[u.uz.dnum].dname); + Sprintf(buf, "on the %s level", svd.dungeons[u.uz.dnum].dname); /* TODO? maybe phrase it differently when actually inside the fort, if we're able to determine that (not trivial) */ } else { char dgnbuf[QBUFSZ]; - Strcpy(dgnbuf, gd.dungeons[u.uz.dnum].dname); + Strcpy(dgnbuf, svd.dungeons[u.uz.dnum].dname); if (!strncmpi(dgnbuf, "The ", 4)) *dgnbuf = lowc(*dgnbuf); Sprintf(tmpbuf, "level %d", @@ -599,11 +600,12 @@ background_enlightenment(int unused_mode UNUSED, int final) you_are(buf, ""); /* this is shown even if the 'time' option is off */ - if (gm.moves == 1L) { + if (svm.moves == 1L) { you_have("just started your adventure", ""); } else { /* 'turns' grates on the nerves in this context... */ - Sprintf(buf, "the dungeon %ld turn%s ago", gm.moves, plur(gm.moves)); + Sprintf(buf, "the dungeon %ld turn%s ago", + svm.moves, plur(svm.moves)); /* same phrasing for current and final: "entered" is unconditional */ enlght_line(You_, "entered ", buf, ""); } @@ -913,7 +915,7 @@ status_enlightenment(int mode, int final) /* if hero dies while dismounting, u.usteed will still be set; we want to ignore steed in that situation */ && !(final == ENL_GAMEOVERDEAD - && !strcmp(gk.killer.name, "riding accident"))); + && !strcmp(svk.killer.name, "riding accident"))); const char *steedname = (!Riding ? (char *) 0 : x_monnam(u.usteed, u.usteed->mtame ? ARTICLE_YOUR : ARTICLE_THE, @@ -1501,7 +1503,8 @@ attributes_enlightenment( item_resistance_message(AD_DISN, " protected from disintegration", final); if (Shock_resistance) you_are("shock resistant", from_what(SHOCK_RES)); - item_resistance_message(AD_ELEC, " protected from electric shocks", final); + item_resistance_message(AD_ELEC, " protected from electric shocks", + final); if (Poison_resistance) you_are("poison resistant", from_what(POISON_RES)); if (Acid_resistance) { @@ -1544,30 +1547,26 @@ attributes_enlightenment( you_are("telepathic", from_what(TELEPAT)); if (Warning) you_are("warned", from_what(WARNING)); - if (Warn_of_mon && gc.context.warntype.obj) { + if (Warn_of_mon && svc.context.warntype.obj) { Sprintf(buf, "aware of the presence of %s", - (gc.context.warntype.obj & M2_ORC) ? "orcs" - : (gc.context.warntype.obj & M2_ELF) ? "elves" - : (gc.context.warntype.obj & M2_DEMON) ? "demons" : something); + (svc.context.warntype.obj & M2_ORC) ? "orcs" + : (svc.context.warntype.obj & M2_ELF) ? "elves" + : (svc.context.warntype.obj & M2_DEMON) ? "demons" + : something); you_are(buf, from_what(WARN_OF_MON)); } - if (Warn_of_mon && gc.context.warntype.polyd) { + if (Warn_of_mon && svc.context.warntype.polyd) { Sprintf(buf, "aware of the presence of %s", - ((gc.context.warntype.polyd & (M2_HUMAN | M2_ELF)) - == (M2_HUMAN | M2_ELF)) - ? "humans and elves" - : (gc.context.warntype.polyd & M2_HUMAN) - ? "humans" - : (gc.context.warntype.polyd & M2_ELF) - ? "elves" - : (gc.context.warntype.polyd & M2_ORC) - ? "orcs" - : (gc.context.warntype.polyd & M2_DEMON) - ? "demons" - : "certain monsters"); + ((svc.context.warntype.polyd & (M2_HUMAN | M2_ELF)) + == (M2_HUMAN | M2_ELF)) ? "humans and elves" + : (svc.context.warntype.polyd & M2_HUMAN) ? "humans" + : (svc.context.warntype.polyd & M2_ELF) ? "elves" + : (svc.context.warntype.polyd & M2_ORC) ? "orcs" + : (svc.context.warntype.polyd & M2_DEMON) ? "demons" + : "certain monsters"); you_are(buf, ""); } - warnspecies = gc.context.warntype.speciesidx; + warnspecies = svc.context.warntype.speciesidx; if (Warn_of_mon && ismnum(warnspecies)) { Sprintf(buf, "aware of the presence of %s", makeplural(mons[warnspecies].pmnames[NEUTRAL])); @@ -1917,7 +1916,7 @@ attributes_enlightenment( Sprintf(buf, "Fruit #%d ", f->fid); enl_msg(buf, "is ", "was ", f->fname, ""); } - enl_msg("The current fruit ", "is ", "was ", gp.pl_fruit, ""); + enl_msg("The current fruit ", "is ", "was ", svp.pl_fruit, ""); Sprintf(buf, "%d", flags.made_fruit); enl_msg("The made fruit flag ", "is ", "was ", buf, ""); } @@ -2005,7 +2004,7 @@ youhiding(boolean via_enlghtmt, /* enlightenment line vs topl message */ if (is_pool(u.ux, u.uy)) Sprintf(bp, " in the %s", waterbody_name(u.ux, u.uy)); } else if (hides_under(gy.youmonst.data)) { - struct obj *o = gl.level.objects[u.ux][u.uy]; + struct obj *o = svl.level.objects[u.ux][u.uy]; if (o) Sprintf(bp, " underneath %s", ansimpleoname(o)); @@ -2061,6 +2060,8 @@ show_conduct(int final) you_have_been("deaf from birth"); if (u.uroleplay.nudist) you_have_been("faithfully nudist"); + if (u.uroleplay.pauper) + enl_msg(You_, "have gone", "started out", " without possessions", ""); if (!u.uconduct.food) enl_msg(You_, "have gone", "went", " without food", ""); @@ -2395,7 +2396,7 @@ record_achievement(schar achidx) /* avoid livelog for achievements recorded during final disclosure: nudist and blind-from-birth; also ascension which is suppressed by this gets logged separately in really_done() */ - if (gp.program_state.gameover) + if (program_state.gameover) return; if (absidx >= ACH_RNK1 && absidx <= ACH_RNK8) { @@ -2408,8 +2409,8 @@ record_achievement(schar achidx) || achidx == ACH_MINE_PRIZE) { /* need to supply extra information for these two */ short otyp = ((achidx == ACH_SOKO_PRIZE) - ? gc.context.achieveo.soko_prize_otyp - : gc.context.achieveo.mines_prize_otyp); + ? svc.context.achieveo.soko_prize_otyp + : svc.context.achieveo.mines_prize_otyp); /* note: OBJ_NAME() works here because both "bag of holding" and "amulet of reflection" are fully named in their objects[] entry @@ -2632,6 +2633,15 @@ vanqsort_cmp( } res = mcls1 - mcls2; /* class */ if (res == 0) { + /* Riders are in the same class as major demons, yielding res==0 + above when both mcls1 and mcls2 are either Riders or demons or + one of each; force Riders to be sorted before demons */ + res = is_rider(&mons[indx2]) - is_rider(&mons[indx1]); + /* res -1 => #1 is a Rider, #2 isn't; + 0 => both Riders or neither; + +1 => #2 is a Rider, #1 isn't */ + if (res) + break; mlev1 = mons[indx1].mlevel; mlev2 = mons[indx2].mlevel; res = mlev1 - mlev2; /* mlevel low to high */ @@ -2641,8 +2651,8 @@ vanqsort_cmp( break; case VANQ_COUNT_H_L: case VANQ_COUNT_L_H: - died1 = gm.mvitals[indx1].died; - died2 = gm.mvitals[indx2].died; + died1 = svm.mvitals[indx1].died; + died2 = svm.mvitals[indx2].died; res = died2 - died1; /* dead count high to low */ if (flags.vanq_sortmode == VANQ_COUNT_L_H) res = -res; /* dead count low to high */ @@ -2709,7 +2719,8 @@ set_vanq_order(boolean for_vanq) int dovanquished(void) { - list_vanquished(iflags.menu_requested ? 'a' : 'y', FALSE); + list_vanquished(iflags.menu_requested ? 'A' : 'y', FALSE); + iflags.menu_requested = FALSE; return ECMD_OK; } @@ -2717,8 +2728,9 @@ dovanquished(void) #define UniqCritterIndx(mndx) \ ((mons[mndx].geno & G_UNIQ) != 0 && mndx != PM_HIGH_CLERIC) -#define done_stopprint gp.program_state.stopprint +#define done_stopprint program_state.stopprint +/* used for #vanquished and end of game disclosure and end of game dumplog */ void list_vanquished(char defquery, boolean ask) { @@ -2729,18 +2741,31 @@ list_vanquished(char defquery, boolean ask) winid klwin; short mindx[NUMMONS]; char c, buf[BUFSZ], buftoo[BUFSZ]; - boolean dumping; /* for DUMPLOG; doesn't need to be conditional */ + /* 'A' is only supplied by 'm #vanquished'; 'd' is only supplied by + dump_everything() when writing dumplog, so won't happen if built + without '#define DUMPLOG' but there's no need for conditionals here */ + boolean force_sort = (defquery == 'A'), + dumping = (defquery == 'd'); - dumping = (defquery == 'd'); - if (dumping) { + /* normally we don't ask about sort order for the vanquished list unless + it contains at least two entries; however, if player has used explicit + 'm #vanquished', choose order no matter what it contains so far */ + if (force_sort) { /* iflags.menu_requested via dovanquished() */ + /* choose value for vanq_sortmode via menu; ESC cancels choosing + sort order but continues with vanquishd monsters display */ + (void) set_vanq_order(TRUE); + } + if (dumping || force_sort) { + /* switch from 'A' or 'd' to 'y'; 'ask' is already False for the + cases that might supply 'A' or 'd' */ defquery = 'y'; - ask = FALSE; /* redundant; caller passes False with defquery=='d' */ + ask = FALSE; /* redundant */ } /* get totals first */ ntypes = 0; for (i = LOW_PM; i < NUMMONS; i++) { - if ((nkilled = (int) gm.mvitals[i].died) == 0) + if ((nkilled = (int) svm.mvitals[i].died) == 0) continue; mindx[ntypes++] = i; total_killed += (long) nkilled; @@ -2751,16 +2776,30 @@ list_vanquished(char defquery, boolean ask) */ if (ntypes != 0) { char mlet, prev_mlet = 0; /* used as small integer, not character */ - boolean class_header, uniq_header, was_uniq = FALSE; + boolean class_header, uniq_header, Rider, + was_uniq = FALSE, special_hdr = FALSE; + + if (ask) { + char allow_yn[10]; + + if (ntypes > 1) { + Strcpy(allow_yn, ynaqchars); + } else { + Strcpy(allow_yn, ynqchars); /* don't include 'a', but */ + Strcat(allow_yn, "\033a"); /* allow user to answer 'a' */ + if (defquery == 'a') /* potential default from 'disclose' */ + defquery = 'y'; + } + c = yn_function("Do you want an account of creatures vanquished?", + allow_yn, defquery, TRUE); + } else { + c = defquery; + } - c = ask ? yn_function( - "Do you want an account of creatures vanquished?", - ynaqchars, defquery, TRUE) - : defquery; if (c == 'q') done_stopprint++; if (c == 'y' || c == 'a') { - if (c == 'a' && ntypes > 1) { /* ask player to choose sort order */ + if (c == 'a' && ntypes > 1) { /* ask user 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(TRUE) < 0) @@ -2779,10 +2818,18 @@ list_vanquished(char defquery, boolean ask) qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp); for (ni = 0; ni < ntypes; ni++) { i = mindx[ni]; - nkilled = gm.mvitals[i].died; + nkilled = svm.mvitals[i].died; + Rider = is_rider(&mons[i]); mlet = mons[i].mlet; - if (class_header && mlet != prev_mlet) { - Strcpy(buf, def_monsyms[(int) mlet].explain); + if (class_header + && (mlet != prev_mlet || (special_hdr && !Rider))) { + if (!Rider) { + Strcpy(buf, def_monsyms[(int) mlet].explain); + special_hdr = FALSE; + } else { + Strcpy(buf, "Rider"); + special_hdr = TRUE; + } /* 'ask' implies final disclosure, where highlighting of various header lines is suppressed */ putstr(klwin, ask ? ATR_NONE : iflags.menu_headings.attr, @@ -2852,7 +2899,7 @@ list_vanquished(char defquery, boolean ask) * still in progress, so use present tense via pline(), or for dumplog * which needs putstr() and past tense. */ - } else if (!gp.program_state.gameover) { + } else if (!program_state.gameover) { /* #vanquished rather than final disclosure, so pline() is ok */ pline("No creatures have been vanquished."); #ifdef DUMPLOG @@ -2869,7 +2916,7 @@ num_genocides(void) int i, n = 0; for (i = LOW_PM; i < NUMMONS; ++i) { - if (gm.mvitals[i].mvflags & G_GENOD) { + if (svm.mvitals[i].mvflags & G_GENOD) { ++n; if (UniqCritterIndx(i)) impossible("unique creature '%d: %s' genocided?", @@ -2888,7 +2935,7 @@ num_extinct(void) for (i = LOW_PM; i < NUMMONS; ++i) { if (UniqCritterIndx(i)) continue; - if ((gm.mvitals[i].mvflags & G_GONE) == G_EXTINCT) + if ((svm.mvitals[i].mvflags & G_GONE) == G_EXTINCT) ++n; } return n; @@ -2909,7 +2956,7 @@ num_gone(int mvflags, int *mindx) if (UniqCritterIndx(i)) continue; - if ((gm.mvitals[i].mvflags & mflg) != 0) + if ((svm.mvitals[i].mvflags & mflg) != 0) mindx[n++] = i; } return n; @@ -2927,7 +2974,7 @@ list_genocided(char defquery, boolean ask) char buf[BUFSZ]; boolean genoing, /* prompting for genocide or class genocide */ dumping; /* for DUMPLOG; doesn't need to be conditional */ - boolean both = (gp.program_state.gameover || wizard || discover); + boolean both = (program_state.gameover || wizard || discover); dumping = (defquery == 'd'); genoing = (defquery == 'g'); @@ -3011,7 +3058,7 @@ list_genocided(char defquery, boolean ask) * clear. During normal play, 'mndx' won't be in the * collected list unless that bit is set. */ - if ((gm.mvitals[mndx].mvflags & G_GONE) == G_EXTINCT) + if ((svm.mvitals[mndx].mvflags & G_GONE) == G_EXTINCT) Strcat(buf, " (extinct)"); putstr(klwin, 0, buf); } @@ -3031,7 +3078,7 @@ list_genocided(char defquery, boolean ask) } /* See the comment for similar code near the end of list_vanquished(). */ - } else if (!gp.program_state.gameover) { + } else if (!program_state.gameover) { /* #genocided rather than final disclosure, so pline() is ok and extinction has been ignored */ pline("No creatures have been genocided%s.", genoing ? " yet" : ""); @@ -3064,18 +3111,18 @@ doborn(void) putstr(datawin, 0, "died born"); for (i = LOW_PM; i < NUMMONS; i++) - if (gm.mvitals[i].born || gm.mvitals[i].died - || (gm.mvitals[i].mvflags & G_GONE) != 0) { + if (svm.mvitals[i].born || svm.mvitals[i].died + || (svm.mvitals[i].mvflags & G_GONE) != 0) { Sprintf(buf, fmt, - gm.mvitals[i].died, gm.mvitals[i].born, - ((gm.mvitals[i].mvflags & G_GONE) == G_EXTINCT) ? 'E' - : ((gm.mvitals[i].mvflags & G_GONE) == G_GENOD) ? 'G' - : ((gm.mvitals[i].mvflags & G_GONE) != 0) ? 'X' + svm.mvitals[i].died, svm.mvitals[i].born, + ((svm.mvitals[i].mvflags & G_GONE) == G_EXTINCT) ? 'E' + : ((svm.mvitals[i].mvflags & G_GONE) == G_GENOD) ? 'G' + : ((svm.mvitals[i].mvflags & G_GONE) != 0) ? 'X' : ' ', mons[i].pmnames[NEUTRAL]); putstr(datawin, 0, buf); - nborn += gm.mvitals[i].born; - ndied += gm.mvitals[i].died; + nborn += svm.mvitals[i].born; + ndied += svm.mvitals[i].died; } putstr(datawin, 0, ""); @@ -3205,7 +3252,7 @@ mstatusline(struct monst *mtmp) if (mtmp->data == &mons[PM_LONG_WORM]) { int segndx, nsegs = count_wsegs(mtmp); - /* the worm code internals don't consider the head of be one of + /* the worm code internals don't consider the head to be one of the worm's segments, but we count it as such when presenting worm feedback to the player */ if (!nsegs) { @@ -3226,8 +3273,10 @@ mstatusline(struct monst *mtmp) Strcat(info, ", eating"); /* a stethoscope exposes mimic before getting here so this won't be relevant for it, but wand of probing doesn't */ - if (mtmp->mundetected || mtmp->m_ap_type) - mhidden_description(mtmp, MHID_PREFIX | MHID_ARTICLE | MHID_ALTMON, + if (mtmp->mundetected || mtmp->m_ap_type + || visible_region_at(gb.bhitpos.x, gb.bhitpos.y)) + mhidden_description(mtmp, + MHID_PREFIX | MHID_ARTICLE | MHID_ALTMON | MHID_REGION, eos(info)); if (mtmp->mcan) Strcat(info, ", cancelled"); @@ -3311,7 +3360,9 @@ mstatusline(struct monst *mtmp) void ustatusline(void) { + NhRegion *reg; char info[BUFSZ]; + size_t ln; info[0] = '\0'; if (Sick) { @@ -3366,17 +3417,31 @@ ustatusline(void) Strcat(info, Very_fast ? ", very fast" : ", fast"); if (u.uundetected) Strcat(info, ", concealed"); + else if (U_AP_TYPE != M_AP_NOTHING) + Strcat(info, ", disguised"); if (Invis) Strcat(info, ", invisible"); if (u.ustuck) { - if (sticks(gy.youmonst.data)) - Strcat(info, ", holding "); - else + if (u.uswallow) + Strcat(info, digests(u.ustuck->data) ? ", being digested by " + : ", engulfed by "); + else if (!sticks(gy.youmonst.data)) Strcat(info, ", held by "); - Strcat(info, mon_nam(u.ustuck)); + else + Strcat(info, ", holding "); + /* FIXME? a_monnam() uses x_monnam() which has a special case that + forces "the" instead of "a" when formatting u.ustuck while hero + is swallowed; we don't really want that here but it isn't worth + fiddling with just for self-probing while engulfed */ + Strcat(info, a_monnam(u.ustuck)); } + if (!u.uswallow + && (reg = visible_region_at(u.ux, u.uy)) != 0 + && (ln = strlen(info)) < sizeof info) + Snprintf(eos(info), sizeof info - ln, ", in a cloud of %s", + reg_damg(reg) ? "poison gas" : "vapor"); - pline("Status of %s (%s): Level %d HP %d(%d) AC %d%s.", gp.plname, + pline("Status of %s (%s): Level %d HP %d(%d) AC %d%s.", svp.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); diff --git a/src/invent.c b/src/invent.c index b2020e342..fcf1f5bc8 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 invent.c $NHDT-Date: 1702023269 2023/12/08 08:14:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.485 $ */ +/* NetHack 3.7 invent.c $NHDT-Date: 1724094299 2024/08/19 19:04:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.516 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -355,7 +355,7 @@ loot_xname(struct obj *obj) if (wizard) { /* flags.debug */ /* paranoia: before toggling off wizard mode, guard against a panic in xname() producing a normal mode panic save file */ - gp.program_state.something_worth_saving = 0; + program_state.something_worth_saving = 0; flags.debug = FALSE; } @@ -363,7 +363,7 @@ loot_xname(struct obj *obj) if (save_debug) { flags.debug = TRUE; - gp.program_state.something_worth_saving = 1; + program_state.something_worth_saving = 1; } /* restore the object */ if (obj->oclass == POTION_CLASS) { @@ -404,7 +404,8 @@ invletter_value(char c) : ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26) : (c == '$') ? 1 : (c == '#') ? 1 + invlet_basic + 1 - : 1 + invlet_basic + 1 + 1; /* none of the above (shouldn't happen) */ + : 1 + invlet_basic + 1 + 1; /* none of the above + * (shouldn't happen) */ } /* qsort comparison routine for sortloot() */ @@ -1006,11 +1007,11 @@ addinv_core1(struct obj *obj) dumplog, originally just recorded in XLOGFILE */ if (is_mines_prize(obj)) { record_achievement(ACH_MINE_PRIZE); - gc.context.achieveo.mines_prize_oid = 0; /* done with luckstone o_id */ + svc.context.achieveo.mines_prize_oid = 0; /* done w/ luckstone o_id */ obj->nomerge = 0; /* was set in create_object(sp_lev.c) */ } else if (is_soko_prize(obj)) { record_achievement(ACH_SOKO_PRIZE); - gc.context.achieveo.soko_prize_oid = 0; /* done with bag/amulet o_id */ + svc.context.achieveo.soko_prize_oid = 0; /* done w/ bag/amulet o_id */ obj->nomerge = 0; /* (got set in sp_lev.c) */ } } @@ -1384,7 +1385,7 @@ delallobj(coordxy x, coordxy y) { struct obj *otmp, *otmp2; - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp2) { + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp2) { if (otmp == uball) unpunish(); /* after unpunish(), or might get deallocated chain */ @@ -1437,7 +1438,7 @@ sobj_at(int otyp, coordxy x, coordxy y) { struct obj *otmp; - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) if (otmp->otyp == otyp) break; @@ -1561,7 +1562,7 @@ obj_here(struct obj *obj, coordxy x, coordxy y) { struct obj *otmp; - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) if (obj == otmp) return TRUE; return FALSE; @@ -1570,7 +1571,7 @@ obj_here(struct obj *obj, coordxy x, coordxy y) struct obj * g_at(coordxy x, coordxy y) { - struct obj *obj = gl.level.objects[x][y]; + struct obj *obj = svl.level.objects[x][y]; while (obj) { if (obj->oclass == COIN_CLASS) @@ -1794,8 +1795,9 @@ getobj( *bp++ = ' '; /* put a space after the '-' in the prompt */ break; case GETOBJ_DOWNPLAY: /* acceptable but not shown as likely choice */ - case GETOBJ_EXCLUDE_INACCESS: /* nothing currently gives this for '-' but - * theoretically could if wearing gloves */ + case GETOBJ_EXCLUDE_INACCESS: /* nothing currently gives this for '-' + * but theoretically could if wearing + * gloves */ case GETOBJ_EXCLUDE_SELECTABLE: /* ditto, I think... */ allownone = TRUE; *ap++ = HANDS_SYM; @@ -2186,7 +2188,8 @@ ggetobj(const char *word, int (*fn)(OBJ_P), int mx, ofilter = not_fully_identified; } - iletct = collect_obj_classes(ilets, gi.invent, FALSE, ofilter, &itemcount); + iletct = collect_obj_classes(ilets, gi.invent, FALSE, ofilter, + &itemcount); unpaid = count_unpaid(gi.invent); if (ident && !iletct) { @@ -2650,7 +2653,7 @@ update_inventory(void) { int save_suppress_price; - if (!gp.program_state.in_moveloop) /* not covered by suppress_map_output */ + if (!program_state.in_moveloop) /* not covered by suppress_map_output */ return; if (suppress_map_output()) /* despite name, used for perm_invent too */ return; @@ -3119,11 +3122,13 @@ itemactions(struct obj *otmp) if (otmp->oclass == COIN_CLASS) ia_addmenu(win, IA_APPLY_OBJ, 'a', "Flip a coin"); else if (otmp->otyp == CREAM_PIE) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Hit yourself with this cream pie"); + ia_addmenu(win, IA_APPLY_OBJ, 'a', + "Hit yourself with this cream pie"); else if (otmp->otyp == BULLWHIP) ia_addmenu(win, IA_APPLY_OBJ, 'a', "Lash out with this whip"); else if (otmp->otyp == GRAPPLING_HOOK) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Grapple something with this hook"); + ia_addmenu(win, IA_APPLY_OBJ, 'a', + "Grapple something with this hook"); else if (otmp->otyp == BAG_OF_TRICKS && objects[otmp->otyp].oc_name_known) /* bag of tricks skips this unless discovered */ ia_addmenu(win, IA_APPLY_OBJ, 'a', "Reach into this bag"); @@ -3187,7 +3192,8 @@ itemactions(struct obj *otmp) ia_addmenu(win, IA_APPLY_OBJ, 'a', "Make this figurine transform"); else if (otmp->otyp == UNICORN_HORN) ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use this unicorn horn"); - else if (otmp->otyp == HORN_OF_PLENTY && objects[otmp->otyp].oc_name_known) + else if (otmp->otyp == HORN_OF_PLENTY + && objects[otmp->otyp].oc_name_known) ia_addmenu(win, IA_APPLY_OBJ, 'a', "Blow into the horn of plenty"); else if (otmp->otyp >= WOODEN_FLUTE && otmp->otyp <= DRUM_OF_EARTHQUAKE) ia_addmenu(win, IA_APPLY_OBJ, 'a', "Play this musical instrument"); @@ -3417,7 +3423,8 @@ itemactions(struct obj *otmp) ia_addmenu(win, IA_SWAPWEAPON, 'x', "Ready this as an alternate weapon"); else if (otmp == uswapwep) - ia_addmenu(win, IA_SWAPWEAPON, 'x', "Swap this with your main weapon"); + ia_addmenu(win, IA_SWAPWEAPON, 'x', + "Swap this with your main weapon"); /* this is based on TWOWEAPOK() in wield.c; we don't call can_two_weapon() because it is very verbose; attempting to two-weapon might be rejected @@ -3997,7 +4004,8 @@ display_used_invlets(char avoidlet) tmpglyph = obj_to_glyph(otmp, rn2_on_display_rng); map_glyphinfo(0, 0, tmpglyph, 0U, &tmpglyphinfo); add_menu(win, &tmpglyphinfo, &any, ilet, 0, - ATR_NONE, clr, doname(otmp), MENU_ITEMFLAGS_NONE); + ATR_NONE, clr, doname(otmp), + MENU_ITEMFLAGS_NONE); } } if (flags.sortpack && *++invlet) @@ -4347,7 +4355,7 @@ dotypeinv(void) title[0] = '\0'; u_carried = count_unpaid(gi.invent); u_floor = count_unpaid(fobj); - u_buried = count_unpaid(gl.level.buriedobjlist); + u_buried = count_unpaid(svl.level.buriedobjlist); any_unpaid = u_carried + u_floor + u_buried; tally_BUCX(gi.invent, FALSE, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt, &jcnt); @@ -4658,10 +4666,25 @@ look_here( } return (!!Blind ? ECMD_TIME : ECMD_OK); } - if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen) - There("is %s here.", an(trapname(trap->ttyp, FALSE))); + if (!skip_objects) { + NhRegion *reg; + char regbuf[QBUFSZ]; - otmp = gl.level.objects[u.ux][u.uy]; + regbuf[0] = '\0'; + if ((reg = visible_region_at(u.ux, u.uy)) != 0) + Sprintf(regbuf, "a %s cloud", + reg_damg(reg) ? "poison gas" : "vapor"); + if ((trap = t_at(u.ux, u.uy)) != 0 && !trap->tseen) + trap = (struct trap *) NULL; + + if (reg || trap) + There("is %s%s%s here.", + reg ? regbuf : "", + (reg && trap) ? " and " : "", + trap ? an(trapname(trap->ttyp, FALSE)) : ""); + } + + otmp = svl.level.objects[u.ux][u.uy]; dfeature = dfeature_at(u.ux, u.uy, fbuf2); if (dfeature && !strcmp(dfeature, "pool of water") && Underwater) dfeature = 0; @@ -4851,7 +4874,8 @@ stackobj(struct obj *obj) { struct obj *otmp; - for (otmp = gl.level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[obj->ox][obj->oy]; otmp; + otmp = otmp->nexthere) if (otmp != obj && merged(&obj, &otmp)) break; return; @@ -5249,7 +5273,7 @@ useupf(struct obj *obj, long numused) otmp = splitobj(obj, numused); else otmp = obj; - if (!gc.context.mon_moving && costly_spot(otmp->ox, otmp->oy)) { + if (!svc.context.mon_moving && costly_spot(otmp->ox, otmp->oy)) { if (strchr(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0))) addtobill(otmp, FALSE, FALSE, FALSE); else @@ -5550,7 +5574,7 @@ doorganize_core(struct obj *obj) char let; #define GOLD_INDX 0 #define GOLD_OFFSET 1 -#define OVRFLW_INDX (GOLD_OFFSET + invlet_basic) /* past gold & 2*26 letters */ +#define OVRFLW_INDX (GOLD_OFFSET + invlet_basic) /* past gold+2*26 letters */ char lets[1 + invlet_basic + 1 + 1]; /* room for '$a-zA-Z#\0' */ char qbuf[QBUFSZ]; char *objname, *otmpname; @@ -5656,7 +5680,9 @@ doorganize_core(struct obj *obj) collect = (let == obj->invlet); /* change the inventory and print the resulting item */ - adj_type = collect ? "Collecting:" : !splitting ? "Moving:" : "Splitting:"; + adj_type = collect ? "Collecting:" + : !splitting ? "Moving:" + : "Splitting:"; /* * don't use freeinv/addinv to avoid double-touching artifacts, @@ -5975,7 +6001,7 @@ display_binventory(coordxy x, coordxy y, boolean as_if_seen) should use the normal look_here command instead of probing (caller has already used bhitpile() which will have set dknown on all items) */ if (is_pool_or_lava(x, y) && !Underwater - && (obj = gl.level.objects[x][y]) != 0) { + && (obj = svl.level.objects[x][y]) != 0) { const char *real_liquid = is_pool(x, y) ? "water" : "lava", *seen_liquid = hliquid(real_liquid); @@ -5991,7 +6017,7 @@ display_binventory(coordxy x, coordxy y, boolean as_if_seen) underwhat = more_than_1 ? "under them" : "beneath it"; } else { Sprintf(qbuf, "Things that are under the %s here:", seen_liquid); - if (query_objlist(qbuf, &gl.level.objects[x][y], BY_NEXTHERE, + if (query_objlist(qbuf, &svl.level.objects[x][y], BY_NEXTHERE, &selected, PICK_NONE, allow_all) > 0) free((genericptr_t) selected), selected = 0; for (n2 = 0; obj; obj = obj->nexthere) @@ -6001,7 +6027,7 @@ display_binventory(coordxy x, coordxy y, boolean as_if_seen) } /* count # of buried objects here */ - for (n = 0, obj = gl.level.buriedobjlist; obj; obj = obj->nobj) + for (n = 0, obj = svl.level.buriedobjlist; obj; obj = obj->nobj) if (obj->ox == x && obj->oy == y) { if (as_if_seen) obj->dknown = 1; @@ -6013,7 +6039,7 @@ display_binventory(coordxy x, coordxy y, boolean as_if_seen) go.only.y = y; /* "buried here", but vary if we've already shown underwater items */ Sprintf(qbuf, "Things that are buried %s:", underwhat); - if (query_objlist(qbuf, &gl.level.buriedobjlist, INVORDER_SORT, + if (query_objlist(qbuf, &svl.level.buriedobjlist, INVORDER_SORT, &selected, PICK_NONE, only_here) > 0) free((genericptr_t) selected); go.only.x = go.only.y = 0; @@ -6120,7 +6146,7 @@ sync_perminvent(void) WIN_INVEN = create_nhwindow(NHW_MENU); } - if (WIN_INVEN != WIN_ERR && gp.program_state.beyond_savefile_load) { + if (WIN_INVEN != WIN_ERR && program_state.beyond_savefile_load) { gi.in_sync_perminvent = 1; (void) display_inventory((char *) 0, FALSE); gi.in_sync_perminvent = 0; diff --git a/src/lock.c b/src/lock.c index 3cf20a669..fa8fb22f8 100644 --- a/src/lock.c +++ b/src/lock.c @@ -29,7 +29,8 @@ picking_lock(coordxy *x, coordxy *y) boolean picking_at(coordxy x, coordxy y) { - return (boolean) (go.occupation == picklock && gx.xlock.door == &levl[x][y]); + return (boolean) (go.occupation == picklock + && gx.xlock.door == &levl[x][y]); } /* produce an occupation string appropriate for the current activity */ @@ -107,7 +108,8 @@ picklock(void) /* unfortunately we don't have a 'tknown' flag to record "known to be trapped" so declining to disarm and then retrying lock manipulation will find it all over again */ - if (y_n("You find a trap! Do you want to try to disarm it?") == 'y') { + if (y_n("You find a trap! Do you want to try to disarm it?") + == 'y') { const char *what; boolean alreadyunlocked; @@ -182,7 +184,8 @@ breakchestlock(struct obj *box, boolean destroyit) if (!rn2(3) || otmp->oclass == POTION_CLASS) { chest_shatter_msg(otmp); if (costly) - loss += stolen_value(otmp, u.ux, u.uy, peaceful_shk, TRUE); + loss += stolen_value(otmp, u.ux, u.uy, peaceful_shk, + TRUE); if (otmp->quan == 1L) { obfree(otmp, (struct obj *) 0); continue; @@ -192,7 +195,7 @@ breakchestlock(struct obj *box, boolean destroyit) useup(otmp); } if (box->otyp == ICE_BOX && otmp->otyp == CORPSE) { - otmp->age = gm.moves - otmp->age; /* actual age */ + otmp->age = svm.moves - otmp->age; /* actual age */ start_corpse_timeout(otmp); } place_object(otmp, u.ux, u.uy); @@ -441,7 +444,7 @@ pick_lock( count = 0; c = 'n'; /* in case there are no boxes here */ - for (otmp = gl.level.objects[cc.x][cc.y]; otmp; + for (otmp = svl.level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere) { /* autounlock on boxes: only the one that was just discovered to be locked; don't include any other boxes which might be here */ @@ -506,7 +509,8 @@ pick_lock( You_cant("do that with %s.", an(simple_typename(picktyp))); return PICKLOCK_LEARNED_SOMETHING; - } else if (autounlock && !touch_artifact(pick, &gy.youmonst)) { + } else if (autounlock + && !touch_artifact(pick, &gy.youmonst)) { /* note: for !autounlock, apply already did touch check */ return PICKLOCK_DID_SOMETHING; } @@ -575,7 +579,7 @@ pick_lock( /* this is probably only relevant when blind */ feel_location(cc.x, cc.y); if (door->glyph != oldglyph - || gl.lastseentyp[cc.x][cc.y] != oldlastseentyp) + || svl.lastseentyp[cc.x][cc.y] != oldlastseentyp) res = PICKLOCK_LEARNED_SOMETHING; if (is_drawbridge_wall(cc.x, cc.y) >= 0) @@ -639,7 +643,7 @@ pick_lock( gx.xlock.box = 0; } } - gc.context.move = 0; + svc.context.move = 0; gx.xlock.chance = ch; gx.xlock.picktyp = picktyp; gx.xlock.magic_key = is_magic_key(&gy.youmonst, pick); @@ -706,7 +710,7 @@ doforce(void) /* A lock is made only for the honest man, the thief will break it. */ gx.xlock.box = (struct obj *) 0; - for (otmp = gl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { if (otmp->obroken || !otmp->olocked) { /* force doname() to omit known "broken" or "unlocked" @@ -827,7 +831,7 @@ doopen_indir(coordxy x, coordxy y) newsym(cc.x, cc.y); if (door->glyph != oldglyph - || gl.lastseentyp[cc.x][cc.y] != oldlastseentyp) + || svl.lastseentyp[cc.x][cc.y] != oldlastseentyp) res = ECMD_TIME; /* learned something */ } @@ -878,7 +882,8 @@ doopen_indir(coordxy x, coordxy y) && (flags.autounlock & AUTOUNLOCK_KICK) != 0 && ynq("Kick it?") == 'y') { cmdq_add_ec(CQ_CANNED, dokick); - cmdq_add_dir(CQ_CANNED, sgn(cc.x - u.ux), sgn(cc.y - u.uy), 0); + cmdq_add_dir(CQ_CANNED, + sgn(cc.x - u.ux), sgn(cc.y - u.uy), 0); res = ECMD_TIME; } } @@ -989,7 +994,8 @@ doclose(void) schar oldlastseentyp = update_mapseen_for(x, y); feel_location(x, y); - if (door->glyph != oldglyph || gl.lastseentyp[x][y] != oldlastseentyp) + if (door->glyph != oldglyph + || svl.lastseentyp[x][y] != oldlastseentyp) res = ECMD_TIME; /* learned something */ } diff --git a/src/mail.c b/src/mail.c index 3c7d64c11..c1c62dc78 100644 --- a/src/mail.c +++ b/src/mail.c @@ -170,7 +170,8 @@ md_start(coord *startp) * hero. */ while (stway) { - if (stway->tolev.dnum == u.uz.dnum && couldsee(stway->sx, stway->sy)) { + if (stway->tolev.dnum == u.uz.dnum + && couldsee(stway->sx, stway->sy)) { startp->x = stway->sx; startp->y = stway->sy; return TRUE; @@ -184,8 +185,8 @@ md_start(coord *startp) * position that could be seen. What we really ought to be doing is * finding a path from a stairwell... * - * The arrays gv.viz_rmin[] and gv.viz_rmax[] are set even when blind. These - * are the LOS limits for each row. + * The arrays gv.viz_rmin[] and gv.viz_rmax[] are set even when blind. + * These are the LOS limits for each row. */ lax = 0; /* be picky */ max_distance = -1; @@ -406,7 +407,7 @@ newmail(struct mail_info *info) message_seen = TRUE; SetVoice(md, 0, 80, 0); - verbalize("%s, %s! %s.", Hello(md), gp.plname, info->display_txt); + verbalize("%s, %s! %s.", Hello(md), svp.plname, info->display_txt); if (info->message_typ) { struct obj *obj = mksobj(SCR_MAIL, FALSE, FALSE); @@ -447,7 +448,8 @@ ckmailstatus(void) return; if (mustgetmail < 0) { #if defined(AMIGA) || defined(MSDOS) || defined(TOS) - mustgetmail = (gm.moves < 2000) ? (100 + rn2(2000)) : (2000 + rn2(3000)); + mustgetmail = (svm.moves < 2000) ? (100 + rn2(2000)) + : (2000 + rn2(3000)); #endif return; } @@ -488,11 +490,13 @@ readmail(struct obj *otmp UNUSED) (suboptimal but works correctly); dollar sign and fractional zorkmids are inappropriate within nethack but are suitable for typical dysfunctional spam mail */ - "Buy a potion of gain level for only $19.99! Guaranteed to be blessed!", - /* DEVTEAM_URL will be substituted for 2nd "%s"; terminating punctuation - (formerly "!") has deliberately been omitted so that it can't be - mistaken for part of the URL (unfortunately that is still followed - by a closing quote--in the pline below, not the data here) */ + ("Buy a potion of gain level for only $19.99! " + " Guaranteed to be blessed!"), + /* DEVTEAM_URL will be substituted for 2nd "%s"; + terminating punctuation (formerly "!") has deliberately been + omitted so that it can't be mistaken for part of the URL + (unfortunately that is still followed by a closing quote--in + the pline below, not the data here) */ "%sInvitation: Visit the NetHack web site at %s%s" }; const char *const it_reads = "It reads: \""; @@ -533,12 +537,12 @@ ckmailstatus(void) if (!mailbox || u.uswallow || !flags.biff #ifdef MAILCKFREQ - || gm.moves < laststattime + MAILCKFREQ + || svm.moves < laststattime + MAILCKFREQ #endif ) return; - laststattime = gm.moves; + laststattime = svm.moves; if (stat(mailbox, &nmstat)) { #ifdef PERMANENT_MAILBOX pline("Cannot get status of MAIL=\"%s\" anymore.", mailbox); @@ -668,8 +672,8 @@ ck_server_admin_msg(void) static struct stat ost,nst; static long lastchk = 0; - if (gm.moves < lastchk + SERVER_ADMIN_MSG_CKFREQ) return; - lastchk = gm.moves; + if (svm.moves < lastchk + SERVER_ADMIN_MSG_CKFREQ) return; + lastchk = svm.moves; if (!stat(SERVER_ADMIN_MSG, &nst)) { if (nst.st_mtime > ost.st_mtime) diff --git a/src/makemon.c b/src/makemon.c index 2e2662210..8c7643490 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 makemon.c $NHDT-Date: 1713334814 2024/04/17 06:20:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.245 $ */ +/* NetHack 3.7 makemon.c $NHDT-Date: 1720128166 2024/07/04 21:22:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.249 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -76,7 +76,10 @@ wrong_elem_type(struct permonst *ptr) /* make a group just like mtmp */ staticfn void -m_initgrp(struct monst *mtmp, coordxy x, coordxy y, int n, mmflags_nht mmflags) +m_initgrp( + struct monst *mtmp, + coordxy x, coordxy y, int n, + mmflags_nht mmflags) { coord mm; int cnt = rnd(n); @@ -830,7 +833,8 @@ clone_mon( struct monst *m2; /* may be too weak or have been extinguished for population control */ - if (mon->mhp <= 1 || (gm.mvitals[monsndx(mon->data)].mvflags & G_EXTINCT)) + if (mon->mhp <= 1 + || (svm.mvitals[monsndx(mon->data)].mvflags & G_EXTINCT) != 0) return (struct monst *) 0; if (x == 0) { @@ -894,7 +898,7 @@ clone_mon( } /* not all clones caused by player are tame or peaceful */ - if (!gc.context.mon_moving && mon->mpeaceful) { + if (!svc.context.mon_moving && mon->mpeaceful) { if (mon->mtame) m2->mtame = rn2(max(2 + u.uluck, 2)) ? mon->mtame : 0; else if (mon->mpeaceful) @@ -947,23 +951,23 @@ propagate(int mndx, boolean tally, boolean ghostly) boolean gone, result; int lim = mbirth_limit(mndx); - gone = (gm.mvitals[mndx].mvflags & G_GONE) != 0; /* geno'd|extinct */ - result = ((int) gm.mvitals[mndx].born < lim && !gone) ? TRUE : FALSE; + gone = (svm.mvitals[mndx].mvflags & G_GONE) != 0; /* geno'd|extinct */ + result = ((int) svm.mvitals[mndx].born < lim && !gone) ? TRUE : FALSE; /* if it's unique, don't ever make it again */ if ((mons[mndx].geno & G_UNIQ) != 0 && mndx != PM_HIGH_CLERIC) - gm.mvitals[mndx].mvflags |= G_EXTINCT; + svm.mvitals[mndx].mvflags |= G_EXTINCT; - if (gm.mvitals[mndx].born < 255 && tally && (!ghostly || result)) - gm.mvitals[mndx].born++; - if ((int) gm.mvitals[mndx].born >= lim + if (svm.mvitals[mndx].born < 255 && tally && (!ghostly || result)) + svm.mvitals[mndx].born++; + if ((int) svm.mvitals[mndx].born >= lim && !(mons[mndx].geno & G_NOGEN) - && !(gm.mvitals[mndx].mvflags & G_EXTINCT)) { + && !(svm.mvitals[mndx].mvflags & G_EXTINCT)) { if (wizard) { debugpline1("Automatically extinguished %s.", makeplural(mons[mndx].pmnames[NEUTRAL])); } - gm.mvitals[mndx].mvflags |= G_EXTINCT; + svm.mvitals[mndx].mvflags |= G_EXTINCT; } return result; } @@ -1152,7 +1156,7 @@ makemon( fakemon = cg.zeromonst; cc.x = cc.y = 0; - if (iflags.debug_mongen || (!gl.level.flags.rndmongen && !ptr)) + if (iflags.debug_mongen || (!svl.level.flags.rndmongen && !ptr)) return (struct monst *) 0; /* if caller wants random location, do it here */ @@ -1190,9 +1194,9 @@ makemon( mndx = monsndx(ptr); /* if you are to make a specific monster and it has already been genocided, return */ - if (gm.mvitals[mndx].mvflags & G_GENOD) + if (svm.mvitals[mndx].mvflags & G_GENOD) return (struct monst *) 0; - if (wizard && (gm.mvitals[mndx].mvflags & G_EXTINCT)) { + if (wizard && (svm.mvitals[mndx].mvflags & G_EXTINCT)) { debugpline1("Explicitly creating extinct monster %s.", mons[mndx].pmnames[NEUTRAL]); } @@ -1238,7 +1242,7 @@ makemon( mtmp->m_id = next_ident(); set_mon_data(mtmp, ptr); /* mtmp->data = ptr; */ if (ptr->msound == MS_LEADER && quest_info(MS_LEADER) == mndx) - gq.quest_status.leader_m_id = mtmp->m_id; + svq.quest_status.leader_m_id = mtmp->m_id; mtmp->mnum = mndx; /* set up level and hit points */ @@ -1255,9 +1259,9 @@ makemon( but for ones which can be random, it has already been chosen (in role_init(), for possible use by the quest pager code) */ else if (ptr->msound == MS_LEADER && quest_info(MS_LEADER) == mndx) - mtmp->female = gq.quest_status.ldrgend; + mtmp->female = svq.quest_status.ldrgend; else if (ptr->msound == MS_NEMESIS && quest_info(MS_NEMESIS) == mndx) - mtmp->female = gq.quest_status.nemgend; + mtmp->female = svq.quest_status.nemgend; /* female used to be set randomly here even for neuters on the grounds that it was ignored, but after corpses were changed to @@ -1269,7 +1273,7 @@ makemon( mon_learns_traps(mtmp, PIT); mon_learns_traps(mtmp, HOLE); } - if (Is_stronghold(&u.uz) && !mindless(ptr)) /* know about the trap doors */ + if (Is_stronghold(&u.uz) && !mindless(ptr)) /* know about trap doors */ mon_learns_traps(mtmp, TRAPDOOR); /* quest leader and nemesis both know about all trap types */ if (ptr->msound == MS_LEADER || ptr->msound == MS_NEMESIS) @@ -1350,8 +1354,8 @@ makemon( allow_minvent = FALSE; } else if (mndx == PM_WIZARD_OF_YENDOR) { mtmp->iswiz = TRUE; - gc.context.no_of_wizards++; - if (gc.context.no_of_wizards == 1 && Is_earthlevel(&u.uz)) + svc.context.no_of_wizards++; + if (svc.context.no_of_wizards == 1 && Is_earthlevel(&u.uz)) mitem = SPE_DIG; } else if (mndx == PM_GHOST && !(mmflags & MM_NONAME)) { mtmp = christen_monst(mtmp, rndghostname()); @@ -1502,10 +1506,11 @@ unmakemon( that just happened when creating this monster or the threshold had already been reached and further increments were suppressed; assume the latter */ - if (countbirth && gm.mvitals[mndx].born > 0 && gm.mvitals[mndx].born < 255) - gm.mvitals[mndx].born -= 1; + if (countbirth && svm.mvitals[mndx].born > 0 + && svm.mvitals[mndx].born < 255) + svm.mvitals[mndx].born -= 1; if ((mon->data->geno & G_UNIQ) != 0) - gm.mvitals[mndx].mvflags &= ~G_EXTINCT; + svm.mvitals[mndx].mvflags &= ~G_EXTINCT; mon->mhp = 0; /* let discard_minvent() know that mon isn't being kept */ /* uncreate any artifact that the monster was provided with; unlike @@ -1573,7 +1578,7 @@ uncommon(int mndx) { if (mons[mndx].geno & (G_NOGEN | G_UNIQ)) return TRUE; - if (gm.mvitals[mndx].mvflags & G_GONE) + if (svm.mvitals[mndx].mvflags & G_GONE) return TRUE; if (Inhell) return (boolean) (mons[mndx].maligntyp > A_NEUTRAL); @@ -1593,11 +1598,11 @@ align_shift(struct permonst *ptr) static NEARDATA s_level *lev; int alshift; - if (oldmoves != gm.moves) { + if (oldmoves != svm.moves) { lev = Is_special(&u.uz); - oldmoves = gm.moves; + oldmoves = svm.moves; } - switch ((lev) ? lev->flags.align : gd.dungeons[u.uz.dnum].flags.align) { + switch ((lev) ? lev->flags.align : svd.dungeons[u.uz.dnum].flags.align) { default: /* just in case */ case AM_NONE: alshift = 0; @@ -1619,8 +1624,8 @@ align_shift(struct permonst *ptr) staticfn int temperature_shift(struct permonst *ptr) { - if (gl.level.flags.temperature - && pm_resistance(ptr, (gl.level.flags.temperature > 0) + if (svl.level.flags.temperature + && pm_resistance(ptr, (svl.level.flags.temperature > 0) ? MR_FIRE : MR_COLD)) return 3; return 0; @@ -1716,7 +1721,7 @@ mk_gen_ok(int mndx, unsigned mvflagsmask, unsigned genomask) { struct permonst *ptr = &mons[mndx]; - if (gm.mvitals[mndx].mvflags & mvflagsmask) + if (svm.mvitals[mndx].mvflags & mvflagsmask) return FALSE; if (ptr->geno & genomask) return FALSE; @@ -1780,7 +1785,8 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ /* Assumption #2: monsters of a given class are presented in ascending * order of strength. */ - for (last = first; last < SPECIAL_PM && mons[last].mlet == class; last++) { + for (last = first; last < SPECIAL_PM && mons[last].mlet == class; + last++) { if (atyp != A_NONE && sgn(mons[last].maligntyp) != sgn(atyp)) continue; /* traditionally mkclass() ignored hell-only and never-in-hell; @@ -1812,7 +1818,7 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ against picking the next demon resulted in incubus being picked nearly twice as often as succubus); we need the '+1' in case the entire set is too high - level (really low gl.level hero) */ + level (really low svl.level hero) */ nums[last] = k + 1 - (adj_lev(&mons[last]) > (u.ulevel * 2)); num += nums[last]; } @@ -1876,7 +1882,7 @@ adj_lev(struct permonst *ptr) /* does not depend on other strengths, but does get stronger * every time he is killed */ - tmp = ptr->mlevel + gm.mvitals[PM_WIZARD_OF_YENDOR].died; + tmp = ptr->mlevel + svm.mvitals[PM_WIZARD_OF_YENDOR].died; if (tmp > 49) tmp = 49; return tmp; @@ -1977,12 +1983,12 @@ grow_up(struct monst *mtmp, struct monst *victim) /* new form might force gender change */ fem = is_male(ptr) ? 0 : is_female(ptr) ? 1 : mtmp->female; - if (gm.mvitals[newtype].mvflags & G_GENOD) { /* allow G_EXTINCT */ + if (svm.mvitals[newtype].mvflags & G_GENOD) { /* allow G_EXTINCT */ if (canspotmon(mtmp)) pline("As %s grows up into %s, %s %s!", mon_nam(mtmp), an(pmname(ptr, Mgender(mtmp))), mhe(mtmp), nonliving(ptr) ? "expires" : "dies"); - set_mon_data(mtmp, ptr); /* keep gm.mvitals[] accurate */ + set_mon_data(mtmp, ptr); /* keep svm.mvitals[] accurate */ mondied(mtmp); return (struct permonst *) 0; } else if (canspotmon(mtmp)) { @@ -1999,11 +2005,11 @@ grow_up(struct monst *mtmp, struct monst *victim) slightly less sexist if prepared for it...) */ : (fem && !mtmp->female) ? "female " : "", pmname(ptr, fem)); - pline("%s %s %s.", upstart(y_monnam(mtmp)), - (fem != mtmp->female) ? "changes into" - : humanoid(ptr) ? "becomes" - : "grows up into", - an(buf)); + pline_mon(mtmp, "%s %s %s.", YMonnam(mtmp), + (fem != mtmp->female) ? "changes into" + : humanoid(ptr) ? "becomes" + : "grows up into", + an(buf)); } set_mon_data(mtmp, ptr); if (mtmp->cham == oldtype && is_shapeshifter(ptr)) @@ -2261,7 +2267,7 @@ set_mimic_sym(struct monst *mtmp) /* only valid for INSIDE of room */ roomno = levl[mx][my].roomno - ROOMOFFSET; if (roomno >= 0) - rt = gr.rooms[roomno].rtype; + rt = svr.rooms[roomno].rtype; #ifdef SPECIALIZATION else if (IS_ROOM(typ)) rt = OROOM, roomno = 0; @@ -2271,7 +2277,7 @@ set_mimic_sym(struct monst *mtmp) if (OBJ_AT(mx, my)) { ap_type = M_AP_OBJECT; - appear = gl.level.objects[mx][my]->otyp; + appear = svl.level.objects[mx][my]->otyp; } else if (IS_DOOR(typ) || IS_WALL(typ) || typ == SDOOR || typ == SCORR) { ap_type = M_AP_FURNITURE; /* @@ -2291,7 +2297,7 @@ set_mimic_sym(struct monst *mtmp) appear = Is_rogue_level(&u.uz) ? S_hwall : S_hcdoor; else appear = Is_rogue_level(&u.uz) ? S_vwall : S_vcdoor; - } else if (gl.level.flags.is_maze_lev + } else if (svl.level.flags.is_maze_lev && !(In_mines(&u.uz) && in_town(u.ux, u.uy)) && !In_sokoban(&u.uz) && rn2(2)) { ap_type = M_AP_OBJECT; @@ -2371,7 +2377,7 @@ set_mimic_sym(struct monst *mtmp) && (appear == STATUE || appear == FIGURINE || appear == CORPSE || appear == EGG || appear == TIN)) { int mndx = rndmonnum(), - nocorpse_ndx = (gm.mvitals[mndx].mvflags & G_NOCORPSE) != 0; + nocorpse_ndx = (svm.mvitals[mndx].mvflags & G_NOCORPSE) != 0; if (appear == CORPSE && nocorpse_ndx) mndx = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1, PM_ARCHEOLOGIST); @@ -2383,7 +2389,7 @@ set_mimic_sym(struct monst *mtmp) MCORPSENM(mtmp) = mndx; } else if (ap_type == M_AP_OBJECT && appear == SLIME_MOLD) { newmcorpsenm(mtmp); - MCORPSENM(mtmp) = gc.context.current_fruit; + MCORPSENM(mtmp) = svc.context.current_fruit; /* if no objects of this fruit type have been created yet, context.current_fruit is available for re-use when the player assigns a new fruit name; override that--having a mimic as the diff --git a/src/mcastu.c b/src/mcastu.c index afa7a8722..68a8a8119 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -64,7 +64,7 @@ cursetxt(struct monst *mtmp, boolean undirected) point_msg = "at you, then curses"; pline_mon(mtmp, "%s points %s.", Monnam(mtmp), point_msg); - } else if ((!(gm.moves % 4) || !rn2(4))) { + } else if ((!(svm.moves % 4) || !rn2(4))) { if (!Deaf) Norep("You hear a mumbled curse."); /* Deaf-aware */ } @@ -388,14 +388,14 @@ touch_of_death(struct monst *mtmp) u.mh = 0; rehumanize(); /* fatal iff Unchanging */ } else if (drain >= u.uhpmax) { - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, kbuf); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, kbuf); done(DIED); } else { u.uhpmax -= drain; losehp(dmg, kbuf, KILLED_BY); } - gk.killer.name[0] = '\0'; /* not killed if we get here... */ + svk.killer.name[0] = '\0'; /* not killed if we get here... */ } /* give a reason for death by some monster spells */ @@ -468,7 +468,7 @@ cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum) dmg = 0; break; case MGC_CLONE_WIZ: - if (mtmp->iswiz && gc.context.no_of_wizards == 1) { + if (mtmp->iswiz && svc.context.no_of_wizards == 1) { pline("Double Trouble..."); clonewiz(); dmg = 0; @@ -544,7 +544,7 @@ cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum) losestr(rnd(dmg), death_inflicted_by(kbuf, "strength loss", mtmp), KILLED_BY); - gk.killer.name[0] = '\0'; /* not killed if we get here... */ + svk.killer.name[0] = '\0'; /* not killed if we get here... */ monstunseesu(M_SEEN_MAGR); } dmg = 0; @@ -928,7 +928,7 @@ spell_would_be_useless(struct monst *mtmp, unsigned int adtyp, int spellnum) if (!mcouldseeu && (spellnum == MGC_SUMMON_MONS || (!mtmp->iswiz && spellnum == MGC_CLONE_WIZ))) return TRUE; - if ((!mtmp->iswiz || gc.context.no_of_wizards > 1) + if ((!mtmp->iswiz || svc.context.no_of_wizards > 1) && spellnum == MGC_CLONE_WIZ) return TRUE; /* aggravation (global wakeup) when everyone is already active */ diff --git a/src/mdlib.c b/src/mdlib.c index 530574547..b6da48e33 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -76,7 +76,7 @@ extern int GUILaunched; /* these are in extern.h but we don't include hack.h */ /* XXX move to new file mdlib.h? */ -extern void populate_nomakedefs(struct version_info *) NONNULLARG1; /* date.c */ +extern void populate_nomakedefs(struct version_info *) NONNULLARG1; /*date.c*/ extern void free_nomakedefs(void); /* date.c */ void runtime_info_init(void); const char *do_runtime_info(int *) NO_NNARGS; @@ -363,9 +363,9 @@ version_id_string(char *outbuf, size_t bufsz, const char *build_date) Strcpy(&subbuf[1], PORT_SUB_ID); #endif - Snprintf(outbuf, bufsz, "%s NetHack%s Version %s%s - last %s %s.", PORT_ID, - subbuf, mdlib_version_string(versbuf, "."), statusbuf, - date_via_env ? "revision" : "build", build_date); + Snprintf(outbuf, bufsz, "%s NetHack%s Version %s%s - last %s %s.", + PORT_ID, subbuf, mdlib_version_string(versbuf, "."), statusbuf, + date_via_env ? "revision" : "build", build_date); return outbuf; } @@ -836,7 +836,8 @@ build_options(void) /* 1 2 3 4 5 6 7 1234567890123456789012345678901234567890123456789012345678901234567890123456 */ - " \"Permission is hereby granted, free of charge, to any person obtaining", + (" \"Permission is hereby granted, free of charge," + " to any person obtaining"), " a copy of this software and associated documentation files (the ", " \"Software\"), to deal in the Software without restriction including", " without limitation the rights to use, copy, modify, merge, publish,", diff --git a/src/mhitm.c b/src/mhitm.c index d74866296..a473fa06c 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -28,9 +28,9 @@ noises(struct monst *magr, struct attack *mattk) { boolean farq = (mdistu(magr) > 15); - if (!Deaf && (farq != gf.far_noise || gm.moves - gn.noisetime > 10)) { + if (!Deaf && (farq != gf.far_noise || svm.moves - gn.noisetime > 10)) { gf.far_noise = farq; - gn.noisetime = gm.moves; + gn.noisetime = svm.moves; You_hear("%s%s.", (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises", farq ? " in the distance" : ""); @@ -360,7 +360,7 @@ mattackm( * some cases, in which case this still counts as its move for the round * and it shouldn't move again. */ - magr->mlstmv = gm.moves; + magr->mlstmv = svm.moves; /* controls whether a mind flayer uses all of its tentacle-for-DRIN attacks; when fighting a headless monster, stop after the first @@ -1090,7 +1090,8 @@ mdamagem( } else if (pd == &mons[PM_WRAITH]) { (void) grow_up(magr, (struct monst *) 0); /* don't grow up twice */ - return (M_ATTK_DEF_DIED | (!DEADMONSTER(magr) ? 0 : M_ATTK_AGR_DIED)); + return (M_ATTK_DEF_DIED + | (!DEADMONSTER(magr) ? 0 : M_ATTK_AGR_DIED)); } else if (pd == &mons[PM_NURSE]) { magr->mhp = magr->mhpmax; } @@ -1098,7 +1099,8 @@ mdamagem( } /* caveat: above digestion handling doesn't keep `pa' up to date */ - return (M_ATTK_DEF_DIED | (grow_up(magr, mdef) ? 0 : M_ATTK_AGR_DIED)); + return (M_ATTK_DEF_DIED + | (grow_up(magr, mdef) ? 0 : M_ATTK_AGR_DIED)); } return (mhm.hitflags == M_ATTK_AGR_DIED) ? M_ATTK_AGR_DIED : M_ATTK_HIT; } @@ -1266,7 +1268,8 @@ mswingsm( { if (flags.verbose && !Blind && mon_visible(magr)) { boolean bash = (is_pole(otemp) - && dist2(magr->mx, magr->my, mdef->mx, mdef->my) <= 2); + && (dist2(magr->mx, magr->my, mdef->mx, mdef->my) + <= 2)); pline("%s %s %s%s %s at %s.", Monnam(magr), mswings_verb(otemp, bash), (otemp->quan > 1L) ? "one of " : "", mhis(magr), xname(otemp), diff --git a/src/mhitu.c b/src/mhitu.c index 1a2e59400..b7f338294 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mhitu.c $NHDT-Date: 1689448844 2023/07/15 19:20:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.301 $ */ +/* NetHack 3.7 mhitu.c $NHDT-Date: 1721844072 2024/07/24 18:01:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.318 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -132,8 +132,10 @@ mswings( boolean bash) /* True: polearm used at too close range */ { if (flags.verbose && !Blind && mon_visible(mtmp)) { - pline_mon(mtmp, "%s %s %s%s %s.", Monnam(mtmp), mswings_verb(otemp, bash), - (otemp->quan > 1L) ? "one of " : "", mhis(mtmp), xname(otemp)); + pline_mon(mtmp, "%s %s %s%s %s.", Monnam(mtmp), + mswings_verb(otemp, bash), + (otemp->quan > 1L) ? "one of " : "", + mhis(mtmp), xname(otemp)); } } @@ -302,12 +304,15 @@ expels( /* select a monster's next attack, possibly substituting for its usual one */ struct attack * -getmattk(struct monst *magr, struct monst *mdef, - int indx, int prev_result[], struct attack *alt_attk_buf) +getmattk( + struct monst *magr, struct monst *mdef, + int indx, int prev_result[], + struct attack *alt_attk_buf) { struct permonst *mptr = magr->data; struct attack *attk = &mptr->mattk[indx]; struct obj *weap = (magr == &gy.youmonst) ? uwep : MON_WEP(magr); + boolean udefend = mdef == &gy.youmonst; /* honor SEDUCE=0 */ if (!SYSOPT_SEDUCE) { @@ -338,7 +343,7 @@ getmattk(struct monst *magr, struct monst *mdef, attk->adtyp = AD_STUN; /* make drain-energy damage be somewhat in proportion to energy */ - } else if (attk->adtyp == AD_DREN && mdef == &gy.youmonst) { + } else if (attk->adtyp == AD_DREN && udefend) { int ulev = max(u.ulevel, 6); *alt_attk_buf = *attk; @@ -400,7 +405,31 @@ getmattk(struct monst *magr, struct monst *mdef, *alt_attk_buf = *attk; attk = alt_attk_buf; attk->adtyp = AD_PHYS; + + /* liches have a touch attack for cold damage and also a spell attack; + they won't use the spell for monster vs monster so become impotent + aganst cold resistant foes; change the touch damage from cold to + physical if target will resist */ + } else if (indx == 0 && attk->aatyp == AT_TUCH && attk->adtyp == AD_COLD + && (udefend ? Cold_resistance : resists_cold(mdef)) + /* don't substitute if target is immune to normal damage */ + && mdef->data != &mons[PM_SHADE]) { + *alt_attk_buf = *attk; + attk = alt_attk_buf; + attk->adtyp = AD_PHYS; + /* lessen new physical damage compared to old cold damage: + * before after + * lich: 1d10 1d6 + * demi: 3d4 2d4 + * master: 3d6 2d6 + * arch-: 5d6 3d6 + */ + attk->damn = (attk->damn + 1) / 2; + if (attk->damd == 10) + attk->damd = 6; + } + return attk; } @@ -566,7 +595,7 @@ mattacku(struct monst *mtmp) * parallelism to work, we can't rephrase it, so we * zap the "laid by you" momentarily instead. */ - struct obj *obj = gl.level.objects[u.ux][u.uy]; + struct obj *obj = svl.level.objects[u.ux][u.uy]; if (obj || u.umonnum == PM_TRAPPER || (gy.youmonst.data->mlet == S_EEL @@ -585,14 +614,14 @@ mattacku(struct monst *mtmp) pline( "Wait, %s! There's a hidden %s named %s there!", m_monnam(mtmp), - pmname(gy.youmonst.data, Ugender), gp.plname); + pmname(gy.youmonst.data, Ugender), svp.plname); else pline( "Wait, %s! There's a %s named %s hiding under %s!", m_monnam(mtmp), pmname(gy.youmonst.data, Ugender), - gp.plname, - doname(gl.level.objects[u.ux][u.uy])); + svp.plname, + doname(svl.level.objects[u.ux][u.uy])); if (obj) obj->spe = save_spe; } else @@ -614,7 +643,7 @@ mattacku(struct monst *mtmp) pline("It gets stuck on you."); else /* see note about m_monnam() above */ pline("Wait, %s! That's a %s named %s!", m_monnam(mtmp), - pmname(gy.youmonst.data, Ugender), gp.plname); + pmname(gy.youmonst.data, Ugender), svp.plname); if (sticky) set_ustuck(mtmp); gy.youmonst.m_ap_type = M_AP_NOTHING; @@ -628,14 +657,15 @@ mattacku(struct monst *mtmp) if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); if (!youseeit) - pline("%s %s!", Something, (likes_gold(mtmp->data) - && gy.youmonst.mappearance == GOLD_PIECE) - ? "tries to pick you up" - : "disturbs you"); + pline("%s %s!", Something, + (likes_gold(mtmp->data) + && gy.youmonst.mappearance == GOLD_PIECE) + ? "tries to pick you up" + : "disturbs you"); else /* see note about m_monnam() above */ pline("Wait, %s! That %s is really %s named %s!", m_monnam(mtmp), mimic_obj_name(&gy.youmonst), - an(pmname(&mons[u.umonnum], Ugender)), gp.plname); + an(pmname(&mons[u.umonnum], Ugender)), svp.plname); if (gm.multi < 0) { /* this should always be the case */ char buf[BUFSZ]; @@ -870,7 +900,7 @@ mattacku(struct monst *mtmp) bot(); /* give player a chance of waking up before dying -kaa */ if (sum[i] == M_ATTK_HIT) { /* successful attack */ - if (u.usleep && u.usleep < gm.moves && !rn2(10)) { + if (u.usleep && u.usleep < svm.moves && !rn2(10)) { gm.multi = -1; gn.nomovemsg = "The combat suddenly awakens you."; } @@ -1060,7 +1090,8 @@ magic_negation(struct monst *mon) protection is too easy); it confers minimum mc 1 instead of 0 */ if ((is_you && ((HProtection && u.ublessed > 0) || u.uspellprot)) /* aligned priests and angels have innate intrinsic Protection */ - || (mon->data == &mons[PM_ALIGNED_CLERIC] || is_minion(mon->data))) + || (mon->data == &mons[PM_ALIGNED_CLERIC] + || is_minion(mon->data))) mc = 1; } return mc; @@ -1095,7 +1126,7 @@ hitmu(struct monst *mtmp, struct attack *mattk) const char *what; char Amonbuf[BUFSZ]; - if ((obj = gl.level.objects[mtmp->mx][mtmp->my]) != 0) { + if ((obj = svl.level.objects[mtmp->mx][mtmp->my]) != 0) { if (Blind && !obj->dknown) what = something; else if (is_pool(mtmp->mx, mtmp->my) && !Underwater) @@ -1667,8 +1698,8 @@ gazemu(struct monst *mtmp, struct attack *mattk) if (poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM)) break; urgent_pline("You turn to stone..."); - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, pmname(mtmp->data, Mgender(mtmp))); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, pmname(mtmp->data, Mgender(mtmp))); done(STONING); } break; @@ -1837,7 +1868,7 @@ mdamageu(struct monst *mtmp, int n) int could_seduce( struct monst *magr, struct monst *mdef, - struct attack *mattk) /* non-Null: current atk; Null: general capability */ + struct attack *mattk) /* non-Null: current atk; Null: genrl capability */ { struct permonst *pagr; boolean agrinvis, defperc; @@ -1965,7 +1996,7 @@ doseduce(struct monst *mon) /* confirmation prompt when charisma is high bypassed if deaf */ if (!Deaf && rn2(20) < ACURR(A_CHA)) { (void) safe_qbuf(qbuf, "\"That ", - " looks pretty. Would you wear it for me?\"", + " looks pretty. Would you wear it for me?\"", ring, xname, simpleonames, "ring"); makeknown(RIN_ADORNMENT); SetVoice(mon, 0, 80, 0); @@ -2221,7 +2252,7 @@ mayberem(struct monst *mon, if (Deaf) { pline("%s takes off your %s.", seducer, str); } else if (rn2(20) < ACURR(A_CHA)) { - SetVoice(mon, 0, 80, 0); /* y_n a.k.a. yn_function is set up for this */ + SetVoice(mon, 0, 80, 0); /* y_n aka yn_function is set up for this */ Sprintf(qbuf, "\"Shall I remove your %s, %s?\"", str, (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart")); if (y_n(qbuf) == 'n') @@ -2451,14 +2482,14 @@ cloneu(void) if (u.mh <= 1) return (struct monst *) 0; - if (gm.mvitals[mndx].mvflags & G_EXTINCT) + if (svm.mvitals[mndx].mvflags & G_EXTINCT) return (struct monst *) 0; mon = makemon(gy.youmonst.data, u.ux, u.uy, NO_MINVENT | MM_EDOG | MM_NOMSG); if (!mon) return NULL; mon->mcloned = 1; - mon = christen_monst(mon, gp.plname); + mon = christen_monst(mon, svp.plname); initedog(mon); mon->m_lev = gy.youmonst.data->mlevel; mon->mhpmax = u.mhmax; diff --git a/src/minion.c b/src/minion.c index 1aee993a0..77644e7a7 100644 --- a/src/minion.c +++ b/src/minion.c @@ -133,7 +133,7 @@ msummon(struct monst *mon) * If this daemon is unique and being re-summoned (the only way we * could get this far with an extinct dtype), try another. */ - if ((gm.mvitals[dtype].mvflags & G_GONE) != 0) { + if ((svm.mvitals[dtype].mvflags & G_GONE) != 0) { dtype = ndemon(atyp); if (dtype == NON_PM) return 0; @@ -388,7 +388,7 @@ dprince(aligntyp atyp) for (tryct = !In_endgame(&u.uz) ? 20 : 0; tryct > 0; --tryct) { pm = rn1(PM_DEMOGORGON + 1 - PM_ORCUS, PM_ORCUS); - if (!(gm.mvitals[pm].mvflags & G_GONE) + if (!(svm.mvitals[pm].mvflags & G_GONE) && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp))) return pm; } @@ -402,7 +402,7 @@ dlord(aligntyp atyp) for (tryct = !In_endgame(&u.uz) ? 20 : 0; tryct > 0; --tryct) { pm = rn1(PM_YEENOGHU + 1 - PM_JUIBLEX, PM_JUIBLEX); - if (!(gm.mvitals[pm].mvflags & G_GONE) + if (!(svm.mvitals[pm].mvflags & G_GONE) && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp))) return pm; } @@ -413,7 +413,7 @@ dlord(aligntyp atyp) int llord(void) { - if (!(gm.mvitals[PM_ARCHON].mvflags & G_GONE)) + if (!(svm.mvitals[PM_ARCHON].mvflags & G_GONE)) return PM_ARCHON; return lminion(); /* approximate */ @@ -459,7 +459,8 @@ ndemon(aligntyp atyp) /* A_NONE is used for 'any alignment' */ /* guardian angel has been affected by conflict so is abandoning hero */ void -lose_guardian_angel(struct monst *mon) /* if null, angel hasn't been created yet */ +lose_guardian_angel( + struct monst *mon) /* if Null, angel hasn't been created yet */ { coord mm; int i; diff --git a/src/mklev.c b/src/mklev.c index 589d12d60..d4205b12a 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -64,7 +64,7 @@ mkroom_cmp(const genericptr vx, const genericptr vy) } /* Return TRUE if a door placed at (x, y) which otherwise passes okdoor() - * checks would be connecting into an area that was declared as joined = false. + * checks would be connecting into an area that was declared as joined=false. * Checking for this in finddpos() enables us to have rooms with sub-areas * (such as shops) that will never randomly generate unwanted doors in order * to connect them up to other areas. @@ -82,7 +82,7 @@ door_into_nonjoined(coordxy x, coordxy y) /* Is this connecting to a room that doesn't want joining? */ if (levl[tx][ty].roomno >= ROOMOFFSET - && !gr.rooms[levl[tx][ty].roomno - ROOMOFFSET].needjoining) { + && !svr.rooms[levl[tx][ty].roomno - ROOMOFFSET].needjoining) { return TRUE; } } @@ -124,13 +124,13 @@ void sort_rooms(void) { coordxy x, y; - unsigned i, ri[MAXNROFROOMS + 1] = { 0U }, n = (unsigned) gn.nroom; + unsigned i, ri[MAXNROFROOMS + 1] = { 0U }, n = (unsigned) svn.nroom; - qsort((genericptr_t) gr.rooms, n, sizeof (struct mkroom), mkroom_cmp); + qsort((genericptr_t) svr.rooms, n, sizeof (struct mkroom), mkroom_cmp); /* Update the roomnos on the map */ for (i = 0; i < n; i++) - ri[gr.rooms[i].roomnoidx] = i; + ri[svr.rooms[i].roomnoidx] = i; for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { @@ -170,7 +170,7 @@ do_room_or_subroom(struct mkroom *croom, } else croom->rlit = 0; - croom->roomnoidx = (croom - gr.rooms); + croom->roomnoidx = (croom - svr.rooms); croom->lx = lowx; croom->hx = hix; croom->ly = lowy; @@ -220,12 +220,12 @@ add_room(int lowx, int lowy, int hix, int hiy, { struct mkroom *croom; - croom = &gr.rooms[gn.nroom]; + croom = &svr.rooms[svn.nroom]; do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, (boolean) TRUE); croom++; croom->hx = -1; - gn.nroom++; + svn.nroom++; } void @@ -254,7 +254,7 @@ free_luathemes(enum lua_theme_group theme_group) * most_themes => entering endgame, free non-endgame themes; * all_themes => end of game, free all themes. */ - for (i = 0; i < gn.n_dgns; ++i) { + for (i = 0; i < svn.n_dgns; ++i) { if ((theme_group == tut_themes && i != tutorial_dnum) || (theme_group == most_themes && i == astral_level.dnum)) continue; @@ -274,7 +274,7 @@ makerooms(void) nhl_sandbox_info sbi = {NHL_SB_SAFE, 1*1024*1024, 0, 1*1024*1024}; lua_State *themes = (lua_State *) gl.luathemes[u.uz.dnum]; - if (!themes && *(fname = gd.dungeons[u.uz.dnum].themerms)) { + if (!themes && *(fname = svd.dungeons[u.uz.dnum].themerms)) { if ((themes = nhl_init(&sbi)) != 0) { if (!nhl_loadlua(themes, fname)) { /* loading lua failed, don't use themed rooms */ @@ -288,7 +288,7 @@ makerooms(void) } } if (!themes) /* don't try again when making next level */ - *fname = '\0'; /* gd.dungeons[u.uz.dnum].themerms */ + *fname = '\0'; /* svd.dungeons[u.uz.dnum].themerms */ } if (themes) { @@ -302,13 +302,13 @@ makerooms(void) /* make rooms until satisfied */ /* rnd_rect() will returns 0 if no more rects are available... */ - while (gn.nroom < (MAXNROFROOMS - 1) && rnd_rect()) { - if (gn.nroom >= (MAXNROFROOMS / 6) && rn2(2) && !tried_vault) { + while (svn.nroom < (MAXNROFROOMS - 1) && rnd_rect()) { + if (svn.nroom >= (MAXNROFROOMS / 6) && rn2(2) && !tried_vault) { tried_vault = TRUE; if (create_vault()) { - gv.vault_x = gr.rooms[gn.nroom].lx; - gv.vault_y = gr.rooms[gn.nroom].ly; - gr.rooms[gn.nroom].hx = -1; + gv.vault_x = svr.rooms[svn.nroom].lx; + gv.vault_y = svr.rooms[svn.nroom].ly; + svr.rooms[svn.nroom].hx = -1; } } else { if (themes) { @@ -319,7 +319,7 @@ makerooms(void) iflags.in_lua = gi.in_mk_themerooms = FALSE; if (gt.themeroom_failed && ((themeroom_tries++ > 10) - || (gn.nroom >= (MAXNROFROOMS / 6)))) + || (svn.nroom >= (MAXNROFROOMS / 6)))) break; } else { if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1)) @@ -345,8 +345,8 @@ join(int a, int b, boolean nxcor) struct mkroom *croom, *troom; int dx, dy; - croom = &gr.rooms[a]; - troom = &gr.rooms[b]; + croom = &svr.rooms[a]; + troom = &svr.rooms[b]; if (!croom->needjoining || !troom->needjoining) return; @@ -408,7 +408,7 @@ join(int a, int b, boolean nxcor) dest.y = ty; if (!dig_corridor(&org, &dest, nxcor, - gl.level.flags.arboreal ? ROOM : CORR, STONE)) + svl.level.flags.arboreal ? ROOM : CORR, STONE)) return; /* we succeeded in digging the corridor */ @@ -428,48 +428,49 @@ makecorridors(void) int a, b, i; boolean any = TRUE; - for (a = 0; a < gn.nroom - 1; a++) { + for (a = 0; a < svn.nroom - 1; a++) { join(a, a + 1, FALSE); if (!rn2(50)) break; /* allow some randomness */ } - for (a = 0; a < gn.nroom - 2; a++) + for (a = 0; a < svn.nroom - 2; a++) if (gs.smeq[a] != gs.smeq[a + 2]) join(a, a + 2, FALSE); - for (a = 0; any && a < gn.nroom; a++) { + for (a = 0; any && a < svn.nroom; a++) { any = FALSE; - for (b = 0; b < gn.nroom; b++) + for (b = 0; b < svn.nroom; b++) if (gs.smeq[a] != gs.smeq[b]) { join(a, b, FALSE); any = TRUE; } } /* add some extra corridors which may be blocked off */ - if (gn.nroom > 2) - for (i = rn2(gn.nroom) + 4; i; i--) { - a = rn2(gn.nroom); - b = rn2(gn.nroom - 2); + if (svn.nroom > 2) + for (i = rn2(svn.nroom) + 4; i; i--) { + a = rn2(svn.nroom); + b = rn2(svn.nroom - 2); if (b >= a) b += 2; join(a, b, TRUE); } } -/* (re)allocate space for gd.doors array */ +/* (re)allocate space for svd.doors array */ staticfn void alloc_doors(void) { - if (!gd.doors || gd.doorindex >= gd.doors_alloc) { - int c = gd.doors_alloc + DOORINC; - coord *doortmp = (coord *) alloc(c * sizeof(coord)); + if (!svd.doors || gd.doorindex >= svd.doors_alloc) { + int c = svd.doors_alloc + DOORINC; + coord *doortmp = (coord *) alloc(c * sizeof (coord)); - (void) memset((genericptr_t) doortmp, 0, c * sizeof(coord)); - if (gd.doors) { - (void) memcpy(doortmp, gd.doors, gd.doors_alloc * sizeof(coord)); - free(gd.doors); + (void) memset((genericptr_t) doortmp, 0, c * sizeof (coord)); + if (svd.doors) { + (void) memcpy(doortmp, svd.doors, + svd.doors_alloc * sizeof (coord)); + free(svd.doors); } - gd.doors = doortmp; - gd.doors_alloc = c; + svd.doors = doortmp; + svd.doors_alloc = c; } } @@ -485,7 +486,7 @@ add_door(coordxy x, coordxy y, struct mkroom *aroom) if (aroom->doorct) { for (i = 0; i < aroom->doorct; i++) { tmp = aroom->fdoor + i; - if (gd.doors[tmp].x == x && gd.doors[tmp].y == y) + if (svd.doors[tmp].x == x && svd.doors[tmp].y == y) return; } } @@ -496,10 +497,10 @@ add_door(coordxy x, coordxy y, struct mkroom *aroom) aroom->doorct++; for (tmp = gd.doorindex; tmp > aroom->fdoor; tmp--) - gd.doors[tmp] = gd.doors[tmp - 1]; + svd.doors[tmp] = svd.doors[tmp - 1]; - for (i = 0; i < gn.nroom; i++) { - broom = &gr.rooms[i]; + for (i = 0; i < svn.nroom; i++) { + broom = &svr.rooms[i]; if (broom != aroom && broom->doorct && broom->fdoor >= aroom->fdoor) broom->fdoor++; } @@ -510,8 +511,8 @@ add_door(coordxy x, coordxy y, struct mkroom *aroom) } gd.doorindex++; - gd.doors[aroom->fdoor].x = x; - gd.doors[aroom->fdoor].y = y; + svd.doors[aroom->fdoor].x = x; + svd.doors[aroom->fdoor].y = y; } staticfn void @@ -546,7 +547,7 @@ dosdoor(coordxy x, coordxy y, struct mkroom *aroom, int type) } /* also done in roguecorr(); doing it here first prevents - making mimics in place of trapped doors on rogue gl.level */ + making mimics in place of trapped doors on rogue svl.level */ if (Is_rogue_level(&u.uz)) levl[x][y].doormask = D_NODOOR; @@ -554,9 +555,9 @@ dosdoor(coordxy x, coordxy y, struct mkroom *aroom, int type) struct monst *mtmp; if (level_difficulty() >= 9 && !rn2(5) - && !((gm.mvitals[PM_SMALL_MIMIC].mvflags & G_GONE) - && (gm.mvitals[PM_LARGE_MIMIC].mvflags & G_GONE) - && (gm.mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) { + && !((svm.mvitals[PM_SMALL_MIMIC].mvflags & G_GONE) + && (svm.mvitals[PM_LARGE_MIMIC].mvflags & G_GONE) + && (svm.mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) { /* make a mimic instead */ levl[x][y].doormask = D_NODOOR; mtmp = makemon(mkclass(S_MIMIC, 0), x, y, NO_MM_FLAGS); @@ -583,7 +584,7 @@ dosdoor(coordxy x, coordxy y, struct mkroom *aroom, int type) staticfn boolean cardinal_nextto_room(struct mkroom *aroom, coordxy x, coordxy y) { - int rmno = (int) ((aroom - gr.rooms) + ROOMOFFSET); + int rmno = (int) ((aroom - svr.rooms) + ROOMOFFSET); if (isok(x - 1, y) && !levl[x - 1][y].edge && (int) levl[x - 1][y].roomno == rmno) @@ -610,11 +611,13 @@ place_niche( if (rn2(2)) { *dy = 1; - if (!finddpos(&dd, aroom->lx, aroom->hy + 1, aroom->hx, aroom->hy + 1)) + if (!finddpos(&dd, aroom->lx, aroom->hy + 1, + aroom->hx, aroom->hy + 1)) return FALSE; } else { *dy = -1; - if (!finddpos(&dd, aroom->lx, aroom->ly - 1, aroom->hx, aroom->ly - 1)) + if (!finddpos(&dd, aroom->lx, aroom->ly - 1, + aroom->hx, aroom->ly - 1)) return FALSE; } *xx = dd.x; @@ -649,7 +652,7 @@ makeniche(int trap_type) struct trap *ttmp; while (vct--) { - aroom = &gr.rooms[rn2(gn.nroom)]; + aroom = &svr.rooms[rn2(svn.nroom)]; if (aroom->rtype != OROOM) continue; /* not an ordinary room */ if (aroom->doorct == 1 && rn2(5)) @@ -690,7 +693,7 @@ makeniche(int trap_type) mkclass(S_HUMAN, 0), xx, yy + dy, TRUE); } - if (!gl.level.flags.noteleport) + if (!svl.level.flags.noteleport) (void) mksobj_at(SCR_TELEPORTATION, xx, yy + dy, TRUE, FALSE); if (!rn2(3)) @@ -704,8 +707,8 @@ makeniche(int trap_type) staticfn void make_niches(void) { - int ct = rnd((gn.nroom >> 1) + 1), dep = depth(&u.uz); - boolean ltptr = (!gl.level.flags.noteleport && dep > 15), + int ct = rnd((svn.nroom >> 1) + 1), dep = depth(&u.uz); + boolean ltptr = (!svl.level.flags.noteleport && dep > 15), vamp = (dep > 5 && dep < 25); while (ct--) { @@ -732,15 +735,15 @@ count_level_features(void) { coordxy x, y; - gl.level.flags.nfountains = gl.level.flags.nsinks = 0; + svl.level.flags.nfountains = svl.level.flags.nsinks = 0; for (y = 0; y < ROWNO; y++) for (x = 1; x < COLNO; x++) { int typ = levl[x][y].typ; if (typ == FOUNTAIN) - gl.level.flags.nfountains++; + svl.level.flags.nfountains++; else if (typ == SINK) - gl.level.flags.nsinks++; + svl.level.flags.nsinks++; } } @@ -765,55 +768,55 @@ clear_level_structures(void) lev = &levl[x][0]; for (y = 0; y < ROWNO; y++) { *lev++ = zerorm; - gl.level.objects[x][y] = (struct obj *) 0; - gl.level.monsters[x][y] = (struct monst *) 0; + svl.level.objects[x][y] = (struct obj *) 0; + svl.level.monsters[x][y] = (struct monst *) 0; } } - gl.level.objlist = (struct obj *) 0; - gl.level.buriedobjlist = (struct obj *) 0; - gl.level.monlist = (struct monst *) 0; - gl.level.damagelist = (struct damage *) 0; - gl.level.bonesinfo = (struct cemetery *) 0; + svl.level.objlist = (struct obj *) 0; + svl.level.buriedobjlist = (struct obj *) 0; + svl.level.monlist = (struct monst *) 0; + svl.level.damagelist = (struct damage *) 0; + svl.level.bonesinfo = (struct cemetery *) 0; - gl.level.flags.nfountains = 0; - gl.level.flags.nsinks = 0; - gl.level.flags.has_shop = 0; - gl.level.flags.has_vault = 0; - gl.level.flags.has_zoo = 0; - gl.level.flags.has_court = 0; - gl.level.flags.has_morgue = gl.level.flags.graveyard = 0; - gl.level.flags.has_beehive = 0; - gl.level.flags.has_barracks = 0; - gl.level.flags.has_temple = 0; - gl.level.flags.has_swamp = 0; - gl.level.flags.noteleport = 0; - gl.level.flags.hardfloor = 0; - gl.level.flags.nommap = 0; - gl.level.flags.hero_memory = 1; - gl.level.flags.shortsighted = 0; - gl.level.flags.sokoban_rules = 0; - gl.level.flags.is_maze_lev = 0; - gl.level.flags.is_cavernous_lev = 0; - gl.level.flags.arboreal = 0; - gl.level.flags.has_town = 0; - gl.level.flags.wizard_bones = 0; - gl.level.flags.corrmaze = 0; - gl.level.flags.temperature = In_hell(&u.uz) ? 1 : 0; - gl.level.flags.rndmongen = 1; - gl.level.flags.deathdrops = 1; - gl.level.flags.noautosearch = 0; - gl.level.flags.fumaroles = 0; - gl.level.flags.stormy = 0; + svl.level.flags.nfountains = 0; + svl.level.flags.nsinks = 0; + svl.level.flags.has_shop = 0; + svl.level.flags.has_vault = 0; + svl.level.flags.has_zoo = 0; + svl.level.flags.has_court = 0; + svl.level.flags.has_morgue = svl.level.flags.graveyard = 0; + svl.level.flags.has_beehive = 0; + svl.level.flags.has_barracks = 0; + svl.level.flags.has_temple = 0; + svl.level.flags.has_swamp = 0; + svl.level.flags.noteleport = 0; + svl.level.flags.hardfloor = 0; + svl.level.flags.nommap = 0; + svl.level.flags.hero_memory = 1; + svl.level.flags.shortsighted = 0; + svl.level.flags.sokoban_rules = 0; + svl.level.flags.is_maze_lev = 0; + svl.level.flags.is_cavernous_lev = 0; + svl.level.flags.arboreal = 0; + svl.level.flags.has_town = 0; + svl.level.flags.wizard_bones = 0; + svl.level.flags.corrmaze = 0; + svl.level.flags.temperature = In_hell(&u.uz) ? 1 : 0; + svl.level.flags.rndmongen = 1; + svl.level.flags.deathdrops = 1; + svl.level.flags.noautosearch = 0; + svl.level.flags.fumaroles = 0; + svl.level.flags.stormy = 0; - gn.nroom = 0; - gr.rooms[0].hx = -1; + svn.nroom = 0; + svr.rooms[0].hx = -1; gn.nsubroom = 0; gs.subrooms[0].hx = -1; gd.doorindex = 0; - if (gd.doors_alloc) { - free((genericptr_t) gd.doors); - gd.doors = (coord *) 0; - gd.doors_alloc = 0; + if (svd.doors_alloc) { + free((genericptr_t) svd.doors); + svd.doors = (coord *) 0; + svd.doors_alloc = 0; } init_rect(); init_vault(); @@ -1035,8 +1038,8 @@ fill_ordinary_room( * of rooms; about 5 - 7.5% for 2 boxes, least likely * when few rooms; chance for 3 or more is negligible. */ - /*assert(gn.nroom > 0); // must be true because we're filling a room*/ - if (!skip_chests && !rn2(gn.nroom * 5 / 2) && somexyspace(croom, &pos)) + /*assert(svn.nroom > 0); // must be true because we're filling a room*/ + if (!skip_chests && !rn2(svn.nroom * 5 / 2) && somexyspace(croom, &pos)) (void) mksobj_at(rn2(3) ? LARGE_BOX : CHEST, pos.x, pos.y, TRUE, FALSE); @@ -1113,10 +1116,10 @@ makelevel(void) /* check for special levels */ if (slev && !Is_rogue_level(&u.uz)) { makemaz(slev->proto); - } else if (gd.dungeons[u.uz.dnum].proto[0]) { + } else if (svd.dungeons[u.uz.dnum].proto[0]) { makemaz(""); - } else if (gd.dungeons[u.uz.dnum].fill_lvl[0]) { - makemaz(gd.dungeons[u.uz.dnum].fill_lvl); + } else if (svd.dungeons[u.uz.dnum].fill_lvl[0]) { + makemaz(svd.dungeons[u.uz.dnum].fill_lvl); } else if (In_quest(&u.uz)) { char fillname[9]; s_level *loc_lev; @@ -1142,7 +1145,7 @@ makelevel(void) } else { makerooms(); } - assert(gn.nroom > 0); + assert(svn.nroom > 0); sort_rooms(); generate_stairs(); /* up and down stairs */ @@ -1167,20 +1170,20 @@ makelevel(void) add_room(gv.vault_x, gv.vault_y, gv.vault_x + w, gv.vault_y + h, TRUE, VAULT, FALSE); - gl.level.flags.has_vault = 1; + svl.level.flags.has_vault = 1; ++room_threshold; - gr.rooms[gn.nroom - 1].needfill = FILL_NORMAL; - fill_special_room(&gr.rooms[gn.nroom - 1]); + svr.rooms[svn.nroom - 1].needfill = FILL_NORMAL; + fill_special_room(&svr.rooms[svn.nroom - 1]); mk_knox_portal(gv.vault_x + w, gv.vault_y + h); - if (!gl.level.flags.noteleport && !rn2(3)) + if (!svl.level.flags.noteleport && !rn2(3)) makevtele(); } else if (rnd_rect() && create_vault()) { - gv.vault_x = gr.rooms[gn.nroom].lx; - gv.vault_y = gr.rooms[gn.nroom].ly; + gv.vault_x = svr.rooms[svn.nroom].lx; + gv.vault_y = svr.rooms[svn.nroom].ly; if (check_room(&gv.vault_x, &w, &gv.vault_y, &h, TRUE)) goto fill_vault; else - gr.rooms[gn.nroom].hx = -1; + svr.rooms[svn.nroom].hx = -1; } } @@ -1190,31 +1193,31 @@ makelevel(void) if (wizard && nh_getenv("SHOPTYPE")) do_mkroom(SHOPBASE); else if (u_depth > 1 && u_depth < depth(&medusa_level) - && gn.nroom >= room_threshold && rn2(u_depth) < 3) + && svn.nroom >= room_threshold && rn2(u_depth) < 3) do_mkroom(SHOPBASE); else if (u_depth > 4 && !rn2(6)) do_mkroom(COURT); else if (u_depth > 5 && !rn2(8) - && !(gm.mvitals[PM_LEPRECHAUN].mvflags & G_GONE)) + && !(svm.mvitals[PM_LEPRECHAUN].mvflags & G_GONE)) do_mkroom(LEPREHALL); else if (u_depth > 6 && !rn2(7)) do_mkroom(ZOO); else if (u_depth > 8 && !rn2(5)) do_mkroom(TEMPLE); else if (u_depth > 9 && !rn2(5) - && !(gm.mvitals[PM_KILLER_BEE].mvflags & G_GONE)) + && !(svm.mvitals[PM_KILLER_BEE].mvflags & G_GONE)) do_mkroom(BEEHIVE); else if (u_depth > 11 && !rn2(6)) do_mkroom(MORGUE); else if (u_depth > 12 && !rn2(8) && antholemon()) do_mkroom(ANTHOLE); else if (u_depth > 14 && !rn2(4) - && !(gm.mvitals[PM_SOLDIER].mvflags & G_GONE)) + && !(svm.mvitals[PM_SOLDIER].mvflags & G_GONE)) do_mkroom(BARRACKS); else if (u_depth > 15 && !rn2(6)) do_mkroom(SWAMP); else if (u_depth > 16 && !rn2(8) - && !(gm.mvitals[PM_COCKATRICE].mvflags & G_GONE)) + && !(svm.mvitals[PM_COCKATRICE].mvflags & G_GONE)) do_mkroom(COCKNEST); skip0: @@ -1233,7 +1236,7 @@ makelevel(void) rooms (intended to be indistinguishable from the normally generated items); work out which room these will be placed in */ int fillable_room_count = 0; - for (croom = gr.rooms; croom->hx > 0; croom++) { + for (croom = svr.rooms; croom->hx > 0; croom++) { if (ROOM_IS_FILLABLE(croom)) fillable_room_count++; } @@ -1245,7 +1248,7 @@ makelevel(void) ? rn2(fillable_room_count) : -1; /* for each room: put things inside */ - for (croom = gr.rooms; croom->hx > 0; croom++) { + for (croom = svr.rooms; croom->hx > 0; croom++) { boolean fillable = ROOM_IS_FILLABLE(croom); fill_ordinary_room(croom, @@ -1256,8 +1259,8 @@ makelevel(void) } /* Fill all special rooms now, regardless of whether this is a special * level, proto level, or ordinary level. */ - for (i = 0; i < gn.nroom; ++i) { - fill_special_room(&gr.rooms[i]); + for (i = 0; i < svn.nroom; ++i) { + fill_special_room(&svr.rooms[i]); } themerooms_post_level_generate(); @@ -1303,7 +1306,7 @@ mineralize(int kelp_pool, int kelp_moat, int goldprob, int gemprob, almost all special levels are excluded */ if (!skip_lvl_checks && (In_hell(&u.uz) || In_V_tower(&u.uz) || Is_rogue_level(&u.uz) - || gl.level.flags.arboreal + || svl.level.flags.arboreal || ((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz) && (!In_mines(&u.uz) || sp->flags.town)))) return; @@ -1382,16 +1385,16 @@ level_finalize_topology(void) mineralize(-1, -1, -1, -1, FALSE); gi.in_mklev = FALSE; /* avoid coordinates in future lua-loads for this level being thrown off - * because xstart and ystart aren't saved with the level and will be 0 after - * leaving and returning */ + * because xstart and ystart aren't saved with the level and will be 0 + * after leaving and returning */ gx.xstart = gy.ystart = 0; /* has_morgue gets cleared once morgue is entered; graveyard stays set (graveyard might already be set even when has_morgue is clear [see fixup_special()], so don't update it unconditionally) */ - if (gl.level.flags.has_morgue) - gl.level.flags.graveyard = 1; - if (!gl.level.flags.is_maze_lev) { - for (croom = &gr.rooms[0]; croom != &gr.rooms[gn.nroom]; croom++) + if (svl.level.flags.has_morgue) + svl.level.flags.graveyard = 1; + if (!svl.level.flags.is_maze_lev) { + for (croom = &svr.rooms[0]; croom != &svr.rooms[svn.nroom]; croom++) #ifdef SPECIALIZATION topologize(croom, FALSE); #else @@ -1399,10 +1402,10 @@ level_finalize_topology(void) #endif } set_wall_state(); - /* for many room types, gr.rooms[].rtype is zeroed once the room has been - entered; gr.rooms[].orig_rtype always retains original rtype value */ - for (ridx = 0; ridx < SIZE(gr.rooms); ridx++) - gr.rooms[ridx].orig_rtype = gr.rooms[ridx].rtype; + /* for many room types, svr.rooms[].rtype is zeroed once the room has been + entered; svr.rooms[].orig_rtype always retains original rtype value */ + for (ridx = 0; ridx < SIZE(svr.rooms); ridx++) + svr.rooms[ridx].orig_rtype = svr.rooms[ridx].rtype; } void @@ -1432,7 +1435,7 @@ topologize(struct mkroom *croom) #endif { coordxy x, y; - int roomno = (int) ((croom - gr.rooms) + ROOMOFFSET); + int roomno = (int) ((croom - svr.rooms) + ROOMOFFSET); coordxy lowx = croom->lx, lowy = croom->ly; coordxy hix = croom->hx, hiy = croom->hy; #ifdef SPECIALIZATION @@ -1493,7 +1496,7 @@ find_branch_room(coord *mp) { struct mkroom *croom = 0; - if (gn.nroom == 0) { + if (svn.nroom == 0) { mazexy(mp); /* already verifies location */ } else { croom = generate_stairs_find_room(); @@ -1511,7 +1514,7 @@ pos_to_room(coordxy x, coordxy y) int i; struct mkroom *curr; - for (curr = gr.rooms, i = 0; i < gn.nroom; curr++, i++) + for (curr = svr.rooms, i = 0; i < svn.nroom; curr++, i++) if (inside_room(curr, x, y)) return curr; ; @@ -1790,7 +1793,7 @@ traptype_rnd(unsigned mktrapflags) kind = NO_TRAP; break; case LEVEL_TELEP: - if (lvl < 5 || gl.level.flags.noteleport + if (lvl < 5 || svl.level.flags.noteleport || single_level_branch(&u.uz)) kind = NO_TRAP; break; @@ -1816,7 +1819,7 @@ traptype_rnd(unsigned mktrapflags) kind = NO_TRAP; break; case TELEP_TRAP: - if (gl.level.flags.noteleport) + if (svl.level.flags.noteleport) kind = NO_TRAP; break; case HOLE: @@ -2045,25 +2048,25 @@ generate_stairs_find_room(void) int i, phase, ai; int *rmarr; - if (!gn.nroom) + if (!svn.nroom) return (struct mkroom *) 0; - rmarr = (int *) alloc(sizeof(int) * gn.nroom); + rmarr = (int *) alloc(sizeof(int) * svn.nroom); for (phase = 2; phase > -1; phase--) { ai = 0; - for (i = 0; i < gn.nroom; i++) - if (generate_stairs_room_good(&gr.rooms[i], phase)) + for (i = 0; i < svn.nroom; i++) + if (generate_stairs_room_good(&svr.rooms[i], phase)) rmarr[ai++] = i; if (ai > 0) { i = rmarr[rn2(ai)]; free(rmarr); - return &gr.rooms[i]; + return &svr.rooms[i]; } } free(rmarr); - croom = &gr.rooms[rn2(gn.nroom)]; + croom = &svr.rooms[rn2(svn.nroom)]; return croom; } @@ -2081,7 +2084,7 @@ generate_stairs(void) if (!Is_botlevel(&u.uz)) { if ((croom = generate_stairs_find_room()) == NULL) - panic(gen_stairs_panic, gn.nroom); + panic(gen_stairs_panic, svn.nroom); if (!somexyspace(croom, &pos)) { pos.x = somex(croom); @@ -2094,7 +2097,7 @@ generate_stairs(void) /* if there is only 1 room and we found it above, this will find it again */ if ((croom = generate_stairs_find_room()) == NULL) - panic(gen_stairs_panic, gn.nroom); + panic(gen_stairs_panic, svn.nroom); if (!somexyspace(croom, &pos)) { pos.x = somex(croom); @@ -2119,7 +2122,7 @@ mkfount(struct mkroom *croom) if (!rn2(7)) levl[m.x][m.y].blessedftn = 1; - gl.level.flags.nfountains++; + svl.level.flags.nfountains++; } staticfn boolean @@ -2148,7 +2151,7 @@ mksink(struct mkroom *croom) if (!set_levltyp(m.x, m.y, SINK)) return; - gl.level.flags.nsinks++; + svl.level.flags.nsinks++; } staticfn void @@ -2222,7 +2225,7 @@ mkgrave(struct mkroom *croom) /* * Major level transmutation: add a set of stairs (to the Sanctum) after * an earthquake that leaves behind a new topology, centered at inv_pos. - * Assumes there are no rooms within the invocation area and that gi.inv_pos + * Assumes there are no rooms within the invocation area and that svi.inv_pos * is not too close to the edge of the map. Also assume the hero can see, * which is guaranteed for normal play due to the fact that sight is needed * to read the Book of the Dead. [That assumption is not valid; it is @@ -2240,8 +2243,8 @@ mkinvokearea(void) pline_The("floor shakes violently under you!"); /* decide whether to issue the crumbling walls message */ { - xmin = xmax = gi.inv_pos.x; - ymin = ymax = gi.inv_pos.y; + xmin = xmax = svi.inv_pos.x; + ymin = ymax = svi.inv_pos.y; wallct = mkinvk_check_wall(xmin, ymin); /* this replicates the somewhat convoluted loop below, working out from the stair position, except for stopping early when @@ -2285,8 +2288,8 @@ mkinvokearea(void) reset_utrap(FALSE); } - xmin = xmax = gi.inv_pos.x; /* reset after the check for walls */ - ymin = ymax = gi.inv_pos.y; + xmin = xmax = svi.inv_pos.x; /* reset after the check for walls */ + ymin = ymax = svi.inv_pos.y; mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */ for (dist = 1; dist < 7; dist++) { @@ -2412,7 +2415,7 @@ mkinvpos(coordxy x, coordxy y, int dist) } if (!does_block(x, y, lev)) - unblock_point(x, y); /* make sure vision knows this location is open */ + unblock_point(x, y); /* make sure vision knows location is open */ /* display new value of position; could have a monster/object on it */ newsym(x, y); @@ -2464,7 +2467,7 @@ mk_knox_portal(coordxy x, coordxy y) } /* Already set or 2/3 chance of deferring until a later level. */ - if (source->dnum < gn.n_dgns || (rn2(3) && !wizard)) + if (source->dnum < svn.n_dgns || (rn2(3) && !wizard)) return; if (!(u.uz.dnum == oracle_level.dnum /* in main dungeon */ diff --git a/src/mkmap.c b/src/mkmap.c index 7246e97c4..32c6aef68 100644 --- a/src/mkmap.c +++ b/src/mkmap.c @@ -251,8 +251,8 @@ join_map_cleanup(void) for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) levl[x][y].roomno = NO_ROOM; - gn.nroom = gn.nsubroom = 0; - gr.rooms[gn.nroom].hx = gs.subrooms[gn.nsubroom].hx = -1; + svn.nroom = gn.nsubroom = 0; + svr.rooms[svn.nroom].hx = gs.subrooms[gn.nsubroom].hx = -1; } staticfn void @@ -272,12 +272,12 @@ join_map(schar bg_typ, schar fg_typ) gm.min_rx = gm.max_rx = i; gm.min_ry = gm.max_ry = j; gn.n_loc_filled = 0; - flood_fill_rm(i, j, gn.nroom + ROOMOFFSET, FALSE, FALSE); + flood_fill_rm(i, j, svn.nroom + ROOMOFFSET, FALSE, FALSE); if (gn.n_loc_filled > 3) { add_room(gm.min_rx, gm.min_ry, gm.max_rx, gm.max_ry, FALSE, OROOM, TRUE); - gr.rooms[gn.nroom - 1].irregular = TRUE; - if (gn.nroom >= (MAXNROFROOMS * 2)) + svr.rooms[svn.nroom - 1].irregular = TRUE; + if (svn.nroom >= (MAXNROFROOMS * 2)) goto joinm; } else { /* @@ -287,7 +287,7 @@ join_map(schar bg_typ, schar fg_typ) for (sx = gm.min_rx; sx <= gm.max_rx; sx++) for (sy = gm.min_ry; sy <= gm.max_ry; sy++) if ((int) levl[sx][sy].roomno - == gn.nroom + ROOMOFFSET) { + == svn.nroom + ROOMOFFSET) { levl[sx][sy].typ = bg_typ; levl[sx][sy].roomno = NO_ROOM; } @@ -302,8 +302,8 @@ join_map(schar bg_typ, schar fg_typ) * so don't call sort_rooms(), which can screw up the roomno's * validity in the levl structure. */ - for (croom = &gr.rooms[0], croom2 = croom + 1; - croom2 < &gr.rooms[gn.nroom]; ) { + for (croom = &svr.rooms[0], croom2 = croom + 1; + croom2 < &svr.rooms[svn.nroom]; ) { /* pick random starting and end locations for "corridor" */ if (!somexy(croom, &sm) || !somexy(croom2, &em)) { /* ack! -- the level is going to be busted */ @@ -350,8 +350,8 @@ finish_map( || (bg_typ == TREE && levl[i][j].typ == bg_typ) || (walled && IS_WALL(levl[i][j].typ))) levl[i][j].lit = TRUE; - for (i = 0; i < gn.nroom; i++) - gr.rooms[i].rlit = 1; + for (i = 0; i < svn.nroom; i++) + svr.rooms[i].rlit = 1; } /* light lava even if everything's otherwise unlit; ice might be frozen pool rather than frozen moat */ @@ -383,8 +383,8 @@ remove_rooms(int lx, int ly, int hx, int hy) int i; struct mkroom *croom; - for (i = gn.nroom - 1; i >= 0; --i) { - croom = &gr.rooms[i]; + for (i = svn.nroom - 1; i >= 0; --i) { + croom = &svr.rooms[i]; if (croom->hx < lx || croom->lx >= hx || croom->hy < ly || croom->ly >= hy) continue; /* no overlap */ @@ -413,8 +413,8 @@ remove_rooms(int lx, int ly, int hx, int hy) staticfn void remove_room(unsigned int roomno) { - struct mkroom *croom = &gr.rooms[roomno]; - struct mkroom *maxroom = &gr.rooms[--gn.nroom]; + struct mkroom *croom = &svr.rooms[roomno]; + struct mkroom *maxroom = &svr.rooms[--svn.nroom]; int i, j; unsigned oroomno; @@ -425,7 +425,7 @@ remove_room(unsigned int roomno) *croom = *maxroom; /* since maxroom moved, update affected level roomno values */ - oroomno = gn.nroom + ROOMOFFSET; + oroomno = svn.nroom + ROOMOFFSET; roomno += ROOMOFFSET; for (i = croom->lx; i <= croom->hx; ++i) for (j = croom->ly; j <= croom->hy; ++j) { @@ -481,8 +481,8 @@ mkmap(lev_init *init_lev) init_lev->icedpools); /* a walled, joined level is cavernous, not mazelike -dlc */ if (walled && join) { - gl.level.flags.is_maze_lev = FALSE; - gl.level.flags.is_cavernous_lev = TRUE; + svl.level.flags.is_maze_lev = FALSE; + svl.level.flags.is_cavernous_lev = TRUE; } free(gn.new_locations); } diff --git a/src/mkmaze.c b/src/mkmaze.c index 5acf97cc6..d485dabdf 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -40,6 +40,7 @@ staticfn boolean is_exclusion_zone(xint16, coordxy, coordxy); } \ } while (0) +/* used to determine if wall spines can join this location */ staticfn int iswall(coordxy x, coordxy y) { @@ -49,9 +50,11 @@ iswall(coordxy x, coordxy y) return 0; type = levl[x][y].typ; return (IS_WALL(type) || IS_DOOR(type) + || type == LAVAWALL || type == WATER || type == SDOOR || type == IRONBARS); } +/* used to determine if wall spines can join this location */ staticfn int iswall_or_stone(coordxy x, coordxy y) { @@ -302,11 +305,13 @@ maze0xy(coord *cc) staticfn boolean is_exclusion_zone(xint16 type, coordxy x, coordxy y) { - struct exclusion_zone *ez = ge.exclusion_zones; + struct exclusion_zone *ez = sve.exclusion_zones; while (ez) { - if (((type == LR_DOWNTELE && (ez->zonetype == LR_DOWNTELE || ez->zonetype == LR_TELE)) - || (type == LR_UPTELE && (ez->zonetype == LR_UPTELE || ez->zonetype == LR_TELE)) + if (((type == LR_DOWNTELE + && (ez->zonetype == LR_DOWNTELE || ez->zonetype == LR_TELE)) + || (type == LR_UPTELE + && (ez->zonetype == LR_UPTELE || ez->zonetype == LR_TELE)) || type == ez->zonetype) && within_bounded_area(x, y, ez->lx, ez->ly, ez->hx, ez->hy)) return TRUE; @@ -329,7 +334,7 @@ bad_location( return (boolean) (occupied(x, y) || within_bounded_area(x, y, nlx, nly, nhx, nhy) || !((levl[x][y].typ == CORR - && gl.level.flags.is_maze_lev) + && svl.level.flags.is_maze_lev) || levl[x][y].typ == ROOM || levl[x][y].typ == AIR)); } @@ -352,7 +357,7 @@ place_lregion( * if there are rooms and this a branch, let place_branch choose * the branch location (to avoid putting branches in corridors). */ - if (rtype == LR_BRANCH && gn.nroom) { + if (rtype == LR_BRANCH && svn.nroom) { place_branch(Is_branchlev(&u.uz), 0, 0); return; } @@ -403,7 +408,8 @@ put_lregion_here( { struct monst *mtmp; - if (bad_location(x, y, nlx, nly, nhx, nhy) || is_exclusion_zone(rtype, x, y)) { + if (bad_location(x, y, nlx, nly, nhx, nhy) + || is_exclusion_zone(rtype, x, y)) { if (!oneshot) { return FALSE; /* caller should try again */ } else { @@ -417,7 +423,8 @@ put_lregion_here( mtmp->mtrapped = 0; deltrap(t); } - if (bad_location(x, y, nlx, nly, nhx, nhy) || is_exclusion_zone(rtype, x, y)) + if (bad_location(x, y, nlx, nly, nhx, nhy) + || is_exclusion_zone(rtype, x, y)) return FALSE; } } @@ -559,7 +566,7 @@ fixup_special(void) boolean added_branch = FALSE; if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) { - gl.level.flags.hero_memory = 0; + svl.level.flags.hero_memory = 0; /* water level is an odd beast - it has to be set up before calling place_lregions etc. */ setup_waterlevel(); @@ -594,24 +601,24 @@ fixup_special(void) case LR_DOWNTELE: /* save the region outlines for goto_level() */ if (r->rtype == LR_TELE || r->rtype == LR_UPTELE) { - gu.updest.lx = r->inarea.x1; - gu.updest.ly = r->inarea.y1; - gu.updest.hx = r->inarea.x2; - gu.updest.hy = r->inarea.y2; - gu.updest.nlx = r->delarea.x1; - gu.updest.nly = r->delarea.y1; - gu.updest.nhx = r->delarea.x2; - gu.updest.nhy = r->delarea.y2; + svu.updest.lx = r->inarea.x1; + svu.updest.ly = r->inarea.y1; + svu.updest.hx = r->inarea.x2; + svu.updest.hy = r->inarea.y2; + svu.updest.nlx = r->delarea.x1; + svu.updest.nly = r->delarea.y1; + svu.updest.nhx = r->delarea.x2; + svu.updest.nhy = r->delarea.y2; } if (r->rtype == LR_TELE || r->rtype == LR_DOWNTELE) { - gd.dndest.lx = r->inarea.x1; - gd.dndest.ly = r->inarea.y1; - gd.dndest.hx = r->inarea.x2; - gd.dndest.hy = r->inarea.y2; - gd.dndest.nlx = r->delarea.x1; - gd.dndest.nly = r->delarea.y1; - gd.dndest.nhx = r->delarea.x2; - gd.dndest.nhy = r->delarea.y2; + svd.dndest.lx = r->inarea.x1; + svd.dndest.ly = r->inarea.y1; + svd.dndest.hx = r->inarea.x2; + svd.dndest.hy = r->inarea.y2; + svd.dndest.nlx = r->delarea.x1; + svd.dndest.nly = r->delarea.y1; + svd.dndest.nhx = r->delarea.x2; + svd.dndest.nhy = r->delarea.y2; } /* place_lregion gets called from goto_level() */ break; @@ -631,7 +638,7 @@ fixup_special(void) struct obj *otmp; int tryct; - croom = &gr.rooms[0]; /* the first room defined on the medusa level */ + croom = &svr.rooms[0]; /* the first room defined on the medusa level */ for (tryct = rnd(4); tryct; tryct--) { x = somex(croom); y = somey(croom); @@ -666,9 +673,9 @@ fixup_special(void) } } else if (Role_if(PM_CLERIC) && In_quest(&u.uz)) { /* less chance for undead corpses (lured from lower morgues) */ - gl.level.flags.graveyard = 1; + svl.level.flags.graveyard = 1; } else if (Is_stronghold(&u.uz)) { - gl.level.flags.graveyard = 1; + svl.level.flags.graveyard = 1; } else if (on_level(&u.uz, &baalzebub_level)) { /* custom wallify the "beetle" potion of the level */ baalz_fixup(); @@ -677,7 +684,7 @@ fixup_special(void) } if ((sp = Is_special(&u.uz)) != 0 && sp->flags.town) /* Mine Town */ - gl.level.flags.has_town = 1; + svl.level.flags.has_town = 1; if (gl.lregions) free((genericptr_t) gl.lregions), gl.lregions = 0; @@ -702,7 +709,7 @@ migrate_orc(struct monst *mtmp, unsigned long mflags) cur_depth = (int) depth(&u.uz); max_depth = dunlevs_in_dungeon(&u.uz) - + (gd.dungeons[u.uz.dnum].depth_start - 1); + + (svd.dungeons[u.uz.dnum].depth_start - 1); if (mflags == ORC_LEADER) { /* Note that the orc leader will take possession of any * remaining stuff not already delivered to other @@ -804,7 +811,7 @@ stolen_booty(void) cnt = rnd(3); for (i = 0; i < cnt; ++i) migr_booty_item(SKELETON_KEY, gang); - otyp = rn2((GAUNTLETS_OF_DEXTERITY - LEATHER_GLOVES) + 1) + LEATHER_GLOVES; + otyp = rn1((GAUNTLETS_OF_DEXTERITY - LEATHER_GLOVES) + 1, LEATHER_GLOVES); migr_booty_item(otyp, gang); cnt = rnd(10); for (i = 0; i < cnt; ++i) { @@ -958,7 +965,7 @@ create_maze(int corrwid, int wallthick, boolean rmdeadends) rdx = (gx.x_maze_max / scale); rdy = (gy.y_maze_max / scale); - if (gl.level.flags.corrmaze) + if (svl.level.flags.corrmaze) for (x = 2; x < (rdx * 2); x++) for (y = 2; y < (rdy * 2); y++) levl[x][y].typ = STONE; @@ -976,7 +983,7 @@ create_maze(int corrwid, int wallthick, boolean rmdeadends) walkfrom((int) mm.x, (int) mm.y, 0); if (rmdeadends) - maze_remove_deadends((gl.level.flags.corrmaze) ? CORR : ROOM); + maze_remove_deadends((svl.level.flags.corrmaze) ? CORR : ROOM); /* restore bounds */ gx.x_maze_max = tmp_xmax; @@ -1049,10 +1056,10 @@ pick_vibrasquare_location(void) if (x_range <= INVPOS_X_MARGIN || y_range <= INVPOS_Y_MARGIN || (x_range * y_range) <= (INVPOS_DISTANCE * INVPOS_DISTANCE)) { - debugpline2("gi.inv_pos: maze is too small! (%d x %d)", + debugpline2("svi.inv_pos: maze is too small! (%d x %d)", gx.x_maze_max, gy.y_maze_max); } - gi.inv_pos.x = gi.inv_pos.y = 0; /*{occupied() => invocation_pos()}*/ + svi.inv_pos.x = svi.inv_pos.y = 0; /*{occupied() => invocation_pos()}*/ do { x = rn1(x_range, x_maze_min + INVPOS_X_MARGIN + 1); y = rn1(y_range, y_maze_min + INVPOS_Y_MARGIN + 1); @@ -1065,8 +1072,8 @@ pick_vibrasquare_location(void) || abs(x - stway->sx) == abs(y - stway->sy) || distmin(x, y, stway->sx, stway->sy) <= INVPOS_DISTANCE || !SPACE_POS(levl[x][y].typ) || occupied(x, y))); - gi.inv_pos.x = x; - gi.inv_pos.y = y; + svi.inv_pos.x = x; + svi.inv_pos.y = y; #undef INVPOS_X_MARGIN #undef INVPOS_Y_MARGIN #undef INVPOS_DISTANCE @@ -1118,22 +1125,22 @@ makemaz(const char *s) "%s-%d", s, rnd((int) sp->rndlevs)); else Strcpy(protofile, s); - } else if (*(gd.dungeons[u.uz.dnum].proto)) { + } else if (*(svd.dungeons[u.uz.dnum].proto)) { if (dunlevs_in_dungeon(&u.uz) > 1) { if (sp && sp->rndlevs) Snprintf(protofile, sizeof protofile, - "%s%d-%d", gd.dungeons[u.uz.dnum].proto, + "%s%d-%d", svd.dungeons[u.uz.dnum].proto, dunlev(&u.uz), rnd((int) sp->rndlevs)); else Snprintf(protofile, sizeof protofile, - "%s%d", gd.dungeons[u.uz.dnum].proto, + "%s%d", svd.dungeons[u.uz.dnum].proto, dunlev(&u.uz)); } else if (sp && sp->rndlevs) { Snprintf(protofile, sizeof protofile, - "%s-%d", gd.dungeons[u.uz.dnum].proto, + "%s-%d", svd.dungeons[u.uz.dnum].proto, rnd((int) sp->rndlevs)); } else - Strcpy(protofile, gd.dungeons[u.uz.dnum].proto); + Strcpy(protofile, svd.dungeons[u.uz.dnum].proto); } else Strcpy(protofile, ""); @@ -1176,8 +1183,8 @@ makemaz(const char *s) impossible("Couldn't load \"%s\" - making a maze.", protofile); } - gl.level.flags.is_maze_lev = 1; - gl.level.flags.corrmaze = !rn2(3); + svl.level.flags.is_maze_lev = 1; + svl.level.flags.corrmaze = !rn2(3); if (!Invocation_lev(&u.uz) && rn2(2)) { create_maze(-1, -1, !rn2(5)); @@ -1185,7 +1192,7 @@ makemaz(const char *s) create_maze(1, 1, FALSE); } - if (!gl.level.flags.corrmaze) + if (!svl.level.flags.corrmaze) wallification(2, 2, gx.x_maze_max, gy.y_maze_max); mazexy(&mm); @@ -1195,7 +1202,7 @@ makemaz(const char *s) mkstairs(mm.x, mm.y, 0, (struct mkroom *) 0, FALSE); /* down */ } else { /* choose "vibrating square" location */ pick_vibrasquare_location(); - maketrap(gi.inv_pos.x, gi.inv_pos.y, VIBRATING_SQUARE); + maketrap(svi.inv_pos.x, svi.inv_pos.y, VIBRATING_SQUARE); } /* place branch stair or portal */ @@ -1219,7 +1226,7 @@ walkfrom(coordxy x, coordxy y, schar typ) int dirs[4]; if (!typ) { - if (gl.level.flags.corrmaze) + if (svl.level.flags.corrmaze) typ = CORR; else typ = ROOM; @@ -1264,7 +1271,7 @@ walkfrom(coordxy x, coordxy y, schar typ) int dirs[4]; if (!typ) { - if (gl.level.flags.corrmaze) + if (svl.level.flags.corrmaze) typ = CORR; else typ = ROOM; @@ -1298,7 +1305,7 @@ void mazexy(coord *cc) { coordxy x, y; - int allowedtyp = (gl.level.flags.corrmaze ? CORR : ROOM); + int allowedtyp = (svl.level.flags.corrmaze ? CORR : ROOM); int cpt = 0; do { @@ -1354,7 +1361,7 @@ get_level_extends( } } } - xmin -= (nonwall || !gl.level.flags.is_maze_lev) ? 2 : 1; + xmin -= (nonwall || !svl.level.flags.is_maze_lev) ? 2 : 1; if (xmin < 0) xmin = 0; @@ -1370,7 +1377,7 @@ get_level_extends( } } } - xmax += (nonwall || !gl.level.flags.is_maze_lev) ? 2 : 1; + xmax += (nonwall || !svl.level.flags.is_maze_lev) ? 2 : 1; if (xmax >= COLNO) xmax = COLNO - 1; @@ -1386,7 +1393,7 @@ get_level_extends( } } } - ymin -= (nonwall || !gl.level.flags.is_maze_lev) ? 2 : 1; + ymin -= (nonwall || !svl.level.flags.is_maze_lev) ? 2 : 1; found = nonwall = FALSE; for (ymax = ROWNO - 1; !found && ymax >= 0; ymax--) { @@ -1400,7 +1407,7 @@ get_level_extends( } } } - ymax += (nonwall || !gl.level.flags.is_maze_lev) ? 2 : 1; + ymax += (nonwall || !svl.level.flags.is_maze_lev) ? 2 : 1; *left = xmin; *right = xmax; @@ -1447,12 +1454,14 @@ mkportal(coordxy x, coordxy y, xint16 todnum, xint16 todlevel) return; } debugpline4("mkportal: at <%d,%d>, to %s, level %d", x, y, - gd.dungeons[todnum].dname, todlevel); + svd.dungeons[todnum].dname, todlevel); ttmp->dst.dnum = todnum; ttmp->dst.dlevel = todlevel; return; } +/* augment the Plane of Fire; called from goto_level() when arriving and + moveloop_core() when on the level */ void fumaroles(void) { @@ -1464,7 +1473,7 @@ fumaroles(void) nmax++; sizemin += 5; } - if (gl.level.flags.temperature > 0) { + if (svl.level.flags.temperature > 0) { nmax++; sizemin += 5; } @@ -1494,10 +1503,10 @@ fumaroles(void) */ /* bubble movement boundaries */ -#define gbxmin (gx.xmin + 1) -#define gbymin (gy.ymin + 1) -#define gbxmax (gx.xmax - 1) -#define gbymax (gy.ymax - 1) +#define gbxmin (svx.xmin + 1) +#define gbymin (svy.ymin + 1) +#define gbxmax (svx.xmax - 1) +#define gbymax (svy.ymax - 1) /* the bubble hero is in */ static struct bubble *hero_bubble = NULL; @@ -1506,13 +1515,16 @@ staticfn void set_wportal(void); staticfn void mk_bubble(coordxy, coordxy, int); staticfn void mv_bubble(struct bubble *, coordxy, coordxy, boolean); +/* augment the Planes of Water (for bubbles) and Air (for clouds); called + from goto_level() when arriving and moveloop_core() when on the level */ void movebubbles(void) { - static const struct rm water_pos = { cmap_b_to_glyph(S_water), WATER, 0, - 0, 0, 0, 0, 0, 0, 0 }; - static const struct rm air_pos = { cmap_b_to_glyph(S_cloud), AIR, 0, 0, 0, - 1, 0, 0, 0, 0 }; + static const struct rm water_pos = { + cmap_b_to_glyph(S_water), WATER, 0, 0, 0, 0, 0, 0, 0, 0 + }, air_pos = { + cmap_b_to_glyph(S_cloud), AIR, 0, 0, 0, 1, 0, 0, 0, 0 + }; static boolean up = FALSE; struct bubble *b; struct container *cons; @@ -1537,7 +1549,7 @@ movebubbles(void) * Pick up everything inside of a bubble then fill all bubble * locations. */ - for (b = up ? gb.bbubbles : ge.ebubbles; b; + for (b = up ? svb.bbubbles : ge.ebubbles; b; b = up ? b->next : b->prev) { if (b->cons) panic("movebubbles: cons != null"); @@ -1553,7 +1565,7 @@ movebubbles(void) if (OBJ_AT(x, y)) { struct obj *olist = (struct obj *) 0, *otmp; - while ((otmp = gl.level.objects[x][y]) != 0) { + while ((otmp = svl.level.objects[x][y]) != 0) { remove_object(otmp); otmp->ox = otmp->oy = 0; otmp->nexthere = olist; @@ -1641,7 +1653,7 @@ movebubbles(void) * would eventually end up in the last bubble in the chain. */ up = !up; - for (b = up ? gb.bbubbles : ge.ebubbles; b; b = up ? b->next : b->prev) { + for (b = up ? svb.bbubbles : ge.ebubbles; b; b = up ? b->next : b->prev) { int rx = rn2(3), ry = rn2(3); mv_bubble(b, b->dx + 1 - (!b->dx ? rx : (rx ? 1 : 0)), @@ -1694,21 +1706,21 @@ save_waterlevel(NHFILE *nhfp) { struct bubble *b; - if (!gb.bbubbles) + if (!svb.bbubbles) return; if (perform_bwrite(nhfp)) { int n = 0; - for (b = gb.bbubbles; b; b = b->next) + for (b = svb.bbubbles; b; b = b->next) ++n; if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &n, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &gx.xmin, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &gy.ymin, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &gx.xmax, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &gy.ymax, sizeof(int)); + bwrite(nhfp->fd, (genericptr_t) &svx.xmin, sizeof(int)); + bwrite(nhfp->fd, (genericptr_t) &svy.ymin, sizeof(int)); + bwrite(nhfp->fd, (genericptr_t) &svx.xmax, sizeof(int)); + bwrite(nhfp->fd, (genericptr_t) &svy.ymax, sizeof(int)); } - for (b = gb.bbubbles; b; b = b->next) { + for (b = svb.bbubbles; b; b = b->next) { if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) b, sizeof(struct bubble)); } @@ -1724,14 +1736,14 @@ restore_waterlevel(NHFILE *nhfp) struct bubble *b = (struct bubble *) 0, *btmp; int i, n = 0; - gb.bbubbles = (struct bubble *) 0; + svb.bbubbles = (struct bubble *) 0; set_wportal(); if (nhfp->structlevel) { mread(nhfp->fd,(genericptr_t) &n, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &gx.xmin, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &gy.ymin, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &gx.xmax, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &gy.ymax, sizeof (int)); + mread(nhfp->fd,(genericptr_t) &svx.xmin, sizeof (int)); + mread(nhfp->fd,(genericptr_t) &svy.ymin, sizeof (int)); + mread(nhfp->fd,(genericptr_t) &svx.xmax, sizeof (int)); + mread(nhfp->fd,(genericptr_t) &svy.ymax, sizeof (int)); } for (i = 0; i < n; i++) { btmp = b; @@ -1742,7 +1754,7 @@ restore_waterlevel(NHFILE *nhfp) btmp->next = b; b->prev = btmp; } else { - gb.bbubbles = b; + svb.bbubbles = b; b->prev = (struct bubble *) 0; } mv_bubble(b, 0, 0, TRUE); @@ -1752,7 +1764,7 @@ restore_waterlevel(NHFILE *nhfp) b->next = (struct bubble *) 0; } else { /* avoid "saving and reloading may fix this" */ - gp.program_state.something_worth_saving = 0; + program_state.something_worth_saving = 0; /* during restore, information about what level this is might not be available so we're wishy-washy about what we describe */ impossible("No %s to restore?", @@ -1761,7 +1773,7 @@ restore_waterlevel(NHFILE *nhfp) : (Is_airlevel(&u.uz) || Is_airlevel(&gu.uz_save)) ? "clouds" : "air bubbles or clouds"); - gp.program_state.something_worth_saving = 1; + program_state.something_worth_saving = 1; } } @@ -1786,15 +1798,15 @@ setup_waterlevel(void) (int) u.uz.dnum, (int) u.uz.dlevel); /* ouch, hardcoded... (file scope statics and used in bxmin,bymax,&c) */ - gx.xmin = 3; - gy.ymin = 1; + svx.xmin = 3; + svy.ymin = 1; /* use separate statements so that compiler won't complain about min() comparing two constants; the alternative is to do this in the preprocessor: #if (20 > ROWNO-1) ymax=ROWNO-1 #else ymax=20 #endif */ - gx.xmax = 78; - gx.xmax = min(gx.xmax, (COLNO - 1) - 1); - gy.ymax = 20; - gy.ymax = min(gy.ymax, (ROWNO - 1)); + svx.xmax = 78; + svx.xmax = min(svx.xmax, (COLNO - 1) - 1); + svy.ymax = 20; + svy.ymax = min(svy.ymax, (ROWNO - 1)); /* entire level is remembered as one glyph and any unspecified portion should default to level's base element rather than to usual stone */ @@ -1829,11 +1841,11 @@ unsetup_waterlevel(void) struct bubble *b, *bb; /* free bubbles */ - for (b = gb.bbubbles; b; b = bb) { + for (b = svb.bbubbles; b; b = bb) { bb = b->next; free((genericptr_t) b); } - gb.bbubbles = ge.ebubbles = (struct bubble *) 0; + svb.bbubbles = ge.ebubbles = (struct bubble *) 0; } staticfn void @@ -1879,8 +1891,8 @@ mk_bubble(coordxy x, coordxy y, int n) (void) memcpy((genericptr_t) b->bm, (genericptr_t) bmask[n], (bmask[n][1] + 2) * sizeof (b->bm[0])); b->cons = 0; - if (!gb.bbubbles) - gb.bbubbles = b; + if (!svb.bbubbles) + svb.bbubbles = b; if (ge.ebubbles) { ge.ebubbles->next = b; b->prev = ge.ebubbles; diff --git a/src/mkobj.c b/src/mkobj.c index d289dd0fe..ea14e4c5d 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mkobj.c $NHDT-Date: 1715109575 2024/05/07 19:19:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.296 $ */ +/* NetHack 3.7 mkobj.c $NHDT-Date: 1725138481 2024/08/31 21:08:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.304 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -177,7 +177,7 @@ staticfn boolean may_generate_eroded(struct obj *otmp) { /* initial hero inventory */ - if (gm.moves <= 1 && !gi.in_mklev) + if (svm.moves <= 1 && !gi.in_mklev) return FALSE; /* already erodeproof or cannot be eroded */ if (otmp->oerodeproof || !erosion_matters(otmp) || !is_damageable(otmp)) @@ -283,18 +283,18 @@ mkobj(int oclass, boolean artif) } if (oclass == SPBOOK_no_NOVEL) { - i = rnd_class(gb.bases[SPBOOK_CLASS], SPE_BLANK_PAPER); + i = rnd_class(svb.bases[SPBOOK_CLASS], SPE_BLANK_PAPER); oclass = SPBOOK_CLASS; /* for sanity check below */ } else { prob = rnd(go.oclass_prob_totals[oclass]); - i = gb.bases[oclass]; + i = svb.bases[oclass]; while ((prob -= objects[i].oc_prob) > 0) ++i; } if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i])) { impossible("probtype error, oclass=%d i=%d", (int) oclass, i); - i = gb.bases[oclass]; + i = svb.bases[oclass]; } return mksobj(i, TRUE, artif); @@ -321,7 +321,7 @@ mkbox_cnts(struct obj *box) case SACK: case OILSKIN_SACK: /* initial inventory: sack starts out empty */ - if (gm.moves <= 1 && !gi.in_mklev) { + if (svm.moves <= 1 && !gi.in_mklev) { n = 0; break; } @@ -447,7 +447,7 @@ copy_oextra(struct obj *obj2, struct obj *obj1) } /* - * Split obj so that it gets size gets reduced by num. The quantity num is + * Split stack so that its size gets reduced by num. The quantity num is * put in the object structure delivered by this call. The returned object * has its wornmask cleared and is positioned just following the original * in the nobj chain (and nexthere chain when on the floor). @@ -473,8 +473,8 @@ splitobj(struct obj *obj, long num) otmp->lua_ref_cnt = 0; otmp->pickup_prev = 0; - gc.context.objsplit.parent_oid = obj->o_id; - gc.context.objsplit.child_oid = otmp->o_id; + svc.context.objsplit.parent_oid = obj->o_id; + svc.context.objsplit.child_oid = otmp->o_id; obj->nobj = otmp; /* Only set nexthere when on the floor; nexthere is also used as a back pointer to the container object when contained. @@ -504,7 +504,7 @@ splitobj(struct obj *obj, long num) unsigned next_ident(void) { - unsigned res = gc.context.ident; + unsigned res = svc.context.ident; /* +rnd(2): originally just +1; changed to rnd() to avoid potential exploit of player using #adjust to split an object stack in a manner @@ -514,14 +514,14 @@ next_ident(void) next object to be created was knowable and player could make a wish under controlled circumstances for an item that is affected by the low bits of its obj->o_id [particularly helm of opposite alignment] */ - gc.context.ident += rnd(2); /* ready for next new object or monster */ + svc.context.ident += rnd(2); /* ready for next new object or monster */ /* if ident has wrapped to 0, force it to be non-zero; if/when it ever wraps past 0 (unlikely, but possible on a configuration which uses 16-bit 'int'), just live with that and hope no o_id conflicts between objects or m_id conflicts between monsters arise */ - if (!gc.context.ident) - gc.context.ident = rnd(2); + if (!svc.context.ident) + svc.context.ident = rnd(2); return res; } @@ -532,7 +532,7 @@ staticfn unsigned nextoid(struct obj *oldobj, struct obj *newobj) { int olddif, newdif, trylimit = 256; /* limit of 4 suffices at present */ - unsigned oid = gc.context.ident - 1; /* loop increment will reverse -1 */ + unsigned oid = svc.context.ident - 1; /* loop increment will reverse -1 */ olddif = oid_price_adjustment(oldobj, oldobj->o_id); do { @@ -541,7 +541,7 @@ nextoid(struct obj *oldobj, struct obj *newobj) ++oid; newdif = oid_price_adjustment(newobj, oid); } while (newdif != olddif && --trylimit >= 0); - gc.context.ident = oid; /* update 'last ident used' */ + svc.context.ident = oid; /* update 'last ident used' */ (void) next_ident(); /* increment context.ident for next use */ return oid; /* caller will use this ident */ } @@ -582,17 +582,17 @@ unsplitobj(struct obj *obj) } /* first try the expected case; obj is split from another stack */ - if (obj->o_id == gc.context.objsplit.child_oid) { + if (obj->o_id == svc.context.objsplit.child_oid) { /* parent probably precedes child and will require list traversal */ ochild = obj; - target_oid = gc.context.objsplit.parent_oid; + target_oid = svc.context.objsplit.parent_oid; if (obj->nobj && obj->nobj->o_id == target_oid) oparent = obj->nobj; - } else if (obj->o_id == gc.context.objsplit.parent_oid) { + } else if (obj->o_id == svc.context.objsplit.parent_oid) { /* alternate scenario: another stack was split from obj; child probably follows parent and will be found here */ oparent = obj; - target_oid = gc.context.objsplit.child_oid; + target_oid = svc.context.objsplit.child_oid; if (obj->nobj && obj->nobj->o_id == target_oid) ochild = obj->nobj; } @@ -621,7 +621,7 @@ unsplitobj(struct obj *obj) void clear_splitobjs(void) { - gc.context.objsplit.parent_oid = gc.context.objsplit.child_oid = 0; + svc.context.objsplit.parent_oid = svc.context.objsplit.child_oid = 0; } /* @@ -666,7 +666,7 @@ replace_object(struct obj *obj, struct obj *otmp) obj->nobj = otmp; obj->nexthere = otmp; extract_nobj(obj, &fobj); - extract_nexthere(obj, &gl.level.objects[obj->ox][obj->oy]); + extract_nexthere(obj, &svl.level.objects[obj->ox][obj->oy]); break; default: panic("replace_object: obj position"); @@ -722,12 +722,12 @@ bill_dummy_object(struct obj *otmp) dummy->timed = 0; copy_oextra(dummy, otmp); if (has_omid(dummy)) - free_omid(dummy); /* only one association with m_id*/ + free_omid(dummy); /* only one association with m_id */ if (Is_candle(dummy)) dummy->lamplit = 0; dummy->owornmask = 0L; /* dummy object is not worn */ addtobill(dummy, FALSE, TRUE, TRUE); - if (cost) + if (cost && dummy->where != OBJ_DELETED) alter_cost(dummy, -cost); /* no_charge is only valid for some locations */ otmp->no_charge = (otmp->where == OBJ_FLOOR @@ -889,11 +889,11 @@ mksobj_init(struct obj *otmp, boolean artif) tryct = 50; do otmp->corpsenm = undead_to_corpse(rndmonnum()); - while ((gm.mvitals[otmp->corpsenm].mvflags & G_NOCORPSE) + while ((svm.mvitals[otmp->corpsenm].mvflags & G_NOCORPSE) && (--tryct > 0)); if (tryct == 0) { /* perhaps rndmonnum() only wants to make G_NOCORPSE - monsters on this gl.level; create an adventurer's + monsters on this svl.level; create an adventurer's corpse instead, then */ otmp->corpsenm = PM_HUMAN; } @@ -919,7 +919,7 @@ mksobj_init(struct obj *otmp, boolean artif) for (tryct = 200; tryct > 0; --tryct) { mndx = undead_to_corpse(rndmonnum()); if (mons[mndx].cnutrit - && !(gm.mvitals[mndx].mvflags & G_NOCORPSE)) { + && !(svm.mvitals[mndx].mvflags & G_NOCORPSE)) { otmp->corpsenm = mndx; set_tin_variety(otmp, RANDOM_TIN); break; @@ -928,7 +928,7 @@ mksobj_init(struct obj *otmp, boolean artif) blessorcurse(otmp, 10); break; case SLIME_MOLD: - otmp->spe = gc.context.current_fruit; + otmp->spe = svc.context.current_fruit; flags.made_fruit = TRUE; break; case KELP_FROND: @@ -1046,7 +1046,7 @@ mksobj_init(struct obj *otmp, boolean artif) break; case AMULET_CLASS: if (otmp->otyp == AMULET_OF_YENDOR) - gc.context.made_amulet = TRUE; + svc.context.made_amulet = TRUE; if (rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION || otmp->otyp == AMULET_OF_CHANGE || otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) { @@ -1086,7 +1086,7 @@ mksobj_init(struct obj *otmp, boolean artif) otmp = mk_artifact(otmp, (aligntyp) A_NONE); /* simulate lacquered armor for samurai */ if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL - && (gm.moves <= 1 || In_quest(&u.uz))) { + && (svm.moves <= 1 || In_quest(&u.uz))) { #ifdef UNIXPC /* optimizer bitfield bug */ otmp->oerodeproof = 1; @@ -1100,7 +1100,8 @@ mksobj_init(struct obj *otmp, boolean artif) if (otmp->otyp == WAN_WISHING) otmp->spe = rnd(3); else - otmp->spe = rn1(5, (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4); + otmp->spe = rn1(5, + (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4); blessorcurse(otmp, 17); otmp->recharged = 0; /* used to control recharging */ break; @@ -1160,7 +1161,7 @@ mksobj(int otyp, boolean init, boolean artif) otmp = newobj(); *otmp = cg.zeroobj; - otmp->age = gm.moves; + otmp->age = max(svm.moves, 1L); otmp->o_id = next_ident(); otmp->quan = 1L; otmp->oclass = let; @@ -1181,7 +1182,7 @@ mksobj(int otyp, boolean init, boolean artif) case CORPSE: if (otmp->corpsenm == NON_PM) { otmp->corpsenm = undead_to_corpse(rndmonnum()); - if (gm.mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE | G_GONE)) + if (svm.mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE | G_GONE)) otmp->corpsenm = gu.urole.mnum; } /*FALLTHRU*/ @@ -1341,7 +1342,7 @@ start_corpse_timeout(struct obj *body) action = ROT_CORPSE; /* default action: rot away */ rot_adjust = gi.in_mklev ? 25 : 10; /* give some variation */ - age = gm.moves - body->age; + age = max(svm.moves, 1) - body->age; if (age > ROT_AGE) when = rot_adjust; else @@ -1460,9 +1461,9 @@ shrink_glob( /* * If shrinkage occurred while we were on another level, catch up now. */ - if (expire_time < gm.moves && globloc != BURIED_UNDER_ICE) { + if (expire_time < svm.moves && globloc != BURIED_UNDER_ICE) { /* number of units of weight to remove */ - long delta = (gm.moves - expire_time + 24L) / 25L, + long delta = (svm.moves - expire_time + 24L) / 25L, /* leftover amount to use for new timer */ moddelta = 25L - (delta % 25L); @@ -1501,7 +1502,7 @@ shrink_glob( */ if (eating_glob(obj) || globloc == BURIED_UNDER_ICE - || (globloc == SET_ON_ICE && (gm.moves % 3L) == 1L)) { + || (globloc == SET_ON_ICE && (svm.moves % 3L) == 1L)) { /* schedule next shrink attempt; for the being eaten case, the glob and its timer might be deleted before this kicks in */ start_glob_timeout(obj, 0L); @@ -1803,7 +1804,7 @@ set_bknown( { if (obj->bknown != onoff) { obj->bknown = onoff; - if (obj->where == OBJ_INVENT && gm.moves > 1L) + if (obj->where == OBJ_INVENT && svm.moves > 1L) update_inventory(); } } @@ -1964,7 +1965,7 @@ fixup_oil( } else if (source && source->otyp == POT_OIL) { /* potion is no longer oil, being turned into non-oil */ if (potion->age == source->age) - potion->age = gm.moves; + potion->age = svm.moves; /* when source is a partly used oil, mark potion as diluted */ if (source->age < MAX_OIL_IN_FLASK) potion->odiluted = 1; @@ -2031,8 +2032,9 @@ mkcorpstat( otmp->corpsenm = monsndx(ptr); otmp->owt = weight(otmp); - if (otmp->otyp == CORPSE && (gz.zombify || special_corpse(old_corpsenm) - || special_corpse(otmp->corpsenm))) { + if (otmp->otyp == CORPSE + && (gz.zombify || special_corpse(old_corpsenm) + || special_corpse(otmp->corpsenm))) { obj_stop_timers(otmp); start_corpse_timeout(otmp); } @@ -2246,7 +2248,7 @@ place_object(struct obj *otmp, coordxy x, coordxy y) safe_typename(otmp->otyp), otmp->where); assert(x >= 0 && x < COLNO && y >= 0 && y < ROWNO); - otmp2 = gl.level.objects[x][y]; + otmp2 = svl.level.objects[x][y]; obj_no_longer_held(otmp); if (otmp->otyp == BOULDER) { @@ -2266,7 +2268,7 @@ place_object(struct obj *otmp, coordxy x, coordxy y) } else { /* put on top of current pile */ otmp->nexthere = otmp2; - gl.level.objects[x][y] = otmp; + svl.level.objects[x][y] = otmp; } /* set the object's new location */ @@ -2294,7 +2296,7 @@ recreate_pile_at(coordxy x, coordxy y) struct obj *otmp, *next_obj, *reversed = 0; /* remove all objects at , saving a reversed temporary list */ - for (otmp = gl.level.objects[x][y]; otmp; otmp = next_obj) { + for (otmp = svl.level.objects[x][y]; otmp; otmp = next_obj) { next_obj = otmp->nexthere; remove_object(otmp); /* obj_extract_self() for floor */ otmp->nobj = reversed; @@ -2319,12 +2321,12 @@ obj_ice_effects(coordxy x, coordxy y, boolean do_buried) { struct obj *otmp; - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp->nexthere) { + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) { if (otmp->timed) obj_timer_checks(otmp, x, y, 0); } if (do_buried) { - for (otmp = gl.level.buriedobjlist; otmp; otmp = otmp->nobj) { + for (otmp = svl.level.buriedobjlist; otmp; otmp = otmp->nobj) { if (otmp->ox == x && otmp->oy == y) { if (otmp->timed) obj_timer_checks(otmp, x, y, 0); @@ -2347,12 +2349,12 @@ peek_at_iced_corpse_age(struct obj *otmp) if (otmp->otyp == CORPSE && otmp->on_ice) { /* Adjust the age; must be same as obj_timer_checks() for off ice*/ - age = gm.moves - otmp->age; + age = svm.moves - otmp->age; retval += age * (ROT_ICE_ADJUSTMENT - 1) / ROT_ICE_ADJUSTMENT; debugpline3( "The %s age has ice modifications: otmp->age = %ld, returning %ld.", s_suffix(doname(otmp)), otmp->age, retval); - debugpline1("Effective age of corpse: %ld.", gm.moves - retval); + debugpline1("Effective age of corpse: %ld.", svm.moves - retval); } return retval; } @@ -2381,8 +2383,8 @@ obj_timer_checks( /* mark the corpse as being on ice */ otmp->on_ice = 1; - debugpline3("%s is now on ice at <%d,%d>.", The(xname(otmp)), x, - y); + debugpline3("%s is now on ice at <%d,%d>.", + The(xname(otmp)), x, y); /* Adjust the time remaining */ tleft *= ROT_ICE_ADJUSTMENT; restart_timer = TRUE; @@ -2391,8 +2393,8 @@ obj_timer_checks( later calculations behave as if it had been on ice during that time (longwinded way of saying this is the inverse of removing it from the ice and of peeking at its age). */ - age = gm.moves - otmp->age; - otmp->age = gm.moves - (age * ROT_ICE_ADJUSTMENT); + age = svm.moves - otmp->age; + otmp->age = svm.moves - (age * ROT_ICE_ADJUSTMENT); } /* Check for corpses coming off ice */ @@ -2413,7 +2415,7 @@ obj_timer_checks( tleft /= ROT_ICE_ADJUSTMENT; restart_timer = TRUE; /* Adjust the age */ - age = gm.moves - otmp->age; + age = svm.moves - otmp->age; otmp->age += age * (ROT_ICE_ADJUSTMENT - 1) / ROT_ICE_ADJUSTMENT; } } @@ -2433,7 +2435,7 @@ remove_object(struct obj *otmp) if (otmp->where != OBJ_FLOOR) panic("remove_object: obj not on floor"); - extract_nexthere(otmp, &gl.level.objects[x][y]); + extract_nexthere(otmp, &svl.level.objects[x][y]); extract_nobj(otmp, &fobj); /* update vision iff this was the only boulder at its spot */ if (otmp->otyp == BOULDER && !sobj_at(BOULDER, x, y)) @@ -2459,7 +2461,8 @@ discard_minvent(struct monst *mtmp, boolean uncreate_artifacts) /* * Free obj from whatever list it is on in preparation for deleting it - * or moving it elsewhere; obj->where will end up set to OBJ_FREE. + * or moving it elsewhere; obj->where will end up set to OBJ_FREE unless + * it is already OBJ_LUAFREE or OBJ_DELETED. * Doesn't handle unwearing of objects in hero's or monsters' inventories. * * Object positions: @@ -2472,6 +2475,7 @@ discard_minvent(struct monst *mtmp, boolean uncreate_artifacts) * OBJ_BURIED level.buriedobjs chain * OBJ_ONBILL on gb.billobjs chain * OBJ_LUAFREE obj is dealloc'd from core, but still used by lua + * OBJ_DELETED obj has been deleted from play but not yet deallocated */ void obj_extract_self(struct obj *obj) @@ -2500,7 +2504,7 @@ obj_extract_self(struct obj *obj) extract_nobj(obj, &gm.migrating_objs); break; case OBJ_BURIED: - extract_nobj(obj, &gl.level.buriedobjlist); + extract_nobj(obj, &svl.level.buriedobjlist); break; case OBJ_ONBILL: extract_nobj(obj, &gb.billobjs); @@ -2643,8 +2647,8 @@ add_to_buried(struct obj *obj) panic("add_to_buried: obj not free"); obj->where = OBJ_BURIED; - obj->nobj = gl.level.buriedobjlist; - gl.level.buriedobjlist = obj; + obj->nobj = svl.level.buriedobjlist; + svl.level.buriedobjlist = obj; } /* recalculate weight of object, which doesn't have to be a container @@ -2704,9 +2708,9 @@ dealloc_obj(struct obj *obj) /* if obj came from the most recent splitobj(), it's no longer eligible for unsplitobj(); perform inline clear_splitobjs() */ - if (obj->o_id == gc.context.objsplit.parent_oid - || obj->o_id == gc.context.objsplit.child_oid) - gc.context.objsplit.parent_oid = gc.context.objsplit.child_oid = 0; + if (obj->o_id == svc.context.objsplit.parent_oid + || obj->o_id == svc.context.objsplit.child_oid) + svc.context.objsplit.parent_oid = svc.context.objsplit.child_oid = 0; if (obj->lua_ref_cnt) { /* obj is referenced from a lua script, let lua gc free it */ @@ -2869,7 +2873,7 @@ obj_sanity_check(void) for (y = 0; y < ROWNO; y++) { char at_fmt[BUFSZ]; - otop = gl.level.objects[x][y]; + otop = svl.level.objects[x][y]; prevo = 0; for (obj = otop; obj; prevo = obj, obj = prevo->nexthere) { /* should match ; <0,*> should always be empty */ @@ -2903,7 +2907,7 @@ obj_sanity_check(void) objlist_sanity(gi.invent, OBJ_INVENT, "invent sanity"); objlist_sanity(gm.migrating_objs, OBJ_MIGRATING, "migrating sanity"); - objlist_sanity(gl.level.buriedobjlist, OBJ_BURIED, "buried sanity"); + objlist_sanity(svl.level.buriedobjlist, OBJ_BURIED, "buried sanity"); objlist_sanity(gb.billobjs, OBJ_ONBILL, "bill sanity"); objlist_sanity(go.objs_deleted, OBJ_DELETED, "deleted object sanity"); @@ -3185,7 +3189,7 @@ nomerge_exception(struct obj *obj) static const char *const obj_state_names[NOBJ_STATES] = { "free", "floor", "contained", "invent", "minvent", "migrating", "buried", "onbill", - "luafree" + "luafree", "deleted", }; staticfn const char * @@ -3260,7 +3264,7 @@ init_dummyobj(struct obj *obj, short otyp, long oquan) obj->next_boulder = 0; /* overloads corpsenm, avoid NON_PM */ /* but suppressing fruit details leads to "bad fruit #0" */ if (obj->otyp == SLIME_MOLD) - obj->spe = gc.context.current_fruit; + obj->spe = svc.context.current_fruit; } return obj; } @@ -3619,11 +3623,11 @@ obj_absorb(struct obj **obj1, struct obj **obj2) o2wt = otmp2->oeaten ? otmp2->oeaten : otmp2->owt; /* averaging the relative ages is less likely to overflow than averaging the absolute ages directly */ - agetmp = (((gm.moves - otmp1->age) * o1wt - + (gm.moves - otmp2->age) * o2wt) + agetmp = (((svm.moves - otmp1->age) * o1wt + + (svm.moves - otmp2->age) * o2wt) / (o1wt + o2wt)); /* convert relative age back to absolute age */ - otmp1->age = gm.moves - agetmp; + otmp1->age = svm.moves - agetmp; otmp1->owt += o2wt; if (otmp1->oeaten || otmp2->oeaten) otmp1->oeaten = o1wt + o2wt; diff --git a/src/mkroom.c b/src/mkroom.c index 0d256ab79..61a913e8f 100644 --- a/src/mkroom.c +++ b/src/mkroom.c @@ -150,14 +150,14 @@ mkshop(void) } gottype: - for (sroom = &gr.rooms[0];; sroom++) { + for (sroom = &svr.rooms[0];; sroom++) { /* return from this loop: cannot find any eligible room to be a shop * continue: sroom is ineligible * break: sroom is eligible */ if (sroom->hx < 0) return; - if (sroom - gr.rooms >= gn.nroom) { + if (sroom - svr.rooms >= svn.nroom) { impossible("rooms[] not closed by -1?"); return; } @@ -215,11 +215,11 @@ staticfn struct mkroom * pick_room(boolean strict) { struct mkroom *sroom; - int i = gn.nroom; + int i = svn.nroom; - for (sroom = &gr.rooms[rn2(gn.nroom)]; i--; sroom++) { - if (sroom == &gr.rooms[gn.nroom]) - sroom = &gr.rooms[0]; + for (sroom = &svr.rooms[rn2(svn.nroom)]; i--; sroom++) { + if (sroom == &svr.rooms[svn.nroom]) + sroom = &svr.rooms[0]; if (sroom->hx < 0) return (struct mkroom *) 0; if (sroom->rtype != OROOM) @@ -274,7 +274,7 @@ fill_zoo(struct mkroom *sroom) int sx, sy, i; int sh, goldlim = 0, type = sroom->rtype; coordxy tx = 0, ty = 0; - int rmno = (int) ((sroom - gr.rooms) + ROOMOFFSET); + int rmno = (int) ((sroom - svr.rooms) + ROOMOFFSET); coord mm; /* Note: This doesn't check needfill; it assumes the caller has already @@ -282,7 +282,7 @@ fill_zoo(struct mkroom *sroom) sh = sroom->fdoor; switch (type) { case COURT: - if (gl.level.flags.is_maze_lev) { + if (svl.level.flags.is_maze_lev) { for (tx = sroom->lx; tx <= sroom->hx; tx++) for (ty = sroom->ly; ty <= sroom->hy; ty++) if (IS_THRONE(levl[tx][ty].typ)) @@ -320,15 +320,18 @@ fill_zoo(struct mkroom *sroom) if (sroom->irregular) { if ((int) levl[sx][sy].roomno != rmno || levl[sx][sy].edge || (sroom->doorct - && distmin(sx, sy, gd.doors[sh].x, gd.doors[sh].y) <= 1)) + && (distmin(sx, sy, svd.doors[sh].x, svd.doors[sh].y) + <= 1))) continue; } else if (!SPACE_POS(levl[sx][sy].typ) || (sroom->doorct - && ((sx == sroom->lx && gd.doors[sh].x == sx - 1) - || (sx == sroom->hx && gd.doors[sh].x == sx + 1) - || (sy == sroom->ly && gd.doors[sh].y == sy - 1) + && ((sx == sroom->lx && svd.doors[sh].x == sx - 1) + || (sx == sroom->hx && svd.doors[sh].x + == sx + 1) + || (sy == sroom->ly && svd.doors[sh].y + == sy - 1) || (sy == sroom->hy - && gd.doors[sh].y == sy + 1)))) + && svd.doors[sh].y == sy + 1)))) continue; /* don't place monster on explicitly placed throne */ if (type == COURT && IS_THRONE(levl[sx][sy].typ)) @@ -362,7 +365,8 @@ fill_zoo(struct mkroom *sroom) case ZOO: case LEPREHALL: if (sroom->doorct) { - int distval = dist2(sx, sy, gd.doors[sh].x, gd.doors[sh].y); + int distval = dist2(sx, sy, + svd.doors[sh].x, svd.doors[sh].y); i = sq(distval); } else i = goldlim; @@ -421,23 +425,23 @@ fill_zoo(struct mkroom *sroom) add_to_container(chest, gold); chest->owt = weight(chest); chest->spe = 2; /* so it can be found later */ - gl.level.flags.has_court = 1; + svl.level.flags.has_court = 1; break; } case BARRACKS: - gl.level.flags.has_barracks = 1; + svl.level.flags.has_barracks = 1; break; case ZOO: - gl.level.flags.has_zoo = 1; + svl.level.flags.has_zoo = 1; break; case MORGUE: - gl.level.flags.has_morgue = 1; + svl.level.flags.has_morgue = 1; break; case SWAMP: - gl.level.flags.has_swamp = 1; + svl.level.flags.has_swamp = 1; break; case BEEHIVE: - gl.level.flags.has_beehive = 1; + svl.level.flags.has_beehive = 1; break; } } @@ -462,7 +466,7 @@ mkundead( || !revive(otmp, FALSE))) (void) makemon(mdat, cc.x, cc.y, mm_flags); } - gl.level.flags.graveyard = TRUE; /* reduced chance for undead corpse */ + svl.level.flags.graveyard = TRUE; /* reduced chance for undead corpse */ } staticfn struct permonst * @@ -511,9 +515,9 @@ antholemon(void) break; } /* try again if chosen type has been genocided or used up */ - } while (++trycnt < 3 && (gm.mvitals[mtyp].mvflags & G_GONE)); + } while (++trycnt < 3 && (svm.mvitals[mtyp].mvflags & G_GONE)); - return ((gm.mvitals[mtyp].mvflags & G_GONE) ? (struct permonst *) 0 + return ((svm.mvitals[mtyp].mvflags & G_GONE) ? (struct permonst *) 0 : &mons[mtyp]); } @@ -526,12 +530,12 @@ mkswamp(void) /* Michiel Huisjes & Fred de Wilde */ int rmno; for (i = 0; i < 5; i++) { /* turn up to 5 rooms swampy */ - sroom = &gr.rooms[rn2(gn.nroom)]; + sroom = &svr.rooms[rn2(svn.nroom)]; if (sroom->hx < 0 || sroom->rtype != OROOM || has_upstairs(sroom) || has_dnstairs(sroom)) continue; - rmno = (int)(sroom - gr.rooms) + ROOMOFFSET; + rmno = (int)(sroom - svr.rooms) + ROOMOFFSET; /* satisfied; make a swamp */ sroom->rtype = SWAMP; @@ -560,7 +564,7 @@ mkswamp(void) /* Michiel Huisjes & Fred de Wilde */ NO_MM_FLAGS); } } - gl.level.flags.has_swamp = 1; + svl.level.flags.has_swamp = 1; } } @@ -569,7 +573,7 @@ shrine_pos(int roomno) { static coord buf; int delta; - struct mkroom *troom = &gr.rooms[roomno - ROOMOFFSET]; + struct mkroom *troom = &svr.rooms[roomno - ROOMOFFSET]; /* if width and height are odd, placement will be the exact center; if either or both are even, center point is a hypothetical spot @@ -601,13 +605,13 @@ mktemple(void) * In temples, shrines are blessed altars * located in the center of the room */ - shrine_spot = shrine_pos((int) ((sroom - gr.rooms) + ROOMOFFSET)); + shrine_spot = shrine_pos((int) ((sroom - svr.rooms) + ROOMOFFSET)); lev = &levl[shrine_spot->x][shrine_spot->y]; lev->typ = ALTAR; lev->altarmask = induced_align(80); priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE); lev->altarmask |= AM_SHRINE; - gl.level.flags.has_temple = 1; + svl.level.flags.has_temple = 1; } boolean @@ -669,7 +673,7 @@ boolean inside_room(struct mkroom *croom, coordxy x, coordxy y) { if (croom->irregular) { - int i = (int) ((croom - gr.rooms) + ROOMOFFSET); + int i = (int) ((croom - svr.rooms) + ROOMOFFSET); return (!levl[x][y].edge && (int) levl[x][y].roomno == i); } @@ -688,7 +692,7 @@ somexy(struct mkroom *croom, coord *c) int i; if (croom->irregular) { - i = (int) ((croom - gr.rooms) + ROOMOFFSET); + i = (int) ((croom - svr.rooms) + ROOMOFFSET); while (try_cnt++ < 100) { c->x = somex(croom); @@ -757,7 +761,7 @@ search_special(schar type) { struct mkroom *croom; - for (croom = &gr.rooms[0]; croom->hx >= 0; croom++) + for (croom = &svr.rooms[0]; croom->hx >= 0; croom++) if ((type == ANY_TYPE && croom->rtype != OROOM) || (type == ANY_SHOP && croom->rtype >= SHOPBASE) || croom->rtype == type) @@ -821,7 +825,7 @@ squadmon(void) } mndx = ROLL_FROM(squadprob).pm; gotone: - if (!(gm.mvitals[mndx].mvflags & G_GONE)) + if (!(svm.mvitals[mndx].mvflags & G_GONE)) return &mons[mndx]; else return (struct permonst *) 0; @@ -858,9 +862,9 @@ save_rooms(NHFILE *nhfp) /* First, write the number of rooms */ if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &gn.nroom, sizeof(gn.nroom)); - for (i = 0; i < gn.nroom; i++) - save_room(nhfp, &gr.rooms[i]); + bwrite(nhfp->fd, (genericptr_t) &svn.nroom, sizeof(svn.nroom)); + for (i = 0; i < svn.nroom; i++) + save_room(nhfp, &svr.rooms[i]); } staticfn void @@ -888,14 +892,14 @@ rest_rooms(NHFILE *nhfp) short i; if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &gn.nroom, sizeof(gn.nroom)); + mread(nhfp->fd, (genericptr_t) &svn.nroom, sizeof(svn.nroom)); gn.nsubroom = 0; - for (i = 0; i < gn.nroom; i++) { - rest_room(nhfp, &gr.rooms[i]); - gr.rooms[i].resident = (struct monst *) 0; + for (i = 0; i < svn.nroom; i++) { + rest_room(nhfp, &svr.rooms[i]); + svr.rooms[i].resident = (struct monst *) 0; } - gr.rooms[gn.nroom].hx = -1; /* restore ending flags */ + svr.rooms[svn.nroom].hx = -1; /* restore ending flags */ gs.subrooms[gn.nsubroom].hx = -1; } @@ -1022,17 +1026,17 @@ cmap_to_type(int sym) return typ; } -/* With the introduction of themed rooms, there are certain room shapes that may - * generate a door, the square just inside the door, and only one other ROOM - * square touching that one. E.g. +/* With the introduction of themed rooms, there are certain room shapes that + * may generate a door, the square just inside the door, and only one other + * ROOM square touching that one. E.g. * --- * ---.. * +.... * ---.. * --- - * This means that if the room becomes a shop, the shopkeeper will move between - * those two squares nearest the door without ever allowing the player to get - * past them. + * This means that if the room becomes a shop, the shopkeeper will move + * between those two squares nearest the door without ever allowing the + * player to get past them. * Before approving sroom as a shop, check for this circumstance, and if it * exists, don't consider it as valid for a shop. * @@ -1043,8 +1047,8 @@ staticfn boolean invalid_shop_shape(struct mkroom *sroom) { coordxy x, y; - coordxy doorx = gd.doors[sroom->fdoor].x; - coordxy doory = gd.doors[sroom->fdoor].y; + coordxy doorx = svd.doors[sroom->fdoor].x; + coordxy doory = svd.doors[sroom->fdoor].y; coordxy insidex = 0, insidey = 0, insidect = 0; /* First, identify squares inside the room and next to the door. */ diff --git a/src/mon.c b/src/mon.c index a436dc897..a52f9a051 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mon.c $NHDT-Date: 1718303201 2024/06/13 18:26:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.576 $ */ +/* NetHack 3.7 mon.c $NHDT-Date: 1722365546 2024/07/30 18:52:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.584 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -40,8 +40,8 @@ extern const struct shclass shtypes[]; /* defined in shknam.c */ #define LEVEL_SPECIFIC_NOCORPSE(mdat) \ (Is_rogue_level(&u.uz) \ - || !gl.level.flags.deathdrops \ - || (gl.level.flags.graveyard && is_undead(mdat) && rn2(3))) + || !svl.level.flags.deathdrops \ + || (svl.level.flags.graveyard && is_undead(mdat) && rn2(3))) #if 0 @@ -98,7 +98,7 @@ sanity_check_single_mon( #endif return; } - if (chk_geno && (gm.mvitals[mndx].mvflags & G_GENOD) != 0) + if (chk_geno && (svm.mvitals[mndx].mvflags & G_GENOD) != 0) impossible("genocided %s in play (%s)", pmname(mptr, Mgender(mtmp)), msg); if (mtmp->mtame && !mtmp->mpeaceful) @@ -255,7 +255,7 @@ mon_sanity_check(void) if (x != u.ux || y != u.uy) impossible("steed (%s) claims to be at <%d,%d>?", fmt_ptr((genericptr_t) mtmp), x, y); - } else if (gl.level.monsters[x][y] != mtmp) { + } else if (svl.level.monsters[x][y] != mtmp) { impossible("mon (%s) at <%d,%d> is not there!", fmt_ptr((genericptr_t) mtmp), x, y); } else if (mtmp->wormno) { @@ -271,7 +271,7 @@ mon_sanity_check(void) for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) - if ((mtmp = gl.level.monsters[x][y]) != 0) { + if ((mtmp = svl.level.monsters[x][y]) != 0) { for (m = fmon; m; m = m->nmon) if (m == mtmp) break; @@ -530,7 +530,7 @@ pm_to_cham(int mndx) || is_reviver((mon)->data) \ /* normally quest leader will be unique, */ \ /* but he or she might have been polymorphed */ \ - || (mon)->m_id == gq.quest_status.leader_m_id \ + || (mon)->m_id == svq.quest_status.leader_m_id \ /* special cancellation handling for these */ \ || (dmgtype((mon)->data, AD_SEDU) || dmgtype((mon)->data, AD_SSEX))) @@ -712,7 +712,7 @@ make_corpse(struct monst *mtmp, unsigned int corpseflags) case PM_FIRE_ANT: case PM_GIANT_BEETLE: case PM_QUEEN_BEE: case PM_QUIVERING_BLOB: case PM_ACID_BLOB: case PM_GELATINOUS_CUBE: - case PM_CHICKATRICE: case PM_COCKATRICE: case PM_PYROLISK: + case PM_CHICKATRICE: case PM_COCKATRICE: case PM_PYROLISK: case PM_JACKAL: case PM_FOX: case PM_COYOTE: case PM_WEREJACKAL: case PM_LITTLE_DOG: case PM_DINGO: case PM_DOG: case PM_LARGE_DOG: @@ -780,7 +780,7 @@ make_corpse(struct monst *mtmp, unsigned int corpseflags) case PM_GNOME: case PM_GNOME_LEADER: case PM_GNOMISH_WIZARD: case PM_GNOME_RULER: - case PM_GIANT: case PM_STONE_GIANT: case PM_HILL_GIANT: + case PM_GIANT: case PM_STONE_GIANT: case PM_HILL_GIANT: case PM_FIRE_GIANT: case PM_FROST_GIANT: case PM_ETTIN: case PM_STORM_GIANT: case PM_TITAN: @@ -865,8 +865,8 @@ make_corpse(struct monst *mtmp, unsigned int corpseflags) #else default: #endif -default_1: - if (gm.mvitals[mndx].mvflags & G_NOCORPSE) { + default_1: + if (svm.mvitals[mndx].mvflags & G_NOCORPSE) { return (struct obj *) 0; } else { corpstatflags |= CORPSTAT_INIT; @@ -890,7 +890,7 @@ default_1: /* if polymorph or undead turning has killed this monster, prevent the same attack beam from hitting its corpse */ - if (gc.context.bypasses) + if (svc.context.bypasses) bypass_obj(obj); if (has_mgivenname(mtmp)) @@ -1010,7 +1010,7 @@ minliquid_core(struct monst *mtmp) hero to create lava beneath a monster, so the !mon_moving case is not expected to happen (and we haven't made a player-against-monster variation of the message above) */ - if (gc.context.mon_moving) + if (svc.context.mon_moving) mondead(mtmp); /* no corpse */ else xkilled(mtmp, XKILL_NOMSG); @@ -1038,7 +1038,8 @@ minliquid_core(struct monst *mtmp) * water damage to dead monsters' inventory, but survivors need to * be handled here. Swimmers are able to protect their stuff... */ - if ((waterwall || !is_clinger(mtmp->data)) && !cant_drown(mtmp->data)) { + if ((waterwall || !is_clinger(mtmp->data)) + && !cant_drown(mtmp->data)) { /* like hero with teleport intrinsic or spell, teleport away if possible */ if (can_teleport(mtmp->data) && !tele_restrict(mtmp)) { @@ -1046,7 +1047,7 @@ minliquid_core(struct monst *mtmp) return 0; } if (cansee(mtmp->mx, mtmp->my)) { - if (gc.context.mon_moving) + if (svc.context.mon_moving) pline_mon(mtmp, "%s drowns.", Monnam(mtmp)); else /* hero used fire to melt ice that monster was on */ @@ -1058,7 +1059,7 @@ minliquid_core(struct monst *mtmp) pline("%s sinks as %s rushes in and flushes you out.", Monnam(mtmp), hliquid("water")); } - if (gc.context.mon_moving) + if (svc.context.mon_moving) mondied(mtmp); /* ok to leave corpse despite water */ else xkilled(mtmp, XKILL_NOMSG); @@ -1102,7 +1103,7 @@ mcalcmove( else if (mon->mspeed == MFAST) mmove = (4 * mmove + 2) / 3; - if (mon == u.usteed && u.ugallop && gc.context.mv) { + if (mon == u.usteed && u.ugallop && svc.context.mv) { /* increase movement by a factor of 1.5; also increase variance of movement speed (if it's naturally 24, we don't want it to always become 36) */ @@ -1151,9 +1152,7 @@ m_calcdistress(struct monst *mtmp) /* possibly polymorph shapechangers and lycanthropes */ if (ismnum(mtmp->cham)) - decide_to_shapeshift(mtmp, (canspotmon(mtmp) - || engulfing_u(mtmp)) - ? SHIFT_MSG : 0); + decide_to_shapeshift(mtmp); were_change(mtmp); /* gradually time out temporary problems */ @@ -1176,7 +1175,7 @@ movemon_singlemon(struct monst *mtmp) if (u.utotype #ifdef SAFERHANGUP /* or if the program has lost contact with the user */ - || gp.program_state.done_hup + || program_state.done_hup #endif ) { gs.somebody_can_move = FALSE; @@ -1191,9 +1190,9 @@ movemon_singlemon(struct monst *mtmp) mon->isgd flag so that dmonsfree() will get rid of mon) */ if (mtmp->isgd && !mtmp->mx && !(mtmp->mstate & MON_MIGRATING)) { /* parked at <0,0>; eventually isgd should get set to false */ - if (gm.moves > mtmp->mlstmv) { + if (svm.moves > mtmp->mlstmv) { (void) gd_move(mtmp); - mtmp->mlstmv = gm.moves; + mtmp->mlstmv = svm.moves; } return FALSE; } @@ -1218,7 +1217,7 @@ movemon_singlemon(struct monst *mtmp) vision_recalc(0); /* vision! */ /* reset obj bypasses before next monster moves */ - if (gc.context.bypasses) + if (svc.context.bypasses) clear_bypasses(); clear_splitobjs(); if (minliquid(mtmp)) @@ -1291,7 +1290,7 @@ movemon(void) if (any_light_source()) gv.vision_full_recalc = 1; /* in case a mon moved w/ a light source */ /* reset obj bypasses after last monster has moved */ - if (gc.context.bypasses) + if (svc.context.bypasses) clear_bypasses(); clear_splitobjs(); /* remove dead monsters; dead vault guard will be left at <0,0> @@ -1374,7 +1373,7 @@ m_consume_obj(struct monst *mtmp, struct obj *otmp) || corpsenm == PM_LARGE_MIMIC || corpsenm == PM_GIANT_MIMIC)); slimer = (otmp->otyp == GLOB_OF_GREEN_SLIME); - poly = polyfodder(otmp); + poly = polyfood(otmp); grow = mlevelgain(otmp); heal = mhealup(otmp); eyes = (otmp->otyp == CARROT); @@ -1432,7 +1431,7 @@ meatmetal(struct monst *mtmp) return 0; /* Eats topmost metal object if it is there */ - for (otmp = gl.level.objects[mtmp->mx][mtmp->my]; otmp; + for (otmp = svl.level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp->nexthere) { /* Don't eat indigestible/choking/inappropriate objects */ if ((mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp)) @@ -1505,7 +1504,7 @@ meatobj(struct monst* mtmp) /* for gelatinous cubes */ /* eat organic objects, including cloth and wood, if present; engulf others, except huge rocks and metal attached to player [despite comment at top, doesn't assume that eater is a g-cube] */ - for (otmp = gl.level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { + for (otmp = svl.level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; /* avoid special items; once hero picks them up, they'll cease @@ -1632,7 +1631,7 @@ meatcorpse( /* skip some corpses */ if (vegan(corpsepm) /* ignore veggy corpse even if omnivorous */ /* don't eat harmful corpses */ - || (touch_petrifies(corpsepm) && !resists_ston(mtmp))) + || (flesh_petrifies(corpsepm) && !resists_ston(mtmp))) continue; if (is_rider(corpsepm)) { boolean revived_it = revive_corpse(otmp); @@ -1687,9 +1686,9 @@ mon_give_prop(struct monst *mtmp, int prop) const char *msg = NULL; unsigned short intrinsic = 0; /* MR_* constant */ - /* Pets don't have all the fields that the hero does, so they can't get all - the same intrinsics. If it happens to choose strength gain or teleport - control or whatever, ignore it. */ + /* Pets don't have all the fields that the hero does, so they can't get + all the same intrinsics. If it happens to choose strength gain or + teleport control or whatever, ignore it. */ switch (prop) { case FIRE_RES: msg = "%s shivers slightly."; @@ -1820,7 +1819,7 @@ mpickstuff(struct monst *mtmp) if (!could_reach_item(mtmp, mtmp->mx, mtmp->my)) return FALSE; - for (otmp = gl.level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { + for (otmp = svl.level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; /* avoid special items; once hero picks them up, they'll cease @@ -2226,7 +2225,8 @@ mfndpos( /* Displacement also displaces the Elbereth/scare monster, * as long as you are visible. */ - if (Displaced && monseeu && mon->mux == nx && mon->muy == ny) { + if (Displaced && monseeu + && mon->mux == nx && mon->muy == ny) { dispx = u.ux; dispy = u.uy; } else { @@ -2277,7 +2277,8 @@ mfndpos( } /* Note: ALLOW_SANCT only prevents movement, not attack, into a temple. */ - if (gl.level.flags.has_temple && *in_rooms(nx, ny, TEMPLE) + if (svl.level.flags.has_temple + && *in_rooms(nx, ny, TEMPLE) && !*in_rooms(x, y, TEMPLE) && in_your_sanctuary((struct monst *) 0, nx, ny)) { if (!(flag & ALLOW_SANCT)) @@ -2311,8 +2312,8 @@ mfndpos( */ if ((ttmp = t_at(nx, ny)) != 0) { if (ttmp->ttyp >= TRAPNUM || ttmp->ttyp == 0) { - impossible( - "A monster looked at a very strange trap of type %d.", + impossible("A monster looked at a very strange trap" + " of type %d.", ttmp->ttyp); continue; } @@ -2457,8 +2458,8 @@ replmon(struct monst *mtmp, struct monst *mtmp2) } mtmp->minvent = 0; /* before relmon(mtmp), because it could clear polearm.hitmon */ - if (gc.context.polearm.hitmon == mtmp) - gc.context.polearm.hitmon = mtmp2; + if (svc.context.polearm.hitmon == mtmp) + svc.context.polearm.hitmon = mtmp2; /* remove the old monster from the map and from `fmon' list */ relmon(mtmp, (struct monst **) 0); @@ -2621,14 +2622,14 @@ staticfn void mon_leaving_level(struct monst *mon) { coordxy mx = mon->mx, my = mon->my; - boolean onmap = (isok(mx, my) && gl.level.monsters[mx][my] == mon); + boolean onmap = (isok(mx, my) && svl.level.monsters[mx][my] == mon); /* to prevent an infinite relobj-flooreffects-hmon-killed loop */ mon->mtrapped = 0; unstuck(mon); /* mon is not swallowing or holding you nor held by you */ /* vault guard might be at <0,0> */ - if (onmap || mon == gl.level.monsters[0][0]) { + if (onmap || mon == svl.level.monsters[0][0]) { if (mon->wormno) remove_worm(mon); else @@ -2650,8 +2651,8 @@ mon_leaving_level(struct monst *mon) newsym(mx, my); } /* if mon is a remembered target, forget it since it isn't here anymore */ - if (mon == gc.context.polearm.hitmon) - gc.context.polearm.hitmon = (struct monst *) 0; + if (mon == svc.context.polearm.hitmon) + svc.context.polearm.hitmon = (struct monst *) 0; } /* 'mtmp' is going away; remove effects of mtmp from other data structures */ @@ -2789,7 +2790,7 @@ lifesaved_monster(struct monst *mtmp) /* equip replacement amulet, if any, on next move */ check_gear_next_turn(mtmp); - surviver = !(gm.mvitals[monsndx(mtmp->data)].mvflags & G_GENOD); + surviver = !(svm.mvitals[monsndx(mtmp->data)].mvflags & G_GENOD); mtmp->mcanmove = 1; mtmp->mfrozen = 0; if (mtmp->mtame && !mtmp->isminion) { @@ -2808,8 +2809,6 @@ lifesaved_monster(struct monst *mtmp) } } -DISABLE_WARNING_FORMAT_NONLITERAL - /* when a shape-shifted vampire is killed, it reverts to base form instead of dying; moved into separate routine to unclutter mondead() */ staticfn boolean @@ -2818,9 +2817,9 @@ vamprises(struct monst *mtmp) int mndx = mtmp->cham; if (ismnum(mndx) && mndx != monsndx(mtmp->data) - && !(gm.mvitals[mndx].mvflags & G_GENOD)) { + && !(svm.mvitals[mndx].mvflags & G_GENOD)) { coord new_xy; - char buf[BUFSZ]; + char action[BUFSZ]; /* alternate message phrasing for some monster types */ boolean spec_mon = (nonliving(mtmp->data) || noncorporeal(mtmp->data) @@ -2830,13 +2829,12 @@ vamprises(struct monst *mtmp) || amorphous(mtmp->data)); coordxy x = mtmp->mx, y = mtmp->my; - /* construct a format string before transformation; - will be capitalized when used, expects one %s arg */ - Snprintf(buf, sizeof buf, - "%s suddenly %s and rises as %%s!", + /* construct a 'before' argument to pass to pline(); this used + to construct a dynamic format string but that's overkill */ + Snprintf(action, sizeof action, "%s suddenly %s and rises as", x_monnam(mtmp, ARTICLE_THE, spec_mon ? (char *) 0 : "seemingly dead", - (SUPPRESS_INVISIBLE | SUPPRESS_IT), FALSE), + (SUPPRESS_INVISIBLE | AUGMENT_IT), FALSE), spec_death ? "reconstitutes" : "transforms"); mtmp->mcanmove = 1; mtmp->mfrozen = 0; @@ -2857,19 +2855,16 @@ vamprises(struct monst *mtmp) rloc_to(mtmp, new_xy.x, new_xy.y); } (void) newcham(mtmp, &mons[mndx], NO_NC_FLAGS); - if (mtmp->data == &mons[mndx]) - mtmp->cham = NON_PM; - else - mtmp->cham = mndx; + mtmp->cham = (mtmp->data == &mons[mndx]) ? NON_PM : mndx; if (canspotmon(mtmp)) { /* 3.6.0 used a_monnam(mtmp); that was weird if mtmp was named: "Dracula suddenly transforms and rises as Dracula"; 3.6.1 used mtmp->data->mname; that ignored hallucination */ - pline_mon(mtmp, upstart(buf), - x_monnam(mtmp, ARTICLE_A, (char *) 0, + pline_mon(mtmp, "%s %s!", upstart(action), + x_monnam(mtmp, ARTICLE_A, (char *) 0, (SUPPRESS_NAME | SUPPRESS_IT | SUPPRESS_INVISIBLE), - FALSE)); + FALSE)); gv.vamp_rise_msg = TRUE; } newsym(x, y); @@ -2878,8 +2873,6 @@ vamprises(struct monst *mtmp) return FALSE; } -RESTORE_WARNING_FORMAT_NONLITERAL - /* specific combination of x_monnam flags for livelogging; show what was actually killed even when unseen or hallucinated to be something else */ #define livelog_mon_nam(mtmp) \ @@ -2890,7 +2883,7 @@ RESTORE_WARNING_FORMAT_NONLITERAL staticfn void logdeadmon(struct monst *mtmp, int mndx) { - int howmany = gm.mvitals[mndx].died; + int howmany = svm.mvitals[mndx].died; if (mndx == PM_MEDUSA && howmany == 1) { record_achievement(ACH_MEDU); /* also generates a livelog event */ @@ -2899,7 +2892,7 @@ logdeadmon(struct monst *mtmp, int mndx) || (mtmp->isshk && !mtmp->mrevived)) { char shkdetail[QBUFSZ]; const char *mkilled; - boolean herodidit = !gc.context.mon_moving; + boolean herodidit = !svc.context.mon_moving; /* * livelog event; unique_corpstat() includes the Wizard and @@ -3010,7 +3003,7 @@ mondead(struct monst *mtmp) set_mon_data(mtmp, &mons[PM_HUMAN_WERERAT]); /* - * gm.mvitals[].died does double duty as total number of dead monsters + * svm.mvitals[].died does double duty as total number of dead monsters * and as experience factor for the player killing more monsters. * this means that a dragon dying by other means reduces the * experience the player gets for killing a dragon directly; this @@ -3020,16 +3013,16 @@ mondead(struct monst *mtmp) * for rings of conflict and such. */ mndx = monsndx(mtmp->data); - if (gm.mvitals[mndx].died < 255) - gm.mvitals[mndx].died++; + if (svm.mvitals[mndx].died < 255) + svm.mvitals[mndx].died++; /* if it's a (possibly polymorphed) quest leader, mark him as dead */ - if (mtmp->m_id == gq.quest_status.leader_m_id) - gq.quest_status.leader_is_dead = TRUE; + if (mtmp->m_id == svq.quest_status.leader_m_id) + svq.quest_status.leader_is_dead = TRUE; #ifdef MAIL_STRUCTURES /* if the mail daemon dies, no more mail delivery. -3. */ if (mndx == PM_MAIL_DAEMON) - gm.mvitals[mndx].mvflags |= G_GENOD; + svm.mvitals[mndx].mvflags |= G_GENOD; #endif if (mtmp->data->mlet == S_KOP) { @@ -3092,9 +3085,10 @@ corpse_chance( if (was_swallowed && magr) { if (magr == &gy.youmonst) { There("is an explosion in your %s!", body_part(STOMACH)); - Sprintf(gk.killer.name, "%s explosion", + Sprintf(svk.killer.name, "%s explosion", s_suffix(pmname(mdat, Mgender(mon)))); - losehp(Maybe_Half_Phys(tmp), gk.killer.name, KILLED_BY_AN); + losehp(Maybe_Half_Phys(tmp), svk.killer.name, + KILLED_BY_AN); } else { You_hear("an explosion."); magr->mhp -= tmp; @@ -3358,7 +3352,7 @@ killed(struct monst *mtmp) void xkilled( struct monst *mtmp, - int xkill_flags) /* 1: suppress message, 2: suppress corpse, 4: pacifist */ + int xkill_flags) /* 1: suppress mesg, 2: suppress corpse, 4: pacifist */ { int tmp, mndx; coordxy x = mtmp->mx, y = mtmp->my; @@ -3466,7 +3460,7 @@ xkilled( int otyp; /* illogical but traditional "treasure drop" */ - if (!rn2(6) && !(gm.mvitals[mndx].mvflags & G_NOCORPSE) + if (!rn2(6) && !(svm.mvitals[mndx].mvflags & G_NOCORPSE) /* no extra item from swallower or steed */ && (x != u.ux || y != u.uy) /* no extra item from kops--too easy to abuse */ @@ -3551,19 +3545,19 @@ xkilled( } /* give experience points */ - tmp = experience(mtmp, (int) gm.mvitals[mndx].died); + tmp = experience(mtmp, (int) svm.mvitals[mndx].died); more_experienced(tmp, 0); newexplevel(); /* will decide if you go up */ /* adjust alignment points */ - if (mtmp->m_id == gq.quest_status.leader_m_id) { /* REAL BAD! */ + if (mtmp->m_id == svq.quest_status.leader_m_id) { /* REAL BAD! */ adjalign(-(u.ualign.record + (int) ALIGNLIM / 2)); u.ugangr += 7; /* instantly become "extremely" angry */ change_luck(-20); pline("That was %sa bad idea...", u.uevent.qcompleted ? "probably " : ""); } else if (mdat->msound == MS_NEMESIS) { /* Real good! */ - if (!gq.quest_status.killed_leader) + if (!svq.quest_status.killed_leader) adjalign((int) (ALIGNLIM / 4)); } else if (mdat->msound == MS_GUARDIAN) { /* Bad */ adjalign(-(int) (ALIGNLIM / 8)); @@ -3637,7 +3631,7 @@ vamp_stone(struct monst *mtmp) /* this only happens if shapeshifted */ if (mndx >= LOW_PM && mndx != monsndx(mtmp->data) - && !(gm.mvitals[mndx].mvflags & G_GENOD)) { + && !(svm.mvitals[mndx].mvflags & G_GENOD)) { char buf[BUFSZ]; /* construct a format string before transformation */ @@ -3749,10 +3743,10 @@ elemental_clog(struct monst *mon) if (In_endgame(&u.uz)) { m1 = m2 = m3 = m4 = m5 = zm = (struct monst *) 0; - if (!msgmv || (gm.moves - msgmv) > 200L) { + if (!msgmv || (svm.moves - msgmv) > 200L) { if (!msgmv || rn2(2)) You_feel("besieged."); - msgmv = gm.moves; + msgmv = svm.moves; } /* * m1 an elemental from another plane. @@ -3942,7 +3936,8 @@ mnearto( if (move_other && othermon) { res = 2; /* moving another monster out of the way */ - if (!mnearto(othermon, x, y, FALSE, rlocflags)) /* no 'move_other' this time */ + /* 'move_other'==FALSE this time; fail rather than recurse */ + if (!mnearto(othermon, x, y, FALSE, rlocflags)) deal_with_overcrowding(othermon); } @@ -4050,14 +4045,20 @@ peacefuls_respond(struct monst *mtmp) } } /* shopkeepers and temple priests might gasp in - surprise, but they won't become angry here */ - if (mon->isshk || mon->ispriest) { + surprise, but they won't become angry here; + quest leader will only get angry if hero attacks + own quest guardians */ + if (mon->isshk || mon->ispriest + || (mon->data == &mons[quest_info(MS_LEADER)] + && mtmp->data != &mons[gu.urole.guardnum])) { if (exclaimed) pline_mon(mon, "%s%s", buf, " then shrugs."); continue; } - if (mon->data->mlevel < rn2(10)) { + if (mon->data->mlevel < rn2(10) + /* don't have quest guardians turn to flee */ + && (mon->data != &mons[gu.urole.guardnum])) { alreadyfleeing = (mon->mflee || mon->mfleetim); monflee(mon, rn2(50) + 25, TRUE, !exclaimed); if (exclaimed) { @@ -4075,6 +4076,7 @@ peacefuls_respond(struct monst *mtmp) * perhaps reduce tameness? */ } else { mon->mpeaceful = 0; + mon->mstrategy &= ~STRAT_WAITMASK; adjalign(-1); if (!exclaimed) pline_mon(mon, "%s gets angry!", Monnam(mon)); @@ -4157,7 +4159,7 @@ setmangry(struct monst *mtmp, boolean via_attack) qst_guardians_respond(); /* make other peaceful monsters react */ - if (!gc.context.mon_moving) + if (!svc.context.mon_moving) peacefuls_respond(mtmp); } @@ -4185,7 +4187,7 @@ wakeup(struct monst *mtmp, boolean via_attack) have to lose his disguise */ if (M_AP_TYPE(mtmp) != M_AP_MONSTER) seemimic(mtmp); - } else if (gc.context.forcefight && !gc.context.mon_moving + } else if (svc.context.forcefight && !svc.context.mon_moving && mtmp->mundetected) { mtmp->mundetected = 0; newsym(mtmp->mx, mtmp->my); @@ -4229,11 +4231,11 @@ wake_nearto_core(coordxy x, coordxy y, int distance, boolean petcall) mtmp->msleeping = 0; /* wake indeterminate sleep */ if (!(mtmp->data->geno & G_UNIQ)) mtmp->mstrategy &= ~STRAT_WAITMASK; /* wake 'meditation' */ - if (gc.context.mon_moving || !petcall) + if (svc.context.mon_moving || !petcall) continue; if (mtmp->mtame) { if (!mtmp->isminion) - EDOG(mtmp)->whistletime = gm.moves; + EDOG(mtmp)->whistletime = svm.moves; /* Fix up a pet who is stuck "fleeing" its master */ mon_track_clear(mtmp); } @@ -4513,7 +4515,7 @@ maybe_unhide_at(coordxy x, coordxy y) if (undetected && ((hides_under(mtmp->data) && (!OBJ_AT(x, y) || trapped - || !can_hide_under_obj(gl.level.objects[x][y]))) + || !can_hide_under_obj(svl.level.objects[x][y]))) || (mtmp->data->mlet == S_EEL && !is_pool(x, y)))) (void) hideunder(mtmp); } @@ -4550,7 +4552,7 @@ hideunder(struct monst *mtmp) } } else if (hides_under(mtmp->data) /* hider-underers only hide under objects */ - && (otmp = gl.level.objects[x][y]) != 0 + && (otmp = svl.level.objects[x][y]) != 0 /* most things can be hidden under, but not all */ && can_hide_under_obj(otmp) /* aquatic creatures don't reach here; other swimmers @@ -4664,19 +4666,15 @@ pick_animal(void) } void -decide_to_shapeshift(struct monst *mon, int shiftflags) +decide_to_shapeshift(struct monst *mon) { struct permonst *ptr = 0; int mndx; unsigned was_female = mon->female; - boolean msg = FALSE, dochng = FALSE; - - if ((shiftflags & SHIFT_MSG) - || ((shiftflags & SHIFT_SEENMSG) && sensemon(mon))) - msg = TRUE; + boolean dochng = FALSE; if (!is_vampshifter(mon)) { - /* regular shapeshifter */ + /* regular shapeshifter; 'ptr' is Null */ if (!rn2(6)) dochng = TRUE; } else if (!(mon->mstrategy & STRAT_WAITFORU)) { @@ -4722,11 +4720,14 @@ decide_to_shapeshift(struct monst *mon, int shiftflags) } } if (dochng) { - if (newcham(mon, ptr, msg ? NC_SHOW_MSG : 0) && is_vampshifter(mon)) { - /* for vampshift, override the 10% chance for sex change */ - ptr = mon->data; - if (!is_male(ptr) && !is_female(ptr) && !is_neuter(ptr)) - mon->female = was_female; + if (newcham(mon, ptr, NC_SHOW_MSG)) { + /* for vampshift, override the 10% chance for sex change + (by forcing original gender in case that occurred) */ + if (is_vampshifter(mon)) { + ptr = mon->data; + if (!is_male(ptr) && !is_female(ptr) && !is_neuter(ptr)) + mon->female = was_female; + } } } } @@ -4760,7 +4761,7 @@ pickvampshape(struct monst *mon) /* return to base form if chosen poly target has been genocided or randomly if already in an alternate form (to prevent always switching back and forth between bat and fog) */ - if ((gm.mvitals[mndx].mvflags & G_GENOD) != 0 + if ((svm.mvitals[mndx].mvflags & G_GENOD) != 0 || (mon->data != &mons[mon->cham] && !rn2(4))) return mon->cham; @@ -4772,7 +4773,7 @@ staticfn boolean isspecmon(struct monst *mon) { return (mon->isshk || mon->ispriest || mon->isgd - || mon->m_id == gq.quest_status.leader_m_id); + || mon->m_id == svq.quest_status.leader_m_id); } /* restrict certain special monsters (shopkeepers, aligned priests, @@ -5021,7 +5022,7 @@ accept_newcham_form(struct monst *mon, int mndx) if (mndx == NON_PM) return 0; mdat = &mons[mndx]; - if ((gm.mvitals[mndx].mvflags & G_GENOD) != 0) + if ((svm.mvitals[mndx].mvflags & G_GENOD) != 0) return 0; if (is_placeholder(mdat)) return 0; @@ -5070,10 +5071,11 @@ newcham( { boolean polyspot = ((ncflags & NC_VIA_WAND_OR_SPELL) !=0), /* "The oldmon turns into a newmon!" */ - msg = ((ncflags & NC_SHOW_MSG) != 0); + msg = ((ncflags & NC_SHOW_MSG) != 0), + seenorsensed = canspotmon(mtmp); int hpn, hpd, mndx, tryct; struct permonst *olddata = mtmp->data; - char *p, oldname[BUFSZ], l_oldname[BUFSZ], newname[BUFSZ]; + char *p, oldname[BUFSZ], l_oldname[BUFSZ]; /* Riders are immune to polymorph and green slime (but apparent Rider might actually be a doppelganger) */ @@ -5094,9 +5096,10 @@ newcham( } if (msg) { - /* like Monnam() but never mention saddle */ - Strcpy(oldname, x_monnam(mtmp, ARTICLE_THE, (char *) 0, - SUPPRESS_SADDLE, FALSE)); + Strcpy(oldname, + /* like YMonnam() but never mention saddle */ + x_monnam(mtmp, mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE, + (char *) 0, SUPPRESS_SADDLE, FALSE)); oldname[0] = highc(oldname[0]); } /* we need this one whether msg is true or not */ @@ -5122,7 +5125,7 @@ newcham( } while (--tryct > 0); if (!tryct) return 0; - } else if (gm.mvitals[monsndx(mdat)].mvflags & G_GENOD) + } else if (svm.mvitals[monsndx(mdat)].mvflags & G_GENOD) return 0; /* passed in mdat is genocided */ if (mdat == olddata) @@ -5244,17 +5247,20 @@ newcham( newsym(mtmp->mx, mtmp->my); if (msg) { - Strcpy(newname, noname_monnam(mtmp, ARTICLE_A)); - /* 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); + /* oldname is capitalized and might be an assigned name */ + if (!canspotmon(mtmp)) { /* can't see or sense it now */ + if (seenorsensed) /* could see or sense it before */ + pline_mon(mtmp, "%s disappears!", oldname); (void) usmellmon(mdat); - } 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); + } else if (!seenorsensed) { /* couldn't see/sense before, can now */ + char *mnm = x_monnam(mtmp, mtmp->mtame ? ARTICLE_YOUR : ARTICLE_A, + (char *) 0, 0, FALSE); + + pline_mon(mtmp, "%s appears!", upstart(mnm)); + } else { /* saw/sensed it before, still see/sense it now */ + pline_mon(mtmp, "%s turns into %s!", oldname, + /* "a " even if it has a name assigned */ + noname_monnam(mtmp, ARTICLE_A)); } } @@ -5268,7 +5274,7 @@ newcham( mon_break_armor(mtmp, polyspot); if (!(mtmp->misc_worn_check & W_ARMG)) mselftouch(mtmp, "No longer petrify-resistant, ", - !gc.context.mon_moving); + !svc.context.mon_moving); check_gear_next_turn(mtmp); /* This ought to re-test can_carry() on each item in the inventory @@ -5302,7 +5308,7 @@ newcham( /* old form might not have been affected by Elbereth but perhaps the new form is */ - if (gc.context.mon_moving) { + if (svc.context.mon_moving) { /* give 'mtmp' a new chance to pinpoint hero's location */ if (!u_at(mtmp->mux, mtmp->muy)) set_apparxy(mtmp); @@ -5383,8 +5389,8 @@ dead_species(int m_idx, boolean egg) */ /* assert(ismnum(m_idx)); */ alt_idx = egg ? big_to_little(m_idx) : m_idx; - return (boolean) ((gm.mvitals[m_idx].mvflags & G_GENOD) != 0 - || (gm.mvitals[alt_idx].mvflags & G_GENOD) != 0); + return (boolean) ((svm.mvitals[m_idx].mvflags & G_GENOD) != 0 + || (svm.mvitals[alt_idx].mvflags & G_GENOD) != 0); } /* kill off any eggs of genocided monsters */ @@ -5442,8 +5448,8 @@ kill_genocided_monsters(void) continue; mndx = monsndx(mtmp->data); kill_cham = (ismnum(mtmp->cham) - && (gm.mvitals[mtmp->cham].mvflags & G_GENOD)); - if ((gm.mvitals[mndx].mvflags & G_GENOD) || kill_cham) { + && (svm.mvitals[mtmp->cham].mvflags & G_GENOD)); + if ((svm.mvitals[mndx].mvflags & G_GENOD) || kill_cham) { if (ismnum(mtmp->cham) && !kill_cham) (void) newcham(mtmp, (struct permonst *) 0, NC_SHOW_MSG); else @@ -5456,7 +5462,7 @@ kill_genocided_monsters(void) kill_eggs(gi.invent); kill_eggs(fobj); kill_eggs(gm.migrating_objs); - kill_eggs(gl.level.buriedobjlist); + kill_eggs(svl.level.buriedobjlist); } void diff --git a/src/mondata.c b/src/mondata.c index 58c29f63f..28da3358a 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -81,7 +81,7 @@ poly_when_stoned(struct permonst *ptr) { /* non-stone golems turn into stone golems unless latter is genocided */ return (boolean) (is_golem(ptr) && ptr != &mons[PM_STONE_GOLEM] - && !(gm.mvitals[PM_STONE_GOLEM].mvflags & G_GENOD)); + && !(svm.mvitals[PM_STONE_GOLEM].mvflags & G_GENOD)); /* allow G_EXTINCT */ } diff --git a/src/monmove.c b/src/monmove.c index c461fb46e..a56b14fba 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 monmove.c $NHDT-Date: 1701435190 2023/12/01 12:53:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.229 $ */ +/* NetHack 3.7 monmove.c $NHDT-Date: 1722116054 2024/07/27 21:34:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.255 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -18,9 +18,9 @@ staticfn boolean holds_up_web(coordxy, coordxy); staticfn int count_webbing_walls(coordxy, coordxy); staticfn boolean soko_allow_web(struct monst *); staticfn boolean m_search_items(struct monst *, coordxy *, coordxy *, int *, - int *); + int *) NONNULLPTRS; staticfn int postmov(struct monst *, struct permonst *, coordxy, coordxy, int, - boolean, boolean, boolean, boolean); + unsigned, boolean, boolean, boolean) NONNULLPTRS; staticfn boolean leppie_avoidance(struct monst *); staticfn void leppie_stash(struct monst *); staticfn boolean m_balks_at_approaching(struct monst *); @@ -159,6 +159,15 @@ m_break_boulder(struct monst *mtmp, coordxy x, coordxy y) set_msg_xy(x, y); pline_The("boulder falls apart."); } + + /* boulders pushed onto shop's boundary or free spot are cases where + an item not in hero's inventory can have its unpaid flag set; + if the boulder isn't already on the bill, don't charge for it */ + if (otmp->unpaid) { + /* remove original from bill + add cloned copy to used-up bill */ + bill_dummy_object(otmp); + } + /* fracturing keeps otmp, changing its otyp from BOULDER to ROCK */ fracture_rock(otmp); } } @@ -184,8 +193,8 @@ watch_on_duty(struct monst *mtmp) } } else if (is_digging()) { /* chewing, wand/spell of digging are checked elsewhere */ - watch_dig(mtmp, gc.context.digging.pos.x, gc.context.digging.pos.y, - FALSE); + watch_dig(mtmp, svc.context.digging.pos.x, + svc.context.digging.pos.y, FALSE); } } } @@ -287,7 +296,7 @@ void mon_regen(struct monst *mon, boolean digest_meal) { if (mon->mhp < mon->mhpmax - && (gm.moves % 20 == 0 || regenerates(mon->data))) + && (svm.moves % 20 == 0 || regenerates(mon->data))) mon->mhp++; if (mon->mspec_used) mon->mspec_used--; @@ -357,7 +366,7 @@ find_pmmonst(int pm) { struct monst *mtmp = 0; - if ((gm.mvitals[pm].mvflags & G_GENOD) == 0) + if ((svm.mvitals[pm].mvflags & G_GENOD) == 0) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; @@ -445,7 +454,8 @@ monflee( sleep and temporary paralysis, so both conditions receive the same alternate message */ if (!mtmp->mcanmove || !mtmp->data->mmove) { - pline_mon(mtmp, "%s seems to flinch.", Adjmonnam(mtmp, "immobile")); + pline_mon(mtmp, "%s seems to flinch.", + Adjmonnam(mtmp, "immobile")); } else if (flees_light(mtmp)) { if (Unaware) { /* tell the player even if the hero is unconscious */ @@ -598,19 +608,20 @@ mind_blast(struct monst *mtmp) } } -/* called every turn for each living monster on the map, - and the hero */ +/* called every turn for each living monster on the map, and the hero; + caller makes sure that we're not called for DEADMONSTER() */ void m_everyturn_effect(struct monst *mtmp) { boolean is_u = (mtmp == &gy.youmonst) ? TRUE : FALSE; coordxy x = is_u ? u.ux : mtmp->mx, - y = is_u ? u.uy : mtmp->my; + y = is_u ? u.uy : mtmp->my; if (mtmp->data == &mons[PM_FOG_CLOUD]) { - NhRegion *reg = visible_region_at(x, y); - - if (!reg) + /* don't leave a vapor cloud if some other gas cloud is already + present, or when flowing under closed doors so that visibility + changes aren't mixed with messages about doing such */ + if (!closed_door(x, y) && !visible_region_at(x, y)) create_gas_cloud(x, y, 1, 0); /* harmless vapor */ } } @@ -626,7 +637,7 @@ m_postmove_effect(struct monst *mtmp) { boolean is_u = (mtmp == &gy.youmonst) ? TRUE : FALSE; coordxy x = is_u ? u.ux0 : mtmp->mx, - y = is_u ? u.uy0 : mtmp->my; + y = is_u ? u.uy0 : mtmp->my; /* Hezrous create clouds of stench. This does not cost a move. */ if (mtmp->data == &mons[PM_HEZROU]) /* stench */ @@ -999,7 +1010,7 @@ mon_would_consume_item(struct monst *mtmp, struct obj *otmp) if (mtmp->mtame && has_edog(mtmp) /* has_edog(): not guardian angel */ && (ftyp = dogfood(mtmp, otmp)) < MANFOOD - && (ftyp < ACCFOOD || EDOG(mtmp)->hungrytime <= gm.moves)) + && (ftyp < ACCFOOD || EDOG(mtmp)->hungrytime <= svm.moves)) return TRUE; return FALSE; @@ -1240,6 +1251,21 @@ m_avoid_kicked_loc(struct monst *mtmp, coordxy nx, coordxy ny) return FALSE; } +/* monster avoids a location nx, ny, if we're in sokoban, and + there's a boulder between the location and hero */ +boolean +m_avoid_soko_push_loc(struct monst *mtmp, coordxy nx, coordxy ny) +{ + if (Sokoban + && (mtmp->mpeaceful || mtmp->mtame) + && !mtmp->mconf && !mtmp->mstun + && !Conflict + && (dist2(nx, ny, u.ux, u.uy) == 4) + && sobj_at(BOULDER, nx + sgn(u.ux - nx), ny + sgn(u.uy - ny))) + return TRUE; + return FALSE; +} + /* max distmin() distance for monster to look for items */ #define SQSRCHRADIUS 5 @@ -1323,7 +1349,7 @@ m_search_items( costly = costly_spot(xx, yy); /* look through the items on this location */ - for (otmp = gl.level.objects[xx][yy]; + for (otmp = svl.level.objects[xx][yy]; otmp; otmp = otmp->nexthere) { /* monsters may pick rocks up, but won't go out of their way to grab them; this might hamper sling wielders, but it cuts @@ -1356,7 +1382,7 @@ m_search_items( } } -finish_search: + finish_search: if (minr < SQSRCHRADIUS && *appr == -1) { if (distmin(omx, omy, mtmp->mux, mtmp->muy) <= 3) { *ggx = mtmp->mux; @@ -1375,7 +1401,7 @@ postmov( struct permonst *ptr, coordxy omx, coordxy omy, int mmoved, - boolean sawmon, + unsigned seenflgs, boolean can_tunnel, boolean can_unlock, boolean can_open) @@ -1404,15 +1430,18 @@ postmov( && IS_DOOR(levl[nix][niy].typ) && ((levl[nix][niy].doormask & (D_LOCKED | D_CLOSED)) != 0) && can_fog(mtmp)) { - if (sawmon) { + /* note: remove_monster()+place_monster is not right for + long worms but they won't reach here */ + if (seenflgs) { remove_monster(nix, niy); place_monster(mtmp, omx, omy); newsym(nix, niy), newsym(omx, omy); } - if (vamp_shift(mtmp, &mons[PM_FOG_CLOUD], sawmon)) { + if (vamp_shift(mtmp, &mons[PM_FOG_CLOUD], + ((seenflgs & 1) != 0) ? TRUE : FALSE)) { ptr = mtmp->data; /* update cached value */ } - if (sawmon) { + if (seenflgs) { remove_monster(omx, omy); place_monster(mtmp, nix, niy); newsym(omx, omy), newsym(nix, niy); @@ -1460,7 +1489,7 @@ postmov( if ((here->doormask & (D_LOCKED | D_CLOSED)) != 0 && amorphous(ptr)) { if (flags.verbose && canseemon(mtmp)) - pline_mon(mtmp, "%s %s under the door.", Monnam(mtmp), + pline_mon(mtmp, "%s %s under the door.", YMonnam(mtmp), (ptr == &mons[PM_FOG_CLOUD] || ptr->mlet == S_LIGHT) ? "flows" : "oozes"); } else if (here->doormask & D_LOCKED && can_unlock) { @@ -1518,7 +1547,8 @@ postmov( Soundeffect(se_door_crash_open, 50); if (flags.verbose) { if (canseeit && canspotmon(mtmp)) { - pline_mon(mtmp, "%s smashes down a door.", Monnam(mtmp)); + pline_mon(mtmp, "%s smashes down a door.", + Monnam(mtmp)); } else if (canseeit) { You_see("a door crash open."); } else if (!Deaf) { @@ -1540,7 +1570,8 @@ postmov( && (dmgtype(ptr, AD_RUST) || dmgtype(ptr, AD_CORR) || metallivorous(ptr))) { if (canseemon(mtmp)) - pline_mon(mtmp, "%s eats through the iron bars.", Monnam(mtmp)); + pline_mon(mtmp, "%s eats through the iron bars.", + Monnam(mtmp)); dissolve_bars(mtmp->mx, mtmp->my); return MMOVE_DONE; } else if (flags.verbose && canseemon(mtmp)) @@ -1632,7 +1663,7 @@ m_move(struct monst *mtmp, int after) boolean getitems = FALSE; boolean avoid = FALSE; boolean better_with_displacing = FALSE; - boolean sawmon = canspotmon(mtmp); /* before it moved */ + unsigned seenflgs; struct permonst *ptr; int chi, mmoved = MMOVE_NOTHING; /* not strictly nec.: chi >= 0 will do */ long info[9]; @@ -1658,9 +1689,13 @@ m_move(struct monst *mtmp, int after) return MMOVE_DONE; /* still eating */ } if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my) - && can_hide_under_obj(gl.level.objects[mtmp->mx][mtmp->my]) && rn2(10)) + && can_hide_under_obj(svl.level.objects[mtmp->mx][mtmp->my]) + && rn2(10)) return MMOVE_NOTHING; /* do not leave hiding place */ + /* set up pre-move visibility flags */ + seenflgs = (canseemon(mtmp) ? 1 : 0) | (canspotmon(mtmp) ? 2 : 0); + /* Where does 'mtmp' think you are? Not necessary if m_move() called from this file, but needed for other calls of m_move(). */ set_apparxy(mtmp); /* set mtmp->mux, mtmp->muy */ @@ -1676,7 +1711,7 @@ m_move(struct monst *mtmp, int after) /* my dog gets special treatment */ if (mtmp->mtame) { return postmov(mtmp, ptr, omx, omy, dog_move(mtmp, after), - sawmon, can_tunnel, can_unlock, can_open); + seenflgs, can_tunnel, can_unlock, can_open); } /* and the acquisitive monsters get special treatment */ @@ -1705,7 +1740,7 @@ m_move(struct monst *mtmp, int after) mmoved = MMOVE_NOTHING; } return postmov(mtmp, ptr, omx, omy, mmoved, - sawmon, can_tunnel, can_unlock, can_open); + seenflgs, can_tunnel, can_unlock, can_open); } /* likewise for shopkeeper, guard, or priest */ @@ -1727,7 +1762,7 @@ m_move(struct monst *mtmp, int after) case 1: return postmov(mtmp, ptr, omx, omy, (xm != 1) ? MMOVE_NOTHING : MMOVE_MOVED, - sawmon, can_tunnel, can_unlock, can_open); + seenflgs, can_tunnel, can_unlock, can_open); } } @@ -1750,7 +1785,7 @@ m_move(struct monst *mtmp, int after) else mnexto(mtmp, RLOC_MSG); return postmov(mtmp, ptr, omx, omy, MMOVE_MOVED, - sawmon, can_tunnel, can_unlock, can_open); + seenflgs, can_tunnel, can_unlock, can_open); } not_special: if (u.uswallow && !mtmp->mflee && u.ustuck != mtmp) @@ -1797,7 +1832,8 @@ m_move(struct monst *mtmp, int after) if ((!mtmp->mpeaceful || !rn2(10)) && (!Is_rogue_level(&u.uz))) { boolean in_line = (lined_up(mtmp) && (distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) - <= (throws_rocks(gy.youmonst.data) ? 20 : ACURRSTR / 2 + 1))); + <= (throws_rocks(gy.youmonst.data) ? 20 + : (ACURRSTR / 2 + 1)))); if (appr != 1 || !in_line) { /* Monsters in combat won't pick stuff up, avoiding the @@ -1810,7 +1846,7 @@ m_move(struct monst *mtmp, int after) if (getitems && m_search_items(mtmp, &ggx, &ggy, &mmoved, &appr)) return postmov(mtmp, ptr, omx, omy, mmoved, - sawmon, can_tunnel, can_unlock, can_open); + seenflgs, can_tunnel, can_unlock, can_open); /* don't tunnel if hostile and close enough to prefer a weapon */ if (can_tunnel && needspick(ptr) @@ -1839,7 +1875,7 @@ m_move(struct monst *mtmp, int after) chi = -1; nidist = dist2(nix, niy, ggx, ggy); /* allow monsters be shortsighted on some levels for balance */ - if (!mtmp->mpeaceful && gl.level.flags.shortsighted + if (!mtmp->mpeaceful && svl.level.flags.shortsighted && nidist > (couldsee(nix, niy) ? 144 : 36) && appr == 1) appr = 0; if (is_unicorn(ptr) && noteleport_level(mtmp)) { @@ -1973,7 +2009,7 @@ m_move(struct monst *mtmp, int after) worm_nomove(mtmp); } return postmov(mtmp, ptr, omx, omy, mmoved, - sawmon, can_tunnel, can_unlock, can_open); + seenflgs, can_tunnel, can_unlock, can_open); } /* The part of m_move that deals with a monster attacking another monster (and @@ -2266,12 +2302,15 @@ can_ooze(struct monst *mtmp) boolean can_fog(struct monst *mtmp) { - if (!(gm.mvitals[PM_FOG_CLOUD].mvflags & G_GENOD) && is_vampshifter(mtmp) + if (!(svm.mvitals[PM_FOG_CLOUD].mvflags & G_GENOD) && is_vampshifter(mtmp) && !Protection_from_shape_changers && !stuff_prevents_passage(mtmp)) return TRUE; return FALSE; } +/* this is called when a vampire turns into a fog cloud in order to move + under a closed door; if it was sensed via telepathy or seen via + infravision, its new fog cloud shape will disappear */ staticfn int vamp_shift( struct monst *mon, @@ -2279,34 +2318,16 @@ vamp_shift( boolean domsg) { int reslt = 0; - char oldmtype[BUFSZ]; - boolean sawmon = canseemon(mon); /* before shape change */ - - /* remember current monster type before shapechange */ - Strcpy(oldmtype, domsg ? noname_monnam(mon, ARTICLE_THE) : ""); if (mon->data == ptr) { /* already right shape */ reslt = 1; - domsg = FALSE; } else if (is_vampshifter(mon)) { - reslt = newcham(mon, ptr, NO_NC_FLAGS); - } - - if (reslt && domsg) { - /* might have seen vampire/bat/wolf with infravision then be - unable to see the same creature when it turns into a fog cloud */ - if (canspotmon(mon)) - You("%s %s where %s was.", - !canseemon(mon) ? "now detect" : "observe", - noname_monnam(mon, ARTICLE_A), oldmtype); - else - You("can no longer %s %s.", sawmon ? "see" : "sense", oldmtype); - /* this message is given when it turns into a fog cloud - in order to move under a closed door */ + reslt = newcham(mon, ptr, domsg ? NC_SHOW_MSG : NO_NC_FLAGS); + /* shape-change message is given when vampshifter turns into a + fog cloud in order to move under a closed door */ display_nhwindow(WIN_MESSAGE, FALSE); } - return reslt; } diff --git a/src/mthrowu.c b/src/mthrowu.c index adf4cfb99..b91d44435 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -28,21 +28,21 @@ static NEARDATA const char *breathwep[] = { /* hallucinatory ray types */ static const char *const hallublasts[] = { "asteroids", "beads", "bubbles", "butterflies", "champagne", "chaos", - "coins", "cotton candy", "crumbs", "dark matter", "darkness", "dust specks", - "emoticons", "emotions", "entropy", "flowers", "foam", "fog", "gamma rays", - "gelatin", "gemstones", "ghosts", "glass shards", "glitter", "good vibes", - "gravel", "gravity", "gravy", "grawlixes", "holy light", "hornets", - "hot air", "hyphens", "hypnosis", "infrared", "insects", "laser beams", - "leaves", "lightening", "logic gates", "magma", "marbles", "mathematics", - "megabytes", "metal shavings", "metapatterns", "meteors", "mist", "mud", - "music", "nanites", "needles", "noise", "nostalgia", "oil", "paint", - "photons", "pixels", "plasma", "polarity", "powder", "powerups", - "prismatic light", "pure logic", "purple", "radio waves", "rainbows", - "rock music", "rocket fuel", "rope", "sadness", "salt", "sand", "scrolls", - "sludge", "smileys", "snowflakes", "sparkles", "specularity", "spores", - "stars", "steam", "tetrahedrons", "text", "the past", "tornadoes", - "toxic waste", "ultraviolet light", "viruses", "water", "waveforms", "wind", - "X-rays", "zorkmids" + "coins", "cotton candy", "crumbs", "dark matter", "darkness", "data", + "dust specks", "emoticons", "emotions", "entropy", "flowers", "foam", + "fog", "gamma rays", "gelatin", "gemstones", "ghosts", "glass shards", + "glitter", "good vibes", "gravel", "gravity", "gravy", "grawlixes", + "holy light", "hornets", "hot air", "hyphens", "hypnosis", "infrared", + "insects", "jargon", "laser beams", "leaves", "lightening", "logic gates", + "magma", "marbles", "mathematics", "megabytes", "metal shavings", + "metapatterns", "meteors", "mist", "mud", "music", "nanites", "needles", + "noise", "nostalgia", "oil", "paint", "photons", "pixels", "plasma", + "polarity", "powder", "powerups", "prismatic light", "pure logic", + "purple", "radio waves", "rainbows", "rock music", "rocket fuel", "rope", + "sadness", "salt", "sand", "scrolls", "sludge", "smileys", "snowflakes", + "sparkles", "specularity", "spores", "stars", "steam", "tetrahedrons", + "text", "the past", "tornadoes", "toxic waste", "ultraviolet light", + "viruses", "water", "waveforms", "wind", "X-rays", "zorkmids" }; /* Return a random hallucinatory blast. */ @@ -121,8 +121,8 @@ thitu( if (is_acid && Acid_resistance) { pline("It doesn't seem to hurt you."); monstseesu(M_SEEN_ACID); - } else if (obj && stone_missile(obj) && passes_rocks(gy.youmonst.data)) { - + } else if (obj && stone_missile(obj) + && passes_rocks(gy.youmonst.data)) { /* use 'named' as an approximation for "hitting from above"; we avoid "passes through you" for horizontal flight path because missile stops and that wording would suggest that @@ -319,8 +319,8 @@ ohitmon( struct obj *otmp, /* missile; might be destroyed by drop_throw */ int range, /* how much farther will object travel if it misses; * use -1 to signify to keep going even after hit, - * unless it's gone (used for rolling_boulder_traps) */ - boolean verbose)/* give message(s) even when you can't see what happened */ + * unless it's gone (for rolling_boulder_traps) */ + boolean verbose)/* give messages even when you can't see what happened */ { int damage, tmp; boolean vis, ismimic, objgone; @@ -453,7 +453,7 @@ ohitmon( (nonliving(mtmp->data) || is_vampshifter(mtmp) || !canspotmon(mtmp)) ? "destroyed" : "killed"); /* don't blame hero for unknown rolling boulder trap */ - if (!gc.context.mon_moving && (otmp->otyp != BOULDER + if (!svc.context.mon_moving && (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped)) xkilled(mtmp, XKILL_NOMSG); else @@ -484,7 +484,7 @@ ohitmon( mtmp->mblinded = tmp; } - if (!DEADMONSTER(mtmp) && !gc.context.mon_moving) + if (!DEADMONSTER(mtmp) && !svc.context.mon_moving) setmangry(mtmp, TRUE); objgone = drop_throw(otmp, 1, gb.bhitpos.x, gb.bhitpos.y); diff --git a/src/muse.c b/src/muse.c index d26cb4c74..2d4d02955 100644 --- a/src/muse.c +++ b/src/muse.c @@ -68,8 +68,8 @@ precheck(struct monst *mon, struct obj *obj) struct monst *mtmp; if (objdescr_is(obj, "milky")) { - if (!(gm.mvitals[PM_GHOST].mvflags & G_GONE) - && !rn2(POTION_OCCUPANT_CHANCE(gm.mvitals[PM_GHOST].born))) { + if (!(svm.mvitals[PM_GHOST].mvflags & G_GONE) + && !rn2(POTION_OCCUPANT_CHANCE(svm.mvitals[PM_GHOST].born))) { if (!enexto(&cc, mon->mx, mon->my, &mons[PM_GHOST])) return 0; mquaffmsg(mon, obj); @@ -85,7 +85,8 @@ precheck(struct monst *mon, struct obj *obj) mon_nam(mon), Hallucination ? rndmonnam(NULL) : (const char *) "ghost"); - pline("%s is frightened to death, and unable to move.", + pline("%s is frightened to death," + " and unable to move.", Monnam(mon)); } paralyze_monst(mon, 3); @@ -94,8 +95,8 @@ precheck(struct monst *mon, struct obj *obj) } } if (objdescr_is(obj, "smoky") - && !(gm.mvitals[PM_DJINNI].mvflags & G_GONE) - && !rn2(POTION_OCCUPANT_CHANCE(gm.mvitals[PM_DJINNI].born))) { + && !(svm.mvitals[PM_DJINNI].mvflags & G_GONE) + && !rn2(POTION_OCCUPANT_CHANCE(svm.mvitals[PM_DJINNI].born))) { if (!enexto(&cc, mon->mx, mon->my, &mons[PM_DJINNI])) return 0; mquaffmsg(mon, obj); @@ -598,7 +599,7 @@ find_defensive(struct monst *mtmp, boolean tryescape) or some other monster is there */ if (u_at(xx, yy) || (xx != x && yy != y && !diag_ok) - || (gl.level.monsters[xx][yy] && !(xx == x && yy == y))) + || (svl.level.monsters[xx][yy] && !(xx == x && yy == y))) continue; /* skip if there's no trap or can't/won't move onto trap */ if ((t = t_at(xx, yy)) == 0 @@ -771,7 +772,7 @@ staticfn int mon_escape(struct monst *mtmp, boolean vismon) { if (mon_has_special(mtmp) - || (mtmp->iswiz && gc.context.no_of_wizards < 2)) + || (mtmp->iswiz && svc.context.no_of_wizards < 2)) return 0; if (vismon) pline("%s escapes the dungeon!", Monnam(mtmp)); @@ -1611,7 +1612,7 @@ mbhitm(struct monst *mtmp, struct obj *otmp) /* context.bypasses=True: if resist() happens to be fatal, make_corpse() will set obj->bypass on the new corpse so that mbhito() will skip it instead of reviving it */ - gc.context.bypasses = TRUE; /* for make_corpse() */ + svc.context.bypasses = TRUE; /* for make_corpse() */ (void) resist(mtmp, WAND_CLASS, rnd(8), NOTELL); } if (wake) { @@ -1645,7 +1646,7 @@ fhito_loc(struct obj *obj, if (!fhito || !OBJ_AT(tx, ty)) return FALSE; - for (otmp = gl.level.objects[tx][ty]; otmp; otmp = next_obj) { + for (otmp = svl.level.objects[tx][ty]; otmp; otmp = next_obj) { next_obj = otmp->nexthere; if (otmp->where != OBJ_FLOOR || otmp->ox != tx || otmp->oy != ty) @@ -2038,7 +2039,7 @@ find_misc(struct monst *mtmp) for (yy = y - 1; yy <= y + 1; yy++) if (isok(xx, yy) && !u_at(xx, yy) && (diag_ok || xx == x || yy == y) - && ((xx == x && yy == y) || !gl.level.monsters[xx][yy])) + && ((xx == x && yy == y) || !svl.level.monsters[xx][yy])) if ((t = t_at(xx, yy)) != 0 && (ignore_boulders || !sobj_at(BOULDER, xx, yy)) && !onscary(xx, yy, mtmp)) { @@ -2848,14 +2849,14 @@ mon_consume_unstone( if (mon->mtame && !mon->isminion && nutrit > 0) { struct edog *edog = EDOG(mon); - if (edog->hungrytime < gm.moves) - edog->hungrytime = gm.moves; + if (edog->hungrytime < svm.moves) + edog->hungrytime = svm.moves; edog->hungrytime += nutrit; mon->mconf = 0; } /* use up monster's next move */ mon->movement -= NORMAL_SPEED; - mon->mlstmv = gm.moves; + mon->mlstmv = svm.moves; } /* decide whether obj can cure petrification; also used when picking up */ @@ -3114,7 +3115,7 @@ muse_unslime( } /* use up monster's next move */ mon->movement -= NORMAL_SPEED; - mon->mlstmv = gm.moves; + mon->mlstmv = svm.moves; return res; } @@ -3157,7 +3158,8 @@ green_mon(struct monst *mon) /* approximation */ if (strstri(ptr->pmnames[NEUTRAL], "green") || (ptr->pmnames[MALE] && strstri(ptr->pmnames[MALE], "green")) - || (ptr->pmnames[FEMALE] && strstri(ptr->pmnames[FEMALE], "green"))) + || (ptr->pmnames[FEMALE] + && strstri(ptr->pmnames[FEMALE], "green"))) return TRUE; switch (monsndx(ptr)) { case PM_FOREST_CENTAUR: diff --git a/src/music.c b/src/music.c index 740b3dc77..d4ebd46e8 100644 --- a/src/music.c +++ b/src/music.c @@ -714,23 +714,23 @@ staticfn char * improvised_notes(boolean *same_as_last_time) { static const char notes[7] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; - /* target buffer has to be in gc.context, otherwise saving game + /* target buffer has to be in svc.context, otherwise saving game * between improvised recitals would not be able to maintain * the same_as_last_time context. */ /* You can change your tune, usually */ - if (!(Unchanging && gc.context.jingle[0] != '\0')) { - int i, notecount = rnd(SIZE(gc.context.jingle) - 1); /* 1 - 5 */ + if (!(Unchanging && svc.context.jingle[0] != '\0')) { + int i, notecount = rnd(SIZE(svc.context.jingle) - 1); /* 1 - 5 */ for (i = 0; i < notecount; ++i) { - gc.context.jingle[i] = ROLL_FROM(notes); + svc.context.jingle[i] = ROLL_FROM(notes); } - gc.context.jingle[notecount] = '\0'; + svc.context.jingle[notecount] = '\0'; *same_as_last_time = FALSE; } else { *same_as_last_time = TRUE; } - return gc.context.jingle; + return svc.context.jingle; } /* @@ -769,7 +769,7 @@ do_play_instrument(struct obj *instr) if (c == 'q') { goto nevermind; } else if (c == 'y') { - Strcpy(buf, gt.tune); + Strcpy(buf, svt.tune); } else { getlin("What tune are you playing? [5 notes, A-G]", buf); (void) mungspaces(buf); @@ -794,7 +794,7 @@ do_play_instrument(struct obj *instr) */ if (Is_stronghold(&u.uz)) { exercise(A_WIS, TRUE); /* just for trying */ - if (!strcmp(buf, gt.tune)) { + if (!strcmp(buf, svt.tune)) { /* Search for the drawbridge */ for (y = u.uy - 1; y <= u.uy + 1; y++) for (x = u.ux - 1; x <= u.ux + 1; x++) { @@ -834,13 +834,13 @@ do_play_instrument(struct obj *instr) for (x = 0; x < (int) strlen(buf); x++) if (x < 5) { - if (buf[x] == gt.tune[x]) { + if (buf[x] == svt.tune[x]) { gears++; matched[x] = TRUE; } else { for (y = 0; y < 5; y++) - if (!matched[y] && buf[x] == gt.tune[y] - && buf[y] != gt.tune[y]) { + if (!matched[y] && buf[x] == svt.tune[y] + && buf[y] != svt.tune[y]) { tumblers++; matched[y] = TRUE; break; diff --git a/src/nhlobj.c b/src/nhlobj.c index 411219f0a..ca2f74e17 100644 --- a/src/nhlobj.c +++ b/src/nhlobj.c @@ -72,7 +72,8 @@ l_obj_gc(lua_State *L) staticfn struct _lua_obj * l_obj_push(lua_State *L, struct obj *otmp) { - struct _lua_obj *lo = (struct _lua_obj *) lua_newuserdata(L, sizeof(struct _lua_obj)); + struct _lua_obj *lo + = (struct _lua_obj *) lua_newuserdata(L, sizeof (struct _lua_obj)); luaL_getmetatable(L, "obj"); lua_setmetatable(L, -2); @@ -379,7 +380,7 @@ l_obj_at(lua_State *L) cvt_to_abscoord(&x, &y); lua_pop(L, 2); - (void) l_obj_push(L, gl.level.objects[x][y]); + (void) l_obj_push(L, svl.level.objects[x][y]); return 1; } else nhl_error(L, "l_obj_at: Wrong args"); diff --git a/src/nhlsel.c b/src/nhlsel.c index 544df9d4b..2d0f92b4c 100644 --- a/src/nhlsel.c +++ b/src/nhlsel.c @@ -79,7 +79,8 @@ l_selection_gc(lua_State *L) staticfn struct selectionvar * l_selection_to(lua_State *L, int index) { - struct selectionvar *sel = (struct selectionvar *) lua_touserdata(L, index); + struct selectionvar *sel + = (struct selectionvar *) lua_touserdata(L, index); if (!sel) nhl_error(L, "Selection error"); @@ -92,8 +93,8 @@ staticfn struct selectionvar * l_selection_push_new(lua_State *L) { struct selectionvar *tmp = selection_new(); - struct selectionvar - *sel = (struct selectionvar *) lua_newuserdata(L, sizeof(struct selectionvar)); + struct selectionvar *sel + = (struct selectionvar *) lua_newuserdata(L, sizeof (struct selectionvar)); luaL_getmetatable(L, "selection"); lua_setmetatable(L, -2); @@ -109,8 +110,8 @@ l_selection_push_new(lua_State *L) void l_selection_push_copy(lua_State *L, struct selectionvar *tmp) { - struct selectionvar - *sel = (struct selectionvar *) lua_newuserdata(L, sizeof(struct selectionvar)); + struct selectionvar *sel + = (struct selectionvar *) lua_newuserdata(L, sizeof (struct selectionvar)); luaL_getmetatable(L, "selection"); lua_setmetatable(L, -2); @@ -152,7 +153,7 @@ DISABLE_WARNING_UNREACHABLE_CODE /* local sel = selection.set(); */ /* local sel = sel:set(); */ /* local sel = selection.set(sel); */ -/* TODO: allow setting multiple coordinates at once: set({x,y}, {x,y}, ...); */ +/* TODO: allow setting multiple coords at once: set({x1,y1},{x2,y2},...); */ staticfn int l_selection_setpoint(lua_State *L) { @@ -240,7 +241,8 @@ l_selection_getpoint(lua_State *L) crd = SP_COORD_PACK_RANDOM(0); else crd = SP_COORD_PACK(x,y); - get_location_coord(&x, &y, ANY_LOC, gc.coder ? gc.coder->croom : NULL, crd); + get_location_coord(&x, &y, ANY_LOC, + gc.coder ? gc.coder->croom : NULL, crd); val = selection_getpoint(x, y, sel); lua_settop(L, 0); @@ -277,7 +279,7 @@ l_selection_not(lua_State *L) staticfn int l_selection_and(lua_State *L) { - int x,y; + int x, y; struct selectionvar *sela = l_selection_check(L, 1); struct selectionvar *selb = l_selection_check(L, 2); struct selectionvar *selr = l_selection_push_new(L); @@ -287,7 +289,9 @@ l_selection_and(lua_State *L) for (x = rect.lx; x <= rect.hx; x++) for (y = rect.ly; y <= rect.hy; y++) { - int val = selection_getpoint(x, y, sela) & selection_getpoint(x, y, selb); + int val = (selection_getpoint(x, y, sela) + & selection_getpoint(x, y, selb)); + selection_setpoint(x, y, selr, val); } @@ -310,7 +314,9 @@ l_selection_or(lua_State *L) for (x = rect.lx; x <= rect.hx; x++) for (y = rect.ly; y <= rect.hy; y++) { - int val = selection_getpoint(x, y, sela) | selection_getpoint(x, y, selb); + int val = (selection_getpoint(x, y, sela) + | selection_getpoint(x, y, selb)); + selection_setpoint(x, y, selr, val); } selr->bounds = rect; @@ -334,11 +340,13 @@ l_selection_xor(lua_State *L) for (x = rect.lx; x <= rect.hx; x++) for (y = rect.ly; y <= rect.hy; y++) { - int val = selection_getpoint(x, y, sela) ^ selection_getpoint(x, y, selb); + int val = (selection_getpoint(x, y, sela) + ^ selection_getpoint(x, y, selb)); + selection_setpoint(x, y, selr, val); } - /* this may have created a smaller or irregular selection with bounds_dirty - * set to true - update its boundaries */ + /* this may have created a smaller or irregular selection with + * bounds_dirty set to true - update its boundaries */ selection_recalc_bounds(selr); lua_remove(L, 1); @@ -366,8 +374,8 @@ l_selection_sub(lua_State *L) int val = (a_pt ^ b_pt) & a_pt; selection_setpoint(x, y, selr, val); } - /* this may have created a smaller or irregular selection with bounds_dirty - * set to true - update its boundaries */ + /* this may have created a smaller or irregular selection with + * bounds_dirty set to true - update its boundaries */ selection_recalc_bounds(selr); lua_remove(L, 1); @@ -429,7 +437,7 @@ l_selection_room(lua_State *L) if (argc == 1) { int i = luaL_checkinteger(L, -1); - croom = (i >= 0 && i < gn.nroom) ? &gr.rooms[i] : NULL; + croom = (i >= 0 && i < svn.nroom) ? &svr.rooms[i] : NULL; } sel = selection_from_mkroom(croom); @@ -506,8 +514,10 @@ l_selection_line(lua_State *L) nhl_error(L, "selection.line: illegal arguments"); } - get_location_coord(&x1, &y1, ANY_LOC, gc.coder ? gc.coder->croom : NULL, SP_COORD_PACK(x1,y1)); - get_location_coord(&x2, &y2, ANY_LOC, gc.coder ? gc.coder->croom : NULL, SP_COORD_PACK(x2,y2)); + get_location_coord(&x1, &y1, ANY_LOC, gc.coder ? gc.coder->croom : NULL, + SP_COORD_PACK(x1, y1)); + get_location_coord(&x2, &y2, ANY_LOC, gc.coder ? gc.coder->croom : NULL, + SP_COORD_PACK(x2, y2)); (void) l_selection_clone(L); sel = l_selection_check(L, 2); @@ -603,10 +613,10 @@ l_selection_randline(lua_State *L) (void) l_selection_check(L, 1); } - get_location_coord(&x1, &y1, ANY_LOC, - gc.coder ? gc.coder->croom : NULL, SP_COORD_PACK(x1, y1)); - get_location_coord(&x2, &y2, ANY_LOC, - gc.coder ? gc.coder->croom : NULL, SP_COORD_PACK(x2, y2)); + get_location_coord(&x1, &y1, ANY_LOC, gc.coder ? gc.coder->croom : NULL, + SP_COORD_PACK(x1, y1)); + get_location_coord(&x2, &y2, ANY_LOC, gc.coder ? gc.coder->croom : NULL, + SP_COORD_PACK(x2, y2)); (void) l_selection_clone(L); sel = l_selection_check(L, 2); @@ -619,10 +629,13 @@ l_selection_randline(lua_State *L) staticfn int l_selection_grow(lua_State *L) { + const char *const growdirs[] = { + "all", "random", "north", "west", "east", "south", NULL + }; + const int growdirs2i[] = { + W_ANY, W_RANDOM, W_NORTH, W_WEST, W_EAST, W_SOUTH, 0 + }; int argc = lua_gettop(L); - const char *const growdirs[] = { "all", "random", "north", "west", "east", "south", NULL }; - const int growdirs2i[] = { W_ANY, W_RANDOM, W_NORTH, W_WEST, W_EAST, W_SOUTH, 0 }; - struct selectionvar *sel = l_selection_check(L, 1); int dir = growdirs2i[luaL_checkoption(L, 2, "all", growdirs)]; @@ -723,8 +736,8 @@ l_selection_flood(lua_State *L) /*NOTREACHED*/ } - get_location_coord(&x, &y, ANY_LOC, - gc.coder ? gc.coder->croom : NULL, SP_COORD_PACK(x, y)); + get_location_coord(&x, &y, ANY_LOC, gc.coder ? gc.coder->croom : NULL, + SP_COORD_PACK(x, y)); if (isok(x, y)) { set_floodfillchk_match_under(levl[x][y].typ); @@ -773,8 +786,8 @@ l_selection_circle(lua_State *L) /*NOTREACHED*/ } - get_location_coord(&x, &y, ANY_LOC, - gc.coder ? gc.coder->croom : NULL, SP_COORD_PACK(x, y)); + get_location_coord(&x, &y, ANY_LOC, gc.coder ? gc.coder->croom : NULL, + SP_COORD_PACK(x, y)); selection_do_ellipse(sel, x, y, r, r, !filled); @@ -824,8 +837,8 @@ l_selection_ellipse(lua_State *L) /*NOTREACHED*/ } - get_location_coord(&x, &y, ANY_LOC, - gc.coder ? gc.coder->croom : NULL, SP_COORD_PACK(x, y)); + get_location_coord(&x, &y, ANY_LOC, gc.coder ? gc.coder->croom : NULL, + SP_COORD_PACK(x, y)); selection_do_ellipse(sel, x, y, r1, r2, !filled); @@ -847,8 +860,8 @@ l_selection_gradient(lua_State *L) * if they are set, the gradient is centered on a (x,y) to (x2,y2) line */ coordxy x = 0, y = 0, x2 = -1, y2 = -1; /* points are always added within mindist of the center; the chance for a - * point between mindist and maxdist to be added to the selection starts at - * 100% at mindist and decreases linearly to 0% at maxdist */ + * point between mindist and maxdist to be added to the selection starts + * at 100% at mindist and decreases linearly to 0% at maxdist */ coordxy mindist = 0, maxdist = 0; long type = 0; static const char *const gradtypes[] = { @@ -867,8 +880,8 @@ l_selection_gradient(lua_State *L) y2 = (coordxy) get_table_int_opt(L, "y2", -1); cvt_to_abscoord(&x, &y); cvt_to_abscoord(&x2, &y2); - /* maxdist is required because there's no obvious default value for it, - * whereas mindist has an obvious default of 0 */ + /* maxdist is required because there's no obvious default value for + * it, whereas mindist has an obvious default of 0 */ maxdist = get_table_int(L, "maxdist"); mindist = get_table_int_opt(L, "mindist", 0); @@ -896,7 +909,8 @@ l_selection_gradient(lua_State *L) /* sel:iterate(function(x,y) ... end); * The x, y coordinates passed to the function are map- or room-relative - * rather than absolute, unless there has been no previous map or room defined. + * rather than absolute, unless there has been no previous map or room + * defined. */ staticfn int l_selection_iterate(lua_State *L) @@ -917,8 +931,9 @@ l_selection_iterate(lua_State *L) lua_pushvalue(L, 2); lua_pushinteger(L, tmpx); lua_pushinteger(L, tmpy); - if (nhl_pcall_handle(L, 2, 0, "l_selection_iterate", NHLpa_impossible)) { - /* abort the loops to prevent possible error cascade */ + if (nhl_pcall_handle(L, 2, 0, "l_selection_iterate", + NHLpa_impossible)) { + /* abort loops to prevent possible error cascade */ goto out; } } @@ -926,7 +941,7 @@ l_selection_iterate(lua_State *L) nhl_error(L, "wrong parameters"); /*NOTREACHED*/ } -out: + out: return 0; } diff --git a/src/nhlua.c b/src/nhlua.c index 93816ef83..08de9cfe1 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -486,10 +486,10 @@ RESTORE_WARNING_UNREACHABLE_CODE and set the x and y values. return TRUE if there are such params in the stack. Note that this does not adjust the values of x and y at all from what is - specified in the level file; so, it returns absolute coordinates rather than - map-relative coordinates. Callers of this function must decide if they want - to interpret the values as absolute or as map-relative, and adjust - accordingly. + specified in the level file; so, it returns absolute coordinates rather + than map-relative coordinates. Callers of this function must decide if + they want to interpret the values as absolute or as map-relative, and + adjust accordingly. */ boolean nhl_get_xy_params(lua_State *L, lua_Integer *x, lua_Integer *y) @@ -700,11 +700,12 @@ nhl_getlin(lua_State *L) } /* - selected = menu("prompt", default, pickX, { "a" = "option a", "b" = "option b", ...}) + selected = menu("prompt",default,pickX,{"a"="option a", "b"="option b",...}) pickX = 0,1,2, or "none", "one", "any" (PICK_X in code) selected = menu("prompt", default, pickX, - { {key:"a", text:"option a"}, {key:"b", text:"option b"}, ... } ) */ + {{key:"a", text:"option a"},{key:"b", text:"option b"},... }) + */ staticfn int nhl_menu(lua_State *L) { @@ -1091,8 +1092,8 @@ nhl_dnum_name(lua_State *L) if (argc == 1) { lua_Integer dnum = luaL_checkinteger(L, 1); - if (dnum >= 0 && dnum < gn.n_dgns) - lua_pushstring(L, gd.dungeons[dnum].dname); + if (dnum >= 0 && dnum < svn.n_dgns) + lua_pushstring(L, svd.dungeons[dnum].dname); else lua_pushstring(L, ""); } else @@ -1584,8 +1585,8 @@ nhl_gamestate(lua_State *L) d_level cur_uz = u.uz, cur_uz0 = u.uz0; /* restore game state */ - gm.moves = gg.gmst_moves; - pline("Resetting time to move #%ld.", gm.moves); + svm.moves = gg.gmst_moves; + pline("Resetting time to move #%ld.", svm.moves); gg.gmst_moves = 0L; gl.lastinvnr = 51; @@ -1602,11 +1603,11 @@ nhl_gamestate(lua_State *L) assert(gg.gmst_ubak != NULL); (void) memcpy((genericptr_t) &u, gg.gmst_ubak, sizeof u); assert(gg.gmst_disco != NULL); - (void) memcpy((genericptr_t) &gd.disco, gg.gmst_disco, - sizeof gd.disco); + (void) memcpy((genericptr_t) &svd.disco, gg.gmst_disco, + sizeof svd.disco); assert(gg.gmst_mvitals != NULL); - (void) memcpy((genericptr_t) &gm.mvitals, gg.gmst_mvitals, - sizeof gm.mvitals); + (void) memcpy((genericptr_t) &svm.mvitals, gg.gmst_mvitals, + sizeof svm.mvitals); /* some restored state would confuse the level change in progress */ u.uz = cur_uz, u.uz0 = cur_uz0; init_uhunger(); @@ -1614,7 +1615,7 @@ nhl_gamestate(lua_State *L) gg.gmst_stored = FALSE; } else if (!reststate && !gg.gmst_stored) { /* store game state */ - gg.gmst_moves = gm.moves; + gg.gmst_moves = svm.moves; while ((otmp = gi.invent) != NULL) { wornmask = otmp->owornmask; setnotworn(otmp); @@ -1626,12 +1627,12 @@ nhl_gamestate(lua_State *L) gl.lastinvnr = 51; /* next inv letter to try to use will be 'a' */ gg.gmst_ubak = (genericptr_t) alloc(sizeof u); (void) memcpy(gg.gmst_ubak, (genericptr_t) &u, sizeof u); - gg.gmst_disco = (genericptr_t) alloc(sizeof gd.disco); - (void) memcpy(gg.gmst_disco, (genericptr_t) &gd.disco, - sizeof gd.disco); - gg.gmst_mvitals = (genericptr_t) alloc(sizeof gm.mvitals); - (void) memcpy(gg.gmst_mvitals, (genericptr_t) &gm.mvitals, - sizeof gm.mvitals); + gg.gmst_disco = (genericptr_t) alloc(sizeof svd.disco); + (void) memcpy(gg.gmst_disco, (genericptr_t) &svd.disco, + sizeof svd.disco); + gg.gmst_mvitals = (genericptr_t) alloc(sizeof svm.mvitals); + (void) memcpy(gg.gmst_mvitals, (genericptr_t) &svm.mvitals, + sizeof svm.mvitals); gg.gmst_stored = TRUE; } else { impossible("nhl_gamestate: inconsistent state (%s vs %s)", @@ -1840,7 +1841,7 @@ nhl_meta_u_index(lua_State *L) lua_pushstring(L, gu.urole.name.m); return 1; } else if (!strcmp(tkey, "moves")) { - lua_pushinteger(L, gm.moves); + lua_pushinteger(L, svm.moves); return 1; } else if (!strcmp(tkey, "uhave_amulet")) { lua_pushinteger(L, u.uhave.amulet); @@ -2335,12 +2336,14 @@ static struct e ct_base_base[] = { { EOT, NULL } }; -/* NHL_BASE_ERROR - not really safe - might not want Lua to kill the process */ +/* NHL_BASE_ERROR - not really safe--might not want Lua to kill the process */ static struct e ct_base_error[] = { - { IFFLAG, "assert" }, /* ok, calls error */ - { IFFLAG, "error" }, /* ok, calls G->panic */ - { NEVER, "print" }, /*not ok - calls lua_writestring/lua_writeline -> stdout*/ - { NEVER, "warn" }, /*not ok - calls lua_writestringerror -> stderr*/ + { IFFLAG, "assert" }, /* ok, calls error */ + { IFFLAG, "error" }, /* ok, calls G->panic */ + { NEVER, "print" }, /* not ok - calls lua_writestring/lua_writeline + * which write to stdout */ + { NEVER, "warn" }, /* not ok - calls lua_writestringerror which writes + * to stderr */ { EOT, NULL } }; @@ -2548,13 +2551,15 @@ is pop sufficient? XXX or wrong - look at the balance */ #define HOOKTBLNAME "org.nethack.nethack.sb.fs" #ifdef notyet -static int (*io_open)(lua_State *) = NULL; /* XXX this may have to be in g TBD */ +static int (*io_open)(lua_State *) = NULL; /* XXX this may have to be in + * struct g (gi now) TBD */ #endif void nhl_pushhooked_open_table(lua_State *L) { int hot = lua_getfield(L, LUA_REGISTRYINDEX, HOOKTBLNAME); + if (hot == LUA_TNONE) { lua_newtable(L); lua_pushvalue(L, -1); diff --git a/src/o_init.c b/src/o_init.c index 7ae3840e7..aeff43030 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 o_init.c $NHDT-Date: 1701720461 2023/12/04 20:07:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.79 $ */ +/* NetHack 3.7 o_init.c $NHDT-Date: 1720391455 2024/07/07 22:30:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.87 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -58,7 +58,7 @@ setgemprobs(d_level *dlev) : ledger_no(dlev); else lev = 0; - first = gb.bases[GEM_CLASS]; + first = svb.bases[GEM_CLASS]; for (j = 0; j < 9 - lev / 3; j++) objects[first + j].oc_prob = 0; @@ -73,7 +73,7 @@ setgemprobs(d_level *dlev) objects[j].oc_prob = (171 + j - first) / (LAST_REAL_GEM + 1 - first); /* recompute GEM_CLASS total oc_prob - including rocks/stones */ - for (j = gb.bases[GEM_CLASS]; j < gb.bases[GEM_CLASS + 1]; j++) + for (j = svb.bases[GEM_CLASS]; j < svb.bases[GEM_CLASS + 1]; j++) sum += objects[j].oc_prob; go.oclass_prob_totals[GEM_CLASS] = sum; } @@ -152,7 +152,7 @@ init_objects(void) char oclass; for (i = 0; i <= MAXOCLASSES; i++) { - gb.bases[i] = 0; + svb.bases[i] = 0; if (i > 0 && i < MAXOCLASSES && objects[i].oc_class != i) panic( "init_objects: class for generic object #%d doesn't match (%d)", @@ -180,7 +180,7 @@ init_objects(void) last = first + 1; while (last < NUM_OBJECTS && objects[last].oc_class == oclass) last++; - gb.bases[(int) oclass] = first; + svb.bases[(int) oclass] = first; if (oclass == GEM_CLASS) { setgemprobs((d_level *) 0); @@ -192,14 +192,18 @@ init_objects(void) /* extra entry allows deriving the range of a class via bases[class] through bases[class+1]-1 for all classes (except for ILLOBJ_CLASS which is separated from WEAPON_CLASS - by generic objects) */ - gb.bases[MAXOCLASSES] = NUM_OBJECTS; + by generic objects); second extra entry is to prevent an + explained crash in doclassdisco(), where the code ended up + attempting to process non-existent class MAXOCLASSES; the + [MAXOCLASSES+1] element gives that non-class 0 objects + when traversing objects[] from bases[X] through bases[X+1]-1 */ + svb.bases[MAXOCLASSES] = svb.bases[MAXOCLASSES + 1] = NUM_OBJECTS; /* hypothetically someone might remove all objects of some class, or be adding a new class and not populated it yet, leaving gaps in bases[]; guarantee that there are no such gaps */ for (last = MAXOCLASSES - 1; last >= 0; --last) - if (!gb.bases[last]) - gb.bases[last] = gb.bases[last + 1]; + if (!svb.bases[last]) + svb.bases[last] = svb.bases[last + 1]; /* check objects[].oc_name_known */ for (i = MAXOCLASSES; i < NUM_OBJECTS; ++i) { @@ -229,7 +233,7 @@ init_objects(void) } /* Compute the total probability of each object class. - * Assumes gb.bases[] has already been set. */ + * Assumes svb.bases[] has already been set. */ void init_oclass_probs(void) { @@ -241,15 +245,15 @@ init_oclass_probs(void) /* note: for ILLOBJ_CLASS, bases[oclass+1]-1 isn't the last item in the class; but all the generic items have probability 0 so adding them to 'sum' has no impact */ - for (i = gb.bases[oclass]; i < gb.bases[oclass + 1]; ++i) { + for (i = svb.bases[oclass]; i < svb.bases[oclass + 1]; ++i) { sum += objects[i].oc_prob; } if (sum <= 0 && oclass != ILLOBJ_CLASS - && gb.bases[oclass] != gb.bases[oclass + 1]) { + && svb.bases[oclass] != svb.bases[oclass + 1]) { impossible("%s (%d) probability total for oclass %d", !sum ? "zero" : "negative", sum, oclass); /* gracefully fail by setting all members of this class to 1 */ - for (i = gb.bases[oclass]; i < gb.bases[oclass + 1]; ++i) { + for (i = svb.bases[oclass]; i < svb.bases[oclass + 1]; ++i) { objects[i].oc_prob = 1; sum++; } @@ -282,14 +286,14 @@ obj_shuffle_range( break; case POTION_CLASS: /* potion of water has the only fixed description */ - *lo_p = gb.bases[POTION_CLASS]; + *lo_p = svb.bases[POTION_CLASS]; *hi_p = POT_WATER - 1; break; case AMULET_CLASS: case SCROLL_CLASS: case SPBOOK_CLASS: /* exclude non-magic types and also unique ones */ - *lo_p = gb.bases[ocls]; + *lo_p = svb.bases[ocls]; for (i = *lo_p; objects[i].oc_class == ocls; i++) if (objects[i].oc_unique || !objects[i].oc_magic) break; @@ -299,8 +303,8 @@ obj_shuffle_range( case WAND_CLASS: case VENOM_CLASS: /* entire class */ - *lo_p = gb.bases[ocls]; - *hi_p = gb.bases[ocls + 1] - 1; + *lo_p = svb.bases[ocls]; + *hi_p = svb.bases[ocls + 1] - 1; break; } @@ -328,7 +332,8 @@ shuffle_all(void) /* do whole classes (amulets, &c) */ for (idx = 0; idx < SIZE(shuffle_classes); idx++) { - obj_shuffle_range(gb.bases[(int) shuffle_classes[idx]], &first, &last); + obj_shuffle_range(svb.bases[(int) shuffle_classes[idx]], + &first, &last); shuffle(first, last, TRUE); } /* do type ranges (helms, &c) */ @@ -372,8 +377,8 @@ savenames(NHFILE *nhfp) if (perform_bwrite(nhfp)) { if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) gb.bases, sizeof gb.bases); - bwrite(nhfp->fd, (genericptr_t) gd.disco, sizeof gd.disco); + bwrite(nhfp->fd, (genericptr_t) svb.bases, sizeof svb.bases); + bwrite(nhfp->fd, (genericptr_t) svd.disco, sizeof svd.disco); bwrite(nhfp->fd, (genericptr_t) objects, sizeof(struct objclass) * NUM_OBJECTS); } @@ -404,8 +409,8 @@ restnames(NHFILE *nhfp) unsigned int len = 0; if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) gb.bases, sizeof gb.bases); - mread(nhfp->fd, (genericptr_t) gd.disco, sizeof gd.disco); + mread(nhfp->fd, (genericptr_t) svb.bases, sizeof svb.bases); + mread(nhfp->fd, (genericptr_t) svd.disco, sizeof svd.disco); mread(nhfp->fd, (genericptr_t) objects, NUM_OBJECTS * sizeof (struct objclass)); } @@ -440,10 +445,10 @@ discover_object( uname'd) or the next open slot; one or the other will be found before we reach the next class... */ - for (dindx = gb.bases[acls]; gd.disco[dindx] != 0; dindx++) - if (gd.disco[dindx] == oindx) + for (dindx = svb.bases[acls]; svd.disco[dindx] != 0; dindx++) + if (svd.disco[dindx] == oindx) break; - gd.disco[dindx] = oindx; + svd.disco[dindx] = oindx; /* if already known, we forced an item with a Japanese name into disco[] but don't want to exercise wisdom or update perminv */ @@ -456,7 +461,7 @@ discover_object( exercise(A_WIS, TRUE); } /* !in_moveloop => initial inventory, gameover => final disclosure */ - if (gp.program_state.in_moveloop && !gp.program_state.gameover) { + if (program_state.in_moveloop && !program_state.gameover) { if (objects[oindx].oc_class == GEM_CLASS) gem_learned(oindx); /* could affect price of unpaid gems */ update_inventory(); @@ -473,18 +478,18 @@ undiscover_object(int oindx) boolean found = FALSE; /* find the object; shift those behind it forward one slot */ - for (dindx = gb.bases[acls]; - dindx < NUM_OBJECTS && gd.disco[dindx] != 0 + for (dindx = svb.bases[acls]; + dindx < NUM_OBJECTS && svd.disco[dindx] != 0 && objects[dindx].oc_class == acls; dindx++) if (found) - gd.disco[dindx - 1] = gd.disco[dindx]; - else if (gd.disco[dindx] == oindx) + svd.disco[dindx - 1] = svd.disco[dindx]; + else if (svd.disco[dindx] == oindx) found = TRUE; /* clear last slot */ if (found) - gd.disco[dindx - 1] = 0; + svd.disco[dindx - 1] = 0; else impossible("named object not in disco"); @@ -545,7 +550,7 @@ sortloot_descr(int otyp, char *outbuf) o.corpsenm = NON_PM; /* suppress statue and figurine details */ /* but suppressing fruit details leads to "bad fruit #0" */ if (otyp == SLIME_MOLD) - o.spe = gc.context.current_fruit; + o.spe = svc.context.current_fruit; (void) memset((genericptr_t) &sl_cookie, 0, sizeof sl_cookie); sl_cookie.obj = (struct obj *) 0; @@ -573,7 +578,7 @@ static const char *const disco_orders_descr[] = { int choose_disco_sort( - int mode) /* 0 => 'O' cmd, 1 => full discoveries; 2 => class discoveries */ + int mode) /* 0 => 'O' cmd, 1 => full discoveries; 2 => class disco */ { winid tmpwin; menu_item *selected; @@ -603,7 +608,7 @@ choose_disco_sort( add_menu_str(tmpwin, " are equivalent for single class discovery, but"); add_menu_str(tmpwin, - " will matter for future use of total discoveries."); + " will matter for future use of total discoveries."); } end_menu(tmpwin, "Ordering of discoveries"); @@ -750,14 +755,15 @@ dodiscovered(void) /* free after Robert Viduya */ for (s = classes; *s; s++) { oclass = *s; prev_class = oclass + 1; /* forced different from oclass */ - for (i = gb.bases[(int) oclass]; + for (i = svb.bases[(int) oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) { - if ((dis = gd.disco[i]) != 0 && interesting_to_discover(dis)) { + if ((dis = svd.disco[i]) != 0 && interesting_to_discover(dis)) { ct++; if (oclass != prev_class) { if ((alphabyclass || lootsort) && sorted_ct) { /* output previous class */ - disco_output_sorted(tmpwin, sorted_lines, sorted_ct, lootsort); + disco_output_sorted(tmpwin, sorted_lines, sorted_ct, + lootsort); sorted_ct = 0; } if (!alphabetized || alphabyclass) { @@ -880,11 +886,11 @@ doclassdisco(void) for (s = allclasses; *s; ++s) { oclass = *s; c = def_oc_syms[(int) oclass].sym; - for (i = gb.bases[(int) oclass]; + for (i = svb.bases[(int) oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; ++i) - if ((dis = gd.disco[i]) != 0 && interesting_to_discover(dis)) { + if ((dis = svd.disco[i]) != 0 && interesting_to_discover(dis)) { if (!strchr(discosyms, c)) { - Sprintf(eos(discosyms), "%c", c); + (void) strkitten(discosyms, c); if (!traditional) { any.a_int = c; add_menu(tmpwin, &nul_glyphinfo, &any, @@ -981,14 +987,18 @@ doclassdisco(void) break; default: oclass = def_char_to_objclass(c); + /* this should never happen but has been observed via the fuzzer */ + if (oclass == MAXOCLASSES) + impossible("doclassdisco: invalid object class '%s'", visctrl(c)); Sprintf(buf, "Discovered %s in %s", let_to_name(oclass, FALSE, FALSE), (flags.discosort == 'o') ? "order of discovery" : (flags.discosort == 's') ? "'sortloot' order" : "alphabetical order"); putstr(tmpwin, 0, buf); /* skip iflags.menu_headings */ sorted_ct = 0; - for (i = gb.bases[(int) oclass]; i <= gb.bases[oclass + 1] - 1; ++i) { - if ((dis = gd.disco[i]) != 0 && interesting_to_discover(dis)) { + for (i = svb.bases[(int) oclass]; i <= svb.bases[oclass + 1] - 1; + ++i) { + if ((dis = svd.disco[i]) != 0 && interesting_to_discover(dis)) { ++ct; Strcpy(buf, objects[dis].oc_pre_discovered ? "* " : " "); if (lootsort) @@ -1050,9 +1060,9 @@ rename_disco(void) for (s = flags.inv_order; *s; s++) { oclass = *s; prev_class = oclass + 1; /* forced different from oclass */ - for (i = gb.bases[(int) oclass]; + for (i = svb.bases[(int) oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) { - dis = gd.disco[i]; + dis = svd.disco[i]; if (!dis || !interesting_to_discover(dis)) continue; ct++; diff --git a/src/objnam.c b/src/objnam.c index 7713a5dad..727f91dbd 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -325,7 +325,7 @@ obj_is_pname(struct obj *obj) { if (!obj->oartifact || !has_oname(obj)) return FALSE; - if (!gp.program_state.gameover && !iflags.override_ID) { + if (!program_state.gameover && !iflags.override_ID) { if (not_fully_identified(obj)) return FALSE; } @@ -371,7 +371,7 @@ distant_name( against a potential extra chance to browse the map with getpos() during final disclosure (not currently implemented, nor planned) */ save_oid = obj->o_id; - if (gp.program_state.gameover) + if (program_state.gameover) obj->o_id = 0; /* this maybe-nearby part used to be replicated in multiple callers */ @@ -406,12 +406,12 @@ fruitname( boolean juice) /* whether or not to append " juice" to the name */ { char *buf = nextobuf(); - const char *fruit_nam = strstri(gp.pl_fruit, " of "); + const char *fruit_nam = strstri(svp.pl_fruit, " of "); if (fruit_nam) fruit_nam += 4; /* skip past " of " */ else - fruit_nam = gp.pl_fruit; /* use it as is */ + fruit_nam = svp.pl_fruit; /* use it as is */ Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : ""); return buf; @@ -955,7 +955,7 @@ xname_flags( "You were acid resistant because of your alchemy smock \ with text \"Kiss the cook\"." when disclosing attributes anyway */ - if (gp.program_state.gameover && obj->o_id && bufspaceleft > 0) { + if (program_state.gameover && obj->o_id && bufspaceleft > 0) { const char *lbl; char tmpbuf[BUFSZ]; @@ -1444,7 +1444,7 @@ doname_base( the message as it gets added to invent and also if it gets snuffed out immediately (where it will end up as not partly used after all) */ - turns_left += peek_timer(BURN_OBJECT, &timer) - gm.moves; + turns_left += peek_timer(BURN_OBJECT, &timer) - svm.moves; } if (turns_left < full_burn_time) Strcat(prefix, "partly used "); @@ -1503,7 +1503,7 @@ doname_base( Strcat(prefix, "stale "); #endif if (ismnum(omndx) - && (known || (gm.mvitals[omndx].mvflags & MV_KNOWS_EGG))) { + && (known || (svm.mvitals[omndx].mvflags & MV_KNOWS_EGG))) { Strcat(prefix, mons[omndx].pmnames[NEUTRAL]); Strcat(prefix, " "); if (obj->spe == 1) @@ -1625,7 +1625,7 @@ doname_base( bill might not be available yet while restore is in progress (objects won't normally be formatted during that time, but if 'perm_invent' is enabled then they might be [not any more...]) */ - if (iflags.suppress_price || gp.program_state.restoring) { + if (iflags.suppress_price || program_state.restoring) { ; /* don't attempt to obtain any shop pricing, even if 'with_price' */ } else if (is_unpaid(obj)) { /* in inventory or in container in invent */ char pricebuf[40]; @@ -2273,28 +2273,51 @@ Doname2(struct obj *obj) return s; } -#if 0 /* stalled-out work in progress */ -/* Doname2() for itemized buying of 'obj' from a shop */ +/* doname() for itemized buying of 'obj' from a shop */ char * -payDoname(struct obj *obj) +paydoname(struct obj *obj) { static const char and_contents[] = " and its contents"; - char *p = doname(obj); + char *p; + unsigned save_cknown = obj->cknown; + boolean save_wizweight = iflags.wizweight; - if (Is_container(obj) && !obj->cknown) { - if (obj->unpaid) { - if ((int) strlen(p) + sizeof and_contents - 1 < BUFSZ - PREFIX) - Strcat(p, and_contents); - *p = highc(*p); - } else { - p = strprepend(p, "Contents of "); + if (Has_contents(obj)) + obj->cknown = 0; + /* avoid showing item weights to unclutter billing's pay-menu a bit */ + iflags.wizweight = FALSE; + /* suppress invent-style price; caller will add billing-style price */ + iflags.suppress_price++; + p = doname_base(obj, 0U); + iflags.suppress_price--; + iflags.wizweight = save_wizweight; + + if (Has_contents(obj)) { + /* buy_container() sets no_charge for a container that has just + been purchased so that when paydoname() is called by + shk_names_obj(), we'll provide "a/an " instead of + "your " */ + if (!obj->no_charge) { + if (!strncmp(p, "a ", 2)) + p += 2; + else if (!strncmp(p, "an ", 3)) + p += 3; + p = strprepend(p, obj->unpaid ? "an unpaid " : "your "); + } + + if (!obj->cknown) { + if (obj->unpaid) { + if ((int) strlen(p) + sizeof and_contents - 1 + < BUFSZ - PREFIX) + Strcat(p, and_contents); + } else { + p = strprepend(p, "the contents of "); + } } - } else { - *p = highc(*p); } + obj->cknown = save_cknown; return p; } -#endif /*0*/ /* returns "[your ]xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */ char * @@ -3356,7 +3379,7 @@ rnd_otyp_by_wpnskill(schar skill) int i, n = 0; short otyp = STRANGE_OBJECT; - for (i = gb.bases[WEAPON_CLASS]; + for (i = svb.bases[WEAPON_CLASS]; i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++) if (objects[i].oc_skill == skill) { n++; @@ -3364,7 +3387,7 @@ rnd_otyp_by_wpnskill(schar skill) } if (n > 0) { n = rn2(n); - for (i = gb.bases[WEAPON_CLASS]; + for (i = svb.bases[WEAPON_CLASS]; i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++) if (objects[i].oc_skill == skill) if (--n < 0) @@ -3396,8 +3419,8 @@ rnd_otyp_by_namedesc( (void) memset((genericptr_t) validobjs, 0, sizeof validobjs); if (oclass) { - lo = gb.bases[(uchar) oclass]; - hi = gb.bases[(uchar) oclass + 1] - 1; + lo = svb.bases[(uchar) oclass]; + hi = svb.bases[(uchar) oclass + 1] - 1; } else { lo = MAXOCLASSES; /* STRANGE_OBJECT + 1; */ hi = NUM_OBJECTS - 1; @@ -3498,7 +3521,7 @@ wizterrainwish(struct _readobjnam_data *d) if (!BSTRCMPI(bp, p - 8, "fountain")) { lev->typ = FOUNTAIN; if (oldtyp != FOUNTAIN) - gl.level.flags.nfountains++; + svl.level.flags.nfountains++; lev->looted = d->looted ? F_LOOTED : 0; /* overlays 'flags' */ lev->blessedftn = d->blessed || !strncmpi(bp, "magic ", 6); pline("A %sfountain.", lev->blessedftn ? "magic " : ""); @@ -3511,7 +3534,7 @@ wizterrainwish(struct _readobjnam_data *d) } else if (!BSTRCMPI(bp, p - 4, "sink")) { lev->typ = SINK; if (oldtyp != SINK) - gl.level.flags.nsinks++; + svl.level.flags.nsinks++; lev->looted = d->looted ? (S_LPUDDING | S_LDWASHER | S_LRING) : 0; pline("A sink."); madeterrain = TRUE; @@ -3545,7 +3568,7 @@ wizterrainwish(struct _readobjnam_data *d) } else { dbterrainmesg("Moat", x, y); } - water_damage_chain(gl.level.objects[x][y], TRUE); + water_damage_chain(svl.level.objects[x][y], TRUE); madeterrain = TRUE; /* also matches "molten lava" */ @@ -3569,7 +3592,7 @@ wizterrainwish(struct _readobjnam_data *d) } else { dbterrainmesg("Lava", x, y); } - fire_damage_chain(gl.level.objects[x][y], TRUE, TRUE, x, y); + fire_damage_chain(svl.level.objects[x][y], TRUE, TRUE, x, y); madeterrain = TRUE; } else if (!BSTRCMPI(bp, p - 3, "ice")) { if (!is_dbridge) { @@ -3690,7 +3713,7 @@ wizterrainwish(struct _readobjnam_data *d) lev->wall_info |= (old_wall_info & WM_MASK); /* set up trapped flag; open door states aren't eligible */ if (d->trapped == 2 /* 2: wish includes explicit "untrapped" */ - || secret /* secret doors can't trapped due to their use + || secret /* secret doors can't be trapped due to their use * of both doormask and wall_info; those both * overlay rm->flags and partially conflict */ || (lev->doormask & (D_LOCKED | D_CLOSED)) == 0) @@ -3867,7 +3890,7 @@ readobjnam_init(char *bp, struct _readobjnam_data *d) d->bp = d->origbp = bp; d->p = (char *) 0; d->name = (const char *) 0; - d->ftype = gc.context.current_fruit; + d->ftype = svc.context.current_fruit; (void) memset(d->globbuf, '\0', sizeof d->globbuf); (void) memset(d->fruitbuf, '\0', sizeof d->fruitbuf); } @@ -4628,7 +4651,7 @@ readobjnam_postparse3(struct _readobjnam_data *d) /* check real names of gems first */ if (!d->oclass && d->actualn) { - for (i = gb.bases[GEM_CLASS]; i <= LAST_REAL_GEM; i++) { + for (i = svb.bases[GEM_CLASS]; i <= LAST_REAL_GEM; i++) { const char *zn; if ((zn = OBJ_NAME(objects[i])) != 0 && !strcmpi(d->actualn, zn)) { @@ -4871,7 +4894,7 @@ readobjnam(char *bp, struct obj *no_wish) * Disallow such topology tweaks for WIZKIT startup wishes. */ wiztrap: - if (wizard && !gp.program_state.wizkit_wishing && !d.oclass) { + if (wizard && !program_state.wizkit_wishing && !d.oclass) { /* [inline code moved to separate routine to unclutter readobjnam] */ if ((d.otmp = wizterrainwish(&d)) != 0) return d.otmp; @@ -4959,7 +4982,7 @@ readobjnam(char *bp, struct obj *no_wish) if (rn1cnt > 6 - d.gsize) rn1cnt = 6 - d.gsize; if (d.cnt > rn1cnt - && (!wizard || gp.program_state.wizkit_wishing + && (!wizard || program_state.wizkit_wishing || y_n("Override glob weight limit?") != 'y')) d.cnt = rn1cnt; d.otmp->owt *= (unsigned) d.cnt; @@ -5093,7 +5116,7 @@ readobjnam(char *bp, struct obj *no_wish) corpses and tins, switch to their corresponding human form; for figurines, override the can't-be-human restriction instead */ if (d.typ != FIGURINE && is_were(&mons[d.mntmp]) - && (gm.mvitals[d.mntmp].mvflags & G_NOCORPSE) != 0 + && (svm.mvitals[d.mntmp].mvflags & G_NOCORPSE) != 0 && (humanwere = counter_were(d.mntmp)) != NON_PM) d.mntmp = humanwere; @@ -5102,14 +5125,14 @@ readobjnam(char *bp, struct obj *no_wish) if (dead_species(d.mntmp, FALSE)) { d.otmp->corpsenm = NON_PM; /* it's empty */ } else if ((!(mons[d.mntmp].geno & G_UNIQ) || wizard) - && !(gm.mvitals[d.mntmp].mvflags & G_NOCORPSE) + && !(svm.mvitals[d.mntmp].mvflags & G_NOCORPSE) && mons[d.mntmp].cnutrit != 0) { d.otmp->corpsenm = d.mntmp; } break; case CORPSE: if ((!(mons[d.mntmp].geno & G_UNIQ) || wizard) - && !(gm.mvitals[d.mntmp].mvflags & G_NOCORPSE)) { + && !(svm.mvitals[d.mntmp].mvflags & G_NOCORPSE)) { if (mons[d.mntmp].msound == MS_GUARDIAN) d.mntmp = genus(d.mntmp, 1); set_corpsenm(d.otmp, d.mntmp); diff --git a/src/options.c b/src/options.c index 0c05ae9ad..28eaa91c3 100644 --- a/src/options.c +++ b/src/options.c @@ -478,8 +478,19 @@ parseoptions( using_alias = FALSE; go.opt_initial = tinitial; go.opt_from_file = tfrom_file; - if ((op = strchr(opts, ',')) != 0) { + /* + * Process elements of comma-separated list in right to left order. + * When some options are set interactively--notably various compound + * options that issue a prompt for a value--they use parseoptions() + * to handle setting the new value. For those, 'tinitial' is False + * and if user tries to supply a comma-separated list, it will be + * treated as part of the current option, probably failing to parse. + */ + if (tinitial && (op = strchr(opts, ',')) != 0) { *op++ = 0; + /* current element remains pending while the rest of the line gets + handled recursively; if the rest of line contains any commas, + then the process will recurse deeper as it is processed */ if (!parseoptions(op, go.opt_initial, go.opt_from_file)) retval = FALSE; } @@ -578,7 +589,7 @@ parseoptions( } /* allow optfn's to test whether they were called from parseoptions() */ - gp.program_state.in_parseoptions++; + program_state.in_parseoptions++; if (got_match && matchidx >= 0) { duplicate = duplicate_opt_detection(matchidx); @@ -604,8 +615,8 @@ parseoptions( } } - if (gp.program_state.in_parseoptions > 0) - gp.program_state.in_parseoptions--; + if (program_state.in_parseoptions > 0) + program_state.in_parseoptions--; #if 0 /* This specialization shouldn't be needed any longer because each of @@ -1279,11 +1290,12 @@ optfn_crash_urlmax( return optn_ok; } if (req == do_set) { - if ((op = string_for_opt(opts, FALSE)) - != empty_optstr) { + if ((op = string_for_opt(opts, FALSE)) != empty_optstr) { int temp = atoi(op); - if(temp < 75){ - config_error_add("Invalid value %d for crash_urlmax. Minimum value is 75.",temp); + + if (temp < 75){ + config_error_add("Invalid value %d for crash_urlmax. " + " Minimum value is 75.", temp); return optn_err; } gc.crash_urlmax = temp; @@ -1695,7 +1707,7 @@ optfn_fruit( f = fruit_from_name(op, FALSE, &fnum); if (!f) { if (!flags.made_fruit) - forig = fruit_from_name(gp.pl_fruit, FALSE, (int *) 0); + forig = fruit_from_name(svp.pl_fruit, FALSE, (int *) 0); if (!forig && fnum >= 100) { config_error_add( @@ -1705,19 +1717,19 @@ optfn_fruit( } } goodfruit: - nmcpy(gp.pl_fruit, op, PL_FSIZ); - sanitize_name(gp.pl_fruit); + nmcpy(svp.pl_fruit, op, PL_FSIZ); + sanitize_name(svp.pl_fruit); /* OBJ_NAME(objects[SLIME_MOLD]) won't work for this after initialization; it gets changed to generic "fruit" */ - if (!*gp.pl_fruit) - nmcpy(gp.pl_fruit, "slime mold", PL_FSIZ); + if (!*svp.pl_fruit) + nmcpy(svp.pl_fruit, "slime mold", PL_FSIZ); if (!go.opt_initial) { /* if 'forig' is nonNull, we replace it rather than add a new fruit; it can only be nonNull if no fruits have been created since the previous name was put in place */ - (void) fruitadd(gp.pl_fruit, forig); + (void) fruitadd(svp.pl_fruit, forig); if (give_opt_msg) - pline("Fruit is now \"%s\".", gp.pl_fruit); + pline("Fruit is now \"%s\".", svp.pl_fruit); } /* If initial, then initoptions is allowed to do it instead * of here (initoptions always has to do it even if there's @@ -1727,7 +1739,7 @@ optfn_fruit( return optn_ok; } if (req == get_val || req == get_cnf_val) { - Sprintf(opts, "%s", gp.pl_fruit); + Sprintf(opts, "%s", svp.pl_fruit); return optn_ok; } return optn_ok; @@ -2446,13 +2458,13 @@ optfn_name( if ((op = string_for_env_opt(allopt[optidx].name, opts, FALSE)) != empty_optstr) { - nmcpy(gp.plname, op, PL_NSIZ); + nmcpy(svp.plname, op, PL_NSIZ); } else return optn_err; return optn_ok; } if (req == get_val || req == get_cnf_val) { - Sprintf(opts, "%s", gp.plname); + Sprintf(opts, "%s", svp.plname); return optn_ok; } return optn_ok; @@ -3491,7 +3503,7 @@ optfn_role( config_error_add("Unknown %s '%s'", allopt[optidx].name, op); return optn_err; } - nmcpy(gp.pl_character, op, PL_NSIZ); /* Backwards compat */ + nmcpy(svp.pl_character, op, PL_NSIZ); /* Backwards compat */ saveoptstr(optidx, rolestring(flags.initrole, roles, name.m)); } return optn_ok; @@ -3534,7 +3546,8 @@ optfn_runmode( return optn_err; } } else { - config_error_add("Value is mandatory for %s", allopt[optidx].name); + config_error_add("Value is mandatory for %s", + allopt[optidx].name); return optn_err; } return optn_ok; @@ -5161,6 +5174,10 @@ optfn_boolean( /* After the change */ switch (optidx) { + case opt_pauper: + /* pauper implies nudist */ + u.uroleplay.nudist = u.uroleplay.pauper; + break; case opt_ascii_map: iflags.wc_tiled_map = negated; break; @@ -5647,9 +5664,11 @@ handler_msg_window(void) for (i = 0; i < SIZE(menutype); i++) { if (i < 2 && is_curses) continue; - Sprintf(buf, "%-12.12s%c%.60s", msgwind[i][0], sep, msgwind[i][1]); + Sprintf(buf, "%-12.12s%c%.60s", msgwind[i][0], sep, + msgwind[i][1]); any.a_char = c = *msgwind[i][0]; - add_menu(tmpwin, &nul_glyphinfo, &any, *buf, 0, ATR_NONE, clr, buf, + add_menu(tmpwin, &nul_glyphinfo, &any, *buf, 0, + ATR_NONE, clr, buf, (c == iflags.prevmsg_window) ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE); /* second line is prefixed by spaces that "c - " would use */ @@ -5943,7 +5962,8 @@ handler_runmode(void) staticfn int handler_petattr(void) { - int tmp = query_attr("Select pet highlight attribute", iflags.wc2_petattr); + int tmp + = query_attr("Select pet highlight attribute", iflags.wc2_petattr); if (tmp != -1) { iflags.wc2_petattr = tmp; @@ -7080,7 +7100,7 @@ initoptions_init(void) /* since this is done before init_objects(), do partial init here */ objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD; - nmcpy(gp.pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); + nmcpy(svp.pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); } /* @@ -7167,7 +7187,7 @@ initoptions_finish(void) free((genericptr_t) gc.cmdline_rcfile), gc.cmdline_rcfile = 0; /*[end of nethackrc handling]*/ - (void) fruitadd(gp.pl_fruit, (struct fruit *) 0); + (void) fruitadd(svp.pl_fruit, (struct fruit *) 0); /* * Remove "slime mold" from list of object names. This will * prevent it from being wished unless it's actually present @@ -7975,7 +7995,7 @@ fruitadd(char *str, struct fruit *replace_fruit) struct fruit *f; int highest_fruit_id = 0, globpfx; char buf[PL_FSIZ], altname[PL_FSIZ]; - boolean user_specified = (str == gp.pl_fruit); + boolean user_specified = (str == svp.pl_fruit); /* if not user-specified, then it's a fruit name for a fruit on * a bones level or from orctown raider's loot... */ @@ -7991,21 +8011,22 @@ fruitadd(char *str, struct fruit *replace_fruit) they already received it in their original game; str==pl_fruit but makesingular() creates a copy so we need to copy that back into pl_fruit */ - nmcpy(gp.pl_fruit, makesingular(str), PL_FSIZ); + nmcpy(svp.pl_fruit, makesingular(str), PL_FSIZ); /* disallow naming after other foods (since it'd be impossible * to tell the difference); globs might have a size prefix which * needs to be skipped in order to match the object type name */ - globpfx = (!strncmp(gp.pl_fruit, "small ", 6) - || !strncmp(gp.pl_fruit, "large ", 6)) ? 6 - : (!strncmp(gp.pl_fruit, "medium ", 7)) ? 7 - : (!strncmp(gp.pl_fruit, "very large ", 11)) ? 11 + globpfx = (!strncmp(svp.pl_fruit, "small ", 6) + || !strncmp(svp.pl_fruit, "large ", 6)) ? 6 + : (!strncmp(svp.pl_fruit, "medium ", 7)) ? 7 + : (!strncmp(svp.pl_fruit, "very large ", 11)) ? 11 : 0; - for (i = gb.bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; i++) { - if (!strcmp(OBJ_NAME(objects[i]), gp.pl_fruit) - || (globpfx > 0 - && !strcmp(OBJ_NAME(objects[i]), &gp.pl_fruit[globpfx]))) { + for (i = svb.bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; + i++) { + if (!strcmp(OBJ_NAME(objects[i]), svp.pl_fruit) + || (globpfx > 0 && !strcmp(OBJ_NAME(objects[i]), + &svp.pl_fruit[globpfx]))) { found = TRUE; break; } @@ -8013,7 +8034,7 @@ fruitadd(char *str, struct fruit *replace_fruit) if (!found) { char *c; - for (c = gp.pl_fruit; *c >= '0' && *c <= '9'; c++) + for (c = svp.pl_fruit; *c >= '0' && *c <= '9'; c++) continue; if (!*c || isspace((uchar) *c)) numeric = TRUE; @@ -8022,22 +8043,22 @@ fruitadd(char *str, struct fruit *replace_fruit) /* these checks for applying food attributes to actual items are case sensitive; "glob of foo" is caught by 'found' if 'foo' is a valid glob; when not valid, allow it as-is */ - || !strncmp(gp.pl_fruit, "cursed ", 7) - || !strncmp(gp.pl_fruit, "uncursed ", 9) - || !strncmp(gp.pl_fruit, "blessed ", 8) - || !strncmp(gp.pl_fruit, "partly eaten ", 13) - || (!strncmp(gp.pl_fruit, "tin of ", 7) - && (!strcmp(gp.pl_fruit + 7, "spinach") - || ismnum(name_to_mon(gp.pl_fruit + 7, (int *) 0)))) - || !strcmp(gp.pl_fruit, "empty tin") - || (!strcmp(gp.pl_fruit, "glob") - || (globpfx > 0 && !strcmp("glob", &gp.pl_fruit[globpfx]))) - || ((str_end_is(gp.pl_fruit, " corpse") - || str_end_is(gp.pl_fruit, " egg")) - && ismnum(name_to_mon(gp.pl_fruit, (int *) 0)))) { - Strcpy(buf, gp.pl_fruit); - Strcpy(gp.pl_fruit, "candied "); - nmcpy(gp.pl_fruit + 8, buf, PL_FSIZ - 8); + || !strncmp(svp.pl_fruit, "cursed ", 7) + || !strncmp(svp.pl_fruit, "uncursed ", 9) + || !strncmp(svp.pl_fruit, "blessed ", 8) + || !strncmp(svp.pl_fruit, "partly eaten ", 13) + || (!strncmp(svp.pl_fruit, "tin of ", 7) + && (!strcmp(svp.pl_fruit + 7, "spinach") + || ismnum(name_to_mon(svp.pl_fruit + 7, (int *) 0)))) + || !strcmp(svp.pl_fruit, "empty tin") + || (!strcmp(svp.pl_fruit, "glob") + || (globpfx > 0 && !strcmp("glob", &svp.pl_fruit[globpfx]))) + || ((str_end_is(svp.pl_fruit, " corpse") + || str_end_is(svp.pl_fruit, " egg")) + && ismnum(name_to_mon(svp.pl_fruit, (int *) 0)))) { + Strcpy(buf, svp.pl_fruit); + Strcpy(svp.pl_fruit, "candied "); + nmcpy(svp.pl_fruit + 8, buf, PL_FSIZ - 8); } *altname = '\0'; /* This flag indicates that a fruit has been made since the @@ -8052,7 +8073,7 @@ fruitadd(char *str, struct fruit *replace_fruit) /* replace_fruit is already part of the fruit chain; update it in place rather than looking it up again */ f = replace_fruit; - copynchars(f->fname, gp.pl_fruit, PL_FSIZ - 1); + copynchars(f->fname, svp.pl_fruit, PL_FSIZ - 1); goto nonew; } } else { @@ -8083,7 +8104,7 @@ fruitadd(char *str, struct fruit *replace_fruit) gf.ffruit = f; nonew: if (user_specified) - gc.context.current_fruit = f->fid; + svc.context.current_fruit = f->fid; return f->fid; } @@ -8573,8 +8594,7 @@ doset(void) /* changing options via menu by Per Liboriussen */ anything any; menu_item *pick_list; int indexoffset, startpass, endpass; - boolean setinitial = FALSE, fromfile = FALSE, - gavehelp = FALSE, skiphelp = !iflags.cmdassist; + boolean gavehelp = FALSE, skiphelp = !iflags.cmdassist; int clr = NO_COLOR; if (iflags.menu_requested) { @@ -8598,7 +8618,8 @@ doset(void) /* changing options via menu by Per Liboriussen */ "For a brief explanation of how this works, type '?' to select", "the next menu choice, then press or .", NULL, /* actual '?' menu entry gets inserted here */ - "[To suppress this menu help, toggle off the 'cmdassist' option.]", + ("[To suppress this menu help," + " toggle off the 'cmdassist' option.]"), "", }; any = cg.zeroany; @@ -8607,7 +8628,7 @@ doset(void) /* changing options via menu by Per Liboriussen */ Sprintf(buf, "%4s%.75s", "", helptext[i]); add_menu_str(tmpwin, buf); } else { - any.a_int = HELP_IDX + 1; /* processing pick_list subtracts 1 */ + any.a_int = HELP_IDX + 1; /* handling pick_list subtracts 1 */ add_menu(tmpwin, &nul_glyphinfo, &any, '?', '?', ATR_NONE, clr, "view help for options menu", MENU_ITEMFLAGS_SKIPINVERT); @@ -8731,7 +8752,7 @@ doset(void) /* changing options via menu by Per Liboriussen */ /* boolean option */ Sprintf(buf, "%s%s", *allopt[opt_indx].addr ? "!" : "", allopt[opt_indx].name); - (void) parseoptions(buf, setinitial, fromfile); + (void) parseoptions(buf, FALSE, FALSE); } else { /* compound option */ int k = opt_indx, reslt; @@ -8755,7 +8776,7 @@ doset(void) /* changing options via menu by Per Liboriussen */ (void) strncat(eos(buf), abuf, (sizeof buf - 1 - strlen(buf))); /* pass the buck */ - (void) parseoptions(buf, setinitial, fromfile); + (void) parseoptions(buf, FALSE, FALSE); } } if (wc_supported(allopt[opt_indx].name) @@ -9212,7 +9233,8 @@ static const char *opt_intro[] = { #endif "or press \"O\" while playing and use the menu.", "", - "Boolean options (which can be negated by prefixing them with '!' or \"no\"):", + ("Boolean options (which can be negated by prefixing them" + " with '!' or \"no\"):"), (char *) 0 }; @@ -9885,7 +9907,7 @@ set_playmode(void) { if (wizard) { if (authorize_wizard_mode()) - gp.plnamelen = (int) strlen(strcpy(gp.plname, "wizard")); + gp.plnamelen = (int) strlen(strcpy(svp.plname, "wizard")); else wizard = FALSE; /* not allowed or not available */ /* try explore mode if we didn't make it into wizard mode */ diff --git a/src/pager.c b/src/pager.c index c1536421e..eff6bfd6b 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 pager.c $NHDT-Date: 1713334816 2024/04/17 06:20:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.274 $ */ +/* NetHack 3.7 pager.c $NHDT-Date: 1724094301 2024/08/19 19:05:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.279 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -115,11 +115,13 @@ self_lookat(char *outbuf) Sprintf(outbuf, "%s%s%s called %s", /* being blinded may hide invisibility from self */ (Invis && (senseself() || !Blind)) ? "invisible " : "", race, - pmname(&mons[u.umonnum], Ugender), gp.plname); + pmname(&mons[u.umonnum], Ugender), svp.plname); if (u.usteed) Sprintf(eos(outbuf), ", mounted on %s", y_monnam(u.usteed)); - if (u.uundetected || (Upolyd && U_AP_TYPE)) - mhidden_description(&gy.youmonst, MHID_PREFIX | MHID_ARTICLE, + if (u.uundetected || (Upolyd && U_AP_TYPE) + || visible_region_at(u.ux, u.uy)) + mhidden_description(&gy.youmonst, + MHID_PREFIX | MHID_ARTICLE | MHID_REGION, eos(outbuf)); if (Punished) Sprintf(eos(outbuf), ", chained to %s", @@ -187,12 +189,15 @@ mhidden_description( { struct obj *otmp; const char *what; + NhRegion *reg; + size_t buflen; boolean incl_prefix = (mhid_flags & MHID_PREFIX) != 0, incl_article = (mhid_flags & MHID_ARTICLE) != 0, - show_altmon = (mhid_flags & MHID_ALTMON) != 0; + show_altmon = (mhid_flags & MHID_ALTMON) != 0, + force_region = (mhid_flags & MHID_REGION) != 0; boolean fakeobj, isyou = (mon == &gy.youmonst); coordxy x = isyou ? u.ux : mon->mx, y = isyou ? u.uy : mon->my; - int glyph = (gl.level.flags.hero_memory && !isyou) ? levl[x][y].glyph + int glyph = (svl.level.flags.hero_memory && !isyou) ? levl[x][y].glyph : glyph_at(x, y); *outbuf = '\0'; @@ -251,6 +256,26 @@ mhidden_description( Strcat(outbuf, " in murky water"); } } + + /* FIXME: isn't right when looking at long worm tails */ + if ((reg = visible_region_at(x, y)) != 0 + && (buflen = strlen(outbuf)) < BUFSZ - 1) { + int r = (u.xray_range > 1) ? u.xray_range : 1; + + /* at present, hero must be next to the monster; being able to see + from the hero's spot to the monster's spot would be much better, + but a visible region marks all its spots as can't-be-seen, so + this monster's spot is !cansee and !couldsee [maybe we need an + additional vision bit for "hero's side of edge of gas cloud"?] */ + if (distu(x, y) <= r * (r + 1) || force_region) { + int rglyph = reg->glyph; + boolean poison_gas = (glyph_is_cmap(rglyph) + && glyph_to_cmap(rglyph) == S_poisoncloud); + + Snprintf(eos(outbuf), BUFSZ - buflen, ", in a cloud of %s", + poison_gas ? "poison gas" : "vapor"); + } + } } /* extracted from lookat(); also used by namefloorobj() */ @@ -265,7 +290,7 @@ object_from_map(int glyph, coordxy x, coordxy y, struct obj **obj_p) *obj_p = (struct obj *) 0; /* TODO: check inside containers in case glyph came from detection */ if ((otmp = sobj_at(glyphotyp, x, y)) == 0) - for (otmp = gl.level.buriedobjlist; otmp; otmp = otmp->nobj) + for (otmp = svl.level.buriedobjlist; otmp; otmp = otmp->nobj) if (otmp->ox == x && otmp->oy == y && otmp->otyp == glyphotyp) break; @@ -286,10 +311,10 @@ object_from_map(int glyph, coordxy x, coordxy y, struct obj **obj_p) if (otmp->oclass == COIN_CLASS) otmp->quan = 2L; /* to force pluralization */ else if (otmp->otyp == SLIME_MOLD) - otmp->spe = gc.context.current_fruit; /* give it a type */ + otmp->spe = svc.context.current_fruit; /* give it a type */ if (mtmp && has_mcorpsenm(mtmp)) { /* mimic as corpse/statue */ if (otmp->otyp == SLIME_MOLD) - /* override gc.context.current_fruit to avoid + /* override svc.context.current_fruit to avoid look, use 'O' to make new named fruit, look again giving different results when current_fruit changes */ otmp->spe = MCORPSENM(mtmp); @@ -424,8 +449,9 @@ look_at_monster( /* we know the hero sees a monster at this location, but if it's shown due to persistent monster detection he might remember something else */ - if (mtmp->mundetected || M_AP_TYPE(mtmp)) - mhidden_description(mtmp, MHID_PREFIX | MHID_ARTICLE, eos(buf)); + if (mtmp->mundetected || M_AP_TYPE(mtmp) || visible_region_at(x, y)) + mhidden_description(mtmp, MHID_PREFIX | MHID_ARTICLE | MHID_REGION, + eos(buf)); if (monbuf) { unsigned how_seen = howmonseen(mtmp); @@ -474,8 +500,8 @@ look_at_monster( if (Hallucination) { Strcat(monbuf, "paranoid delusion"); } else { - unsigned long mW = (gc.context.warntype.obj - | gc.context.warntype.polyd), + unsigned long mW = (svc.context.warntype.obj + | svc.context.warntype.polyd), m2 = mtmp->data->mflags2; const char *whom = ((mW & M2_HUMAN & m2) ? "human" : (mW & M2_ELF & m2) ? "elf" @@ -507,7 +533,7 @@ waterbody_name(coordxy x, coordxy y) { static char pooltype[40]; schar ltyp; - boolean hallucinate = Hallucination && !gp.program_state.gameover; + boolean hallucinate = Hallucination && !program_state.gameover; if (!isok(x, y)) return "drink"; /* should never happen */ @@ -580,6 +606,8 @@ ice_descr(coordxy x, coordxy y, char *outbuf) } else { long time_left = spot_time_left(x, y, MELT_ICE_AWAY); + /* other, real ice thickness/strength terminology exists but seems + to be too unfamiliar for nethack's use */ iflags.ice_rating = !time_left ? 0 /* solid */ : (time_left > 1000L) ? 1 /* sturdy */ : (time_left > 100L) ? 2 /* steady */ @@ -649,8 +677,6 @@ lookat(coordxy x, coordxy y, char *buf, char *monbuf) Sprintf(buf, "interior of %s", mon_nam(u.ustuck)); pm = u.ustuck->data; } else if (glyph_is_monster(glyph)) { - gb.bhitpos.x = x; - gb.bhitpos.y = y; if ((mtmp = m_at(x, y)) != 0) { look_at_monster(buf, monbuf, mtmp, x, y); pm = mtmp->data; @@ -713,8 +739,9 @@ lookat(coordxy x, coordxy y, char *buf, char *monbuf) Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud"); break; case S_pool: - case S_water: + case S_water: /* was Plane of Water, now that or "wall of water" */ case S_lava: + case S_lavawall: case S_ice: /* for hallucination; otherwise defsyms[] would be fine */ Strcpy(buf, waterbody_name(x, y)); break; @@ -1102,7 +1129,7 @@ add_cmap_descr( if (absidx == S_pool) idx = S_pool; } else if (absidx == S_pool || idx == S_water - || idx == S_lava || idx == S_ice) { + || idx == S_lava || idx == S_lavawall || idx == S_ice) { /* replace some descriptions (x_str) with waterbody_name() */ schar save_ltyp = levl[cc.x][cc.y].typ; long save_prop = EHalluc_resistance; @@ -1121,26 +1148,34 @@ add_cmap_descr( it's not pool so must be one of water/lava/ice to get here */ levl[cc.x][cc.y].typ = (idx == S_water) ? WATER : (idx == S_lava) ? LAVAPOOL - : ICE; + : (idx == S_lavawall) ? LAVAWALL + : ICE; } EHalluc_resistance = 1; Strcpy(mbuf, waterbody_name(cc.x, cc.y)); EHalluc_resistance = save_prop; levl[cc.x][cc.y].typ = save_ltyp; - /* shorten the feedback for farlook/quicklook: "a pool or ..." */ + /* shorten the feedback for farlook/quicklook: "pool or ..." */ if (!strcmp(mbuf, "pool of water")) mbuf[4] = '\0'; else if (!strcmp(mbuf, "molten lava")) Strcpy(mbuf, "lava"); x_str = mbuf; + /* avoid "an ice" and so forth; "a pool", "a moat", and + "a wall of ..." are grammatically correct but make + "a pool or a moat or a wall of water" become too verbose */ article = !(!strncmp(x_str, "water", 5) || !strncmp(x_str, "ice", 3) + || !strncmp(x_str, "pool", 4) + || !strncmp(x_str, "moat", 4) || !strncmp(x_str, "lava", 4) || !strncmp(x_str, "swamp", 5) || !strncmp(x_str, "molten", 6) || !strncmp(x_str, "shallow", 7) || !strncmp(x_str, "limitless", 9) + || !strncmp(x_str, "wall of lava", 12) + || !strncmp(x_str, "wall of water", 13) /* ice while hallucinating */ || !strncmp(x_str, "frozen", 6) /* thawing ice ("solid ice", "thin ice", &c) */ @@ -1192,7 +1227,7 @@ do_screen_description( skipped_venom = 0, found = 0; /* count of matching syms found */ boolean hit_trap, need_to_look = FALSE, submerged = (Underwater && !Is_waterlevel(&u.uz)), - hallucinate = (Hallucination && !gp.program_state.gameover); + hallucinate = (Hallucination && !program_state.gameover); const char *x_str; nhsym tmpsym; glyph_info glyphinfo = nul_glyphinfo; @@ -1379,15 +1414,24 @@ do_screen_description( for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) { /* * Index hackery: we want - * "a pool or a moat or a wall of water or lava" + * "pool or moat or wall of water or lava or wall of lava" * rather than - * "a pool or a moat or lava or a wall of water" + * "pool or moat or lava or wall of lava or wall of water" * but S_lava comes before S_water so 'i' reaches it sooner. * Use 'alt_i' for the rest of the loop to behave as if their * places were swapped. + * This was much simpler when it just exchanged water and lava. + * Now it rotates water to the first of (lava, lavawall, water) + * lava to the middle of (lava, lavawall, water), and lavawall + * to last of (lava, lavawall, water); other values are used + * as-is. + * If S_water (and corresponding tile) were renumbered, this + * hackery could go away. */ - alt_i = ((i != S_water && i != S_lava) ? i /* as-is */ - : (S_water + S_lava - i)); /* swap water and lava */ + alt_i = (i == S_lava) ? S_water /* do water first (of these 3) */ + : (i == S_lavawall) ? S_lava /* process lava second */ + : (i == S_water) ? S_lavawall /* and wall of lava third */ + : i; /* other; handle in defsyms[] order */ x_str = defsyms[alt_i].explanation; /* cmap includes beams, shield effects, swallow boundaries, and explosions; skip all of those */ @@ -1424,7 +1468,9 @@ do_screen_description( if (alt_i == S_altar || is_cmap_trap(alt_i) || (hallucinate && (alt_i == S_water /* S_pool already done */ - || alt_i == S_lava || alt_i == S_ice)) + || alt_i == S_lava + || alt_i == S_lavawall + || alt_i == S_ice)) || alt_i == S_engroom || alt_i == S_engrcorr || alt_i == S_grave) /* 'need_to_look' to report engraving */ need_to_look = TRUE; @@ -1879,8 +1925,6 @@ look_all( if (glyph_is_monster(glyph)) { struct monst *mtmp; - gb.bhitpos.x = x; /* [is this actually necessary?] */ - gb.bhitpos.y = y; if (u_at(x, y) && canspotself()) { (void) self_lookat(lookbuf); ++count; @@ -2050,7 +2094,7 @@ look_engrs(boolean nearby) if (!e) continue; glyph = glyph_at(x, y); - sym = ((levl[x][y].typ == GRAVE || gl.lastseentyp[x][y] == GRAVE) + sym = ((levl[x][y].typ == GRAVE || svl.lastseentyp[x][y] == GRAVE) ? S_grave : (levl[x][y].typ == CORR) ? S_engrcorr : S_engroom); diff --git a/src/pickup.c b/src/pickup.c index a215d4ff8..75e685b97 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 pickup.c $NHDT-Date: 1707521383 2024/02/09 23:29:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.370 $ */ +/* NetHack 3.7 pickup.c $NHDT-Date: 1720074481 2024/07/04 06:28:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.374 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -312,7 +312,7 @@ force_decor(boolean via_probing) iflags.prev_decor = STONE; (void) describe_decor(); gd.decor_fumble_override = gd.decor_levitate_override = FALSE; - gl.lastseentyp[u.ux][u.uy] = levl[u.ux][u.uy].typ; + svl.lastseentyp[u.ux][u.uy] = levl[u.ux][u.uy].typ; } void @@ -421,14 +421,14 @@ check_here(boolean picked_some) } /* count the objects here */ - for (obj = gl.level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) { + for (obj = svl.level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) { if (obj != uchain) ct++; } /* If there are objects here, take a look. */ if (ct) { - if (gc.context.run) + if (svc.context.run) nomul(0); flush_screen(1); (void) look_here(ct, lhflags); @@ -681,7 +681,7 @@ pickup(int what) /* should be a long */ struct trap *t; /* no auto-pick if no-pick move, nothing there, or in a pool */ - if (autopickup && (gc.context.nopick || !OBJ_AT(u.ux, u.uy) + if (autopickup && (svc.context.nopick || !OBJ_AT(u.ux, u.uy) || (is_pool(u.ux, u.uy) && !Underwater) || is_lava(u.ux, u.uy))) { if (flags.mention_decor) @@ -693,16 +693,17 @@ pickup(int what) /* should be a long */ t = t_at(u.ux, u.uy); if (!can_reach_floor(t && is_pit(t->ttyp))) { (void) describe_decor(); /* even when !flags.mention_decor */ - if ((gm.multi && !gc.context.run) || (autopickup && !flags.pickup) + if ((gm.multi && !svc.context.run) + || (autopickup && !flags.pickup) || (t && (uteetering_at_seen_pit(t) || uescaped_shaft(t)))) read_engr_at(u.ux, u.uy); return 0; } - /* multi && !gc.context.run means they are in the middle of some other - * action, or possibly paralyzed, sleeping, etc.... and they just - * teleported onto the object. They shouldn't pick it up. + /* multi && !svc.context.run means they are in the middle of some + * other action, or possibly paralyzed, sleeping, etc.... and they + * just teleported onto the object. They shouldn't pick it up. */ - if ((gm.multi && !gc.context.run) + if ((gm.multi && !svc.context.run) || (autopickup && !flags.pickup) || notake(gy.youmonst.data)) { check_here(FALSE); @@ -713,14 +714,14 @@ pickup(int what) /* should be a long */ } /* if there's anything here, stop running */ - if (OBJ_AT(u.ux, u.uy) && gc.context.run && gc.context.run != 8 - && !gc.context.nopick) + if (OBJ_AT(u.ux, u.uy) && svc.context.run && svc.context.run != 8 + && !svc.context.nopick) nomul(0); } add_valid_menu_class(0); /* reset */ if (!u.uswallow) { - objchain_p = &gl.level.objects[u.ux][u.uy]; + objchain_p = &svl.level.objects[u.ux][u.uy]; traverse_how = BY_NEXTHERE; } else { objchain_p = &u.ustuck->minvent; @@ -2005,7 +2006,7 @@ container_at(coordxy x, coordxy y, boolean countem) struct obj *cobj, *nobj; int container_count = 0; - for (cobj = gl.level.objects[x][y]; cobj; cobj = nobj) { + for (cobj = svl.level.objects[x][y]; cobj; cobj = nobj) { nobj = cobj->nexthere; if (Is_container(cobj)) { container_count++; @@ -2077,7 +2078,7 @@ do_loot_cont( int res = ECMD_OK; #if 0 - if (ccount < 2 && (gl.level.objects[cobj->ox][cobj->oy] == cobj)) + if (ccount < 2 && (svl.level.objects[cobj->ox][cobj->oy] == cobj)) pline("%s locked.", cobj->lknown ? "It is" : "Hmmm, it turns out to be"); else @@ -2105,7 +2106,7 @@ do_loot_cont( res = ECMD_TIME; /* attempting to untrap or unlock might trigger a trap which destroys 'cobj'; inform caller if that happens */ - for (otmp = gl.level.objects[ox][oy]; otmp; + for (otmp = svl.level.objects[ox][oy]; otmp; otmp = otmp->nexthere) if (otmp == cobj) break; @@ -2117,7 +2118,8 @@ do_loot_cont( && res != ECMD_TIME && ccount == 1 && u_have_forceable_weapon()) { /* single container, and we could #force it open... */ - cmdq_add_ec(CQ_CANNED, doforce); /* doforce asks for confirmation */ + /* note: doforce asks for confirmation */ + cmdq_add_ec(CQ_CANNED, doforce); ga.abort_looting = TRUE; } } @@ -2223,12 +2225,12 @@ doloot_core(void) win = create_nhwindow(NHW_MENU); start_menu(win, MENU_BEHAVE_STANDARD); - for (cobj = gl.level.objects[cc.x][cc.y]; cobj; + for (cobj = svl.level.objects[cc.x][cc.y]; cobj; cobj = cobj->nexthere) if (Is_container(cobj)) { any.a_obj = cobj; - add_menu(win, &nul_glyphinfo, &any, 0, 0, - ATR_NONE, clr, doname(cobj), MENU_ITEMFLAGS_NONE); + add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr, + doname(cobj), MENU_ITEMFLAGS_NONE); } end_menu(win, "Loot which containers?"); n = select_menu(win, PICK_ANY, &pick_list); @@ -2249,7 +2251,7 @@ doloot_core(void) if (n != 0) c = 'y'; } else { - for (cobj = gl.level.objects[cc.x][cc.y]; cobj; cobj = nobj) { + for (cobj = svl.level.objects[cc.x][cc.y]; cobj; cobj = nobj) { nobj = cobj->nexthere; if (Is_container(cobj)) { @@ -2334,7 +2336,8 @@ reverse_loot(void) if (!rn2(3)) { /* n objects: 1/(n+1) chance per object, 1/(n+1) to fall off end */ - for (n = inv_cnt(TRUE), otmp = gi.invent; otmp; --n, otmp = otmp->nobj) + for (n = inv_cnt(TRUE), otmp = gi.invent; otmp; + --n, otmp = otmp->nobj) if (!rn2(n + 1)) { prinv("You find old loot:", otmp, 0L); return TRUE; @@ -2363,7 +2366,7 @@ reverse_loot(void) if (g_at(x, y)) pline("Ok, now there is loot here."); } else { - /* find original coffers chest if present, otherwise use nearest one */ + /* find original coffers chest if present, otherwise use nearest */ otmp = 0; for (coffers = fobj; coffers; coffers = coffers->nobj) if (coffers->otyp == CHEST) { @@ -2608,16 +2611,18 @@ in_container(struct obj *obj) if (obj->oclass != COIN_CLASS) { /* sellobj() will take an unpaid item off the shop bill */ was_unpaid = obj->unpaid ? TRUE : FALSE; - /* don't sell when putting the item into your own container, - * but handle billing correctly */ - sellobj_state(gc.current_container->no_charge - ? SELL_DONTSELL : SELL_DELIBERATE); + if (gs.sellobj_first) { + /* don't sell when putting the item into your own container, + but handle billing correctly */ + sellobj_state(gc.current_container->no_charge + ? SELL_DONTSELL : SELL_DELIBERATE); + gs.sellobj_first = FALSE; + } sellobj(obj, u.ux, u.uy); - sellobj_state(SELL_NORMAL); } } if (Icebox && !age_is_relative(obj)) { - obj->age = gm.moves - obj->age; /* actual age */ + obj->age = svm.moves - obj->age; /* actual age */ /* stop any corpse timeouts when frozen */ if (obj->otyp == CORPSE) { if (obj->timed) { @@ -2644,9 +2649,9 @@ in_container(struct obj *obj) obfree(obj, (struct obj *) 0); /* if carried, shop goods will be flagged 'unpaid' and obfree() will handle bill issues, but if on floor, we need to put them on bill - before deleting them (non-shop items will be flagged 'no_charge') */ - if (floor_container - && costly_spot(gc.current_container->ox, gc.current_container->oy)) { + before deleting them (non-shop items will be flagged 'no_charge')*/ + if (floor_container && costly_spot(gc.current_container->ox, + gc.current_container->oy)) { struct obj save_no_charge; save_no_charge.no_charge = gc.current_container->no_charge; @@ -2756,7 +2761,7 @@ void removed_from_icebox(struct obj *obj) { if (!age_is_relative(obj)) { - obj->age = gm.moves - obj->age; /* actual age */ + obj->age = svm.moves - obj->age; /* actual age */ if (obj->otyp == CORPSE) { struct monst *m = get_mtraits(obj, FALSE); boolean iceT = m ? (m->data == &mons[PM_ICE_TROLL]) @@ -2845,7 +2850,7 @@ observe_quantum_cat(struct obj *box, boolean makecat, boolean givemsg) /* set_corpsenm() will start the rot timer that was removed when makemon() created SchroedingersBox; start it from now rather than from when this special corpse got created */ - deadcat->age = gm.moves; + deadcat->age = svm.moves; set_corpsenm(deadcat, PM_HOUSECAT); deadcat = oname(deadcat, sc, ONAME_NO_FLAGS); } @@ -2943,6 +2948,7 @@ use_container( long loss; ga.abort_looting = FALSE; + gs.sellobj_first = TRUE; /* in_container() should call sellobj_state() */ emptymsg[0] = '\0'; if (!u_handsy()) @@ -3176,6 +3182,7 @@ use_container( update_inventory(); } + sellobj_state(SELL_NORMAL); /* in case in_container() set it */ *objp = gc.current_container; /* might have become null */ if (gc.current_container) gc.current_container = 0; /* avoid hanging on to stale pointer */ @@ -3298,7 +3305,8 @@ menu_loot(int retry, boolean put_in) n_looted += res; } } - } else if (put_in && loot_justpicked && count_justpicked(gi.invent) == 1) { + } else if (put_in && loot_justpicked + && count_justpicked(gi.invent) == 1) { otmp = find_justpicked(gi.invent); if (otmp) { n_looted = 1; @@ -3411,7 +3419,8 @@ in_or_out_menu( if (more_containers) { any.a_int = 7; /* 'n' */ add_menu(win, &nul_glyphinfo, &any, menuselector[any.a_int], 0, - ATR_NONE, clr, "loot next container", MENU_ITEMFLAGS_SELECTED); + ATR_NONE, clr, "loot next container", + MENU_ITEMFLAGS_SELECTED); } any.a_int = 8; /* 'q' */ Strcpy(buf, alreadyused ? "done" : "do nothing"); @@ -3472,7 +3481,7 @@ choose_tip_container_menu(void) win = create_nhwindow(NHW_MENU); start_menu(win, MENU_BEHAVE_STANDARD); - for (otmp = gl.level.objects[u.ux][u.uy], i = 0; otmp; + for (otmp = svl.level.objects[u.ux][u.uy], i = 0; otmp; otmp = otmp->nexthere) if (Is_container(otmp)) { ++i; @@ -3556,7 +3565,8 @@ dotip(void) return res; /* else pick-from-gi.invent below */ } else { - for (cobj = gl.level.objects[cc.x][cc.y]; cobj; cobj = nobj) { + for (cobj = svl.level.objects[cc.x][cc.y]; cobj; + cobj = nobj) { nobj = cobj->nexthere; if (!Is_container(cobj)) continue; @@ -3679,7 +3689,8 @@ tipcontainer(struct obj *box) /* or bag */ if (tipcontainer_checks(box, targetbox, FALSE) != TIPCHECK_OK) return; - if (targetbox && tipcontainer_checks(targetbox, NULL, TRUE) != TIPCHECK_OK) + if (targetbox + && tipcontainer_checks(targetbox, NULL, TRUE) != TIPCHECK_OK) return; { diff --git a/src/pline.c b/src/pline.c index 811d5a2fe..010dea488 100644 --- a/src/pline.c +++ b/src/pline.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 pline.c $NHDT-Date: 1693083243 2023/08/26 20:54:03 $ $NHDT-Branch: keni-crashweb2 $:$NHDT-Revision: 1.124 $ */ +/* NetHack 3.7 pline.c $NHDT-Date: 1719819280 2024/07/01 07:34:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.130 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -157,10 +157,10 @@ vpline(const char *line, va_list the_args) if (!line || !*line) return; #ifdef HANGUPHANDLING - if (gp.program_state.done_hup) + if (program_state.done_hup) return; #endif - if (gp.program_state.wizkit_wishing) + if (program_state.wizkit_wishing) return; if (a11y.accessiblemsg && isok(a11y.msg_loc.x,a11y.msg_loc.y)) { @@ -509,7 +509,7 @@ livelog_printf(long ll_type, const char *line, ...) (void) vsnprintf(gamelogbuf, sizeof gamelogbuf, line, the_args); va_end(the_args); - gamelog_add(ll_type, gm.moves, gamelogbuf); + gamelog_add(ll_type, svm.moves, gamelogbuf); strNsubst(gamelogbuf, "\t", "_", 0); livelog_add(ll_type, gamelogbuf); } @@ -542,7 +542,7 @@ raw_printf(const char *line, ...) va_start(the_args, line); vraw_printf(line, the_args); va_end(the_args); - if (!gp.program_state.beyond_savefile_load) + if (!program_state.beyond_savefile_load) ge.early_raw_messages++; } @@ -567,7 +567,7 @@ vraw_printf(const char *line, va_list the_args) #if defined(MSGHANDLER) execplinehandler(line); #endif - if (!gp.program_state.beyond_savefile_load) + if (!program_state.beyond_savefile_load) ge.early_raw_messages++; } @@ -579,10 +579,10 @@ impossible(const char *s, ...) char pbuf2[BUFSZ]; va_start(the_args, s); - if (gp.program_state.in_impossible) + if (program_state.in_impossible) panic("impossible called impossible"); - gp.program_state.in_impossible = 1; + program_state.in_impossible = 1; (void) vsnprintf(pbuf, sizeof pbuf, s, the_args); va_end(the_args); pbuf[BUFSZ - 1] = '\0'; /* sanity */ @@ -594,8 +594,14 @@ impossible(const char *s, ...) pline("%s", pbuf); gp.pline_flags = 0; + if (program_state.in_sanity_check) { + /* skip rest of multi-line feedback */ + program_state.in_impossible = 0; + return; + } + Strcpy(pbuf2, "Program in disorder!"); - if (gp.program_state.something_worth_saving) + if (program_state.something_worth_saving) Strcat(pbuf2, " (Saving and reloading may fix this problem.)"); pline("%s", pbuf2); pline("Please report these messages to %s.", DEVTEAM_EMAIL); @@ -608,14 +614,14 @@ impossible(const char *s, ...) boolean report = ('y' == yn_function("Report now?", ynchars, 'n', FALSE)); - raw_print(""); // prove to the user the character was accepted + raw_print(""); /* prove to the user the character was accepted */ if (report) { submit_web_report(1, "Impossible", pbuf); } } #endif - gp.program_state.in_impossible = 0; + program_state.in_impossible = 0; } RESTORE_WARNING_FORMAT_NONLITERAL diff --git a/src/polyself.c b/src/polyself.c index 806192693..a40570f83 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -109,7 +109,7 @@ set_uasmon(void) which won't be known during the restore process: but BFlying and BStealth should be set correctly already in that case, so there's nothing to do */ - if (!gp.program_state.restoring) + if (!program_state.restoring) float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ polysense(); @@ -228,11 +228,11 @@ polyman(const char *fmt, const char *arg) struct kinfo *kptr = find_delayed_killer(POLYMORPH); if (kptr != (struct kinfo *) 0 && kptr->name[0]) { - gk.killer.format = kptr->format; - Strcpy(gk.killer.name, kptr->name); + svk.killer.format = kptr->format; + Strcpy(svk.killer.name, kptr->name); } else { - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, "self-genocide"); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, "self-genocide"); } dealloc_killer(kptr); done(GENOCIDED); @@ -275,9 +275,9 @@ change_sex(void) u.mfemale = !u.mfemale; max_rank_sz(); /* [this appears to be superfluous] */ if ((Upolyd ? u.mfemale : flags.female) && gu.urole.name.f) - Strcpy(gp.pl_character, gu.urole.name.f); + Strcpy(svp.pl_character, gu.urole.name.f); else - Strcpy(gp.pl_character, gu.urole.name.m); + Strcpy(svp.pl_character, gu.urole.name.m); if (!Upolyd) { u.umonnum = u.umonster; } else if (u.umonnum == PM_AMOROUS_DEMON) { @@ -413,8 +413,8 @@ newman(void) dead: /* we come directly here if experience level went to 0 or less */ urgent_pline( "Your new form doesn't seem healthy enough to survive."); - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, "unsuccessful polymorph"); + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, "unsuccessful polymorph"); done(DIED); /* must have been life-saved to get here */ newuhs(FALSE); @@ -617,7 +617,7 @@ polyself(int psflags) if (draconian) { do_merge: mntmp = armor_to_dragon(uarm->otyp); - if (!(gm.mvitals[mntmp].mvflags & G_GENOD)) { + if (!(svm.mvitals[mntmp].mvflags & G_GENOD)) { unsigned was_lit = uarm->lamplit; int arm_light = artifact_light(uarm) ? arti_light_radius(uarm) : 0; @@ -729,7 +729,7 @@ polymon(int mntmp) was_hiding_under = u.uundetected && hides_under(gy.youmonst.data); int mlvl, newMaxStr; - if (gm.mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ + if (svm.mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ You_feel("rather %s-ish.", pmname(&mons[mntmp], flags.female ? FEMALE : MALE)); exercise(A_WIS, TRUE); @@ -1346,8 +1346,8 @@ rehumanize(void) /* You can't revert back while unchanging */ if (Unchanging) { if (u.mh < 1) { - gk.killer.format = NO_KILLER_PREFIX; - Strcpy(gk.killer.name, "killed while stuck in creature form"); + svk.killer.format = NO_KILLER_PREFIX; + Strcpy(svk.killer.name, "killed while stuck in creature form"); done(DIED); /* can get to here if declining to die in explore or wizard mode; since we're wearing an amulet of unchanging we can't @@ -1373,9 +1373,9 @@ rehumanize(void) /* can only happen if some bit of code reduces u.uhp instead of u.mh while poly'd */ Your("old form was not healthy enough to survive."); - Sprintf(gk.killer.name, "reverting to unhealthy %s form", + Sprintf(svk.killer.name, "reverting to unhealthy %s form", gu.urace.adj); - gk.killer.format = KILLED_BY; + svk.killer.format = KILLED_BY; done(DIED); } nomul(0); @@ -1732,8 +1732,8 @@ dogaze(void) l_monnam(mtmp)); /* as if gazing at a sleeping anything is fruitful... */ urgent_pline("You turn to stone..."); - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, "deliberately meeting Medusa's gaze"); done(STONING); } @@ -1781,7 +1781,7 @@ dohide(void) } if (hides_under(gy.youmonst.data)) { long ct = 0L; - struct obj *otmp, *otop = gl.level.objects[u.ux][u.uy]; + struct obj *otmp, *otop = svl.level.objects[u.ux][u.uy]; if (!otop) { There("is nothing to hide under here."); @@ -2210,9 +2210,9 @@ polysense(void) { short warnidx = NON_PM; - gc.context.warntype.speciesidx = NON_PM; - gc.context.warntype.species = 0; - gc.context.warntype.polyd = 0; + svc.context.warntype.speciesidx = NON_PM; + svc.context.warntype.species = 0; + svc.context.warntype.polyd = 0; HWarn_of_mon &= ~FROMRACE; switch (u.umonnum) { @@ -2222,13 +2222,13 @@ polysense(void) break; case PM_VAMPIRE: case PM_VAMPIRE_LEADER: - gc.context.warntype.polyd = M2_HUMAN | M2_ELF; + svc.context.warntype.polyd = M2_HUMAN | M2_ELF; HWarn_of_mon |= FROMRACE; return; } if (ismnum(warnidx)) { - gc.context.warntype.speciesidx = warnidx; - gc.context.warntype.species = &mons[warnidx]; + svc.context.warntype.speciesidx = warnidx; + svc.context.warntype.species = &mons[warnidx]; HWarn_of_mon |= FROMRACE; } } @@ -2237,8 +2237,8 @@ polysense(void) boolean ugenocided(void) { - return ((gm.mvitals[gu.urole.mnum].mvflags & G_GENOD) - || (gm.mvitals[gu.urace.mnum].mvflags & G_GENOD)); + return ((svm.mvitals[gu.urole.mnum].mvflags & G_GENOD) + || (svm.mvitals[gu.urace.mnum].mvflags & G_GENOD)); } /* how hero feels "inside" after self-genocide of role or race */ diff --git a/src/potion.c b/src/potion.c index d97f274a9..25e5e4f0c 100644 --- a/src/potion.c +++ b/src/potion.c @@ -41,6 +41,7 @@ staticfn int dip_ok(struct obj *); staticfn int dip_hands_ok(struct obj *); staticfn void hold_potion(struct obj *, const char *, const char *, const char *); +staticfn void poof(struct obj *); staticfn int potion_dip(struct obj *obj, struct obj *potion); /* used to indicate whether quaff or dip has skipped an opportunity to @@ -570,31 +571,41 @@ dodrink(void) if (!otmp) return ECMD_CANCEL; - /* quan > 1 used to be left to useup(), but we need to force - the current potion to be unworn, and don't want to do - that for the entire stack when starting with more than 1. - [Drinking a wielded potion of polymorph can trigger a shape - change which causes hero's weapon to be dropped. In 3.4.x, - that led to an "object lost" panic since subsequent useup() - was no longer dealing with an inventory item. Unwearing - the current potion is intended to keep it in inventory.] */ - if (otmp->quan > 1L) { - otmp = splitobj(otmp, 1L); - otmp->owornmask = 0L; /* rest of original stuck unaffected */ - } else if (otmp->owornmask) { - remove_worn_item(otmp, FALSE); + /* + * 3.6: quan > 1 used to be left to useup(), but we need to + * force the current potion to be unworn, and don't want to do + * that for the entire stack when starting with more than 1. + * [Drinking a wielded potion of polymorph can trigger a shape + * change which causes hero's weapon to be dropped. In 3.4.x, + * that led to an "object lost" panic since subsequent useup() + * was no longer dealing with an inventory item. Unwearing + * the current potion is intended to keep it in inventory.] + * + * 3.7: switch back to relying on useup() unless the object is + * actually worn. Otherwise drinking a stack of unpaid potions + * one by one in a shop makes each one a separate used-up item + * for 'Ix' invent display and for itemized shop billing instead + * of having a single stack with quantity greater than 1. + */ + if (otmp->owornmask) { + if (otmp->quan > 1L) { + otmp = splitobj(otmp, 1L); + otmp->owornmask = 0L; /* rest of original stack is unaffected */ + } else { + remove_worn_item(otmp, FALSE); + } } otmp->in_use = TRUE; /* you've opened the stopper */ if (objdescr_is(otmp, "milky") - && !(gm.mvitals[PM_GHOST].mvflags & G_GONE) - && !rn2(POTION_OCCUPANT_CHANCE(gm.mvitals[PM_GHOST].born))) { + && !(svm.mvitals[PM_GHOST].mvflags & G_GONE) + && !rn2(POTION_OCCUPANT_CHANCE(svm.mvitals[PM_GHOST].born))) { ghost_from_bottle(); useup(otmp); return ECMD_TIME; } else if (objdescr_is(otmp, "smoky") - && !(gm.mvitals[PM_DJINNI].mvflags & G_GONE) - && !rn2(POTION_OCCUPANT_CHANCE(gm.mvitals[PM_DJINNI].born))) { + && !(svm.mvitals[PM_DJINNI].mvflags & G_GONE) + && !rn2(POTION_OCCUPANT_CHANCE(svm.mvitals[PM_DJINNI].born))) { djinni_from_bottle(otmp); useup(otmp); return ECMD_TIME; @@ -1887,7 +1898,7 @@ potionhit(struct monst *mon, struct obj *obj, int how) when inside a tended shop */ if (!shkp) /* if shkp was killed, unpaid ought to cleared already */ obj->unpaid = 0; - else if (gc.context.mon_moving) /* obj thrown by monster */ + else if (svc.context.mon_moving) /* obj thrown by monster */ subfrombill(obj, shkp); else /* obj thrown by hero */ (void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful, @@ -2369,6 +2380,14 @@ dip_into(void) return potion_dip(obj, potion); } +staticfn void +poof(struct obj *potion) +{ + if (potion->dknown) + trycall(potion); + useup(potion); +} + /* called by dodip() or dip_into() after obj and potion have been chosen */ staticfn int potion_dip(struct obj *obj, struct obj *potion) @@ -2393,8 +2412,10 @@ potion_dip(struct obj *obj, struct obj *potion) boolean useeit = !Blind || (obj == ublindf && Blindfolded_only); const char *obj_glows = Yobjnam2(obj, "glow"); - if (H2Opotion_dip(potion, obj, useeit, obj_glows)) - goto poof; + if (H2Opotion_dip(potion, obj, useeit, obj_glows)) { + poof(potion); + return ECMD_TIME; + } } else if (obj->otyp == POT_POLYMORPH || potion->otyp == POT_POLYMORPH) { /* some objects can't be polymorphed */ if (obj_unpolyable(obj->otyp == POT_POLYMORPH ? potion : obj)) { @@ -2424,7 +2445,8 @@ potion_dip(struct obj *obj, struct obj *potion) return ECMD_TIME; } else { pline1(nothing_seems_to_happen); - goto poof; + poof(potion); + return ECMD_TIME; } } potion->in_use = FALSE; /* didn't go poof */ @@ -2551,7 +2573,8 @@ potion_dip(struct obj *obj, struct obj *potion) if (potion->otyp == POT_WATER && obj->otyp == TOWEL) { pline_The("towel soaks it up!"); /* wetting towel already done via water_damage() in H2Opotion_dip */ - goto poof; + poof(potion); + return ECMD_TIME; } if (is_poisonable(obj)) { @@ -2564,19 +2587,23 @@ potion_dip(struct obj *obj, struct obj *potion) Strcpy(buf, The(xname(potion))); pline("%s forms a coating on %s.", buf, the(xname(obj))); obj->opoisoned = TRUE; - goto poof; + poof(potion); + return ECMD_TIME; } else if (obj->opoisoned && (potion->otyp == POT_HEALING || potion->otyp == POT_EXTRA_HEALING || potion->otyp == POT_FULL_HEALING)) { pline("A coating wears off %s.", the(xname(obj))); obj->opoisoned = 0; - goto poof; + poof(potion); + return ECMD_TIME; } } if (potion->otyp == POT_ACID) { - if (erode_obj(obj, 0, ERODE_CORRODE, EF_GREASE) != ER_NOTHING) - goto poof; + if (erode_obj(obj, 0, ERODE_CORRODE, EF_GREASE) != ER_NOTHING) { + poof(potion); + return ECMD_TIME; + } } if (potion->otyp == POT_OIL) { @@ -2726,12 +2753,6 @@ potion_dip(struct obj *obj, struct obj *potion) pline("Interesting..."); return ECMD_TIME; - - poof: - if (potion->dknown) - trycall(potion); - useup(potion); - return ECMD_TIME; } /* *monp grants a wish and then leaves the game */ diff --git a/src/pray.c b/src/pray.c index 71aed4e26..ee50fc10e 100644 --- a/src/pray.c +++ b/src/pray.c @@ -443,7 +443,8 @@ fix_worst_trouble(int trouble) if ((otmp = stuck_ring(uleft, RIN_SUSTAIN_ABILITY)) != 0) { if (otmp == uleft) what = leftglow; - } else if ((otmp = stuck_ring(uright, RIN_SUSTAIN_ABILITY)) != 0) { + } else if ((otmp = stuck_ring(uright, RIN_SUSTAIN_ABILITY)) + != 0) { if (otmp == uright) what = rightglow; } @@ -690,8 +691,8 @@ fry_by_god(aligntyp resp_god, boolean via_disintegration) { You("%s!", !via_disintegration ? "fry to a crisp" : "disintegrate into a pile of dust"); - gk.killer.format = KILLED_BY; - Sprintf(gk.killer.name, "the wrath of %s", align_gname(resp_god)); + svk.killer.format = KILLED_BY; + Sprintf(svk.killer.name, "the wrath of %s", align_gname(resp_god)); done(DIED); } @@ -848,7 +849,8 @@ gcrownu(void) case A_CHAOTIC: u.uevent.uhand_of_elbereth = 3; in_hand = u_wield_art(ART_STORMBRINGER); - already_exists = exist_artifact(RUNESWORD, artiname(ART_STORMBRINGER)); + already_exists = exist_artifact(RUNESWORD, + artiname(ART_STORMBRINGER)); what = (((already_exists && !in_hand) || class_gift != STRANGE_OBJECT) ? "take lives" : "steal souls"); @@ -1011,7 +1013,7 @@ give_spell(void) || carrying(MAGIC_MARKER)) break; } - otmp->otyp = rnd_class(gb.bases[SPBOOK_CLASS], SPE_BLANK_PAPER); + otmp->otyp = rnd_class(svb.bases[SPBOOK_CLASS], SPE_BLANK_PAPER); } /* * 25% chance of learning the spell directly instead of @@ -1220,7 +1222,7 @@ pleased(aligntyp g_align) } else if (u.uevent.uheard_tune < 2) { Soundeffect(se_divine_music, 50); You_hear("a divine music..."); - pline("It sounds like: \"%s\".", gt.tune); + pline("It sounds like: \"%s\".", svt.tune); u.uevent.uheard_tune++; record_achievement(ACH_TUNE); break; @@ -1350,8 +1352,8 @@ pleased(aligntyp g_align) of nutrition will be required. The increase gets throttled if it ever reaches 32K so that configurations using 16-bit ints are still viable. */ - if (gm.moves > 100000L) { - long incr = (gm.moves - 100000L) / 100L, + if (svm.moves > 100000L) { + long incr = (svm.moves - 100000L) / 100L, largest_ublesscnt_incr = (long) (LARGEST_INT - u.ublesscnt); if (incr > largest_ublesscnt_incr) @@ -1372,7 +1374,7 @@ water_prayer(boolean bless_water) long changed = 0; boolean other = FALSE, bc_known = !(Blind || Hallucination); - for (otmp = gl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { + for (otmp = svl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { /* turn water into (un)holy water */ if (otmp->otyp == POT_WATER && (bless_water ? !otmp->blessed : !otmp->cursed)) { @@ -1531,8 +1533,8 @@ offer_real_amulet(struct obj *otmp, aligntyp altaralign) /*[apparently shrug/snarl can be sensed without being seen]*/ pline("%s shrugs and retains dominion over %s,", Moloch, u_gname()); pline("then mercilessly snuffs out your life."); - Sprintf(gk.killer.name, "%s indifference", s_suffix(Moloch)); - gk.killer.format = KILLED_BY; + Sprintf(svk.killer.name, "%s indifference", s_suffix(Moloch)); + svk.killer.format = KILLED_BY; done(DIED); /* life-saved (or declined to die in wizard/explore mode) */ pline("%s snarls and tries again...", Moloch); @@ -1859,8 +1861,8 @@ dosacrifice(void) /* KMH, conduct */ if (!u.uconduct.gnostic++) - livelog_printf(LL_CONDUCT, - "rejected atheism by offering %s on an altar of %s", + livelog_printf(LL_CONDUCT, "rejected atheism" + " by offering %s on an altar of %s", corpse_xname(otmp, (const char *) 0, CXN_ARTICLE), a_gname()); @@ -1871,7 +1873,7 @@ dosacrifice(void) return ECMD_TIME; if (otmp->corpsenm == PM_ACID_BLOB - || (gm.moves <= peek_at_iced_corpse_age(otmp) + 50)) { + || (svm.moves <= peek_at_iced_corpse_age(otmp) + 50)) { value = mons[otmp->corpsenm].difficulty + 1; if (otmp->oeaten) value = eaten_stat(value, otmp); @@ -2066,9 +2068,9 @@ can_pray(boolean praying) /* false means no messages should be given */ if (gp.p_aligntyp == A_NONE) /* praying to Moloch */ gp.p_type = -2; - else if ((gp.p_trouble > 0) ? (u.ublesscnt > 200) /* big trouble */ - : (gp.p_trouble < 0) ? (u.ublesscnt > 100) /* minor difficulties */ - : (u.ublesscnt > 0)) /* not in trouble */ + else if ((gp.p_trouble > 0) ? (u.ublesscnt > 200) /* big trouble */ + : (gp.p_trouble < 0) ? (u.ublesscnt > 100) /* minor difficulty */ + : (u.ublesscnt > 0)) /* not in trouble */ gp.p_type = 0; /* too soon... */ else if ((int) Luck < 0 || u.ugangr || alignment < 0) gp.p_type = 1; /* too naughty... */ @@ -2096,7 +2098,7 @@ pray_revive(void) { struct obj *otmp; - for (otmp = gl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) if (otmp->otyp == CORPSE && has_omonst(otmp) && OMONST(otmp)->mtame && !OMONST(otmp)->isminion) break; @@ -2119,7 +2121,8 @@ dopray(void) * than just "y" (will also require "no" to decline). */ if (ParanoidPray) { - ok = paranoid_query(ParanoidConfirm, "Are you sure you want to pray?"); + ok = paranoid_query(ParanoidConfirm, + "Are you sure you want to pray?"); /* clear command recall buffer; otherwise ^A to repeat p(ray) would do so without confirmation (if 'ok') or do nothing (if '!ok') */ @@ -2586,7 +2589,7 @@ blocked_boulder(int dx, int dy) int nx, ny; long count = 0L; - for (otmp = gl.level.objects[u.ux + dx][u.uy + dy]; otmp; + for (otmp = svl.level.objects[u.ux + dx][u.uy + dy]; otmp; otmp = otmp->nexthere) { if (otmp->otyp == BOULDER) count += otmp->quan; diff --git a/src/priest.c b/src/priest.c index 108bf11a4..57de18440 100644 --- a/src/priest.c +++ b/src/priest.c @@ -91,6 +91,7 @@ move_special(struct monst *mtmp, boolean in_his_shop, schar appr, } } } +#undef GDIST if (mtmp->ispriest && avoid && nix == omx && niy == omy && onlineu(omx, omy)) { /* might as well move closer as long it's going to stay @@ -143,7 +144,7 @@ temple_occupied(char *array) char *ptr; for (ptr = array; *ptr; ptr++) - if (gr.rooms[*ptr - ROOMOFFSET].rtype == TEMPLE) + if (svr.rooms[*ptr - ROOMOFFSET].rtype == TEMPLE) return *ptr; return '\0'; } @@ -243,7 +244,7 @@ priestini( priest = makemon(prim, px, py, MM_EPRI); if (priest) { - EPRI(priest)->shroom = (schar) ((sroom - gr.rooms) + ROOMOFFSET); + EPRI(priest)->shroom = (schar) ((sroom - svr.rooms) + ROOMOFFSET); EPRI(priest)->shralign = Amask2align(levl[sx][sy].altarmask); EPRI(priest)->shrpos.x = sx; EPRI(priest)->shrpos.y = sy; @@ -364,7 +365,7 @@ priestname( /* same as distant_monnam(), more or less... */ if (do_hallu || !high_priest || reveal_high_priest || !Is_astralevel(&u.uz) - || m_next2u(mon) || gp.program_state.gameover) { + || m_next2u(mon) || program_state.gameover) { Strcat(pname, " of "); Strcat(pname, halu_gname(mon_aligntyp(mon))); } @@ -434,7 +435,7 @@ intemple(int roomno) sanctum = (priest->data == &mons[PM_HIGH_CLERIC] && (Is_sanctum(&u.uz) || In_endgame(&u.uz))); can_speak = !helpless(priest); - if (can_speak && !Deaf && gm.moves >= epri_p->intone_time) { + if (can_speak && !Deaf && svm.moves >= epri_p->intone_time) { unsigned save_priest = priest->ispriest; /* don't reveal the altar's owner upon temple entry in @@ -445,7 +446,7 @@ intemple(int roomno) pline("%s intones:", canseemon(priest) ? Monnam(priest) : "A nearby voice"); priest->ispriest = save_priest; - epri_p->intone_time = gm.moves + (long) d(10, 500); /* ~2505 */ + epri_p->intone_time = svm.moves + (long) d(10, 500); /* ~2505 */ /* make sure that we don't suppress entry message when we've just given its "priest intones" introduction */ epri_p->enter_time = 0L; @@ -463,7 +464,7 @@ intemple(int roomno) /* repeat visit, or attacked priest before entering */ msg1 = "You desecrate this place by your presence!"; } - } else if (gm.moves >= epri_p->enter_time) { + } else if (svm.moves >= epri_p->enter_time) { Sprintf(buf, "Pilgrim, you enter a %s place!", !shrined ? "desecrated" : "sacred"); msg1 = buf; @@ -473,7 +474,7 @@ intemple(int roomno) verbalize1(msg1); if (msg2) verbalize1(msg2); - epri_p->enter_time = gm.moves + (long) d(10, 100); /* ~505 */ + epri_p->enter_time = svm.moves + (long) d(10, 100); /* ~505 */ } if (!sanctum) { if (!shrined || !p_coaligned(priest) @@ -491,9 +492,9 @@ intemple(int roomno) /* give message if we haven't seen it recently or if alignment update has caused it to switch from forbidding to sense-of-peace or vice versa */ - if (gm.moves >= *this_time || *other_time >= *this_time) { + if (svm.moves >= *this_time || *other_time >= *this_time) { You(msg1, msg2); - *this_time = gm.moves + (long) d(10, 20); /* ~55 */ + *this_time = svm.moves + (long) d(10, 20); /* ~55 */ /* avoid being tricked by the RNG: switch might have just happened and previous random threshold could be larger */ if (*this_time <= *other_time) @@ -524,7 +525,7 @@ intemple(int roomno) if (!rn2(5) && (mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, MM_NOMSG)) != 0) { - int ngen = gm.mvitals[PM_GHOST].born; + int ngen = svm.mvitals[PM_GHOST].born; if (canspotmon(mtmp)) pline("A%s ghost appears next to you%c", ngen < 5 ? "n enormous" : "", @@ -672,9 +673,9 @@ priest_talk(struct monst *priest) SetVoice(priest, 0, 80, 0); verbalize("Thy selfless generosity is deeply appreciated."); if (money_cnt(gi.invent) < (offer * 2L) && coaligned) { - if (strayed && (gm.moves - u.ucleansed) > 5000L) { + if (strayed && (svm.moves - u.ucleansed) > 5000L) { u.ualign.record = 0; /* cleanse thee */ - u.ucleansed = gm.moves; + u.ucleansed = svm.moves; } else { adjalign(2); } @@ -769,7 +770,7 @@ ghod_hitsu(struct monst *priest) ax = x = EPRI(priest)->shrpos.x; ay = y = EPRI(priest)->shrpos.y; - troom = &gr.rooms[roomno - ROOMOFFSET]; + troom = &svr.rooms[roomno - ROOMOFFSET]; if (u_at(x, y) || !linedup(u.ux, u.uy, x, y, 1)) { if (IS_DOOR(levl[u.ux][u.uy].typ)) { @@ -901,4 +902,7 @@ restpriest(struct monst *mtmp, boolean ghostly) } } +#undef ALGN_SINNED +#undef ALGN_PIOUS + /*priest.c*/ diff --git a/src/quest.c b/src/quest.c index e2c363903..b554a664c 100644 --- a/src/quest.c +++ b/src/quest.c @@ -9,7 +9,7 @@ #include "quest.h" #define Not_firsttime (on_level(&u.uz0, &u.uz)) -#define Qstat(x) (gq.quest_status.x) +#define Qstat(x) (svq.quest_status.x) staticfn void on_start(void); staticfn void on_locate(void); @@ -411,16 +411,16 @@ nemesis_speaks(void) void nemesis_stinks(coordxy mx, coordxy my) { - boolean save_mon_moving = gc.context.mon_moving; + boolean save_mon_moving = svc.context.mon_moving; /* * Some nemeses (determined by caller) release a cloud of noxious * gas when they die. Don't make the hero be responsible for such * a cloud even if hero has just killed nemesis. */ - gc.context.mon_moving = TRUE; + svc.context.mon_moving = TRUE; create_gas_cloud(mx, my, 5, 8); - gc.context.mon_moving = save_mon_moving; + svc.context.mon_moving = save_mon_moving; } staticfn void diff --git a/src/questpgr.c b/src/questpgr.c index bacfbc01d..29ef494c8 100644 --- a/src/questpgr.c +++ b/src/questpgr.c @@ -114,7 +114,7 @@ find_quest_artifact(unsigned whichchains) qarti = find_qarti(gm.migrating_objs); } if (!qarti && (whichchains & (1 << OBJ_BURIED)) != 0) - qarti = find_qarti(gl.level.buriedobjlist); + qarti = find_qarti(svl.level.buriedobjlist); return qarti; } @@ -217,9 +217,9 @@ qtext_pronoun( : (lwhich == 'i') ? "them" : (lwhich == 'j') ? "their" : "?"; } else { - godgend = (who == 'd') ? gq.quest_status.godgend - : (who == 'l') ? gq.quest_status.ldrgend - : (who == 'n') ? gq.quest_status.nemgend + godgend = (who == 'd') ? svq.quest_status.godgend + : (who == 'l') ? svq.quest_status.ldrgend + : (who == 'n') ? svq.quest_status.nemgend : 2; /* default to neuter */ pnoun = (lwhich == 'h') ? genders[godgend].he : (lwhich == 'i') ? genders[godgend].him @@ -239,7 +239,7 @@ convert_arg(char c) switch (c) { case 'p': - str = gp.plname; + str = svp.plname; break; case 'c': str = (flags.female && gu.urole.name.f) ? gu.urole.name.f @@ -312,7 +312,7 @@ convert_arg(char c) str = Blind ? "sense" : "see"; break; case 'Z': - str = gd.dungeons[0].dname; + str = svd.dungeons[0].dname; break; case '%': str = "%"; @@ -456,7 +456,7 @@ staticfn boolean skip_pager(boolean common UNUSED) { /* WIZKIT: suppress plot feedback if starting with quest artifact */ - if (gp.program_state.wizkit_wishing) + if (program_state.wizkit_wishing) return TRUE; return FALSE; } @@ -637,12 +637,12 @@ qt_montype(void) if (rn2(5)) { qpm = gu.urole.enemy1num; - if (qpm != NON_PM && rn2(5) && !(gm.mvitals[qpm].mvflags & G_GENOD)) + if (qpm != NON_PM && rn2(5) && !(svm.mvitals[qpm].mvflags & G_GENOD)) return &mons[qpm]; return mkclass(gu.urole.enemy1sym, 0); } qpm = gu.urole.enemy2num; - if (qpm != NON_PM && rn2(5) && !(gm.mvitals[qpm].mvflags & G_GENOD)) + if (qpm != NON_PM && rn2(5) && !(svm.mvitals[qpm].mvflags & G_GENOD)) return &mons[qpm]; return mkclass(gu.urole.enemy2sym, 0); } diff --git a/src/read.c b/src/read.c index af36193bb..5d1a3c92d 100644 --- a/src/read.c +++ b/src/read.c @@ -1650,7 +1650,7 @@ seffect_light(struct obj **sobjp) } else { int pm = scursed ? PM_BLACK_LIGHT : PM_YELLOW_LIGHT; - if ((gm.mvitals[pm].mvflags & G_GONE)) { + if ((svm.mvitals[pm].mvflags & G_GONE)) { pline("Tiny lights sparkle in the air momentarily."); } else { /* surround with cancelled tame lights which won't explode */ @@ -1730,7 +1730,7 @@ seffect_amnesia(struct obj **sobjp) forget((!sblessed ? ALL_SPELLS : 0)); if (Hallucination) /* Ommmmmm! */ Your("mind releases itself from mundane concerns."); - else if (!strncmpi(gp.plname, "Maud", 4)) + else if (!strncmpi(svp.plname, "Maud", 4)) pline("As your mind turns inward on itself," " you forget everything else."); else if (rn2(2)) @@ -2003,7 +2003,7 @@ seffect_magic_mapping(struct obj **sobjp) int cval; if (is_scroll) { - if (gl.level.flags.nommap) { + if (svl.level.flags.nommap) { Your("mind is filled with crazy lines!"); if (Hallucination) pline("Wow! Modern art."); @@ -2024,7 +2024,7 @@ seffect_magic_mapping(struct obj **sobjp) gk.known = TRUE; } - if (gl.level.flags.nommap) { + if (svl.level.flags.nommap) { Your("%s spins as %s blocks the spell!", body_part(HEAD), something); make_confused(HConfusion + rnd(30), FALSE); @@ -2472,12 +2472,13 @@ litroom( int rx, ry; if (rnum >= 0) { - for (rx = gr.rooms[rnum].lx - 1; rx <= gr.rooms[rnum].hx + 1; rx++) - for (ry = gr.rooms[rnum].ly - 1; - ry <= gr.rooms[rnum].hy + 1; ry++) + for (rx = svr.rooms[rnum].lx - 1; rx <= svr.rooms[rnum].hx + 1; + rx++) + for (ry = svr.rooms[rnum].ly - 1; + ry <= svr.rooms[rnum].hy + 1; ry++) set_lit(rx, ry, (genericptr_t) (on ? &is_lit : (char *) 0)); - gr.rooms[rnum].rlit = on; + svr.rooms[rnum].rlit = on; } /* hallways remain dark on the rogue level */ } else if (is_art(obj, ART_SUNSWORD)) { @@ -2577,7 +2578,7 @@ do_class_genocide(void) if (mons[i].mlet == class) { if (!(mons[i].geno & G_GENO)) immunecnt++; - else if (gm.mvitals[i].mvflags & G_GENOD) + else if (svm.mvitals[i].mvflags & G_GENOD) gonecnt++; else goodcnt++; @@ -2618,7 +2619,7 @@ do_class_genocide(void) */ if (Your_Own_Role(i) || Your_Own_Race(i) || ((mons[i].geno & G_GENO) - && !(gm.mvitals[i].mvflags & G_GENOD))) { + && !(svm.mvitals[i].mvflags & G_GENOD))) { /* This check must be first since player monsters might * have G_GENOD or !G_GENO. */ @@ -2632,7 +2633,7 @@ do_class_genocide(void) def_monsyms[class].sym); } - gm.mvitals[i].mvflags |= (G_GENOD | G_NOCORPSE); + svm.mvitals[i].mvflags |= (G_GENOD | G_NOCORPSE); kill_genocided_monsters(); update_inventory(); /* eggs & tins */ pline("Wiped out all %s.", nam); @@ -2665,7 +2666,7 @@ do_class_genocide(void) gameover = TRUE; } } - } else if (gm.mvitals[i].mvflags & G_GENOD) { + } else if (svm.mvitals[i].mvflags & G_GENOD) { if (!gameover) pline("%s are already nonexistent.", upstart(nam)); } else if (!gameover) { @@ -2697,8 +2698,8 @@ do_class_genocide(void) } } if (gameover || u.uhp == -1) { - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, "scroll of genocide"); + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, "scroll of genocide"); if (gameover) done(GENOCIDED); } @@ -2738,7 +2739,8 @@ do_genocide( pline1(thats_enough_tries); return; } - Strcpy(promptbuf, "What type of monster do you want to genocide?"); + Strcpy(promptbuf, + "What type of monster do you want to genocide?"); if (i > 0) Snprintf(eos(promptbuf), sizeof promptbuf - strlen(promptbuf), " [enter %s]", @@ -2774,7 +2776,7 @@ do_genocide( } mndx = name_to_mon(buf, (int *) 0); - if (mndx == NON_PM || (gm.mvitals[mndx].mvflags & G_GENOD)) { + if (mndx == NON_PM || (svm.mvitals[mndx].mvflags & G_GENOD)) { pline("Such creatures %s exist in this world.", (mndx == NON_PM) ? "do not" : "no longer"); continue; @@ -2803,8 +2805,10 @@ do_genocide( * aren't supposed to be hampered by deafness.... */ if (flags.verbose) - pline("A thunderous voice booms through the caverns:"); + pline("A thunderous voice booms" + " through the caverns:"); SetVoice((struct monst *) 0, 0, 80, voice_deity); + /* FIXME? shouldn't this override deafness? */ verbalize("No, mortal! That will not be done."); } continue; @@ -2841,29 +2845,29 @@ do_genocide( livelog_printf(LL_GENOCIDE, "genocided %s", makeplural(buf)); /* setting no-corpse affects wishing and random tin generation */ - gm.mvitals[mndx].mvflags |= (G_GENOD | G_NOCORPSE); + svm.mvitals[mndx].mvflags |= (G_GENOD | G_NOCORPSE); pline("Wiped out %s%s.", which, (*which != 'a') ? buf : makeplural(buf)); if (killplayer) { u.uhp = -1; if (how & PLAYER) { - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, "genocidal confusion"); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, "genocidal confusion"); } else if (how & ONTHRONE) { /* player selected while on a throne */ - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, "imperious order"); + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, "imperious order"); } else { /* selected player deliberately, not confused */ - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, "scroll of genocide"); + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, "scroll of genocide"); } /* Polymorphed characters will die as soon as they're rehumanized. */ /* KMH -- Unchanging prevents rehumanization */ if (Upolyd && ptr != gy.youmonst.data) { - delayed_killer(POLYMORPH, gk.killer.format, gk.killer.name); + delayed_killer(POLYMORPH, svk.killer.format, svk.killer.name); You_feel("%s inside.", udeadinside()); } else done(GENOCIDED); @@ -2876,12 +2880,12 @@ do_genocide( int cnt = 0, census = monster_census(FALSE); if (!(mons[mndx].geno & G_UNIQ) - && !(gm.mvitals[mndx].mvflags & (G_GENOD | G_EXTINCT))) + && !(svm.mvitals[mndx].mvflags & (G_GENOD | G_EXTINCT))) for (i = rn1(3, 4); i > 0; i--) { if (!makemon(ptr, u.ux, u.uy, NO_MINVENT | MM_NOMSG)) break; /* couldn't make one */ ++cnt; - if (gm.mvitals[mndx].mvflags & G_EXTINCT) + if (svm.mvitals[mndx].mvflags & G_EXTINCT) break; /* just made last one */ } if (cnt) { diff --git a/src/region.c b/src/region.c index a3d7b6526..3a51ae15c 100644 --- a/src/region.c +++ b/src/region.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 region.c $NHDT-Date: 1707462965 2024/02/09 07:16:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.89 $ */ +/* NetHack 3.7 region.c $NHDT-Date: 1723580898 2024/08/13 20:28:18 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.98 $ */ /* Copyright (c) 1996 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -39,6 +39,7 @@ NhRegion *create_force_field(coordxy,coordxy,int,long); staticfn void reset_region_mids(NhRegion *); staticfn boolean is_hero_inside_gas_cloud(void); +staticfn void make_gas_cloud(NhRegion *, int, boolean) NONNULLARG1; static const callback_proc callbacks[] = { #define INSIDE_GAS_CLOUD 0 @@ -282,7 +283,7 @@ add_region(NhRegion *reg) NhRegion **tmp_reg; int i, j; - if (gm.max_regions <= gn.n_regions) { + if (gm.max_regions <= svn.n_regions) { tmp_reg = gr.regions; gr.regions = (NhRegion **) alloc((gm.max_regions + 10) * sizeof (NhRegion *)); @@ -293,8 +294,8 @@ add_region(NhRegion *reg) } gm.max_regions += 10; } - gr.regions[gn.n_regions] = reg; - gn.n_regions++; + gr.regions[svn.n_regions] = reg; + svn.n_regions++; /* Check for monsters inside the region */ for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++) for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) { @@ -341,16 +342,16 @@ remove_region(NhRegion *reg) { int i, x, y; - for (i = 0; i < gn.n_regions; i++) + for (i = 0; i < svn.n_regions; i++) if (gr.regions[i] == reg) break; - if (i == gn.n_regions) + if (i == svn.n_regions) return; /* remove region before potential newsym() calls, but don't free it yet */ - if (--gn.n_regions != i) - gr.regions[i] = gr.regions[gn.n_regions]; - gr.regions[gn.n_regions] = (NhRegion *) 0; + if (--svn.n_regions != i) + gr.regions[i] = gr.regions[svn.n_regions]; + gr.regions[svn.n_regions] = (NhRegion *) 0; /* Update screen if necessary */ reg->ttl = -2L; /* for visible_region_at */ @@ -386,9 +387,9 @@ clear_regions(void) { int i; - for (i = 0; i < gn.n_regions; i++) + for (i = 0; i < svn.n_regions; i++) free_region(gr.regions[i]); - gn.n_regions = 0; + svn.n_regions = 0; if (gm.max_regions > 0) free((genericptr_t) gr.regions); gm.max_regions = 0; @@ -412,7 +413,7 @@ run_regions(void) /* End of life ? */ /* Do it backward because the array will be modified */ - for (i = gn.n_regions - 1; i >= 0; i--) { + for (i = svn.n_regions - 1; i >= 0; i--) { if (gr.regions[i]->ttl == 0L) { if ((f_indx = gr.regions[i]->expire_f) == NO_CALLBACK || (*callbacks[f_indx])(gr.regions[i], (genericptr_t) 0)) @@ -421,7 +422,7 @@ run_regions(void) } /* Process remaining regions */ - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { /* Make the region age */ if (gr.regions[i]->ttl > 0L) gr.regions[i]->ttl--; @@ -447,12 +448,20 @@ run_regions(void) } } - if (gg.gas_cloud_diss_within) + if (gg.gas_cloud_diss_within) { pline_The("gas cloud around you dissipates."); - if (gg.gas_cloud_diss_seen) - You_see("%s dissipate.", - gg.gas_cloud_diss_seen == 1 - ? "a gas cloud" : "some gas clouds"); + /* normally won't see additional dissipation when within */ + /* FIXME? this assumes that additional dissipation is close by */ + if (u.xray_range <= 1) + gg.gas_cloud_diss_seen = 0; + gg.gas_cloud_diss_within = FALSE; + } + if (gg.gas_cloud_diss_seen) { + You_see("%s gas cloud%s dissipate.", + (gg.gas_cloud_diss_seen == 1) ? "a" : "some", + plur(gg.gas_cloud_diss_seen)); + gg.gas_cloud_diss_seen = 0; + } } /* @@ -464,7 +473,7 @@ in_out_region(coordxy x, coordxy y) int i, f_indx = 0; /* First check if hero can do the move */ - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { if (gr.regions[i]->attach_2_u) continue; if (inside_region(gr.regions[i], x, y) @@ -478,7 +487,7 @@ in_out_region(coordxy x, coordxy y) } /* Callbacks for the regions hero does leave */ - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { if (gr.regions[i]->attach_2_u) continue; if (hero_inside(gr.regions[i]) @@ -492,7 +501,7 @@ in_out_region(coordxy x, coordxy y) } /* Callbacks for the regions hero does enter */ - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { if (gr.regions[i]->attach_2_u) continue; if (!hero_inside(gr.regions[i]) @@ -517,7 +526,7 @@ m_in_out_region(struct monst *mon, coordxy x, coordxy y) int i, f_indx = 0; /* First check if mon can do the move */ - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { if (gr.regions[i]->attach_2_m == mon->m_id) continue; if (inside_region(gr.regions[i], x, y) @@ -531,7 +540,7 @@ m_in_out_region(struct monst *mon, coordxy x, coordxy y) } /* Callbacks for the regions mon does leave */ - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { if (gr.regions[i]->attach_2_m == mon->m_id) continue; if (mon_in_region(gr.regions[i], mon) @@ -543,7 +552,7 @@ m_in_out_region(struct monst *mon, coordxy x, coordxy y) } /* Callbacks for the regions mon does enter */ - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { if (gr.regions[i]->attach_2_m == mon->m_id) continue; if (!mon_in_region(gr.regions[i], mon) @@ -565,7 +574,7 @@ update_player_regions(void) { int i; - for (i = 0; i < gn.n_regions; i++) + for (i = 0; i < svn.n_regions; i++) if (!gr.regions[i]->attach_2_u && inside_region(gr.regions[i], u.ux, u.uy)) set_hero_inside(gr.regions[i]); @@ -581,7 +590,7 @@ update_monster_region(struct monst *mon) { int i; - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { if (inside_region(gr.regions[i], mon->mx, mon->my)) { if (!mon_in_region(gr.regions[i], mon)) add_mon_to_reg(gr.regions[i], mon); @@ -606,7 +615,7 @@ struct monst *monold, *monnew; { int i; - for (i = 0; i < gn.n_regions; i++) + for (i = 0; i < svn.n_regions; i++) if (mon_in_region(gr.regions[i], monold)) { remove_mon_from_reg(gr.regions[i], monold); add_mon_to_reg(gr.regions[i], monnew); @@ -621,13 +630,77 @@ remove_mon_from_regions(struct monst *mon) { int i; - for (i = 0; i < gn.n_regions; i++) + for (i = 0; i < svn.n_regions; i++) if (mon_in_region(gr.regions[i], mon)) remove_mon_from_reg(gr.regions[i], mon); } #endif /*0*/ +/* per-turn damage inflicted by visible region; hides details from caller */ +int +reg_damg(NhRegion *reg) +{ + int damg = (!reg->visible || reg->ttl == -2L) ? 0 : reg->arg.a_int; + + return damg; +} + +/* check whether current level has any visible regions */ +boolean +any_visible_region(void) +{ + int i; + + for (i = 0; i < svn.n_regions; i++) { + if (!gr.regions[i]->visible || gr.regions[i]->ttl == -2L) + continue; + return TRUE; + } + return FALSE; +} + +/* for the wizard mode #timeout command */ +void +visible_region_summary(winid win) +{ + NhRegion *reg; + char buf[BUFSZ], typbuf[QBUFSZ]; + int i, damg, hdr_done = 0; + const char *fldsep = iflags.menu_tab_sep ? "\t" : " "; + + for (i = 0; i < svn.n_regions; i++) { + reg = gr.regions[i]; + if (!reg->visible || reg->ttl == -2L) + continue; + + if (!hdr_done++) { + putstr(win, 0, ""); + putstr(win, 0, "Visible regions"); + } + /* + * TODO? sort the regions by time-to-live or by bounding box. + */ + + /* we display relative time (turns left) rather than absolute + (the turn when region will go away); + since time-to-live has already been decremented, regions + which are due to timeout on the next turn have ttl==0; + adding 1 is intended to make the display be less confusing */ + Sprintf(buf, "%5ld", reg->ttl + 1L); + damg = reg->arg.a_int; + if (damg) + Sprintf(typbuf, "poison gas (%d)", damg); + else + Strcpy(typbuf, "vapor"); + Sprintf(eos(buf), "%s%-16s", fldsep, typbuf); + Sprintf(eos(buf), "%s@[%d,%d..%d,%d]", fldsep, + reg->bounding_box.lx, reg->bounding_box.ly, + reg->bounding_box.hx, reg->bounding_box.hy); + putstr(win, 0, buf); + } +} + /* * Check if a spot is under a visible region (eg: gas cloud). * Returns NULL if not, otherwise returns region. @@ -637,7 +710,7 @@ visible_region_at(coordxy x, coordxy y) { int i; - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { if (!gr.regions[i]->visible || gr.regions[i]->ttl == -2L) continue; if (inside_region(gr.regions[i], x, y)) @@ -666,18 +739,20 @@ save_regions(NHFILE *nhfp) goto skip_lots; if (nhfp->structlevel) { /* timestamp */ - bwrite(nhfp->fd, (genericptr_t) &gm.moves, sizeof (gm.moves)); - bwrite(nhfp->fd, (genericptr_t) &gn.n_regions, sizeof (gn.n_regions)); + bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); + bwrite(nhfp->fd, (genericptr_t) &svn.n_regions, sizeof svn.n_regions); } - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { r = gr.regions[i]; if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->bounding_box, sizeof (NhRect)); + bwrite(nhfp->fd, (genericptr_t) &r->bounding_box, + sizeof (NhRect)); bwrite(nhfp->fd, (genericptr_t) &r->nrects, sizeof (short)); } for (j = 0; j < r->nrects; j++) { if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &r->rects[j], sizeof (NhRect)); + bwrite(nhfp->fd, (genericptr_t) &r->rects[j], + sizeof (NhRect)); } if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &r->attach_2_u, sizeof (boolean)); @@ -744,15 +819,15 @@ rest_regions(NHFILE *nhfp) if (ghostly) tmstamp = 0; else - tmstamp = (gm.moves - tmstamp); + tmstamp = (svm.moves - tmstamp); if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &gn.n_regions, sizeof (gn.n_regions)); + mread(nhfp->fd, (genericptr_t) &svn.n_regions, sizeof svn.n_regions); - gm.max_regions = gn.n_regions; - if (gn.n_regions > 0) - gr.regions = (NhRegion **) alloc(sizeof (NhRegion *) * gn.n_regions); - for (i = 0; i < gn.n_regions; i++) { + gm.max_regions = svn.n_regions; + if (svn.n_regions > 0) + gr.regions = (NhRegion **) alloc(svn.n_regions * sizeof (NhRegion *)); + for (i = 0; i < svn.n_regions; i++) { r = gr.regions[i] = (NhRegion *) alloc(sizeof (NhRegion)); if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &r->bounding_box, sizeof (NhRect)); @@ -834,7 +909,7 @@ rest_regions(NHFILE *nhfp) } /* remove expired regions, do not trigger the expire_f callback (yet!); also update monster lists if this data is coming from a bones file */ - for (i = gn.n_regions - 1; i >= 0; i--) { + for (i = svn.n_regions - 1; i >= 0; i--) { r = gr.regions[i]; if (r->ttl == 0L) remove_region(r); @@ -858,9 +933,9 @@ region_stats( /* other stats formats take one parameter; this takes two */ Sprintf(hdrbuf, hdrfmt, (long) sizeof (NhRegion), (long) sizeof (NhRect)); - *count = (long) gn.n_regions; /* might be 0 even though max_regions isn't */ + *count = (long) svn.n_regions; /* might be 0 even tho max_regions isn't */ *size = (long) gm.max_regions * (long) sizeof (NhRegion); - for (i = 0; i < gn.n_regions; ++i) { + for (i = 0; i < svn.n_regions; ++i) { rg = gr.regions[i]; *size += (long) rg->nrects * (long) sizeof (NhRect); if (rg->enter_msg) @@ -972,7 +1047,7 @@ create_force_field(coordxy x, coordxy y, int radius, long ttl) tmprect.hy--; } ff->ttl = ttl; - if (!gi.in_mklev && !gc.context.mon_moving) + if (!gi.in_mklev && !svc.context.mon_moving) set_heros_fault(ff); /* assume player has created it */ /* ff->can_enter_f = enter_force_field; */ /* ff->can_leave_f = enter_force_field; */ @@ -1021,11 +1096,13 @@ expire_gas_cloud(genericptr_t p1, genericptr_t p2 UNUSED) if (pass == 1) { if (!does_block(x, y, &levl[x][y])) unblock_point(x, y); - if (u_at(x, y)) - gg.gas_cloud_diss_within = TRUE; } else { /* pass==2 */ - if (cansee(x, y)) - gg.gas_cloud_diss_seen++; + if (!u.uswallow) { + if (u_at(x, y)) + gg.gas_cloud_diss_within = TRUE; + else if (cansee(x, y)) + gg.gas_cloud_diss_seen++; + } } } } @@ -1118,20 +1195,51 @@ is_hero_inside_gas_cloud(void) { int i; - for (i = 0; i < gn.n_regions; i++) + for (i = 0; i < svn.n_regions; i++) if (hero_inside(gr.regions[i]) && gr.regions[i]->inside_f == INSIDE_GAS_CLOUD) return TRUE; return FALSE; } +/* details of gas cloud creation which are common to create_gas_cloud() + and create_gas_cloud_selection() */ +staticfn void +make_gas_cloud( + NhRegion *cloud, + int damage, + boolean inside_cloud) +{ + if (!gi.in_mklev && !svc.context.mon_moving) + set_heros_fault(cloud); /* assume player has created it */ + cloud->inside_f = INSIDE_GAS_CLOUD; + cloud->expire_f = EXPIRE_GAS_CLOUD; + cloud->arg = cg.zeroany; + cloud->arg.a_int = damage; + cloud->visible = TRUE; + cloud->glyph = cmap_to_glyph(damage ? S_poisoncloud : S_cloud); + add_region(cloud); + + if (!gi.in_mklev && !inside_cloud && is_hero_inside_gas_cloud()) { + You("are enveloped in a cloud of %s!", + /* FIXME: "steam" is wrong if this cloud is just the trail of + a fog cloud's movement; changing to "vapor" would handle + that but seems a step backward when it really is steam */ + damage ? "noxious gas" : "steam"); + iflags.last_msg = PLNMSG_ENVELOPED_IN_GAS; + } +} + /* Create a gas cloud which starts at (x,y) and grows outward from it via * breadth-first search. * cloudsize is the number of squares the cloud will attempt to fill. * damage is how much it deals to afflicted creatures. */ #define MAX_CLOUD_SIZE 150 NhRegion * -create_gas_cloud(coordxy x, coordxy y, int cloudsize, int damage) +create_gas_cloud( + coordxy x, coordxy y, + int cloudsize, + int damage) { NhRegion *cloud; int i, j; @@ -1148,7 +1256,7 @@ create_gas_cloud(coordxy x, coordxy y, int cloudsize, int damage) /* a single-point cloud on hero and it deals no damage. probably a natural cause of being polyed. don't message about it */ - if (!gc.context.mon_moving && u_at(x, y) && cloudsize == 1 + if (!svc.context.mon_moving && u_at(x, y) && cloudsize == 1 && (!damage || (damage && m_poisongas_ok(&gy.youmonst) == M_POISONGAS_OK))) inside_cloud = TRUE; @@ -1172,13 +1280,13 @@ create_gas_cloud(coordxy x, coordxy y, int cloudsize, int damage) for (i = 4; i > 0; --i) { coordxy swapidx = rn2(i); coord tmp = dirs[swapidx]; - dirs[swapidx] = dirs[i-1]; - dirs[i-1] = tmp; + + dirs[swapidx] = dirs[i - 1]; + dirs[i - 1] = tmp; } int nvalid = 0; /* # of valid adjacent spots */ for (i = 0; i < 4; ++i) { - /* try all 4 directions */ - + /* try all 4 cardinal directions */ int dx = dirs[i].x, dy = dirs[i].y; boolean isunpicked = TRUE; @@ -1222,28 +1330,15 @@ create_gas_cloud(coordxy x, coordxy y, int cloudsize, int damage) /* If cloud was constrained in small space, give it more time to live. */ cloud->ttl = (cloud->ttl * cloudsize) / newidx; - if (!gi.in_mklev && !gc.context.mon_moving) - set_heros_fault(cloud); /* assume player has created it */ - cloud->inside_f = INSIDE_GAS_CLOUD; - cloud->expire_f = EXPIRE_GAS_CLOUD; - cloud->arg = cg.zeroany; - cloud->arg.a_int = damage; - cloud->visible = TRUE; - cloud->glyph = cmap_to_glyph(damage ? S_poisoncloud : S_cloud); - add_region(cloud); - - if (!gi.in_mklev && !inside_cloud && is_hero_inside_gas_cloud()) { - You("are enveloped in a cloud of %s!", - damage ? "noxious gas" : "steam"); - iflags.last_msg = PLNMSG_ENVELOPED_IN_GAS; - } - + make_gas_cloud(cloud, damage, inside_cloud); return cloud; } /* create a single gas cloud from selection */ NhRegion * -create_gas_cloud_selection(struct selectionvar *sel, int damage) +create_gas_cloud_selection( + struct selectionvar *sel, + int damage) { NhRegion *cloud; NhRect tmprect; @@ -1262,19 +1357,7 @@ create_gas_cloud_selection(struct selectionvar *sel, int damage) add_rect_to_reg(cloud, &tmprect); } - if (!gi.in_mklev && !gc.context.mon_moving) - set_heros_fault(cloud); /* assume player has created it */ - cloud->inside_f = INSIDE_GAS_CLOUD; - cloud->expire_f = EXPIRE_GAS_CLOUD; - cloud->arg = cg.zeroany; - cloud->arg.a_int = damage; - cloud->visible = TRUE; - cloud->glyph = cmap_to_glyph(damage ? S_poisoncloud : S_cloud); - add_region(cloud); - - if (!gi.in_mklev && !inside_cloud && is_hero_inside_gas_cloud()) - You("are enveloped in a cloud of %s!", - damage ? "noxious gas" : "steam"); + make_gas_cloud(cloud, damage, inside_cloud); return cloud; } @@ -1285,7 +1368,7 @@ region_danger(void) { int i, f_indx, n = 0; - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { /* only care about regions that hero is in */ if (!hero_inside(gr.regions[i])) continue; @@ -1313,7 +1396,7 @@ region_safety(void) NhRegion *r = 0; int i, f_indx, n = 0; - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { /* only care about regions that hero is in */ if (!hero_inside(gr.regions[i])) continue; diff --git a/src/restore.c b/src/restore.c index 4d587ce9f..63c038124 100644 --- a/src/restore.c +++ b/src/restore.c @@ -67,7 +67,7 @@ extern int amii_numcolors; in an implicit conversion; this macro does it explicitly */ #define Mread(fd,adr,siz) mread((fd), (genericptr_t) (adr), (unsigned) (siz)) -/* Recalculate gl.level.objects[x][y], since this info was not saved. */ +/* Recalculate svl.level.objects[x][y], since this info was not saved. */ staticfn void find_lev_obj(void) { @@ -77,7 +77,7 @@ find_lev_obj(void) for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) - gl.level.objects[x][y] = (struct obj *) 0; + svl.level.objects[x][y] = (struct obj *) 0; /* * Reverse the entire fobj chain, which is necessary so that we can @@ -92,7 +92,7 @@ find_lev_obj(void) } /* fobj should now be empty */ - /* Set gl.level.objects (as well as reversing the chain back again) */ + /* Set svl.level.objects (as well as reversing the chain back again) */ while ((otmp = fobjtmp) != 0) { fobjtmp = otmp->nobj; place_object(otmp, otmp->ox, otmp->oy); @@ -131,7 +131,7 @@ restlevchn(NHFILE *nhfp) int cnt = 0; s_level *tmplev, *x; - gs.sp_levchn = (s_level *) 0; + svs.sp_levchn = (s_level *) 0; if (nhfp->structlevel) Mread(nhfp->fd, &cnt, sizeof cnt); @@ -140,10 +140,10 @@ restlevchn(NHFILE *nhfp) if (nhfp->structlevel) Mread(nhfp->fd, tmplev, sizeof *tmplev); - if (!gs.sp_levchn) - gs.sp_levchn = tmplev; + if (!svs.sp_levchn) + svs.sp_levchn = tmplev; else { - for (x = gs.sp_levchn; x->next; x = x->next) + for (x = svs.sp_levchn; x->next; x = x->next) ; x->next = tmplev; } @@ -171,10 +171,10 @@ restdamage(NHFILE *nhfp) Mread(nhfp->fd, tmp_dam, sizeof *tmp_dam); if (ghostly) - tmp_dam->when += (gm.moves - go.omoves); + tmp_dam->when += (svm.moves - go.omoves); - tmp_dam->next = gl.level.damagelist; - gl.level.damagelist = tmp_dam; + tmp_dam->next = svl.level.damagelist; + svl.level.damagelist = tmp_dam; } while (--counter > 0); } @@ -270,7 +270,7 @@ restobjchn(NHFILE *nhfp, boolean frozen) * immediately after old player died. */ if (ghostly && !frozen && !age_is_relative(otmp)) - otmp->age = gm.moves - go.omoves + otmp->age; + otmp->age = svm.moves - go.omoves + otmp->age; /* get contents of a container or statue */ if (Has_contents(otmp)) { @@ -285,12 +285,12 @@ restobjchn(NHFILE *nhfp, boolean frozen) otmp->bypass = 0; if (!ghostly) { /* fix the pointers */ - if (otmp->o_id == gc.context.victual.o_id) - gc.context.victual.piece = otmp; - if (otmp->o_id == gc.context.tin.o_id) - gc.context.tin.tin = otmp; - if (otmp->o_id == gc.context.spbook.o_id) - gc.context.spbook.book = otmp; + if (otmp->o_id == svc.context.victual.o_id) + svc.context.victual.piece = otmp; + if (otmp->o_id == svc.context.tin.o_id) + svc.context.tin.tin = otmp; + if (otmp->o_id == svc.context.spbook.o_id) + svc.context.spbook.book = otmp; } otmp2 = otmp; } @@ -439,8 +439,8 @@ restmonchn(NHFILE *nhfp) restpriest(mtmp, ghostly); if (!ghostly) { - if (mtmp->m_id == gc.context.polearm.m_id) - gc.context.polearm.hitmon = mtmp; + if (mtmp->m_id == svc.context.polearm.m_id) + svc.context.polearm.hitmon = mtmp; } mtmp2 = mtmp; } @@ -527,13 +527,13 @@ restgamestate(NHFILE *nhfp) return FALSE; } - newgamecontext = gc.context; /* copy statically init'd context */ + newgamecontext = svc.context; /* copy statically init'd context */ if (nhfp->structlevel) - Mread(nhfp->fd, &gc.context, sizeof gc.context); - gc.context.warntype.species = (ismnum(gc.context.warntype.speciesidx)) - ? &mons[gc.context.warntype.speciesidx] + Mread(nhfp->fd, &svc.context, sizeof svc.context); + svc.context.warntype.species = (ismnum(svc.context.warntype.speciesidx)) + ? &mons[svc.context.warntype.speciesidx] : (struct permonst *) 0; - /* gc.context.victual.piece, .tin.tin, .spellbook.book, and .polearm.hitmon + /* context.victual.piece, .tin.tin, .spellbook.book, and .polearm.hitmon are pointers which get set to Null during save and will be recovered via corresponding o_id or m_id while objs or mons are being restored */ @@ -613,7 +613,7 @@ restgamestate(NHFILE *nhfp) iflags.deferred_X = FALSE; iflags.perm_invent = defer_perm_invent; flags = newgameflags; - gc.context = newgamecontext; + svc.context = newgamecontext; gy.youmonst = cg.zeromonst; return FALSE; } @@ -641,7 +641,7 @@ restgamestate(NHFILE *nhfp) gm.migrating_mons = restmonchn(nhfp); if (nhfp->structlevel) { - Mread(nhfp->fd, &gm.mvitals[0], sizeof gm.mvitals); + Mread(nhfp->fd, &svm.mvitals[0], sizeof svm.mvitals); } /* @@ -669,17 +669,17 @@ restgamestate(NHFILE *nhfp) restore_dungeon(nhfp); restlevchn(nhfp); if (nhfp->structlevel) { - Mread(nhfp->fd, &gm.moves, sizeof gm.moves); + Mread(nhfp->fd, &svm.moves, sizeof svm.moves); /* hero_seq isn't saved and restored because it can be recalculated */ - gh.hero_seq = gm.moves << 3; /* normally handled in moveloop() */ - Mread(nhfp->fd, &gq.quest_status, sizeof gq.quest_status); - Mread(nhfp->fd, gs.spl_book, (MAXSPELL + 1) * sizeof (struct spell)); + gh.hero_seq = svm.moves << 3; /* normally handled in moveloop() */ + Mread(nhfp->fd, &svq.quest_status, sizeof svq.quest_status); + Mread(nhfp->fd, svs.spl_book, (MAXSPELL + 1) * sizeof (struct spell)); } restore_artifacts(nhfp); restore_oracles(nhfp); if (nhfp->structlevel) { - Mread(nhfp->fd, gp.pl_character, sizeof gp.pl_character); - Mread(nhfp->fd, gp.pl_fruit, sizeof gp.pl_fruit); + Mread(nhfp->fd, svp.pl_character, sizeof svp.pl_character); + Mread(nhfp->fd, svp.pl_fruit, sizeof svp.pl_fruit); } freefruitchn(gf.ffruit); /* clean up fruit(s) made by initoptions() */ gf.ffruit = loadfruitchn(nhfp); @@ -721,7 +721,7 @@ restlevelfile(xint8 ltmp) nhfp = create_levelfile(ltmp, whynot); if (!nhfp) { /* failed to create a new file; don't attempt to make a panic save */ - gp.program_state.something_worth_saving = 0; + program_state.something_worth_saving = 0; panic("restlevelfile: %s", whynot); } bufon(nhfp->fd); @@ -738,9 +738,9 @@ dorecover(NHFILE *nhfp) int rtmp; /* suppress map display if some part of the code tries to update that */ - gp.program_state.restoring = REST_GSTATE; + program_state.restoring = REST_GSTATE; - get_plname_from_file(nhfp, gp.plname); + get_plname_from_file(nhfp, svp.plname); getlev(nhfp, 0, (xint8) 0); if (!restgamestate(nhfp)) { NHFILE tnhfp; @@ -755,7 +755,7 @@ dorecover(NHFILE *nhfp) close_nhfile(nhfp); (void) delete_savefile(); u.usteed_mid = u.ustuck_mid = 0; - gp.program_state.restoring = 0; + program_state.restoring = 0; return 0; } /* after restgamestate() -> restnames() so that 'bases[]' is populated */ @@ -769,7 +769,7 @@ dorecover(NHFILE *nhfp) if (rtmp < 2) return rtmp; /* dorecover called recursively */ - gp.program_state.restoring = REST_LEVELS; + program_state.restoring = REST_LEVELS; /* these pointers won't be valid while we're processing the * other levels, but they'll be reset again by restlevelstate() @@ -793,7 +793,7 @@ dorecover(NHFILE *nhfp) #endif clear_nhwindow(WIN_MESSAGE); You("return to level %d in %s%s.", depth(&u.uz), - gd.dungeons[u.uz.dnum].dname, + svd.dungeons[u.uz.dnum].dname, flags.debug ? " while in debug mode" : flags.explore ? " while in explore mode" : ""); curs(WIN_MAP, 1, 1); @@ -828,15 +828,15 @@ dorecover(NHFILE *nhfp) restoreinfo.mread_flags = 0; rewind_nhfile(nhfp); /* return to beginning of file */ (void) validate(nhfp, (char *) 0, FALSE); - get_plname_from_file(nhfp, gp.plname); + get_plname_from_file(nhfp, svp.plname); /* not 0 nor REST_GSTATE nor REST_LEVELS */ - gp.program_state.restoring = REST_CURRENT_LEVEL; + program_state.restoring = REST_CURRENT_LEVEL; getlev(nhfp, 0, (xint8) 0); close_nhfile(nhfp); restlevelstate(); - gp.program_state.something_worth_saving = 1; /* useful data now exists */ + program_state.something_worth_saving = 1; /* useful data now exists */ if (!wizard && !discover) (void) delete_savefile(); @@ -866,9 +866,9 @@ dorecover(NHFILE *nhfp) gv.vision_full_recalc = 1; /* recompute vision (not saved) */ run_timers(); /* expire all timers that have gone off while away */ - gp.program_state.restoring = 0; /* affects bot() so clear before docrt() */ + program_state.restoring = 0; /* affects bot() so clear before docrt() */ - if (ge.early_raw_messages && !gp.program_state.beyond_savefile_load) { + if (ge.early_raw_messages && !program_state.beyond_savefile_load) { /* * We're about to obliterate some potentially important * startup messages, so give the player a chance to see them. @@ -877,7 +877,7 @@ dorecover(NHFILE *nhfp) wait_synch(); } u.usteed_mid = u.ustuck_mid = 0; - gp.program_state.beyond_savefile_load = 1; + program_state.beyond_savefile_load = 1; docrt(); clear_nhwindow(WIN_MESSAGE); @@ -907,7 +907,7 @@ rest_stairs(NHFILE *nhfp) if (nhfp->structlevel) { Mread(nhfp->fd, &stway, sizeof stway); } - if (gp.program_state.restoring != REST_GSTATE + if (program_state.restoring != REST_GSTATE && stway.tolev.dnum == u.uz.dnum) { /* stairway dlevel is relative, make it absolute */ stway.tolev.dlevel += u.uz.dlevel; @@ -993,7 +993,7 @@ trickery(char *reason) pline("Strange, this map is not as I remember it."); pline("Somebody is trying some trickery here..."); pline("This game is void."); - Strcpy(gk.killer.name, reason ? reason : ""); + Strcpy(svk.killer.name, reason ? reason : ""); done(TRICKED); } @@ -1012,7 +1012,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) short tlev; #endif - gp.program_state.in_getlev = TRUE; + program_state.in_getlev = TRUE; if (ghostly) clear_id_mapping(); @@ -1052,34 +1052,34 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) pline1(trickbuf); trickery(trickbuf); } - restcemetery(nhfp, &gl.level.bonesinfo); + restcemetery(nhfp, &svl.level.bonesinfo); rest_levl(nhfp, (boolean) ((sfrestinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP)); if (nhfp->structlevel) { - Mread(nhfp->fd, gl.lastseentyp, sizeof gl.lastseentyp); + Mread(nhfp->fd, svl.lastseentyp, sizeof svl.lastseentyp); Mread(nhfp->fd, &go.omoves, sizeof go.omoves); } - elapsed = gm.moves - go.omoves; + elapsed = svm.moves - go.omoves; if (nhfp->structlevel) { rest_stairs(nhfp); - Mread(nhfp->fd, &gu.updest, sizeof gu.updest); - Mread(nhfp->fd, &gd.dndest, sizeof gd.dndest); - Mread(nhfp->fd, &gl.level.flags, sizeof gl.level.flags); - if (gd.doors) { - free(gd.doors); - gd.doors = 0; + Mread(nhfp->fd, &svu.updest, sizeof svu.updest); + Mread(nhfp->fd, &svd.dndest, sizeof svd.dndest); + Mread(nhfp->fd, &svl.level.flags, sizeof svl.level.flags); + if (svd.doors) { + free(svd.doors); + svd.doors = 0; } - Mread(nhfp->fd, &gd.doors_alloc, sizeof gd.doors_alloc); - if (gd.doors_alloc) { /* avoid pointless alloc(0) */ - gd.doors = (coord *) alloc(gd.doors_alloc * sizeof (coord)); - Mread(nhfp->fd, gd.doors, gd.doors_alloc * sizeof (coord)); + Mread(nhfp->fd, &svd.doors_alloc, sizeof svd.doors_alloc); + if (svd.doors_alloc) { /* avoid pointless alloc(0) */ + svd.doors = (coord *) alloc(svd.doors_alloc * sizeof (coord)); + Mread(nhfp->fd, svd.doors, svd.doors_alloc * sizeof (coord)); } } rest_rooms(nhfp); /* No joke :-) */ - if (gn.nroom) - gd.doorindex = gr.rooms[gn.nroom - 1].fdoor - + gr.rooms[gn.nroom - 1].doorct; + if (svn.nroom) + gd.doorindex = svr.rooms[svn.nroom - 1].fdoor + + svr.rooms[svn.nroom - 1].doorct; else gd.doorindex = 0; @@ -1096,7 +1096,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) if (nhfp->structlevel) Mread(nhfp->fd, trap, sizeof *trap); if (trap->tx != 0) { - if (gp.program_state.restoring != REST_GSTATE + if (program_state.restoring != REST_GSTATE && trap->dst.dnum == u.uz.dnum) { /* convert relative destination to absolute */ trap->dst.dlevel += u.uz.dlevel; @@ -1112,14 +1112,14 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) find_lev_obj(); /* restobjchn()'s `frozen' argument probably ought to be a callback routine so that we can check for objects being buried under ice */ - gl.level.buriedobjlist = restobjchn(nhfp, FALSE); + svl.level.buriedobjlist = restobjchn(nhfp, FALSE); gb.billobjs = restobjchn(nhfp, FALSE); rest_engravings(nhfp); /* reset level.monsters for new level */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) - gl.level.monsters[x][y] = (struct monst *) 0; + svl.level.monsters[x][y] = (struct monst *) 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (mtmp->isshk) set_residency(mtmp, FALSE); @@ -1140,7 +1140,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) } /* regenerate monsters while on another level */ - if (!u.uz.dlevel || gp.program_state.restoring == REST_LEVELS) + if (!u.uz.dlevel || program_state.restoring == REST_LEVELS) continue; if (ghostly) { /* reset peaceful/malign relative to new character; @@ -1242,7 +1242,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) if (ghostly) clear_id_mapping(); - gp.program_state.in_getlev = FALSE; + program_state.in_getlev = FALSE; } void @@ -1410,10 +1410,11 @@ reset_oattached_mids(boolean ghostly) #ifdef SELECTSAVED /* put up a menu listing each character from this player's saved games; - returns 1: use gp.plname[], 0: new game, -1: quit */ + returns 1: use svp.plname[], 0: new game, -1: quit */ int restore_menu( - winid bannerwin) /* if not WIN_ERR, clear window and show copyright in menu */ + winid bannerwin) /* if not WIN_ERR, clear window + * and show copyright in menu */ { winid tmpwin; anything any; @@ -1422,7 +1423,7 @@ restore_menu( int k, clet, ch = 0; /* ch: 0 => new game */ int clr = NO_COLOR; - *gp.plname = '\0'; + *svp.plname = '\0'; saved = get_saved_games(); /* array of character names */ if (saved && *saved) { tmpwin = create_nhwindow(NHW_MENU); @@ -1455,7 +1456,7 @@ restore_menu( if (select_menu(tmpwin, PICK_ONE, &chosen_game) > 0) { ch = chosen_game->item.a_int; if (ch > 0) - Strcpy(gp.plname, saved[ch - 1]); + Strcpy(svp.plname, saved[ch - 1]); else if (ch < 0) ++ch; /* -1 -> 0 (new game), -2 -> -1 (quit) */ free((genericptr_t) chosen_game); diff --git a/src/rip.c b/src/rip.c index dc237d4b2..d482eb0a2 100644 --- a/src/rip.c +++ b/src/rip.c @@ -58,7 +58,8 @@ static const char *const rip_txt[] = { " | | | Ascended |", " | 1001 | | |", " * | * * * | * * | * * * | *", - " _____)/\\|\\__//(\\/(/\\)/\\//\\/|_)________)/|\\\\_/_/(\\/(/\\)/\\/\\/|_)____", + (" _____)/\\|\\__//(\\/(/\\)/\\//\\/|_)___" + "_____)/|\\\\_/_/(\\/(/\\)/\\/\\/|_)____"), 0 }; #define STONE_LINE_CENT 19 /* char[] element of center of stone face */ @@ -96,7 +97,7 @@ genl_outrip(winid tmpwin, int how, time_t when) dp[x] = (char *) 0; /* Put name on stone */ - Sprintf(buf, "%.*s", (int) STONE_LINE_LEN, gp.plname); + Sprintf(buf, "%.*s", (int) STONE_LINE_LEN, svp.plname); center(NAME_LINE, buf); /* Put $ on stone */ diff --git a/src/role.c b/src/role.c index cf1616e52..7055ff5b7 100644 --- a/src/role.c +++ b/src/role.c @@ -1664,31 +1664,32 @@ plnamesuffix(void) /* some generic user names will be ignored in favor of prompting */ if (sysopt.genericusers) { if (*sysopt.genericusers == '*') { - gp.plname[0] = '\0'; + svp.plname[0] = '\0'; } else { /* need to ignore appended '-role-race-gender-alignment'; 'plnamelen' is non-zero when dealing with plname[] value that contains a username with dash(es) in it and is usually 0 */ - i = ((eptr = strchr(gp.plname + gp.plnamelen, '-')) != 0) - ? (int) (eptr - gp.plname) - : (int) Strlen(gp.plname); + i = ((eptr = strchr(svp.plname + gp.plnamelen, '-')) != 0) + ? (int) (eptr - svp.plname) + : (int) Strlen(svp.plname); /* look for plname[] in the 'genericusers' space-separated list */ - if (findword(sysopt.genericusers, gp.plname, i, FALSE)) + if (findword(sysopt.genericusers, svp.plname, i, FALSE)) /* it's generic; remove it so that askname() will be called */ - gp.plname[0] = '\0'; + svp.plname[0] = '\0'; } - if (!gp.plname[0]) + if (!svp.plname[0]) gp.plnamelen = 0; } do { - if (!gp.plname[0]) { - askname(); /* fill gp.plname[] if necessary, or set defer_plname */ + if (!svp.plname[0]) { + askname(); /* fill svp.plname[] if necessary, or set + * defer_plname */ gp.plnamelen = 0; /* plname[] might have -role-race-&c attached */ } /* Look for tokens delimited by '-' */ - sptr = gp.plname + gp.plnamelen; + sptr = svp.plname + gp.plnamelen; if ((eptr = strchr(sptr, '-')) != (char *) 0) *eptr++ = '\0'; while (eptr) { @@ -1707,10 +1708,10 @@ plnamesuffix(void) else if ((i = str2align(sptr)) != ROLE_NONE) flags.initalign = i; } - } while (!gp.plname[0] && !iflags.defer_plname); + } while (!svp.plname[0] && !iflags.defer_plname); - /* commas in the gp.plname confuse the record file, convert to spaces */ - (void) strNsubst(gp.plname, ",", " ", 0); + /* commas in the svp.plname confuse the record file, convert to spaces */ + (void) strNsubst(svp.plname, ",", " ", 0); } /* show current settings for name, role, race, gender, and alignment @@ -1733,7 +1734,8 @@ role_selection_prolog(int which, winid where) allowmask = roles[r].allow; if ((allowmask & ROLE_RACEMASK) == MH_HUMAN) c = 0; /* races[human] */ - else if (IndexOkT(c, races) && !(allowmask & ROLE_RACEMASK & races[c].allow)) + else if (IndexOkT(c, races) + && !(allowmask & ROLE_RACEMASK & races[c].allow)) c = ROLE_RANDOM; if ((allowmask & ROLE_GENDMASK) == ROLE_MALE) gend = 0; /* role forces male (hypothetical) */ @@ -1762,7 +1764,7 @@ role_selection_prolog(int which, winid where) Sprintf(buf, "%12s ", "name:"); Strcat(buf, (which == RS_NAME) ? choosing - : !*gp.plname ? not_yet : gp.plname); + : !*svp.plname ? not_yet : svp.plname); putstr(where, 0, buf); Sprintf(buf, "%12s ", "role:"); assert(which == RS_ROLE || r == ROLE_NONE || r == ROLE_RANDOM @@ -1848,8 +1850,8 @@ role_menu_extra(int which, winid where, boolean preselect) if (c >= 0) { constrainer = "role"; forcedvalue = races[c].noun; - } else if (f >= 0 - && (allowmask & ~gr.rfilter.mask) == races[f].selfmask) { + } else if (f >= 0 && ((allowmask & ~gr.rfilter.mask) + == races[f].selfmask)) { /* if there is only one race choice available due to user options disallowing others, race menu entry is disabled */ constrainer = "filter"; @@ -1870,8 +1872,8 @@ role_menu_extra(int which, winid where, boolean preselect) if (gend >= 0) { constrainer = "role"; forcedvalue = genders[gend].adj; - } else if (f >= 0 - && (allowmask & ~gr.rfilter.mask) == genders[f].allow) { + } else if (f >= 0 && ((allowmask & ~gr.rfilter.mask) + == genders[f].allow)) { /* if there is only one gender choice available due to user options disallowing other, gender menu entry is disabled */ constrainer = "filter"; @@ -1982,15 +1984,15 @@ role_init(void) /* Check for a valid role. Try flags.initrole first. */ if (!validrole(flags.initrole)) { /* Try the player letter second */ - if ((flags.initrole = str2role(gp.pl_character)) < 0) + if ((flags.initrole = str2role(svp.pl_character)) < 0) /* None specified; pick a random role */ flags.initrole = randrole_filtered(); } /* We now have a valid role index. Copy the role name back. */ /* This should become OBSOLETE */ - Strcpy(gp.pl_character, roles[flags.initrole].name.m); - gp.pl_character[PL_CSIZ - 1] = '\0'; + Strcpy(svp.pl_character, roles[flags.initrole].name.m); + svp.pl_character[PL_CSIZ - 1] = '\0'; /* Check for a valid race */ if (!validrace(flags.initrole, flags.initrace)) @@ -2025,7 +2027,7 @@ role_init(void) pm->maligntyp = alignmnt * 3; /* if gender is random, we choose it now instead of waiting until the leader monster is created */ - gq.quest_status.ldrgend = + svq.quest_status.ldrgend = is_neuter(pm) ? 2 : is_female(pm) ? 1 : is_male(pm) ? 0 : (rn2(100) < 50); @@ -2048,7 +2050,7 @@ role_init(void) pm->mflags3 |= M3_WANTSARTI | M3_WAITFORU; /* if gender is random, we choose it now instead of waiting until the nemesis monster is created */ - gq.quest_status.nemgend = is_neuter(pm) ? 2 : is_female(pm) ? 1 + svq.quest_status.nemgend = is_neuter(pm) ? 2 : is_female(pm) ? 1 : is_male(pm) ? 0 : (rn2(100) < 50); } @@ -2074,7 +2076,7 @@ role_init(void) gu.urole.cgod = roles[flags.pantheon].cgod; } /* 0 or 1; no gods are neuter, nor is gender randomized */ - gq.quest_status.godgend = !strcmpi(align_gtitle(alignmnt), "goddess"); + svq.quest_status.godgend = !strcmpi(align_gtitle(alignmnt), "goddess"); #if 0 /* @@ -2204,7 +2206,7 @@ genl_player_setup(int screenheight) char pick4u = 'n'; int result = 0; /* assume failure (player chooses to 'quit') */ - gp.program_state.in_role_selection++; /* affects tty menu cleanup */ + program_state.in_role_selection++; /* affects tty menu cleanup */ /* Used to avoid "Is this ok?" if player has already specified all * four facets of role. * Note that rigid_role_checks might force any unspecified facets to @@ -2535,7 +2537,9 @@ genl_player_setup(int screenheight) } /* picking gender */ if (nextpick == RS_ALGNMNT) { - nextpick = (ROLE < 0) ? RS_ROLE : (RACE < 0) ? RS_RACE : RS_GENDER; + nextpick = (ROLE < 0) ? RS_ROLE + : (RACE < 0) ? RS_RACE + : RS_GENDER; /* Select an alignment, if necessary; force compatibility with role/race/gender. */ if (ALGN < 0 || !validalign(ROLE, RACE, ALGN)) { @@ -2651,7 +2655,8 @@ genl_player_setup(int screenheight) if (iflags.renameallowed) { any.a_int = 3; add_menu(win, &nul_glyphinfo, &any, 'a', 0, ATR_NONE, - clr, "Not yet; choose another name", MENU_ITEMFLAGS_NONE); + clr, "Not yet; choose another name", + MENU_ITEMFLAGS_NONE); } any.a_int = -1; add_menu(win, &nul_glyphinfo, &any, 'q', 0, @@ -2680,10 +2685,12 @@ genl_player_setup(int screenheight) iflags.renameinprogress = TRUE; /* affects main() in unixmain.c */ /* plnamesuffix() can change any or all of ROLE, RACE, GEND, ALGN; we'll override that and honor only the name */ - saveROLE = ROLE, saveRACE = RACE, saveGEND = GEND, saveALGN = ALGN; - gp.plname[0] = '\0'; - plnamesuffix(); /* calls askname() when gp.plname[] is empty */ - ROLE = saveROLE, RACE = saveRACE, GEND = saveGEND, ALGN = saveALGN; + saveROLE = ROLE, saveRACE = RACE, + saveGEND = GEND, saveALGN = ALGN; + svp.plname[0] = '\0'; + plnamesuffix(); /* calls askname() when svp.plname[] is empty */ + ROLE = saveROLE, RACE = saveRACE, + GEND = saveGEND, ALGN = saveALGN; break; /* getconfirmation is still True */ } case 2: /* 'n' */ @@ -2704,7 +2711,7 @@ genl_player_setup(int screenheight) result = 1; setup_done: - gp.program_state.in_role_selection--; + program_state.in_role_selection--; return result; } @@ -2800,7 +2807,7 @@ plsel_startmenu(int ttyrows, int aspect) rolename = (ROLE < 0) ? "" : (GEND == 1 && roles[ROLE].name.f) ? roles[ROLE].name.f : roles[ROLE].name.m; - if (!gp.plname[0] || ROLE < 0 || RACE < 0 || GEND < 0 || ALGN < 0) { + if (!svp.plname[0] || ROLE < 0 || RACE < 0 || GEND < 0 || ALGN < 0) { /* " " */ Sprintf(qbuf, "%.20s %.20s %.20s %.20s", rolename, @@ -2810,7 +2817,7 @@ plsel_startmenu(int ttyrows, int aspect) } else { /* " the " */ Sprintf(qbuf, "%.20s the %.20s %.20s %.20s %.20s", - gp.plname, + svp.plname, aligns[ALGN].adj, genders[GEND].adj, races[RACE].adj, diff --git a/src/rumors.c b/src/rumors.c index 82794b04b..11545fb6d 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -582,7 +582,7 @@ init_oracles(dlb *fp) (void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment*/ (void) dlb_fgets(line, sizeof line, fp); if (sscanf(line, "%5d\n", &cnt) == 1 && cnt > 0) { - go.oracle_cnt = (unsigned) cnt; + svo.oracle_cnt = (unsigned) cnt; go.oracle_loc = (unsigned long *) alloc((unsigned) cnt * sizeof(long)); for (i = 0; i < cnt; i++) { (void) dlb_fgets(line, sizeof line, fp); @@ -597,19 +597,19 @@ save_oracles(NHFILE *nhfp) { if (perform_bwrite(nhfp)) { if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &go.oracle_cnt, - sizeof go.oracle_cnt); - if (go.oracle_cnt) { + bwrite(nhfp->fd, (genericptr_t) &svo.oracle_cnt, + sizeof svo.oracle_cnt); + if (svo.oracle_cnt) { if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) go.oracle_loc, - go.oracle_cnt * sizeof (long)); + svo.oracle_cnt * sizeof (long)); } } } if (release_data(nhfp)) { - if (go.oracle_cnt) { + if (svo.oracle_cnt) { free((genericptr_t) go.oracle_loc); - go.oracle_loc = 0, go.oracle_cnt = 0, go.oracle_flg = 0; + go.oracle_loc = 0, svo.oracle_cnt = 0, go.oracle_flg = 0; } } } @@ -618,13 +618,13 @@ void restore_oracles(NHFILE *nhfp) { if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &go.oracle_cnt, sizeof go.oracle_cnt); + mread(nhfp->fd, (genericptr_t) &svo.oracle_cnt, sizeof svo.oracle_cnt); - if (go.oracle_cnt) { - go.oracle_loc = (unsigned long *) alloc(go.oracle_cnt * sizeof(long)); + if (svo.oracle_cnt) { + go.oracle_loc = (unsigned long *) alloc(svo.oracle_cnt * sizeof(long)); if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) go.oracle_loc, - go.oracle_cnt * sizeof (long)); + svo.oracle_cnt * sizeof (long)); } go.oracle_flg = 1; /* no need to call init_oracles() */ } @@ -640,7 +640,7 @@ outoracle(boolean special, boolean delphi) /* early return if we couldn't open ORACLEFILE on previous attempt, or if all the oracularities are already exhausted */ - if (go.oracle_flg < 0 || (go.oracle_flg > 0 && go.oracle_cnt == 0)) + if (go.oracle_flg < 0 || (go.oracle_flg > 0 && svo.oracle_cnt == 0)) return; oracles = dlb_fopen(ORACLEFILE, "r"); @@ -649,17 +649,17 @@ outoracle(boolean special, boolean delphi) if (go.oracle_flg == 0) { /* if this is the first outoracle() */ init_oracles(oracles); go.oracle_flg = 1; - if (go.oracle_cnt == 0) + if (svo.oracle_cnt == 0) goto close_oracles; } /* oracle_loc[0] is the special oracle; oracle_loc[1..oracle_cnt-1] are normal ones */ - if (go.oracle_cnt <= 1 && !special) + if (svo.oracle_cnt <= 1 && !special) goto close_oracles; /*(shouldn't happen)*/ - oracle_idx = special ? 0 : rnd((int) go.oracle_cnt - 1); + oracle_idx = special ? 0 : rnd((int) svo.oracle_cnt - 1); (void) dlb_fseek(oracles, (long) go.oracle_loc[oracle_idx], SEEK_SET); if (!special) /* move offset of very last one into this slot */ - go.oracle_loc[oracle_idx] = go.oracle_loc[--go.oracle_cnt]; + go.oracle_loc[oracle_idx] = go.oracle_loc[--svo.oracle_cnt]; tmpwin = create_nhwindow(NHW_TEXT); if (delphi) @@ -723,7 +723,7 @@ doconsult(struct monst *oracl) break; case 'n': if (umoney <= (long) minor_cost /* don't even ask */ - || (go.oracle_cnt == 1 || go.oracle_flg < 0)) + || (svo.oracle_cnt == 1 || go.oracle_flg < 0)) return ECMD_OK; Sprintf(qbuf, "\"Then dost thou desire a major one?\" (%d %s)", major_cost, currency((long) major_cost)); @@ -763,16 +763,16 @@ doconsult(struct monst *oracl) staticfn void couldnt_open_file(const char *filename) { - int save_something = gp.program_state.something_worth_saving; + int save_something = program_state.something_worth_saving; /* most likely the file is missing, so suppress impossible()'s "saving and restoring might fix this" (unless the fuzzer, which escalates impossible to panic, is running) */ if (!iflags.debug_fuzzer) - gp.program_state.something_worth_saving = 0; + program_state.something_worth_saving = 0; impossible("Can't open '%s' file.", filename); - gp.program_state.something_worth_saving = save_something; + program_state.something_worth_saving = save_something; } /* is 'word' a capitalized monster name that should be preceded by "the"? diff --git a/src/save.c b/src/save.c index d747db1f3..f3ea97a62 100644 --- a/src/save.c +++ b/src/save.c @@ -41,7 +41,7 @@ staticfn void zerocomp_bputc(int); #endif #if defined(HANGUPHANDLING) -#define HUP if (!gp.program_state.done_hup) +#define HUP if (!program_state.done_hup) #else #define HUP #endif @@ -59,7 +59,7 @@ dosave(void) clear_nhwindow(WIN_MESSAGE); pline("Saving..."); #if defined(HANGUPHANDLING) - gp.program_state.done_hup = 0; + program_state.done_hup = 0; #endif if (dosave0()) { u.uhp = -1; /* universal game's over indicator */ @@ -86,7 +86,7 @@ dosave0(void) NHFILE *nhfp, *onhfp; int res = 0; - gp.program_state.saving++; /* inhibit status and perm_invent updates */ + program_state.saving++; /* inhibit status and perm_invent updates */ /* we may get here via hangup signal, in which case we want to fix up a few of things before saving so that they won't be restored in an improper state; these will be no-ops for normal save sequence */ @@ -103,7 +103,7 @@ dosave0(void) when punished, make sure ball and chain are placed too */ done_object_cleanup(); /* maybe force some items onto map */ - if (!gp.program_state.something_worth_saving || !gs.SAVEF[0]) + if (!program_state.something_worth_saving || !gs.SAVEF[0]) goto done; fq_save = fqname(gs.SAVEF, SAVEPREFIX, 1); /* level files take 0 */ @@ -190,7 +190,7 @@ dosave0(void) for (ltmp = (xint8) 1; ltmp <= maxledgerno(); ltmp++) { if (ltmp == ledger_no(&gu.uz_save)) continue; - if (!(gl.level_info[ltmp].flags & LFILE_EXISTS)) + if (!(svl.level_info[ltmp].flags & LFILE_EXISTS)) continue; #ifdef MICRO curs(WIN_MAP, 1 + dotcnt++, dotrow); @@ -208,12 +208,12 @@ dosave0(void) HUP pline1(whynot); close_nhfile(nhfp); (void) delete_savefile(); - HUP Strcpy(gk.killer.name, whynot); + HUP Strcpy(svk.killer.name, whynot); HUP done(TRICKED); goto done; } minit(); /* ZEROCOMP */ - getlev(onhfp, gh.hackpid, ltmp); + getlev(onhfp, svh.hackpid, ltmp); close_nhfile(onhfp); if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* lvl no. */ @@ -230,11 +230,11 @@ dosave0(void) delete_levelfile(0); nh_compress(fq_save); /* this should probably come sooner... */ - gp.program_state.something_worth_saving = 0; + program_state.something_worth_saving = 0; res = 1; done: - gp.program_state.saving--; + program_state.saving--; return res; } @@ -276,11 +276,11 @@ savegamestate(NHFILE *nhfp) { unsigned long uid; - gp.program_state.saving++; /* caller should/did already set this... */ + program_state.saving++; /* caller should/did already set this... */ uid = (unsigned long) getuid(); if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid); - bwrite(nhfp->fd, (genericptr_t) &gc.context, sizeof gc.context); + bwrite(nhfp->fd, (genericptr_t) &svc.context, sizeof svc.context); bwrite(nhfp->fd, (genericptr_t) &flags, sizeof flags); } urealtime.finish_time = getnow(); @@ -313,23 +313,23 @@ savegamestate(NHFILE *nhfp) if (release_data(nhfp)) gm.migrating_mons = (struct monst *) 0; if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) gm.mvitals, sizeof gm.mvitals); + bwrite(nhfp->fd, (genericptr_t) svm.mvitals, sizeof svm.mvitals); save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp), (boolean) !!release_data(nhfp)); savelevchn(nhfp); if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &gm.moves, sizeof gm.moves); - bwrite(nhfp->fd, (genericptr_t) &gq.quest_status, - sizeof gq.quest_status); - bwrite(nhfp->fd, (genericptr_t) gs.spl_book, + bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); + bwrite(nhfp->fd, (genericptr_t) &svq.quest_status, + sizeof svq.quest_status); + bwrite(nhfp->fd, (genericptr_t) svs.spl_book, sizeof (struct spell) * (MAXSPELL + 1)); } save_artifacts(nhfp); save_oracles(nhfp); if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) gp.pl_character, - sizeof gp.pl_character); - bwrite(nhfp->fd, (genericptr_t) gp.pl_fruit, sizeof gp.pl_fruit); + bwrite(nhfp->fd, (genericptr_t) svp.pl_character, + sizeof svp.pl_character); + bwrite(nhfp->fd, (genericptr_t) svp.pl_fruit, sizeof svp.pl_fruit); } savefruitchn(nhfp); savenames(nhfp); @@ -338,7 +338,7 @@ savegamestate(NHFILE *nhfp) save_luadata(nhfp); if (nhfp->structlevel) bflush(nhfp->fd); - gp.program_state.saving--; + program_state.saving--; return; } @@ -349,7 +349,7 @@ tricked_fileremoved(NHFILE *nhfp, char *whynot) if (!nhfp) { pline1(whynot); pline("Probably someone removed it."); - Strcpy(gk.killer.name, whynot); + Strcpy(svk.killer.name, whynot); done(TRICKED); return TRUE; } @@ -364,7 +364,7 @@ savestateinlock(void) char whynot[BUFSZ]; NHFILE *nhfp; - gp.program_state.saving++; /* inhibit status and perm_invent updates */ + program_state.saving++; /* inhibit status and perm_invent updates */ /* When checkpointing is on, the full state needs to be written * on each checkpoint. When checkpointing is off, only the pid * needs to be in the level.0 file, so it does not need to be @@ -385,15 +385,15 @@ savestateinlock(void) */ nhfp = open_levelfile(0, whynot); if (tricked_fileremoved(nhfp, whynot)) { - gp.program_state.saving--; + program_state.saving--; return; } if (nhfp->structlevel) (void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid); - if (gh.hackpid != hpid) { + if (svh.hackpid != hpid) { Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!", - hpid, gh.hackpid); + hpid, svh.hackpid); goto giveup; } close_nhfile(nhfp); @@ -402,24 +402,26 @@ savestateinlock(void) if (!nhfp) { pline1(whynot); giveup: - Strcpy(gk.killer.name, whynot); + Strcpy(svk.killer.name, whynot); /* done(TRICKED) will return when running in wizard mode; clear the display-update-suppression flag before rather than after so that screen updating behaves normally; game data shouldn't be inconsistent yet, unlike it would become midway through saving */ - gp.program_state.saving--; + program_state.saving--; done(TRICKED); return; } nhfp->mode = WRITING; if (nhfp->structlevel) - (void) write(nhfp->fd, (genericptr_t) &gh.hackpid, sizeof gh.hackpid); + (void) write(nhfp->fd, (genericptr_t) &svh.hackpid, + sizeof svh.hackpid); if (flags.ins_chkpt) { int currlev = ledger_no(&u.uz); if (nhfp->structlevel) - (void) write(nhfp->fd, (genericptr_t) &currlev, sizeof currlev); + (void) write(nhfp->fd, (genericptr_t) &currlev, + sizeof currlev); save_savefile_name(nhfp); store_version(nhfp); store_savefileinfo(nhfp); @@ -433,7 +435,7 @@ savestateinlock(void) } close_nhfile(nhfp); } - gp.program_state.saving--; + program_state.saving--; gh.havestate = flags.ins_chkpt; return; } @@ -450,7 +452,7 @@ savelev(NHFILE *nhfp, xint8 lev) but we'll be called during run-down */ if (set_uz_save && perform_bwrite(nhfp)) { if (u.uz.dnum == 0 && u.uz.dlevel == 0) { - gp.program_state.something_worth_saving = 0; + program_state.something_worth_saving = 0; panic("savelev: where are we?"); } gu.uz_save = u.uz; @@ -469,7 +471,7 @@ savelev_core(NHFILE *nhfp, xint8 lev) short tlev; #endif - gp.program_state.saving++; /* even if current mode is FREEING */ + program_state.saving++; /* even if current mode is FREEING */ if (!nhfp) panic("Save on bad file!"); /* impossible */ @@ -500,9 +502,9 @@ savelev_core(NHFILE *nhfp, xint8 lev) dmonsfree(); if (lev >= 0 && lev <= maxledgerno()) - gl.level_info[lev].flags |= VISITED; + svl.level_info[lev].flags |= VISITED; if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &gh.hackpid, sizeof gh.hackpid); + bwrite(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof svh.hackpid); #ifdef TOS tlev = lev; tlev &= 0x00ff; @@ -520,24 +522,27 @@ savelev_core(NHFILE *nhfp, xint8 lev) the guessing that was needed in 3.4.3 and without having to interpret level data to find where to start; unfortunately it still needs to handle all the data compression schemes */ - savecemetery(nhfp, &gl.level.bonesinfo); + savecemetery(nhfp, &svl.level.bonesinfo); if (nhfp->mode == FREEING) /* see above */ goto skip_lots; savelevl(nhfp, ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP)); if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) gl.lastseentyp, sizeof gl.lastseentyp); - bwrite(nhfp->fd, (genericptr_t) &gm.moves, sizeof gm.moves); + bwrite(nhfp->fd, (genericptr_t) svl.lastseentyp, + sizeof svl.lastseentyp); + bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); save_stairs(nhfp); - bwrite(nhfp->fd, (genericptr_t) &gu.updest, sizeof (dest_area)); - bwrite(nhfp->fd, (genericptr_t) &gd.dndest, sizeof (dest_area)); - bwrite(nhfp->fd, (genericptr_t) &gl.level.flags, sizeof gl.level.flags); - bwrite(nhfp->fd, (genericptr_t) &gd.doors_alloc, sizeof gd.doors_alloc); + bwrite(nhfp->fd, (genericptr_t) &svu.updest, sizeof (dest_area)); + bwrite(nhfp->fd, (genericptr_t) &svd.dndest, sizeof (dest_area)); + bwrite(nhfp->fd, (genericptr_t) &svl.level.flags, + sizeof svl.level.flags); + bwrite(nhfp->fd, (genericptr_t) &svd.doors_alloc, + sizeof svd.doors_alloc); /* don't rely on underlying write() behavior to write * nothing if count arg is 0, just skip it */ - if (gd.doors_alloc) - bwrite(nhfp->fd, (genericptr_t) gd.doors, - gd.doors_alloc * sizeof (coord)); + if (svd.doors_alloc) + bwrite(nhfp->fd, (genericptr_t) svd.doors, + svd.doors_alloc * sizeof (coord)); } save_rooms(nhfp); /* no dynamic memory to reclaim */ @@ -551,7 +556,7 @@ savelev_core(NHFILE *nhfp, xint8 lev) save_worm(nhfp); /* save worm information */ savetrapchn(nhfp, gf.ftrap); saveobjchn(nhfp, &fobj); - saveobjchn(nhfp, &gl.level.buriedobjlist); + saveobjchn(nhfp, &svl.level.buriedobjlist); saveobjchn(nhfp, &gb.billobjs); save_engravings(nhfp); savedamage(nhfp); /* pending shop wall and/or floor repair */ @@ -564,12 +569,12 @@ savelev_core(NHFILE *nhfp, xint8 lev) if (nhfp->structlevel) bflush(nhfp->fd); } - gp.program_state.saving--; + program_state.saving--; if (release_data(nhfp)) { clear_level_structures(); gf.ftrap = 0; gb.billobjs = 0; - (void) memset(gr.rooms, 0, sizeof(gr.rooms)); + (void) memset(svr.rooms, 0, sizeof(svr.rooms)); } return; } @@ -688,7 +693,7 @@ savedamage(NHFILE *nhfp) struct damage *damageptr, *tmp_dam; unsigned int xl = 0; - damageptr = gl.level.damagelist; + damageptr = svl.level.damagelist; for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) xl++; if (perform_bwrite(nhfp)) { @@ -706,7 +711,7 @@ savedamage(NHFILE *nhfp) free((genericptr_t) tmp_dam); } if (release_data(nhfp)) - gl.level.damagelist = 0; + svl.level.damagelist = 0; } staticfn void @@ -717,7 +722,7 @@ save_stairs(NHFILE *nhfp) while (stway) { if (perform_bwrite(nhfp)) { - boolean use_relative = (gp.program_state.restoring != REST_GSTATE + boolean use_relative = (program_state.restoring != REST_GSTATE && stway->tolev.dnum == u.uz.dnum); if (use_relative) { /* make dlevel relative to current level */ @@ -840,17 +845,17 @@ saveobjchn(NHFILE *nhfp, struct obj **obj_p) * Always invalidate the pointer, but ensure that we have * the o_id in order to restore the pointer on reload. */ - if (otmp == gc.context.victual.piece) { - gc.context.victual.o_id = otmp->o_id; - gc.context.victual.piece = (struct obj *) 0; + if (otmp == svc.context.victual.piece) { + svc.context.victual.o_id = otmp->o_id; + svc.context.victual.piece = (struct obj *) 0; } - if (otmp == gc.context.tin.tin) { - gc.context.tin.o_id = otmp->o_id; - gc.context.tin.tin = (struct obj *) 0; + if (otmp == svc.context.tin.tin) { + svc.context.tin.o_id = otmp->o_id; + svc.context.tin.tin = (struct obj *) 0; } - if (otmp == gc.context.spbook.book) { - gc.context.spbook.o_id = otmp->o_id; - gc.context.spbook.book = (struct obj *) 0; + if (otmp == svc.context.spbook.book) { + svc.context.spbook.o_id = otmp->o_id; + svc.context.spbook.book = (struct obj *) 0; } otmp->where = OBJ_FREE; /* set to free so dealloc will work */ otmp->nobj = NULL; /* nobj saved into otmp2 */ @@ -961,9 +966,9 @@ savemonchn(NHFILE *nhfp, struct monst *mtmp) if (mtmp->minvent) saveobjchn(nhfp, &mtmp->minvent); if (release_data(nhfp)) { - if (mtmp == gc.context.polearm.hitmon) { - gc.context.polearm.m_id = mtmp->m_id; - gc.context.polearm.hitmon = NULL; + if (mtmp == svc.context.polearm.hitmon) { + svc.context.polearm.m_id = mtmp->m_id; + svc.context.polearm.hitmon = NULL; } if (mtmp == u.ustuck) u.ustuck_mid = u.ustuck->m_id; @@ -980,7 +985,7 @@ savemonchn(NHFILE *nhfp, struct monst *mtmp) } } -/* save traps; gf.ftrap is the only trap chain so the 2nd arg is superfluous */ +/* save traps; gf.ftrap is the only trap chain so 2nd arg is superfluous */ staticfn void savetrapchn(NHFILE *nhfp, struct trap *trap) { @@ -988,7 +993,7 @@ savetrapchn(NHFILE *nhfp, struct trap *trap) struct trap *trap2; while (trap) { - boolean use_relative = (gp.program_state.restoring != REST_GSTATE + boolean use_relative = (program_state.restoring != REST_GSTATE && trap->dst.dnum == u.uz.dnum); trap2 = trap->ntrap; if (use_relative) @@ -1045,13 +1050,13 @@ savelevchn(NHFILE *nhfp) s_level *tmplev, *tmplev2; int cnt = 0; - for (tmplev = gs.sp_levchn; tmplev; tmplev = tmplev->next) + for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev->next) cnt++; if (perform_bwrite(nhfp)) { if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &cnt, sizeof cnt); } - for (tmplev = gs.sp_levchn; tmplev; tmplev = tmplev2) { + for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev2) { tmplev2 = tmplev->next; if (perform_bwrite(nhfp)) { if (nhfp->structlevel) @@ -1061,7 +1066,7 @@ savelevchn(NHFILE *nhfp) free((genericptr_t) tmplev); } if (release_data(nhfp)) - gs.sp_levchn = 0; + svs.sp_levchn = 0; } void @@ -1073,7 +1078,7 @@ store_plname_in_file(NHFILE *nhfp) bufoff(nhfp->fd); /* bwrite() before bufon() uses plain write() */ bwrite(nhfp->fd, (genericptr_t) &plsiztmp, sizeof plsiztmp); - bwrite(nhfp->fd, (genericptr_t) gp.plname, plsiztmp); + bwrite(nhfp->fd, (genericptr_t) svp.plname, plsiztmp); bufon(nhfp->fd); } return; diff --git a/src/selvar.c b/src/selvar.c index a746be28b..1951edfb8 100644 --- a/src/selvar.c +++ b/src/selvar.c @@ -761,9 +761,10 @@ selection_size_description(struct selectionvar *sel, char *buf) selection_getbounds(sel, &rect); dx = rect.hx - rect.lx + 1; dy = rect.hy - rect.ly + 1; - Sprintf(buf, "%s %i by %i", selection_is_irregular(sel) ? "irregularly shaped" + Sprintf(buf, "%s %i by %i", + selection_is_irregular(sel) ? "irregularly shaped" : (dx == dy) ? "square" - : "rectangular", + : "rectangular", dx, dy); return buf; } @@ -780,7 +781,7 @@ selection_from_mkroom(struct mkroom *croom) if (!croom) return sel; - rmno = (unsigned)((croom - gr.rooms) + ROOMOFFSET); + rmno = (unsigned)((croom - svr.rooms) + ROOMOFFSET); for (y = croom->ly; y <= croom->hy; y++) for (x = croom->lx; x <= croom->hx; x++) if (isok(x, y) && !levl[x][y].edge diff --git a/src/sfstruct.c b/src/sfstruct.c index 5d84583bd..ae0b2c5fd 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -194,7 +194,7 @@ bwrite(int fd, const genericptr_t loc, unsigned num) } if (failed) { #if defined(HANGUPHANDLING) - if (gp.program_state.done_hup) + if (program_state.done_hup) nh_terminate(EXIT_FAILURE); else #endif @@ -230,7 +230,7 @@ mread(int fd, genericptr_t buf, unsigned len) } else { pline("Read %d instead of %u bytes.", (int) rlen, len); display_nhwindow(WIN_MESSAGE, TRUE); /* flush before error() */ - if (gp.program_state.restoring) { + if (program_state.restoring) { (void) nhclose(fd); (void) delete_savefile(); error("Error restoring old game."); diff --git a/src/shk.c b/src/shk.c index c78f045e6..0ec28f217 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,23 +1,55 @@ -/* NetHack 3.7 shk.c $NHDT-Date: 1652299941 2022/05/11 20:12:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.232 $ */ +/* NetHack 3.7 shk.c $NHDT-Date: 1720717993 2024/07/11 17:13:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.298 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" -#define PAY_SOME 2 +/* + * FIXME: + * The normal shop messages are verbal. There are a lot of cases + * where an alternate message is given if the hero is deaf or shk + * is mute (when poly'd), but that is usually visual-based. It is + * possible for hero to pay for items while blind (only if adjacent + * to shk) and the alternate messages fail to account for that. + */ + #define PAY_BUY 1 #define PAY_CANT 0 /* too poor */ #define PAY_SKIP (-1) #define PAY_BROKE (-2) +enum billitem_status { + FullyUsedUp = 1, /* completely used up; obj->where==OBJ_ONBILL */ + PartlyUsedUp = 2, /* partly used up; obj->where==OBJ_INVENT or similar */ + PartlyIntact = 3, /* intact portion of partly used up item */ + FullyIntact = 4, /* normal unpaid item */ + KnownContainer = 5, /* container->cknown==1, holding unpaid item(s) */ + UndisclosedContainer = 6, /* container->cknown==0 */ +}; +/* this is similar to sortloot; the shop bill gets converted into a array of + struct sortbill_item so that sorting and traversal don't need to access + the original bill or even the shk; the array gets sorted by usedup vs + unpaid and by cost within each of those two categories */ +struct sortbill_item { + struct obj *obj; + long cost; + long quan; + int bidx; + int8 usedup; /* small but signed */ + boolean queuedpay; +}; +typedef struct sortbill_item Bill; + staticfn void makekops(coord *); +staticfn void getcad(struct monst *, const char *, coordxy, coordxy, boolean, + boolean, boolean); staticfn void call_kops(struct monst *, boolean); staticfn void kops_gone(boolean); #define NOTANGRY(mon) ((mon)->mpeaceful) #define ANGRY(mon) (!NOTANGRY(mon)) -#define IS_SHOP(x) (gr.rooms[x].rtype >= SHOPBASE) +#define IS_SHOP(x) (svr.rooms[x].rtype >= SHOPBASE) #define muteshk(shkp) (helpless(shkp) || (shkp)->data->msound <= MS_ANIMAL) @@ -44,10 +76,22 @@ staticfn long get_cost(struct obj *, struct monst *); staticfn long set_cost(struct obj *, struct monst *); staticfn const char *shk_embellish(struct obj *, long); staticfn long cost_per_charge(struct monst *, struct obj *, boolean); -staticfn long cheapest_item(struct monst *); -staticfn int menu_pick_pay_items(struct monst *); -staticfn int dopayobj(struct monst *, struct bill_x *, struct obj **, int, - boolean); + +staticfn int QSORTCALLBACK sortbill_cmp(const genericptr, const genericptr) + NONNULLPTRS; +staticfn long cheapest_item(int, Bill *) NONNULLPTRS; +staticfn int make_itemized_bill(struct monst *shkp, Bill **ibill) NONNULLPTRS; +staticfn int menu_pick_pay_items(int, Bill *) NONNULLPTRS; +staticfn boolean pay_billed_items(struct monst *, int, Bill *, boolean, + boolean *) NONNULLPTRS; +staticfn void update_bill(int, int, Bill *, struct eshk *, struct bill_x *, + struct obj *) NONNULLPTRS; +staticfn int dopayobj(struct monst *, struct bill_x *, struct obj *, int, + boolean, boolean) NONNULLPTRS; +staticfn int buy_container(struct monst *, int, int, Bill *) NONNULLPTRS; +staticfn void reject_purchase(struct monst *, struct obj *, long) NONNULLPTRS; +staticfn boolean insufficient_funds(struct monst *, struct obj *, long) + NONNULLPTRS; staticfn long stolen_container(struct obj *, struct monst *, long, boolean); staticfn long corpsenm_price_adj(struct obj *); staticfn long getprice(struct obj *, boolean); @@ -186,7 +230,7 @@ void shkgone(struct monst *mtmp) { struct eshk *eshk = ESHK(mtmp); - struct mkroom *sroom = &gr.rooms[eshk->shoproom - ROOMOFFSET]; + struct mkroom *sroom = &svr.rooms[eshk->shoproom - ROOMOFFSET]; struct obj *otmp; char *p; int sx, sy; @@ -197,12 +241,12 @@ shkgone(struct monst *mtmp) discard_damage_owned_by(mtmp); sroom->resident = (struct monst *) 0; if (!search_special(ANY_SHOP)) - gl.level.flags.has_shop = 0; + svl.level.flags.has_shop = 0; /* items on shop floor revert to ordinary objects */ for (sx = sroom->lx; sx <= sroom->hx; sx++) for (sy = sroom->ly; sy <= sroom->hy; sy++) - for (otmp = gl.level.objects[sx][sy]; otmp; + for (otmp = svl.level.objects[sx][sy]; otmp; otmp = otmp->nexthere) otmp->no_charge = 0; @@ -223,14 +267,14 @@ void set_residency(struct monst *shkp, boolean zero_out) { if (on_level(&(ESHK(shkp)->shoplevel), &u.uz)) - gr.rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident = + svr.rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident = (zero_out) ? (struct monst *) 0 : shkp; } void replshk(struct monst *mtmp, struct monst *mtmp2) { - gr.rooms[ESHK(mtmp2)->shoproom - ROOMOFFSET].resident = mtmp2; + svr.rooms[ESHK(mtmp2)->shoproom - ROOMOFFSET].resident = mtmp2; if (inhishop(mtmp) && *u.ushops == ESHK(mtmp)->shoproom) { ESHK(mtmp2)->bill_p = &(ESHK(mtmp2)->bill[0]); } @@ -249,7 +293,7 @@ restshk(struct monst *shkp, boolean ghostly) /* savebones guarantees that non-homed shk's will be gone */ if (ghostly) { assign_level(&eshkp->shoplevel, &u.uz); - if (ANGRY(shkp) && strncmpi(eshkp->customer, gp.plname, PL_NSIZ)) + if (ANGRY(shkp) && strncmpi(eshkp->customer, svp.plname, PL_NSIZ)) pacify_shk(shkp, TRUE); } } @@ -317,7 +361,7 @@ clear_no_charge_obj( || !isok(x, y) || (rno = levl[x][y].roomno) < ROOMOFFSET || !IS_SHOP(rno - ROOMOFFSET) - || (rm_shkp = gr.rooms[rno - ROOMOFFSET].resident) == 0 + || (rm_shkp = svr.rooms[rno - ROOMOFFSET].resident) == 0 || rm_shkp == shkp) otmp->no_charge = 0; } @@ -344,8 +388,8 @@ setpaid(struct monst *shkp) clear_unpaid(shkp, gi.invent); clear_unpaid(shkp, fobj); - if (gl.level.buriedobjlist) - clear_unpaid(shkp, gl.level.buriedobjlist); + if (svl.level.buriedobjlist) + clear_unpaid(shkp, svl.level.buriedobjlist); if (gt.thrownobj) clear_unpaid_obj(shkp, gt.thrownobj); if (gk.kickedobj) @@ -359,7 +403,7 @@ setpaid(struct monst *shkp) /* clear obj->no_charge for all obj in shkp's shop */ clear_no_charge(shkp, fobj); - clear_no_charge(shkp, gl.level.buriedobjlist); + clear_no_charge(shkp, svl.level.buriedobjlist); while ((obj = gb.billobjs) != 0) { obj_extract_self(obj); @@ -400,10 +444,10 @@ call_kops(struct monst *shkp, boolean nearshop) if (!Deaf) pline("An alarm sounds!"); - nokops = ((gm.mvitals[PM_KEYSTONE_KOP].mvflags & G_GONE) - && (gm.mvitals[PM_KOP_SERGEANT].mvflags & G_GONE) - && (gm.mvitals[PM_KOP_LIEUTENANT].mvflags & G_GONE) - && (gm.mvitals[PM_KOP_KAPTAIN].mvflags & G_GONE)); + nokops = ((svm.mvitals[PM_KEYSTONE_KOP].mvflags & G_GONE) + && (svm.mvitals[PM_KOP_SERGEANT].mvflags & G_GONE) + && (svm.mvitals[PM_KOP_LIEUTENANT].mvflags & G_GONE) + && (svm.mvitals[PM_KOP_KAPTAIN].mvflags & G_GONE)); if (!angry_guards(!!Deaf) && nokops) { if (flags.verbose && !Deaf) @@ -490,7 +534,7 @@ u_left_shop(char *leavestring, boolean newlev) SetVoice(shkp, 0, 80, 0); verbalize(not_upset ? "%s! Please pay before leaving." : "%s! Don't you leave without paying!", - gp.plname); + svp.plname); } else { pline("%s %s that you need to pay before leaving%s", Shknam(shkp), @@ -604,7 +648,7 @@ staticfn void deserted_shop(/*const*/ char *enterstring) { struct monst *mtmp; - struct mkroom *r = &gr.rooms[(int) *enterstring - ROOMOFFSET]; + struct mkroom *r = &svr.rooms[(int) *enterstring - ROOMOFFSET]; int x, y, m = 0, n = 0; for (x = r->lx; x <= r->hx; ++x) @@ -666,11 +710,11 @@ u_entered_shop(char *enterstring) eshkp->bill_p = &(eshkp->bill[0]); if ((!eshkp->visitct || *eshkp->customer) - && strncmpi(eshkp->customer, gp.plname, PL_NSIZ)) { + && strncmpi(eshkp->customer, svp.plname, PL_NSIZ)) { /* You seem to be new here */ eshkp->visitct = 0; eshkp->following = 0; - (void) strncpy(eshkp->customer, gp.plname, PL_NSIZ); + (void) strncpy(eshkp->customer, svp.plname, PL_NSIZ); pacify_shk(shkp, TRUE); } @@ -689,12 +733,12 @@ u_entered_shop(char *enterstring) return; } - rt = gr.rooms[*enterstring - ROOMOFFSET].rtype; + rt = svr.rooms[*enterstring - ROOMOFFSET].rtype; if (ANGRY(shkp)) { if (!Deaf && !muteshk(shkp)) { SetVoice(shkp, 0, 80, 0); - verbalize("So, %s, you dare return to %s %s?!", gp.plname, + verbalize("So, %s, you dare return to %s %s?!", svp.plname, s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); } else { pline("%s seems %s over your return to %s %s!", @@ -705,7 +749,7 @@ u_entered_shop(char *enterstring) if (!Deaf && !muteshk(shkp)) { SetVoice(shkp, 0, 80, 0); verbalize("Back again, %s? I've got my %s on you.", - gp.plname, mbodypart(shkp, EYE)); + svp.plname, mbodypart(shkp, EYE)); } else { pline_The("atmosphere at %s %s seems unwelcoming.", s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); @@ -722,7 +766,7 @@ u_entered_shop(char *enterstring) } else { if (!Deaf && !muteshk(shkp)) { set_voice(shkp, 0, 80, 0); - verbalize("%s, %s! Welcome%s to %s %s!", Hello(shkp), gp.plname, + verbalize("%s, %s! Welcome%s to %s %s!", Hello(shkp), svp.plname, eshkp->visitct++ ? " again" : "", s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); } else { @@ -811,7 +855,7 @@ pick_pick(struct obj *obj) /* if you bring a sack of N picks into a shop to sell, don't repeat this N times when they're taken out */ - if (gm.moves != pickmovetime) { + if (svm.moves != pickmovetime) { if (!Deaf && !muteshk(shkp)) { SetVoice(shkp, 0, 80, 0); verbalize("You sneaky %s! Get out of here with that pick!", @@ -823,7 +867,7 @@ pick_pick(struct obj *obj) : "is dismayed because of"); } } - pickmovetime = gm.moves; + pickmovetime = svm.moves; } } @@ -934,7 +978,7 @@ shop_keeper(char rmno) { struct monst *shkp; - shkp = (rmno >= ROOMOFFSET) ? gr.rooms[rmno - ROOMOFFSET].resident : 0; + shkp = (rmno >= ROOMOFFSET) ? svr.rooms[rmno - ROOMOFFSET].resident : 0; if (shkp) { if (has_eshk(shkp)) { if (ANGRY(shkp)) { @@ -947,13 +991,13 @@ shop_keeper(char rmno) shkp->isshk ? "shopkeeper career change" : "shop resident not shopkeeper", (int) rmno, - (int) gr.rooms[rmno - ROOMOFFSET].rtype, + (int) svr.rooms[rmno - ROOMOFFSET].rtype, shkp->mnum, /* [real shopkeeper name is kept in ESHK, not MGIVENNAME] */ has_mgivenname(shkp) ? MGIVENNAME(shkp) : "anonymous"); /* not sure if this is appropriate, because it does nothing to - correct the underlying gr.rooms[].resident issue but... */ + correct the underlying svr.rooms[].resident issue but... */ return (struct monst *) 0; } } @@ -1092,7 +1136,7 @@ obfree(struct obj *obj, struct obj *merge) if ((bp = onbill(obj, shkp, FALSE)) != 0) { if (!merge) { - bp->useup = 1; + bp->useup = TRUE; obj->unpaid = 0; /* only for doinvbill */ /* for used up glob, put back original weight in case it gets formatted ('I x' or itemized billing) with 'wizweight' On */ @@ -1195,7 +1239,7 @@ home_shk(struct monst *shkp, boolean killkops) coordxy x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y; (void) mnearto(shkp, x, y, TRUE, RLOC_NOMSG); - gl.level.flags.has_shop = 1; + svl.level.flags.has_shop = 1; if (killkops) { kops_gone(TRUE); pacify_guards(); @@ -1328,7 +1372,7 @@ hot_pursuit(struct monst *shkp) return; rile_shk(shkp); - (void) strncpy(ESHK(shkp)->customer, gp.plname, PL_NSIZ); + (void) strncpy(ESHK(shkp)->customer, svp.plname, PL_NSIZ); ESHK(shkp)->following = 1; /* shopkeeper networking: clear obj->no_charge for all obj on the @@ -1367,58 +1411,227 @@ static const char no_money[] = "Moreover, you%s have no gold.", not_enough_money[] = "Besides, you don't have enough to interest %s."; +/* if one item is used-up and the other isn't, the used-up one comes first; + otherwise, if their costs differ, the more expensive one comes first; + if costs are the same, use internal index as tie-breaker for stable sort */ +staticfn int QSORTCALLBACK +sortbill_cmp(const genericptr vptr1, const genericptr vptr2) +{ + const struct sortbill_item *sbi1 = (struct sortbill_item *) vptr1, + *sbi2 = (struct sortbill_item *) vptr2; + long cost1 = sbi1->cost, cost2 = sbi2->cost; + int bidx1 = sbi1->bidx, bidx2 = sbi2->bidx, + /* sort such that FullyUsedUp and PartlyUsedUp come before + PartlyIntact, FullyIntact, KnownContainer, UndisclosedContainer */ + used1 = sbi1->usedup <= PartlyUsedUp, /* 0=>unpaid, 1=>used */ + used2 = sbi2->usedup <= PartlyUsedUp; + + if (used1 != used2) + return (used2 - used1); /* bigger comes before smaller here */ + if (cost1 != cost2) + return (cost2 - cost1); /* bigger comes before smaller here too */ + /* index into eshkp->bill_p[] isn't unique (an item that is partly + used and partly intact will have two ibill[] entries indexing same + bill_p[] element) but duplicates won't reach here (used1 vs used2) */ + return (bidx1 - bidx2); +} + /* delivers the cheapest item on the list */ staticfn long -cheapest_item(struct monst *shkp) +cheapest_item(int ibillct, Bill *ibill) { - int ct = ESHK(shkp)->billct; - struct bill_x *bp = ESHK(shkp)->bill_p; - long gmin = (bp->price * bp->bquan); + int i; + long gmin = ibill[0].cost; - while (ct--) { - if (bp->price * bp->bquan < gmin) - gmin = bp->price * bp->bquan; - bp++; - } + /* + * 3.7: old version didn't determine cheapest item correctly if it + * was either the partly used or partly intact portion of a partially + * used stack. Rather than modify it to use bp_to_obj() in order to + * obtain quanities for every entry on eshkp->bill_p[], switch to + * ibill[] which has already split such items into separate entries. + */ + + for (i = 1; i < ibillct; ++i) + if (ibill[i].cost < gmin) + gmin = ibill[i].cost; return gmin; } +/* for itemized purchasing, create an alternate shop bill that hides + container contents */ +staticfn int /* returns number of entries */ +make_itemized_bill( + struct monst *shkp, + Bill **ibill_p) /* output, augmented bill similar to a 'sortloot array' */ +{ + static Bill zerosbi; /* Null sortbill item */ + Bill *ibill; + struct bill_x *bp; + struct obj *otmp; + struct eshk *eshkp = ESHK(shkp); + int i, n, ebillct = eshkp->billct; + int8 used; + long quan, cost; + + /* this overallocates unless there happens to be a used-up portion + and an intact potion for every object on the bill; doing it this + way avoids the need to look up every object on the bill an extra + time; (the +1 for a terminator isn't actually needed) */ + n = 2 * ebillct + 1; + ibill = *ibill_p = (Bill *) alloc(n * sizeof *ibill); + for (i = 0; i < n; ++i) + ibill[i] = zerosbi; + + n = 0; /* number of entries in ibill[]; won't necessary match ebillct */ + for (i = 0; i < ebillct; ++i) { + bp = &eshkp->bill_p[i]; + /* find the object on the bill */ + otmp = bp_to_obj(bp); + if (!otmp) { + impossible("Can't find shop bill entry for #%d", bp->bo_id); + continue; + } + + if (otmp->quan == 0L || otmp->where == OBJ_ONBILL) { + /* item is completely used up; restore quantity from when it + was first unpaid; otmp is on billobjs list where it can + only be seen via Ix and itemized billing while paying shk */ + otmp->quan = bp->bquan; + bp->useup = TRUE; /* (expected to be set already) */ + } else if (otmp->quan < bp->bquan) { + /* item is partly used up; we will create two entries in the + augmented bill: one for the used up part here, another for + the intact part (which might be inside a container if put in + after using part of a stack; used up part isn't) below */ + ibill[n].obj = otmp; + ibill[n].quan = bp->bquan - otmp->quan; + ibill[n].cost = bp->price * ibill[n].quan; + ibill[n].bidx = i; /* duplicate index into eshkp->bill_p[] */ + ibill[n].usedup = PartlyUsedUp; /* for sorting */ + ++n; /* intact portion will be a separate entry, next */ + } + + if (otmp->where == OBJ_ONBILL) { + /* completely used up */ + quan = bp->bquan; + cost = bp->price * quan; + used = FullyUsedUp; + } else if (otmp->where == OBJ_CONTAINED || Has_contents(otmp)) { + int j; + struct obj *item = otmp; + boolean cknown = TRUE; /* assume container contents are known */ + + /* when it's in a container, put the container rather than the + specific object into ibill[]; find outermost container */ + while (otmp->where == OBJ_CONTAINED) { + otmp = otmp->ocontainer; + if (!otmp->cknown) + cknown = FALSE; + } + /* this container might already be in ibill[] if it is unpaid + itself or if it holds more than one unpaid item and another + besides this one has already been processed; only include + first instance */ + for (j = 0; j < n; ++j) + if (otmp == ibill[j].obj) + break; + if (j < n) { + /* when already on bill as FullyIntact, update; the cost + saved in ibill[j] is based on the container even if the + entry was initially created for an item of its contents */ + if (ibill[j].usedup == FullyIntact) + ibill[j].usedup = cknown ? KnownContainer + : UndisclosedContainer; + continue; /* 'i' loop */ + } + /* include 1 container containing unpaid item(s) */ + quan = 1L; + cost = unpaid_cost(otmp, COST_CONTENTS); + /* an unpaid container without any unpaid contents is classified + as 'FullyIntact'; a container with unpaid contents will be + '*Container' regardless of whether it is unpaid itself */ + used = (otmp == item) ? FullyIntact + : cknown ? KnownContainer + : UndisclosedContainer; + } else { + /* ordinary unpaid; when partly used, these are values for the + intact portion; might be an empty shop-owned container */ + quan = otmp->quan; + cost = bp->price * quan; + used = (quan < bp->bquan) ? PartlyIntact : FullyIntact; + } + + ibill[n].obj = otmp; + ibill[n].quan = quan; + ibill[n].cost = cost; + ibill[n].bidx = i; + ibill[n].usedup = used; + ++n; + } + ibill[n].bidx = -1; /* end of list; not strictly needed */ + + /* ibill[0..n-1] contains data, ibill[n] has Null obj and -1 bidx */ + if (n > 1) + qsort((genericptr_t) ibill, n, sizeof *ibill, sortbill_cmp); + return n; +} + /* show items on your bill in a menu, and ask which to pay. returns the number of entries selected. */ staticfn int -menu_pick_pay_items(struct monst *shkp) +menu_pick_pay_items( + int ibillct, /* number of entries in ibill[] */ + Bill *ibill) /* all used up items, if any, precede all intact items */ { - struct eshk *eshkp = ESHK(shkp); + struct obj *otmp; winid win; anything any; menu_item *pick_list = (menu_item *) 0; - int i, j, n, clr = NO_COLOR; - char buf[BUFSZ]; + char *p, buf[BUFSZ]; + long amt, largest_amt, save_quan; + int i, j, n, amt_width; any = cg.zeroany; win = create_nhwindow(NHW_MENU); start_menu(win, MENU_BEHAVE_STANDARD); - for (n = 0; n < eshkp->billct; n++) { - struct obj *otmp; - struct bill_x *bp = &(eshkp->bill_p[n]); + /* we go through ibill[] twice, first time to control price formatting + during the second */ + largest_amt = 0L; + for (i = 0; i < ibillct; ++i) + if (ibill[i].cost > largest_amt) + largest_amt = ibill[i].cost; + Sprintf(buf, "%ld", largest_amt); + amt_width = (int) strlen(buf); - bp->queuedpay = FALSE; - - /* find the object on one of the lists */ - if ((otmp = bp_to_obj(bp)) != 0) { - /* if completely used up, object quantity is stale; - restoring it to its original value here avoids - making the partly-used-up code more complicated */ - if (bp->useup) - otmp->quan = bp->bquan; - Snprintf(buf, sizeof buf, "%s%s", - bp->useup ? "(used up) " : "", - doname(otmp)); - any.a_int = n + 1; /* +1: avoid 0 */ - add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr, buf, - MENU_ITEMFLAGS_NONE); + /* show the "used up items" header if there are any used up items on + the bill, no matter whether there are also any intact items; + note: ibill[] has been sorted to hold used-up items first */ + if (ibill[0].usedup <= PartlyUsedUp) { + Sprintf(buf, "Used up item%s:", + (ibillct > 1 && ibill[1].usedup <= PartlyUsedUp) ? "s" : ""); + add_menu_heading(win, buf); + } + for (i = 0; i < ibillct; ++i) { + /* the "unpaid items" header is only shown if the "used up items" + one was shown before the first menu entry */ + if (i > 0 && ibill[i - 1].usedup <= PartlyUsedUp + && ibill[i].usedup >= PartlyIntact) { + Sprintf(buf, "Unpaid item%s:", (i < ibillct - 1) ? "s" : ""); + add_menu_heading(win, buf); } + otmp = ibill[i].obj; + save_quan = otmp->quan; + otmp->quan = ibill[i].quan; /* in case it's partly used */ + p = paydoname(otmp); + otmp->quan = save_quan; + amt = ibill[i].cost; + /* this doesn't support hallucinatory currency because shopkeeper + isn't hallucinating; also, that would mess up the alignment */ + Snprintf(buf, sizeof buf, "%*ld Zm, %s", amt_width, amt, p); + any.a_int = i + 1; /* +1: avoid 0 */ + add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, NO_COLOR, buf, + MENU_ITEMFLAGS_NONE); } end_menu(win, "Pay for which items?"); @@ -1426,11 +1639,17 @@ menu_pick_pay_items(struct monst *shkp) destroy_nhwindow(win); for (j = 0; j < n; ++j) { + /* + * FIXME: + * The menu will accept a subset count for each entry but buying + * doesn't have any support for that. + */ i = pick_list[j].item.a_int - 1; /* -1: reverse +1 above */ - eshkp->bill_p[i].queuedpay = TRUE; + ibill[i].queuedpay = TRUE; } free(pick_list); - return n; + /* for ESC, return 0 instead of usual -1 */ + return max(n, 0); } /* the #pay command */ @@ -1440,10 +1659,12 @@ dopay(void) struct eshk *eshkp; struct monst *shkp; struct monst *nxtm, *resident; + Bill *ibill = (Bill *) NULL; long ltmp; long umoney; - int pass, tmp, sk = 0, seensk = 0, nexttosk = 0; - boolean paid = FALSE, stashed_gold = (hidden_gold(TRUE) > 0L); + int sk = 0, seensk = 0, nexttosk = 0; + boolean paid = FALSE, stashed_gold = (hidden_gold(TRUE) > 0L), + pay_done; gm.multi = 0; @@ -1560,9 +1781,9 @@ dopay(void) if (shkp != resident && NOTANGRY(shkp)) { umoney = money_cnt(gi.invent); - if (!ltmp) + if (!ltmp) { You("do not owe %s anything.", shkname(shkp)); - else if (!umoney) { + } else if (!umoney) { You("%shave no gold.", stashed_gold ? "seem to " : ""); if (stashed_gold) pline("But you have some gold stashed away."); @@ -1627,7 +1848,7 @@ dopay(void) : shkname(shkp), noit_mhim(shkp)); pay(1000L, shkp); - if (strncmp(eshkp->customer, gp.plname, PL_NSIZ) || rn2(3)) + if (strncmp(eshkp->customer, svp.plname, PL_NSIZ) || rn2(3)) make_happy_shk(shkp, FALSE); else pline("But %s is as angry as ever.", shkname(shkp)); @@ -1655,8 +1876,9 @@ dopay(void) else Strcat(sbuf, "for gold picked up and the use of merchandise."); - } else + } else { Strcat(sbuf, "for the use of merchandise."); + } pline1(sbuf); if (umoney + eshkp->credit < dtmp) { pline("But you don't%s have enough gold%s.", @@ -1688,115 +1910,18 @@ dopay(void) paid = TRUE; } } + /* now check items on bill */ + pay_done = TRUE; /* assume success */ if (eshkp->billct) { - boolean itemize; - boolean queuedpay = FALSE, via_menu; - int iprompt; + int ibillct = make_itemized_bill(shkp, &ibill); - umoney = money_cnt(gi.invent); - if (!umoney && !eshkp->credit) { - You("%shave no gold or credit%s.", - stashed_gold ? "seem to " : "", paid ? " left" : ""); - return ECMD_OK; - } - if ((umoney + eshkp->credit) < cheapest_item(shkp)) { - You("don't have enough gold to buy%s the item%s you picked.", - eshkp->billct > 1 ? " any of" : "", plur(eshkp->billct)); - if (stashed_gold) - pline("Maybe you have some gold stashed away?"); - return ECMD_OK; - } - - via_menu = (flags.menu_style != MENU_TRADITIONAL); - /* allow 'm p' to request a menu for menustyle:traditional; - for other styles, it will do the opposite; that doesn't make - a whole lot of sense for a 'request-menu' prefix, but otherwise - it would simply be redundant and there wouldn't be any way to - skip the menu when hero owes for multiple items */ - if (iflags.menu_requested) - via_menu = !via_menu; - /* this will loop for a second iteration iff not initially using a - menu and player answers 'm' to custom ynq prompt */ - do { - if (via_menu && eshkp->billct > 1) { - if (!menu_pick_pay_items(shkp)) - return ECMD_OK; - queuedpay = TRUE; - itemize = FALSE; - via_menu = FALSE; /* reset so that we don't loop */ - } else { - /* this isn't quite right; it itemizes without asking if the - single item on bill is partly used up and partly unpaid */ - iprompt = (eshkp->billct < 2) ? 'y' - : yn_function("Itemized billing?", - "ynq m", 'q', TRUE); - itemize = (iprompt == 'y'); - if (iprompt == 'q') - goto thanks; - via_menu = (iprompt == 'm'); - } - } while (via_menu); - - for (pass = 0; pass <= 1; pass++) { - tmp = 0; - while (tmp < eshkp->billct) { - struct obj *otmp; - struct bill_x *bp = &(eshkp->bill_p[tmp]); - - if (queuedpay && !bp->queuedpay) { - tmp++; - continue; - } - - /* find the object on one of the lists */ - if ((otmp = bp_to_obj(bp)) != 0) { - /* if completely used up, object quantity is stale; - restoring it to its original value here avoids - making the partly-used-up code more complicated */ - if (bp->useup) - otmp->quan = bp->bquan; - } else { - impossible("Shopkeeper administration out of order."); - setpaid(shkp); /* be nice to the player */ - return ECMD_TIME; - } - if (pass == bp->useup && otmp->quan == bp->bquan) { - /* pay for used-up items on first pass and others - * on second, so player will be stuck in the store - * less often; things which are partly used up - * are processed on both passes */ - tmp++; - } else { - switch (dopayobj(shkp, bp, &otmp, pass, itemize)) { - case PAY_CANT: - return ECMD_TIME; /*break*/ - case PAY_BROKE: - paid = TRUE; - goto thanks; /*break*/ - case PAY_SKIP: - tmp++; - continue; /*break*/ - case PAY_SOME: - paid = TRUE; - if (itemize) - bot(); - continue; /*break*/ - case PAY_BUY: - paid = TRUE; - break; - } - if (itemize) - bot(); - *bp = eshkp->bill_p[--eshkp->billct]; - } - } - } - thanks: - if (!itemize) - update_inventory(); /* Done in dopayobj() if itemize. */ + if (!pay_billed_items(shkp, ibillct, ibill, stashed_gold, &paid)) + pay_done = FALSE; /* skip thank you message */ } - if (!ANGRY(shkp) && paid) { + + /* {mute shk,deaf hero}-aware thank you message */ + if (pay_done && !ANGRY(shkp) && paid) { if (!Deaf && !muteshk(shkp)) { SetVoice(shkp, 0, 80, 0); verbalize("Thank you for shopping in %s %s%s", @@ -1810,7 +1935,193 @@ dopay(void) !eshkp->surcharge ? "!" : "."); } } - return ECMD_TIME; + + if (paid) + update_inventory(); + iflags.menu_requested = FALSE; /* reset */ + /* free the sortbill array used for itemized billing */ + if (ibill) { + free((genericptr_t) ibill), ibill = NULL; + nhUse(ibill); + } + return paid ? ECMD_TIME : ECMD_OK; +} + +/* for menustyle=Traditional, choose between paying for everything (by + declining to itemize), asking item-by-item (by accepting itemization), + or switch to selecting via menu (special 'm' answer at "Itemize? [ynq m]" + prompt); for other menustyles, always select via menu; + player can use 'm' prefix before 'p' command to invert those behaviors; + once the method is chosen, actually pay for the selected items, item by + item for as long as hero has enough credit+cash */ +staticfn boolean +pay_billed_items( + struct monst *shkp, + int ibillct, + Bill *ibill, + boolean stashed_gold, + boolean *paid_p) /* output */ +{ + struct bill_x *bp; + struct obj *otmp; + long umoney; + boolean itemize, more_than_one; + boolean queuedpay = FALSE, via_menu; + int buy, indx, bidx, pass, iprompt, ebillct; + struct eshk *eshkp = ESHK(shkp); + + umoney = money_cnt(gi.invent); + if (!umoney && !eshkp->credit) { + You("%shave no gold or credit%s.", + stashed_gold ? "seem to " : "", *paid_p ? " left" : ""); + return TRUE; + } + bp = eshkp->bill_p; + otmp = bp_to_obj(bp); + ebillct = eshkp->billct; + more_than_one = (ebillct > 1 || otmp->quan < bp->bquan + /* note: will only get here for a single item, so + we can deduce that it is ibill[0] */ + || ibill[0].usedup == UndisclosedContainer); + if ((umoney + eshkp->credit) < cheapest_item(ibillct, ibill)) { + You("don't have enough gold to buy%s the item%s %s.", + more_than_one ? " any of" : "", plur(more_than_one ? 2 : 1), + (ebillct > 1) ? "you've picked" : "on your bill"); + if (stashed_gold) + pline("Maybe you have some gold stashed away?"); + return TRUE; + } + + via_menu = (flags.menu_style != MENU_TRADITIONAL); + /* allow 'm p' to request a menu for menustyle:traditional; + for other styles, it will do the opposite; that doesn't make + a whole lot of sense for a 'request-menu' prefix, but otherwise + it would simply be redundant and there wouldn't be any way to + skip the menu when hero owes for multiple items */ + if (iflags.menu_requested) + via_menu = !via_menu; + /* this will loop for a second iteration iff not initially using a + menu and player answers 'm' at custom ynq prompt */ + do { + if (via_menu /*&& more_than_one*/ ) { + if (!menu_pick_pay_items(ibillct, ibill)) + return TRUE; + queuedpay = TRUE; + itemize = FALSE; + via_menu = FALSE; /* reset so that we don't loop */ + } else { + iprompt = !more_than_one ? 'y' + : yn_function("Itemized billing?", "ynq m", 'q', TRUE); + if (iprompt == 'q') + return TRUE; + itemize = (iprompt == 'y'); + via_menu = (iprompt == 'm'); + } + } while (via_menu); + + /* + * 3.7: this used to make two passes through eshkp->bill_p[], + * the first for used up items and the second for unpaid ones. + * Items which were partly used were processed on both passes. + * + * Now it makes one pass through ibill[], which has all used up + * items sorted to the beginning and unpaid ones sorted to the end. + * Partly used items have two entries for same base item, one in + * each section. + */ + for (indx = 0; indx < ibillct; ++indx) { + if (queuedpay && !ibill[indx].queuedpay) + continue; + + bidx = ibill[indx].bidx; + bp = &eshkp->bill_p[bidx]; + otmp = ibill[indx].obj; + pass = (ibill[indx].usedup <= PartlyUsedUp) ? 0 : 1; + + if (ibill[indx].usedup >= KnownContainer) { + /* when successfull, buy_container() will call both + dopayobj() and update_bill(), possibly multiple times */ + int boxbag_result = buy_container(shkp, indx, ibillct, ibill); + + if (boxbag_result == 0) { + buy = PAY_BUY; + } else { /* buy_container() failed... */ + if (boxbag_result == 2) /* ... but didn't explain why */ + verbalize("You need to remove any unpaid items from" + " that %s and buy them separately.", + simpleonames(otmp)); + buy = PAY_CANT; + } + } else { + buy = dopayobj(shkp, bp, otmp, pass, itemize, FALSE); + + if (buy == PAY_BUY) + update_bill(indx, ibillct, ibill, eshkp, bp, otmp); + } + switch (buy) { + case PAY_CANT: + return FALSE; + case PAY_BROKE: + *paid_p = TRUE; + return TRUE; + case PAY_SKIP: + continue; + /* case PAY_SOME: //no longer used */ + case PAY_BUY: + *paid_p = TRUE; + if (itemize || queuedpay) { + update_inventory(); + bot(); + } + break; + } + } + return TRUE; +} + +/* update shk's bill and augmented bill after an item has been purchased */ +staticfn void +update_bill( + int indx, + int ibillct, + Bill *ibill, + struct eshk *eshkp, + struct bill_x *bp, + struct obj *paiditem) +{ + int j, newebillct; + int bidx = ibill[indx].bidx; + + /* remove from eshkp->bill_p[] unless this was the used up portion + of partly used item (since removal would take out both; note: + can't buy PartlyIntact until PartlyUsedUp has been paid for) */ + if (ibill[indx].usedup == PartlyUsedUp) { + /* 'paiditem' points to the partly intact portion still in invent or + inside a container (ibill[indx].obj points to the container) */ + bp->bquan = paiditem->quan; + for (j = 0; j < ibillct; ++j) + if (ibill[j].obj == paiditem && ibill[j].usedup == PartlyIntact) { + ibill[j].usedup = FullyIntact; + break; + } + } else { + /* if we get here, something was bought and needs to be removed + from shop bill; if it was used up, remove it from the billobjs + list and delete it; update shop's bill by moving last bill_p[] + entry into vacated slot; also update ibill[] indices for that */ + paiditem->unpaid = 0; /* set before maybe deallocating */ + if (paiditem->where == OBJ_ONBILL) { + obj_extract_self(paiditem); + dealloc_obj(paiditem); + } + newebillct = eshkp->billct - 1; + *bp = eshkp->bill_p[newebillct]; + for (j = 0; j < ibillct; ++j) + if (ibill[j].bidx == newebillct) + ibill[j].bidx = bidx; + eshkp->billct = newebillct; /* eshkp->billct - 1 */ + } + return; } /* return 2 if used-up portion paid @@ -1823,29 +2134,26 @@ staticfn int dopayobj( struct monst *shkp, struct bill_x *bp, - struct obj **obj_p, + struct obj *obj, int which /* 0 => used-up item, 1 => other (unpaid or lost) */, - boolean itemize) - + boolean itemize, + boolean unseen) { - struct obj *obj = *obj_p; long ltmp, quan, save_quan; - long umoney = money_cnt(gi.invent); int buy; - boolean stashed_gold = (hidden_gold(TRUE) > 0L), - consumed = (which == 0); + boolean consumed = (which == 0); - if (!obj->unpaid && !bp->useup) { + if (!obj->unpaid && !bp->useup + && !(Has_contents(obj) && unpaid_cost(obj, COST_CONTENTS))) { impossible("Paid object on bill??"); return PAY_BUY; } - if (itemize && umoney + ESHK(shkp)->credit == 0L) { - You("%shave no gold or credit left.", - stashed_gold ? "seem to " : ""); + if (itemize && insufficient_funds(shkp, obj, 0L)) { return PAY_BROKE; } /* we may need to temporarily adjust the object, if part of the - original quantity has been used up but part remains unpaid */ + original quantity has been used up but part remains unpaid; [note: + this predates 'ibill[]' and feels redundant but still works] */ save_quan = obj->quan; if (consumed) { /* either completely used up (simple), or split needed */ @@ -1856,83 +2164,232 @@ dopayobj( /* dealing with ordinary unpaid item */ quan = obj->quan; } - obj->quan = quan; /* to be used by doname() */ - obj->unpaid = 0; /* ditto */ - iflags.suppress_price++; /* affects containers */ ltmp = bp->price * quan; + + obj->quan = quan; /* to be used by doname() */ + iflags.suppress_price++; /* affects containers */ buy = PAY_BUY; /* flag; if changed then return early */ if (itemize) { char qbuf[BUFSZ], qsfx[BUFSZ]; + /* + * TODO: + * This should also accept 'a' and 'q' to end itemized paying: + * 'a' to buy the rest without asking, 'q' to just stop. + */ + Sprintf(qsfx, " for %ld %s. Pay?", ltmp, currency(ltmp)); (void) safe_qbuf(qbuf, (char *) 0, qsfx, obj, (quan == 1L) ? Doname2 : doname, ansimpleoname, (quan == 1L) ? "that" : "those"); if (y_n(qbuf) == 'n') { buy = PAY_SKIP; /* don't want to buy */ - } else if (quan < bp->bquan && !consumed) { /* partly used goods */ - obj->quan = bp->bquan - save_quan; /* used up amount */ - if (!Deaf && !muteshk(shkp)) { - SetVoice(shkp, 0, 80, 0); - verbalize("%s for the other %s before buying %s.", - 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), - ANGRY(shkp) ? "angrily " : "", - nolimbs(shkp->data) ? "motions to" : "points out", - simpleonames(obj)); - } - buy = PAY_SKIP; /* shk won't sell */ } + } /* itemize */ + + if (quan < bp->bquan && !consumed) { /* partly used goods */ + /* shk won't sell the intact portion until the used up portion has + been paid for (once it has been, bp->bquan will match quan) */ + reject_purchase(shkp, obj, bp->bquan); + buy = PAY_SKIP; } - if (buy == PAY_BUY && umoney + ESHK(shkp)->credit < ltmp) { - You("don't%s have gold%s enough to pay for %s.", - stashed_gold ? " seem to" : "", - (ESHK(shkp)->credit > 0L) ? " or credit" : "", - thesimpleoname(obj)); + if (buy == PAY_BUY && insufficient_funds(shkp, obj, ltmp)) { buy = itemize ? PAY_SKIP : PAY_CANT; } - if (buy != PAY_BUY) { - /* restore unpaid object to original state */ - obj->quan = save_quan; - obj->unpaid = 1; - iflags.suppress_price--; - return buy; + if (buy == PAY_BUY) { + pay(ltmp, shkp); + if (!unseen) + shk_names_obj(shkp, obj, + consumed + ? "paid for %s at a cost of %ld gold piece%s.%s" + : "bought %s for %ld gold piece%s.%s", + ltmp, ""); } - pay(ltmp, shkp); - shk_names_obj(shkp, obj, - consumed ? "paid for %s at a cost of %ld gold piece%s.%s" - : "bought %s for %ld gold piece%s.%s", - ltmp, ""); + /* restore obj to original state */ obj->quan = save_quan; /* restore original count */ - /* quan => amount just bought, save_quan => remaining unpaid count */ + iflags.suppress_price--; - iflags.suppress_price--; /* before update_inventory() below */ - if (consumed) { - if (quan != bp->bquan) { - /* eliminate used-up portion; remainder is still unpaid */ - bp->bquan = obj->quan; - obj->unpaid = 1; - bp->useup = 0; - buy = PAY_SOME; - } else { /* completely used-up, so get rid of it */ - obj_extract_self(obj); - /* assert( obj == *obj_p ); */ - dealloc_obj(obj); - *obj_p = 0; /* destroy pointer to freed object */ - } - } else if (itemize) { - update_inventory(); /* Done just once in dopay() if !itemize. */ - } return buy; } +/* pay for the unpaid contents of a container without itemizing, + and for the container itself if it is unpaid too; + returns 0==successfully bought; 1==rejected, message given here; + 2=rejected, caller should issue message */ +staticfn int +buy_container( + struct monst *shkp, + int indx, + int ibillct, + Bill *ibill) +{ + unsigned boid, boids[BILLSZ]; + int i, j, buy, buycount = 0, boidsct = 0; + struct eshk *eshkp = ESHK(shkp); + int bidx = ibill[indx].bidx, + ebillct = eshkp->billct; + struct bill_x *bp = &eshkp->bill_p[bidx]; + struct obj *otmp, *otop, + *container = ibill[indx].obj; + unsigned unpaidcontainer = container->unpaid; + long totalcost = ibill[indx].cost; + boolean sightunseen = ibill[indx].usedup == UndisclosedContainer + /* give feedback just for container+contents rather + than for individiual contents even when those + contents are known */ + || ibill[indx].usedup == KnownContainer; + + /* check for no-gold first, then for not-enough-gold; feedback is + different for the two cases */ + if (insufficient_funds(shkp, container, 0L) + || insufficient_funds(shkp, container, totalcost)) + return 1; /* message given by insufficent_funds() */ + + /* check for partly intact portion of a not-yet-paid partly used item */ + for (i = 0; i < ebillct; ++i) { + bp = &eshkp->bill_p[i]; + otmp = bp_to_obj(bp); /* ibill[bidx].obj is the container */ + if (!otmp) { + impossible("Can't find contained item on shop bill (#%d).", + bp->bo_id); + return 2; /* failure; have caller give a generic message */ + } + if (otmp->where != OBJ_CONTAINED && !Has_contents(otmp)) + continue; + /* otmp is contained, but possibly inside a different container */ + for (otop = otmp; otop->where == OBJ_CONTAINED; + otop = otop->ocontainer) + continue; /* where==OBJ_CONTAINED loop */ + if (otop != container) + continue; /* 'i' loop */ + /* now check for partly intact portion of partly used item */ + if (otmp->quan < bp->bquan) { + reject_purchase(shkp, otmp, bp->bquan); + return 1; /* message given by reject_purchase() */ + } + /* record this for the second pass; unless it's the container--that + will be deferred until after the loop so that it will be last */ + if (bp->bo_id != container->o_id) + boids[boidsct++] = bp->bo_id; + } + if (unpaidcontainer) + boids[boidsct++] = container->o_id; + + /* now make the actual purchasing pass; we've collected a set of + o_id values in order to avoid traversing the shk's bill while it + undergoes updates */ + for (j = 0; j < boidsct; ++j) { + boid = boids[j]; + for (i = 0, bp = eshkp->bill_p; i < ebillct; ++i, ++bp) + if (bp->bo_id == boid) + break; + if (i == ebillct) { + impossible("Buying %s contents: item #%u disappeared from bill.", + simpleonames(container), boid); + return 2; + } + otmp = bp_to_obj(bp); + + buy = dopayobj(shkp, bp, otmp, 1, FALSE, sightunseen); + if (buy != PAY_BUY) + impossible("Buying %s contents failed unexpectedly (#%u %d).", + simpleonames(container), otmp->o_id, buy); + update_bill(indx, ibillct, ibill, eshkp, bp, otmp); + ++buycount; + } + if (buycount && sightunseen) { + /* if the container was unpaid, the hero has just purchased it; + normally paydoname()--called by shk_names_obj()--would give + "contents of your " when it's hero-owned but we + want it to reflect container's state before purchase; + since paydoname() isn't called for no_charge items, we use + obj->no_charge as a hack to avoid that phrasing in favor of + "a/an and its contents"; temporarily set + obj->unpaid to reflect the before-purchase state too */ + if (unpaidcontainer) + container->unpaid = container->no_charge = 1; + shk_names_obj(shkp, container, + "bought %s for %ld gold piece%s.%s", + totalcost, ""); + container->unpaid = container->no_charge = 0; + } + + return buycount ? 0 : 2; /* we don't expect buycount to be 0 */ +} + +/* called if an item on shop bill is partly used up and partly intact and + player tries to buy the intact portion before paying for used up portion + (not actually very effective since player can just drop the unpaid + portion then pick it back up to have it get its own distinct bill entry; + the former partly used up portion becomes a fully used up separate item) */ +staticfn void +reject_purchase( + struct monst *shkp, + struct obj *obj, + long billed_quan) +{ + long intact_quan = obj->quan; + + assert(intact_quan < billed_quan); + /* temporarily change obj to refer to the used up portion */ + obj->quan = billed_quan - intact_quan; + if (!Deaf && !muteshk(shkp)) { + char which[BUFSZ]; + + if (obj->where == OBJ_CONTAINED) + Snprintf(which, sizeof which, "the one%s in %s", + plur(intact_quan), thesimpleoname(obj->ocontainer)); + else + Sprintf(which, "%s", (intact_quan > 1L) ? "these" : "this one"); + + SetVoice(shkp, 0, 80, 0); + verbalize("%s for the other %s before buying %s.", + ANGRY(shkp) ? "Pay" : "Please pay", + simpleonames(obj), /* short name suffices */ + which); + } 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)); + } + obj->quan = intact_quan; +} + +/* gold+credit checking+feedback common to dopayobj() and buy_container() */ +staticfn boolean +insufficient_funds( + struct monst *shkp, + struct obj *item, + long cost) /* 0: check for no-gold; >0: check for specified amount */ +{ + long stashed_gold; + long umoney = money_cnt(gi.invent), + ecredit = ESHK(shkp)->credit; + + /* dopayobj() checks for no-gold early and not-enough-gold later; + buy_container() checks for both early but uses separate calls to us */ + if (!cost && umoney + ecredit == 0L) { + stashed_gold = hidden_gold(TRUE); + You("%shave no gold or credit left.", + (stashed_gold > 0) ? "seem to " : ""); + return TRUE; + } + if (cost && umoney + ecredit < cost) { + stashed_gold = hidden_gold(TRUE); + You("don't%s have gold%s enough to pay for %s.", + (stashed_gold > 0L) ? " seem to" : "", + (ecredit > 0L) ? " or credit" : "", + paydoname(item)); + return TRUE; + } + return FALSE; +} + /* routine called after dying (or quitting) */ boolean paybill( @@ -2109,7 +2566,7 @@ inherits( if (!silently) pline("%s %s the %ld %s %sowed %s.", Shknam(shkp), takes, loss, currency(loss), - strncmp(eshkp->customer, gp.plname, PL_NSIZ) ? "" + strncmp(eshkp->customer, svp.plname, PL_NSIZ) ? "" : "you ", noit_mhim(shkp)); /* shopkeeper has now been paid in full */ @@ -2238,7 +2695,7 @@ find_oid(unsigned int id) return obj; if ((obj = o_on(id, fobj)) != 0) return obj; - if ((obj = o_on(id, gl.level.buriedobjlist)) != 0) + if ((obj = o_on(id, svl.level.buriedobjlist)) != 0) return obj; if ((obj = o_on(id, gm.migrating_objs)) != 0) return obj; @@ -2331,6 +2788,13 @@ get_cost( struct obj *obj, struct monst *shkp) /* if angry, impose a surcharge */ { + /* + * FIXME: + * If this obj is already on the shop's bill, use the price which + * has been set there. Otherwise, the amount could be different + * (if billed while undiscovered and now become discovered or + * hero's charisma and/or visible worn gear have changed). + */ long tmp = getprice(obj, FALSE), /* used to perform a single calculation even when multiple adjustments (unID'd, dunce/tourist, charisma) are made */ @@ -2750,42 +3214,50 @@ unpaid_cost( return amt; } +/* add 'obj' to 'shkp's bill */ staticfn void -add_one_tobill(struct obj *obj, boolean dummy, struct monst *shkp) +add_one_tobill( + struct obj *obj, + boolean dummy, /* True: obj is used up so goes on bill differently */ + struct monst *shkp) { struct eshk *eshkp; struct bill_x *bp; int bct; + boolean unbilled = FALSE; - if (!billable(&shkp, obj, *u.ushops, TRUE)) - return; eshkp = ESHK(shkp); - - if (eshkp->billct == BILLSZ) { - You("got that for free!"); - /* - * FIXME: - * What happens when this is a dummy object? It won't be on any - * object list. - */ - return; - } - /* normally bill_p gets set up whenever you enter the shop, but obj might be going onto the bill because hero just snagged it with a grappling hook from outside without ever having been inside */ if (!eshkp->bill_p) - eshkp->bill_p = &(eshkp->bill[0]); + eshkp->bill_p = &eshkp->bill[0]; + + if (!billable(&shkp, obj, *u.ushops, TRUE)) { + /* shk doesn't want it */ + unbilled = TRUE; + } else if (eshkp->billct == BILLSZ) { + /* shk's bill is completely full */ + You("got that for free!"); + unbilled = TRUE; + } + /* if not on any list (probably from bill_dummy_object() which creates + a new OBJ_FREE object), don't leave unmanaged object hanging around */ + if (unbilled) { + if (obj->where == OBJ_FREE) + dealloc_obj(obj); /* change to obj->where==OBJ_DELETED */ + return; + } bct = eshkp->billct; - bp = &(eshkp->bill_p[bct]); + bp = &eshkp->bill_p[bct]; bp->bo_id = obj->o_id; bp->bquan = obj->quan; if (dummy) { /* a dummy object must be inserted into */ - bp->useup = 1; /* the gb.billobjs chain here. crucial for */ + bp->useup = TRUE; /* the gb.billobjs chain here. crucial for */ add_to_billobjs(obj); /* eating floorfood in shop. see eat.c */ } else - bp->useup = 0; + bp->useup = FALSE; bp->price = get_cost(obj, shkp); if (obj->globby) { /* for globs, the amt charged for quan 1 depends on owt */ @@ -2869,7 +3341,7 @@ shk_names_obj( was_unknown |= !objects[obj->otyp].oc_name_known; makeknown(obj->otyp); } - obj_name = doname(obj); + obj_name = paydoname(obj); /* Use an alternate message when extra information is being provided */ if (was_unknown) { Sprintf(fmtbuf, "%%s; you %s", fmt); @@ -3078,14 +3550,14 @@ splitbill(struct obj *obj, struct obj *otmp) } bp->bquan -= otmp->quan; - if (ESHK(shkp)->billct == BILLSZ) + if (ESHK(shkp)->billct == BILLSZ) { otmp->unpaid = 0; - else { + } else { tmp = bp->price; bp = &(ESHK(shkp)->bill_p[ESHK(shkp)->billct]); bp->bo_id = otmp->o_id; bp->bquan = otmp->quan; - bp->useup = 0; + bp->useup = FALSE; bp->price = tmp; ESHK(shkp)->billct++; } @@ -3104,11 +3576,11 @@ sub_one_frombill(struct obj *obj, struct monst *shkp) otmp = newobj(); *otmp = *obj; otmp->oextra = (struct oextra *) 0; - bp->bo_id = otmp->o_id = next_ident(); /* gc.context.ident++ */ + bp->bo_id = otmp->o_id = next_ident(); /* svc.context.ident++ */ otmp->where = OBJ_FREE; otmp->quan = (bp->bquan -= obj->quan); otmp->owt = 0; /* superfluous */ - bp->useup = 1; + bp->useup = TRUE; add_to_billobjs(otmp); return; } @@ -3299,7 +3771,7 @@ stolen_value( if (!silent) { if (canseemon(shkp)) { Norep("%s booms: \"%s, you are a thief!\"", - Shknam(shkp), gp.plname); + Shknam(shkp), svp.plname); } else if (!Deaf) { Norep("You hear a scream, \"Thief!\""); /* Deaf-aware */ } @@ -3850,22 +4322,22 @@ add_damage( if (!*shops) return; } - for (tmp_dam = gl.level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) + for (tmp_dam = svl.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 = gm.moves; /* needed by pay_for_damage() */ + tmp_dam->when = svm.moves; /* needed by pay_for_damage() */ return; } tmp_dam = (struct damage *) alloc((unsigned) sizeof *tmp_dam); (void) memset((genericptr_t) tmp_dam, 0, sizeof *tmp_dam); - tmp_dam->when = gm.moves; + tmp_dam->when = svm.moves; tmp_dam->place.x = x; tmp_dam->place.y = y; tmp_dam->cost = cost; tmp_dam->typ = levl[x][y].typ; tmp_dam->flags = levl[x][y].flags; - tmp_dam->next = gl.level.damagelist; - gl.level.damagelist = tmp_dam; + tmp_dam->next = svl.level.damagelist; + svl.level.damagelist = tmp_dam; /* If player saw damage, display walls post-repair as walls, not stone */ if (cansee(x, y)) levl[x][y].seenv = SVALL; @@ -3897,7 +4369,7 @@ repairable_damage(struct damage *dam, struct monst *shkp) y = dam->place.y; /* too soon to fix it? */ - if ((gm.moves - dam->when) < REPAIR_DELAY) + if ((svm.moves - dam->when) < REPAIR_DELAY) return FALSE; /* is it a wall? don't fix if anyone is in the way */ if (!IS_ROOM(dam->typ)) { @@ -3925,7 +4397,7 @@ repairable_damage(struct damage *dam, struct monst *shkp) staticfn struct damage * find_damage(struct monst *shkp) { - struct damage *dam = gl.level.damagelist; + struct damage *dam = svl.level.damagelist; if (shk_impaired(shkp)) return NULL; @@ -3946,10 +4418,10 @@ discard_damage_struct(struct damage *dam) if (!dam) return; - if (dam == gl.level.damagelist) { - gl.level.damagelist = dam->next; + if (dam == svl.level.damagelist) { + svl.level.damagelist = dam->next; } else { - struct damage *prev = gl.level.damagelist; + struct damage *prev = svl.level.damagelist; while (prev && prev->next != dam) prev = prev->next; @@ -3964,7 +4436,7 @@ discard_damage_struct(struct damage *dam) staticfn void discard_damage_owned_by(struct monst *shkp) { - struct damage *dam = gl.level.damagelist, *dam2, *prevdam = NULL; + struct damage *dam = svl.level.damagelist, *dam2, *prevdam = NULL; while (dam) { coordxy x = dam->place.x, y = dam->place.y; @@ -3973,8 +4445,8 @@ discard_damage_owned_by(struct monst *shkp) dam2 = dam->next; if (prevdam) prevdam->next = dam2; - if (dam == gl.level.damagelist) - gl.level.damagelist = dam2; + if (dam == svl.level.damagelist) + svl.level.damagelist = dam2; (void) memset(dam, 0, sizeof(struct damage)); free((genericptr_t) dam); dam = dam2; @@ -4034,7 +4506,7 @@ litter_getpos( (void) memset((genericptr_t) litter, 0, 9 * sizeof *litter); - if (gl.level.objects[x][y] && !IS_ROOM(levl[x][y].typ)) { + if (svl.level.objects[x][y] && !IS_ROOM(levl[x][y].typ)) { for (i = 0; i < 9; i++) { ix = x + horiz(i); iy = y + vert(i); @@ -4087,7 +4559,7 @@ litter_scatter( unplacebc(); /* pick 'em up */ placebc(); /* put 'em down */ } - while ((otmp = gl.level.objects[x][y]) != 0) { + while ((otmp = svl.level.objects[x][y]) != 0) { /* Don't mess w/ boulders -- just merge into wall */ if (otmp->otyp == BOULDER || otmp->otyp == ROCK) { obj_extract_self(otmp); @@ -4096,7 +4568,7 @@ litter_scatter( int trylimit = 10; int i = rn2(9), ix, iy; - /* otmp must be moved otherwise gl.level.objects[x][y] will + /* otmp must be moved otherwise svl.level.objects[x][y] will never become Null and while-loop won't terminate */ do { i = (i + 1) % 9; @@ -4289,7 +4761,7 @@ fix_shop_damage(void) struct damage *damg, *nextdamg; /* if this level has no shop damage, there's nothing to do */ - if (!gl.level.damagelist) + if (!svl.level.damagelist) return; /* go through all shopkeepers on the level */ @@ -4301,7 +4773,7 @@ fix_shop_damage(void) /* go through all damage data trying to have this shopkeeper fix it; repair_damage() will only make repairs for damage matching shop controlled by specified shopkeeper */ - for (damg = gl.level.damagelist; damg; damg = nextdamg) { + for (damg = svl.level.damagelist; damg; damg = nextdamg) { nextdamg = damg->next; if (repair_damage(shkp, damg, TRUE)) discard_damage_struct(damg); @@ -4337,26 +4809,26 @@ shk_move(struct monst *shkp) return 0; } if (eshkp->following) { - if (strncmp(eshkp->customer, gp.plname, PL_NSIZ)) { + if (strncmp(eshkp->customer, svp.plname, PL_NSIZ)) { if (!Deaf && !muteshk(shkp)) { SetVoice(shkp, 0, 80, 0); verbalize("%s, %s! I was looking for %s.", Hello(shkp), - gp.plname, eshkp->customer); + svp.plname, eshkp->customer); } eshkp->following = 0; return 0; } - if (gm.moves > gf.followmsg + 4) { + if (svm.moves > gf.followmsg + 4) { if (!Deaf && !muteshk(shkp)) { SetVoice(shkp, 0, 80, 0); verbalize("%s, %s! Didn't you forget to pay?", - Hello(shkp), gp.plname); + Hello(shkp), svp.plname); } else { pline("%s holds out %s upturned %s.", Shknam(shkp), noit_mhis(shkp), mbodypart(shkp, HAND)); } - gf.followmsg = gm.moves; + gf.followmsg = svm.moves; if (!rn2(9)) { pline("%s doesn't like customers who don't pay.", Shknam(shkp)); @@ -4417,6 +4889,7 @@ shk_move(struct monst *shkp) appr = gtx = gty = 0; } } +#undef GDIST } z = move_special(shkp, inhishop(shkp), appr, uondoor, avoid, omx, omy, @@ -4437,7 +4910,7 @@ after_shk_move(struct monst *shkp) /* reset bill_p, need to re-calc player's occupancy too */ eshkp->bill_p = &eshkp->bill[0]; /* only re-check occupancy if game hasn't just ended */ - if (!gp.program_state.gameover) + if (!program_state.gameover) check_special_room(FALSE); } } @@ -4560,7 +5033,7 @@ makekops(coord *mm) if ((cnt = k_cnt[k]) == 0) break; mndx = k_mndx[k]; - if (gm.mvitals[mndx].mvflags & G_GONE) + if (svm.mvitals[mndx].mvflags & G_GONE) continue; while (cnt--) @@ -4569,6 +5042,42 @@ makekops(coord *mm) } } +staticfn void +getcad( + struct monst *shkp, const char *dmgstr, coordxy x, coordxy y, + boolean uinshp, boolean animal, boolean pursue) +{ + boolean dugwall = (!strcmp(dmgstr, "dig into") /* wand */ + || !strcmp(dmgstr, "damage")); /* pick-axe */ + + if (muteshk(shkp)) { + if (animal && !helpless(shkp)) + yelp(shkp); + } else if (pursue || uinshp || !um_dist(x, y, 1)) { + if (!Deaf) { + SetVoice(shkp, 0, 80, 0); + verbalize("How dare you %s my %s?", dmgstr, + dugwall ? "shop" : "door"); + } else { + pline("%s is %s that you decided to %s %s %s!", + Shknam(shkp), ROLL_FROM(angrytexts), + dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door"); + } + } else { + if (!Deaf) { + pline("%s shouts:", Shknam(shkp)); + SetVoice(shkp, 0, 80, 0); + verbalize("Who dared %s my %s?", dmgstr, + dugwall ? "shop" : "door"); + } else { + pline("%s is %s that someone decided to %s %s %s!", + Shknam(shkp), ROLL_FROM(angrytexts), + dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door"); + } + } + hot_pursuit(shkp); +} + void pay_for_damage(const char *dmgstr, boolean cant_mollify) { @@ -4577,8 +5086,6 @@ pay_for_damage(const char *dmgstr, boolean cant_mollify) boolean uinshp = (*u.ushops != '\0'); char qbuf[80]; coordxy x, y; - boolean dugwall = (!strcmp(dmgstr, "dig into") /* wand */ - || !strcmp(dmgstr, "damage")); /* pick-axe */ boolean animal, pursue; struct damage *tmp_dam, *appear_here = 0; long cost_of_damage = 0L; @@ -4586,10 +5093,10 @@ pay_for_damage(const char *dmgstr, boolean cant_mollify) nearest_damage = nearest_shk; int picks = 0; - for (tmp_dam = gl.level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) { + for (tmp_dam = svl.level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) { char *shp; - if (tmp_dam->when != gm.moves || !tmp_dam->cost) + if (tmp_dam->when != svm.moves || !tmp_dam->cost) continue; cost_of_damage += tmp_dam->cost; Strcpy(shops_affected, @@ -4636,7 +5143,7 @@ pay_for_damage(const char *dmgstr, boolean cant_mollify) y = appear_here->place.y; /* not the best introduction to the shk... */ - (void) strncpy(ESHK(shkp)->customer, gp.plname, PL_NSIZ); + (void) strncpy(ESHK(shkp)->customer, svp.plname, PL_NSIZ); /* if the shk is already on the war path, be sure it's all out */ if (ANGRY(shkp) || ESHK(shkp)->following) { @@ -4649,7 +5156,8 @@ pay_for_damage(const char *dmgstr, boolean cant_mollify) if (!cansee(shkp->mx, shkp->my)) return; pursue = TRUE; - goto getcad; + getcad(shkp, dmgstr, x, y, uinshp, animal, pursue); + return; } if (uinshp) { @@ -4659,8 +5167,10 @@ pay_for_damage(const char *dmgstr, boolean cant_mollify) mnexto(shkp, RLOC_NOMSG); } pursue = um_dist(shkp->mx, shkp->my, 1); - if (pursue) - goto getcad; + if (pursue) { + getcad(shkp, dmgstr, x, y, uinshp, animal, pursue); + return; + } } else { /* * Make shkp show up at the door. Effect: If there is a monster @@ -4693,33 +5203,7 @@ pay_for_damage(const char *dmgstr, boolean cant_mollify) if ((um_dist(x, y, 1) && !uinshp) || cant_mollify || (money_cnt(gi.invent) + ESHK(shkp)->credit) < cost_of_damage || !rn2(50)) { - getcad: - if (muteshk(shkp)) { - if (animal && !helpless(shkp)) - yelp(shkp); - } else if (pursue || uinshp || !um_dist(x, y, 1)) { - if (!Deaf) { - SetVoice(shkp, 0, 80, 0); - verbalize("How dare you %s my %s?", dmgstr, - dugwall ? "shop" : "door"); - } else { - pline("%s is %s that you decided to %s %s %s!", - Shknam(shkp), ROLL_FROM(angrytexts), - dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door"); - } - } else { - if (!Deaf) { - pline("%s shouts:", Shknam(shkp)); - SetVoice(shkp, 0, 80, 0); - verbalize("Who dared %s my %s?", dmgstr, - dugwall ? "shop" : "door"); - } else { - pline("%s is %s that someone decided to %s %s %s!", - Shknam(shkp), ROLL_FROM(angrytexts), - dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door"); - } - } - hot_pursuit(shkp); + getcad(shkp, dmgstr, x, y, uinshp, animal, pursue); return; } @@ -4776,7 +5260,7 @@ costly_spot(coordxy x, coordxy y) struct monst *shkp; struct eshk *eshkp; - if (!gl.level.flags.has_shop) + if (!svl.level.flags.has_shop) return FALSE; shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)); if (!shkp || !inhishop(shkp)) @@ -4816,7 +5300,7 @@ shop_object(coordxy x, coordxy y) if (!shkp || !inhishop(shkp)) return (struct obj *) 0; - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) if (otmp->oclass != COIN_CLASS) break; /* note: otmp might have ->no_charge set, but that's ok */ @@ -4967,18 +5451,18 @@ shk_chat(struct monst *shkp) (!Deaf && !muteshk(shkp)) ? "mentions" : "indicates", noit_mhe(shkp), eshk->robbed ? "non-paying" : "rude"); } else if (eshk->following) { - if (strncmp(eshk->customer, gp.plname, PL_NSIZ)) { + if (strncmp(eshk->customer, svp.plname, PL_NSIZ)) { if (!Deaf && !muteshk(shkp)) { SetVoice(shkp, 0, 80, 0); verbalize("%s %s! I was looking for %s.", - Hello(shkp), gp.plname, eshk->customer); + Hello(shkp), svp.plname, eshk->customer); } eshk->following = 0; } else { if (!Deaf && !muteshk(shkp)) { SetVoice(shkp, 0, 80, 0); verbalize("%s %s! Didn't you forget to pay?", - Hello(shkp), gp.plname); + Hello(shkp), svp.plname); } else { pline("%s taps you on the %s.", Shknam(shkp), body_part(ARM)); @@ -5546,4 +6030,13 @@ use_unpaid_trapobj(struct obj *otmp, coordxy x, coordxy y) } } +#undef PAY_BUY +#undef PAY_CANT +#undef PAY_SKIP +#undef PAY_BROKE +#undef NOTANGRY +#undef ANGRY +#undef IS_SHOP +#undef muteshk + /*shk.c*/ diff --git a/src/shknam.c b/src/shknam.c index e1b5bd861..7bd9f4e21 100644 --- a/src/shknam.c +++ b/src/shknam.c @@ -413,7 +413,7 @@ shkveg(void) j = maxprob = 0; ok[0] = 0; /* lint suppression */ - for (i = gb.bases[(int) oclass]; i < NUM_OBJECTS; ++i) { + for (i = svb.bases[(int) oclass]; i < NUM_OBJECTS; ++i) { if (objects[i].oc_class != oclass) break; @@ -463,7 +463,7 @@ mkshobj_at(const struct shclass *shp, int sx, int sy, boolean mkspecl) struct obj *novel = mksobj_at(SPE_NOVEL, sx, sy, FALSE, FALSE); if (novel) - gc.context.tribute.bookstock = TRUE; + svc.context.tribute.bookstock = TRUE; return; } @@ -575,7 +575,7 @@ free_eshk(struct monst *mtmp) } /* find a door in room sroom which is good for shop entrance. - returns -1 if no good door found, or the gd.doors index + returns -1 if no good door found, or the svd.doors index and the door coordinates in sx, sy */ staticfn int good_shopdoor(struct mkroom *sroom, coordxy *sx, coordxy *sy) @@ -585,12 +585,12 @@ good_shopdoor(struct mkroom *sroom, coordxy *sx, coordxy *sy) for (i = 0; i < sroom->doorct; i++) { int di = sroom->fdoor + i; - *sx = gd.doors[di].x; - *sy = gd.doors[di].y; + *sx = svd.doors[di].x; + *sy = svd.doors[di].y; /* check that the shopkeeper placement is sane */ if (sroom->irregular) { - int rmno = (int) ((sroom - gr.rooms) + ROOMOFFSET); + int rmno = (int) ((sroom - svr.rooms) + ROOMOFFSET); if (isok(*sx - 1, *sy) && !levl[*sx - 1][*sy].edge && (int) levl[*sx - 1][*sy].roomno == rmno) @@ -646,7 +646,7 @@ shkinit(const struct shclass *shp, struct mkroom *sroom) pline("doormax=%d doorct=%d fdoor=%d", gd.doorindex, sroom->doorct, sh); while (j--) { - pline("door [%d,%d]", gd.doors[sh].x, gd.doors[sh].y); + pline("door [%d,%d]", svd.doors[sh].x, svd.doors[sh].y); sh++; } display_nhwindow(WIN_MESSAGE, FALSE); @@ -666,11 +666,11 @@ shkinit(const struct shclass *shp, struct mkroom *sroom) set_malign(shk); shk->msleeping = 0; mon_learns_traps(shk, ALL_TRAPS); /* we know all the traps already */ - eshkp->shoproom = (schar) ((sroom - gr.rooms) + ROOMOFFSET); + eshkp->shoproom = (schar) ((sroom - svr.rooms) + ROOMOFFSET); sroom->resident = shk; eshkp->shoptype = sroom->rtype; assign_level(&eshkp->shoplevel, &u.uz); - eshkp->shd = gd.doors[sh]; + eshkp->shd = svd.doors[sh]; eshkp->shk.x = sx; eshkp->shk.y = sy; eshkp->robbed = eshkp->credit = eshkp->debit = eshkp->loan = 0L; @@ -692,12 +692,12 @@ stock_room_goodpos(struct mkroom *sroom, int rmno, int sh, int sx, int sy) if (sroom->irregular) { if (levl[sx][sy].edge || (int) levl[sx][sy].roomno != rmno - || distmin(sx, sy, gd.doors[sh].x, gd.doors[sh].y) <= 1) + || distmin(sx, sy, svd.doors[sh].x, svd.doors[sh].y) <= 1) return FALSE; - } else if ((sx == sroom->lx && gd.doors[sh].x == sx - 1) - || (sx == sroom->hx && gd.doors[sh].x == sx + 1) - || (sy == sroom->ly && gd.doors[sh].y == sy - 1) - || (sy == sroom->hy && gd.doors[sh].y == sy + 1)) + } else if ((sx == sroom->lx && svd.doors[sh].x == sx - 1) + || (sx == sroom->hx && svd.doors[sh].x == sx + 1) + || (sy == sroom->ly && svd.doors[sh].y == sy - 1) + || (sy == sroom->hy && svd.doors[sh].y == sy + 1)) return FALSE; /* only generate items on solid floor squares */ @@ -721,7 +721,7 @@ stock_room(int shp_indx, struct mkroom *sroom) int sx, sy, sh; int stockcount = 0, specialspot = 0; char buf[BUFSZ]; - int rmno = (int) ((sroom - gr.rooms) + ROOMOFFSET); + int rmno = (int) ((sroom - svr.rooms) + ROOMOFFSET); const struct shclass *shp = &shtypes[shp_indx]; /* first, try to place a shopkeeper in the room */ @@ -729,8 +729,8 @@ stock_room(int shp_indx, struct mkroom *sroom) return; /* make sure no doorways without doors, and no trapped doors, in shops */ - sx = gd.doors[sroom->fdoor].x; - sy = gd.doors[sroom->fdoor].y; + sx = svd.doors[sroom->fdoor].x; + sy = svd.doors[sroom->fdoor].y; if (levl[sx][sy].doormask == D_NODOOR) { levl[sx][sy].doormask = D_ISOPEN; newsym(sx, sy); @@ -760,7 +760,7 @@ stock_room(int shp_indx, struct mkroom *sroom) || *in_rooms(m, n, 0)) ? ROOM : CORR; } - if (gc.context.tribute.enabled && !gc.context.tribute.bookstock) { + if (svc.context.tribute.enabled && !svc.context.tribute.bookstock) { /* * Out of the number of spots where we're actually * going to put stuff, randomly single out one in particular. @@ -792,7 +792,7 @@ stock_room(int shp_indx, struct mkroom *sroom) mongone(mtmp); } - gl.level.flags.has_shop = TRUE; + svl.level.flags.has_shop = TRUE; } /* does shkp's shop stock this item type? */ @@ -865,7 +865,7 @@ shkname(struct monst *mtmp) } else { const char *shknm = ESHK(mtmp)->shknam; - if (Hallucination && !gp.program_state.gameover) { + if (Hallucination && !program_state.gameover) { const char *const *nlp; int num; diff --git a/src/sit.c b/src/sit.c index 1edd4f4c9..fedb14e38 100644 --- a/src/sit.c +++ b/src/sit.c @@ -135,7 +135,7 @@ throne_sit_effect(void) break; case 10: if (Luck < 0 || (HSee_invisible & INTRINSIC)) { - if (gl.level.flags.nommap) { + if (svl.level.flags.nommap) { pline("A terrible drone fills your head!"); make_confused((HConfusion & TIMEOUT) + (long) rnd(30), FALSE); @@ -275,7 +275,8 @@ dosit(void) You("are already sitting on %s.", mon_nam(u.usteed)); return ECMD_OK; } - if (u.uundetected && is_hider(gy.youmonst.data) && u.umonnum != PM_TRAPPER) + if (u.uundetected && is_hider(gy.youmonst.data) + && u.umonnum != PM_TRAPPER) /* trapper can stay hidden on floor */ u.uundetected = 0; /* no longer on the ceiling */ if (!can_reach_floor(FALSE)) { @@ -303,7 +304,7 @@ dosit(void) && !(uteetering_at_seen_pit(trap) || uescaped_shaft(trap))) { struct obj *obj; - obj = gl.level.objects[u.ux][u.uy]; + obj = svl.level.objects[u.ux][u.uy]; if (gy.youmonst.data->mlet == S_DRAGON && obj->oclass == COIN_CLASS) { You("coil up around your %shoard.", (obj->quan + money_cnt(gi.invent) < u.ulevel * 1000) @@ -320,7 +321,8 @@ dosit(void) pline("Squelch!"); } useupf(obj, obj->quan); - } else if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH)) + } else if (!(Is_box(obj) + || objects[obj->otyp].oc_material == CLOTH)) pline("It's not very comfortable..."); } } else if (trap != 0 || (u.utrap && (u.utraptype >= TT_LAVA))) { diff --git a/src/sounds.c b/src/sounds.c index a6b078d7e..eac50772a 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -22,7 +22,7 @@ mon_in_room(struct monst *mon, int rmtyp) { int rno = levl[mon->mx][mon->my].roomno; if (rno >= ROOMOFFSET) - return gr.rooms[rno - ROOMOFFSET].rtype == rmtyp; + return svr.rooms[rno - ROOMOFFSET].rtype == rmtyp; return FALSE; } @@ -211,24 +211,24 @@ dosounds(void) hallu = Hallucination ? 1 : 0; - if (gl.level.flags.nfountains && !rn2(400)) { + if (svl.level.flags.nfountains && !rn2(400)) { static const char *const fountain_msg[4] = { "bubbling water.", "water falling on coins.", "the splashing of a naiad.", "a soda fountain!", }; You_hear1(fountain_msg[rn2(3) + hallu]); } - if (gl.level.flags.nsinks && !rn2(300)) { + if (svl.level.flags.nsinks && !rn2(300)) { static const char *const sink_msg[3] = { "a slow drip.", "a gurgling noise.", "dishes being washed!", }; You_hear1(sink_msg[rn2(2) + hallu]); } - if (gl.level.flags.has_court && !rn2(200)) { + if (svl.level.flags.has_court && !rn2(200)) { if (get_iter_mons(throne_mon_sound)) return; } - if (gl.level.flags.has_swamp && !rn2(200)) { + if (svl.level.flags.has_swamp && !rn2(200)) { static const char *const swamp_msg[3] = { "hear mosquitoes!", "smell marsh gas!", /* so it's a smell...*/ "hear Donald Duck!", @@ -236,10 +236,10 @@ dosounds(void) You1(swamp_msg[rn2(2) + hallu]); return; } - if (gl.level.flags.has_vault && !rn2(200)) { + if (svl.level.flags.has_vault && !rn2(200)) { if (!(sroom = search_special(VAULT))) { /* strange ... */ - gl.level.flags.has_vault = 0; + svl.level.flags.has_vault = 0; return; } if (gd_sound()) @@ -275,15 +275,15 @@ dosounds(void) } return; } - if (gl.level.flags.has_beehive && !rn2(200)) { + if (svl.level.flags.has_beehive && !rn2(200)) { if (get_iter_mons(beehive_mon_sound)) return; } - if (gl.level.flags.has_morgue && !rn2(200)) { + if (svl.level.flags.has_morgue && !rn2(200)) { if (get_iter_mons(morgue_mon_sound)) return; } - if (gl.level.flags.has_barracks && !rn2(200)) { + if (svl.level.flags.has_barracks && !rn2(200)) { static const char *const barracks_msg[4] = { "blades being honed.", "loud snoring.", "dice being thrown.", "General MacArthur!", @@ -306,14 +306,14 @@ dosounds(void) } } } - if (gl.level.flags.has_zoo && !rn2(200)) { + if (svl.level.flags.has_zoo && !rn2(200)) { if (get_iter_mons(zoo_mon_sound)) return; } - if (gl.level.flags.has_shop && !rn2(200)) { + if (svl.level.flags.has_shop && !rn2(200)) { if (!(sroom = search_special(ANY_SHOP))) { /* strange... */ - gl.level.flags.has_shop = 0; + svl.level.flags.has_shop = 0; return; } if (tended_shop(sroom) @@ -326,7 +326,7 @@ dosounds(void) } return; } - if (gl.level.flags.has_temple && !rn2(200) + if (svl.level.flags.has_temple && !rn2(200) && !(Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) { if (get_iter_mons(temple_priest_sound)) return; @@ -414,7 +414,7 @@ growl(struct monst *mtmp) if (canseemon(mtmp) || !Deaf) { pline("%s %s!", Monnam(mtmp), vtense((char *) 0, growl_verb)); iflags.last_msg = PLNMSG_GROWL; - if (gc.context.run) + if (svc.context.run) nomul(0); } wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 18); @@ -464,7 +464,7 @@ yelp(struct monst *mtmp) if (yelp_verb) { Soundeffect(se, 70); /* Soundeffect() handles Deaf or not Deaf */ pline("%s %s!", Monnam(mtmp), vtense((char *) 0, yelp_verb)); - if (gc.context.run) + if (svc.context.run) nomul(0); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 12); } @@ -504,7 +504,7 @@ whimper(struct monst *mtmp) Soundeffect(se, 50); } pline("%s %s.", Monnam(mtmp), vtense((char *) 0, whimper_verb)); - if (gc.context.run) + if (svc.context.run) nomul(0); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 6); } @@ -693,7 +693,7 @@ domonnoise(struct monst *mtmp) return ECMD_OK; /* leader might be poly'd; if he can still speak, give leader speech */ - if (mtmp->m_id == gq.quest_status.leader_m_id && msound > MS_ANIMAL) + if (mtmp->m_id == svq.quest_status.leader_m_id && msound > MS_ANIMAL) msound = MS_LEADER; /* make sure it's your role's quest guardian; adjust if not */ else if (msound == MS_GUARDIAN && ptr != &mons[gu.urole.guardnum]) @@ -792,12 +792,13 @@ domonnoise(struct monst *mtmp) int vampindex; if (kindred) { - verbl_msg = - "This is my hunting ground that you dare to prowl!"; + verbl_msg = "This is my hunting ground" + " that you dare to prowl!"; } else if (gy.youmonst.data == &mons[PM_SILVER_DRAGON] || gy.youmonst.data == &mons[PM_BABY_SILVER_DRAGON]) { /* Silver dragons are silver in color, not made of silver */ - Sprintf(verbuf, "%s! Your silver sheen does not frighten me!", + Sprintf(verbuf, + "%s! Your silver sheen"" does not frighten me!", (gy.youmonst.data == &mons[PM_SILVER_DRAGON]) ? "Fool" : "Young Fool"); @@ -839,9 +840,9 @@ domonnoise(struct monst *mtmp) } else if (mtmp->mpeaceful) { if (mtmp->mtame && (mtmp->mconf || mtmp->mflee || mtmp->mtrapped - || gm.moves > EDOG(mtmp)->hungrytime || mtmp->mtame < 5)) + || svm.moves > EDOG(mtmp)->hungrytime || mtmp->mtame < 5)) pline_msg = "whines."; - else if (mtmp->mtame && EDOG(mtmp)->hungrytime > gm.moves + 1000) + else if (mtmp->mtame && EDOG(mtmp)->hungrytime > svm.moves + 1000) pline_msg = "yips."; else { if (ptr != &mons[PM_DINGO]) /* dingos do not actually bark */ @@ -857,10 +858,10 @@ domonnoise(struct monst *mtmp) || mtmp->mtame < 5) { Soundeffect(se_feline_yowl, 80); pline_msg = "yowls."; - } else if (gm.moves > EDOG(mtmp)->hungrytime) { + } else if (svm.moves > EDOG(mtmp)->hungrytime) { Soundeffect(se_feline_meow, 80); pline_msg = "meows."; - } else if (EDOG(mtmp)->hungrytime > gm.moves + 1000) { + } else if (EDOG(mtmp)->hungrytime > svm.moves + 1000) { Soundeffect(se_feline_purr, 40); pline_msg = "purrs."; } else { @@ -910,7 +911,7 @@ domonnoise(struct monst *mtmp) if (mtmp->mtame < 5) { Soundeffect(se_equine_neigh, 60); pline_msg = "neighs."; - } else if (gm.moves > EDOG(mtmp)->hungrytime) { + } else if (svm.moves > EDOG(mtmp)->hungrytime) { Soundeffect(se_equine_whinny, 60); pline_msg = "whinnies."; } else { @@ -1045,7 +1046,7 @@ domonnoise(struct monst *mtmp) } else if (mtmp->mhp < mtmp->mhpmax / 2) pline_msg = "asks for a potion of healing."; else if (mtmp->mtame && !mtmp->isminion - && gm.moves > EDOG(mtmp)->hungrytime) + && svm.moves > EDOG(mtmp)->hungrytime) verbl_msg = "I'm hungry."; /* Specific monsters' interests */ else if (is_elf(ptr)) @@ -1067,11 +1068,12 @@ domonnoise(struct monst *mtmp) Phase 1 Phase 2 Phase 3 Collect underpants ? Profit and they never verbalize step 2 so we don't either */ - verbl_msg = (gnomeplan == 1) ? "Phase one, collect underpants." - : "Phase three, profit!"; + verbl_msg = (gnomeplan == 1) + ? "Phase one, collect underpants." + : "Phase three, profit!"; } else { - verbl_msg = - "Many enter the dungeon, and few return to the sunlit lands."; + verbl_msg = "Many enter the dungeon," + " and few return to the sunlit lands."; } } else switch (monsndx(ptr)) { @@ -1191,7 +1193,7 @@ domonnoise(struct monst *mtmp) boolean ms_Death = (ptr == &mons[PM_DEATH]); /* 3.6 tribute */ - if (ms_Death && !gc.context.tribute.Deathnotice + if (ms_Death && !svc.context.tribute.Deathnotice && (book = u_have_novel()) != 0) { if ((tribtitle = noveltitle(&book->novelidx)) != 0) { Sprintf(verbuf, "Ah, so you have a copy of /%s/.", tribtitle); @@ -1201,7 +1203,7 @@ domonnoise(struct monst *mtmp) Strcat(verbuf, " I may have been misquoted there."); verbl_msg = verbuf; } - gc.context.tribute.Deathnotice = 1; + svc.context.tribute.Deathnotice = 1; } else if (ms_Death && rn2(3) && Death_quote(verbuf, sizeof verbuf)) { verbl_msg = verbuf; /* end of tribute addition */ @@ -1334,11 +1336,12 @@ dochat(void) Hallucination ? rndmonnam((char *) 0) : "statue"); return ECMD_OK; } - if (!Deaf && (IS_WALL(levl[tx][ty].typ) || levl[tx][ty].typ == SDOOR)) { + if (!Deaf && (IS_WALL(levl[tx][ty].typ) + || levl[tx][ty].typ == SDOOR)) { /* Talking to a wall; secret door remains hidden by behaving like a wall; IS_WALL() test excludes solid rock even when that serves as a wall bordering a corridor */ - if (Blind && !IS_WALL(gl.lastseentyp[tx][ty])) { + if (Blind && !IS_WALL(svl.lastseentyp[tx][ty])) { /* when blind, you can only talk to a wall if it has already been mapped as a wall */ ; @@ -1561,9 +1564,11 @@ add_sound_mapping(const char *mapping) text[sizeof text - 1] = '\0'; if (sscanf(mapping, "MESG \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d %d", text, filename, &volume, &idx) == 4 - || sscanf(mapping, "MESG %10[^\"] \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d %d", + || sscanf(mapping, + "MESG %10[^\"] \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d %d", msgtyp, text, filename, &volume, &idx) == 5 - || sscanf(mapping, "MESG %10[^\"] \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d", + || sscanf(mapping, + "MESG %10[^\"] \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d", msgtyp, text, filename, &volume) == 4 || sscanf(mapping, "MESG \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d", text, filename, &volume) == 3) { @@ -1587,7 +1592,8 @@ add_sound_mapping(const char *mapping) if (!regex_compile(text, new_map->regex)) { char errbuf[BUFSZ]; - char *re_error_desc = regex_error_desc(new_map->regex, errbuf); + char *re_error_desc + = regex_error_desc(new_map->regex, errbuf); regex_free(new_map->regex); free((genericptr_t) new_map->filename); @@ -2134,7 +2140,11 @@ base_soundname_to_filename( #endif void -set_voice(struct monst *mtmp SPEECHONLY, int32_t tone SPEECHONLY, int32_t volume SPEECHONLY, int32_t moreinfo SPEECHONLY) +set_voice( + struct monst *mtmp SPEECHONLY, + int32_t tone SPEECHONLY, + int32_t volume SPEECHONLY, + int32_t moreinfo SPEECHONLY) { #ifdef SND_SPEECH int32_t gender = (mtmp && mtmp->female) ? FEMALE : MALE; diff --git a/src/sp_lev.c b/src/sp_lev.c index 817623089..316385c29 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -55,7 +55,8 @@ staticfn unsigned int sp_amask_to_amask(unsigned int sp_amask); staticfn void create_monster(monster *, struct mkroom *); staticfn struct obj *create_object(object *, struct mkroom *); staticfn void create_altar(altar *, struct mkroom *); -staticfn boolean search_door(struct mkroom *, coordxy *, coordxy *, xint16, int); +staticfn boolean search_door(struct mkroom *, coordxy *, coordxy *, xint16, + int) NONNULLPTRS; staticfn void create_corridor(corridor *); staticfn struct mkroom *build_room(room *, struct mkroom *); staticfn void light_region(region *); @@ -102,7 +103,8 @@ staticfn void sel_set_ter(coordxy, coordxy, genericptr_t); staticfn void sel_set_door(coordxy, coordxy, genericptr_t); staticfn void sel_set_feature(coordxy, coordxy, genericptr_t); staticfn void levregion_add(lev_region *); -staticfn void get_table_xy_or_coord(lua_State *, lua_Integer *, lua_Integer *); +staticfn void get_table_xy_or_coord(lua_State *, lua_Integer *, + lua_Integer *) NONNULLPTRS; staticfn int get_table_region(lua_State *, const char *, lua_Integer *, lua_Integer *, lua_Integer *, lua_Integer *, boolean); staticfn void set_wallprop_in_selection(lua_State *, int); @@ -362,7 +364,7 @@ lvlfill_maze_grid(int x1, int y1, int x2, int y2, schar filling) for (x = x1; x <= x2; x++) for (y = y1; y <= y2; y++) { - if (gl.level.flags.corrmaze) + if (svl.level.flags.corrmaze) levl[x][y].typ = STONE; else levl[x][y].typ = (y < 2 || ((x % 2) && (y % 2))) ? STONE @@ -625,7 +627,7 @@ flip_level( } /* buried objects */ - for (otmp = gl.level.buriedobjlist; otmp; otmp = otmp->nobj) { + for (otmp = svl.level.buriedobjlist; otmp; otmp = otmp->nobj) { if (!inFlipArea(otmp->ox, otmp->oy)) continue; if (flp & 1) @@ -730,7 +732,7 @@ flip_level( } /* regions (poison clouds, etc) */ - for (i = 0; i < gn.n_regions; i++) { + for (i = 0; i < svn.n_regions; i++) { int j, tmp1, tmp2; if (flp & 1) { tmp1 = FlipY(gr.regions[i]->bounding_box.ly); @@ -759,7 +761,7 @@ flip_level( } /* rooms */ - for (sroom = &gr.rooms[0]; ; sroom++) { + for (sroom = &svr.rooms[0]; ; sroom++) { if (sroom->hx < 0) break; @@ -809,7 +811,7 @@ flip_level( /* doors */ for (i = 0; i < gd.doorindex; i++) { - Flip_coord(gd.doors[i]); + Flip_coord(svd.doors[i]); } /* the map */ @@ -825,13 +827,13 @@ flip_level( levl[x][y] = levl[x][ny]; levl[x][ny] = trm; - otmp = gl.level.objects[x][y]; - gl.level.objects[x][y] = gl.level.objects[x][ny]; - gl.level.objects[x][ny] = otmp; + otmp = svl.level.objects[x][y]; + svl.level.objects[x][y] = svl.level.objects[x][ny]; + svl.level.objects[x][ny] = otmp; - mtmp = gl.level.monsters[x][y]; - gl.level.monsters[x][y] = gl.level.monsters[x][ny]; - gl.level.monsters[x][ny] = mtmp; + mtmp = svl.level.monsters[x][y]; + svl.level.monsters[x][y] = svl.level.monsters[x][ny]; + svl.level.monsters[x][ny] = mtmp; } } if (flp & 2) { @@ -846,13 +848,13 @@ flip_level( levl[x][y] = levl[nx][y]; levl[nx][y] = trm; - otmp = gl.level.objects[x][y]; - gl.level.objects[x][y] = gl.level.objects[nx][y]; - gl.level.objects[nx][y] = otmp; + otmp = svl.level.objects[x][y]; + svl.level.objects[x][y] = svl.level.objects[nx][y]; + svl.level.objects[nx][y] = otmp; - mtmp = gl.level.monsters[x][y]; - gl.level.monsters[x][y] = gl.level.monsters[nx][y]; - gl.level.monsters[nx][y] = mtmp; + mtmp = svl.level.monsters[x][y]; + svl.level.monsters[x][y] = svl.level.monsters[nx][y]; + svl.level.monsters[nx][y] = mtmp; } } @@ -884,7 +886,7 @@ flip_level( if (ball_active && !ball_fliparea) placebc(); Flip_coord(iflags.travelcc); - Flip_coord(gc.context.digging.pos); + Flip_coord(svc.context.digging.pos); } fix_wall_spines(1, 0, COLNO - 1, ROWNO - 1); @@ -1063,7 +1065,7 @@ set_door_orientation(int x, int y) staticfn boolean shared_with_room(int x, int y, struct mkroom *droom) { - int rmno = (droom - gr.rooms) + ROOMOFFSET; + int rmno = (droom - svr.rooms) + ROOMOFFSET; if (!isok(x,y)) return FALSE; @@ -1086,7 +1088,7 @@ maybe_add_door(int x, int y, struct mkroom *droom) { if (droom->hx >= 0 && ((!droom->irregular && inside_room(droom, x, y)) - || (int) levl[x][y].roomno == (droom - gr.rooms) + ROOMOFFSET + || (int) levl[x][y].roomno == (droom - svr.rooms) + ROOMOFFSET || shared_with_room(x, y, droom))) { add_door(x, y, droom); } @@ -1107,10 +1109,10 @@ link_doors_rooms(void) directive, set/clear levl[][].horizontal for it */ set_door_orientation(x, y); - for (tmpi = 0; tmpi < gn.nroom; tmpi++) { - maybe_add_door(x, y, &gr.rooms[tmpi]); - for (m = 0; m < gr.rooms[tmpi].nsubrooms; m++) { - maybe_add_door(x, y, gr.rooms[tmpi].sbrooms[m]); + for (tmpi = 0; tmpi < svn.nroom; tmpi++) { + maybe_add_door(x, y, &svr.rooms[tmpi]); + for (m = 0; m < svr.rooms[tmpi].nsubrooms; m++) { + maybe_add_door(x, y, svr.rooms[tmpi].sbrooms[m]); } } } @@ -1149,7 +1151,7 @@ rndtrap(void) break; case LEVEL_TELEP: case TELEP_TRAP: - if (gl.level.flags.noteleport) + if (svl.level.flags.noteleport) rtrap = NO_TRAP; break; case ROLLING_BOULDER_TRAP: @@ -1168,7 +1170,7 @@ rndtrap(void) * * If x or y is negative, we generate a random coordinate within the area. If * not negative, they are interpreted as relative to the last defined map or - * room, and are output as absolute gl.level.locations coordinates. + * room, and are output as absolute svl.level.locations coordinates. * * The "humidity" flag is used to ensure that engravings aren't created * underwater, or eels on dry land. @@ -1535,10 +1537,11 @@ create_room( + rn2(hx - (lx > 0 ? lx : 3) - dx - xborder + 1); yabs = ly + (ly > 0 ? ylim : 2) + rn2(hy - (ly > 0 ? ly : 2) - dy - yborder + 1); - if (ly == 0 && hy >= (ROWNO - 1) && (!gn.nroom || !rn2(gn.nroom)) + if (ly == 0 && hy >= ROWNO - 1 + && (!svn.nroom || !rn2(svn.nroom)) && (yabs + dy > ROWNO / 2)) { yabs = rn1(3, 2); - if (gn.nroom < 4 && dy > 1) + if (svn.nroom < 4 && dy > 1) dy--; } if (!check_room(&xabs, &dx, &yabs, &dy, vault)) { @@ -1624,12 +1627,12 @@ create_room( split_rects(r1, &r2); if (!vault) { - gs.smeq[gn.nroom] = gn.nroom; + gs.smeq[svn.nroom] = svn.nroom; add_room(xabs, yabs, xabs + wtmp - 1, yabs + htmp - 1, rlit, rtype, FALSE); } else { - gr.rooms[gn.nroom].lx = xabs; - gr.rooms[gn.nroom].ly = yabs; + svr.rooms[svn.nroom].lx = xabs; + svr.rooms[svn.nroom].ly = yabs; } return TRUE; } @@ -1791,7 +1794,7 @@ create_trap(spltrap *t, struct mkroom *croom) if (t->type == VIBRATING_SQUARE) { pick_vibrasquare_location(); - maketrap(gi.inv_pos.x, gi.inv_pos.y, VIBRATING_SQUARE); + maketrap(svi.inv_pos.x, svi.inv_pos.y, VIBRATING_SQUARE); return; } else if (croom) { get_free_room_loc(&x, &y, croom, t->coord); @@ -1920,7 +1923,7 @@ create_monster(monster *m, struct mkroom *croom) pm = (struct permonst *) 0; } else if (m->id != NON_PM) { pm = &mons[m->id]; - g_mvflags = (unsigned) gm.mvitals[monsndx(pm)].mvflags; + g_mvflags = (unsigned) svm.mvitals[monsndx(pm)].mvflags; if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT)) return; if (g_mvflags & G_GONE) /* genocided or extinct */ @@ -2350,9 +2353,9 @@ create_object(object *o, struct mkroom *croom) static const char prize_warning[] = "multiple prizes on %s level"; if (Is_mineend_level(&u.uz)) { - if (!gc.context.achieveo.mines_prize_oid) { - gc.context.achieveo.mines_prize_oid = otmp->o_id; - gc.context.achieveo.mines_prize_otyp = otmp->otyp; + if (!svc.context.achieveo.mines_prize_oid) { + svc.context.achieveo.mines_prize_oid = otmp->o_id; + svc.context.achieveo.mines_prize_otyp = otmp->otyp; /* prevent stacking; cleared when achievement is recorded; will be reset in addinv_core1() */ otmp->nomerge = 1; @@ -2360,9 +2363,9 @@ create_object(object *o, struct mkroom *croom) impossible(prize_warning, "mines end"); } } else if (Is_sokoend_level(&u.uz)) { - if (!gc.context.achieveo.soko_prize_oid) { - gc.context.achieveo.soko_prize_oid = otmp->o_id; - gc.context.achieveo.soko_prize_otyp = otmp->otyp; + if (!svc.context.achieveo.soko_prize_oid) { + svc.context.achieveo.soko_prize_oid = otmp->o_id; + svc.context.achieveo.soko_prize_otyp = otmp->otyp; otmp->nomerge = 1; /* redundant; Sokoban prizes don't stack; * will be reset in addinv_core1() */ } else { @@ -2415,7 +2418,7 @@ create_altar(altar *a, struct mkroom *croom) } else { get_location_coord(&x, &y, DRY, croom, a->coord); if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0) - croom = &gr.rooms[sproom - ROOMOFFSET]; + croom = &svr.rooms[sproom - ROOMOFFSET]; else croom_is_temple = FALSE; } @@ -2439,7 +2442,7 @@ create_altar(altar *a, struct mkroom *croom) levl[x][y].altarmask |= AM_SHRINE; if (a->shrine == 2) /* high altar or sanctum */ levl[x][y].altarmask |= AM_SANCTUM; - gl.level.flags.has_temple = TRUE; + svl.level.flags.has_temple = TRUE; } } @@ -2636,11 +2639,11 @@ create_corridor(corridor *c) impossible("create_corridor to/from a random wall"); return; } - if (!search_door(&gr.rooms[c->src.room], &org.x, &org.y, c->src.wall, + if (!search_door(&svr.rooms[c->src.room], &org.x, &org.y, c->src.wall, c->src.door)) return; if (c->dest.room != -1) { - if (!search_door(&gr.rooms[c->dest.room], + if (!search_door(&svr.rooms[c->dest.room], &dest.x, &dest.y, c->dest.wall, c->dest.door)) return; switch (c->src.wall) { @@ -2703,7 +2706,7 @@ fill_special_room(struct mkroom *croom) /* Shop ? */ if (croom->rtype >= SHOPBASE) { stock_room(croom->rtype - SHOPBASE, croom); - gl.level.flags.has_shop = TRUE; + svl.level.flags.has_shop = TRUE; return; } @@ -2728,28 +2731,28 @@ fill_special_room(struct mkroom *croom) } switch (croom->rtype) { case VAULT: - gl.level.flags.has_vault = TRUE; + svl.level.flags.has_vault = TRUE; break; case ZOO: - gl.level.flags.has_zoo = TRUE; + svl.level.flags.has_zoo = TRUE; break; case COURT: - gl.level.flags.has_court = TRUE; + svl.level.flags.has_court = TRUE; break; case MORGUE: - gl.level.flags.has_morgue = TRUE; + svl.level.flags.has_morgue = TRUE; break; case BEEHIVE: - gl.level.flags.has_beehive = TRUE; + svl.level.flags.has_beehive = TRUE; break; case BARRACKS: - gl.level.flags.has_barracks = TRUE; + svl.level.flags.has_barracks = TRUE; break; case TEMPLE: - gl.level.flags.has_temple = TRUE; + svl.level.flags.has_temple = TRUE; break; case SWAMP: - gl.level.flags.has_swamp = TRUE; + svl.level.flags.has_swamp = TRUE; break; } } @@ -2765,7 +2768,7 @@ build_room(room *r, struct mkroom *mkr) aroom = &gs.subrooms[gn.nsubroom]; okroom = create_subroom(mkr, r->x, r->y, r->w, r->h, rtype, r->rlit); } else { - aroom = &gr.rooms[gn.nroom]; + aroom = &svr.rooms[svn.nroom]; okroom = create_room(r->x, r->y, r->w, r->h, r->xalign, r->yalign, rtype, r->rlit); } @@ -3692,31 +3695,31 @@ lspo_level_flags(lua_State *L) const char *s = luaL_checkstring(L, i); if (!strcmpi(s, "noteleport")) - gl.level.flags.noteleport = 1; + svl.level.flags.noteleport = 1; else if (!strcmpi(s, "hardfloor")) - gl.level.flags.hardfloor = 1; + svl.level.flags.hardfloor = 1; else if (!strcmpi(s, "nommap")) - gl.level.flags.nommap = 1; + svl.level.flags.nommap = 1; else if (!strcmpi(s, "shortsighted")) - gl.level.flags.shortsighted = 1; + svl.level.flags.shortsighted = 1; else if (!strcmpi(s, "arboreal")) - gl.level.flags.arboreal = 1; + svl.level.flags.arboreal = 1; else if (!strcmpi(s, "mazelevel")) - gl.level.flags.is_maze_lev = 1; + svl.level.flags.is_maze_lev = 1; else if (!strcmpi(s, "shroud")) - gl.level.flags.hero_memory = 1; + svl.level.flags.hero_memory = 1; else if (!strcmpi(s, "graveyard")) - gl.level.flags.graveyard = 1; + svl.level.flags.graveyard = 1; else if (!strcmpi(s, "icedpools")) icedpools = 1; else if (!strcmpi(s, "corrmaze")) - gl.level.flags.corrmaze = 1; + svl.level.flags.corrmaze = 1; else if (!strcmpi(s, "premapped")) gc.coder->premapped = 1; else if (!strcmpi(s, "solidify")) gc.coder->solidify = 1; else if (!strcmpi(s, "sokoban")) - Sokoban = 1; /* gl.level.flags.sokoban_rules */ + Sokoban = 1; /* svl.level.flags.sokoban_rules */ else if (!strcmpi(s, "inaccessibles")) gc.coder->check_inaccessibles = 1; else if (!strcmpi(s, "noflipx")) @@ -3726,21 +3729,21 @@ lspo_level_flags(lua_State *L) else if (!strcmpi(s, "noflip")) gc.coder->allow_flips = 0; else if (!strcmpi(s, "temperate")) - gl.level.flags.temperature = 0; + svl.level.flags.temperature = 0; else if (!strcmpi(s, "hot")) - gl.level.flags.temperature = 1; + svl.level.flags.temperature = 1; else if (!strcmpi(s, "cold")) - gl.level.flags.temperature = -1; + svl.level.flags.temperature = -1; else if (!strcmpi(s, "nomongen")) - gl.level.flags.rndmongen = 0; + svl.level.flags.rndmongen = 0; else if (!strcmpi(s, "nodeathdrops")) - gl.level.flags.deathdrops = 0; + svl.level.flags.deathdrops = 0; else if (!strcmpi(s, "noautosearch")) - gl.level.flags.noautosearch = 1; + svl.level.flags.noautosearch = 1; else if (!strcmpi(s, "fumaroles")) - gl.level.flags.fumaroles = 1; + svl.level.flags.fumaroles = 1; else if (!strcmpi(s, "stormy")) - gl.level.flags.stormy = 1; + svl.level.flags.stormy = 1; else { char buf[BUFSZ]; @@ -4617,7 +4620,8 @@ lspo_door(lua_State *L) get_table_xy_or_coord(L, &dx, &dy); x = dx, y = dy; - msk = doorstates2i[get_table_option(L, "state", "random", doorstates)]; + msk = doorstates2i[get_table_option(L, "state", "random", + doorstates)]; } typ = (msk == -1) ? rnddoor() : (coordxy) msk; @@ -4676,7 +4680,7 @@ l_table_getset_feature_flag( } /* guts of nhl_abs_coord; convert a coordinate relative to a map or room - * into an absolute coordinate in gl.level.locations. + * into an absolute coordinate in svl.level.locations. * * If there is no enclosing map or room, the coordinates are assumed to be * absolute already. @@ -4708,7 +4712,7 @@ cvt_to_abscoord(coordxy *x, coordxy *y) } } -/* inverse of cvt_to_abscoord; turn an absolute gl.level.locations coordinate +/* inverse of cvt_to_abscoord; turn an absolute svl.level.locations coordinate * into one relative to the current map or room. */ void cvt_to_relcoord(coordxy *x, coordxy *y) @@ -5358,7 +5362,7 @@ l_get_lregion(lua_State *L, lev_region *tmplregion) /* teleport_region({ region = { x1,y1, x2,y2 } }); */ /* teleport_region({ region = { x1,y1, x2,y2 }, [ region_islev = 1, ] - * exclude = { x1,y1, x2,y2 }, [ exclude_islen = 1, ] [ dir = "up" ] }); */ + * exclude = { x1,y1, x2,y2 }, [ exclude_islen = 1, ] [ dir = "up" ] }); */ /* TODO: maybe allow using selection, with a new method "getextents()"? */ int lspo_teleport_region(lua_State *L) @@ -5438,8 +5442,8 @@ lspo_exclusion(lua_State *L) ez->hy = y2; cvt_to_abscoord(&ez->lx, &ez->ly); cvt_to_abscoord(&ez->hx, &ez->hy); - ez->next = ge.exclusion_zones; - ge.exclusion_zones = ez; + ez->next = sve.exclusion_zones; + sve.exclusion_zones = ez; return 0; } @@ -5507,8 +5511,8 @@ lspo_region(lua_State *L) if (argc <= 1) { lcheck_param_table(L); - /* TODO: "unfilled" ==> filled=0, "filled" ==> filled=1, and - * "lvflags_only" ==> filled=2, probably in a get_table_needfill_opt */ + /* TODO: "unfilled" => filled=0, "filled" => filled=1, and + * "lvflags_only" => filled=2, probably in a get_table_needfill_opt */ needfill = get_table_int_opt(L, "filled", 0); irregular = get_table_boolean_opt(L, "irregular", 0); joined = get_table_boolean_opt(L, "joined", TRUE); @@ -5563,7 +5567,7 @@ lspo_region(lua_State *L) */ room_not_needed = (rtype == OROOM && !irregular && !do_arrival_room && !gi.in_mk_themerooms); - if (room_not_needed || gn.nroom >= MAXNROFROOMS) { + if (room_not_needed || svn.nroom >= MAXNROFROOMS) { region tmpregion; if (!room_not_needed) impossible("Too many rooms on new level!"); @@ -5577,7 +5581,7 @@ lspo_region(lua_State *L) return 0; } - troom = &gr.rooms[gn.nroom]; + troom = &svr.rooms[svn.nroom]; /* mark rooms that must be filled, but do it later */ troom->needfill = needfill; @@ -5587,8 +5591,8 @@ lspo_region(lua_State *L) if (irregular) { gm.min_rx = gm.max_rx = dx1; gm.min_ry = gm.max_ry = dy1; - gs.smeq[gn.nroom] = gn.nroom; - flood_fill_rm(dx1, dy1, gn.nroom + ROOMOFFSET, rlit, TRUE); + gs.smeq[svn.nroom] = svn.nroom; + flood_fill_rm(dx1, dy1, svn.nroom + ROOMOFFSET, rlit, TRUE); add_room(gm.min_rx, gm.min_ry, gm.max_rx, gm.max_ry, FALSE, rtype, TRUE); troom->rlit = rlit; @@ -5721,7 +5725,7 @@ lspo_mazewalk(lua_State *L) } if (ftyp < 1) { - ftyp = gl.level.flags.corrmaze ? CORR : ROOM; + ftyp = svl.level.flags.corrmaze ? CORR : ROOM; } if (dir == W_RANDOM) @@ -5941,7 +5945,7 @@ lspo_finalize_level(lua_State *L) * is currently not possible, we overload the corrmaze flag for this * purpose. */ - if (!gl.level.flags.corrmaze) + if (!svl.level.flags.corrmaze) wallification(1, 0, COLNO - 1, ROWNO - 1); if (L) @@ -5961,8 +5965,8 @@ lspo_finalize_level(lua_State *L) level_finalize_topology(); - for (i = 0; i < gn.nroom; ++i) { - fill_special_room(&gr.rooms[i]); + for (i = 0; i < svn.nroom; ++i) { + fill_special_room(&svr.rooms[i]); } makemap_prepost(FALSE, wtower); @@ -6272,10 +6276,10 @@ sp_level_coder_init(void) (void) memset((genericptr_t) SpLev_Map, 0, sizeof SpLev_Map); - gl.level.flags.is_maze_lev = 0; - gl.level.flags.temperature = In_hell(&u.uz) ? 1 : 0; - gl.level.flags.rndmongen = 1; - gl.level.flags.deathdrops = 1; + svl.level.flags.is_maze_lev = 0; + svl.level.flags.temperature = In_hell(&u.uz) ? 1 : 0; + svl.level.flags.rndmongen = 1; + svl.level.flags.deathdrops = 1; reset_xystart_size(); @@ -6383,7 +6387,7 @@ load_special(const char *name) * is currently not possible, we overload the corrmaze flag for this * purpose. */ - if (!gl.level.flags.corrmaze) + if (!svl.level.flags.corrmaze) wallification(1, 0, COLNO - 1, ROWNO - 1); flip_level_rnd(gc.coder->allow_flips, FALSE); diff --git a/src/spell.c b/src/spell.c index f4c356e31..3a2d4501e 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1,10 +1,10 @@ -/* NetHack 3.7 spell.c $NHDT-Date: 1718303203 2024/06/13 18:26:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.171 $ */ +/* NetHack 3.7 spell.c $NHDT-Date: 1725227807 2024/09/01 21:56:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.173 $ */ /* Copyright (c) M. Stephenson 1988 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" -/* spellmenu arguments; 0 thru n-1 used as gs.spl_book[] index when swapping */ +/* spellmenu arguments; 0..n-1 used as svs.spl_book[] index when swapping */ #define SPELLMENU_CAST (-2) #define SPELLMENU_VIEW (-1) #define SPELLMENU_SORT (MAXSPELL) /* special menu entry */ @@ -18,9 +18,9 @@ initialization; spell memory is decremented at the end of each turn, including the turn on which the spellbook is read; without the extra increment, the hero used to get cheated out of 1 turn of retention */ -#define incrnknow(spell, x) (gs.spl_book[spell].sp_know = KEEN + (x)) +#define incrnknow(spell, x) (svs.spl_book[spell].sp_know = KEEN + (x)) -#define spellev(spell) gs.spl_book[spell].sp_lev +#define spellev(spell) svs.spl_book[spell].sp_lev #define spellname(spell) OBJ_NAME(objects[spellid(spell)]) #define spellet(spell) \ ((char) ((spell < 26) ? ('a' + spell) : ('A' + spell - 26))) @@ -200,7 +200,7 @@ confused_book(struct obj *spellbook) gone = TRUE; } else { You("find yourself reading the %s line over and over again.", - spellbook == gc.context.spbook.book ? "next" : "first"); + spellbook == svc.context.spbook.book ? "next" : "first"); } return gone; } @@ -269,7 +269,7 @@ deadbook(struct obj *book2) arti_cursed = TRUE; } if (otmp->otyp == BELL_OF_OPENING - && (gm.moves - otmp->age) < 5L) { /* you rang it recently */ + && (svm.moves - otmp->age) < 5L) { /* you rang it recently */ if (!otmp->cursed) arti2_primed = TRUE; else @@ -342,7 +342,7 @@ void book_cursed(struct obj *book) { if (book->cursed && gm.multi >= 0 - && go.occupation == learn && gc.context.spbook.book == book) { + && go.occupation == learn && svc.context.spbook.book == book) { pline("%s shut!", Tobjnam(book, "slam")); set_bknown(book, 1); stop_occupation(); @@ -358,25 +358,25 @@ learn(void) short booktype; char splname[BUFSZ]; boolean costly = TRUE, faded_to_blank = FALSE; - struct obj *book = gc.context.spbook.book; + struct obj *book = svc.context.spbook.book; /* JDS: lenses give 50% faster reading; 33% smaller read time */ - if (gc.context.spbook.delay && ublindf + if (svc.context.spbook.delay && ublindf && ublindf->otyp == LENSES && rn2(2)) - gc.context.spbook.delay++; + svc.context.spbook.delay++; if (Confusion) { /* became confused while learning */ (void) confused_book(book); - gc.context.spbook.book = 0; /* no longer studying */ - gc.context.spbook.o_id = 0; - nomul(gc.context.spbook.delay); /* remaining delay is uninterrupted */ + svc.context.spbook.book = 0; /* no longer studying */ + svc.context.spbook.o_id = 0; + nomul(svc.context.spbook.delay); /* remaining delay is uninterrupted */ gm.multi_reason = "reading a book"; gn.nomovemsg = 0; - gc.context.spbook.delay = 0; + svc.context.spbook.delay = 0; return 0; } - if (gc.context.spbook.delay) { - /* not if (gc.context.spbook.delay++), so at end delay == 0 */ - gc.context.spbook.delay++; + if (svc.context.spbook.delay) { + /* not if (svc.context.spbook.delay++), so at end delay == 0 */ + svc.context.spbook.delay++; return 1; /* still busy */ } exercise(A_WIS, TRUE); /* you're studying. */ @@ -422,8 +422,8 @@ learn(void) /* reset spestudied as if polymorph had taken place */ book->spestudied = rn2(book->spestudied); } else { - gs.spl_book[i].sp_id = booktype; - gs.spl_book[i].sp_lev = objects[booktype].oc_level; + svs.spl_book[i].sp_id = booktype; + svs.spl_book[i].sp_lev = objects[booktype].oc_level; incrnknow(i, 1); book->spestudied++; if (!i) @@ -449,15 +449,15 @@ learn(void) if (book->cursed) { /* maybe a demon cursed it */ if (cursed_book(book)) { useup(book); - gc.context.spbook.book = 0; - gc.context.spbook.o_id = 0; + svc.context.spbook.book = 0; + svc.context.spbook.o_id = 0; return 0; } } if (costly) check_unpaid(book); - gc.context.spbook.book = 0; - gc.context.spbook.o_id = 0; + svc.context.spbook.book = 0; + svc.context.spbook.o_id = 0; return 0; } @@ -477,7 +477,7 @@ study_book(struct obj *spellbook) int dullbook = rnd(25) - ACURR(A_WIS); /* adjust chance if hero stayed awake, got interrupted, retries */ - if (gc.context.spbook.delay && spellbook == gc.context.spbook.book) + if (svc.context.spbook.delay && spellbook == svc.context.spbook.book) dullbook -= rnd(objects[booktype].oc_level); if (dullbook > 0) { @@ -492,13 +492,14 @@ study_book(struct obj *spellbook) } } - if (gc.context.spbook.delay && !confused - && spellbook == gc.context.spbook.book + if (svc.context.spbook.delay && !confused + && spellbook == svc.context.spbook.book /* handle the sequence: start reading, get interrupted, have - gc.context.spbook.book become erased somehow, resume reading it */ + svc.context.spbook.book become erased somehow, resume reading it */ && booktype != SPE_BLANK_PAPER) { You("continue your efforts to %s.", - (booktype == SPE_NOVEL) ? "read the novel" : "memorize the spell"); + (booktype == SPE_NOVEL) ? "read the novel" + : "memorize the spell"); } else { /* KMH -- Simplified this code */ if (booktype == SPE_BLANK_PAPER) { @@ -516,7 +517,8 @@ study_book(struct obj *spellbook) spellbook->o_id)) { if (!u.uconduct.literate++) livelog_printf(LL_CONDUCT, - "became literate by reading %s", tribtitle); + "became literate by reading %s", + tribtitle); check_unpaid(spellbook); makeknown(booktype); @@ -534,20 +536,20 @@ study_book(struct obj *spellbook) switch (objects[booktype].oc_level) { case 1: case 2: - gc.context.spbook.delay = -objects[booktype].oc_delay; + svc.context.spbook.delay = -objects[booktype].oc_delay; break; case 3: case 4: - gc.context.spbook.delay = -(objects[booktype].oc_level - 1) + svc.context.spbook.delay = -(objects[booktype].oc_level - 1) * objects[booktype].oc_delay; break; case 5: case 6: - gc.context.spbook.delay = + svc.context.spbook.delay = -objects[booktype].oc_level * objects[booktype].oc_delay; break; case 7: - gc.context.spbook.delay = -8 * objects[booktype].oc_delay; + svc.context.spbook.delay = -8 * objects[booktype].oc_delay; break; default: impossible("Unknown spellbook level %d, book %d;", @@ -602,10 +604,10 @@ study_book(struct obj *spellbook) if (too_hard) { boolean gone = cursed_book(spellbook); - nomul(gc.context.spbook.delay); /* study time */ + nomul(svc.context.spbook.delay); /* study time */ gm.multi_reason = "reading a book"; gn.nomovemsg = 0; - gc.context.spbook.delay = 0; + svc.context.spbook.delay = 0; if (gone || !rn2(3)) { if (!gone) pline_The("spellbook crumbles to dust!"); @@ -618,10 +620,10 @@ study_book(struct obj *spellbook) if (!confused_book(spellbook)) { spellbook->in_use = FALSE; } - nomul(gc.context.spbook.delay); + nomul(svc.context.spbook.delay); gm.multi_reason = "reading a book"; gn.nomovemsg = 0; - gc.context.spbook.delay = 0; + svc.context.spbook.delay = 0; return 1; } spellbook->in_use = FALSE; @@ -630,9 +632,9 @@ study_book(struct obj *spellbook) spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" : "memorize"); } - gc.context.spbook.book = spellbook; - if (gc.context.spbook.book) - gc.context.spbook.o_id = gc.context.spbook.book->o_id; + svc.context.spbook.book = spellbook; + if (svc.context.spbook.book) + svc.context.spbook.o_id = svc.context.spbook.book->o_id; set_occupation(learn, "studying", 0); return 1; } @@ -642,9 +644,9 @@ study_book(struct obj *spellbook) void book_disappears(struct obj *obj) { - if (obj == gc.context.spbook.book) { - gc.context.spbook.book = (struct obj *) 0; - gc.context.spbook.o_id = 0; + if (obj == svc.context.spbook.book) { + svc.context.spbook.book = (struct obj *) 0; + svc.context.spbook.o_id = 0; } } @@ -654,10 +656,10 @@ book_disappears(struct obj *obj) void book_substitution(struct obj *old_obj, struct obj *new_obj) { - if (old_obj == gc.context.spbook.book) { - gc.context.spbook.book = new_obj; - if (gc.context.spbook.book) - gc.context.spbook.o_id = gc.context.spbook.book->o_id; + if (old_obj == svc.context.spbook.book) { + svc.context.spbook.book = new_obj; + if (svc.context.spbook.book) + svc.context.spbook.o_id = svc.context.spbook.book->o_id; } } @@ -814,7 +816,7 @@ docast(void) if (getspell(&spell_no)) { cmdq_add_key(CQ_REPEAT, spellet(spell_no)); - return spelleffects(gs.spl_book[spell_no].sp_id, FALSE, FALSE); + return spelleffects(svs.spl_book[spell_no].sp_id, FALSE, FALSE); } return ECMD_FAIL; } @@ -860,8 +862,8 @@ skill_based_spellbook_id(void) int booktype; const uchar spbook_class = (uchar) SPBOOK_CLASS; - for (booktype = gb.bases[spbook_class]; - booktype < gb.bases[spbook_class + 1]; + for (booktype = svb.bases[spbook_class]; + booktype < svb.bases[spbook_class + 1]; booktype++) { int known_up_to_level; int skill = spell_skilltype(booktype); @@ -888,7 +890,8 @@ skill_based_spellbook_id(void) } if (objects[booktype].oc_level <= known_up_to_level) - makeknown(booktype); + /* makeknown(booktype) but don't exercise Wisdom */ + discover_object(booktype, TRUE, FALSE); } } @@ -1051,9 +1054,9 @@ cast_chain_lightning(void) otherwise other monsters witnessing this would treat it as seeing hero attack a peaceful; mimic will be exposed; forcefight makes hider unhide */ - gc.context.forcefight++; + svc.context.forcefight++; wakeup(mon, FALSE); - gc.context.forcefight--; + svc.context.forcefight--; } } @@ -1701,14 +1704,14 @@ tport_spell(int what) save_tport.tport_indx = MAXSPELL; } else if (what == UNHIDESPELL) { /*assert( save_tport.savespell.sp_id == SPE_TELEPORT_AWAY );*/ - gs.spl_book[save_tport.tport_indx] = save_tport.savespell; + svs.spl_book[save_tport.tport_indx] = save_tport.savespell; save_tport.tport_indx = MAXSPELL; /* burn bridge... */ } else if (what == ADD_SPELL) { - save_tport.savespell = gs.spl_book[i]; + save_tport.savespell = svs.spl_book[i]; save_tport.tport_indx = i; - gs.spl_book[i].sp_id = SPE_TELEPORT_AWAY; - gs.spl_book[i].sp_lev = objects[SPE_TELEPORT_AWAY].oc_level; - gs.spl_book[i].sp_know = KEEN; + svs.spl_book[i].sp_id = SPE_TELEPORT_AWAY; + svs.spl_book[i].sp_lev = objects[SPE_TELEPORT_AWAY].oc_level; + svs.spl_book[i].sp_know = KEEN; return REMOVESPELL; /* operation needed to reverse */ } } else { /* spellid(i) == SPE_TELEPORT_AWAY */ @@ -1716,12 +1719,12 @@ tport_spell(int what) save_tport.tport_indx = MAXSPELL; } else if (what == REMOVESPELL) { /*assert( i == save_tport.tport_indx );*/ - gs.spl_book[i] = save_tport.savespell; + svs.spl_book[i] = save_tport.savespell; save_tport.tport_indx = MAXSPELL; } else if (what == HIDE_SPELL) { - save_tport.savespell = gs.spl_book[i]; + save_tport.savespell = svs.spl_book[i]; save_tport.tport_indx = i; - gs.spl_book[i].sp_id = NO_SPELL; + svs.spl_book[i].sp_id = NO_SPELL; return UNHIDESPELL; /* operation needed to reverse */ } } @@ -1737,8 +1740,8 @@ losespells(void) int n, nzap, i; /* in case reading has been interrupted earlier, discard context */ - gc.context.spbook.book = 0; - gc.context.spbook.o_id = 0; + svc.context.spbook.book = 0; + svc.context.spbook.o_id = 0; /* count the number of known spells */ for (n = 0; n < MAXSPELL; ++n) if (spellid(n) == NO_SPELL) @@ -1844,13 +1847,13 @@ spell_cmp(const genericptr vptr1, const genericptr vptr2) /* * gather up all of the possible parameters except spell name * in advance, even though some might not be needed: - * indx. = spl_orderindx[] index into gs.spl_book[]; - * otyp. = gs.spl_book[] index into objects[]; + * indx. = spl_orderindx[] index into svs.spl_book[]; + * otyp. = svs.spl_book[] index into objects[]; * levl. = spell level; * skil. = skill group aka spell class. */ int indx1 = *(int *) vptr1, indx2 = *(int *) vptr2, - otyp1 = gs.spl_book[indx1].sp_id, otyp2 = gs.spl_book[indx2].sp_id, + otyp1 = svs.spl_book[indx1].sp_id, otyp2 = svs.spl_book[indx2].sp_id, levl1 = objects[otyp1].oc_level, levl2 = objects[otyp2].oc_level, skil1 = objects[otyp1].oc_skill, skil2 = objects[otyp2].oc_skill; @@ -1926,13 +1929,13 @@ sortspells(void) if (gs.spl_sortmode == SORTRETAINORDER) { struct spell tmp_book[MAXSPELL]; - /* sort gs.spl_book[] rather than spl_orderindx[]; + /* sort svs.spl_book[] rather than spl_orderindx[]; this also updates the index to reflect the new ordering (we could just free it since that ordering becomes the default) */ for (i = 0; i < MAXSPELL; i++) - tmp_book[i] = gs.spl_book[gs.spl_orderindx[i]]; + tmp_book[i] = svs.spl_book[gs.spl_orderindx[i]]; for (i = 0; i < MAXSPELL; i++) - gs.spl_book[i] = tmp_book[i], gs.spl_orderindx[i] = i; + svs.spl_book[i] = tmp_book[i], gs.spl_orderindx[i] = i; gs.spl_sortmode = SORTBY_LETTER; /* reset */ return; } @@ -2010,9 +2013,9 @@ dovspell(void) if (!dospellmenu(qbuf, splnum, &othnum)) break; - spl_tmp = gs.spl_book[splnum]; - gs.spl_book[splnum] = gs.spl_book[othnum]; - gs.spl_book[othnum] = spl_tmp; + spl_tmp = svs.spl_book[splnum]; + svs.spl_book[splnum] = svs.spl_book[othnum]; + svs.spl_book[othnum] = spl_tmp; } } } @@ -2032,7 +2035,8 @@ DISABLE_WARNING_FORMAT_NONLITERAL staticfn boolean dospellmenu( const char *prompt, - int splaction, /* SPELLMENU_CAST, SPELLMENU_VIEW, or gs.spl_book[] index */ + int splaction, /* SPELLMENU_CAST, SPELLMENU_VIEW, or + * svs.spl_book[] index */ int *spell_no) { winid tmpwin; @@ -2304,8 +2308,8 @@ initialspell(struct obj *obj) /* initial inventory shouldn't contain duplicate spellbooks */ impossible("Spell %s already known.", OBJ_NAME(objects[otyp])); } else { - gs.spl_book[i].sp_id = otyp; - gs.spl_book[i].sp_lev = objects[otyp].oc_level; + svs.spl_book[i].sp_id = otyp; + svs.spl_book[i].sp_lev = objects[otyp].oc_level; incrnknow(i, 0); } return; @@ -2358,8 +2362,8 @@ force_learn_spell(short otyp) } /* for a going-stale or forgotten spell the sp_id and sp_lev assignments are redundant but harmless; for an unknown spell, they're essential */ - gs.spl_book[i].sp_id = otyp; - gs.spl_book[i].sp_lev = objects[otyp].oc_level; + svs.spl_book[i].sp_id = otyp; + svs.spl_book[i].sp_lev = objects[otyp].oc_level; incrnknow(i, 0); /* set spl_book[i].sp_know to KEEN; unlike when learning * a spell by reading its book, we don't need to add 1 */ return spellet(i); diff --git a/src/stairs.c b/src/stairs.c index 27007c53b..89b9ff3e8 100644 --- a/src/stairs.c +++ b/src/stairs.c @@ -227,7 +227,7 @@ stairs_description( } else { /* known branch stairs; tacking on destination level is too verbose */ Sprintf(outbuf, "branch %s %s to %s", - stairs, updown, gd.dungeons[tolev.dnum].dname); + stairs, updown, svd.dungeons[tolev.dnum].dname); /* dungeons[].dname is capitalized; undo that for "The " */ (void) strsubst(outbuf, "The ", "the "); } diff --git a/src/steal.c b/src/steal.c index 203edb46f..45bf6adef 100644 --- a/src/steal.c +++ b/src/steal.c @@ -1,27 +1,14 @@ -/* NetHack 3.7 steal.c $NHDT-Date: 1707122967 2024/02/05 08:49:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.121 $ */ +/* NetHack 3.7 steal.c $NHDT-Date: 1720895742 2024/07/13 18:35:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.132 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" -staticfn const char *equipname(struct obj *); staticfn int unstolenarm(void); staticfn int stealarm(void); staticfn void worn_item_removal(struct monst *, struct obj *); -staticfn const char * -equipname(struct obj *otmp) -{ - return ((otmp == uarmu) ? shirt_simple_name(otmp) - : (otmp == uarmf) ? boots_simple_name(otmp) - : (otmp == uarms) ? shield_simple_name(otmp) - : (otmp == uarmg) ? gloves_simple_name(otmp) - : (otmp == uarmc) ? cloak_simple_name(otmp) - : (otmp == uarmh) ? helm_simple_name(otmp) - : suit_simple_name(otmp)); -} - /* proportional subset of gold; return value actually fits in an int */ long somegold(long lmoney) @@ -168,7 +155,7 @@ unstolenarm(void) break; gs.stealoid = 0; if (obj) { - You("finish taking off your %s.", equipname(obj)); + You("finish taking off your %s.", armor_simple_name(obj)); } return 0; } @@ -319,6 +306,7 @@ worn_item_removal( struct obj *obj) { char objbuf[BUFSZ], article[20], *p; + const char *verb; int strip_art; Strcpy(objbuf, doname(obj)); @@ -342,7 +330,13 @@ worn_item_removal( && (!strncmp(p + 5, "left ", 5) || !strncmp(p + 5, "right ", 6))) (void) strsubst(p + 2, "on", "from"); - pline("%s takes off %s.", Monnam(mon), objbuf); + /* slightly iffy for alternate weapon that isn't actively dual-wielded, + but it's better to alert the player to the change in equipment than + to suppress the message for that case */ + verb = ((obj->owornmask & W_WEAPONS) != 0L) ? "disarms" + : ((obj->owornmask & W_ACCESSORY) != 0L) ? "removes" + : "takes off"; + pline("%s %s %s.", Some_Monnam(mon), verb, objbuf); iflags.last_msg = PLNMSG_MON_TAKES_OFF_ITEM; /* removal might trigger more messages (due to loss of Lev|Fly; descending happens before the theft in progress finishes) */ @@ -363,6 +357,7 @@ steal(struct monst *mtmp, char *objnambuf) int tmp, could_petrify, armordelay, olddelay, icnt, named = 0, retrycnt = 0; boolean monkey_business = is_animal(mtmp->data), + seen = canspotmon(mtmp), was_doffing, was_punished = Punished; if (objnambuf) @@ -375,10 +370,9 @@ steal(struct monst *mtmp, char *objnambuf) teleporting to safety could result in a previously visible thief no longer being visible; it could also be a case of a blinded hero being able to see via wearing the Eyes of the Overworld and - having those stolen; remember the name in order to avoid "It" - in the eventual " stole " message; (the name might - already be "It"; if so, that's ok) */ - Strcpy(Monnambuf, Monnam(mtmp)); + having those stolen; remember the name as it is now; if unseen, + nymphs will be "Someone" and monkeys will be "Something" */ + Strcpy(Monnambuf, Some_Monnam(mtmp)); /* food being eaten might already be used up but will not have been removed from inventory yet; we don't want to steal that, @@ -496,7 +490,7 @@ steal(struct monst *mtmp, char *objnambuf) pline("%s tries to %s %s%s but gives up.", Monnambuf, ROLL_FROM(how), (otmp->owornmask & W_ARMOR) ? "your " : "", - (otmp->owornmask & W_ARMOR) ? equipname(otmp) + (otmp->owornmask & W_ARMOR) ? armor_simple_name(otmp) : yname(otmp)); /* the fewer items you have, the less likely the thief is going to stick around to try again (0) instead of @@ -541,7 +535,6 @@ steal(struct monst *mtmp, char *objnambuf) } else { int curssv = otmp->cursed; int slowly; - boolean seen = canspotmon(mtmp); otmp->cursed = 0; slowly = (armordelay >= 1 || gm.multi < 0); @@ -552,7 +545,7 @@ steal(struct monst *mtmp, char *objnambuf) : !slowly ? "hand over" : was_doffing ? "continue removing" : "start removing", - equipname(otmp)); + armor_simple_name(otmp)); else urgent_pline("%s seduces you and %s off your %s.", !seen ? "She" : Adjmonnam(mtmp, "beautiful"), @@ -560,7 +553,7 @@ steal(struct monst *mtmp, char *objnambuf) : !slowly ? "you take" : was_doffing ? "you continue taking" : "you start taking", - equipname(otmp)); + armor_simple_name(otmp)); named++; /* the following is to set multi for later on */ nomul(-armordelay); @@ -580,10 +573,14 @@ steal(struct monst *mtmp, char *objnambuf) impossible("Tried to steal a strange worn thing. [%d]", otmp->oclass); } + /* hero's blindfold might have just been stolen; if so, replace + cached "Someone" or "Something" with Monnam */ + if (!seen && canspotmon(mtmp)) + Strcpy(Monnambuf, Monnam(mtmp)); } else if (otmp->owornmask) { /* weapon or ball&chain */ struct obj *item = otmp; - if (otmp == uball && uchain != NULL) + if (otmp == uball) /* non-Null uball implies non-Null uchain */ item = uchain; /* yields a more accurate 'takes off' message */ worn_item_removal(mtmp, item); /* if we switched from uball to uchain for the preface message, @@ -750,29 +747,29 @@ stealamulet(struct monst *mtmp) /* take off outer gear if we're targeting [hypothetical] quest artifact suit, shirt, gloves, or rings */ if ((otmp == uarm || otmp == uarmu) && uarmc) - remove_worn_item(uarmc, FALSE); + worn_item_removal(mtmp, uarmc); if (otmp == uarmu && uarm) - remove_worn_item(uarm, FALSE); + worn_item_removal(mtmp, uarm); if ((otmp == uarmg || ((otmp == uright || otmp == uleft) && uarmg)) && uwep) { /* gloves are about to be unworn; unwield weapon(s) first */ if (u.twoweap) /* remove_worn_item(uswapwep) indirectly */ - remove_worn_item(uswapwep, FALSE); /* clears u.twoweap */ - remove_worn_item(uwep, FALSE); + worn_item_removal(mtmp, uswapwep); /* clears u.twoweap */ + worn_item_removal(mtmp, uwep); } if ((otmp == uright || otmp == uleft) && uarmg) /* calls Gloves_off() to handle wielded cockatrice corpse */ - remove_worn_item(uarmg, FALSE); + worn_item_removal(mtmp, uarmg); /* finally, steal the target item */ if (otmp->owornmask) - remove_worn_item(otmp, TRUE); + worn_item_removal(mtmp, otmp); if (otmp->unpaid) subfrombill(otmp, shop_keeper(*u.ushops)); freeinv(otmp); Strcpy(buf, doname(otmp)); (void) mpickobj(mtmp, otmp); /* could merge and free otmp but won't */ - pline("%s steals %s!", Monnam(mtmp), buf); + pline("%s steals %s!", Some_Monnam(mtmp), buf); if (can_teleport(mtmp->data) && !tele_restrict(mtmp)) (void) rloc(mtmp, RLOC_MSG); (void) encumber_msg(); diff --git a/src/steed.c b/src/steed.c index 7866939f9..2c7be9c2e 100644 --- a/src/steed.c +++ b/src/steed.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 steed.c $NHDT-Date: 1702274036 2023/12/11 05:53:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.115 $ */ +/* NetHack 3.7 steed.c $NHDT-Date: 1720128167 2024/07/04 21:22:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.121 $ */ /* Copyright (c) Kevin Hugo, 1998-1999. */ /* NetHack may be freely redistributed. See license for details. */ @@ -869,12 +869,12 @@ stucksteed(boolean checkfeeding) if (steed) { /* check whether steed can move */ if (helpless(steed)) { - pline("%s won't move!", upstart(y_monnam(steed))); + pline("%s won't move!", YMonnam(steed)); return TRUE; } /* optionally check whether steed is in the midst of a meal */ if (checkfeeding && steed->meating) { - pline("%s is still eating.", upstart(y_monnam(steed))); + pline("%s is still eating.", YMonnam(steed)); return TRUE; } } @@ -906,7 +906,7 @@ place_monster(struct monst *mon, coordxy x, coordxy y) mon->mstate, buf); return; } - if ((othermon = gl.level.monsters[x][y]) != 0) { + if ((othermon = svl.level.monsters[x][y]) != 0) { describe_level(buf, 0); monnm = minimal_monnam(mon, FALSE); othnm = (mon != othermon) ? minimal_monnam(othermon, TRUE) : "itself"; @@ -914,7 +914,7 @@ place_monster(struct monst *mon, coordxy x, coordxy y) monnm, othnm, x, y, othermon->mstate, mon->mstate, buf); } mon->mx = x, mon->my = y; - gl.level.monsters[x][y] = mon; + svl.level.monsters[x][y] = mon; mon->mstate = MON_FLOOR; } diff --git a/src/teleport.c b/src/teleport.c index 51fb281e7..e4aeedbe3 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -35,7 +35,7 @@ noteleport_level(struct monst *mon) return TRUE; /* natural no-teleport level */ - if (gl.level.flags.noteleport) + if (svl.level.flags.noteleport) return TRUE; return FALSE; @@ -368,30 +368,30 @@ tele_jump_ok(coordxy x1, coordxy y1, coordxy x2, coordxy y2) { if (!isok(x2, y2)) return FALSE; - if (gd.dndest.nlx > 0) { + if (svd.dndest.nlx > 0) { /* if inside a restricted region, can't teleport outside */ - if (within_bounded_area(x1, y1, gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy) - && !within_bounded_area(x2, y2, gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy)) + if (within_bounded_area(x1, y1, svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy) + && !within_bounded_area(x2, y2, svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy)) return FALSE; /* and if outside, can't teleport inside */ - if (!within_bounded_area(x1, y1, gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy) - && within_bounded_area(x2, y2, gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy)) + if (!within_bounded_area(x1, y1, svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy) + && within_bounded_area(x2, y2, svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy)) return FALSE; } - if (gu.updest.nlx > 0) { /* ditto */ - if (within_bounded_area(x1, y1, gu.updest.nlx, gu.updest.nly, - gu.updest.nhx, gu.updest.nhy) - && !within_bounded_area(x2, y2, gu.updest.nlx, gu.updest.nly, - gu.updest.nhx, gu.updest.nhy)) + if (svu.updest.nlx > 0) { /* ditto */ + if (within_bounded_area(x1, y1, svu.updest.nlx, svu.updest.nly, + svu.updest.nhx, svu.updest.nhy) + && !within_bounded_area(x2, y2, svu.updest.nlx, svu.updest.nly, + svu.updest.nhx, svu.updest.nhy)) return FALSE; - if (!within_bounded_area(x1, y1, gu.updest.nlx, gu.updest.nly, - gu.updest.nhx, gu.updest.nhy) - && within_bounded_area(x2, y2, gu.updest.nlx, gu.updest.nly, - gu.updest.nhx, gu.updest.nhy)) + if (!within_bounded_area(x1, y1, svu.updest.nlx, svu.updest.nly, + svu.updest.nhx, svu.updest.nhy) + && within_bounded_area(x2, y2, svu.updest.nlx, svu.updest.nly, + svu.updest.nhx, svu.updest.nhy)) return FALSE; } return TRUE; @@ -1124,10 +1124,10 @@ level_tele(void) if (iflags.debug_fuzzer) { do { - newlevel.dnum = rn2(gn.n_dgns); + newlevel.dnum = rn2(svn.n_dgns); } while (newlevel.dnum == astral_level.dnum - || gd.dungeons[newlevel.dnum].flags.unconnected - || !gd.dungeons[newlevel.dnum].num_dunlevs); + || svd.dungeons[newlevel.dnum].flags.unconnected + || !svd.dungeons[newlevel.dnum].num_dunlevs); newlevel.dlevel = 1 + rn2(dunlevs_in_dungeon(&newlevel)); assign_level(&u.ucamefrom, &u.uz); schedule_goto(&newlevel, UTOTYPE_NONE, (char *) 0, (char *) 0); @@ -1214,8 +1214,8 @@ level_tele(void) if (gi.invent) Your("possessions land on the %s with a thud.", surface(u.ux, u.uy)); - gk.killer.format = NO_KILLER_PREFIX; - Strcpy(gk.killer.name, "committed suicide"); + svk.killer.format = NO_KILLER_PREFIX; + Strcpy(svk.killer.name, "committed suicide"); done(DIED); pline("An energized cloud of dust begins to coalesce."); Your("body rematerializes%s.", @@ -1239,7 +1239,7 @@ level_tele(void) * we let negative values requests fall into the "heaven" handling. */ if (In_quest(&u.uz) && newlev > 0) - newlev = newlev + gd.dungeons[u.uz.dnum].depth_start - 1; + newlev = newlev + svd.dungeons[u.uz.dnum].depth_start - 1; } else { /* involuntary level tele */ random_levtport: newlev = random_teleport_level(); @@ -1269,7 +1269,7 @@ level_tele(void) return; } - gk.killer.name[0] = 0; /* still alive, so far... */ + svk.killer.name[0] = 0; /* still alive, so far... */ if (iflags.debug_fuzzer && newlev < 0) goto random_levtport; @@ -1286,8 +1286,8 @@ level_tele(void) You("arrive in heaven."); SetVoice((struct monst *) 0, 0, 80, voice_deity); verbalize("Thou art early, but we'll admit thee."); - gk.killer.format = NO_KILLER_PREFIX; - Strcpy(gk.killer.name, "went to heaven prematurely"); + svk.killer.format = NO_KILLER_PREFIX; + Strcpy(svk.killer.name, "went to heaven prematurely"); } else if (newlev == -9) { You_feel("deliriously happy."); pline("(In fact, you're on Cloud 9!)"); @@ -1295,7 +1295,7 @@ level_tele(void) } else You("are now high above the clouds..."); - if (gk.killer.name[0]) { + if (svk.killer.name[0]) { ; /* arrival in heaven is pending */ } else if (Levitation) { escape_by_flying = "float gently down to earth"; @@ -1304,14 +1304,14 @@ level_tele(void) } else { pline("Unfortunately, you don't know how to fly."); You("plummet a few thousand feet to your death."); - Sprintf(gk.killer.name, + Sprintf(svk.killer.name, "teleported out of the dungeon and fell to %s death", uhis()); - gk.killer.format = NO_KILLER_PREFIX; + svk.killer.format = NO_KILLER_PREFIX; } } - if (gk.killer.name[0]) { /* the chosen destination was not survivable */ + if (svk.killer.name[0]) { /* the chosen destination was not survivable */ d_level lsav; /* set specific death location; this also suppresses bones */ @@ -1337,7 +1337,7 @@ level_tele(void) /* wizard mode menu; no further validation needed */ ; } else if (u.uz.dnum == medusa_level.dnum - && newlev >= gd.dungeons[u.uz.dnum].depth_start + && newlev >= svd.dungeons[u.uz.dnum].depth_start + dunlevs_in_dungeon(&u.uz)) { find_hell(&newlevel); } else { @@ -1348,7 +1348,7 @@ level_tele(void) d_level *qbranch = In_quest(&u.uz) ? &qstart_level : In_mines(&u.uz) ? &mineend_level : &sanctum_level; - int deepest = gd.dungeons[qbranch->dnum].depth_start + int deepest = svd.dungeons[qbranch->dnum].depth_start + dunlevs_in_dungeon(qbranch) - 1; /* if invocation did not yet occur, teleporting into @@ -1386,7 +1386,7 @@ level_tele(void) /* in case player just read a scroll and is about to be asked to call it something, we can't defer until the end of the turn */ - if (u.utotype && !gc.context.mon_moving) + if (u.utotype && !svc.context.mon_moving) deferred_goto(); #endif } @@ -1528,25 +1528,28 @@ rloc_pos_ok( yy = mtmp->my; if (!xx) { /* no current location (migrating monster arrival) */ - if (gd.dndest.nlx && On_W_tower_level(&u.uz)) + if (svd.dndest.nlx && On_W_tower_level(&u.uz)) return (((yy & 2) != 0) /* inside xor not within */ - ^ !within_bounded_area(x, y, gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy)); - if (gu.updest.lx && (yy & 1) != 0) /* moving up */ - return (within_bounded_area(x, y, gu.updest.lx, gu.updest.ly, - gu.updest.hx, gu.updest.hy) - && (!gu.updest.nlx + ^ !within_bounded_area(x, y, + svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy)); + if (svu.updest.lx && (yy & 1) != 0) /* moving up */ + return (within_bounded_area(x, y, + svu.updest.lx, svu.updest.ly, + svu.updest.hx, svu.updest.hy) + && (!svu.updest.nlx || !within_bounded_area(x, y, - gu.updest.nlx, gu.updest.nly, - gu.updest.nhx, gu.updest.nhy))); - if (gd.dndest.lx && (yy & 1) == 0) /* moving down */ - return (within_bounded_area(x, y, gd.dndest.lx, gd.dndest.ly, - gd.dndest.hx, gd.dndest.hy) - && (!gd.dndest.nlx + svu.updest.nlx, svu.updest.nly, + svu.updest.nhx, svu.updest.nhy))); + if (svd.dndest.lx && (yy & 1) == 0) /* moving down */ + return (within_bounded_area(x, y, + svd.dndest.lx, svd.dndest.ly, + svd.dndest.hx, svd.dndest.hy) + && (!svd.dndest.nlx || !within_bounded_area(x, y, - gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy))); + svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy))); } else { /* [try to] prevent a shopkeeper or temple priest from being sent out of his room (caller might resort to goodpos() if @@ -1906,7 +1909,8 @@ mtele_trap(struct monst *mtmp, struct trap *trap, int in_sight) * possible space - instead it just doesn't work. */ if (!(m_at(trap->teledest.x, trap->teledest.y) || u_at(trap->teledest.x, trap->teledest.y))) { - rloc_to_core(mtmp, trap->teledest.x, trap->teledest.y, RLOC_MSG); + rloc_to_core(mtmp, trap->teledest.x, trap->teledest.y, + RLOC_MSG); } } else (void) rloc(mtmp, RLOC_NONE); @@ -2033,7 +2037,7 @@ rloco(struct obj *obj) obj_extract_self(obj); otx = obj->ox; oty = obj->oy; - restricted_fall = (otx == 0 && gd.dndest.lx); + restricted_fall = (otx == 0 && svd.dndest.lx); do { tx = rn1(COLNO - 3, 2); ty = rn2(ROWNO); @@ -2041,20 +2045,22 @@ rloco(struct obj *obj) break; } while (!goodpos(tx, ty, (struct monst *) 0, 0) || (restricted_fall - && (!within_bounded_area(tx, ty, gd.dndest.lx, gd.dndest.ly, - gd.dndest.hx, gd.dndest.hy) - || (gd.dndest.nlx + && (!within_bounded_area(tx, ty, + svd.dndest.lx, svd.dndest.ly, + svd.dndest.hx, svd.dndest.hy) + || (svd.dndest.nlx && within_bounded_area(tx, ty, - gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy)))) + svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy)))) /* on the Wizard Tower levels, objects inside should stay inside and objects outside should stay outside */ - || (gd.dndest.nlx && On_W_tower_level(&u.uz) - && within_bounded_area(tx, ty, gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy) + || (svd.dndest.nlx && On_W_tower_level(&u.uz) + && within_bounded_area(tx, ty, + svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy) != within_bounded_area(otx, oty, - gd.dndest.nlx, gd.dndest.nly, - gd.dndest.nhx, gd.dndest.nhy))); + svd.dndest.nlx, svd.dndest.nly, + svd.dndest.nhx, svd.dndest.nhy))); if (flooreffects(obj, tx, ty, "fall")) { /* update old location since flooreffects() couldn't; @@ -2140,12 +2146,12 @@ random_teleport_level(void) no one can randomly teleport past it */ if (dunlev_reached(&u.uz) < qlocate_depth) bottom = qlocate_depth; - min_depth = gd.dungeons[u.uz.dnum].depth_start; - max_depth = bottom + (gd.dungeons[u.uz.dnum].depth_start - 1); + min_depth = svd.dungeons[u.uz.dnum].depth_start; + max_depth = bottom + (svd.dungeons[u.uz.dnum].depth_start - 1); } else { min_depth = 1; max_depth = dunlevs_in_dungeon(&u.uz) - + (gd.dungeons[u.uz.dnum].depth_start - 1); + + (svd.dungeons[u.uz.dnum].depth_start - 1); /* can't reach Sanctum if the invocation hasn't been performed */ if (Inhell && !u.uevent.invoked) max_depth -= 1; diff --git a/src/timeout.c b/src/timeout.c index a3ce09ea0..7dcc67804 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 timeout.c $NHDT-Date: 1710029105 2024/03/10 00:05:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.182 $ */ +/* NetHack 3.7 timeout.c $NHDT-Date: 1723580900 2024/08/13 20:28:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.190 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -460,11 +460,11 @@ slimed_to_death(struct kinfo *kptr) } /* more sure killer reason is set up */ if (kptr && kptr->name[0]) { - gk.killer.format = kptr->format; - Strcpy(gk.killer.name, kptr->name); + svk.killer.format = kptr->format; + Strcpy(svk.killer.name, kptr->name); } else { - gk.killer.format = NO_KILLER_PREFIX; - Strcpy(gk.killer.name, "turned into green slime"); + svk.killer.format = NO_KILLER_PREFIX; + Strcpy(svk.killer.name, "turned into green slime"); } dealloc_killer(kptr); @@ -482,20 +482,20 @@ slimed_to_death(struct kinfo *kptr) */ if (emits_light(gy.youmonst.data)) del_light_source(LS_MONSTER, monst_to_any(&gy.youmonst)); - save_mvflags = gm.mvitals[PM_GREEN_SLIME].mvflags; - gm.mvitals[PM_GREEN_SLIME].mvflags = save_mvflags & ~G_GENOD; + save_mvflags = svm.mvitals[PM_GREEN_SLIME].mvflags; + svm.mvitals[PM_GREEN_SLIME].mvflags = save_mvflags & ~G_GENOD; /* become a green slime; also resets youmonst.m_ap_type+.mappearance */ (void) polymon(PM_GREEN_SLIME); - gm.mvitals[PM_GREEN_SLIME].mvflags = save_mvflags; + svm.mvitals[PM_GREEN_SLIME].mvflags = save_mvflags; done_timeout(TURNED_SLIME, SLIMED); /* life-saved; even so, hero still has turned into green slime; player may have genocided green slimes after being infected */ - if ((gm.mvitals[PM_GREEN_SLIME].mvflags & G_GENOD) != 0) { + if ((svm.mvitals[PM_GREEN_SLIME].mvflags & G_GENOD) != 0) { char slimebuf[BUFSZ]; - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, "slimicide"); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, "slimicide"); /* vary the message depending upon whether life-save was due to amulet or due to declining to die in explore or wizard mode */ Strcpy(slimebuf, "green slime has been genocided..."); @@ -566,11 +566,11 @@ nh_timeout(void) if (flags.friday13) baseluck -= 1; - if (gq.quest_status.killed_leader) + if (svq.quest_status.killed_leader) baseluck -= 4; if (u.uluck != baseluck - && gm.moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) { + && svm.moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) { /* Cursed luckstones stop bad luck from timing out; blessed luckstones * stop good luck from timing out; normal luckstones stop both; * neither is stopped if you don't have a luckstone. @@ -637,11 +637,11 @@ nh_timeout(void) switch (upp - u.uprops) { case STONED: if (kptr && kptr->name[0]) { - gk.killer.format = kptr->format; - Strcpy(gk.killer.name, kptr->name); + svk.killer.format = kptr->format; + Strcpy(svk.killer.name, kptr->name); } else { - gk.killer.format = NO_KILLER_PREFIX; - Strcpy(gk.killer.name, "killed by petrification"); + svk.killer.format = NO_KILLER_PREFIX; + Strcpy(svk.killer.name, "killed by petrification"); } dealloc_killer(kptr); /* (unlike sliming, you aren't changing form here) */ @@ -666,21 +666,21 @@ nh_timeout(void) } urgent_pline("You die from your illness."); if (kptr && kptr->name[0]) { - gk.killer.format = kptr->format; - Strcpy(gk.killer.name, kptr->name); + svk.killer.format = kptr->format; + Strcpy(svk.killer.name, kptr->name); } else { - gk.killer.format = KILLED_BY_AN; - gk.killer.name[0] = 0; /* take the default */ + svk.killer.format = KILLED_BY_AN; + svk.killer.name[0] = 0; /* take the default */ } dealloc_killer(kptr); - if ((m_idx = name_to_mon(gk.killer.name, + if ((m_idx = name_to_mon(svk.killer.name, (int *) 0)) >= LOW_PM) { if (type_is_pname(&mons[m_idx])) { - gk.killer.format = KILLED_BY; + svk.killer.format = KILLED_BY; } else if (mons[m_idx].geno & G_UNIQ) { - Strcpy(gk.killer.name, the(gk.killer.name)); - gk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, the(svk.killer.name)); + svk.killer.format = KILLED_BY; } } done_timeout(POISONING, SICK); @@ -826,10 +826,10 @@ nh_timeout(void) case WARN_OF_MON: /* timed Warn_of_mon is via #wizintrinsic only */ if (!Warn_of_mon) { - struct permonst *wptr = gc.context.warntype.species; + struct permonst *wptr = svc.context.warntype.species; - gc.context.warntype.species = (struct permonst *) 0; - gc.context.warntype.speciesidx = NON_PM; + svc.context.warntype.species = (struct permonst *) 0; + svc.context.warntype.speciesidx = NON_PM; if (wptr) You("are no longer warned about %s.", makeplural(wptr->pmnames[NEUTRAL])); @@ -845,8 +845,8 @@ nh_timeout(void) } break; case STRANGLED: - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, (u.uburied) ? "suffocation" : "strangulation"); done_timeout(DIED, STRANGLED); /* must be declining to die in explore|wizard mode; @@ -920,7 +920,7 @@ fall_asleep(int how_long, boolean wakeup_msg) } #endif /* early wakeup from combat won't be possible until next monster turn */ - u.usleep = gm.moves; + u.usleep = svm.moves; gn.nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again; } @@ -984,7 +984,7 @@ hatch_egg(anything *arg, long timeout) mnum = big_to_little(egg->corpsenm); /* The identity of one's father is learned, not innate */ yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2))); - silent = (timeout != gm.moves); /* hatched while away */ + silent = (timeout != svm.moves); /* hatched while away */ /* only can hatch when in INVENT, FLOOR, MINVENT; get_obj_location() will fail for MIGRATING, also for CONTAINED @@ -993,7 +993,7 @@ hatch_egg(anything *arg, long timeout) hatchcount = rnd((int) egg->quan); cansee_hatchspot = cansee(x, y) && !silent; if (!(mons[mnum].geno & G_UNIQ) - && !(gm.mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) { + && !(svm.mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) { for (i = hatchcount; i > 0; i--) { if (!enexto(&cc, x, y, &mons[mnum]) || !(mon = makemon(&mons[mnum], cc.x, cc.y, @@ -1009,7 +1009,7 @@ hatch_egg(anything *arg, long timeout) mon->mtame = 20; } } - if (gm.mvitals[mnum].mvflags & G_EXTINCT) + if (svm.mvitals[mnum].mvflags & G_EXTINCT) break; /* just made last one */ mon2 = mon; /* in case makemon() fails on 2nd egg */ } @@ -1145,7 +1145,7 @@ learn_egg_type(int mnum) { /* baby monsters hatch from grown-up eggs */ mnum = little_to_big(mnum); - gm.mvitals[mnum].mvflags |= MV_KNOWS_EGG; + svm.mvitals[mnum].mvflags |= MV_KNOWS_EGG; /* we might have just learned about other eggs being carried */ update_inventory(); } @@ -1206,9 +1206,9 @@ slip_or_trip(void) } if (!uarmf && otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) { - Sprintf(gk.killer.name, "tripping over %s corpse", + Sprintf(svk.killer.name, "tripping over %s corpse", an(mons[otmp->corpsenm].pmnames[NEUTRAL])); - instapetrify(gk.killer.name); + instapetrify(svk.killer.name); } } else if ((HFumbling & FROMOUTSIDE) || (is_ice(u.ux, u.uy) && !rn2(3))) { /* is fumbling from ice alone? */ @@ -1342,8 +1342,8 @@ burn_object(anything *arg, long timeout) many = menorah ? obj->spe > 1 : obj->quan > 1L; /* timeout while away */ - if (timeout != gm.moves) { - long how_long = gm.moves - timeout; + if (timeout != svm.moves) { + long how_long = svm.moves - timeout; if (how_long >= obj->age) { obj->age = 0; @@ -1783,7 +1783,7 @@ cleanup_burn(anything *arg, long expire_time) del_light_source(LS_OBJECT, obj_to_any(obj)); /* restore unused time */ - obj->age += expire_time - gm.moves; + obj->age += expire_time - svm.moves; obj->lamplit = 0; if (obj->where == OBJ_INVENT) @@ -1799,7 +1799,7 @@ do_storms(void) int count; /* no lightning if not stormy level or too often, even then */ - if (!gl.level.flags.stormy || rn2(8)) + if (!svl.level.flags.stormy || rn2(8)) return; /* the number of strikes is 8-log2(nstrike) */ @@ -1849,7 +1849,7 @@ do_storms(void) * boolean start_timer(long timeout,short kind,short func_index, * anything *arg) * Start a timer of kind 'kind' that will expire at time - * gm.moves+'timeout'. Call the function at 'func_index' + * svm.moves+'timeout'. Call the function at 'func_index' * in the timeout table using argument 'arg'. Return TRUE if * a timer was started. This places the timer on a list ordered * "sooner" to "later". If an object, increment the object's @@ -1997,7 +1997,7 @@ wiz_timeout_queue(void) if (win == WIN_ERR) return ECMD_OK; - Sprintf(buf, "Current time = %ld.", gm.moves); + Sprintf(buf, "Current time = %ld.", svm.moves); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, "Active timeout queue:"); @@ -2056,6 +2056,9 @@ wiz_timeout_queue(void) Sprintf(buf, "Vault counter is %d.", u.uinvault); putstr(win, 0, buf); } + if (any_visible_region()) { + visible_region_summary(win); + } display_nhwindow(win, FALSE); destroy_nhwindow(win); @@ -2158,7 +2161,7 @@ run_timers(void) * any time. The list is ordered, we are done when the first element * is in the future. */ - while (gt.timer_base && gt.timer_base->timeout <= gm.moves) { + while (gt.timer_base && gt.timer_base->timeout <= svm.moves) { curr = gt.timer_base; gt.timer_base = curr->next; @@ -2207,8 +2210,8 @@ start_timer( gnu = (timer_element *) alloc(sizeof *gnu); (void) memset((genericptr_t) gnu, 0, sizeof *gnu); gnu->next = 0; - gnu->tid = gt.timer_id++; - gnu->timeout = gm.moves + when; + gnu->tid = svt.timer_id++; + gnu->timeout = svm.moves + when; gnu->kind = kind; gnu->needs_fixup = 0; gnu->func_index = func_index; @@ -2242,7 +2245,7 @@ stop_timer(short func_index, anything *arg) (*cleanup_func)(arg, timeout); (void) memset((genericptr_t) doomed, 0, sizeof(timer_element)); free((genericptr_t) doomed); - return (timeout - gm.moves); + return (timeout - svm.moves); } return 0L; } @@ -2293,7 +2296,7 @@ obj_split_timers(struct obj *src, struct obj *dest) for (curr = gt.timer_base; curr; curr = next_timer) { next_timer = curr->next; /* things may be inserted */ if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) { - (void) start_timer(curr->timeout - gm.moves, TIMER_OBJECT, + (void) start_timer(curr->timeout - svm.moves, TIMER_OBJECT, curr->func_index, obj_to_any(dest)); } } @@ -2389,7 +2392,7 @@ long spot_time_left(coordxy x, coordxy y, short func_index) { long expires = spot_time_expires(x, y, func_index); - return (expires > 0L) ? expires - gm.moves : 0L; + return (expires > 0L) ? expires - svm.moves : 0L; } /* Insert timer into the global queue */ @@ -2608,7 +2611,8 @@ save_timers(NHFILE *nhfp, int range) if (perform_bwrite(nhfp)) { if (range == RANGE_GLOBAL) { if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) >.timer_id, sizeof(gt.timer_id)); + bwrite(nhfp->fd, (genericptr_t) &svt.timer_id, + sizeof svt.timer_id); } count = maybe_write_timer(nhfp, range, FALSE); if (nhfp->structlevel) @@ -2648,7 +2652,8 @@ restore_timers(NHFILE *nhfp, int range, long adjust) if (range == RANGE_GLOBAL) { if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) >.timer_id, sizeof gt.timer_id); + mread(nhfp->fd, (genericptr_t) &svt.timer_id, + sizeof svt.timer_id); } /* restore elements */ diff --git a/src/topten.c b/src/topten.c index 92f8388da..f38de9244 100644 --- a/src/topten.c +++ b/src/topten.c @@ -24,7 +24,7 @@ static long final_fpos; /* [note: do not move this to the 'g' struct] */ #endif -#define done_stopprint gp.program_state.stopprint +#define done_stopprint program_state.stopprint #define newttentry() (struct toptenentry *) alloc(sizeof (struct toptenentry)) #define dealloc_ttentry(ttent) free((genericptr_t) (ttent)) @@ -85,7 +85,7 @@ staticfn void nsb_mung_line(char *); staticfn void nsb_unmung_line(char *); #endif -/* "killed by",&c ["an"] 'gk.killer.name' */ +/* "killed by",&c ["an"] 'svk.killer.name' */ void formatkiller( char *buf, @@ -104,12 +104,12 @@ formatkiller( "", "", "", "", "" }; unsigned l; - char c, *kname = gk.killer.name; + char c, *kname = svk.killer.name; buf[0] = '\0'; /* lint suppression */ - switch (gk.killer.format) { + switch (svk.killer.format) { default: - impossible("bad killer format? (%d)", gk.killer.format); + impossible("bad killer format? (%d)", svk.killer.format); /*FALLTHRU*/ case NO_KILLER_PREFIX: break; @@ -333,7 +333,7 @@ RESTORE_WARNING_FORMAT_NONLITERAL #ifdef XLOGFILE -/* as tab is never used in eg. gp.plname or death, no need to mangle those. */ +/* as tab is never used in eg. svp.plname or death, no need to mangle those. */ staticfn void writexlentry(FILE *rfile, struct toptenentry *tt, int how) { @@ -359,12 +359,12 @@ writexlentry(FILE *rfile, struct toptenentry *tt, int how) formatkiller(tmpbuf, sizeof tmpbuf, how, FALSE); Fprintf(rfile, "%s%cname=%s%cdeath=%s", buf, /* (already includes separator) */ - XLOG_SEP, gp.plname, XLOG_SEP, tmpbuf); + XLOG_SEP, svp.plname, XLOG_SEP, tmpbuf); if (gm.multi < 0) Fprintf(rfile, "%cwhile=%s", XLOG_SEP, gm.multi_reason ? gm.multi_reason : "helpless"); Fprintf(rfile, "%cconduct=0x%lx%cturns=%ld%cachieve=0x%lx", XLOG_SEP, - encodeconduct(), XLOG_SEP, gm.moves, XLOG_SEP, + encodeconduct(), XLOG_SEP, svm.moves, XLOG_SEP, encodeachieve(FALSE)); Fprintf(rfile, "%cachieveX=%s", XLOG_SEP, encode_extended_achievements(achbuf)); @@ -596,6 +596,7 @@ encode_extended_conducts(char *buf) add_achieveX(buf, "blind", u.uroleplay.blind); add_achieveX(buf, "deaf", u.uroleplay.deaf); add_achieveX(buf, "nudist", u.uroleplay.nudist); + add_achieveX(buf, "pauper", u.uroleplay.pauper); add_achieveX(buf, "bonesless", !flags.bones); add_achieveX(buf, "petless", !u.uconduct.pets); @@ -642,7 +643,7 @@ topten(int how, time_t when) * topten uses alloc() several times, which will lead to * problems if the panic was the result of an alloc() failure. */ - if (gp.program_state.panicking) + if (program_state.panicking) return; if (iflags.toptenwin) { @@ -650,7 +651,7 @@ topten(int how, time_t when) } #if defined(HANGUPHANDLING) -#define HUP if (!gp.program_state.done_hup) +#define HUP if (!program_state.done_hup) #else #define HUP #endif @@ -683,7 +684,7 @@ topten(int how, time_t when) copynchars(t0->plrace, gu.urace.filecode, ROLESZ); copynchars(t0->plgend, genders[flags.female].filecode, ROLESZ); copynchars(t0->plalign, aligns[1 - u.ualign.type].filecode, ROLESZ); - copynchars(t0->name, gp.plname, NAMSZ); + copynchars(t0->name, svp.plname, NAMSZ); formatkiller(t0->death, sizeof t0->death, how, TRUE); t0->birthdate = yyyymmdd(ubirthday); t0->deathdate = yyyymmdd(when); @@ -1020,7 +1021,7 @@ outentry(int rank, struct toptenentry *t1, boolean so) } Sprintf(eos(linebuf), fmt, arg); } else { - Sprintf(eos(linebuf), " in %s", gd.dungeons[t1->deathdnum].dname); + Sprintf(eos(linebuf), " in %s", svd.dungeons[t1->deathdnum].dname); if (t1->deathdnum != knox_level.dnum) Sprintf(eos(linebuf), " on level %d", t1->deathlev); if (t1->deathlev != t1->maxlvl) @@ -1251,7 +1252,7 @@ prscore(int argc, char **argv) playerct = 0; players = (const char **) 0; } else { - player0 = gp.plname; + player0 = svp.plname; if (!*player0) player0 = "all"; /* if no plname[], show all scores * (possibly filtered by '-v') */ diff --git a/src/track.c b/src/track.c index 92a172a3b..e9c4923f8 100644 --- a/src/track.c +++ b/src/track.c @@ -76,8 +76,10 @@ save_track(NHFILE *nhfp) bwrite(nhfp->fd, (genericptr_t) &utcnt, sizeof utcnt); bwrite(nhfp->fd, (genericptr_t) &utpnt, sizeof utpnt); for (i = 0; i < utcnt; i++) { - bwrite(nhfp->fd, (genericptr_t) &utrack[i].x, sizeof utrack[i].x); - bwrite(nhfp->fd, (genericptr_t) &utrack[i].y, sizeof utrack[i].y); + bwrite(nhfp->fd, (genericptr_t) &utrack[i].x, + sizeof utrack[i].x); + bwrite(nhfp->fd, (genericptr_t) &utrack[i].y, + sizeof utrack[i].y); } } } diff --git a/src/trap.c b/src/trap.c index 301d686ae..f83c16085 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 trap.c $NHDT-Date: 1717884802 2024/06/08 22:13:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.598 $ */ +/* NetHack 3.7 trap.c $NHDT-Date: 1720128169 2024/07/04 21:22:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.602 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -522,7 +522,7 @@ maketrap(coordxy x, coordxy y, int typ) && (is_hole(typ) || IS_DOOR(lev->typ) || IS_WALL(lev->typ))) add_damage(x, y, /* schedule repair */ ((IS_DOOR(lev->typ) || IS_WALL(lev->typ)) - && !gc.context.mon_moving) + && !svc.context.mon_moving) ? SHOP_HOLE_COST : 0L); lev->doormask = 0; /* subsumes altarmask, icedpool... */ @@ -535,9 +535,9 @@ maketrap(coordxy x, coordxy y, int typ) else if (lev->typ == STONE || lev->typ == SCORR) (void) set_levltyp(x, y, CORR); else if (IS_WALL(lev->typ) || lev->typ == SDOOR) - (void) set_levltyp(x, y, gl.level.flags.is_maze_lev ? ROOM - : gl.level.flags.is_cavernous_lev ? CORR - : DOOR); + (void) set_levltyp(x, y, svl.level.flags.is_maze_lev ? ROOM + : svl.level.flags.is_cavernous_lev ? CORR + : DOOR); unearth_objs(x, y); break; @@ -788,7 +788,8 @@ animate_statue( comes_to_life = !canspotmon(mon) ? "disappears" : golem_xform ? "turns into flesh" - : (nonliving(mon->data) || is_vampshifter(mon)) ? "moves" + : (nonliving(mon->data) || is_vampshifter(mon)) + ? "moves" : "comes to life"; if (u_at(x, y) || cause == ANIMATE_SPELL) { /* "the|your|Manlobbi's statue [of a wombat]" */ @@ -824,7 +825,7 @@ animate_statue( /* if this isn't caused by a monster using a wand of striking, there might be consequences for the hero */ - if (!gc.context.mon_moving) { + if (!svc.context.mon_moving) { /* if statue is owned by a shop, hero will have to pay for it; stolen_value gives a message (about debt or use of credit) which refers to "it" so needs to follow a message describing @@ -3192,9 +3193,9 @@ launch_obj( launched (perhaps a monster triggered it), destroy context so that next dig attempt never thinks you're resuming previous effort */ if ((otyp == BOULDER || otyp == STATUE) - && singleobj->ox == gc.context.digging.pos.x - && singleobj->oy == gc.context.digging.pos.y) - (void) memset((genericptr_t) &gc.context.digging, 0, + && singleobj->ox == svc.context.digging.pos.x + && singleobj->oy == svc.context.digging.pos.y) + (void) memset((genericptr_t) &svc.context.digging, 0, sizeof(struct dig_info)); dist = distmin(x1, y1, x2, y2); @@ -3333,7 +3334,8 @@ launch_obj( /*FALLTHRU*/ case TELEP_TRAP: if (cansee(x, y)) - pline_xy(x, y, "Suddenly the rolling boulder disappears!"); + pline_xy(x, y, + "Suddenly the rolling boulder disappears!"); else if (!Deaf) You_hear("a rumbling stop abruptly."); singleobj->otrapped = 0; @@ -3666,7 +3668,8 @@ mintrap(struct monst *mtmp, unsigned mintrapflags) if (mtmp == u.usteed) { ; /* true when called from dotrap, inescapable is not an option */ - } else if (Sokoban && (is_pit(tt) || is_hole(tt)) && !trap->madeby_u) { + } else if (Sokoban && (is_pit(tt) || is_hole(tt)) + && !trap->madeby_u) { ; /* nothing here, the trap effects will handle messaging */ } else if (!forcetrap) { if (floor_trigger(tt) && check_in_air(mtmp, mintrapflags)) { @@ -3711,9 +3714,9 @@ instapetrify(const char *str) if (poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM)) return; urgent_pline("You turn to stone..."); - gk.killer.format = KILLED_BY; - if (str != gk.killer.name) - Strcpy(gk.killer.name, str ? str : ""); + svk.killer.format = KILLED_BY; + if (str != svk.killer.name) + Strcpy(svk.killer.name, str ? str : ""); done(STONING); } @@ -3850,7 +3853,8 @@ float_up(void) } else { You("start to float in the air!"); } - if (u.usteed && !is_floater(u.usteed->data) && !is_flyer(u.usteed->data)) { + if (u.usteed && !is_floater(u.usteed->data) + && !is_flyer(u.usteed->data)) { if (Lev_at_will) { pline("%s magically floats up!", Monnam(u.usteed)); } else { @@ -4082,7 +4086,7 @@ climb_pit(void) many times without further user intervention by using a run attempt to keep retrying to escape from the pit) */ if (u.usteed) - Norep("%s is still in a pit.", upstart(y_monnam(u.usteed))); + Norep("%s is still in a pit.", YMonnam(u.usteed)); else Norep((Hallucination && !rn2(5)) ? "You've fallen, and you can't get up." @@ -4911,7 +4915,7 @@ rescued_from_terrain(int how) iflags.last_msg = PLNMSG_BACK_ON_GROUND; /* for describe_decor() */ /* feedback just disclosed this */ update_lastseentyp(u.ux, u.uy); - iflags.prev_decor = gl.lastseentyp[u.ux][u.uy]; + iflags.prev_decor = svl.lastseentyp[u.ux][u.uy]; } /* return TRUE iff player relocated */ @@ -5036,14 +5040,14 @@ drown(void) /* killer format and name are reconstructed every iteration because lifesaving resets them */ pool_of_water = waterbody_name(u.ux, u.uy); - gk.killer.format = KILLED_BY_AN; + svk.killer.format = KILLED_BY_AN; /* avoid "drowned in [a] water" */ if (!strcmp(pool_of_water, "water")) - pool_of_water = "deep water", gk.killer.format = KILLED_BY; + pool_of_water = "deep water", svk.killer.format = KILLED_BY; /* avoid "drowned in _a_ limitless water" on Plane of Water */ else if (!strcmp(pool_of_water, "limitless water")) - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, pool_of_water); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, pool_of_water); done(DROWNING); /* oops, we're still alive. better get out of the water. */ if (safe_teleds(TELEDS_ALLOW_DRAG | TELEDS_TELEPORT)) @@ -5715,7 +5719,7 @@ untrap( here = u_at(x, y); /* !u.dx && !u.dy */ if (here) /* are there are one or more containers here? */ - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { if (++boxcnt > 1) break; @@ -5818,7 +5822,7 @@ untrap( whether any had been found but not attempted to untrap; now at most one per move may be checked and we only continue on to door handling if they are all declined */ - for (otmp = gl.level.objects[x][y]; otmp; otmp = otmp->nexthere) + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { (void) safe_qbuf(qbuf, "There is ", " here. Check it for traps?", otmp, @@ -6183,7 +6187,7 @@ chest_trap( unpunish(); /* destroy everything at the spot (the Amulet, the invocation tools, and Rider corpses will remain intact) */ - for (otmp = gl.level.objects[ox][oy]; otmp; otmp = otmp2) { + for (otmp = svl.level.objects[ox][oy]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (costly) loss += stolen_value(otmp, otmp->ox, otmp->oy, @@ -6211,7 +6215,8 @@ chest_trap( case 17: pline("A cloud of noxious gas billows from %s.", the(xname(obj))); if (rn2(3)) - poisoned("gas cloud", A_STR, "cloud of poison gas", 15, FALSE); + poisoned("gas cloud", A_STR, "cloud of poison gas", 15, + FALSE); else create_gas_cloud(obj->ox, obj->oy, 1, 8); exercise(A_CON, FALSE); @@ -6716,8 +6721,8 @@ lava_effects(void) u.uhp = -1; /* killer format and name are reconstructed every iteration because lifesaving resets them */ - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, lava_killer); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, lava_killer); urgent_pline("You %s...", boil_away ? "boil away" : "burn to a crisp"); done(BURNING); @@ -6753,7 +6758,8 @@ lava_effects(void) boil_away = !Fire_resistance; /* if not fire resistant, sink_into_lava() will quickly be fatal; hero needs to escape immediately */ - set_utrap((unsigned) (rn1(4, 4) + ((boil_away ? 2 : rn1(4, 12)) << 8)), + set_utrap((unsigned) (rn1(4, 4) + ((boil_away ? 2 + : rn1(4, 12)) << 8)), TT_LAVA); You("sink into the %s%s!", waterbody_name(u.ux, u.uy), !boil_away ? ", but it only burns slightly" @@ -6796,8 +6802,8 @@ sink_into_lava(void) u.utrap -= (1 << 8); if (u.utrap < (1 << 8)) { - gk.killer.format = KILLED_BY; - Strcpy(gk.killer.name, "molten lava"); + svk.killer.format = KILLED_BY; + Strcpy(svk.killer.name, "molten lava"); urgent_pline("You sink below the surface and die."); burn_away_slime(); /* add insult to injury? */ done(DISSOLVED); @@ -6860,13 +6866,13 @@ maybe_finish_sokoban(void) if (!t) { /* for livelog to report the sokoban depth in the way that players tend to think about it: 1 for entry level, 4 for top */ - int sokonum = gd.dungeons[u.uz.dnum].entry_lev - u.uz.dlevel + 1; + int sokonum = svd.dungeons[u.uz.dnum].entry_lev - u.uz.dlevel + 1; /* we've passed the last trap without finding a pit or hole; clear the sokoban_rules flag so that luck penalties for things like breaking boulders or jumping will no longer be given, and restrictions on diagonal moves are lifted */ - Sokoban = 0; /* clear gl.level.flags.sokoban_rules */ + Sokoban = 0; /* clear svl.level.flags.sokoban_rules */ /* * TODO: give some feedback about solving the sokoban puzzle * (perhaps say "congratulations" in Japanese?). diff --git a/src/u_init.c b/src/u_init.c index 443587c47..58040518f 100644 --- a/src/u_init.c +++ b/src/u_init.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 u_init.c $NHDT-Date: 1711165379 2024/03/23 03:42:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.106 $ */ +/* NetHack 3.7 u_init.c $NHDT-Date: 1725227809 2024/09/01 21:56:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.111 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -20,10 +20,11 @@ staticfn void ini_inv_adjust_obj(struct trobj *, struct obj *) NONNULLPTRS; staticfn void ini_inv_use_obj(struct obj *) NONNULLARG1; staticfn void ini_inv(struct trobj *) NONNULLARG1; -staticfn void knows_object(int); +staticfn void knows_object(int, boolean); staticfn void knows_class(char); staticfn void u_init_role(void); staticfn void u_init_race(void); +staticfn void pauper_reinit(void); staticfn void u_init_carry_attr_boost(void); staticfn boolean restricted_spell_discipline(int); @@ -192,7 +193,7 @@ static struct trobj Blindfold[] = { { BLINDFOLD, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Instrument[] = { { WOODEN_FLUTE, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; -static struct trobj Xtra_food[] = { { UNDEF_TYP, UNDEF_SPE, FOOD_CLASS, 2, 0 }, +static struct trobj Xtra_food[] = { { UNDEF_TYP, UNDEF_SPE, FOOD_CLASS, 2, 0}, { 0, 0, 0, 0, 0 } }; static struct trobj Leash[] = { { LEASH, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; @@ -557,8 +558,10 @@ static const struct def_skill Skill_W[] = { }; staticfn void -knows_object(int obj) +knows_object(int obj, boolean override_pauper) { + if (u.uroleplay.pauper && !override_pauper) + return; discover_object(obj, TRUE, FALSE); objects[obj].oc_pre_discovered = 1; /* not a "discovery" */ } @@ -571,6 +574,9 @@ knows_class(char sym) struct obj odummy, *o; int ct; + if (u.uroleplay.pauper) + return; + odummy = cg.zeroobj; odummy.oclass = sym; o = &odummy; /* for use in various obj.h macros */ @@ -582,7 +588,7 @@ knows_class(char sym) * arrow, and spear limitation below. */ - for (ct = gb.bases[(uchar) sym]; ct < gb.bases[(uchar) sym + 1]; ct++) { + for (ct = svb.bases[(uchar) sym]; ct < svb.bases[(uchar) sym + 1]; ct++) { /* not flagged as magic but shouldn't be pre-discovered */ if (ct == CORNUTHAUM || ct == DUNCE_CAP) continue; @@ -602,7 +608,7 @@ knows_class(char sym) } if (objects[ct].oc_class == sym && !objects[ct].oc_magic) - knows_object(ct); + knows_object(ct, FALSE); } } @@ -612,6 +618,12 @@ u_init_role(void) { int i; + /* the program used to check moves<=1 && invent==NULL do decide whether + a new game has started, but due to the 'pauper' option/conduct, can't + rely on invent becoming non-Null anymore; instead, initialize moves + to 0 instead of 1, then set it to 1 here, where invent init occurs */ + svm.moves = 1L; + switch (Role_switch) { /* rn2(100) > 50 necessary for some choices because some * random number generators are bad enough to seriously @@ -625,8 +637,10 @@ u_init_role(void) ini_inv(Lamp); else if (!rn2(5)) ini_inv(Magicmarker); - knows_object(SACK); - knows_object(TOUCHSTONE); + knows_object(SACK, FALSE); + knows_object(TOUCHSTONE, FALSE); /* FALSE: don't override pauper here, + * but TOUCHSTONE will be made known + * in pauper_reinit() */ skill_init(Skill_A); break; case PM_BARBARIAN: @@ -651,7 +665,7 @@ u_init_role(void) ini_inv(Healer); if (!rn2(25)) ini_inv(Lamp); - knows_object(POT_FULL_HEALING); + knows_object(POT_FULL_HEALING, FALSE); skill_init(Skill_H); break; case PM_KNIGHT: @@ -675,7 +689,7 @@ u_init_role(void) ini_inv(Lamp); knows_class(ARMOR_CLASS); /* sufficiently martial-arts oriented item to ignore language issue */ - knows_object(SHURIKEN); + knows_object(SHURIKEN, FALSE); skill_init(Skill_Mon); break; } @@ -685,7 +699,7 @@ u_init_role(void) ini_inv(Magicmarker); else if (!rn2(10)) ini_inv(Lamp); - knows_object(POT_WATER); + knows_object(POT_WATER, TRUE); /* override pauper */ skill_init(Skill_P); /* KMH, conduct -- * Some may claim that this isn't agnostic, since they @@ -708,7 +722,9 @@ u_init_role(void) ini_inv(Rogue); if (!rn2(5)) ini_inv(Blindfold); - knows_object(SACK); + knows_object(SACK, FALSE); /* FALSE: don't override pauper here, + * but sack will be made known in + * pauper_reinit() */ knows_class(WEAPON_CLASS); /* daggers only */ skill_init(Skill_R); break; @@ -725,7 +741,9 @@ u_init_role(void) if (objects[i].oc_magic) /* skip "magic koto" */ continue; if (Japanese_item_name(i, (const char *) 0)) - knows_object(i); + /* we don't override pauper here because that would give + samarai an advantage of knowing several items in advance */ + knows_object(i, FALSE); } skill_init(Skill_S); break; @@ -786,28 +804,28 @@ u_init_race(void) } /* Elves can recognize all elvish objects */ - knows_object(ELVEN_SHORT_SWORD); - knows_object(ELVEN_ARROW); - knows_object(ELVEN_BOW); - knows_object(ELVEN_SPEAR); - knows_object(ELVEN_DAGGER); - knows_object(ELVEN_BROADSWORD); - knows_object(ELVEN_MITHRIL_COAT); - knows_object(ELVEN_LEATHER_HELM); - knows_object(ELVEN_SHIELD); - knows_object(ELVEN_BOOTS); - knows_object(ELVEN_CLOAK); + knows_object(ELVEN_SHORT_SWORD, FALSE); + knows_object(ELVEN_ARROW, FALSE); + knows_object(ELVEN_BOW, FALSE); + knows_object(ELVEN_SPEAR, FALSE); + knows_object(ELVEN_DAGGER, FALSE); + knows_object(ELVEN_BROADSWORD, FALSE); + knows_object(ELVEN_MITHRIL_COAT, FALSE); + knows_object(ELVEN_LEATHER_HELM, FALSE); + knows_object(ELVEN_SHIELD, FALSE); + knows_object(ELVEN_BOOTS, FALSE); + knows_object(ELVEN_CLOAK, FALSE); break; case PM_DWARF: /* Dwarves can recognize all dwarvish objects */ - knows_object(DWARVISH_SPEAR); - knows_object(DWARVISH_SHORT_SWORD); - knows_object(DWARVISH_MATTOCK); - knows_object(DWARVISH_IRON_HELM); - knows_object(DWARVISH_MITHRIL_COAT); - knows_object(DWARVISH_CLOAK); - knows_object(DWARVISH_ROUNDSHIELD); + knows_object(DWARVISH_SPEAR, FALSE); + knows_object(DWARVISH_SHORT_SWORD, FALSE); + knows_object(DWARVISH_MATTOCK, FALSE); + knows_object(DWARVISH_IRON_HELM, FALSE); + knows_object(DWARVISH_MITHRIL_COAT, FALSE); + knows_object(DWARVISH_CLOAK, FALSE); + knows_object(DWARVISH_ROUNDSHIELD, FALSE); break; case PM_GNOME: @@ -818,17 +836,17 @@ u_init_race(void) if (!Role_if(PM_WIZARD)) ini_inv(Xtra_food); /* Orcs can recognize all orcish objects */ - knows_object(ORCISH_SHORT_SWORD); - knows_object(ORCISH_ARROW); - knows_object(ORCISH_BOW); - knows_object(ORCISH_SPEAR); - knows_object(ORCISH_DAGGER); - knows_object(ORCISH_CHAIN_MAIL); - knows_object(ORCISH_RING_MAIL); - knows_object(ORCISH_HELM); - knows_object(ORCISH_SHIELD); - knows_object(URUK_HAI_SHIELD); - knows_object(ORCISH_CLOAK); + knows_object(ORCISH_SHORT_SWORD, FALSE); + knows_object(ORCISH_ARROW, FALSE); + knows_object(ORCISH_BOW, FALSE); + knows_object(ORCISH_SPEAR, FALSE); + knows_object(ORCISH_DAGGER, FALSE); + knows_object(ORCISH_CHAIN_MAIL, FALSE); + knows_object(ORCISH_RING_MAIL, FALSE); + knows_object(ORCISH_HELM, FALSE); + knows_object(ORCISH_SHIELD, FALSE); + knows_object(URUK_HAI_SHIELD, FALSE); + knows_object(ORCISH_CLOAK, FALSE); break; default: /* impossible */ @@ -836,6 +854,67 @@ u_init_race(void) } } +/* for 'pauper' aka 'unpreparsed'; take away any skills (bare-handed combat, + riding) that are better than unskilled; learn the book (without carrying + it or knowing its spell yet) for some key spells */ +staticfn void +pauper_reinit(void) +{ + int skill, preknown = STRANGE_OBJECT; + + if (!u.uroleplay.pauper) + return; + + for (skill = 0; skill < P_NUM_SKILLS; skill++) + if (P_SKILL(skill) > P_UNSKILLED) { + P_SKILL(skill) = P_UNSKILLED; + P_ADVANCE(skill) = 0; + } + /* pauper has lost out on initial skills, but provide some unspent skill + credits to make up for that */ + u.weapon_slots = 2; + + /* paupers don't know any spells yet, but several roles will recognize + the spellbook for a key spell (not necessarily that role's special + spell); "supply chests" on the first few levels provide a fairly + high chance to find the book; some other roles know a non-book item */ + switch (Role_switch) { + case PM_HEALER: + preknown = SPE_HEALING; + break; + case PM_CLERIC: + case PM_KNIGHT: + case PM_MONK: + preknown = SPE_PROTECTION; + break; + case PM_WIZARD: + preknown = SPE_FORCE_BOLT; + break; + case PM_ARCHEOLOGIST: + preknown = TOUCHSTONE; + break; + case PM_CAVE_DWELLER: + preknown = FLINT; + break; + case PM_ROGUE: + case PM_TOURIST: + preknown = SACK; + break; + case PM_SAMURAI: + /* food ration isn't interesting to discover, but put "gunyoki" into + discoveries list for players who might not recognize what it is */ + preknown = FOOD_RATION; + break; + default: + case PM_BARBARIAN: + case PM_RANGER: + case PM_VALKYRIE: + break; + } + if (preknown != STRANGE_OBJECT) + knows_object(preknown, TRUE); +} + /* boost STR and CON until hero can carry inventory */ staticfn void u_init_carry_attr_boost(void) @@ -911,7 +990,7 @@ u_init(void) init_uhunger(); for (i = 0; i <= MAXSPELL; i++) - gs.spl_book[i].sp_id = NO_SPELL; + svs.spl_book[i].sp_id = NO_SPELL; u.ublesscnt = 300; /* no prayers just yet */ u.ualignbase[A_CURRENT] = u.ualignbase[A_ORIGINAL] = u.ualign.type = aligns[flags.initalign].value; @@ -939,6 +1018,8 @@ u_init(void) u_init_role(); u_init_race(); + if (u.uroleplay.pauper) + pauper_reinit(); /* roughly based on distribution in human population */ u.uhandedness = rn2(10) ? RIGHT_HANDED : LEFT_HANDED; @@ -1213,6 +1294,9 @@ ini_inv(struct trobj *trop) int otyp; boolean got_sp1 = FALSE; /* got a level 1 spellbook? */ + if (u.uroleplay.pauper) /* pauper gets no items */ + return; + while (trop->trclass) { otyp = (int) trop->trotyp; if (otyp != UNDEF_TYP) { @@ -1241,8 +1325,8 @@ ini_inv(struct trobj *trop) if (obj->oclass == RING_CLASS || obj->oclass == SPBOOK_CLASS) gn.nocreate4 = otyp; } - /* Put post-creation object adjustments that don't depend on whether it - * was UNDEF_TYP or not after this. */ + /* Put post-creation object adjustments that don't depend on whether + * it was UNDEF_TYP or not after this. */ otyp = ini_inv_obj_substitution(trop, obj); diff --git a/src/uhitm.c b/src/uhitm.c index e9062acb9..307883235 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -195,7 +195,7 @@ attack_checks( if (engulfing_u(mtmp)) return FALSE; - if (gc.context.forcefight) { + if (svc.context.forcefight) { /* Do this in the caller, after we checked that the monster * didn't die from the blow. Reason: putting the 'I' there * causes the hero to forget the square's contents since @@ -285,7 +285,7 @@ attack_checks( notseen ? "is present" : "appears"); else if (Blind || (is_pool(mtmp->mx, mtmp->my) && !Underwater)) pline("Wait! There's a hidden monster there!"); - else if ((obj = gl.level.objects[mtmp->mx][mtmp->my]) != 0) + else if ((obj = svl.level.objects[mtmp->mx][mtmp->my]) != 0) pline("Wait! There's %s hiding under %s!", notseen ? something : (const char *) an(lmonbuf), doname(obj)); @@ -314,7 +314,7 @@ attack_checks( Sprintf(qbuf, "Really attack %s?", mon_nam(mtmp)); if (!paranoid_query(ParanoidHit, qbuf)) { - gc.context.move = 0; + svc.context.move = 0; return TRUE; } } @@ -429,12 +429,12 @@ force_attack(struct monst *mtmp, boolean pets_too) { boolean attacked, save_Forcefight; - save_Forcefight = gc.context.forcefight; + save_Forcefight = svc.context.forcefight; /* always set forcefight On for hostiles and peacefuls, maybe for pets */ if (pets_too || !mtmp->mtame) - gc.context.forcefight = TRUE; + svc.context.forcefight = TRUE; attacked = do_attack(mtmp); - gc.context.forcefight = save_Forcefight; + svc.context.forcefight = save_Forcefight; return attacked; } @@ -455,7 +455,7 @@ do_attack(struct monst *mtmp) * you'll usually just swap places if this is a movement command */ /* Intelligent chaotic weapons (Stormbringer) want blood */ - if (is_safemon(mtmp) && !gc.context.forcefight) { + if (is_safemon(mtmp) && !svc.context.forcefight) { if (!u_wield_art(ART_STORMBRINGER)) { /* There are some additional considerations: this won't work * if in a shop or Punished or you miss a random roll or @@ -477,7 +477,7 @@ do_attack(struct monst *mtmp) /* only check for in-shop if don't already have reason to stop */ if (!foo) { for (p = in_rooms(mtmp->mx, mtmp->my, SHOPBASE); *p; p++) - if (tended_shop(&gr.rooms[*p - ROOMOFFSET])) { + if (tended_shop(&svr.rooms[*p - ROOMOFFSET])) { inshop = TRUE; break; } @@ -485,7 +485,7 @@ do_attack(struct monst *mtmp) if (inshop || foo) { char buf[BUFSZ]; - if (!gc.context.travel && !gc.context.run) + if (!svc.context.travel && !svc.context.run) if (canspotmon(mtmp) && mtmp->isshk) return ECMD_TIME | dopay(); @@ -570,7 +570,7 @@ do_attack(struct monst *mtmp) * and it returned 0 (it's okay to attack), and the monster didn't * evade. */ - if (gc.context.forcefight && !DEADMONSTER(mtmp) && !canspotmon(mtmp) + if (svc.context.forcefight && !DEADMONSTER(mtmp) && !canspotmon(mtmp) && !glyph_is_invisible(levl[u.ux + u.dx][u.uy + u.dy].glyph) && !engulfing_u(mtmp)) map_invisible(u.ux + u.dx, u.uy + u.dy); @@ -3306,8 +3306,8 @@ mhitm_ad_wrap( && !Is_waterlevel(&u.uz); urgent_pline("%s drowns you...", Monnam(magr)); - gk.killer.format = KILLED_BY_AN; - Sprintf(gk.killer.name, "%s by %s", + svk.killer.format = KILLED_BY_AN; + Sprintf(svk.killer.name, "%s by %s", moat ? "moat" : "pool of water", an(pmname(magr->data, Mgender(magr)))); done(DROWNING); @@ -4246,7 +4246,7 @@ mhitm_ad_heal( mhm->damage = 0; } else { if (Role_if(PM_HEALER)) { - if (!Deaf && !(gm.moves % 5)) { + if (!Deaf && !(svm.moves % 5)) { SetVoice(magr, 0, 80, 0); verbalize("Doc, I can't help you unless you cooperate."); } @@ -4426,7 +4426,7 @@ mhitm_ad_dgst( */ num = monsndx(pd); if (magr->mtame && !magr->isminion - && !(gm.mvitals[num].mvflags & G_NOCORPSE)) { + && !(svm.mvitals[num].mvflags & G_NOCORPSE)) { struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE); int nutrit; @@ -4914,9 +4914,9 @@ gulpum(struct monst *mdef, struct attack *mattk) if (is_rider(pd)) { pline("Unfortunately, digesting any of it is fatal."); end_engulf(); - Sprintf(gk.killer.name, "unwisely tried to eat %s", + Sprintf(svk.killer.name, "unwisely tried to eat %s", pmname(pd, Mgender(mdef))); - gk.killer.format = NO_KILLER_PREFIX; + svk.killer.format = NO_KILLER_PREFIX; done(DIED); return M_ATTK_MISS; /* lifesaved */ } @@ -4944,7 +4944,7 @@ gulpum(struct monst *mdef, struct attack *mattk) } else { tmp = 1 + (pd->cwt >> 8); if (corpse_chance(mdef, &gy.youmonst, TRUE) - && !(gm.mvitals[monsndx(pd)].mvflags & G_NOCORPSE)) { + && !(svm.mvitals[monsndx(pd)].mvflags & G_NOCORPSE)) { /* nutrition only if there can be a corpse */ u.uhunger += (pd->cnutrit + 1) / 2; } else { @@ -6154,7 +6154,7 @@ flash_hits_mon( light_hits_gremlin(mtmp, amt); } if (!DEADMONSTER(mtmp)) { - if (!gc.context.mon_moving) + if (!svc.context.mon_moving) setmangry(mtmp, TRUE); if (tmp < 9 && !mtmp->isshk && rn2(4)) monflee(mtmp, rn2(4) ? rnd(100) : 0, FALSE, TRUE); @@ -6189,7 +6189,7 @@ light_hits_gremlin(struct monst *mon, int dmg) mon->mhp -= dmg; wake_nearto(mon->mx, mon->my, 30); if (DEADMONSTER(mon)) { - if (gc.context.mon_moving) + if (svc.context.mon_moving) monkilled(mon, (char *) 0, AD_BLND); else killed(mon); diff --git a/src/utf8map.c b/src/utf8map.c index fcf562457..f39ce26a1 100644 --- a/src/utf8map.c +++ b/src/utf8map.c @@ -153,7 +153,8 @@ add_custom_urep_entry( const uint8 *utf8str, enum graphics_sets which_set) { - struct symset_customization *gdc = &gs.sym_customizations[which_set][custom_ureps]; + struct symset_customization *gdc + = &gs.sym_customizations[which_set][custom_ureps]; struct customization_detail *details, *newdetails = 0; @@ -164,7 +165,7 @@ add_custom_urep_entry( gdc->details_end = 0; } details = find_matching_customization(customization_name, - custom_ureps, which_set); /* FIXME */ + custom_ureps, which_set); /* FIXME */ if (details) { while (details) { if (details->content.urep.glyphidx == glyphidx) { diff --git a/src/vault.c b/src/vault.c index 63591948a..eca749697 100644 --- a/src/vault.c +++ b/src/vault.c @@ -49,7 +49,7 @@ clear_fcorr(struct monst *grd, boolean forceshow) coordxy fcx, fcy, fcbeg; struct monst *mtmp; boolean sawcorridor = FALSE, - silently = gp.program_state.stopprint ? TRUE : FALSE; + silently = program_state.stopprint ? TRUE : FALSE; struct egd *egrd = EGD(grd); struct trap *trap; struct rm *lev; @@ -156,8 +156,8 @@ parkguard(struct monst *grd) { /* either guard is dead or will now be treated as if so; monster traversal loops should skip it */ - if (grd == gc.context.polearm.hitmon) - gc.context.polearm.hitmon = 0; + if (grd == svc.context.polearm.hitmon) + svc.context.polearm.hitmon = 0; if (grd->mx) { remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); @@ -246,7 +246,7 @@ vault_occupied(char *array) char *ptr; for (ptr = array; *ptr; ptr++) - if (gr.rooms[*ptr - ROOMOFFSET].rtype == VAULT) + if (svr.rooms[*ptr - ROOMOFFSET].rtype == VAULT) return *ptr; return '\0'; } @@ -495,13 +495,13 @@ invault(void) if (u.ualign.type == A_LAWFUL /* ignore trailing text, in case player includes rank */ - && strncmpi(buf, gp.plname, (int) strlen(gp.plname)) != 0) { + && strncmpi(buf, svp.plname, (int) strlen(svp.plname)) != 0) { adjalign(-1); /* Liar! */ } if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos") || !strcmpi(buf, "Creosote")) { /* Discworld */ - if (!gm.mvitals[PM_CROESUS].died) { + if (!svm.mvitals[PM_CROESUS].died) { if (Deaf) { if (!Blind) pline("%s waves goodbye.", noit_Monnam(guard)); @@ -583,8 +583,8 @@ invault(void) dug into an empty doorway (which could subsequently have been plugged with an intact door by use of locking magic) */ int vlt = EGD(guard)->vroom; - coordxy lowx = gr.rooms[vlt].lx, hix = gr.rooms[vlt].hx; - coordxy lowy = gr.rooms[vlt].ly, hiy = gr.rooms[vlt].hy; + coordxy lowx = svr.rooms[vlt].lx, hix = svr.rooms[vlt].hx; + coordxy lowy = svr.rooms[vlt].ly, hiy = svr.rooms[vlt].hy; if (x == lowx - 1 && y == lowy - 1) typ = TLCORNER; @@ -623,8 +623,8 @@ move_gold(struct obj *gold, int vroom) remove_object(gold); newsym(gold->ox, gold->oy); - nx = gr.rooms[vroom].lx + rn2(2); - ny = gr.rooms[vroom].ly + rn2(2); + nx = svr.rooms[vroom].lx + rn2(2); + ny = svr.rooms[vroom].ly + rn2(2); place_object(gold, nx, ny); stackobj(gold); newsym(nx, ny); @@ -637,8 +637,8 @@ wallify_vault(struct monst *grd) coordxy x, y; int vlt = EGD(grd)->vroom; char tmp_viz; - coordxy lox = gr.rooms[vlt].lx - 1, hix = gr.rooms[vlt].hx + 1, - loy = gr.rooms[vlt].ly - 1, hiy = gr.rooms[vlt].hy + 1; + coordxy lox = svr.rooms[vlt].lx - 1, hix = svr.rooms[vlt].hx + 1, + loy = svr.rooms[vlt].ly - 1, hiy = svr.rooms[vlt].hy + 1; struct monst *mon; struct obj *gold, *rocks; struct trap *trap; @@ -1210,10 +1210,10 @@ paygd(boolean silently) mnexto(grd, RLOC_NOMSG); if (!silently) pline("%s remits your gold to the vault.", Monnam(grd)); - gdx = gr.rooms[EGD(grd)->vroom].lx + rn2(2); - gdy = gr.rooms[EGD(grd)->vroom].ly + rn2(2); + gdx = svr.rooms[EGD(grd)->vroom].lx + rn2(2); + gdy = svr.rooms[EGD(grd)->vroom].ly + rn2(2); Sprintf(buf, "To Croesus: here's the gold recovered from %s the %s.", - gp.plname, + svp.plname, pmname(&mons[u.umonster], flags.female ? FEMALE : MALE)); make_grave(gdx, gdy, buf); } diff --git a/src/version.c b/src/version.c index 2d6467bc5..6678b8d1e 100644 --- a/src/version.c +++ b/src/version.c @@ -170,24 +170,8 @@ doextversion(void) done_rt = FALSE, done_dlb = FALSE, prolog; -#if 0 /* moved to util/mdlib.c and rendered via do_runtime_info() */ - const char *lua_info[] = { - "About Lua: Copyright (c) 1994-2017 Lua.org, PUC-Rio.", - /* 1 2 3 4 5 6 7 - 1234567890123456789012345678901234567890123456789012345678901234567890123456789 - */ - " \"Permission is hereby granted, free of charge, to any person obtaining", - " a copy of this software and associated documentation files (the ", - " \"Software\"), to deal in the Software without restriction including", - " without limitation the rights to use, copy, modify, merge, publish,", - " distribute, sublicense, and/or sell copies of the Software, and to ", - " permit persons to whom the Software is furnished to do so, subject to", - " the following conditions:", - " The above copyright notice and this permission notice shall be", - " included in all copies or substantial portions of the Software.\"", - (const char *) 0 - }; -#endif /*0*/ + /* lua_info[] moved to util/mdlib.c and rendered via do_runtime_info() */ + #if defined(OPTIONS_AT_RUNTIME) use_dlb = FALSE; #else diff --git a/src/vision.c b/src/vision.c index 997a88715..d94c56bf4 100644 --- a/src/vision.c +++ b/src/vision.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 vision.c $NHDT-Date: 1707424350 2024/02/08 20:32:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.62 $ */ +/* NetHack 3.7 vision.c $NHDT-Date: 1724939600 2024/08/29 13:53:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.70 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -170,7 +170,7 @@ does_block(int x, int y, struct rm *lev) #endif /* Boulders block light. */ - for (obj = gl.level.objects[x][y]; obj; obj = obj->nexthere) + for (obj = svl.level.objects[x][y]; obj; obj = obj->nexthere) if (obj->otyp == BOULDER) return 1; @@ -311,12 +311,12 @@ rogue_vision(seenV **next, coordxy *rmin, coordxy *rmax) /* If in a lit room, we are able to see to its boundaries. */ /* If dark, set COULD_SEE so various spells work -dlc */ if (rnum >= 0) { - for (zy = gr.rooms[rnum].ly - 1; zy <= gr.rooms[rnum].hy + 1; zy++) { - rmin[zy] = start = gr.rooms[rnum].lx - 1; - rmax[zy] = stop = gr.rooms[rnum].hx + 1; + for (zy = svr.rooms[rnum].ly - 1; zy <= svr.rooms[rnum].hy + 1; zy++) { + rmin[zy] = start = svr.rooms[rnum].lx - 1; + rmax[zy] = stop = svr.rooms[rnum].hx + 1; for (zx = start; zx <= stop; zx++) { - if (gr.rooms[rnum].rlit) { + if (svr.rooms[rnum].rlit) { next[zy][zx] = COULD_SEE | IN_SIGHT; levl[zx][zy].seenv = SVALL; /* see the walls */ } else @@ -521,7 +521,7 @@ vision_recalc(int control) int oldseenv; /* previous seenv value */ gv.vision_full_recalc = 0; /* reset flag */ - if (gi.in_mklev || gp.program_state.in_getlev || !iflags.vision_inited) + if (gi.in_mklev || program_state.in_getlev || !iflags.vision_inited) return; /* @@ -825,9 +825,9 @@ vision_recalc(int control) /* This newsym() caused a crash delivering msg about failure to open * dungeon file init_dungeons() -> panic() -> done(11) -> * vision_recalc(2) -> newsym() -> crash! u.ux and u.uy are 0 and - * gp.program_state.panicking == 1 under those circumstances + * program_state.panicking == 1 under those circumstances */ - if (!gp.program_state.panicking) + if (!program_state.panicking) newsym(u.ux, u.uy); /* Make sure the hero shows up! */ /* Set the new min and max pointers. */ @@ -2093,8 +2093,8 @@ do_clear_area( /* vision doesn't pass through water or clouds, detection should [this probably ought to be an arg supplied by our caller...] */ - override_vision = - (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) && detecting(func); + override_vision = (detecting(func) + && (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))); if (range > MAX_RADIUS || range < 1) panic("do_clear_area: illegal range %d", range); @@ -2107,8 +2107,8 @@ do_clear_area( y = 0; for (; y <= max_y; y++) { offset = limits[v_abs(y - srow)]; - if ((min_x = (scol - offset)) < 0) - min_x = 0; + if ((min_x = (scol - offset)) < 1) + min_x = 1; if ((max_x = (scol + offset)) >= COLNO) max_x = COLNO - 1; for (x = min_x; x <= max_x; x++) diff --git a/src/weapon.c b/src/weapon.c index 01d6f63e4..e10c456fa 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 weapon.c $NHDT-Date: 1690488665 2023/07/27 20:11:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.111 $ */ +/* NetHack 3.7 weapon.c $NHDT-Date: 1725227810 2024/09/01 21:56:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.128 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -11,7 +11,7 @@ #include "hack.h" staticfn void give_may_advance_msg(int); -staticfn void finish_towel_change(struct obj *obj, int); +staticfn void finish_towel_change(struct obj *obj, int) NONNULLARG1; staticfn boolean could_advance(int); staticfn boolean peaked_skill(int); staticfn int slots_required(int); @@ -66,8 +66,10 @@ static NEARDATA const char *const barehands_or_martial[] = { ? barehands_or_martial[martial_bonus()] \ : odd_skill_names[-skill_names_indices[type]]) -static NEARDATA const char kebabable[] = { S_XORN, S_DRAGON, S_JABBERWOCK, - S_NAGA, S_GIANT, '\0' }; +/* targets that provide attacker with small to-hit bonus when using a spear */ +static NEARDATA const char kebabable[] = { + S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0' +}; staticfn void give_may_advance_msg(int skill) @@ -184,7 +186,7 @@ hitval(struct obj *otmp, struct monst *mon) } /* Historical note: The original versions of Hack used a range of damage - * which was similar to, but not identical to the damage used in Advanced + * which was similar to, but not identical to, the damage used in Advanced * Dungeons and Dragons. I figured that since it was so close, I may as well * make it exactly the same as AD&D, adding some more weapons in the process. * This has the advantage that it is at least possible that the player would @@ -976,10 +978,10 @@ finish_towel_change(struct obj *obj, int newspe) /* increase a towel's wetness */ void -wet_a_towel(struct obj *obj, - int amt, /* positive: new value; negative: increment by -amt; - zero: no-op */ - boolean verbose) +wet_a_towel( + struct obj *obj, + int amt, /* positive: new val; negative: increment by -amt; zero: no-op */ + boolean verbose) { int newspe = (amt <= 0) ? obj->spe - amt : amt; @@ -1146,7 +1148,11 @@ skill_advance(int skill) P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more", P_NAME(skill)); - skill_based_spellbook_id(); + /* wizards discover spellbook IDs depending on spell 'school' skill limits; + this allows them to successfully write books for unknown spells without + the Luck bias they used to have over other roles */ + if (skill >= P_FIRST_SPELL && skill <= P_LAST_SPELL) + skill_based_spellbook_id(); } static const struct skill_range { @@ -1179,7 +1185,7 @@ enhance_weapon_skill(void) int clr = NO_COLOR; /* player knows about #enhance, don't show tip anymore */ - gc.context.tips[TIP_ENHANCE] = TRUE; + svc.context.tips[TIP_ENHANCE] = TRUE; if (wizard && y_n("Advance skills without practice?") == 'y') speedy = TRUE; @@ -1703,7 +1709,8 @@ skill_init(const struct def_skill *class_skill) (despite the function name, this works for spell skills too) */ unrestrict_weapon_skill(spell_skilltype(gu.urole.spelspec)); - skill_based_spellbook_id(); + if (!u.uroleplay.pauper) /* paupers lack advanced access to books */ + skill_based_spellbook_id(); } void diff --git a/src/were.c b/src/were.c index e78215ebf..0832555f1 100644 --- a/src/were.c +++ b/src/were.c @@ -130,7 +130,7 @@ new_were(struct monst *mon) /* vision capability isn't changing so we don't call set_apparxy() to update mon's idea of where hero is; peaceful check is redundant */ - if (gc.context.mon_moving && !mon->mpeaceful + if (svc.context.mon_moving && !mon->mpeaceful && onscary(mon->mux, mon->muy, mon) && monnear(mon, mon->mux, mon->muy)) monflee(mon, rn1(9, 2), TRUE, TRUE); /* 2..10 turns */ diff --git a/src/wield.c b/src/wield.c index 6bb329367..b07952ed1 100644 --- a/src/wield.c +++ b/src/wield.c @@ -371,14 +371,14 @@ dowield(void) /* previously interrupted armor removal mustn't be resumed */ reset_remarm(); /* if player chose a partial stack but can't wield it, undo split */ - if (wep->o_id && wep->o_id == gc.context.objsplit.child_oid) + if (wep->o_id && wep->o_id == svc.context.objsplit.child_oid) unsplitobj(wep); return ECMD_FAIL; - } else if (wep->o_id && wep->o_id == gc.context.objsplit.child_oid) { + } else if (wep->o_id && wep->o_id == svc.context.objsplit.child_oid) { /* if wep is the result of supplying a count to getobj() we don't want to split something already wielded; for any other item, we need to give it its own inventory slot */ - if (uwep && uwep->o_id == gc.context.objsplit.parent_oid) { + if (uwep && uwep->o_id == svc.context.objsplit.parent_oid) { unsplitobj(wep); /* wep was merged back to uwep, already_wielded uses wep */ wep = uwep; @@ -538,11 +538,11 @@ doquiver_core(const char *verb) /* "ready" or "fire" */ You("already have no ammunition readied!"); } return ECMD_OK; - } else if (newquiver->o_id == gc.context.objsplit.child_oid) { + } else if (newquiver->o_id == svc.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 == gc.context.objsplit.parent_oid) { + if (uquiver && uquiver->o_id == svc.context.objsplit.parent_oid) { unsplitobj(newquiver); goto already_quivered; } else if (newquiver->oclass == COIN_CLASS) { diff --git a/src/windows.c b/src/windows.c index e7f1351f7..de126da2a 100644 --- a/src/windows.c +++ b/src/windows.c @@ -1196,13 +1196,14 @@ dump_fmtstr( break; case 'n': /* player name */ if (fullsubs) - Sprintf(tmpbuf, "%s", *gp.plname ? gp.plname : "unknown"); + Sprintf(tmpbuf, "%s", + *svp.plname ? svp.plname : "unknown"); else Strcpy(tmpbuf, "{hero name}"); break; case 'N': /* first character of player name */ if (fullsubs) - Sprintf(tmpbuf, "%c", *gp.plname ? *gp.plname : 'u'); + Sprintf(tmpbuf, "%c", *svp.plname ? *svp.plname : 'u'); else Strcpy(tmpbuf, "{hero initial}"); break; @@ -1430,7 +1431,7 @@ encglyph(int glyph) { static char encbuf[20]; /* 10+1 would suffice */ - Sprintf(encbuf, "\\G%04X%04X", gc.context.rndencode, glyph); + Sprintf(encbuf, "\\G%04X%04X", svc.context.rndencode, glyph); return encbuf; } @@ -1449,7 +1450,7 @@ decode_glyph(const char *str, int *glyph_ptr) } else break; } - if (rndchk == gc.context.rndencode) { + if (rndchk == svc.context.rndencode) { *glyph_ptr = dcount = 0; for (; *str && ++dcount <= 4; ++str) { if ((dp = strchr(hexdd, *str)) != 0) { @@ -1672,7 +1673,8 @@ choose_classes_menu(const char *prompt, case 0: idx = def_char_to_monclass(*class_list); if (!IndexOk(idx, def_monsyms)) { - panic("choose_classes_menu: invalid monclass '%c'", *class_list); + panic("choose_classes_menu: invalid monclass '%c'", + *class_list); /*NOTREACHED*/ } text = def_monsyms[idx].explain; @@ -1682,7 +1684,8 @@ choose_classes_menu(const char *prompt, case 1: idx = def_char_to_objclass(*class_list); if (!IndexOk(idx, def_oc_syms)) { - panic("choose_classes_menu: invalid objclass '%c'", *class_list); + panic("choose_classes_menu: invalid objclass '%c'", + *class_list); /*NOTREACHED*/ } text = def_oc_syms[idx].explain; @@ -1814,7 +1817,7 @@ add_menu_heading(winid tmpwin, const char *buf) color = iflags.menu_headings.color; /* suppress highlighting during end-of-game disclosure */ - if (gp.program_state.gameover) + if (program_state.gameover) attr = ATR_NONE, color = NO_COLOR; add_menu(tmpwin, &nul_glyphinfo, &any, '\0', '\0', attr, color, @@ -1862,10 +1865,10 @@ getlin(const char *query, char *bufp) { boolean old_bot_disabled = gb.bot_disabled; - gp.program_state.in_getlin = 1; + program_state.in_getlin = 1; gb.bot_disabled = TRUE; (*windowprocs.win_getlin)(query, bufp); gb.bot_disabled = old_bot_disabled; - gp.program_state.in_getlin = 0; + program_state.in_getlin = 0; } /*windows.c*/ diff --git a/src/wizard.c b/src/wizard.c index 0989f9b20..aefba556d 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -86,7 +86,7 @@ amulet(void) } } - if (!gc.context.no_of_wizards) + if (!svc.context.no_of_wizards) return; /* find Wizard, and wake him if necessary */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { @@ -295,7 +295,7 @@ strategy(struct monst *mtmp) break; } - if (gc.context.made_amulet) + if (svc.context.made_amulet) if ((strat = target_on(M3_WANTSAMUL, mtmp)) != STRAT_NONE) return strat; @@ -544,7 +544,7 @@ pick_nasty( master mind flayer -> mind flayer, but the substitutes are likely to be genocided too */ alt = res; - if ((gm.mvitals[res].mvflags & G_GENOD) != 0 + if ((svm.mvitals[res].mvflags & G_GENOD) != 0 || (difcap > 0 && mons[res].difficulty >= difcap) /* note: nasty() -> makemon() ignores G_HELL|G_NOHELL; arch-lich and master lich are both flagged as hell-only; @@ -552,7 +552,7 @@ pick_nasty( outside of Gehennom (unless the latter has been genocided) */ || (mons[res].geno & (Inhell ? G_NOHELL : G_HELL)) != 0) alt = big_to_little(res); - if (alt != res && (gm.mvitals[alt].mvflags & G_GENOD) == 0) { + if (alt != res && (svm.mvitals[alt].mvflags & G_GENOD) == 0) { const char *mnam = mons[alt].pmnames[NEUTRAL], *lastspace = strrchr(mnam, ' '); @@ -702,7 +702,7 @@ resurrect(void) long elapsed; const char *verb; - if (!gc.context.no_of_wizards) { + if (!svc.context.no_of_wizards) { /* make a new Wizard */ verb = "kill"; mtmp = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy, MM_NOWAIT); @@ -718,7 +718,7 @@ resurrect(void) if (mtmp->iswiz /* if he has the Amulet, he won't bring it to you */ && !mon_has_amulet(mtmp) - && (elapsed = gm.moves - mtmp->mlstmv) > 0L) { + && (elapsed = svm.moves - mtmp->mlstmv) > 0L) { mon_catchup_elapsed_time(mtmp, elapsed); if (elapsed >= LARGEST_INT) elapsed = LARGEST_INT - 1; @@ -798,7 +798,7 @@ intervene(void) void wizdeadorgone(void) { - gc.context.no_of_wizards--; + svc.context.no_of_wizards--; if (!u.uevent.udemigod) { u.uevent.udemigod = TRUE; u.udg_cnt = rn1(250, 50); diff --git a/src/wizcmds.c b/src/wizcmds.c index f4f3006f2..454b4deb9 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 wizcmds.c $NHDT-Date: 1716592982 2024/05/24 23:23:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.7 $ */ +/* NetHack 3.7 wizcmds.c $NHDT-Date: 1723580901 2024/08/13 20:28:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /*-Copyright (c) Robert Patrick Rankin, 2024. */ /* NetHack may be freely redistributed. See license for details. */ @@ -76,9 +76,9 @@ makemap_unmakemon(struct monst *mtmp, boolean migratory) /* uncreate any unique monster so that it is eligible to be remade on the new incarnation of the level; ignores DEADMONSTER() [why?] */ if (mtmp->data->geno & G_UNIQ) - gm.mvitals[ndx].mvflags &= ~G_EXTINCT; - if (gm.mvitals[ndx].born) - gm.mvitals[ndx].born--; + svm.mvitals[ndx].mvflags &= ~G_EXTINCT; + if (svm.mvitals[ndx].born) + svm.mvitals[ndx].born--; /* vault is going away; get rid of guard who might be in play or be parked at <0,0>; for the latter, might already be flagged as @@ -276,8 +276,8 @@ wiz_kill(void) Sprintf(qbuf, "%s?", Role_if(PM_SAMURAI) ? "Perform seppuku" : "Commit suicide"); if (paranoid_query(TRUE, qbuf)) { - Sprintf(gk.killer.name, "%s own player", uhis()); - gk.killer.format = KILLED_BY; + Sprintf(svk.killer.name, "%s own player", uhis()); + svk.killer.format = KILLED_BY; done(DIED); } break; @@ -318,12 +318,12 @@ wiz_kill(void) gas spore whose explosion kills any other monsters we need to have the mon_moving flag be True in order to avoid blaming or crediting hero for their deaths */ - gc.context.mon_moving = TRUE; + svc.context.mon_moving = TRUE; pline("%s is %s.", upstart(Mn), nonliving(mtmp->data) ? "destroyed" : "killed"); /* Null second arg suppresses the usual message */ monkilled(mtmp, (char *) 0, AD_PHYS); - gc.context.mon_moving = FALSE; + svc.context.mon_moving = FALSE; } /* end targetting loop if an engulfer dropped hero onto a level- changing trap */ @@ -736,48 +736,48 @@ wiz_map_levltyp(void) /* alignment currently omitted to save space */ } /* level features */ - if (gl.level.flags.nfountains) + if (svl.level.flags.nfountains) Sprintf(eos(dsc), " %c:%d", defsyms[S_fountain].sym, - (int) gl.level.flags.nfountains); - if (gl.level.flags.nsinks) + (int) svl.level.flags.nfountains); + if (svl.level.flags.nsinks) Sprintf(eos(dsc), " %c:%d", defsyms[S_sink].sym, - (int) gl.level.flags.nsinks); - if (gl.level.flags.has_vault) + (int) svl.level.flags.nsinks); + if (svl.level.flags.has_vault) Strcat(dsc, " vault"); - if (gl.level.flags.has_shop) + if (svl.level.flags.has_shop) Strcat(dsc, " shop"); - if (gl.level.flags.has_temple) + if (svl.level.flags.has_temple) Strcat(dsc, " temple"); - if (gl.level.flags.has_court) + if (svl.level.flags.has_court) Strcat(dsc, " throne"); - if (gl.level.flags.has_zoo) + if (svl.level.flags.has_zoo) Strcat(dsc, " zoo"); - if (gl.level.flags.has_morgue) + if (svl.level.flags.has_morgue) Strcat(dsc, " morgue"); - if (gl.level.flags.has_barracks) + if (svl.level.flags.has_barracks) Strcat(dsc, " barracks"); - if (gl.level.flags.has_beehive) + if (svl.level.flags.has_beehive) Strcat(dsc, " hive"); - if (gl.level.flags.has_swamp) + if (svl.level.flags.has_swamp) Strcat(dsc, " swamp"); /* level flags */ - if (gl.level.flags.noteleport) + if (svl.level.flags.noteleport) Strcat(dsc, " noTport"); - if (gl.level.flags.hardfloor) + if (svl.level.flags.hardfloor) Strcat(dsc, " noDig"); - if (gl.level.flags.nommap) + if (svl.level.flags.nommap) Strcat(dsc, " noMMap"); - if (!gl.level.flags.hero_memory) + if (!svl.level.flags.hero_memory) Strcat(dsc, " noMem"); - if (gl.level.flags.shortsighted) + if (svl.level.flags.shortsighted) Strcat(dsc, " shortsight"); - if (gl.level.flags.graveyard) + if (svl.level.flags.graveyard) Strcat(dsc, " graveyard"); - if (gl.level.flags.is_maze_lev) + if (svl.level.flags.is_maze_lev) Strcat(dsc, " maze"); - if (gl.level.flags.is_cavernous_lev) + if (svl.level.flags.is_cavernous_lev) Strcat(dsc, " cave"); - if (gl.level.flags.arboreal) + if (svl.level.flags.arboreal) Strcat(dsc, " tree"); if (Sokoban) Strcat(dsc, " sokoban-rules"); @@ -806,7 +806,7 @@ wiz_map_levltyp(void) Strcat(dsc, " endgame"); else { /* somebody's added a dungeon branch we're not expecting */ - const char *brname = gd.dungeons[u.uz.dnum].dname; + const char *brname = svd.dungeons[u.uz.dnum].dname; if (!brname || !*brname) brname = "unknown"; @@ -1047,9 +1047,9 @@ wiz_intrinsic(void) break; case WARN_OF_MON: if (!Warn_of_mon) { - gc.context.warntype.speciesidx = PM_GRID_BUG; - gc.context.warntype.species - = &mons[gc.context.warntype.speciesidx]; + svc.context.warntype.speciesidx = PM_GRID_BUG; + svc.context.warntype.species + = &mons[svc.context.warntype.speciesidx]; } goto def_feedback; case GLIB: @@ -1193,7 +1193,7 @@ contained_stats( count_obj(gi.invent, &count, &size, FALSE, TRUE); count_obj(fobj, &count, &size, FALSE, TRUE); - count_obj(gl.level.buriedobjlist, &count, &size, FALSE, TRUE); + count_obj(svl.level.buriedobjlist, &count, &size, FALSE, TRUE); count_obj(gm.migrating_objs, &count, &size, FALSE, TRUE); /* DEADMONSTER check not required in this loop since they have no * inventory */ @@ -1317,7 +1317,7 @@ misc_stats( } count = size = 0L; - for (sd = gl.level.damagelist; sd; sd = sd->next) { + for (sd = svl.level.damagelist; sd; sd = sd->next) { ++count; size += (long) sizeof *sd; } @@ -1340,7 +1340,7 @@ misc_stats( } count = size = 0L; - for (k = gk.killer.next; k; k = k->next) { + for (k = svk.killer.next; k; k = k->next) { ++count; size += (long) sizeof *k; } @@ -1354,7 +1354,7 @@ misc_stats( } count = size = 0L; - for (bi = gl.level.bonesinfo; bi; bi = bi->next) { + for (bi = svl.level.bonesinfo; bi; bi = bi->next) { ++count; size += (long) sizeof *bi; } @@ -1435,6 +1435,7 @@ sanity_check(void) iflags.sanity_no_check = FALSE; return; } + program_state.in_sanity_check++; you_sanity_check(); obj_sanity_check(); timer_sanity_check(); @@ -1443,6 +1444,7 @@ sanity_check(void) bc_sanity_check(); trap_sanity_check(); engraving_sanity_check(); + program_state.in_sanity_check--; } /* qsort() comparison routine for use in list_migrating_mons() */ @@ -1597,7 +1599,7 @@ wiz_show_stats(void) obj_chain(win, "invent", gi.invent, TRUE, &total_obj_count, &total_obj_size); obj_chain(win, "fobj", fobj, TRUE, &total_obj_count, &total_obj_size); - obj_chain(win, "buried", gl.level.buriedobjlist, FALSE, + obj_chain(win, "buried", svl.level.buriedobjlist, FALSE, &total_obj_count, &total_obj_size); obj_chain(win, "migrating obj", gm.migrating_objs, FALSE, &total_obj_count, &total_obj_size); diff --git a/src/worm.c b/src/worm.c index 479c9d75e..bb95dc4d5 100644 --- a/src/worm.c +++ b/src/worm.c @@ -211,13 +211,13 @@ worm_move(struct monst *worm) seg->nseg = new_seg; /* attach it to the end of the list */ wheads[wnum] = new_seg; /* move the end pointer */ - if (wgrowtime[wnum] <= gm.moves) { + if (wgrowtime[wnum] <= svm.moves) { int whplimit, whpcap, prev_mhp, wsegs = count_wsegs(worm); /* first set up for the next time to grow */ if (!wgrowtime[wnum]) { /* new worm; usually grow a tail segment on its next turn */ - wgrowtime[wnum] = gm.moves + rnd(5); + wgrowtime[wnum] = svm.moves + rnd(5); } else { int mmove = mcalcmove(worm, FALSE), /* prior to 3.7.0, next-grow increment was 3..17 but since @@ -230,7 +230,7 @@ worm_move(struct monst *worm) * speed of 3, effective value is 8..48 */ incr = (incr * NORMAL_SPEED) / max(mmove, 1); - wgrowtime[wnum] = gm.moves + incr; + wgrowtime[wnum] = svm.moves + incr; } /* increase HP based on number of segments; if it has shrunk, it @@ -432,7 +432,7 @@ cutworm(struct monst *worm, coordxy x, coordxy y, /* Sometimes the tail end dies. */ if (!new_worm) { place_worm_seg(worm, x, y); /* place the "head" segment back */ - if (gc.context.mon_moving) { + if (svc.context.mon_moving) { if (canspotmon(worm)) pline("Part of %s tail has been cut off.", s_suffix(mon_nam(worm))); @@ -466,7 +466,7 @@ cutworm(struct monst *worm, coordxy x, coordxy y, /* Place the new monster at all the segment locations. */ place_wsegs(new_worm, worm); - if (gc.context.mon_moving) + if (svc.context.mon_moving) pline("%s is cut in half.", Monnam(worm)); else You("cut %s in half.", mon_nam(worm)); @@ -670,9 +670,9 @@ sanity_check_worm(struct monst *worm) x = curr->wx, y = curr->wy; if (!isok(x, y)) impossible("worm seg not isok <%d,%d>", x, y); - else if (gl.level.monsters[x][y] != worm) + else if (svl.level.monsters[x][y] != worm) impossible("mon (%s) at seg location is not worm (%s)", - fmt_ptr((genericptr_t) gl.level.monsters[x][y]), + fmt_ptr((genericptr_t) svl.level.monsters[x][y]), fmt_ptr((genericptr_t) worm)); curr = curr->nseg; diff --git a/src/worn.c b/src/worn.c index b8593b214..1f35776d4 100644 --- a/src/worn.c +++ b/src/worn.c @@ -7,7 +7,8 @@ staticfn void m_lose_armor(struct monst *, struct obj *, boolean) NONNULLPTRS; staticfn void clear_bypass(struct obj *) NO_NNARGS; -staticfn void m_dowear_type(struct monst *, long, boolean, boolean) NONNULLARG1; +staticfn void m_dowear_type(struct monst *, long, boolean, boolean) + NONNULLARG1; staticfn int extra_pref(struct monst *, struct obj *) NONNULLARG1; static const struct worn { @@ -971,7 +972,7 @@ clear_bypass(struct obj *objchn) /* all objects with their bypass bit set should now be reset to normal; this can be a relatively expensive operation so is only called if - gc.context.bypasses is set */ + svc.context.bypasses is set */ void clear_bypasses(void) { @@ -980,14 +981,14 @@ clear_bypasses(void) /* * 'Object' bypass is also used for one monster function: * polymorph control of long worms. Activated via setting - * gc.context.bypasses even if no specific object has been + * svc.context.bypasses even if no specific object has been * bypassed. */ clear_bypass(fobj); clear_bypass(gi.invent); clear_bypass(gm.migrating_objs); - clear_bypass(gl.level.buriedobjlist); + clear_bypass(svl.level.buriedobjlist); clear_bypass(gb.billobjs); clear_bypass(go.objs_deleted); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { @@ -1018,14 +1019,14 @@ clear_bypasses(void) if (uchain) uchain->bypass = 0; - gc.context.bypasses = FALSE; + svc.context.bypasses = FALSE; } void bypass_obj(struct obj *obj) { obj->bypass = 1; - gc.context.bypasses = TRUE; + svc.context.bypasses = TRUE; } /* set or clear the bypass bit in a list of objects */ @@ -1035,7 +1036,7 @@ bypass_objlist( boolean on) /* TRUE => set, FALSE => clear */ { if (on && objchain) - gc.context.bypasses = TRUE; + svc.context.bypasses = TRUE; while (objchain) { objchain->bypass = on ? 1 : 0; objchain = objchain->nobj; diff --git a/src/write.c b/src/write.c index 4536b864e..fd967685e 100644 --- a/src/write.c +++ b/src/write.c @@ -171,8 +171,8 @@ dowrite(struct obj *pen) deferred = real = 0; /* not any scroll or book */ deferralchance = 0; /* incremented for each oc_uname match */ - first = gb.bases[(int) paper->oclass]; - last = gb.bases[(int) paper->oclass + 1] - 1; + first = svb.bases[(int) paper->oclass]; + last = svb.bases[(int) paper->oclass + 1] - 1; /* first loop: look for match with name/description */ for (i = first; i <= last; i++) { /* extra shufflable descr not representing a real object */ @@ -363,7 +363,7 @@ dowrite(struct obj *pen) Strcpy(namebuf, OBJ_DESCR(objects[new_obj->otyp])); wipeout_text(namebuf, (6 + MAXULEV - u.ulevel) / 6, 0); } else - Sprintf(namebuf, "%s was here!", gp.plname); + Sprintf(namebuf, "%s was here!", svp.plname); You("write \"%s\" and the scroll disappears.", namebuf); useup(paper); } diff --git a/src/zap.c b/src/zap.c index 4d2ae0036..6a83399df 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 zap.c $NHDT-Date: 1715284462 2024/05/09 19:54:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.539 $ */ +/* NetHack 3.7 zap.c $NHDT-Date: 1723946858 2024/08/18 02:07:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.542 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -218,8 +218,8 @@ bhitm(struct monst *mtmp, struct obj *otmp) mon_adjust_speed(mtmp, 1, otmp); check_gear_next_turn(mtmp); /* might want speed boots */ } - if (mtmp->mtame) - helpful_gesture = TRUE; + /* wake but don't anger a peaceful target */ + helpful_gesture = TRUE; break; case WAN_UNDEAD_TURNING: case SPE_TURN_UNDEAD: @@ -234,7 +234,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) dmg *= 2; if (otyp == SPE_TURN_UNDEAD) dmg = spell_damage_bonus(dmg); - gc.context.bypasses = TRUE; /* for make_corpse() */ + svc.context.bypasses = TRUE; /* for make_corpse() */ if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) { if (!DEADMONSTER(mtmp)) monflee(mtmp, 0, FALSE, TRUE); @@ -273,7 +273,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) pline("%s shudders!", Monnam(mtmp)); learn_it = TRUE; } - /* gc.context.bypasses = TRUE; ## for make_corpse() */ + /* svc.context.bypasses = TRUE; ## for make_corpse() */ /* no corpse after system shock */ xkilled(mtmp, XKILL_GIVEMSG | XKILL_NOCORPSE); } else { @@ -309,7 +309,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) /* flag to indicate that cleanup is needed; object bypass cleanup also clears mon->mextra->mcorpsenm for all long worms on the level */ - gc.context.bypasses = TRUE; + svc.context.bypasses = TRUE; } } break; @@ -724,10 +724,10 @@ montraits( if (mtmp->m_id) { mtmp2->m_id = mtmp->m_id; /* might be bringing quest leader back to life */ - if (gq.quest_status.leader_is_dead + if (svq.quest_status.leader_is_dead /* leader_is_dead implies leader_m_id is valid */ - && mtmp2->m_id == gq.quest_status.leader_m_id) - gq.quest_status.leader_is_dead = FALSE; + && mtmp2->m_id == svq.quest_status.leader_m_id) + svq.quest_status.leader_is_dead = FALSE; } mtmp2->mx = mtmp->mx; mtmp2->my = mtmp->my; @@ -1144,7 +1144,7 @@ unturn_dead(struct monst *mon) save_norevive = otmp->norevive; otmp->norevive = 0; - if ((mtmp2 = revive(otmp, !gc.context.mon_moving)) != 0) { + if ((mtmp2 = revive(otmp, !svc.context.mon_moving)) != 0) { ++res; /* might get revived as a zombie rather than corpse's monster */ different_type = (mtmp2->data != &mons[corpsenm]); @@ -1432,7 +1432,7 @@ obj_shudders(struct obj *obj) { int zap_odds; - if (gc.context.bypasses && obj->bypass) + if (svc.context.bypasses && obj->bypass) return FALSE; if (obj->oclass == WAND_CLASS) @@ -1463,7 +1463,7 @@ polyuse(struct obj *objhdr, int mat, int minwt) for (otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) { otmp2 = otmp->nexthere; - if (gc.context.bypasses && otmp->bypass) + if (svc.context.bypasses && otmp->bypass) continue; if (otmp == uball || otmp == uchain) continue; @@ -1505,7 +1505,7 @@ create_polymon(struct obj *obj, int okind) const char *material; int pm_index; - if (gc.context.bypasses) { + if (svc.context.bypasses) { /* this is approximate because the "no golems" !obj->nexthere check below doesn't understand bypassed objects; but it should suffice since bypassed objects always end up as a @@ -1575,7 +1575,7 @@ create_polymon(struct obj *obj, int okind) break; } - if (!(gm.mvitals[pm_index].mvflags & G_GENOD)) + if (!(svm.mvitals[pm_index].mvflags & G_GENOD)) mdat = &mons[pm_index]; mtmp = makemon(mdat, obj->ox, obj->oy, MM_NOMSG); @@ -1819,7 +1819,7 @@ poly_obj(struct obj *obj, int id) case SPBOOK_CLASS: while (otmp->otyp == SPE_POLYMORPH) - otmp->otyp = rnd_class(gb.bases[SPBOOK_CLASS], SPE_BLANK_PAPER); + otmp->otyp = rnd_class(svb.bases[SPBOOK_CLASS], SPE_BLANK_PAPER); /* reduce spellbook abuse; non-blank books degrade; 3.7: novels don't use spestudied so shouldn't degrade to blank (but don't force spestudied to zero for them since a non-zero @@ -2110,13 +2110,13 @@ bhito(struct obj *obj, struct obj *otmp) * the invent or mon->minvent chain, possibly recursively. * * The bypass bit on all objects is reset each turn, whenever - * gc.context.bypasses is set. + * svc.context.bypasses is set. * - * We check the obj->bypass bit above AND gc.context.bypasses + * We check the obj->bypass bit above AND svc.context.bypasses * as a safeguard against any stray occurrence left in an obj * struct someplace, although that should never happen. */ - if (gc.context.bypasses) { + if (svc.context.bypasses) { return 0; } else { debugpline1("%s for a moment.", Tobjnam(obj, "pulsate")); @@ -2158,7 +2158,7 @@ bhito(struct obj *obj, struct obj *otmp) (void) boxlock(obj, otmp); if (obj_shudders(obj)) { - boolean cover = ((obj == gl.level.objects[u.ux][u.uy]) + boolean cover = ((obj == svl.level.objects[u.ux][u.uy]) && u.uundetected && hides_under(gy.youmonst.data)); @@ -2247,7 +2247,7 @@ bhito(struct obj *obj, struct obj *otmp) } else { int oox = obj->ox, ooy = obj->oy; - if (gc.context.mon_moving ? !breaks(obj, oox, ooy) + if (svc.context.mon_moving ? !breaks(obj, oox, ooy) : !hero_breaks(obj, oox, ooy, 0)) maybelearnit = FALSE; /* nothing broke */ else @@ -2287,7 +2287,7 @@ bhito(struct obj *obj, struct obj *otmp) struct monst *mtmp; coordxy ox, oy; unsigned save_norevive; - boolean by_u = !gc.context.mon_moving; + boolean by_u = !svc.context.mon_moving; int corpsenm = corpse_revive_type(obj); char *corpsname = cxname_singular(obj); @@ -2385,7 +2385,7 @@ bhitpile( boolean hidingunder, first; int prevotyp, hitanything = 0; - if (!gl.level.objects[tx][ty]) + if (!svl.level.objects[tx][ty]) return 0; /* if hiding underneath an object and zapping up or down, the top item @@ -2395,7 +2395,7 @@ bhitpile( if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) { struct trap *t = t_at(tx, ty); - struct obj *topofpile = gl.level.objects[tx][ty]; + struct obj *topofpile = svl.level.objects[tx][ty]; /* We can't settle for the default calling sequence of bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy) @@ -2408,12 +2408,12 @@ bhitpile( /* assume zapping up or down while hiding under the top item can still activate the trap even if it's below (when zapping up) or above (when zapping down) */ - if (gl.level.objects[tx][ty] != topofpile) + if (svl.level.objects[tx][ty] != topofpile) first = FALSE; /* top item was statue which activated */ } gp.poly_zapped = -1; - for (otmp = gl.level.objects[tx][ty]; otmp; otmp = next_obj) { + for (otmp = svl.level.objects[tx][ty]; otmp; otmp = next_obj) { next_obj = otmp->nexthere; if (hidingunder) { if (first) { @@ -2432,14 +2432,14 @@ bhitpile( } if (gp.poly_zapped >= 0) - create_polymon(gl.level.objects[tx][ty], gp.poly_zapped); + create_polymon(svl.level.objects[tx][ty], gp.poly_zapped); /* when boulders are present they're expected to be on top; with multiple boulders it's possible for some to have been changed into non-boulders (polymorph, stone-to-flesh) while ones beneath resist, so re-stack pile if there are any non-boulders above boulders */ prevotyp = BOULDER; - for (otmp = gl.level.objects[tx][ty]; otmp; otmp = otmp->nexthere) { + for (otmp = svl.level.objects[tx][ty]; otmp; otmp = otmp->nexthere) { if (otmp->otyp == BOULDER && prevotyp != BOULDER) { recreate_pile_at(tx, ty); break; @@ -2483,7 +2483,7 @@ do_enlightenment_effect(void) /* * zapnodir - zaps a NODIR wand/spell. - * added by GAN 11/03/86 + * Won't get here if wand has no charges (unless wresting 1 last charge). */ void zapnodir(struct obj *obj) @@ -2493,36 +2493,45 @@ zapnodir(struct obj *obj) switch (obj->otyp) { case WAN_LIGHT: case SPE_LIGHT: + /* FIXME? wand of light becoming discovered should be contingent upon + seeing at least one previously unlit spot become lit */ + known = (obj->dknown && !Blind); litroom(TRUE, obj); - if (!Blind) - known = TRUE; - if (lightdamage(obj, TRUE, 5)) - known = TRUE; + (void) lightdamage(obj, TRUE, 5); break; case WAN_SECRET_DOOR_DETECTION: case SPE_DETECT_UNSEEN: - if (!findit()) - return; - if (!Blind) - known = TRUE; + /* findit() gives sufficient feedback to discover the wand even when + blinded or when it fails to find anything */ + known = !!obj->dknown; + (void) findit(); break; case WAN_CREATE_MONSTER: - known = create_critters(rn2(23) ? 1 : rn1(7, 2), - (struct permonst *) 0, FALSE); + /* create_critters() returns True iff hero sees a new monster appear */ + if (create_critters(rn2(23) ? 1 : rn1(7, 2), + (struct permonst *) 0, FALSE)) + known = !!obj->dknown; break; case WAN_WISHING: - known = TRUE; if (Luck + rn2(5) < 0) { pline("Unfortunately, nothing happens."); - break; + known = FALSE; + } else { + known = !!obj->dknown; + /* wand of wishing asks player what to wish for so always becomes + discovered (unless it hasn't been seen) */ + makewish(); } - makewish(); break; case WAN_ENLIGHTENMENT: - known = TRUE; + known = !!obj->dknown; + /* do_enlightenmnt_effect() always describes enlightenment */ do_enlightenment_effect(); break; + default: + break; } + if (known) { if (!objects[obj->otyp].oc_name_known) more_experienced(0, 10); @@ -2820,8 +2829,8 @@ zapyourself(struct obj *obj, boolean ordinary) break; } learn_it = TRUE; - Sprintf(gk.killer.name, "shot %sself with a death ray", uhim()); - gk.killer.format = NO_KILLER_PREFIX; + Sprintf(svk.killer.name, "shot %sself with a death ray", uhim()); + svk.killer.format = NO_KILLER_PREFIX; /* probably don't need these to be urgent; player just gave input without subsequent opportunity to dismiss --More-- with ESC */ urgent_pline("You irradiate yourself with pure energy!"); @@ -3177,7 +3186,7 @@ zap_updown(struct obj *obj) /* wand or spell, nonnull */ map_zapped = TRUE; if (ltyp == ICE || IS_FURNITURE(ltyp)) { surf = "it"; - if (gl.lastseentyp[x][y] != rememberedltyp) + if (svl.lastseentyp[x][y] != rememberedltyp) ptmp += 1; } else { surf = the(surface(x, y)); @@ -3323,7 +3332,7 @@ zap_updown(struct obj *obj) /* wand or spell, nonnull */ */ if (u.uundetected && hides_under(gy.youmonst.data)) { int hitit = 0; - otmp = gl.level.objects[u.ux][u.uy]; + otmp = svl.level.objects[u.ux][u.uy]; if (otmp) hitit = bhito(otmp, obj); @@ -3581,7 +3590,7 @@ zap_map( case WAN_POLYMORPH: case SPE_POLYMORPH: del_engr(e); - make_engr_at(x, y, random_engraving(ebuf), gm.moves, 0); + make_engr_at(x, y, random_engraving(ebuf), svm.moves, 0); break; case WAN_CANCELLATION: case SPE_CANCELLATION: @@ -3654,10 +3663,10 @@ zap_map( /* map terrain; might reveal a special room which is already within view that hasn't been entered yet */ - oldtyp = gl.lastseentyp[x][y]; + oldtyp = svl.lastseentyp[x][y]; oldglyph = glyph_at(x, y); show_map_spot(x, y, FALSE); - if (oldtyp != gl.lastseentyp[x][y] || oldglyph != glyph_at(x, y)) { + if (oldtyp != svl.lastseentyp[x][y] || oldglyph != glyph_at(x, y)) { /* TODO: ought to give some message */ learn_it = TRUE; } @@ -4409,8 +4418,8 @@ zhitu( break; } monstunseesu(M_SEEN_MAGR); - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, fltxt ? fltxt : ""); + svk.killer.format = KILLED_BY_AN; + Strcpy(svk.killer.name, fltxt ? fltxt : ""); /* when killed by disintegration breath, don't leave corpse */ u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM; done(DIED); @@ -4513,7 +4522,7 @@ burn_floor_objects( char buf1[BUFSZ], buf2[BUFSZ]; int cnt = 0; - for (obj = gl.level.objects[x][y]; obj; obj = obj2) { + for (obj = svl.level.objects[x][y]; obj; obj = obj2) { obj2 = obj->nexthere; if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS || (obj->oclass == FOOD_CLASS @@ -4559,7 +4568,7 @@ burn_floor_objects( } /* This also ignites floor items, but does not change cnt because they weren't consumed. */ - ignite_items(gl.level.objects[x][y]); + ignite_items(svl.level.objects[x][y]); return cnt; } @@ -5009,15 +5018,15 @@ melt_ice_away(anything *arg, long timeout UNUSED) { coordxy x, y; long where = arg->a_long; - boolean save_mon_moving = gc.context.mon_moving; /* will be False */ + boolean save_mon_moving = svc.context.mon_moving; /* will be False */ /* melt_ice -> minliquid -> mondead|xkilled shouldn't credit/blame hero */ - gc.context.mon_moving = TRUE; /* hero isn't causing this ice to melt */ + svc.context.mon_moving = TRUE; /* hero isn't causing this ice to melt */ y = (coordxy) (where & 0xFFFF); x = (coordxy) ((where >> 16) & 0xFFFF); /* melt_ice does newsym when appropriate */ melt_ice(x, y, "Some ice melts away."); - gc.context.mon_moving = save_mon_moving; + svc.context.mon_moving = save_mon_moving; } /* Burn floor scrolls, evaporate pools, etc... in a single square. @@ -5128,7 +5137,7 @@ zap_over_floor( if (is_pool(x, y) || is_lava(x, y) || lavawall) { boolean lava = (is_lava(x, y) || lavawall), moat = is_moat(x, y); - int chance = max(2, 5 + gl.level.flags.temperature * 10); + int chance = max(2, 5 + svl.level.flags.temperature * 10); if (IS_WATERWALL(lev->typ) || (lavawall && rn2(chance))) { /* For now, don't let WATER freeze. */ @@ -5416,12 +5425,12 @@ mon_spell_hits_spot( } } -/* fractured by pick-axe or wand of striking or by vault guard */ +/* fractured by pick-axe or wand of striking or by vault guard or shopkeeper */ void fracture_rock(struct obj *obj) /* no texts here! */ { coordxy x, y; - boolean by_you = !gc.context.mon_moving; + boolean by_you = !svc.context.mon_moving; if (by_you && get_obj_location(obj, &x, &y, 0) && costly_spot(x, y)) { struct monst *shkp = 0; @@ -5468,7 +5477,7 @@ break_statue(struct obj *obj) /* [obj is assumed to be on floor, so no get_obj_location() needed] */ struct trap *trap = t_at(obj->ox, obj->oy); struct obj *item; - boolean by_you = !gc.context.mon_moving; + boolean by_you = !svc.context.mon_moving; if (trap && trap->ttyp == STATUE_TRAP && activate_statue_trap(trap, obj->ox, obj->oy, TRUE)) diff --git a/submodules/CHKSUMS b/submodules/CHKSUMS index 44ae314a0..bea046547 100644 --- a/submodules/CHKSUMS +++ b/submodules/CHKSUMS @@ -5,3 +5,4 @@ # generate: # shasum -a 256 FILETOCHECK >>THISFILE 7d5ea1b9cb6aa0b59ca3dde1c6adcb57ef83a1ba8e5432c0ecd06bf439b3ad88 lua-5.4.6.tar.gz +9fbf5e28ef86c69858f6d3d34eccc32e911c1a28b4120ff3e84aaa70cfbf1e30 lua-5.4.7.tar.gz diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index 421ad62b9..d43cdc362 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -81,7 +81,7 @@ nhmain(int argc, char *argv[]) early_init(argc, argv); gh.hname = argv[0]; - gh.hackpid = getpid(); + svh.hackpid = getpid(); (void) umask(0777 & ~FCMASK); choose_windows(DEFAULT_WINDOW_SYS); @@ -193,7 +193,7 @@ nhmain(int argc, char *argv[]) * It seems you really want to play. */ u.uhp = 1; /* prevent RIP on early quits */ - gp.program_state.preserve_locks = 1; + program_state.preserve_locks = 1; #ifndef NO_SIGNAL sethanguphandler((SIG_RET_TYPE) hangup); #endif @@ -227,7 +227,7 @@ nhmain(int argc, char *argv[]) /* wizard mode access is deferred until here */ set_playmode(); /* sets plname to "wizard" for wizard mode */ /* hide any hyphens from plnamesuffix() */ - gp.plnamelen = exact_username ? (int) strlen(gp.plname) : 0; + gp.plnamelen = exact_username ? (int) strlen(svp.plname) : 0; /* strip role,race,&c suffix; calls askname() if plname[] is empty or holds a generic user name like "player" or "games" */ plnamesuffix(); @@ -270,12 +270,12 @@ nhmain(int argc, char *argv[]) * clock, &c not currently in use in the playground directory * (for gl.locknum > 0). */ - if (*gp.plname) { + if (*svp.plname) { getlock(); - gp.program_state.preserve_locks = 0; /* after getlock() */ + program_state.preserve_locks = 0; /* after getlock() */ } - if (*gp.plname && (nhfp = restore_saved_game()) != 0) { + if (*svp.plname && (nhfp = restore_saved_game()) != 0) { const char *fq_save = fqname(gs.SAVEF, SAVEPREFIX, 1); (void) chmod(fq_save, 0); /* disallow parallel restores */ @@ -306,7 +306,7 @@ nhmain(int argc, char *argv[]) } if (!resuming) { - boolean neednewlock = (!*gp.plname); + boolean neednewlock = (!*svp.plname); /* new game: start by choosing role, race, etc; player might change the hero's name while doing that, in which case we try to restore under the new name @@ -315,7 +315,7 @@ nhmain(int argc, char *argv[]) if (!plsel_once) player_selection(); plsel_once = TRUE; - if (neednewlock && *gp.plname) + if (neednewlock && *svp.plname) goto attempt_restore; if (iflags.renameinprogress) { /* player has renamed the hero while selecting role; @@ -381,12 +381,12 @@ process_options(int argc, char *argv[]) #endif case 'u': if (argv[0][2]) { - (void) strncpy(gp.plname, argv[0] + 2, sizeof gp.plname - 1); + (void) strncpy(svp.plname, argv[0] + 2, sizeof svp.plname - 1); gp.plnamelen = 0; /* plname[] might have -role-race attached */ } else if (argc > 1) { argc--; argv++; - (void) strncpy(gp.plname, argv[0], sizeof gp.plname - 1); + (void) strncpy(svp.plname, argv[0], sizeof svp.plname - 1); gp.plnamelen = 0; } else { raw_print("Player name expected after -u"); @@ -534,7 +534,7 @@ whoami(void) * Note that we trust the user here; it is possible to play under * somebody else's name. */ - if (!*gp.plname) { + if (!*svp.plname) { const char *s; s = nh_getenv("USER"); @@ -544,8 +544,8 @@ whoami(void) s = getlogin(); if (s && *s) { - (void) strncpy(gp.plname, s, sizeof gp.plname - 1); - if (strchr(gp.plname, '-')) + (void) strncpy(svp.plname, s, sizeof svp.plname - 1); + if (strchr(svp.plname, '-')) return TRUE; } } @@ -672,7 +672,7 @@ check_user_string(const char *optstr) if (optstr[0] == '*') return TRUE; /* allow any user */ if (sysopt.check_plname) - pwname = gp.plname; + pwname = svp.plname; else if ((pw = get_unix_pw()) != 0) pwname = pw->pw_name; if (!pwname || !*pwname) @@ -1066,7 +1066,7 @@ void js_globals_init() { }); /* globals */ - CREATE_GLOBAL(gp.plname, "s"); + CREATE_GLOBAL(svp.plname, "s"); /* window globals */ CREATE_GLOBAL(WIN_MAP, "i"); diff --git a/sys/msdos/pckeys.c b/sys/msdos/pckeys.c index 3c66cb6b7..5e5c1ee69 100644 --- a/sys/msdos/pckeys.c +++ b/sys/msdos/pckeys.c @@ -36,7 +36,7 @@ pckeys(unsigned char scancode, unsigned char shift) { boolean opening_dialog; - opening_dialog = gp.pl_character[0] ? FALSE : TRUE; + opening_dialog = svp.pl_character[0] ? FALSE : TRUE; switch (scancode) { #ifdef SIMULATE_CURSOR case 0x3d: /* F3 = toggle cursor type */ diff --git a/sys/msdos/vidvesa.c b/sys/msdos/vidvesa.c index 205c9d619..08d92b7a3 100644 --- a/sys/msdos/vidvesa.c +++ b/sys/msdos/vidvesa.c @@ -794,7 +794,7 @@ vesa_cliparound(int x, int y) clipymax = ROWNO - 1; } if (clipx != oldx || clipy != oldy) { - if (on_level(&u.uz0, &u.uz) && !gp.program_state.restoring) + if (on_level(&u.uz0, &u.uz) && !program_state.restoring) /* (void) doredraw(); */ vesa_redrawmap(); } diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index 8e50ccca8..f2473cfc5 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -472,7 +472,7 @@ vga_cliparound(int x, int y UNUSED) clipx = clipxmax - (viewport_size - 1); } if (clipx != oldx) { - if (on_level(&u.uz0, &u.uz) && !gp.program_state.restoring) + if (on_level(&u.uz0, &u.uz) && !program_state.restoring) /* (void) doredraw(); */ vga_redrawmap(1); } diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index ec8ff0c70..3e0a4c355 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -411,19 +411,19 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ * overwritten without confirmation when a user starts up * another game with the same player name. */ - Strcpy(gl.lock, gp.plname); + Strcpy(gl.lock, svp.plname); regularize(gl.lock); getlock(); #else /* What follows is !PC_LOCKING */ #ifdef AMIGA /* We'll put the bones & levels in the user specified directory \ -jhsa */ - Strcat(gl.lock, gp.plname); + Strcat(gl.lock, svp.plname); Strcat(gl.lock, ".99"); #else /* I'm not sure what, if anything, is left here, but old MFLOPPY had * conflicts with set_lock_and_bones() in files.c. */ - Strcpy(gl.lock, gp.plname); + Strcpy(gl.lock, svp.plname); Strcat(gl.lock, ".99"); regularize(gl.lock); /* is this necessary? */ /* not compatible with full path a la AMIGA */ @@ -436,9 +436,9 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ if (!nhfp) { raw_print("Cannot create lock file"); } else { - gh.hackpid = 1; + svh.hackpid = 1; if (nhfp->structlevel) - write(nhfp->fd, (genericptr_t) &gh.hackpid, sizeof(gh.hackpid)); + write(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof(svh.hackpid)); close_nhfile(nhfp); } @@ -549,11 +549,11 @@ process_options(int argc, char *argv[]) #endif case 'u': if (argv[0][2]) - (void) strncpy(gp.plname, argv[0] + 2, sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, argv[0] + 2, sizeof(svp.plname) - 1); else if (argc > 1) { argc--; argv++; - (void) strncpy(gp.plname, argv[0], sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, argv[0], sizeof(svp.plname) - 1); } else raw_print("Player name expected after -u"); break; @@ -715,7 +715,7 @@ port_help(void) boolean authorize_wizard_mode(void) { - if (!strcmp(gp.plname, WIZARD_NAME)) + if (!strcmp(svp.plname, WIZARD_NAME)) return TRUE; return FALSE; } diff --git a/sys/share/pcunix.c b/sys/share/pcunix.c index 115134548..f95a26a79 100644 --- a/sys/share/pcunix.c +++ b/sys/share/pcunix.c @@ -179,8 +179,8 @@ gotlock: #endif error("cannot creat file (%s.)", fq_lock); } else { - if (write(fd, (char *) &gh.hackpid, sizeof(gh.hackpid)) - != sizeof(gh.hackpid)) { + if (write(fd, (char *) &svh.hackpid, sizeof(svh.hackpid)) + != sizeof(svh.hackpid)) { #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index 957bfe81e..c7bb4b524 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -1,5 +1,5 @@ # NetHack Top-level Makefile. -# NetHack 3.7 Makefile.top $NHDT-Date: 1693519381 2023/08/31 22:03:01 $ $NHDT-Branch: keni-crashweb2 $:$NHDT-Revision: 1.91 $ +# NetHack 3.7 Makefile.top $NHDT-Date: 1722119081 2024/07/27 22:24:41 $ $NHDT-Branch: keni-fetchlua $:$NHDT-Revision: 1.109 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -161,6 +161,16 @@ luabin: ( cd $(LUATOP) \ && make $(LUAMAKEFILES) all && cd $(LUA2NHTOP) ) +# This is only needed for some internal tools. +nhlua: + base=`ls -td lib/lua-*|head -1` ; \ + [ -z $$base ] && $(MAKE) fetch-lua ; \ + base=`ls -td lib/lua-*|head -1` ; \ + cp -R $$base/ lib/nhlsrc ; \ + rm -f util/nhlua ; \ + ( cd lib/nhlsrc && $(MAKE) clean posix ) ; \ + cp lib/nhlsrc/src/lua util/nhlua + # hints file could set LUATESTTARGET to this if GITSUBMODULES is defined submodules/lua/lua.h: git submodule init submodules/lua @@ -322,45 +332,55 @@ dofiles-nodlb: LUA_URL :=www.lua.org/ftp LUA_URL_MIRROR :=www.tecgraf.puc-rio.br/lua/mirror/ftp +LUA_URL_NHD :=www.nethack.org/download/thirdparty +LUA_URL_list:=$(LUA_URL) $(LUA_URL_MIRROR) $(LUA_URL_NHD) -fetch-lua-mirror: LUA_URL :=$(LUA_URL_MIRROR) +fetch-lua-mirror: LUA_URL_list:=$(LUA_URL_MIRROR) fetch-lua-mirror: fetch-Lua @true +fetch-lua-nhd: LUA_URL_list:=$(LUA_URL_NHD) +fetch-lua-nhd: fetch-Lua + @true + fetch-lua: fetch-Lua @true fetch-Lua: - @( mkdir -p lib && cd lib && \ - n=0; \ + @( \ + shac1=`command -v shasum`; \ + shac2=`command -v sha256sum`; \ + if [ ! -z $$shac1 ]; then \ + shac="$$shac1 -a 256"; elif [ ! -z $$shac2 ]; then \ + shac=$$shac2; else echo "CAUTION: no way to check integrity"; \ + fi; \ + set -- DUMMY $(LUA_URL_list); \ + luafile=lua-$(LUA_VERSION).tar.gz; \ export curlstatus=1; \ - while [ $${n} -lt 2 ]; do \ + mkdir -p lib && cd lib && \ + while [ $$# -gt 0 ]; do \ + shift; \ if [ $$curlstatus -ne 0 ]; then \ - if [ $${n} -eq 0 ]; then \ - luaurl=https://$(LUA_URL)/lua-$(LUA_VERSION).tar.gz; \ - fi; \ - if [ $${n} -eq 1 ]; then \ - luaurl=https://$(LUA_URL_MIRROR)/lua-$(LUA_VERSION).tar.gz; \ - fi; \ - echo trying $$luaurl; \ - shac1=`command -v shasum`; \ - shac2=`command -v sha256sum`; \ - if [ ! -z $$shac1 ]; then \ - shac="$$shac1 -a 256"; elif [ ! -z $$shac2 ]; then \ - shac=$$shac2; else echo "CAUTION: no way to check integrity"; \ - fi; \ + luaurl=https://$$1/$$luafile; \ + echo Trying $$luaurl; \ curl -R -O $$luaurl; \ - export curlstatus=$$?; \ + curlstatus=$$?; \ if [ $$curlstatus -eq 0 ]; then \ if [ ! -z "$$shac" ]; then \ - echo Checking integrity with $$shac; \ - $$shac -w -c ../submodules/CHKSUMS < lua-$(LUA_VERSION).tar.gz; \ + CHKSUMS=../submodules/CHKSUMS; \ + CHKSUMSTMP=../submodules/CHKSUMS.tmp; \ + fgrep $$luafile < $$CHKSUMS > $$CHKSUMSTMP; \ + if [ -z $$CHKSUMSTMP ]; then \ + echo "Cannot check $$luafile - no checksum known"; \ + else \ + echo Checking integrity of $$luafile with $$shac; \ + $$shac -w --ignore-missing -c $$CHKSUMSTMP < $$luafile; \ + fi; \ fi; \ - tar zxf lua-$(LUA_VERSION).tar.gz && \ - rm -f lua-$(LUA_VERSION).tar.gz; \ + tar zxf $$luafile && \ + rm -f $$luafile; \ fi; \ fi; \ - n=`expr $$n + 1`; \ done; \ true ) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index dfd3473d2..cc4463319 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -7,6 +7,19 @@ objects = { /* Begin PBXBuildFile section */ + 056E43C62C810EE800FD1F52 /* coloratt.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43BC2C810EE800FD1F52 /* coloratt.c */; }; + 056E43C72C810EE800FD1F52 /* nhmd4.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43C02C810EE800FD1F52 /* nhmd4.c */; }; + 056E43C82C810EE800FD1F52 /* Makefile in Sources */ = {isa = PBXBuildFile; fileRef = 056E43BF2C810EE800FD1F52 /* Makefile */; }; + 056E43C92C810EE800FD1F52 /* report.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43C12C810EE800FD1F52 /* report.c */; }; + 056E43CA2C810EE800FD1F52 /* selvar.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43C22C810EE800FD1F52 /* selvar.c */; }; + 056E43CB2C810EE800FD1F52 /* calendar.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43BB2C810EE800FD1F52 /* calendar.c */; }; + 056E43CC2C810EE800FD1F52 /* stairs.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43C32C810EE800FD1F52 /* stairs.c */; }; + 056E43CD2C810EE800FD1F52 /* glyphs.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43BE2C810EE800FD1F52 /* glyphs.c */; }; + 056E43CE2C810EE800FD1F52 /* strutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43C42C810EE800FD1F52 /* strutil.c */; }; + 056E43CF2C810EE800FD1F52 /* getpos.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43BD2C810EE800FD1F52 /* getpos.c */; }; + 056E43D02C810EE800FD1F52 /* wizcmds.c in Sources */ = {isa = PBXBuildFile; fileRef = 056E43C52C810EE800FD1F52 /* wizcmds.c */; }; + 059660BE2C80B00400398EDE /* hacklib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36421A238040055BD01 /* hacklib.c */; }; + 059660C12C80B0C700398EDE /* hacklib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36421A238040055BD01 /* hacklib.c */; }; 31B8A30C21A20D8B0055BD01 /* makedefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A30B21A20D8B0055BD01 /* makedefs.c */; }; 31B8A30F21A20DC10055BD01 /* objects.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A30D21A20DC10055BD01 /* objects.c */; }; 31B8A31021A20DC10055BD01 /* monst.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A30E21A20DC10055BD01 /* monst.c */; }; @@ -244,6 +257,15 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 059660C42C80B15300398EDE /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 3189576F21A1FCC100FB2ABE /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -271,18 +293,20 @@ ); runOnlyForDeploymentPostprocessing = 1; }; - 31B8A45521A26A970055BD01 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 056E43BB2C810EE800FD1F52 /* calendar.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = calendar.c; path = ../../src/calendar.c; sourceTree = ""; }; + 056E43BC2C810EE800FD1F52 /* coloratt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = coloratt.c; path = ../../src/coloratt.c; sourceTree = ""; }; + 056E43BD2C810EE800FD1F52 /* getpos.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = getpos.c; path = ../../src/getpos.c; sourceTree = ""; }; + 056E43BE2C810EE800FD1F52 /* glyphs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = glyphs.c; path = ../../src/glyphs.c; sourceTree = ""; }; + 056E43BF2C810EE800FD1F52 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../src/Makefile; sourceTree = ""; }; + 056E43C02C810EE800FD1F52 /* nhmd4.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = nhmd4.c; path = ../../src/nhmd4.c; sourceTree = ""; }; + 056E43C12C810EE800FD1F52 /* report.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = report.c; path = ../../src/report.c; sourceTree = ""; }; + 056E43C22C810EE800FD1F52 /* selvar.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = selvar.c; path = ../../src/selvar.c; sourceTree = ""; }; + 056E43C32C810EE800FD1F52 /* stairs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = stairs.c; path = ../../src/stairs.c; sourceTree = ""; }; + 056E43C42C810EE800FD1F52 /* strutil.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = strutil.c; path = ../../src/strutil.c; sourceTree = ""; }; + 056E43C52C810EE800FD1F52 /* wizcmds.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = wizcmds.c; path = ../../src/wizcmds.c; sourceTree = ""; }; 2A953FB221A3F404007906E5 /* XCode.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = XCode.xcconfig; sourceTree = ""; }; 3186A36D21A4B0F90052BF02 /* xwindowp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xwindowp.h; path = ../../include/xwindowp.h; sourceTree = ""; }; 3186A36E21A4B0FA0052BF02 /* botl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = botl.h; path = ../../include/botl.h; sourceTree = ""; }; @@ -628,6 +652,17 @@ 3189578C21A1FF8200FB2ABE /* src */ = { isa = PBXGroup; children = ( + 056E43BB2C810EE800FD1F52 /* calendar.c */, + 056E43BC2C810EE800FD1F52 /* coloratt.c */, + 056E43BD2C810EE800FD1F52 /* getpos.c */, + 056E43BE2C810EE800FD1F52 /* glyphs.c */, + 056E43BF2C810EE800FD1F52 /* Makefile */, + 056E43C02C810EE800FD1F52 /* nhmd4.c */, + 056E43C12C810EE800FD1F52 /* report.c */, + 056E43C22C810EE800FD1F52 /* selvar.c */, + 056E43C32C810EE800FD1F52 /* stairs.c */, + 056E43C42C810EE800FD1F52 /* strutil.c */, + 056E43C52C810EE800FD1F52 /* wizcmds.c */, 54A3D3EB282C55A900143F8C /* utf8map.c */, 54435B51247999CB00804CB3 /* nhlobj.c */, 54FB2B4A246310A600397C0E /* symbols.c */, @@ -1022,6 +1057,7 @@ 3189577C21A1FDA400FB2ABE /* Frameworks */, 3189577D21A1FDA400FB2ABE /* CopyFiles */, 317E7C4B21A35F0500F6E4E5 /* Copy makedefs */, + 059660C02C80B07100398EDE /* Codesign makedefs */, 319CBA3821A3458100150830 /* Build data */, 317E7C4521A3548F00F6E4E5 /* Build rumors */, 317E7C4E21A3697300F6E4E5 /* Build options */, @@ -1045,6 +1081,8 @@ 31B8A44621A26A4B0055BD01 /* Sources */, 31B8A44721A26A4B0055BD01 /* Frameworks */, 31B8A44821A26A4B0055BD01 /* CopyFiles */, + 059660C32C80B12300398EDE /* Copy recover */, + 059660C52C80B1A000398EDE /* Codesign recover */, ); buildRules = ( ); @@ -1062,8 +1100,9 @@ buildPhases = ( 31B8A45321A26A970055BD01 /* Sources */, 31B8A45421A26A970055BD01 /* Frameworks */, - 31B8A45521A26A970055BD01 /* CopyFiles */, - 3192867221A3AA5700325BEB /* copy dlb */, + 059660C42C80B15300398EDE /* CopyFiles */, + 3192867221A3AA5700325BEB /* Copy dlb */, + 059660C22C80B0FD00398EDE /* Codesign dlb */, ); buildRules = ( ); @@ -1084,6 +1123,7 @@ BAE8010727B97760002B3786 /* Sources */, BAE8010827B97760002B3786 /* Frameworks */, BAE8010F27B9825E002B3786 /* Build nhlua.h */, + 056E43A42C81094100FD1F52 /* Copy libnhlua.a */, ); buildRules = ( ); @@ -1143,6 +1183,97 @@ /* End PBXProject section */ /* Begin PBXShellScriptBuildPhase section */ + 056E43A42C81094100FD1F52 /* Copy libnhlua.a */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Copy libnhlua.a"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"Copying ${BUILT_PRODUCTS_DIR}/libnhlua.a to ${NH_LIB_DIR}/libnhlua.a\"\ncp \"${BUILT_PRODUCTS_DIR}\"/libnhlua.a \"${NH_LIB_DIR}\"/libnhlua.a\necho \"Copying ${BUILT_PRODUCTS_DIR}/libnhlua.a to ${NH_LIB_DIR}/libnhlua.a\"\ncp \"${BUILT_PRODUCTS_DIR}\"/libnhlua.a \"${NH_LIB_DIR}\"/libnhlua.a\n"; + }; + 059660C02C80B07100398EDE /* Codesign makedefs */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Codesign makedefs"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "codesign --force --deep -s - \"${NH_UTIL_DIR}\"/makedefs\n"; + }; + 059660C22C80B0FD00398EDE /* Codesign dlb */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Codesign dlb"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "codesign --force --deep -s - \"${NH_UTIL_DIR}\"/dlb\n"; + }; + 059660C32C80B12300398EDE /* Copy recover */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Copy recover"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cp \"${BUILT_PRODUCTS_DIR}\"/recover \"${NH_UTIL_DIR}\"/recover\n"; + }; + 059660C52C80B1A000398EDE /* Codesign recover */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Codesign recover"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "codesign --force --deep -s - \"${NH_UTIL_DIR}\"/recover\n"; + }; 317E7C4521A3548F00F6E4E5 /* Build rumors */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1466,7 +1597,7 @@ shellPath = /bin/sh; shellScript = "cp \"${BUILT_PRODUCTS_DIR}\"/nethack \"${NH_SRC_DIR}\"/nethack\n"; }; - 3192867221A3AA5700325BEB /* copy dlb */ = { + 3192867221A3AA5700325BEB /* Copy dlb */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1476,7 +1607,7 @@ inputPaths = ( "${BUILT_PRODUCTS_DIR}/dlb", ); - name = "copy dlb"; + name = "Copy dlb"; outputFileListPaths = ( ); outputPaths = ( @@ -1545,7 +1676,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "cd $NH_ROOT_DIR\necho LUA VERSION: $LUA_VERSION\nif test ! -d lib/lua-$LUA_VERSION ; then ( echo \"Fetching $LUA_VERSION\" && \\\n mkdir -p lib && cd lib && \\\n curl -s -S -R -O http://www.lua.org/ftp/lua-$LUA_VERSION.tar.gz && \\\n tar zxf lua-$LUA_VERSION.tar.gz && \\\n rm -f lua-$LUA_VERSION.tar.gz ) ; fi\n"; + shellScript = "cd $NH_ROOT_DIR\necho LUA VERSION: $LUA_VERSION\nif test ! -d lib/lua-$LUA_VERSION ; then ( echo \"Fetching $LUA_VERSION\" && \\\n mkdir -p lib && cd lib && \\\n curl -s -S -R -O https://www.lua.org/ftp/lua-$LUA_VERSION.tar.gz && \\\n tar zxf lua-$LUA_VERSION.tar.gz && \\\n rm -f lua-$LUA_VERSION.tar.gz ) ; fi\n"; }; BAE8010F27B9825E002B3786 /* Build nhlua.h */ = { isa = PBXShellScriptBuildPhase; @@ -1616,6 +1747,17 @@ 31B8A3CB21A238060055BD01 /* alloc.c in Sources */, 31B8A39821A238060055BD01 /* mail.c in Sources */, 31B8A3C821A238060055BD01 /* options.c in Sources */, + 056E43C62C810EE800FD1F52 /* coloratt.c in Sources */, + 056E43C72C810EE800FD1F52 /* nhmd4.c in Sources */, + 056E43C82C810EE800FD1F52 /* Makefile in Sources */, + 056E43C92C810EE800FD1F52 /* report.c in Sources */, + 056E43CA2C810EE800FD1F52 /* selvar.c in Sources */, + 056E43CB2C810EE800FD1F52 /* calendar.c in Sources */, + 056E43CC2C810EE800FD1F52 /* stairs.c in Sources */, + 056E43CD2C810EE800FD1F52 /* glyphs.c in Sources */, + 056E43CE2C810EE800FD1F52 /* strutil.c in Sources */, + 056E43CF2C810EE800FD1F52 /* getpos.c in Sources */, + 056E43D02C810EE800FD1F52 /* wizcmds.c in Sources */, 31B8A3CD21A238060055BD01 /* write.c in Sources */, 31B8A40F21A23EEC0055BD01 /* cursmesg.c in Sources */, 31B8A3DF21A238060055BD01 /* end.c in Sources */, @@ -1716,6 +1858,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 059660BE2C80B00400398EDE /* hacklib.c in Sources */, 544A5CF0277B40CF00734B53 /* panic.c in Sources */, 5493735A277AAE830031FE02 /* alloc.c in Sources */, 5439B3BC275AADC600B8FB2F /* date.c in Sources */, @@ -1737,6 +1880,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 059660C12C80B0C700398EDE /* hacklib.c in Sources */, 31B8A46121A26AF60055BD01 /* panic.c in Sources */, 31B8A45E21A26ACF0055BD01 /* dlb.c in Sources */, 31B8A46021A26AE70055BD01 /* dlb_main.c in Sources */, @@ -2003,6 +2147,23 @@ GCC_C_LANGUAGE_STANDARD = c99; INSTALL_PATH = "$(NH_INSTALL_DIR)"; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; + OTHER_CFLAGS = ( + "-DNOMAIL", + "-DNOTPARMDECL", + "-DDEFAULT_WINDOW_SYS=\\\"tty\\\"", + "-DDLB", + "-DGREPPATH=\\\"/usr/bin/grep\\\"", + "-DSYSCF", + "-DSYSCF_FILE=\\\"$(NH_INSTALL_DIR)/sysconf\\\"", + "-DHACKDIR=\\\"$(NH_INSTALL_DIR)\\\"", + "-DSECURE", + "-DCURSES_GRAPHICS", + "-DSND_LIB_MACSOUND", + "-DSND_SOUNDEFFECTS_AUTOMAP", + "-DUSER_SOUNDS", + "-DCURSES_UNICODE", + "-D_XOPEN_SOURCE_EXTENDED", + ); "OTHER_LDFLAGS[arch=*]" = "-L${NH_LIB_DIR}/lua"; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -2017,6 +2178,20 @@ GCC_C_LANGUAGE_STANDARD = c99; INSTALL_PATH = "$(NH_INSTALL_DIR)"; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; + OTHER_CFLAGS = ( + "-DNOMAIL", + "-DNOTPARMDECL", + "-DDEFAULT_WINDOW_SYS=\\\"tty\\\"", + "-DDLB", + "-DGREPPATH=\\\"/usr/bin/grep\\\"", + "-DSYSCF", + "-DSYSCF_FILE=\\\"$(NH_INSTALL_DIR)/sysconf\\\"", + "-DHACKDIR=\\\"$(NH_INSTALL_DIR)\\\"", + "-DSECURE", + "-DCURSES_GRAPHICS", + "-DCURSES_UNICODE", + "-D_XOPEN_SOURCE_EXTENDED", + ); "OTHER_LDFLAGS[arch=*]" = "-L${NH_LIB_DIR}/lua"; PRODUCT_NAME = "$(TARGET_NAME)"; }; diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index f8106995a..557b3504a 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -82,10 +82,10 @@ dodata: endif # CROSS_TO_MSDOS ifdef CROSS_TO_WASM -$(WASM_TARGET): pregame $(TARGETPFX)date.o $(HOSTOBJ) $(HOBJ) $(LUACROSSLIB) $(WASM_DATA_DIR) +$(WASM_TARGET): pregame $(TARGET_HACKLIB) $(TARGETPFX)date.o $(HOSTOBJ) $(HOBJ) $(LUACROSSLIB) $(WASM_DATA_DIR) -rm $@ $(TARGET_CC) $(TARGET_LFLAGS) $(TARGET_CFLAGS) -o $@ \ - $(HOBJ) $(TARGETPFX)date.o $(TARGET_LIBS) + $(HOBJ) $(TARGETPFX)date.o $(TARGET_HACKLIB) $(TARGET_LIBS) $(WASM_DATA_DIR): $(WASM_DATA_DIR)/nhdat touch $(WASM_DATA_DIR)/perm diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index 55294e286..fa5f0911c 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -275,7 +275,8 @@ WASM_CFLAGS += -Wshadow # Nethack C flags WASM_CFLAGS += $(WINCFLAGS) #WINCFLAGS set from multiw-2.370 WASM_CFLAGS += -DSYSCF -DSYSCF_FILE=\"/sysconf\" -DSECURE -WASM_CFLAGS += -g -I../include -DNOTPARMDECL +#WASM_CFLAGS += -g -I../include -DNOTPARMDECL +WASM_CFLAGS += -I../include -DNOTPARMDECL # NetHack sources control WASM_CFLAGS += -DDLB WASM_CFLAGS += -DHACKDIR=\"$(HACKDIR)\" diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 1a22fd96a..679f5e627 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -99,7 +99,7 @@ main(int argc, char *argv[]) #endif gh.hname = argv[0]; - gh.hackpid = getpid(); + svh.hackpid = getpid(); (void) umask(0777 & ~FCMASK); choose_windows(DEFAULT_WINDOW_SYS); @@ -164,7 +164,7 @@ main(int argc, char *argv[]) */ u.uhp = 1; /* prevent RIP on early quits */ #if defined(HANGUPHANDLING) - gp.program_state.preserve_locks = 1; + program_state.preserve_locks = 1; #ifndef NO_SIGNAL sethanguphandler((SIG_RET_TYPE) hangup); #endif @@ -195,7 +195,7 @@ main(int argc, char *argv[]) /* wizard mode access is deferred until here */ set_playmode(); /* sets plname to "wizard" for wizard mode */ /* hide any hyphens from plnamesuffix() */ - gp.plnamelen = exact_username ? (int) strlen(gp.plname) : 0; + gp.plnamelen = exact_username ? (int) strlen(svp.plname) : 0; /* strip role,race,&c suffix; calls askname() if plname[] is empty or holds a generic user name like "player" or "games" */ plnamesuffix(); @@ -236,14 +236,14 @@ main(int argc, char *argv[]) * clock, &c not currently in use in the playground directory * (for gl.locknum > 0). */ - if (*gp.plname) { + if (*svp.plname) { getlock(); #if defined(HANGUPHANDLING) - gp.program_state.preserve_locks = 0; /* after getlock() */ + program_state.preserve_locks = 0; /* after getlock() */ #endif } - if (*gp.plname && (nhfp = restore_saved_game()) != 0) { + if (*svp.plname && (nhfp = restore_saved_game()) != 0) { const char *fq_save = fqname(gs.SAVEF, SAVEPREFIX, 1); (void) chmod(fq_save, 0); /* disallow parallel restores */ @@ -276,13 +276,13 @@ main(int argc, char *argv[]) } } } - if (gp.program_state.in_self_recover) { - gp.program_state.in_self_recover = FALSE; + if (program_state.in_self_recover) { + program_state.in_self_recover = FALSE; } } if (!resuming) { - boolean neednewlock = (!*gp.plname); + boolean neednewlock = (!*svp.plname); /* new game: start by choosing role, race, etc; player might change the hero's name while doing that, in which case we try to restore under the new name @@ -291,7 +291,7 @@ main(int argc, char *argv[]) if (!plsel_once) player_selection(); plsel_once = TRUE; - if (neednewlock && *gp.plname) + if (neednewlock && *svp.plname) goto attempt_restore; if (iflags.renameinprogress) { /* player has renamed the hero while selecting role; @@ -474,12 +474,12 @@ process_options(int argc, char *argv[]) break; case 'u': if (arg[2]) { - (void) strncpy(gp.plname, arg + 2, sizeof gp.plname - 1); + (void) strncpy(svp.plname, arg + 2, sizeof svp.plname - 1); gp.plnamelen = 0; /* plname[] might have -role-race attached */ } else if (argc > 1) { argc--; argv++; - (void) strncpy(gp.plname, argv[0], sizeof gp.plname - 1); + (void) strncpy(svp.plname, argv[0], sizeof svp.plname - 1); gp.plnamelen = 0; } else { config_error_add("Character name expected after -u"); @@ -916,7 +916,7 @@ whoami(void) * Note that we trust the user here; it is possible to play under * somebody else's name. */ - if (!*gp.plname) { + if (!*svp.plname) { register const char *s; s = nh_getenv("USER"); @@ -926,8 +926,8 @@ whoami(void) s = getlogin(); if (s && *s) { - (void) strncpy(gp.plname, s, sizeof gp.plname - 1); - if (strchr(gp.plname, '-')) + (void) strncpy(svp.plname, s, sizeof svp.plname - 1); + if (strchr(svp.plname, '-')) return TRUE; } } @@ -1052,7 +1052,7 @@ check_user_string(const char *optstr) if (optstr[0] == '*') return TRUE; /* allow any user */ if (sysopt.check_plname) - pwname = gp.plname; + pwname = svp.plname; else if ((pw = get_unix_pw()) != 0) pwname = pw->pw_name; if (!pwname || !*pwname) diff --git a/sys/unix/unixunix.c b/sys/unix/unixunix.c index de465f9b1..8450da5f8 100644 --- a/sys/unix/unixunix.c +++ b/sys/unix/unixunix.c @@ -82,7 +82,7 @@ eraseoldlocks(void) int i; #if defined(HANGUPHANDLING) - gp.program_state.preserve_locks = 0; /* not required but shows intent */ + program_state.preserve_locks = 0; /* not required but shows intent */ /* cannot use maxledgerno() here, because we need to find a lock name * before starting everything (including the dungeon initialization * that sets astral_level, needed for maxledgerno()) up @@ -132,7 +132,7 @@ getlock(void) 'a','b',&c below; override the default and use if we aren't restricting the number of simultaneous games */ if (!gl.locknum) - Sprintf(gl.lock, "%u%s", (unsigned) getuid(), gp.plname); + Sprintf(gl.lock, "%u%s", (unsigned) getuid(), svp.plname); regularize(gl.lock); set_levelfile_name(gl.lock, 0); @@ -216,7 +216,7 @@ getlock(void) } #ifdef SELF_RECOVER if (c == 'r' || c == 'R') { - if (recover_savefile() && gp.program_state.in_self_recover) { + if (recover_savefile() && program_state.in_self_recover) { set_levelfile_name(gl.lock, 0); fq_lock = fqname(gl.lock, LEVELPREFIX, 0); goto gotlock; @@ -246,8 +246,8 @@ getlock(void) error("cannot creat lock file (%s).", fq_lock); /*NOTREACHED*/ } else { - if (write(fd, (genericptr_t) &gh.hackpid, sizeof gh.hackpid) - != sizeof gh.hackpid) { + if (write(fd, (genericptr_t) &svh.hackpid, sizeof svh.hackpid) + != sizeof svh.hackpid) { error("cannot write lock (%s)", fq_lock); /*NOTREACHED*/ } diff --git a/sys/vms/vmsmain.c b/sys/vms/vmsmain.c index 91f9817ff..dcb681caa 100644 --- a/sys/vms/vmsmain.c +++ b/sys/vms/vmsmain.c @@ -58,7 +58,7 @@ main(int argc, char *argv[]) isn't at risk of getting clobbered by core's handling of DEBUGFILES */ progname = dupstr(vms_basename(argv[0], FALSE)); gh.hname = progname; - gh.hackpid = getpid(); + svh.hackpid = getpid(); (void) umask(0); choose_windows(DEFAULT_WINDOW_SYS); @@ -281,11 +281,11 @@ process_options(int argc, char *argv[]) #endif case 'u': if (argv[0][2]) - (void) strncpy(gp.plname, argv[0] + 2, sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, argv[0] + 2, sizeof(svp.plname) - 1); else if (argc > 1) { argc--; argv++; - (void) strncpy(gp.plname, argv[0], sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, argv[0], sizeof(svp.plname) - 1); } else raw_print("Player name expected after -u"); break; @@ -390,8 +390,8 @@ whoami(void) */ char *s; - if (!*gp.plname && (s = nh_getenv("USER"))) - (void) lcase(strncpy(gp.plname, s, sizeof(gp.plname) - 1)); + if (!*svp.plname && (s = nh_getenv("USER"))) + (void) lcase(strncpy(svp.plname, s, sizeof(svp.plname) - 1)); } static void @@ -412,7 +412,7 @@ byebye(void) (void) sys$delprc(&mail_pid, (genericptr_t) 0), mail_pid = 0; #endif #ifdef FREE_ALL_MEMORY - if (progname && !gp.program_state.panicking) { + if (progname && !program_state.panicking) { if (gh.hname == progname) gh.hname = (char *) 0; free((genericptr_t) progname), progname = (char *) 0; @@ -421,7 +421,7 @@ byebye(void) /* SIGHUP doesn't seem to do anything on VMS, so we fudge it here... */ hup = (void (*)(int)) signal(SIGHUP, SIG_IGN); - if (!gp.program_state.exiting++ + if (!program_state.exiting++ && hup != (void (*)(int)) SIG_DFL && hup != (void (*)(int)) SIG_IGN) { (*hup)(SIGHUP); @@ -446,7 +446,7 @@ genericptr_t mechargs) /* [0] is argc, [1..argc] are the real args */ if (condition == SS$_ACCVIO /* access violation */ || (condition >= SS$_ASTFLT && condition <= SS$_TBIT) || (condition >= SS$_ARTRES && condition <= SS$_INHCHME)) { - gp.program_state.done_hup = TRUE; /* pretend hangup has been attempted */ + program_state.done_hup = TRUE; /* pretend hangup has been attempted */ #if (NH_DEVEL_STATUS == NH_STATUS_RELEASED) if (wizard) #endif diff --git a/sys/vms/vmstty.c b/sys/vms/vmstty.c index 8dc0dfe4f..9bd26a9a5 100644 --- a/sys/vms/vmstty.c +++ b/sys/vms/vmstty.c @@ -158,7 +158,7 @@ vms_getchar(void) static volatile int recurse = 0; /* SMG is not AST re-entrant! */ #endif - if (gp.program_state.done_hup) { + if (program_state.done_hup) { /* hangup has occurred; do not attempt to get further user input */ return ESC; } diff --git a/sys/vms/vmsunix.c b/sys/vms/vmsunix.c index de147bf96..69e5a3929 100644 --- a/sys/vms/vmsunix.c +++ b/sys/vms/vmsunix.c @@ -120,7 +120,7 @@ getlock(void) 'a','b',&c below; override the default and use if we aren't restricting the number of simultaneous games */ if (!gl.locknum) - Sprintf(gl.lock, "_%u%s", (unsigned) getuid(), gp.plname); + Sprintf(gl.lock, "_%u%s", (unsigned) getuid(), svp.plname); regularize(gl.lock); set_levelfile_name(gl.lock, 0); @@ -154,8 +154,8 @@ getlock(void) if (fd == -1) { error("cannot creat lock file."); } else { - if (write(fd, (char *) &gh.hackpid, sizeof(gh.hackpid)) - != sizeof(gh.hackpid)) { + if (write(fd, (char *) &svh.hackpid, sizeof(svh.hackpid)) + != sizeof(svh.hackpid)) { error("cannot write lock"); } if (close(fd) == -1) { diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index d739c2528..0fd85885d 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -8,8 +8,8 @@ # MS Visual Studio Visual C++ compiler # # Visual Studio Compilers Tested: -# - Microsoft Visual Studio 2019 Community Edition v 16.11.37 -# - Microsoft Visual Studio 2022 Community Edition v 17.10.2 +# - Microsoft Visual Studio 2019 Community Edition v 16.11.38 +# - Microsoft Visual Studio 2022 Community Edition v 17.11.2 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -989,7 +989,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30154.0 -TESTEDVS2022 = 14.40.33811.0 +TESTEDVS2022 = 14.41.34120.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) diff --git a/sys/windows/build-msys2.txt b/sys/windows/build-msys2.txt index 3676b2679..c9efc6859 100644 --- a/sys/windows/build-msys2.txt +++ b/sys/windows/build-msys2.txt @@ -4,30 +4,16 @@ Prerequisite Requirements: o MSYS2 - https://www.msys2.org/ - - Download the installer, and start the UCRT64 shell. + - Download and run the installer, and start the UCRT64 shell. then pacman -S mingw-w64-ucrt-x86_64-gcc pacman -S git + pacman -S make pacman -S vim (or your editor of choice) pacman -S man (otherwise "git help foo" will not work) o Lua - NetHack 3.7 for Windows requires 3rd party Lua source that is not part - of the NetHack distribution or repository. - - A windows cmd command procedure for fetching prerequisite sources - is available, and can be run as follows from the top of the - NetHack source tree to obtain lua: - sys\windows\fetch.cmd lua o pdcursesmod (Only required if curses interface support is desired) - If you want to include curses interface support in NetHack 3.7 for - 3rd part pdcursesmod source code is required and is not part of the - NetHack distribution or repository. - - A windows cmd command procedure for fetching prerequisite - sources is available, and can be run as follows from the top of - the NetHack source tree to obtain pdcursesmod: - sys\windows\fetch.cmd pdcursesmod - + Instructions for obtaining these are later in this file. /---------------------------------------------\ | Directories for a Windows NetHack build | @@ -81,23 +67,22 @@ Building Two different versions of NetHack will be built for Windows from the command line using the Makefile approach: A tty port utilizing the Win32 Console I/O subsystem Console, - and a curses interface in an executabled called NetHack.exe. - NetHack + and a curses interface in an executable called NetHack.exe. + A Win32 native port built on the Windows API Graphical NetHack, and graphical curses in an executable called NetHackW.exe. -The Makefile configurations will build both; NetHack.exe and NetHackW.exe +The Makefile configurations will build both NetHack.exe and NetHackW.exe and will be able to use the same datafiles, save files and bones files. Since the last official release of NetHack, compilers and computer architectures have evolved and you can now choose whether to build a 32-bit x86 version, or a 64-bit x64 version. The default Makefile is set up for a 32-bit x86 version, but that's only because it will -run on the most number of existing Windows environments. Change it if you +run on the largest number of existing Windows environments. Change it if you want. Be aware that NetHack's save files and bones files in the 3.7.0 -release have not yet evolved enough to allow them to interchange between -the 32-bit version and the 64-bit version (or between different platforms). -That may change in future. +release are not interchangeable between the 32-bit version and the +64-bit version (or between different platforms). I. Dispelling the Myths: @@ -147,7 +132,7 @@ Notes: 1. To rebuild NetHack after changing something, change your current directory to src and issue the appropriate command for your compiler: - For Microsoft compiler: + For gcc: make -f Makefile.mingw32 2. An alternative to MSYS2 may be MinGW-w64 - winlibs standalone build. diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index e430033ce..770c0f19b 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -936,7 +936,7 @@ void buffer_fill_to_end(cell_t * buffer, cell_t * fill, int x, int y) while (dst != sentinel) *dst++ = *fill; - if ((iflags.debug.immediateflips || !gp.program_state.in_moveloop) + if ((iflags.debug.immediateflips || !program_state.in_moveloop) && buffer == console.back_buffer) back_buffer_flip(); } @@ -952,7 +952,7 @@ static void buffer_clear_to_end_of_line(cell_t * buffer, int x, int y) while (dst != sentinel) *dst++ = clear_cell; - if (iflags.debug.immediateflips || !gp.program_state.in_moveloop) + if (iflags.debug.immediateflips || !program_state.in_moveloop) back_buffer_flip(); } @@ -964,7 +964,7 @@ void buffer_write(cell_t * buffer, cell_t * cell, COORD pos) cell_t * dst = buffer + (console.width * pos.Y) + pos.X; *dst = *cell; - if ((iflags.debug.immediateflips || !gp.program_state.in_moveloop) + if ((iflags.debug.immediateflips || !program_state.in_moveloop) && buffer == console.back_buffer) back_buffer_flip(); } @@ -1149,7 +1149,7 @@ tgetch(void) numpad |= 0x10; #endif - return (gp.program_state.done_hup) + return (program_state.done_hup) ? '\033' : keyboard_handling.pCheckInput( console.hConIn, &ir, &count, numpad, 0, &mod, &cc); @@ -1177,7 +1177,7 @@ console_poskey(coordxy *x, coordxy *y, int *mod) if (gc.Cmd.swap_yz) numpad |= 0x10; #endif - ch = (gp.program_state.done_hup) + ch = (program_state.done_hup) ? '\033' : keyboard_handling.pCheckInput( console.hConIn, &ir, &count, numpad, 1, mod, &cc); diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 5c928db86..efa09ebb9 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -704,17 +704,17 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ (*utf8graphics_mode_callback)(); #endif - /* strip role,race,&c suffix; calls askname() if gp.plname[] is empty + /* strip role,race,&c suffix; calls askname() if svp.plname[] is empty or holds a generic user name like "player" or "games" */ plnamesuffix(); - set_playmode(); /* sets gp.plname to "wizard" for wizard mode */ + set_playmode(); /* sets svp.plname to "wizard" for wizard mode */ /* until the getlock code is resolved, override askname()'s setting of renameallowed; when False, player_selection() won't resent renaming as an option */ iflags.renameallowed = FALSE; /* Obtain the name of the logged on user and incorporate * it into the name. */ - Sprintf(fnamebuf, "%s", gp.plname); + Sprintf(fnamebuf, "%s", svp.plname); (void) fname_encode( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%', fnamebuf, encodedfnamebuf, BUFSZ); @@ -732,8 +732,8 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ if (!nhfp) { raw_print("Cannot create lock file"); } else { - gh.hackpid = GetCurrentProcessId(); - (void) write(nhfp->fd, (genericptr_t) &gh.hackpid, sizeof(gh.hackpid)); + svh.hackpid = GetCurrentProcessId(); + (void) write(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof(svh.hackpid)); close_nhfile(nhfp); } /* @@ -771,8 +771,8 @@ attempt_restore: } } } - if (gp.program_state.in_self_recover) { - gp.program_state.in_self_recover = FALSE; + if (program_state.in_self_recover) { + program_state.in_self_recover = FALSE; set_savefile_name(TRUE); } } @@ -923,11 +923,11 @@ process_options(int argc, char * argv[]) #endif case 'u': if (argv[0][2]) - (void) strncpy(gp.plname, argv[0] + 2, sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, argv[0] + 2, sizeof(svp.plname) - 1); else if (argc > 1) { argc--; argv++; - (void) strncpy(gp.plname, argv[0], sizeof(gp.plname) - 1); + (void) strncpy(svp.plname, argv[0], sizeof(svp.plname) - 1); } else raw_print("Player name expected after -u"); break; @@ -1052,7 +1052,7 @@ port_help(void) boolean authorize_wizard_mode(void) { - if (!strcmp(gp.plname, WIZARD_NAME)) + if (!strcmp(svp.plname, WIZARD_NAME)) return TRUE; return FALSE; } @@ -1417,8 +1417,8 @@ gotlock: gf.fqn_prefix[LEVELPREFIX]); raw_print(oops); } else { - if (write(fd, (char *) &gh.hackpid, sizeof(gh.hackpid)) - != sizeof(gh.hackpid)) { + if (write(fd, (char *) &svh.hackpid, sizeof(svh.hackpid)) + != sizeof(svh.hackpid)) { #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp index e1d5324b6..d0128cc62 100644 --- a/win/Qt/qt_bind.cpp +++ b/win/Qt/qt_bind.cpp @@ -237,7 +237,7 @@ void NetHackQtBind::qt_askname() int ch = -1; // -1 => new game have_asked = true; - str_copy(default_plname, gp.plname, PL_NSIZ); + str_copy(default_plname, svp.plname, PL_NSIZ); // We do it all here (plus qt_plsel.cpp and qt_svsel.cpp), // nothing in player_selection(). @@ -252,7 +252,7 @@ void NetHackQtBind::qt_askname() NetHackQtSavedGameSelector sgsel((const char **) saved); ch = sgsel.choose(); if (ch >= 0) - str_copy(gp.plname, saved[ch], SIZE(gp.plname)); + str_copy(svp.plname, saved[ch], SIZE(svp.plname)); // caller needs new lock name even if plname[] hasn't changed // because successful get_saved_games() clobbers gs.SAVEF[] ::iflags.renameinprogress = TRUE; @@ -282,10 +282,10 @@ void NetHackQtBind::qt_askname() break; } - if (!*gp.plname) + if (!*svp.plname) // in case Choose() returns with plname[] empty - Strcpy(gp.plname, default_plname); - else if (strcmp(gp.plname, default_plname) != 0) + Strcpy(svp.plname, default_plname); + else if (strcmp(svp.plname, default_plname) != 0) // caller needs to set new lock file name ::iflags.renameinprogress = TRUE; return; @@ -498,7 +498,7 @@ void NetHackQtBind::qt_update_inventory(int arg UNUSED) main->updateInventory(); // update the paper doll inventory subset /* doesn't work yet - if (gp.program_state.something_worth_saving && iflags.perm_invent) + if (program_state.something_worth_saving && iflags.perm_invent) display_inventory(NULL, false); */ } @@ -667,7 +667,7 @@ char NetHackQtBind::qt_more() // ^C comment in that routine] when the core triggers --More-- via // done2() -> really_done() -> display_nhwindow(WIN_MESSAGE, TRUE) // (get rid of this if the exec() loop issue gets properly fixed) - if (::gp.program_state.gameover) + if (::program_state.gameover) return ch; // bypass --More-- and just continue with program exit NetHackQtMessageWindow *mesgwin = main ? main->GetMessageWindow() : NULL; diff --git a/win/Qt/qt_main.cpp b/win/Qt/qt_main.cpp index 394b8ec5e..73bade00f 100644 --- a/win/Qt/qt_main.cpp +++ b/win/Qt/qt_main.cpp @@ -1015,7 +1015,7 @@ bool NetHackQtMainWindow::ok_for_command() * FIXME: it would be much better to gray-out inapplicable entries * when popping up a command menu instead of needing this. */ - if (::gp.program_state.input_state != commandInp) { + if (::program_state.input_state != commandInp) { NetHackQtBind::qt_nhbell(); // possibly call doKeys("\033"); here? return false; @@ -1059,7 +1059,7 @@ void NetHackQtMainWindow::doQuit(bool) // in case someone wants to change that #ifdef MACOS QString info = nh_qsprintf("This will end your NetHack session.%s", - !gp.program_state.something_worth_saving ? "" + !program_state.something_worth_saving ? "" : "\n(Cancel quitting and use the Save command" "\nto save your current game.)"); /* this is similar to closeEvent but the details are different; @@ -1077,7 +1077,7 @@ void NetHackQtMainWindow::doQuit(bool) break; // return to game case 1: // quit -- bypass the prompting preformed by done2() - gp.program_state.stopprint++; + program_state.stopprint++; ::done(QUIT); /*NOTREACHED*/ break; @@ -1406,7 +1406,7 @@ void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event) void NetHackQtMainWindow::closeEvent(QCloseEvent *e UNUSED) { int ok = 0; - if ( gp.program_state.something_worth_saving ) { + if ( program_state.something_worth_saving ) { /* this used to offer "Save" and "Cancel" but cancel (ignoring the close attempt) won't work if user has clicked on the window's Close button */ @@ -1421,7 +1421,7 @@ void NetHackQtMainWindow::closeEvent(QCloseEvent *e UNUSED) case 1: // quit -- bypass the prompting preformed by done2() ok = 1; - gp.program_state.stopprint++; + program_state.stopprint++; ::done(QUIT); /*NOTREACHED*/ break; diff --git a/win/Qt/qt_menu.cpp b/win/Qt/qt_menu.cpp index f7480ecbc..6a0e7a524 100644 --- a/win/Qt/qt_menu.cpp +++ b/win/Qt/qt_menu.cpp @@ -1071,7 +1071,7 @@ void NetHackQtTextWindow::UseRIP(int how, time_t when) /* Put name on stone */ (void) snprintf(rip_line[NAME_LINE], STONE_LINE_LEN + 1, - "%.*s", STONE_LINE_LEN, gp.plname); + "%.*s", STONE_LINE_LEN, svp.plname); /* Put $ on stone; to keep things safe and relatively simple, impose an arbitrary diff --git a/win/Qt/qt_plsel.cpp b/win/Qt/qt_plsel.cpp index ecc81023b..a280f07fc 100644 --- a/win/Qt/qt_plsel.cpp +++ b/win/Qt/qt_plsel.cpp @@ -40,17 +40,17 @@ extern "C" { /* check whether plname[] is among the list of generic user names */ static bool generic_plname() { - if (*gp.plname) { + if (*svp.plname) { const char *sptr, *p; const char *genericusers = sysopt.genericusers; - int ln = (int) strlen(gp.plname); + int ln = (int) strlen(svp.plname); if (!genericusers || !*genericusers) genericusers = "player games"; else if (!strcmp(genericusers, "*")) /* "*" => always ask for name */ return true; - while ((sptr = strstri(genericusers, gp.plname)) != NULL) { + while ((sptr = strstri(genericusers, svp.plname)) != NULL) { /* check for full word: start of list or following a space */ if ((sptr == genericusers || sptr[-1] == ' ') /* and also preceding a space or at end of list */ @@ -263,8 +263,8 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector( // if plname[] contains a generic user name, clear it if (generic_plname()) - *gp.plname = '\0'; - name->setText(gp.plname); + *svp.plname = '\0'; + name->setText(svp.plname); connect(name, SIGNAL(textChanged(const QString&)), this, SLOT(selectName(const QString&))); name->setFocus(); @@ -545,7 +545,7 @@ void NetHackQtPlayerSelector::Randomize() // if plname[] is empty, disable [Play], otherwise [Play] is the default void NetHackQtPlayerSelector::plnamePlayVsQuit() { - if (*gp.plname) { + if (*svp.plname) { play_btn->setEnabled(true); play_btn->setDefault(true); //quit_btn->setDefault(false); @@ -564,7 +564,7 @@ void NetHackQtPlayerSelector::selectName(const QString& n) // (it would be better to set up a validator that rejects leading spaces) while (*name_str == ' ') ++name_str; - str_copy(gp.plname, name_str, PL_NSIZ); + str_copy(svp.plname, name_str, PL_NSIZ); // possibly enable or disable the [Play] button plnamePlayVsQuit(); } diff --git a/win/Qt/qt_stat.cpp b/win/Qt/qt_stat.cpp index 34dc3e2d1..13aae4108 100644 --- a/win/Qt/qt_stat.cpp +++ b/win/Qt/qt_stat.cpp @@ -858,17 +858,17 @@ void NetHackQtStatusWindow::updateStats() buf = nh_capitalize_words(pmname(&mons[u.umonnum], ::flags.female ? FEMALE : MALE)); } else { - buf = rank_of(u.ulevel, gp.pl_character[0], ::flags.female); + buf = rank_of(u.ulevel, svp.pl_character[0], ::flags.female); } QString buf2; char buf3[BUFSZ]; - buf2 = nh_qsprintf("%s the %s", upstart(strcpy(buf3, gp.plname)), + buf2 = nh_qsprintf("%s the %s", upstart(strcpy(buf3, svp.plname)), buf.toLatin1().constData()); name.setLabel(buf2, NetHackQtLabelledIcon::NoNum, u.ulevel); if (!describe_level(buf3, 0)) { Sprintf(buf3, "%s, level %d", - gd.dungeons[u.uz.dnum].dname, ::depth(&u.uz)); + svd.dungeons[u.uz.dnum].dname, ::depth(&u.uz)); } dlevel.setLabel(buf3); @@ -966,7 +966,7 @@ void NetHackQtStatusWindow::updateStats() if (::flags.time) { // hypothetically Time could grow to enough digits to have trouble // fitting, but it's not worth worrying about - time.setLabel("Time:", (long) gm.moves); + time.setLabel("Time:", (long) svm.moves); } else { time.setLabel(""); } diff --git a/win/Qt/qt_yndlg.cpp b/win/Qt/qt_yndlg.cpp index 4dc355cbc..57e2f212f 100644 --- a/win/Qt/qt_yndlg.cpp +++ b/win/Qt/qt_yndlg.cpp @@ -220,7 +220,7 @@ char NetHackQtYnDialog::Exec() // for "ynaq" (where "all" is a choice) it's "stop" // and for end of game disclosure it really is "quit" if (question.left(10) == QString("Dump core?") - || (::gp.program_state.gameover + || (::program_state.gameover && question.left(11) == QString("Do you want"))) button_name = "Quit"; else if (is_ynaq) diff --git a/win/X11/winX.c b/win/X11/winX.c index 8daf610ef..f808541d5 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -1282,7 +1282,7 @@ X11_update_inventory(int arg) if (iflags.perm_invent) { /* skip any calls to update_inventory() before in_moveloop starts */ - if (gp.program_state.in_moveloop || gp.program_state.gameover) { + if (program_state.in_moveloop || program_state.gameover) { updated_inventory = 1; /* hack to avoid mapping&raising window */ if (!arg) { (void) display_inventory((char *) 0, FALSE); @@ -1798,7 +1798,7 @@ X11_hangup(Widget w, XEvent *event, String *params, Cardinal *num_params) static void X11_bail(const char *mesg) { - gp.program_state.something_worth_saving = 0; + program_state.something_worth_saving = 0; clearlocks(); X11_exit_nhwindows(mesg); nh_terminate(EXIT_SUCCESS); @@ -1815,7 +1815,7 @@ askname_delete(Widget w, XEvent *event, String *params, Cardinal *num_params) nhUse(num_params); nh_XtPopdown(w); - (void) strcpy(gp.plname, "Mumbles"); /* give them a name... ;-) */ + (void) strcpy(svp.plname, "Mumbles"); /* give them a name... ;-) */ exit_x_event = TRUE; } @@ -1840,11 +1840,11 @@ askname_done(Widget w, XtPointer client_data, XtPointer call_data) } /* Truncate name if necessary */ - if (len >= sizeof gp.plname - 1) - len = sizeof gp.plname - 1; + if (len >= sizeof svp.plname - 1) + len = sizeof svp.plname - 1; - (void) strncpy(gp.plname, s, len); - gp.plname[len] = '\0'; + (void) strncpy(svp.plname, s, len); + svp.plname[len] = '\0'; XtFree(s); nh_XtPopdown(XtParent(dialog)); @@ -1892,7 +1892,7 @@ X11_askname(void) (XtCallbackProc) 0); SetDialogPrompt(dialog, nhStr("What is your name?")); /* set prompt */ - SetDialogResponse(dialog, gp.plname, PL_NSIZ); /* set default answer */ + SetDialogResponse(dialog, svp.plname, PL_NSIZ); /* set default answer */ XtRealizeWidget(popup); positionpopup(popup, TRUE); /* center,bottom */ @@ -2041,7 +2041,7 @@ X11_getlin( /* we get here after the popup has exited; put prompt and response into the message window (and into core's dumplog history) unless play hasn't started yet */ - if (gp.program_state.in_moveloop || gp.program_state.gameover) { + if (program_state.in_moveloop || program_state.gameover) { /* single space has meaning (to remove a previously applied name) so show it clearly; don't care about legibility of multiple spaces */ const char *visanswer = !input[0] ? "" diff --git a/win/X11/winmap.c b/win/X11/winmap.c index 110cc8953..d27f0ac88 100644 --- a/win/X11/winmap.c +++ b/win/X11/winmap.c @@ -1988,7 +1988,7 @@ x_event(int exit_condition) /* pkey(retval); */ keep_going = FALSE; #if defined(HANGUPHANDLING) - } else if (gp.program_state.done_hup) { + } else if (program_state.done_hup) { retval = '\033'; inptr = (inptr + 1) % INBUF_SIZE; keep_going = FALSE; @@ -2009,7 +2009,7 @@ x_event(int exit_condition) } keep_going = FALSE; #if defined(HANGUPHANDLING) - } else if (gp.program_state.done_hup) { + } else if (program_state.done_hup) { retval = '\033'; inptr = (inptr + 1) % INBUF_SIZE; keep_going = FALSE; diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 33f790e04..1fcdf471c 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -352,11 +352,11 @@ plsel_dialog_acceptvalues(void) XtSetArg(args[0], nhStr(XtNstring), &s); XtGetValues(plsel_name_input, args, ONE); - (void) strncpy(gp.plname, (char *) s, sizeof gp.plname - 1); - gp.plname[sizeof gp.plname - 1] = '\0'; - (void) mungspaces(gp.plname); - if (strlen(gp.plname) < 1) - (void) strcpy(gp.plname, "Mumbles"); + (void) strncpy(svp.plname, (char *) s, sizeof svp.plname - 1); + svp.plname[sizeof svp.plname - 1] = '\0'; + (void) mungspaces(svp.plname); + if (strlen(svp.plname) < 1) + (void) strcpy(svp.plname, "Mumbles"); iflags.renameinprogress = FALSE; } @@ -779,8 +779,8 @@ X11_create_player_selection_name(Widget form) XtSetArg(args[num_args], nhStr(XtNeditType), !plsel_ask_name ? XawtextRead : XawtextEdit); num_args++; XtSetArg(args[num_args], nhStr(XtNresize), XawtextResizeWidth); num_args++; - XtSetArg(args[num_args], nhStr(XtNstring), gp.plname); num_args++; - XtSetArg(args[num_args], XtNinsertPosition, strlen(gp.plname)); num_args++; + XtSetArg(args[num_args], nhStr(XtNstring), svp.plname); num_args++; + XtSetArg(args[num_args], XtNinsertPosition, strlen(svp.plname)); num_args++; XtSetArg(args[num_args], nhStr(XtNaccelerators), XtParseAcceleratorTable(plsel_input_accelerators)); num_args++; plsel_name_input = XtCreateManagedWidget("name_input", @@ -1222,7 +1222,7 @@ X11_player_selection_dialog(void) if (ps_selected == PS_QUIT #if defined(HANGUPHANDLING) - || gp.program_state.done_hup + || program_state.done_hup #endif ) { clearlocks(); @@ -1300,7 +1300,7 @@ X11_player_selection_prompts(void) if (ps_selected == PS_QUIT #if defined(HANGUPHANDLING) - || gp.program_state.done_hup + || program_state.done_hup #endif ) { clearlocks(); @@ -1373,7 +1373,7 @@ X11_player_selection_prompts(void) if (ps_selected == PS_QUIT #if defined(HANGUPHANDLING) - || gp.program_state.done_hup + || program_state.done_hup #endif ) { clearlocks(); @@ -1445,7 +1445,7 @@ X11_player_selection_prompts(void) if (ps_selected == PS_QUIT #if defined(HANGUPHANDLING) - || gp.program_state.done_hup + || program_state.done_hup #endif ) { clearlocks(); @@ -1515,7 +1515,7 @@ X11_player_selection_prompts(void) if (ps_selected == PS_QUIT #if defined(HANGUPHANDLING) - || gp.program_state.done_hup + || program_state.done_hup #endif ) { clearlocks(); @@ -1539,15 +1539,15 @@ void X11_player_selection(void) { if (iflags.wc_player_selection == VIA_DIALOG) { - if (!*gp.plname) { + if (!*svp.plname) { #ifdef UNIX char *defplname = get_login_name(); #else char *defplname = (char *)0; #endif - (void) strncpy(gp.plname, defplname ? defplname : "Mumbles", - sizeof gp.plname - 1); - gp.plname[sizeof gp.plname - 1] = '\0'; + (void) strncpy(svp.plname, defplname ? defplname : "Mumbles", + sizeof svp.plname - 1); + svp.plname[sizeof svp.plname - 1] = '\0'; iflags.renameinprogress = TRUE; } X11_player_selection_dialog(); diff --git a/win/X11/winstat.c b/win/X11/winstat.c index 63c536910..4e520203c 100644 --- a/win/X11/winstat.c +++ b/win/X11/winstat.c @@ -1535,7 +1535,7 @@ update_val(struct X_status_value *attr_rec, long new_value) if (attr_rec->type == SV_LABEL) { if (attr_rec == &shown_stats[F_NAME]) { - Strcpy(buf, gp.plname); + Strcpy(buf, svp.plname); buf[0] = highc(buf[0]); Strcat(buf, " the "); if (Upolyd) { @@ -1550,12 +1550,12 @@ update_val(struct X_status_value *attr_rec, long new_value) Strcat(buf, mnam); } else { Strcat(buf, - rank_of(u.ulevel, gp.pl_character[0], flags.female)); + rank_of(u.ulevel, svp.pl_character[0], flags.female)); } } else if (attr_rec == &shown_stats[F_DLEVEL]) { if (!describe_level(buf, 0)) { - Strcpy(buf, gd.dungeons[u.uz.dnum].dname); + Strcpy(buf, svd.dungeons[u.uz.dnum].dname); Sprintf(eos(buf), ", level %d", depth(&u.uz)); } } else if (attr_rec == &shown_stats[F_VERS]) { @@ -1987,7 +1987,7 @@ update_fancy_status_field(int i, int color, int attributes) val = (long) u.ualign.type; break; case F_TIME: - val = flags.time ? (long) gm.moves : 0L; + val = flags.time ? (long) svm.moves : 0L; break; case F_SCORE: #ifdef SCORE_ON_BOTL diff --git a/win/X11/wintext.c b/win/X11/wintext.c index 6f2f6f4ff..e401b7018 100644 --- a/win/X11/wintext.c +++ b/win/X11/wintext.c @@ -296,7 +296,7 @@ create_text_window(struct xwindow *wp) XtParseTranslationTable(text_translations)); num_args++; - wp->w = XtCreateManagedWidget(gk.killer.name[0] && WIN_MAP == WIN_ERR + wp->w = XtCreateManagedWidget(svk.killer.name[0] && WIN_MAP == WIN_ERR ? "tombstone" : "text_text", /* name */ asciiTextWidgetClass, @@ -467,7 +467,7 @@ calculate_rip_text(int how, time_t when) long cash; /* Put name on stone */ - Sprintf(rip_line[NAME_LINE], "%.16s", gp.plname); /* STONE_LINE_LEN */ + Sprintf(rip_line[NAME_LINE], "%.16s", svp.plname); /* STONE_LINE_LEN */ /* Put $ on stone */ cash = max(gd.done_money, 0L); diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index f93707463..d02f8a22a 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -227,7 +227,7 @@ curses_character_input_dialog( re-activate them now that input is being requested */ curses_got_input(); - if (gi.invent || (gm.moves > 1)) { + if (svm.moves > 0) { curses_get_window_size(MAP_WIN, &map_height, &map_width); } else { map_height = term_rows; @@ -789,7 +789,7 @@ curses_display_nhmenu( menu_determine_pages(current_menu); /* Display pre and post-game menus centered */ - if ((gm.moves <= 1 && !gi.invent) || gp.program_state.gameover) { + if (svm.moves == 0 || program_state.gameover) { win = curses_create_window(wid, current_menu->width, current_menu->height, CENTER); } else { /* Display during-game menus on the right out of the way */ @@ -1033,7 +1033,7 @@ menu_win_size(nhmenu *menu) int maxheaderwidth = menu->prompt ? (int) strlen(menu->prompt) : 0; nhmenu_item *menu_item_ptr, *last_item_ptr = NULL; - if (gp.program_state.gameover) { + if (program_state.gameover) { /* for final inventory disclosure, use full width */ maxwidth = term_cols - 2; /* +2: borders assumed */ } else { @@ -1555,7 +1555,8 @@ menu_get_selections(WINDOW *win, nhmenu *menu, int how) } /*FALLTHRU*/ default: - if (isdigit(curletter) && !selectors[curletter] + if (curletter > 0 && curletter < 256 + && isdigit(curletter) && !selectors[curletter] && !groupaccels[curletter]) { count = curses_get_count(curletter); /* after count, we know some non-digit is already pending */ diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index 39cb32729..5dee9900b 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -326,9 +326,9 @@ curses_askname(void) } #endif /* SELECTSAVED */ - curses_line_input_dialog("Who are you?", gp.plname, PL_NSIZ); - (void) mungspaces(gp.plname); - if (!gp.plname[0] || gp.plname[0] == '\033') + curses_line_input_dialog("Who are you?", svp.plname, PL_NSIZ); + (void) mungspaces(svp.plname); + if (!svp.plname[0] || svp.plname[0] == '\033') goto bail; iflags.renameallowed = TRUE; /* tty uses this, we don't [yet?] */ @@ -782,7 +782,7 @@ curses_update_inventory(int arg) } /* skip inventory updating during character initialization */ - if (!gp.program_state.in_moveloop && !gp.program_state.gameover) + if (!program_state.in_moveloop && !program_state.gameover) return; if (!arg) { diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 40585e448..73a939f2a 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -776,7 +776,7 @@ Currently this is limited to arrow keys, but this may be expanded. */ int curses_convert_keys(int key) { - boolean reject = (gp.program_state.input_state == otherInp), + boolean reject = (program_state.input_state == otherInp), as_is = FALSE, numpad_esc = FALSE; int ret = key; diff --git a/win/curses/cursstat.c b/win/curses/cursstat.c index d99e473b2..310ba7820 100644 --- a/win/curses/cursstat.c +++ b/win/curses/cursstat.c @@ -1886,7 +1886,7 @@ draw_horizontal(int x, int y, int hp, int hpmax) wmove(win, y, x); get_playerrank(rank); - sprintf(buf, "%s the %s", gp.plname, rank); + sprintf(buf, "%s the %s", svp.plname, rank); /* Use the title as HP bar (similar to hitpointbar) */ draw_bar(TRUE, hp, hpmax, buf); @@ -1954,7 +1954,7 @@ draw_horizontal(int x, int y, int hp, int hpmax) print_statdiff(" Exp:", &prevlevel, u.ulevel, STAT_OTHER); if (flags.time) - print_statdiff(" T:", &prevtime, gm.moves, STAT_TIME); + print_statdiff(" T:", &prevtime, svm.moves, STAT_TIME); curses_add_statuses(win, FALSE, FALSE, NULL, NULL); } @@ -1973,7 +1973,7 @@ draw_horizontal_new(int x, int y, int hp, int hpmax) char race[BUFSZ]; Strcpy(race, gu.urace.adj); race[0] = highc(race[0]); - wprintw(win, "%s the %s %s%s%s", gp.plname, + wprintw(win, "%s the %s %s%s%s", svp.plname, (u.ualign.type == A_CHAOTIC ? "Chaotic" : u.ualign.type == A_NEUTRAL ? "Neutral" : "Lawful"), Upolyd ? "" : race, Upolyd ? "" : " ", @@ -2035,7 +2035,7 @@ draw_horizontal_new(int x, int y, int hp, int hpmax) #endif /* SCORE_ON_BOTL */ if (flags.time) - print_statdiff(" T:", &prevtime, gm.moves, STAT_TIME); + print_statdiff(" T:", &prevtime, svm.moves, STAT_TIME); curses_add_statuses(win, TRUE, FALSE, &x, &y); @@ -2092,7 +2092,7 @@ draw_vertical(int x, int y, int hp, int hpmax) get_playerrank(rank); int ranklen = strlen(rank); - int namelen = strlen(gp.plname); + int namelen = strlen(svp.plname); int maxlen = 19; #ifdef STATUS_COLORS if (!iflags.hitpointbar) @@ -2109,7 +2109,7 @@ draw_vertical(int x, int y, int hp, int hpmax) while ((ranklen + namelen) > maxlen) ranklen--; /* Still doesn't fit, strip rank */ } - sprintf(buf, "%-*s the %-*s", namelen, gp.plname, ranklen, rank); + sprintf(buf, "%-*s the %-*s", namelen, svp.plname, ranklen, rank); draw_bar(TRUE, hp, hpmax, buf); wmove(win, y++, x); wprintw(win, "%s", dungeons[u.uz.dnum].dname); @@ -2188,7 +2188,7 @@ draw_vertical(int x, int y, int hp, int hpmax) wmove(win, y++, x); if (flags.time) { - print_statdiff("Time: ", &prevtime, gm.moves, STAT_TIME); + print_statdiff("Time: ", &prevtime, svm.moves, STAT_TIME); wmove(win, y++, x); } diff --git a/win/curses/curswins.c b/win/curses/curswins.c index d2168ec35..0bc7507b6 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -69,7 +69,7 @@ curses_create_window(int wid, int width, int height, orient orientation) if ((orientation == UP) || (orientation == DOWN) || (orientation == LEFT) || (orientation == RIGHT)) { - if (gi.invent || (gm.moves > 1)) { + if (svm.moves > 0) { map_border = curses_window_has_border(MAP_WIN); curses_get_window_xy(MAP_WIN, &mapx, &mapy); curses_get_window_size(MAP_WIN, &maph, &mapw); @@ -104,7 +104,7 @@ curses_create_window(int wid, int width, int height, orient orientation) starty = (term_rows / 2) - (height / 2); break; case UP: - if (gi.invent || (gm.moves > 1)) { + if (svm.moves > 0) { startx = (mapw / 2) - (width / 2) + mapx + mapb_offset; } else { startx = 0; @@ -113,7 +113,7 @@ curses_create_window(int wid, int width, int height, orient orientation) starty = mapy + mapb_offset; break; case DOWN: - if (gi.invent || (gm.moves > 1)) { + if (svm.moves > 0) { startx = (mapw / 2) - (width / 2) + mapx + mapb_offset; } else { startx = 0; @@ -129,7 +129,7 @@ curses_create_window(int wid, int width, int height, orient orientation) starty = term_rows - height; break; case RIGHT: - if (gi.invent || (gm.moves > 1)) { + if (svm.moves > 0) { startx = (mapw + mapx + (mapb_offset * 2)) - width; } else { startx = term_cols - width; @@ -222,7 +222,7 @@ curses_refresh_nethack_windows(void) return; } - if ((gm.moves <= 1) && !gi.invent) { + if (svm.moves == 0) { /* Main windows not yet displayed; refresh base window instead */ touchwin(stdscr); refresh(); diff --git a/win/tty/getline.c b/win/tty/getline.c index 53a1465bd..1a8215c06 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -232,7 +232,7 @@ xwaitforspace(const char *s) /* chars allowed besides return */ morc = 0; while ( #ifdef HANGUPHANDLING - !gp.program_state.done_hup && + !program_state.done_hup && #endif (c = tty_nhgetch()) != EOF) { if (c == '\n' || c == '\r') diff --git a/win/tty/topl.c b/win/tty/topl.c index e9f70e420..c20dfa288 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -184,7 +184,7 @@ remember_topl(void) cw->datlen[idx] = (short) len; } Strcpy(cw->data[idx], gt.toplines); - if (!gp.program_state.in_checkpoint) { + if (!program_state.in_checkpoint) { *gt.toplines = '\0'; cw->maxcol = cw->maxrow = (idx + 1) % cw->rows; } diff --git a/win/tty/wintty.c b/win/tty/wintty.c index d6cdf6200..17dcd1cc2 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -84,7 +84,7 @@ extern void msmsg(const char *, ...); */ #define HUPSKIP() \ do { \ - if (gp.program_state.done_hup) { \ + if (program_state.done_hup) { \ morc = '\033'; \ return; \ } \ @@ -92,7 +92,7 @@ extern void msmsg(const char *, ...); /* morc=ESC - in case we bypass xwaitforspace() which sets that */ #define HUPSKIP_RESULT(RES) \ do { \ - if (gp.program_state.done_hup) \ + if (program_state.done_hup) \ return (RES); \ } while (0) #else /* !HANGUPHANDLING */ @@ -376,11 +376,11 @@ winch_handler(int sig_unused UNUSED) } #endif - gp.program_state.resize_pending++; /* resize_tty() will reset it */ + program_state.resize_pending++; /* resize_tty() will reset it */ /* if nethack is waiting for input, which is the most likely scenario, we will go ahead and respond to the resize immediately; otherwise, tty_nhgetch() will do so the next time it's called */ - if (gp.program_state.getting_char) { + if (program_state.getting_char) { resize_tty(); #if 0 /* [this doesn't work as intended and seems to be unnecessary] */ if (resize_mesg) { @@ -402,7 +402,7 @@ resize_tty(void) struct WinDesc *cw; /* reset to 0 rather than just decrement */ - gp.program_state.resize_pending = 0; + program_state.resize_pending = 0; resize_mesg = 0; getwindowsz(); /* update LI and CO */ @@ -647,7 +647,7 @@ tty_player_selection(void) } /* - * gp.plname is filled either by an option (-u Player or -uPlayer) or + * svp.plname is filled either by an option (-u Player or -uPlayer) or * explicitly (by being the wizard) or by askname. * It may still contain a suffix denoting the role, etc. * Always called after init_nhwindows() and before @@ -668,7 +668,7 @@ tty_askname(void) case 0: break; /* no game chosen; start new game */ case 1: - return; /* gp.plname[] has been set */ + return; /* svp.plname[] has been set */ } #endif /* SELECTSAVED */ @@ -731,7 +731,7 @@ tty_askname(void) && !(c >= '0' && c <= '9' && ct > 0)) c = '_'; #endif - if (ct < (int) (sizeof gp.plname) - 1) { + if (ct < (int) (sizeof svp.plname) - 1) { #if defined(MICRO) #if defined(MSDOS) if (iflags.grmode) { @@ -742,13 +742,13 @@ tty_askname(void) #else (void) putchar(c); #endif - gp.plname[ct++] = c; + svp.plname[ct++] = c; #ifdef WIN32CON ttyDisplay->curx++; #endif } } - gp.plname[ct] = 0; + svp.plname[ct] = 0; } while (ct == 0); /* move to next line to simulate echo of user's */ @@ -1978,7 +1978,7 @@ tty_dismiss_nhwindow(winid window) can't refresh--force the screen to be cleared instead (affects dismissal of 'reset role filtering' menu if screen height forces that to need a second page) */ - if (gp.program_state.in_role_selection) + if (program_state.in_role_selection) clearscreen = TRUE; erase_menu_or_text(window, cw, clearscreen); @@ -3041,7 +3041,7 @@ ttyinv_add_menu( : !show_gold ? 26 : 27); - if (!gp.program_state.in_moveloop) + if (!program_state.in_moveloop) return; slot = selector_to_slot(ch, ttyinvmode, &ignore); if (inuse_only && slot > 2 * rows_per_side) @@ -3216,7 +3216,7 @@ ttyinv_end_menu(int window, struct WinDesc *cw) { if (iflags.perm_invent || gp.perm_invent_toggling_direction == toggling_on) { - if (gp.program_state.in_moveloop) { + if (program_state.in_moveloop) { boolean inuse_only = ((ttyinvmode & InvInUse) != 0); int rows_per_side = inuse_only ? cw->maxrow - 2 : 0; int old_slots_used = ttyinv_slots_used; /* value before render */ @@ -3245,7 +3245,7 @@ ttyinv_render(winid window, struct WinDesc *cw) uint32 current_row_color = NO_COLOR; struct tty_perminvent_cell *cell; char invbuf[BUFSZ]; - boolean force_redraw = gp.program_state.in_docrt ? TRUE : FALSE, + boolean force_redraw = program_state.in_docrt ? TRUE : FALSE, inuse_only = (ttyinvmode & InvInUse) != 0, show_gold = (ttyinvmode & InvShowGold) != 0 && !inuse_only, sparse = (ttyinvmode & InvSparse) != 0 && !inuse_only; @@ -3603,7 +3603,7 @@ tty_wait_synch(void) if (ttyDisplay->inmore) { addtopl("--More--"); (void) fflush(stdout); - } else if (ttyDisplay->inread > gp.program_state.gameover) { + } else if (ttyDisplay->inread > program_state.gameover) { /* this can only happen if we were reading and got interrupted */ ttyDisplay->toplin = TOPLINE_SPECIAL_PROMPT; /* do this twice; 1st time gets the Quit? message again */ @@ -4036,19 +4036,19 @@ tty_nhgetch(void) i = randomkey(); } else { #ifdef RESIZABLE - if (gp.program_state.resize_pending) + if (program_state.resize_pending) resize_tty(); #endif - gp.program_state.getting_char++; + program_state.getting_char++; #ifdef UNIX - i = (gp.program_state.getting_char == 1) + i = (program_state.getting_char == 1) ? tgetch() : ((read(fileno(stdin), (genericptr_t) &nestbuf, 1) == 1) ? (int) nestbuf : EOF); #else i = tgetch(); #endif - gp.program_state.getting_char--; + program_state.getting_char--; #ifdef RESIZABLE if (resize_mesg) { resize_mesg = 0; diff --git a/win/win32/mhdlg.c b/win/win32/mhdlg.c index 491aa270d..afa55c1c9 100644 --- a/win/win32/mhdlg.c +++ b/win/win32/mhdlg.c @@ -648,7 +648,7 @@ plselInitDialog(struct plsel_data * data) /* set player name */ control_t * name_box = &data->controls[psc_name_box]; - SetDlgItemText(data->dialog, name_box->id, NH_A2W(gp.plname, wbuf, sizeof(wbuf))); + SetDlgItemText(data->dialog, name_box->id, NH_A2W(svp.plname, wbuf, sizeof(wbuf))); plselRandomize(data); diff --git a/win/win32/mhinput.c b/win/win32/mhinput.c index e2317870f..9ad6c32f0 100644 --- a/win/win32/mhinput.c +++ b/win/win32/mhinput.c @@ -39,7 +39,7 @@ mswin_have_input(void) return #ifdef SAFERHANGUP /* we always have input (ESC) if hangup was requested */ - gp.program_state.done_hup || + program_state.done_hup || #endif (nhi_read_pos != nhi_write_pos); } @@ -69,7 +69,7 @@ mswin_input_pop(void) #ifdef SAFERHANGUP /* always return ESC when hangup was requested */ - if (gp.program_state.done_hup) { + if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; hangup_event.ei.kbd.ch = '\033'; @@ -98,7 +98,7 @@ mswin_input_peek(void) #ifdef SAFERHANGUP /* always return ESC when hangup was requested */ - if (gp.program_state.done_hup) { + if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; hangup_event.ei.kbd.ch = '\033'; diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index 231d829a1..bd1a5be79 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -457,16 +457,16 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_CLOSE: { /* exit gracefully */ - if (gp.program_state.gameover) { + if (program_state.gameover) { /* assume the user really meant this, as the game is already * over... */ /* to make sure we still save bones, just set stop printing flag */ - gp.program_state.stopprint++; + program_state.stopprint++; NHEVENT_KBD( '\033'); /* and send keyboard input as if user pressed ESC */ /* additional code for this is done in menu and rip windows */ - } else if (!gp.program_state.something_worth_saving) { + } else if (!program_state.something_worth_saving) { /* User exited before the game started, e.g. during splash display */ /* Just get out. */ @@ -842,7 +842,7 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) case IDM_SAVE: if (iflags.debug_fuzzer) break; - if (!gp.program_state.gameover && !gp.program_state.done_hup) + if (!program_state.gameover && !program_state.done_hup) dosave(); else MessageBeep(0); diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index dfb864f61..89d90e2ab 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -351,10 +351,10 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return FALSE; case WM_CLOSE: - if (gp.program_state.gameover) { + if (program_state.gameover) { data->result = -1; data->done = 1; - gp.program_state.stopprint++; + program_state.stopprint++; return TRUE; } else return FALSE; diff --git a/win/win32/mhrip.c b/win/win32/mhrip.c index 22d22fd6f..3fb9ac9ba 100644 --- a/win/win32/mhrip.c +++ b/win/win32/mhrip.c @@ -227,7 +227,7 @@ NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) GetNHApp()->hMainWnd = NULL; DestroyWindow(hWnd); SetFocus(GetNHApp()->hMainWnd); - gp.program_state.stopprint++; + program_state.stopprint++; return TRUE; case WM_DESTROY: diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index d64aa0734..40bfeb7ba 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -696,7 +696,7 @@ mswin_askname(void) { logDebug("mswin_askname()\n"); - if (mswin_getlin_window("Who are you?", gp.plname, PL_NSIZ) == IDCANCEL) { + if (mswin_getlin_window("Who are you?", svp.plname, PL_NSIZ) == IDCANCEL) { bail("bye-bye"); /* not reached */ } @@ -1251,7 +1251,7 @@ void mswin_update_inventory(int arg) { logDebug("mswin_update_inventory(%d)\n", arg); - if (iflags.perm_invent && gp.program_state.something_worth_saving + if (iflags.perm_invent && program_state.something_worth_saving && iflags.window_inited && WIN_INVEN != WIN_ERR) display_inventory(NULL, FALSE); } @@ -1963,7 +1963,7 @@ mswin_outrip(winid wid, int how, time_t when) } /* Put name on stone */ - Sprintf(buf, "%s", gp.plname); + Sprintf(buf, "%s", svp.plname); buf[STONE_LINE_LEN] = 0; putstr(wid, 0, buf); @@ -2862,7 +2862,7 @@ int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type) { TCHAR title[MAX_LOADSTRING]; - if (gp.program_state.exiting && !strcmp(text, "\n")) + if (program_state.exiting && !strcmp(text, "\n")) text = "Press Enter to exit"; LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING);