diff --git a/DEVEL/Developer.txt b/DEVEL/Developer.txt index adc326003..f7917dc2d 100644 --- a/DEVEL/Developer.txt +++ b/DEVEL/Developer.txt @@ -62,7 +62,7 @@ NOTE: The following instructions require perl. If you do not have perl on A. If you have never set up git on this machine before: (This assumes you will only be using git for NetHack. If you are going to use it for other projects as well, think before you type.) - Tell git what name (or nicname) and email address to use for you: + Tell git what name (or nickname) and email address to use for you: git config --global user.name "MY NAME" git config --global user.email USER@EXAMPLE.COM You probably want to set up a credential cache. diff --git a/DEVEL/code_features.txt b/DEVEL/code_features.txt index 1c60e024e..4e89df7f5 100644 --- a/DEVEL/code_features.txt +++ b/DEVEL/code_features.txt @@ -20,7 +20,7 @@ Here's how to do it: - The example above will alert the users for a new feature added in 3.6.0 via a one-liner via pline(), but you could get more elaborate (just make sure it is all done - in the 'if' code block.. + in the 'if' code block. Once the user finds the alert no longer useful, or becoming annoying, they can set the "suppress_alert" option. @@ -75,7 +75,7 @@ There is a fqn_prefix[] entry for holding the path to each of the following: To recap, they are about enabling "different paths for different things", and separation of: - read-only stuff from read-write stuff. -- sysadmin stuff from user-writeable stuff. +- sysadmin stuff from user-writable stuff. etc. ============================================== diff --git a/DEVEL/code_style.txt b/DEVEL/code_style.txt index 4f16a8995..b17076823 100644 --- a/DEVEL/code_style.txt +++ b/DEVEL/code_style.txt @@ -16,7 +16,7 @@ declarations. Due to some incompatibilities, the patch is not publicly available and clang-format is not expected to be regularly used. Developers should do their best to adhere to the coding style to promote -legibile, easy-to-edit code. Legibility is paramount, so in some cases, it may +legible, easy-to-edit code. Legibility is paramount, so in some cases, it may be better not to fully adhere to the style guidelines. Recipes for common text editors can be found at the end of this file. @@ -30,7 +30,7 @@ characters, not tabs. Lines should be at most 78 characters wide. If a line would be longer than the limit, the line should be wrapped and the wrapped portion should be aligned with the parentheses or brackets containing the wrap. If there is no set of -parenthese or brackets, the line should be indented four spaces. Wrapping +parentheses or brackets, the line should be indented four spaces. Wrapping should normally occur after a comma or before a binary operator, when possible: @@ -43,7 +43,7 @@ possible: Single blank lines should be used wherever convenient to improve readability. -Functions and Control Satements +Functions and Control Statements ------------------------------- For a function definition, the return type, declarator, and opening brace @@ -183,10 +183,10 @@ many entries that reproducing them here is impractical. Fortunately, the options are in plain English, so walking through them with a copy of this Guide handy and making changes as required will suffice. -emacs Configuration +Emacs Configuration =================== -There are no doubt umpteen different ways to handle this in emacs. +There are no doubt umpteen different ways to handle this in Emacs. Putting the following in ~/.emacs.el is one (defun hook-c () diff --git a/README b/README index 677f3d300..e479737b9 100644 --- a/README +++ b/README @@ -127,7 +127,7 @@ filing a bug report from our "Contact Us" web page at: https://www.nethack.org/common/contact.html or http://www.nethack.org/common/contact.html Please include the version information from #version or the command line -option --version in the apropriate field. +option --version in the appropriate field. A public repository of the latest NetHack code that we've made available can be obtained via git here: diff --git a/dat/data.base b/dat/data.base index 6dd001450..f10a9e581 100644 --- a/dat/data.base +++ b/dat/data.base @@ -534,6 +534,7 @@ ooze kind had swept so evilly free of all litter. [ At the Mountains of Madness, by H.P. Lovecraft ] blue jelly +spotted jelly I'd planned how to prevent the lock from sealing behind me; it required a temporary sacrifice, not cleverness. I used the door itself to help me cut off a portion of my body, after shunting all @@ -892,6 +893,20 @@ tiamat extremely vain. citrine* A pale yellow variety of crystalline quartz resembling topaz. +clay golem + It was a warm spring night when a fist knocked at the door so + hard that the hinges bent. + A man opened it and peered out into the street. There was + mist coming off the river and it was a cloudy night. He might + as well have tried to see through white velvet. + But he thought afterwards that there had been shapes out + there, just beyond the light spilling out into the road. A + lot of shapes, watching him carefully. He thought maybe + there'd been very faint points of light... + There was no mistaking the shape right in front of him, + though. It was big and dark red and looked like a child's + clay model of a man. Its eyes were two embers. + [ Feet of Clay, by Terry Pratchett ] cleaver Hither came Conan, the Cimmerian, black-haired, sullen-eyed, sword in hand, a thief, a reaver, a slayer, with gigantic @@ -1994,6 +2009,7 @@ gold golem ~gold golem ~straw golem ~wood golem +~clay golem *golem "The original story harks back, so they say, to the sixteenth century. Using long-lost formulas from the Kabbala, a rabbi is @@ -2305,7 +2321,8 @@ cornucopia And scatters corn and wine, and fruits and flowers. [ Os Lusiadas, by Luis Vaz de Camoes ] horned devil - Horned devils lack any real special abilities, though they +barbed devil + These devils lack any real special abilities, though they are quite difficult to kill. ~horsem* *horse @@ -4001,6 +4018,7 @@ pony continent and to and from our own world. The precise manner of their working is a Management secret. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] +trident poseido*n Poseido(o)n, lord of the seas and father of rivers and fountains, was the son of Chronos and Rhea, brother of Zeus, @@ -5152,6 +5170,7 @@ tripe ration often, alas, because the heat has not been kept low enough, it has the consistency of wet shoe leather. [ Joy of Cooking, by I Rombauer and M Becker ] +~water troll *troll The troll shambled closer. He was perhaps eight feet tall, perhaps more. His forward stoop, with arms dangling past @@ -5420,6 +5439,21 @@ water demon and drink, I will enjoy eating you, the biggest monkey, most of all!" He grinned, and saliva dripped down his hairy chin. [ Buddhist Tales for Young and Old, Vol. 1 ] +water troll + It wasn't that the troll was _horrifying_. Instead of the + rotting, betentacled monstrosity he had been expecting + Rincewind found himself looking at a rather squat but not + particularly ugly old man who would quite easily have passed + for normal on any city street, always provided that other + people on the street were used to seeing old men who were + apparently composed of water and very little else. It was as + if the ocean had decided to create life without going through + all that tedious business of evolution, and had simply formed + a part of itself into a biped and sent it walking squishily up + the beach. The troll was a pleasant translucent blue color. + As Rincewind stared a small shoal of silver fish flashed + across its chest. + [ The Colour of Magic, by Terry Pratchett ] weapon A weapon is a device for making your enemy change his mind. [ The Vor Game, by Lois McMaster Bujold ] @@ -5428,17 +5462,17 @@ web When first we practise to deceive! [ Marmion, by Sir Walter Scott ] whistle - There were legends both on the front and on the back of the + There were legends both on the front and on the back of the whistle. The one read thus: - FLA FUR BIS FLE The other: QUIS EST ISTE QUI VENIT - 'I ought to be able to make it out,' he thought; - 'but I suppose I am a little rusty in my Latin. - When I come to think of it, I don't believe I even - know the word for a whistle. The long one does seem - simple enough. It ought to mean, "Who is this who is coming?" + FLA FUR BIS FLE The other: QUIS EST ISTE QUI VENIT + 'I ought to be able to make it out,' he thought; + 'but I suppose I am a little rusty in my Latin. + When I come to think of it, I don't believe I even + know the word for a whistle. The long one does seem + simple enough. It ought to mean, "Who is this who is coming?" - Well, the best way to find out is evidently to whistle + Well, the best way to find out is evidently to whistle for him.' [Ghost Stories of an Antiquary, by Montague Rhodes James diff --git a/dat/hh b/dat/hh index 4b9c4d9a1..d689f65ef 100644 --- a/dat/hh +++ b/dat/hh @@ -96,7 +96,7 @@ M-2 twoweapon toggle two-weapon combat (unless number_pad is enabled) M-a adjust adjust inventory letters M-A annotate add a one-line note to the current dungeon level (see M-O) M-c chat talk to someone -M-C conduct view optional challanges +M-C conduct view optional challenges M-d dip dip an object into something M-e enhance advance or check weapon and spell skills M-f force force a lock diff --git a/dat/opthelp b/dat/opthelp index 7d328d4a9..dd379be79 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -104,7 +104,7 @@ preload_tiles control whether tiles get pre-loaded into RAM at [TRUE] of the tile graphics, but uses more memory. Boolean option if TTY_TILES_ESCCODES was set at compile time (tty only): -vt_tiledata insert extra data escae code markers into output [FALSE] +vt_tiledata insert extra data escape code markers into output [FALSE] Any Boolean option can be negated by prefixing it with a '!' or 'no'. @@ -159,7 +159,7 @@ paranoid_confirmation space separated list [paranoid_confirmation:pray] pray -- y to confirm an attempt to pray; on by default Remove -- always pick from inventory for 'R' and 'T' even when wearing just one applicable item to remove or take off -pickup_burden when you pick up an item that exceeds this encumberance [S] +pickup_burden when you pick up an item that exceeds this encumbrance [S] level (Unencumbered, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. pickup_types a list of default symbols for kinds of objects to [] diff --git a/dat/quest.txt b/dat/quest.txt index 5f5aeeed2..269ec76a1 100644 --- a/dat/quest.txt +++ b/dat/quest.txt @@ -1668,7 +1668,7 @@ to %ns lair. If you can manage to defeat %n and return undead that befoul the land. "Go with %d as your guide, %p." -%E [%nC invaded %H and captured %o. Defeat %ni and retrive %oh.] +%E [%nC invaded %H and captured %o. Defeat %ni and retrieve %oh.] %Cp Pri 00025 "You can prevail, if you rely on %d." %E @@ -2056,7 +2056,7 @@ the Amulet." %E [You have succeeded. Take %o with you as you go to find the Amulet.] # assumes The Longbow of Diana %Cc Ran 00082 -%l flexs %o reverently. +%l flexes %o reverently. "With this wondrous bow, one need never run out of arrows. You are its keeper now, and the time has come to resume your @@ -2707,7 +2707,7 @@ and you may be able to defeat him." "If you are %a at all times you may succeed, %p." %E %Cp Tou 00034 -"Let all who meet you on your journey know that you are on an quest for +"Let all who meet you on your journey know that you are on a quest for %l and grant safe passage." %E %Cc Tou 00035 @@ -2967,7 +2967,7 @@ The ice and snow gives way to a valley floor. You %x ahead of you a huge round hill surrounded by pools of lava. This then is the entrance to %i. It looks like you're not going to get in without a fight though. -%E [This is the entrace to %i.] +%E [This is the entrance to %i.] %Cp Val 00036 Once again, you stand before the entrance to %i. %E diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index e21956137..e1c67b7fa 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -54,7 +54,7 @@ .in -\\n(PYu \" undo indent past label (etc) .sn \\n(pdu \" tmac.n: inter-paragraph space .. -.\" end of labeled paragrah +.\" end of labeled paragraph .\" .\" aligned single character key with SHORT definition (if it overflows one .\" line, all bets are off) @@ -1583,7 +1583,7 @@ debt or credit, if any. The `Iu' command lists unpaid items The `Ix' command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. .hn 3 -Shop idiosyncracies +Shop idiosyncrasies .pg Several aspects of shop behavior might be unexpected. .\" note: using * instead of \(bu is better for plain text output @@ -2463,19 +2463,19 @@ defaults to the location of the NetHack.exe or NetHackw.exe file so setting HACKDIR to override that is not usually necessary or recommended. .lp LEVELDIR The location that in-progress level files are stored. Defaults to HACKDIR, -must be writeable. +must be writable. .lp SAVEDIR The location where saved games are kept. Defaults to HACKDIR, must be -writeable. +writable. .lp BONESDIR The location that bones files are kept. Defaults to HACKDIR, must be -writeable. +writable. .lp LOCKDIR The location that file synchronization locks are stored. Defaults to -HACKDIR, must be writeable. +HACKDIR, must be writable. .lp TROUBLEDIR The location that a record of game aborts and self-diagnosed game problems -is kept. Defaults to HACKDIR, must be writeable. +is kept. Defaults to HACKDIR, must be writable. .lp AUTOCOMPLETE Enable or disable an extended command autocompletion. Autocompletion has no effect for the X11 windowport. @@ -3004,7 +3004,6 @@ such as ``paranoid_confirmation:attack pray Remove''. .lp perm_invent If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that implement this feature. -Persistent. .lp pettype Specify the type of your initial pet, if you are playing a character class that uses multiple types of pets; or choose to have no initial pet at all. @@ -4018,7 +4017,7 @@ m S_mimic (mimic) ] S_mimic_def (mimic) M S_mummy (mummy) N S_naga (naga) -\. S_ndoor (doorway witout door) +\. S_ndoor (doorway without door) n S_nymph (nymph) O S_ogre (ogre) o S_orc (orc) diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 31a4ee76b..a89c13b07 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -1452,7 +1452,7 @@ be automatically turned off. \item[\tb{\#untrap}] Untrap something (trap, door, or chest). Default key is '{\tt M-u}', and '{\tt u}' if {\it number\verb+_+pad\/} is on. %.lp "" -In some circumstancs it can also be used to rescue trapped monsters. +In some circumstances it can also be used to rescue trapped monsters. %.lp \item[\tb{\#up}] Go up a staircase. Default key is '{\tt <}'. @@ -1830,7 +1830,7 @@ The {\tt Ix} command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. %.hn 3 -\subsubsection*{Shop idiosyncracies} +\subsubsection*{Shop idiosyncrasies} %.pg Several aspects of shop behavior might be unexpected. @@ -2848,23 +2848,23 @@ so setting HACKDIR to override that is not usually necessary or recommended. %.lp \item[\bb{LEVELDIR}] The location that in-progress level files are stored. Defaults to HACKDIR, -must be writeable. +must be writable. %.lp \item[\bb{SAVEDIR}] The location where saved games are kept. Defaults to HACKDIR, must be -writeable. +writable. %.lp \item[\bb{BONESDIR}] The location that bones files are kept. Defaults to HACKDIR, must be -writeable. +writable. %.lp \item[\bb{LOCKDIR}] The location that file synchronization locks are stored. Defaults to -HACKDIR, must be writeable. +HACKDIR, must be writable. %.lp \item[\bb{TROUBLEDIR}] The location that a record of game aborts and self-diagnosed game problems -is kept. Defaults to HACKDIR, must be writeable. +is kept. Defaults to HACKDIR, must be writable. %.lp \item[\bb{AUTOCOMPLETE}] Enable or disable an extended command autocompletion. @@ -3501,7 +3501,6 @@ such as ``{\it par\-a\-noid\verb+_+con\-fir\-ma\-tion:attack~pray~Remove}''. \item[\ib{perm\verb+_+invent}] If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that implement this feature. -Persistent. %.lp \item[\ib{pettype}] Specify the type of your initial pet, if you are playing a character class diff --git a/doc/Guidebook.txt b/doc/Guidebook.txt index a53364f73..f43daba67 100644 --- a/doc/Guidebook.txt +++ b/doc/Guidebook.txt @@ -1926,7 +1926,7 @@ any unpaid items which have been used up, along with other shop fees, if any. - 5.4.1. Shop idiosyncracies + 5.4.1. Shop idiosyncrasies Several aspects of shop behavior might be unexpected. @@ -3015,19 +3015,19 @@ LEVELDIR The location that in-progress level files are stored. Defaults - to HACKDIR, must be writeable. + to HACKDIR, must be writable. SAVEDIR The location where saved games are kept. Defaults to HACKDIR, - must be writeable. + must be writable. BONESDIR The location that bones files are kept. Defaults to HACKDIR, - must be writeable. + must be writable. LOCKDIR The location that file synchronization locks are stored. - Defaults to HACKDIR, must be writeable. + Defaults to HACKDIR, must be writable. NetHack 3.6 May 27, 2018 @@ -3042,7 +3042,7 @@ TROUBLEDIR The location that a record of game aborts and self-diagnosed - game problems is kept. Defaults to HACKDIR, must be writeable. + game problems is kept. Defaults to HACKDIR, must be writable. AUTOCOMPLETE Enable or disable an extended command autocompletion. Autocom- @@ -5043,7 +5043,7 @@ ] S_mimic_def (mimic) M S_mummy (mummy) N S_naga (naga) - . S_ndoor (doorway witout door) + . S_ndoor (doorway without door) n S_nymph (nymph) O S_ogre (ogre) o S_orc (orc) diff --git a/doc/config.nh b/doc/config.nh index 4ceeca6a0..ce5410382 100644 --- a/doc/config.nh +++ b/doc/config.nh @@ -398,21 +398,21 @@ #HACKDIR=c:\games\nethack # The location that level files in progress are stored -# (default=HACKDIR, writeable) +# (default=HACKDIR, writable) #LEVELDIR=c:\nethack\levels -# The location where saved games are kept (default=HACKDIR, writeable) +# The location where saved games are kept (default=HACKDIR, writable) #SAVEDIR=c:\nethack\save -# The location that bones files are kept (default=HACKDIR, writeable) +# The location that bones files are kept (default=HACKDIR, writable) #BONESDIR=c:\nethack\save # The location that file synchronization locks are stored -# (default=HACKDIR, writeable) +# (default=HACKDIR, writable) #LOCKDIR=c:\nethack\levels # The location that a record of game aborts and self-diagnosed game problems -# is kept (default=HACKDIR, writeable) +# is kept (default=HACKDIR, writable) #TROUBLEDIR=c:\nethack\trouble # Finnish keyboards might need these modifications uncommented. Windows GUI. diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 3c514a8a4..3014b1d10 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -117,6 +117,17 @@ for hilite_status of string status fields (title, dungeon-level, alignment), jumping into or over a Sokoban pit, or over a fire trap, triggers trap twice mimics created by #wizgenesis could block or not block vision incorrectly handle monsters inside the invocation area +give monsters who have had a worn item stolen or who have been life-saved + (used up amulet) a chance to wear replacement gear on next move + instead of having to wait until they pick something up +Unchanging hero in clay golem form will be killed when cancelled +poly'd shapechanger and hiding mimic will revert to normal when cancelled, + like werecreature in beast form and non-Unchanging hero +cancelled shapeshifter is no longer able to change shape +cancelled shapeshifter hit by polymorph magic will become uncancelled +polymorph zap which creates a new long worm (or retains an old one via wizard + mode monpolycontrol) can hit that worm multiple times (tail segments) +wishing for "orange" could yield orange or orange colored gem/potion/spellbook Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -133,6 +144,8 @@ tty: ensure that current status fields are always copied to prior status Platform- and/or Interface-Specific Fixes ----------------------------------------- +move 'perm_invent' value from flags to iflags to keep it out of save files; + affects X11, win32, and curses windows-gui: In nethackw, there could be conflicts between menu accelerators and an extra choice accelerator to fix H7132. windows-gui: recognize new BL_RESET in status_update; no change in behavior yet @@ -185,6 +198,7 @@ wizard mode #wizidentify can now select individual items for permanent identification and don't display the selection to permanently identify everything if everything is already fully identified spiders will occasionally spin webs when moving around +make mine town "orctown" variation a multiple level feature of the mines Code Cleanup and Reorganization diff --git a/doc/nethack.6 b/doc/nethack.6 index 1bf53a63f..e9f4c72ff 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -93,7 +93,7 @@ To win the game (as opposed to merely playing to beat other people's high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dungeon and get it out. Few people achieve this; most never do. Those who have go down -in history as heros among heroes - and then they find ways of making the +in history as heroes among heroes - and then they find ways of making the game even harder. See the .I Guidebook section on Conduct if this game has gotten too easy for you. diff --git a/doc/nethack.txt b/doc/nethack.txt index 4c9986349..9cd48ce3d 100644 --- a/doc/nethack.txt +++ b/doc/nethack.txt @@ -26,7 +26,7 @@ DESCRIPTION To win the game (as opposed to merely playing to beat other people's high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dungeon and get it out. Few people achieve - this; most never do. Those who have go down in history as heros among + this; most never do. Those who have go down in history as heroes among heroes - and then they find ways of making the game even harder. See the Guidebook section on Conduct if this game has gotten too easy for you. diff --git a/doc/window.doc b/doc/window.doc index 59b90255d..a7141d448 100644 --- a/doc/window.doc +++ b/doc/window.doc @@ -177,7 +177,7 @@ int nhgetch() -- Returns a single character input from the user. changed and also return ASCII 033 in this case. int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a - a positioning event (perhaps from a mouse). If the + positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of @@ -334,7 +334,7 @@ add_menu(windid window, int glyph, const anything identifier, outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with - the menu command (or their user defined alises), it loses. + the menu command (or their user defined aliases), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the @@ -461,7 +461,7 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percentage, int color For the user's chosen set of BL_MASK_ condition bits, They are stored internally in the cond_hilites[] array, - at the array offset aligned to the color those condtion + at the array offset aligned to the color those condition bits should display in. For example, if the user has chosen to display strngl @@ -602,7 +602,7 @@ getmsghistory(init) If init is TRUE, start over again from most recent message. putmsghistory(msg) - -- The is the counterpart to getmsghistory() for restores + -- This is the counterpart to getmsghistory() for restores used to reload the port's message recall buffer. The routine is called repeatedly from the core restore routine, starting with the oldest message first, and @@ -693,7 +693,7 @@ when processing options, either in the config file, or by the 'O' command. You may be wondering what values your window port will find in the iflags.wc_* and iflags.wc2_* fields for options that the user has not -specified in his/her config file. Put another way, how does you port code +specified in his/her config file. Put another way, how does your port code tell if an option has not been set? The next paragraph explains that. If the core does not set an option, it will still be initialized @@ -1068,7 +1068,7 @@ When writing a new window-port, you need to follow the following guidelines: WINOBJ (if you want the NetHack binary to include them, that is). 9) Look at your port's portmain.c (the file containing main()) and make - sure that all of the calls match the the requirements laid out in + sure that all of the calls match the requirements laid out in Section VII. Now, proceed with compilation and installation as usual. Don't forget diff --git a/include/decl.h b/include/decl.h index f0d806dc8..53902a07f 100644 --- a/include/decl.h +++ b/include/decl.h @@ -160,6 +160,7 @@ E NEARDATA struct sinfo { } program_state; E boolean restoring; +E boolean ransacked; E const char quitchars[]; E const char vowels[]; diff --git a/include/dungeon.h b/include/dungeon.h index f7b16cf2a..45246f150 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -146,7 +146,8 @@ typedef struct branch { #define MIGR_WITH_HERO 9 /* mon: followers; obj: trap door */ #define MIGR_NOBREAK 1024 /* bitmask: don't break on delivery */ #define MIGR_NOSCATTER 2048 /* don't scatter on delivery */ - +#define MIGR_TO_SPECIES 4096 /* migrating to species as they are made */ +#define MIGR_LEFTOVERS 8192 /* grab remaining MIGR_TO_SPECIES objects */ /* level information (saved via ledger number) */ struct linfo { diff --git a/include/extern.h b/include/extern.h index abd4be118..ed186e667 100644 --- a/include/extern.h +++ b/include/extern.h @@ -428,6 +428,8 @@ E const char *NDECL(roguename); E struct obj *FDECL(realloc_obj, (struct obj *, int, genericptr_t, int, const char *)); E char *FDECL(coyotename, (struct monst *, char *)); +E char *FDECL(rndorcname, (char *)); +E struct monst *FDECL(christen_orc, (struct monst *, char *)); E const char *FDECL(noveltitle, (int *)); E const char *FDECL(lookup_novel, (const char *, int *)); @@ -519,6 +521,7 @@ E void FDECL(container_impact_dmg, (struct obj *, XCHAR_P, XCHAR_P)); E int NDECL(dokick); E boolean FDECL(ship_object, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(obj_delivery, (BOOLEAN_P)); +E void FDECL(deliver_obj_to_mon, (struct monst *mtmp, unsigned long)); E schar FDECL(down_gate, (XCHAR_P, XCHAR_P)); E void FDECL(impact_drop, (struct obj *, XCHAR_P, XCHAR_P, XCHAR_P)); @@ -1283,6 +1286,7 @@ E void FDECL(new_omailcmd, (struct obj *, const char *)); E void FDECL(free_omailcmd, (struct obj *)); E struct obj *FDECL(mkobj_at, (CHAR_P, int, int, BOOLEAN_P)); E struct obj *FDECL(mksobj_at, (int, int, int, BOOLEAN_P, BOOLEAN_P)); +E struct obj *FDECL(mksobj_migr_to_species, (int, unsigned, BOOLEAN_P, BOOLEAN_P)); E struct obj *FDECL(mkobj, (CHAR_P, BOOLEAN_P)); E int NDECL(rndmonnum); E boolean FDECL(bogon_is_pname, (CHAR_P)); @@ -1753,7 +1757,7 @@ E char *FDECL(self_lookat, (char *)); E void FDECL(mhidden_description, (struct monst *, BOOLEAN_P, char *)); E boolean FDECL(object_from_map, (int,int,int,struct obj **)); E int FDECL(do_screen_description, (coord, BOOLEAN_P, int, char *, - const char **)); + const char **, struct permonst **)); E int FDECL(do_look, (int, coord *)); E int NDECL(dowhatis); E int NDECL(doquickwhatis); diff --git a/include/flag.h b/include/flag.h index 8d386decf..f2339f6c0 100644 --- a/include/flag.h +++ b/include/flag.h @@ -40,7 +40,7 @@ struct flag { boolean lit_corridor; /* show a dark corr as lit if it is in sight */ boolean nap; /* `timed_delay' option for display effects */ boolean null; /* OK to send nulls to the terminal */ - boolean perm_invent; /* keep full inventories up until dismissed */ + boolean p__obsolete; /* [3.6.2: perm_invent moved to iflags] */ boolean pickup; /* whether you pickup or move and look */ boolean pickup_thrown; /* auto-pickup items you threw */ boolean pushweapon; /* When wielding, push old weapon into second slot */ @@ -292,6 +292,7 @@ struct instance_flags { boolean menu_tab_sep; /* Use tabs to separate option menu fields */ boolean news; /* print news */ boolean num_pad; /* use numbers for movement commands */ + boolean perm_invent; /* keep full inventories up until dismissed */ boolean renameallowed; /* can change hero name during role selection */ boolean renameinprogress; /* we are changing hero name */ boolean status_updates; /* allow updates to bottom status lines; diff --git a/include/hack.h b/include/hack.h index ed699a943..f65d2ddd1 100644 --- a/include/hack.h +++ b/include/hack.h @@ -270,6 +270,12 @@ typedef struct sortloot_item Loot; #define SHIFT_SEENMSG 0x01 /* put out a message if in sight */ #define SHIFT_MSG 0x02 /* always put out a message */ +/* flags for deliver_obj_to_mon */ +#define DF_NONE 0x00 +#define DF_RANDOM2 0x01 +#define DF_RANDOM3 0x02 +#define DF_ALL 0x04 + /* special mhpmax value when loading bones monster to flag as extinct or * genocided */ #define DEFUNCT_MONSTER (-100) diff --git a/include/trap.h b/include/trap.h index 16d096812..8eacc6ccd 100644 --- a/include/trap.h +++ b/include/trap.h @@ -83,4 +83,7 @@ enum trap_types { TRAPNUM }; +#define is_pit(ttyp) ((ttyp) == PIT || (ttyp) == SPIKED_PIT) +#define is_hole(ttyp) ((ttyp) == HOLE || (ttyp) == TRAPDOOR) + #endif /* TRAP_H */ diff --git a/src/ball.c b/src/ball.c index be5b7815f..762de85f8 100644 --- a/src/ball.c +++ b/src/ball.c @@ -599,8 +599,7 @@ drag: || !is_pool(uball->ox, uball->oy) || levl[uball->ox][uball->oy].typ == POOL)) || ((t = t_at(uchain->ox, uchain->oy)) - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == HOLE - || t->ttyp == TRAPDOOR))) { + && (is_pit(t->ttyp) || is_hole(t->ttyp)))) { if (Levitation) { You_feel("a tug from the iron ball."); if (t) @@ -745,8 +744,8 @@ xchar x, y; if (!Levitation && !MON_AT(x, y) && !u.utrap && (is_pool(x, y) || ((t = t_at(x, y)) - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT - || t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) { + && (is_pit(t->ttyp) + || is_hole(t->ttyp))))) { u.ux = x; u.uy = y; } else { diff --git a/src/decl.c b/src/decl.c index 2a9c28746..ffd9ef974 100644 --- a/src/decl.c +++ b/src/decl.c @@ -57,6 +57,7 @@ NEARDATA char pl_fruit[PL_FSIZ] = DUMMY; NEARDATA struct fruit *ffruit = (struct fruit *) 0; NEARDATA char tune[6] = DUMMY; +NEARDATA boolean ransacked = 0; const char *occtxt = DUMMY; const char quitchars[] = " \r\n\033"; diff --git a/src/dig.c b/src/dig.c index 488673b22..0a1669813 100644 --- a/src/dig.c +++ b/src/dig.c @@ -312,8 +312,7 @@ dig(VOID_ARGS) } if (context.digging.effort <= 50 - || (ttmp && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == PIT - || ttmp->ttyp == SPIKED_PIT))) { + || (ttmp && (ttmp->ttyp == TRAPDOOR || is_pit(ttmp->ttyp)))) { return 1; } else if (ttmp && (ttmp->ttyp == LANDMINE || (ttmp->ttyp == BEAR_TRAP && !u.utrap))) { @@ -803,7 +802,7 @@ coord *cc; } } else if ((boulder_here = sobj_at(BOULDER, dig_x, dig_y)) != 0) { - if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) + if (ttmp && is_pit(ttmp->ttyp) && rn2(2)) { pline_The("boulder settles into the %spit.", (dig_x != u.ux || dig_y != u.uy) ? "adjacent " : ""); @@ -1087,7 +1086,7 @@ struct obj *obj; KILLED_BY); } else if (u.utrap && u.utraptype == TT_PIT && trap && (trap_with_u = t_at(u.ux, u.uy)) - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) + && is_pit(trap->ttyp) && !conjoined_pits(trap, trap_with_u, FALSE)) { int idx; @@ -1462,8 +1461,7 @@ zap_dig() struct trap *adjpit = t_at(zx, zy); if ((diridx < 8) && !conjoined_pits(adjpit, trap_with_u, FALSE)) { digdepth = 0; /* limited to the adjacent location only */ - if (!(adjpit && (adjpit->ttyp == PIT - || adjpit->ttyp == SPIKED_PIT))) { + if (!(adjpit && is_pit(adjpit->ttyp))) { char buf[BUFSZ]; cc.x = zx; cc.y = zy; @@ -1477,7 +1475,7 @@ zap_dig() } } if (adjpit - && (adjpit->ttyp == PIT || adjpit->ttyp == SPIKED_PIT)) { + && is_pit(adjpit->ttyp)) { int adjidx = (diridx + 4) % 8; trap_with_u->conjoined |= (1 << diridx); adjpit->conjoined |= (1 << adjidx); @@ -1566,7 +1564,7 @@ zap_dig() if (pitflow && isok(flow_x, flow_y)) { struct trap *ttmp = t_at(flow_x, flow_y); - if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT)) { + if (ttmp && is_pit(ttmp->ttyp)) { schar filltyp = fillholetyp(ttmp->tx, ttmp->ty, TRUE); if (filltyp != ROOM) pit_flow(ttmp, filltyp); @@ -1681,7 +1679,7 @@ struct trap *trap; schar filltyp; { if (trap && (filltyp != ROOM) - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { + && is_pit(trap->ttyp)) { struct trap t; int idx; diff --git a/src/display.c b/src/display.c index 5b8eba8a7..a142eab91 100644 --- a/src/display.c +++ b/src/display.c @@ -783,7 +783,7 @@ register int x, y; /* if monster is in a physical trap, you see the trap too */ - if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT + if (tt == BEAR_TRAP || is_pit(tt) || tt == WEB) { trap->tseen = TRUE; } diff --git a/src/do.c b/src/do.c index 8f878af79..81bbb6235 100644 --- a/src/do.c +++ b/src/do.c @@ -149,8 +149,7 @@ const char *verb; if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) { return TRUE; } else if (obj->otyp == BOULDER && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT - || t->ttyp == TRAPDOOR || t->ttyp == HOLE)) { + && (is_pit(t->ttyp) || is_hole(t->ttyp))) { if (((mtmp = m_at(x, y)) && mtmp->mtrapped) || (u.utrap && u.ux == x && u.uy == y)) { if (*verb) @@ -956,7 +955,7 @@ dodown() if (trap && uteetering_at_seen_pit(trap)) { dotrap(trap, TOOKPLUNGE); return 1; - } else if (!trap || (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE) + } else if (!trap || !is_hole(trap->ttyp) || !Can_fall_thru(&u.uz) || !trap->tseen) { if (flags.autodig && !context.nopick && uwep && is_pick(uwep)) { return use_pick_axe2(uwep); diff --git a/src/do_name.c b/src/do_name.c index e4a874126..4c7653776 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1519420054 2018/02/23 21:07:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.128 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1537477563 2018/09/20 21:06:03 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.132 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -543,7 +543,7 @@ int cx, cy; cc.x = cx; cc.y = cy; - if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) { + if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch, (struct permonst **)0)) { (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords); custompline(SUPPRESS_HISTORY, "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf, @@ -593,7 +593,8 @@ int gloc; any.a_int = i + 1; tmpcc.x = garr[i].x; tmpcc.y = garr[i].y; - if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, &firstmatch)) { + if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, + &firstmatch, (struct permonst **)0)) { (void) coord_desc(garr[i].x, garr[i].y, tmpbuf, iflags.getpos_coords); Sprintf(fullbuf, "%s%s%s", firstmatch, @@ -1699,10 +1700,7 @@ boolean called; if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind && !Hallucination) Strcat(buf, "saddled "); - if (buf[0] != 0) - has_adjectives = TRUE; - else - has_adjectives = FALSE; + has_adjectives = (buf[0] != '\0'); /* Put the actual monster name or type into the buffer now */ /* Be sure to remember whether the buffer starts with a name */ @@ -2067,6 +2065,46 @@ char *buf; return buf; } +char * +rndorcname(s) +char *s; +{ + int i; + const char *v[] = {"a", "ai", "og", "u"}; + const char *snd[] = {"gor", "gris", "un", "bane", "ruk", + "oth","ul", "z", "thos","akh","hai"}; + int vstart = rn2(2); + + if (s) { + *s = '\0'; + for (i = 0; i < rn2(2) + 3; ++i) { + vstart = 1 - vstart; /* 0 -> 1, 1 -> 0 */ + if (!rn2(30) && i > 0) + (void) strcat(s, "-"); + (void) sprintf(eos(s), "%s", vstart ? v[rn2(SIZE(v))] : + snd[rn2(SIZE(snd))]); + } + } + return s; +} + +struct monst * +christen_orc(mtmp, gang) +struct monst *mtmp; +char *gang; +{ + int sz = 0; + char buf[BUFSZ], buf2[BUFSZ], *orcname; + + orcname = rndorcname(buf2); + sz = (int) (strlen(gang) + strlen(orcname) + sizeof " of " - sizeof ""); + if (gang && orcname && sz < BUFSZ) { + Sprintf(buf, "%s of %s", upstart(orcname), upstart(gang)); + mtmp = christen_monst(mtmp, buf); + } + return mtmp; +} + /* make sure "The Colour of Magic" remains the first entry in here */ static const char *const sir_Terry_novels[] = { "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort", diff --git a/src/dog.c b/src/dog.c index 4bcdd7722..46cd832ef 100644 --- a/src/dog.c +++ b/src/dog.c @@ -407,6 +407,12 @@ boolean with_you; break; } + if ((mtmp->mspare1 & MIGR_LEFTOVERS) != 0L) { + /* Pick up the rest of the MIGR_TO_SPECIES objects */ + if (migrating_objs) + deliver_obj_to_mon(mtmp, DF_ALL); + } + if (xlocale && wander) { /* monster moved a bit; pick a nearby location */ /* mnearto() deals w/stone, et al */ diff --git a/src/dokick.c b/src/dokick.c index 950d03553..b2d36de70 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -495,7 +495,7 @@ xchar x, y; return 0; if ((trap = t_at(x, y)) != 0) { - if (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls) + if ((is_pit(trap->ttyp) && !Passes_walls) || trap->ttyp == WEB) { if (!trap->tseen) find_trap(trap); @@ -1515,7 +1515,7 @@ boolean shop_floor_obj; /* boulders never fall through trap doors, but they might knock other things down before plugging the hole */ if (otmp->otyp == BOULDER && ((t = t_at(x, y)) != 0) - && (t->ttyp == TRAPDOOR || t->ttyp == HOLE)) { + && is_hole(t->ttyp)) { if (impact) impact_drop(otmp, x, y, 0); return FALSE; /* let caller finish the drop */ @@ -1612,6 +1612,9 @@ boolean near_hero; continue; where = (int) (otmp->owornmask & 0x7fffL); /* destination code */ + if ((where & MIGR_TO_SPECIES) != 0) + continue; + nobreak = (where & MIGR_NOBREAK) != 0; noscatter = (where & MIGR_WITH_HERO) != 0; where &= ~(MIGR_NOBREAK | MIGR_NOSCATTER); @@ -1667,6 +1670,48 @@ boolean near_hero; } } +void +deliver_obj_to_mon(mtmp, deliverflags) +struct monst *mtmp; +unsigned long deliverflags; +{ + struct obj *otmp, *otmp2; + int where, cnt = 0, maxobj = 0; + + if (deliverflags & DF_RANDOM3) + maxobj = rn2(3) + 1; + else if (deliverflags & DF_RANDOM2) + maxobj = rn2(2) + 1; + else if (deliverflags == DF_NONE) + maxobj = 1; + + for (otmp = migrating_objs; otmp; otmp = otmp2) { + otmp2 = otmp->nobj; + where = (int) (otmp->owornmask & 0x7fffL); /* destination code */ + if ((where & MIGR_TO_SPECIES) == 0) + continue; + + if ((mtmp->data->mflags2 & otmp->corpsenm) != 0) { + obj_extract_self(otmp); + otmp->owornmask = 0L; + otmp->ox = otmp->oy = 0; + + /* special treatment for orcs and their kind */ + if ((otmp->corpsenm & M2_ORC) != 0 && has_oname(otmp)) { + if (!has_mname(mtmp)) + mtmp = christen_orc(mtmp, ONAME(otmp)); + free_oname(otmp); + } + otmp->corpsenm = 0; + (void) add_to_minv(mtmp, otmp); + cnt++; + if (maxobj && cnt >= maxobj) + break; + /* getting here implies DF_ALL */ + } + } +} + STATIC_OVL void otransit_msg(otmp, nodrop, num) register struct obj *otmp; @@ -1717,7 +1762,7 @@ xchar x, y; } if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen) - && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)) { + && is_hole(ttmp->ttyp)) { gate_str = (ttmp->ttyp == TRAPDOOR) ? "through the trap door" : "through the hole"; return MIGR_RANDOM; diff --git a/src/dothrow.c b/src/dothrow.c index b9d122a7d..00978165f 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -744,8 +744,7 @@ int x, y; dotrap(ttmp, 0); /* doesn't print messages */ } else if (ttmp->ttyp == FIRE_TRAP) { dotrap(ttmp, 0); - } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT - || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) + } else if ((is_pit(ttmp->ttyp) || is_hole(ttmp->ttyp)) && Sokoban) { /* air currents overcome the recoil in Sokoban; when jumping, caller performs last step and enters trap */ diff --git a/src/end.c b/src/end.c index 4d176323b..fd5d73db9 100644 --- a/src/end.c +++ b/src/end.c @@ -1280,7 +1280,7 @@ int how; if (WIN_INVEN != WIN_ERR) { destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR; /* precaution in case any late update_inventory() calls occur */ - flags.perm_invent = 0; + iflags.perm_invent = 0; } display_nhwindow(WIN_MESSAGE, TRUE); destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR; diff --git a/src/hack.c b/src/hack.c index cb92b93ad..70671b45f 100644 --- a/src/hack.c +++ b/src/hack.c @@ -151,8 +151,7 @@ moverock() if (mtmp && !noncorporeal(mtmp->data) && (!mtmp->mtrapped - || !(ttmp && ((ttmp->ttyp == PIT) - || (ttmp->ttyp == SPIKED_PIT))))) { + || !(ttmp && is_pit(ttmp->ttyp)))) { if (Blind) feel_location(sx, sy); if (canspotmon(mtmp)) { @@ -1205,7 +1204,7 @@ struct trap *desttrap; /* nonnull if another trap at */ break; case TT_PIT: if (desttrap && desttrap->tseen - && (desttrap->ttyp == PIT || desttrap->ttyp == SPIKED_PIT)) + && is_pit(desttrap->ttyp)) return TRUE; /* move into adjacent pit */ /* try to escape; position stays same regardless of success */ climb_pit(); @@ -1736,7 +1735,7 @@ domove() u.ux = mtmp->mx, u.uy = mtmp->my; /* resume swapping positions */ if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0 - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) + && is_pit(trap->ttyp) && sobj_at(BOULDER, trap->tx, trap->ty)) { /* can't swap places with pet pinned in a pit by a boulder */ u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ @@ -2100,7 +2099,7 @@ boolean pick; * If not a pit, pickup before triggering trap. * If pit, trigger trap before pickup. */ - pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)); + pit = (trap && is_pit(trap->ttyp)); if (pick && !pit) (void) pickup(1); diff --git a/src/invent.c b/src/invent.c index 25280839b..4262a5153 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2511,7 +2511,7 @@ long *out_cnt; if (lets && !*lets) lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */ - if (flags.perm_invent && (lets || xtra_choice)) { + if (iflags.perm_invent && (lets || xtra_choice)) { /* partial inventory in perm_invent setting; don't operate on full inventory window, use an alternate one instead; create the first time needed and keep it for re-use as needed later */ @@ -2536,7 +2536,7 @@ long *out_cnt; * more than 1; for the last one, we don't need a precise number. * For perm_invent update we force 'more than 1'. */ - n = (flags.perm_invent && !lets && !want_reply) ? 2 + n = (iflags.perm_invent && !lets && !want_reply) ? 2 : lets ? (int) strlen(lets) : !invent ? 0 : !invent->nobj ? 1 : 2; /* for xtra_choice, there's another 'item' not included in initial 'n'; @@ -2670,7 +2670,7 @@ nextclass: nothing has been listed (because there isn't anyhing to list; recognized via any.a_char still being zero; the n==0 case above gets skipped for perm_invent), put something into the menu */ - if (flags.perm_invent && !lets && !any.a_char) { + if (iflags.perm_invent && !lets && !any.a_char) { any = zeroany; add_menu(win, NO_GLYPH, &any, 0, 0, 0, not_carrying_anything, MENU_UNSELECTED); diff --git a/src/makemon.c b/src/makemon.c index 0d38383dc..55dc7b49d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 makemon.c $NHDT-Date: 1495237801 2017/05/19 23:50:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.116 $ */ +/* NetHack 3.6 makemon.c $NHDT-Date: 1537477761 2018/09/20 21:09:21 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.124 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1390,6 +1390,9 @@ int mmflags; mtmp->mstrategy |= STRAT_APPEARMSG; } + if (allow_minvent && migrating_objs) + deliver_obj_to_mon(mtmp, DF_RANDOM2); /* in case there's waiting items */ + if (!in_mklev) newsym(mtmp->mx, mtmp->my); /* make sure the mon shows up */ @@ -1834,7 +1837,7 @@ struct monst *mtmp, *victim; slightly less sexist if prepared for it...) */ : (fem && !mtmp->female) ? "female " : "", ptr->mname); - pline("%s %s %s.", Monnam(mtmp), + pline("%s %s %s.", upstart(y_monnam(mtmp)), (fem != mtmp->female) ? "changes into" : humanoid(ptr) ? "becomes" : "grows up into", diff --git a/src/mhitm.c b/src/mhitm.c index 3b0f11855..95413843c 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1268,6 +1268,9 @@ register struct attack *mattk; mwepgone(mdef); otmp->owornmask = 0L; update_mon_intrinsics(mdef, otmp, FALSE, FALSE); + /* give monster a chance to wear other equipment on its next + move instead of waiting until it picks something up */ + mdef->misc_worn_check |= I_SPECIAL; } /* add_to_minv() might free otmp [if it merges] */ if (vis) diff --git a/src/mhitu.c b/src/mhitu.c index c429a0241..97229ba60 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1744,7 +1744,7 @@ struct attack *mattk; if (!engulf_target(mtmp, &youmonst)) return 0; - if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT))) + if ((t && is_pit(t->ttyp)) && sobj_at(BOULDER, u.ux, u.uy)) return 0; diff --git a/src/mklev.c b/src/mklev.c index f704db27d..aecba88fa 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -503,8 +503,7 @@ int trap_type; if (trap_type || !rn2(4)) { rm->typ = SCORR; if (trap_type) { - if ((trap_type == HOLE || trap_type == TRAPDOOR) - && !Can_fall_thru(&u.uz)) + if (is_hole(trap_type) && !Can_fall_thru(&u.uz)) trap_type = ROCKTRAP; ttmp = maketrap(xx, yy + dy, trap_type); if (ttmp) { @@ -1342,15 +1341,14 @@ coord *tm; } while (kind == NO_TRAP); } - if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz)) + if (is_hole(kind) && !Can_fall_thru(&u.uz)) kind = ROCKTRAP; if (tm) { m = *tm; } else { register int tryct = 0; - boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT - || kind == TRAPDOOR || kind == HOLE); + boolean avoid_boulder = (is_pit(kind) || is_hole(kind)); do { if (++tryct > 200) @@ -1390,7 +1388,7 @@ coord *tm; in a pit and yet not be able to identify that the pit is there. */ if (lvl <= (unsigned) rnd(4) && kind != SQKY_BOARD && kind != RUST_TRAP - && kind != PIT && kind != SPIKED_PIT && kind < HOLE) { + && !is_pit(kind) && kind < HOLE) { /* Object generated by the trap; initially NULL, stays NULL if we fail to generate an object or if the trap doesn't generate objects. */ diff --git a/src/mkmaze.c b/src/mkmaze.c index 22fb42d03..8282205f8 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkmaze.c $NHDT-Date: 1518718417 2018/02/15 18:13:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.55 $ */ +/* NetHack 3.6 mkmaze.c $NHDT-Date: 1537477570 2018/09/20 21:06:10 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.61 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -25,6 +25,10 @@ STATIC_DCL boolean FDECL(put_lregion_here, (XCHAR_P, XCHAR_P, XCHAR_P, STATIC_DCL void NDECL(baalz_fixup); STATIC_DCL void NDECL(setup_waterlevel); STATIC_DCL void NDECL(unsetup_waterlevel); +STATIC_DCL void FDECL(check_ransacked, (char *)); +STATIC_DCL void FDECL(migr_booty_item, (int, const char *)); +STATIC_DCL void FDECL(migrate_orc, (struct monst *, unsigned long)); +STATIC_DCL void NDECL(stolen_booty); /* adjust a coordinate one step in the specified direction */ #define mz_move(X, Y, dir) \ @@ -610,6 +614,8 @@ fixup_special() } else if (on_level(&u.uz, &baalzebub_level)) { /* custom wallify the "beetle" potion of the level */ baalz_fixup(); + } else if (u.uz.dnum == mines_dnum && ransacked) { + stolen_booty(); } if (lregions) @@ -617,6 +623,149 @@ fixup_special() num_lregions = 0; } +void +check_ransacked(s) +char *s; +{ + /* this kludge only works as long as orctown is minetn-1 */ + ransacked = (u.uz.dnum == mines_dnum && !strcmp(s, "minetn-1")); +} + +#define ORC_LEADER 1 + +void +migrate_orc(mtmp, mflags) +struct monst *mtmp; +unsigned long mflags; +{ + int nlev, max_depth, cur_depth; + d_level dest; + + cur_depth = (int) depth(&u.uz); + max_depth = dunlevs_in_dungeon(&u.uz) + + (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 + * orcs between here and the bottom of the mines. + */ + nlev = max_depth; + mtmp->mspare1 = MIGR_LEFTOVERS; + } else { + nlev = rn2(max_depth - cur_depth) + cur_depth + 1; + if (nlev == cur_depth) + nlev++; + if (nlev > max_depth) + nlev = max_depth; + mtmp->mspare1 = 0L; + } + get_level(&dest, nlev); + migrate_to_level(mtmp, ledger_no(&dest), MIGR_RANDOM, (coord *) 0); +} + +void +migr_booty_item(otyp, gang) +int otyp; +const char *gang; +{ + struct obj *otmp; + otmp = mksobj_migr_to_species(otyp, (unsigned long) M2_ORC, FALSE, FALSE); + if (otmp && gang) { + new_oname(otmp, strlen(gang) + 1); /* removes old name if one is present */ + Strcpy(ONAME(otmp), gang); + if (otyp >= TRIPE_RATION && otyp <= TIN) + otmp->quan += (long) rn2(3); + } +} + +void +stolen_booty(VOID_ARGS) +{ + char *gang, gang_name[BUFSZ]; + struct monst *mtmp; + int cnt, i, otyp; + + /* + * -------------------------------------------------------- + * Mythos: + * + * A tragic accident has occurred in Frontier Town... + * It has been overrun by orcs. + * + * The booty that the orcs took from the town is now + * in the possession of the orcs that did this and + * have long since fled the level. + * -------------------------------------------------------- + */ + + gang = rndorcname(gang_name); + /* create the leader of the orc gang */ + mtmp = makemon(&mons[PM_ORC_CAPTAIN], 0, 0, MM_NONAME); + if (mtmp) { + mtmp = christen_monst(mtmp, upstart(gang)); + mtmp->mpeaceful = 0; + migrate_orc(mtmp, ORC_LEADER); + } + /* create the stuff that the rest of the gang took */ + migr_booty_item(rn2(2) ? LONG_SWORD : SILVER_SABER, gang); + cnt = rn2(3) + 1; + for (i = 0; i < cnt; ++i) + migr_booty_item(rn2(4) ? TALLOW_CANDLE : WAX_CANDLE, gang); + cnt = rn2(2) + 1; + for (i = 0; i < cnt; ++i) + migr_booty_item(SKELETON_KEY, gang); + otyp = rn2((GAUNTLETS_OF_DEXTERITY - LEATHER_GLOVES) + 1) + LEATHER_GLOVES; + migr_booty_item(otyp, gang); + cnt = rn2(9) + 1; + for (i = 0; i < cnt; ++i) { + /* Food items - but no lembas! (or some other weird things) */ + otyp = rn2((TIN - TRIPE_RATION) + 1) + TRIPE_RATION; + if (otyp != LEMBAS_WAFER && otyp != GLOB_OF_GRAY_OOZE && + otyp != GLOB_OF_BROWN_PUDDING && otyp != GLOB_OF_GREEN_SLIME && + otyp != GLOB_OF_BLACK_PUDDING && otyp != MEAT_STICK && + otyp != MEATBALL && otyp != MEAT_STICK && otyp != MEAT_RING && + otyp != HUGE_CHUNK_OF_MEAT && otyp != CORPSE) + migr_booty_item(otyp, gang); + } + /* Make most of the orcs on the level be part of the invading gang */ + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; + + if (is_orc(mtmp->data) && !has_mname(mtmp) && rn2(10)) { + /* + * We'll consider the orc captain from the level + * .des file to be the captain of a rival orc horde + * who is there to see what has transpired, and to + * contemplate future action. + * + * Don't christen the orc captain as a subordinate + * member of the main orc horde. + */ + if (mtmp->data != &mons[PM_ORC_CAPTAIN]) + mtmp = christen_orc(mtmp, upstart(gang)); + } + } + /* Lastly, ensure there's several more orcs from the gang along the way. + * The mechanics are such that they aren't actually identified as + * members of the invading gang until they get their spoils assigned + * to the inventory; handled during that assignment. + */ + cnt = rn2(7) + 5; + for (i = 0; i < cnt; ++i) { + int mtyp; + + mtyp = rn2((PM_ORC_SHAMAN - PM_ORC) + 1) + PM_ORC; + mtmp = makemon(&mons[mtyp], 0, 0, MM_NONAME); + if (mtmp) + migrate_orc(mtmp, 0UL); + } + + ransacked = 0; +} + +#undef ORC_LEADER + boolean maze_inbounds(x, y) int x, y; @@ -819,6 +968,7 @@ const char *s; } if (*protofile) { + check_ransacked(protofile); Strcat(protofile, LEV_EXT); if (load_special(protofile)) { /* some levels can end up with monsters diff --git a/src/mkobj.c b/src/mkobj.c index cf7a77233..558be1dc6 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -224,6 +224,23 @@ boolean init, artif; return otmp; } +struct obj * +mksobj_migr_to_species(otyp, mflags2, init, artif) +int otyp; +unsigned mflags2; +boolean init, artif; +{ + struct obj *otmp; + + otmp = mksobj(otyp, init, artif); + if (otmp) { + add_to_migration(otmp); + otmp->owornmask = (long) MIGR_TO_SPECIES; + otmp->corpsenm = mflags2; + } + return otmp; +} + /* mkobj(): select a type of item from a class, use mksobj() to create it */ struct obj * mkobj(oclass, artif) diff --git a/src/mon.c b/src/mon.c index 39e777a26..9cdf9b6d9 100644 --- a/src/mon.c +++ b/src/mon.c @@ -731,6 +731,17 @@ movemon() if (minliquid(mtmp)) continue; + /* after losing equipment, try to put on replacement */ + if (mtmp->misc_worn_check & I_SPECIAL) { + long oldworn; + + mtmp->misc_worn_check &= ~I_SPECIAL; + oldworn = mtmp->misc_worn_check; + m_dowear(mtmp, FALSE); + if (mtmp->misc_worn_check != oldworn || !mtmp->mcanmove) + continue; + } + if (is_hider(mtmp->data)) { /* unwatched mimics and piercers may hide again [MRS] */ if (restrap(mtmp)) @@ -1435,8 +1446,7 @@ nexttry: /* eels prefer the water, but if there is no water nearby, if ((ttmp->ttyp != RUST_TRAP || mdat == &mons[PM_IRON_GOLEM]) && ttmp->ttyp != STATUE_TRAP - && ((ttmp->ttyp != PIT && ttmp->ttyp != SPIKED_PIT - && ttmp->ttyp != TRAPDOOR && ttmp->ttyp != HOLE) + && ((!is_pit(ttmp->ttyp) && !is_hole(ttmp->ttyp)) || (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) || Sokoban) && (ttmp->ttyp != SLP_GAS_TRAP || !resists_sleep(mon)) @@ -1796,6 +1806,8 @@ struct monst *mtmp; pline_The("medallion crumbles to dust!"); } m_useup(mtmp, lifesave); + /* equip replacement amulet, if any, on next move */ + mtmp->misc_worn_check |= I_SPECIAL; surviver = !(mvitals[monsndx(mtmp->data)].mvflags & G_GENOD); mtmp->mcanmove = 1; @@ -1806,13 +1818,14 @@ struct monst *mtmp; if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; mtmp->mhp = mtmp->mhpmax; - if (surviver) - return; - /* genocided monster can't be life-saved */ - if (cansee(mtmp->mx, mtmp->my)) - pline("Unfortunately, %s is still genocided...", mon_nam(mtmp)); - mtmp->mhp = 0; + if (!surviver) { + /* genocided monster can't be life-saved */ + if (cansee(mtmp->mx, mtmp->my)) + pline("Unfortunately, %s is still genocided...", + mon_nam(mtmp)); + mtmp->mhp = 0; + } } } @@ -2242,7 +2255,7 @@ int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */ } if (mtmp->mtrapped && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { + && is_pit(t->ttyp)) { if (sobj_at(BOULDER, x, y)) nocorpse = TRUE; /* Prevent corpses/treasure being created "on top" of boulder that is about to fall in. @@ -2887,7 +2900,8 @@ restartcham() for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - mtmp->cham = pm_to_cham(monsndx(mtmp->data)); + if (!mtmp->mcan) + mtmp->cham = pm_to_cham(monsndx(mtmp->data)); if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping && cansee(mtmp->mx, mtmp->my)) { set_mimic_sym(mtmp); @@ -2929,7 +2943,7 @@ register struct monst *mtmp; || rn2(3) || mtmp == u.ustuck /* can't hide while trapped except in pits */ || (mtmp->mtrapped && (t = t_at(mtmp->mx, mtmp->my)) != 0 - && !(t->ttyp == PIT || t->ttyp == SPIKED_PIT)) + && !is_pit(t->ttyp)) || (sensemon(mtmp) && distu(mtmp->mx, mtmp->my) <= 2)) return FALSE; @@ -2957,7 +2971,7 @@ struct monst *mtmp; ; /* can't hide if holding you or held by you */ } else if (is_u ? (u.utrap && u.utraptype != TT_PIT) : (mtmp->mtrapped && (t = t_at(x, y)) != 0 - && !(t->ttyp == PIT || t->ttyp == SPIKED_PIT))) { + && !is_pit(t->ttyp))) { ; /* can't hide while stuck in a non-pit trap */ } else if (mtmp->data->mlet == S_EEL) { undetected = (is_pool(x, y) && !Is_waterlevel(&u.uz)); @@ -3404,6 +3418,13 @@ boolean msg; /* "The oldmon turns into a newmon!" */ anomalous extinction feedback during final disclsoure */ if (mbirth_limit(monsndx(olddata)) < MAXMONNO) return 0; + /* cancelled shapechangers become uncancelled prior + to being given a new shape */ + if (mtmp->mcan && !Protection_from_shape_changers) { + mtmp->cham = pm_to_cham(monsndx(mtmp->data)); + if (mtmp->cham != NON_PM) + mtmp->mcan = 0; + } } if (msg) { diff --git a/src/mthrowu.c b/src/mthrowu.c index e2ec346aa..28a979940 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -126,7 +126,7 @@ int x, y; if (create && !((mtmp = m_at(x, y)) != 0 && mtmp->mtrapped && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT))) { + && is_pit(t->ttyp))) { int objgone = 0; if (down_gate(x, y) != -1) diff --git a/src/muse.c b/src/muse.c index e0403003b..600bdd903 100644 --- a/src/muse.c +++ b/src/muse.c @@ -439,7 +439,7 @@ struct monst *mtmp; || onscary(xx, yy, mtmp)) continue; /* use trap if it's the correct type */ - if ((t->ttyp == TRAPDOOR || t->ttyp == HOLE) + if (is_hole(t->ttyp) && !is_floater(mtmp->data) && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest && Can_fall_thru(&u.uz)) { @@ -489,7 +489,7 @@ struct monst *mtmp; /* kludge to cut down on trap destruction (particularly portals) */ t = t_at(x, y); - if (t && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == WEB + if (t && (is_pit(t->ttyp) || t->ttyp == WEB || t->ttyp == BEAR_TRAP)) t = 0; /* ok for monster to dig here */ diff --git a/src/music.c b/src/music.c index 24e1c559e..71253f6e1 100644 --- a/src/music.c +++ b/src/music.c @@ -249,7 +249,7 @@ int force; unsigned tu_pit = 0; if (trap_at_u) - tu_pit = (trap_at_u->ttyp == PIT || trap_at_u->ttyp == SPIKED_PIT); + tu_pit = is_pit(trap_at_u->ttyp); start_x = u.ux - (force * 2); start_y = u.uy - (force * 2); end_x = u.ux + (force * 2); diff --git a/src/objects.c b/src/objects.c index 0809ff41a..fcca3b0f7 100644 --- a/src/objects.c +++ b/src/objects.c @@ -368,7 +368,7 @@ HELM("helm of telepathy", "visored helmet", * There is code in obj.h, objnam.c, mon.c, read.c that assumes (2). * (1) The dragon scale mails and the dragon scales are together. * (2) That the order of the dragon scale mail and dragon scales - * is the the same as order of dragons defined in monst.c. + * is the same as order of dragons defined in monst.c. */ #define DRGN_ARMR(name,mgc,power,cost,ac,color) \ ARMOR(name, None, 1, mgc, 1, power, 0, 5, 40, \ diff --git a/src/objnam.c b/src/objnam.c index b44ddbf2e..6588b7f9a 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objnam.c $NHDT-Date: 1533352036 2018/08/04 03:07:16 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.206 $ */ +/* NetHack 3.6 objnam.c $NHDT-Date: 1537313446 2018/09/18 23:30:46 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.208 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3204,6 +3204,11 @@ struct obj *no_wish; typ = SPE_BLANK_PAPER; goto typfnd; } + /* specific food rather than color of gem/potion/spellbook[/scales] */ + if (!BSTRCMPI(bp, p - 6, "orange") && mntmp == NON_PM) { + typ = ORANGE; + goto typfnd; + } /* * NOTE: Gold pieces are handled as objects nowadays, and therefore * this section should probably be reconsidered as well as the entire @@ -3508,7 +3513,7 @@ wiztrap: if (strncmpi(tname, bp, strlen(tname))) continue; /* found it; avoid stupid mistakes */ - if ((trap == TRAPDOOR || trap == HOLE) && !Can_fall_thru(&u.uz)) + if (is_hole(trap) && !Can_fall_thru(&u.uz)) trap = ROCKTRAP; if ((t = maketrap(x, y, trap)) != 0) { trap = t->ttyp; diff --git a/src/options.c b/src/options.c index a283f4283..490d68a0a 100644 --- a/src/options.c +++ b/src/options.c @@ -173,7 +173,8 @@ static struct Bool_Opt { #else { "page_wait", (boolean *) 0, FALSE, SET_IN_FILE }, #endif - { "perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME }, + /* 3.6.2: move perm_invent from flags to inflags and out of save file */ + { "perm_invent", &iflags.perm_invent, FALSE, SET_IN_GAME }, { "pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME }, { "popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME }, /*WC*/ { "preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME }, /*WC*/ diff --git a/src/pager.c b/src/pager.c index d44efb795..4515ea8e8 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pager.c $NHDT-Date: 1523142395 2018/04/07 23:06:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.123 $ */ +/* NetHack 3.6 pager.c $NHDT-Date: 1537477571 2018/09/20 21:06:11 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.129 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -16,8 +16,9 @@ STATIC_DCL void FDECL(look_at_monster, (char *, char *, struct monst *, int, int)); STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *)); STATIC_DCL void FDECL(checkfile, (char *, struct permonst *, - BOOLEAN_P, BOOLEAN_P)); + BOOLEAN_P, BOOLEAN_P, char *)); STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P)); +STATIC_DCL void FDECL(do_supplemental_info, (char *, struct permonst *,BOOLEAN_P)); STATIC_DCL void NDECL(whatdoes_help); STATIC_DCL void NDECL(docontact); STATIC_DCL void NDECL(dispfile_help); @@ -279,7 +280,7 @@ int x, y; int tt = t ? t->ttyp : NO_TRAP; /* newsym lets you know of the trap, so mention it here */ - if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT || tt == WEB) + if (tt == BEAR_TRAP || is_pit(tt) || tt == WEB) Sprintf(eos(buf), ", trapped in %s", an(defsyms[trap_to_defsym(tt)].explanation)); } @@ -509,10 +510,11 @@ char *buf, *monbuf; * Therefore, we create a copy of inp _just_ for data.base lookup. */ STATIC_OVL void -checkfile(inp, pm, user_typed_name, without_asking) +checkfile(inp, pm, user_typed_name, without_asking, supplemental_name) char *inp; struct permonst *pm; boolean user_typed_name, without_asking; +char *supplemental_name; { dlb *fp; char buf[BUFSZ], newstr[BUFSZ], givenname[BUFSZ]; @@ -619,7 +621,7 @@ boolean user_typed_name, without_asking; int chk_skip, pass = 1; boolean yes_to_moreinfo, found_in_file, pass1found_in_file, skipping_entry; - char *ap, *alt = 0; /* alternate description */ + char *sp, *ap, *alt = 0; /* alternate description */ /* adjust the input to remove "named " and "called " */ if ((ep = strstri(dbase_str, " named ")) != 0) { @@ -629,6 +631,8 @@ boolean user_typed_name, without_asking; } else if ((ep = strstri(dbase_str, " called ")) != 0) { copynchars(givenname, ep + 8, BUFSZ - 1); alt = givenname; + if (supplemental_name && (sp = strstri(inp, " called ")) != 0) + copynchars(supplemental_name, sp + 8, BUFSZ - 1); } else ep = strstri(dbase_str, ", "); if (ep && ep > dbase_str) @@ -760,12 +764,13 @@ boolean user_typed_name, without_asking; } int -do_screen_description(cc, looked, sym, out_str, firstmatch) +do_screen_description(cc, looked, sym, out_str, firstmatch, for_supplement) coord cc; boolean looked; int sym; char *out_str; const char **firstmatch; +struct permonst **for_supplement; { static const char mon_interior[] = "the interior of a monster", unreconnoitered[] = "unreconnoitered"; @@ -1008,11 +1013,15 @@ const char **firstmatch; didlook: if (looked) { + struct permonst *pm = (struct permonst *)0; + if (found > 1 || need_to_look) { char monbuf[BUFSZ]; char temp_buf[BUFSZ]; - (void) lookat(cc.x, cc.y, look_buf, monbuf); + pm = lookat(cc.x, cc.y, look_buf, monbuf); + if (pm && for_supplement) + *for_supplement = pm; *firstmatch = look_buf; if (*(*firstmatch)) { Sprintf(temp_buf, " (%s)", *firstmatch); @@ -1043,7 +1052,7 @@ coord *click_cc; boolean clicklook = (mode == 2); /* right mouse-click method */ char out_str[BUFSZ] = DUMMY; const char *firstmatch = 0; - struct permonst *pm = 0; + struct permonst *pm = 0, *supplemental_pm = 0; int i = '\0', ans = 0; int sym; /* typed symbol or converted glyph */ int found; /* count of matching syms found */ @@ -1137,7 +1146,7 @@ coord *click_cc; break; } if (*out_str) - checkfile(out_str, pm, TRUE, TRUE); + checkfile(out_str, pm, TRUE, TRUE, (char *) 0); return 0; } case '?': @@ -1151,7 +1160,7 @@ coord *click_cc; return 0; if (out_str[1]) { /* user typed in a complete string */ - checkfile(out_str, pm, TRUE, TRUE); + checkfile(out_str, pm, TRUE, TRUE, (char *) 0); return 0; } sym = out_str[0]; @@ -1204,7 +1213,7 @@ coord *click_cc; } found = do_screen_description(cc, (from_screen || clicklook), sym, - out_str, &firstmatch); + out_str, &firstmatch, &supplemental_pm); /* Finally, print out our explanation. */ if (found) { @@ -1215,16 +1224,19 @@ coord *click_cc; if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE && (ans == LOOK_VERBOSE || (flags.help && !quick)) && !clicklook) { - char temp_buf[BUFSZ]; + char temp_buf[BUFSZ], supplemental_name[BUFSZ]; + supplemental_name[0] = '\0'; Strcpy(temp_buf, firstmatch); checkfile(temp_buf, pm, FALSE, - (boolean) (ans == LOOK_VERBOSE)); + (boolean) (ans == LOOK_VERBOSE), supplemental_name); + if (supplemental_pm) + do_supplemental_info(supplemental_name, supplemental_pm, + (boolean) (ans == LOOK_VERBOSE)); } } else { pline("I've never heard of such things."); } - } while (from_screen && !quick && ans != LOOK_ONCE && !clicklook); flags.verbose = save_verbose; @@ -1319,6 +1331,69 @@ boolean do_mons; /* True => monsters, False => objects */ destroy_nhwindow(win); } +void +do_supplemental_info(name, pm, without_asking) +char *name; +struct permonst *pm; +boolean without_asking; +{ + winid datawin = WIN_ERR; + char *entrytext = name, *bp; + char question[QBUFSZ]; + boolean yes_to_moreinfo = FALSE; + + /* + * Provide some info on some specific things + * meant to support in-game mythology, and not + * available from data.base or other sources. + */ + if (name && pm && is_orc(pm) && + (strlen(name) < (BUFSZ - 1)) && + (bp = strstri(name, " of ")) != 0) { + char fullname[BUFSZ]; + + Strcpy(fullname, name); + if (!without_asking) { + Strcpy(question, "More info about \""); + /* +2 => length of "\"?" */ + copynchars(eos(question), entrytext, + (int) (sizeof question - 1 - (strlen(question) + 2))); + Strcat(question, "\"?"); + if (yn(question) == 'y') + yes_to_moreinfo = TRUE; + } + if (yes_to_moreinfo) { + int i, subs = 0; + char *gang = bp + 4; + static const char *text[] = { + "%s is a member of a marauding horde of orcs", + "rumored to have brutally attacked and plundered the ordinarily", + "sheltered town that is located deep within The Gnomish Mines.", + "", + "The members of that vicious horde proudly and defiantly acclaim", + "their allegiance to their leader %s in their names.", + }; + + *bp = '\0'; + datawin = create_nhwindow(NHW_MENU); + for (i = 0; i < SIZE(text); i++) { + char buf[BUFSZ]; + const char *txt; + + if (strstri(text[i], "%s") != 0) { + Sprintf(buf, text[i], + subs++ ? gang : fullname); + txt = buf; + } else + txt = text[i]; + putstr(datawin, 0, txt); + } + display_nhwindow(datawin, FALSE); + destroy_nhwindow(datawin), datawin = WIN_ERR; + } + } +} + /* the '/' command */ int dowhatis() @@ -1362,8 +1437,7 @@ doidtrap() break; tt = trap->ttyp; if (u.dz) { - if (u.dz < 0 ? (tt == TRAPDOOR || tt == HOLE) - : tt == ROCKTRAP) + if (u.dz < 0 ? is_hole(tt) : tt == ROCKTRAP) break; } tt = what_trap(tt); diff --git a/src/pray.c b/src/pray.c index 8d4c5003d..5d0d456fc 100644 --- a/src/pray.c +++ b/src/pray.c @@ -921,7 +921,7 @@ aligntyp g_align; * - fix all of your problems; * - do you a gratuitous favor. * - * If you make it to the the last category, you roll randomly again + * If you make it to the last category, you roll randomly again * to see what they do for you. * * If your luck is at least 0, then you are guaranteed rescued from diff --git a/src/restore.c b/src/restore.c index f7e92da76..f638875b8 100644 --- a/src/restore.c +++ b/src/restore.c @@ -543,9 +543,12 @@ unsigned int *stuckid, *steedid; /* avoid keeping permanent inventory window up to date during restore (setworn() calls update_inventory); attempting to include the cost of unpaid items before shopkeeper's bill is available is a no-no; - named fruit names aren't accessible yet either */ - defer_perm_invent = flags.perm_invent; - flags.perm_invent = FALSE; + named fruit names aren't accessible yet either + [3.6.2: moved perm_invent from flags to iflags to keep it out of + save files; retaining the override here is simpler than trying to + to figure out where it really belongs now] */ + defer_perm_invent = iflags.perm_invent; + iflags.perm_invent = FALSE; /* wizard and discover are actually flags.debug and flags.explore; player might be overriding the save file values for them; in the discover case, we don't want to set that for a normal @@ -595,6 +598,7 @@ unsigned int *stuckid, *steedid; u.uz.dlevel = 1; /* revert to pre-restore option settings */ iflags.deferred_X = FALSE; + iflags.perm_invent = defer_perm_invent; flags = newgameflags; #ifdef SYSFLAGS sysflags = newgamesysflags; @@ -672,7 +676,7 @@ unsigned int *stuckid, *steedid; relink_timers(FALSE); relink_light_sources(FALSE); /* inventory display is now viable */ - flags.perm_invent = defer_perm_invent; + iflags.perm_invent = defer_perm_invent; return TRUE; } diff --git a/src/sp_lev.c b/src/sp_lev.c index af1cdc678..1d6b0cd3a 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2660,8 +2660,7 @@ fill_empty_maze() maze1xy(&mm, DRY); trytrap = rndtrap(); if (sobj_at(BOULDER, mm.x, mm.y)) - while (trytrap == PIT || trytrap == SPIKED_PIT - || trytrap == TRAPDOOR || trytrap == HOLE) + while (is_pit(trytrap) || is_hole(trytrap)) trytrap = rndtrap(); (void) maketrap(mm.x, mm.y, trytrap); } @@ -3828,7 +3827,7 @@ selection_do_grow(ov, dir) struct opvar *ov; int dir; { - int x, y, c; + int x, y; char tmp[COLNO][ROWNO]; if (ov->spovartyp != SPOVAR_SEL) @@ -3836,40 +3835,31 @@ int dir; if (!ov) return; - (void) memset(tmp, 0, sizeof(tmp)); + (void) memset(tmp, 0, sizeof tmp); - for (x = 0; x < COLNO; x++) + for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { - c = 0; - if ((dir & W_WEST) && (x > 0) - && (selection_getpoint(x - 1, y, ov))) - c++; - if ((dir & (W_WEST | W_NORTH)) && (x > 0) && (y > 0) - && (selection_getpoint(x - 1, y - 1, ov))) - c++; - if ((dir & W_NORTH) && (y > 0) - && (selection_getpoint(x, y - 1, ov))) - c++; - if ((dir & (W_NORTH | W_EAST)) && (y > 0) && (x < COLNO - 1) - && (selection_getpoint(x + 1, y - 1, ov))) - c++; - if ((dir & W_EAST) && (x < COLNO - 1) - && (selection_getpoint(x + 1, y, ov))) - c++; - if ((dir & (W_EAST | W_SOUTH)) && (x < COLNO - 1) - && (y < ROWNO - 1) && (selection_getpoint(x + 1, y + 1, ov))) - c++; - if ((dir & W_SOUTH) && (y < ROWNO - 1) - && (selection_getpoint(x, y + 1, ov))) - c++; - if ((dir & (W_SOUTH | W_WEST)) && (y < ROWNO - 1) && (x > 0) - && (selection_getpoint(x - 1, y + 1, ov))) - c++; - if (c) + /* note: dir is a mask of multiple directions, but the only + way to specify diagonals is by including the two adjacent + orthogonal directions, which effectively specifies three- + way growth [WEST|NORTH => WEST plus WEST|NORTH plus NORTH] */ + if (((dir & W_WEST) && selection_getpoint(x + 1, y, ov)) + || (((dir & (W_WEST | W_NORTH)) == (W_WEST | W_NORTH)) + && selection_getpoint(x + 1, y + 1, ov)) + || ((dir & W_NORTH) && selection_getpoint(x, y + 1, ov)) + || (((dir & (W_NORTH | W_EAST)) == (W_NORTH | W_EAST)) + && selection_getpoint(x - 1, y + 1, ov)) + || ((dir & W_EAST) && selection_getpoint(x - 1, y, ov)) + || (((dir & (W_EAST | W_SOUTH)) == (W_EAST | W_SOUTH)) + && selection_getpoint(x - 1, y - 1, ov)) + || ((dir & W_SOUTH) && selection_getpoint(x, y - 1, ov)) + || (((dir & (W_SOUTH | W_WEST)) == (W_SOUTH | W_WEST)) + && selection_getpoint(x + 1, y - 1, ov))) { tmp[x][y] = 1; + } } - for (x = 0; x < COLNO; x++) + for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (tmp[x][y]) selection_setpoint(x, y, ov, 1); @@ -4495,7 +4485,7 @@ ensure_way_out() while (ttmp) { if ((ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE - || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) + || is_hole(ttmp->ttyp)) && !selection_getpoint(ttmp->tx, ttmp->ty, ov)) selection_floodfill(ov, ttmp->tx, ttmp->ty, TRUE); ttmp = ttmp->ntrap; diff --git a/src/teleport.c b/src/teleport.c index a79429c46..5003ed82d 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1159,7 +1159,7 @@ int in_sight; d_level tolevel; int migrate_typ = MIGR_RANDOM; - if ((tt == HOLE || tt == TRAPDOOR)) { + if (is_hole(tt)) { if (Is_stronghold(&u.uz)) { assign_level(&tolevel, &valley_level); } else if (Is_botlevel(&u.uz)) { diff --git a/src/trap.c b/src/trap.c index 6e7e3ed78..f7d1d0bc9 100644 --- a/src/trap.c +++ b/src/trap.c @@ -7,6 +7,15 @@ extern const char *const destroy_strings[][3]; /* from zap.c */ +STATIC_DCL boolean FDECL(keep_saddle_with_steedcorpse, (unsigned, struct obj *, + struct obj *)); +STATIC_DCL struct obj *FDECL(t_missile, (int, struct trap *)); +STATIC_DCL char *FDECL(trapnote, (struct trap *, BOOLEAN_P)); +STATIC_DCL int FDECL(steedintrap, (struct trap *, struct obj *)); +STATIC_DCL void FDECL(launch_drop_spot, (struct obj *, XCHAR_P, XCHAR_P)); +STATIC_DCL int FDECL(mkroll_launch, (struct trap *, XCHAR_P, XCHAR_P, + SHORT_P, long)); +STATIC_DCL boolean FDECL(isclearpath, (coord *, int, SCHAR_P, SCHAR_P)); STATIC_DCL void FDECL(dofiretrap, (struct obj *)); STATIC_DCL void NDECL(domagictrap); STATIC_DCL boolean FDECL(emergency_disrobe, (boolean *)); @@ -18,26 +27,16 @@ STATIC_DCL int FDECL(disarm_holdingtrap, (struct trap *)); STATIC_DCL int FDECL(disarm_landmine, (struct trap *)); STATIC_DCL int FDECL(disarm_squeaky_board, (struct trap *)); STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int)); +STATIC_DCL void FDECL(clear_conjoined_pits, (struct trap *)); +STATIC_DCL boolean FDECL(adj_nonconjoined_pit, (struct trap *)); STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, BOOLEAN_P)); STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *)); -STATIC_DCL boolean FDECL(thitm, (int, struct monst *, struct obj *, int, - BOOLEAN_P)); -STATIC_DCL void FDECL(launch_drop_spot, (struct obj *, XCHAR_P, XCHAR_P)); -STATIC_DCL int FDECL(mkroll_launch, (struct trap *, XCHAR_P, XCHAR_P, - SHORT_P, long)); -STATIC_DCL boolean FDECL(isclearpath, (coord *, int, SCHAR_P, SCHAR_P)); -STATIC_DCL char *FDECL(trapnote, (struct trap *, BOOLEAN_P)); #if 0 STATIC_DCL void FDECL(join_adjacent_pits, (struct trap *)); #endif -STATIC_DCL void FDECL(clear_conjoined_pits, (struct trap *)); -STATIC_DCL boolean FDECL(adj_nonconjoined_pit, (struct trap *)); - -STATIC_DCL int FDECL(steedintrap, (struct trap *, struct obj *)); -STATIC_DCL boolean FDECL(keep_saddle_with_steedcorpse, (unsigned, - struct obj *, - struct obj *)); +STATIC_DCL boolean FDECL(thitm, (int, struct monst *, struct obj *, int, + BOOLEAN_P)); STATIC_DCL void NDECL(maybe_finish_sokoban); /* mintrap() should take a flags argument, but for time being we use this */ @@ -328,8 +327,7 @@ int x, y, typ; if (u.utrap && x == u.ux && y == u.uy && ((u.utraptype == TT_BEARTRAP && typ != BEAR_TRAP) || (u.utraptype == TT_WEB && typ != WEB) - || (u.utraptype == TT_PIT && typ != PIT - && typ != SPIKED_PIT))) + || (u.utraptype == TT_PIT && !is_pit(typ)))) u.utrap = 0; /* old remain valid */ } else if (IS_FURNITURE(lev->typ) @@ -407,8 +405,7 @@ int x, y, typ; case HOLE: case TRAPDOOR: if (*in_rooms(x, y, SHOPBASE) - && (typ == HOLE || typ == TRAPDOOR - || IS_DOOR(lev->typ) || IS_WALL(lev->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)) && !context.mon_moving) @@ -841,6 +838,21 @@ struct trap *trap; return FALSE; } +/* make a single arrow/dart/rock for a trap to shoot or drop */ +STATIC_OVL struct obj * +t_missile(otyp, trap) +int otyp; +struct trap *trap; +{ + struct obj *otmp = mksobj(otyp, TRUE, FALSE); + + otmp->quan = 1L; + otmp->owt = weight(otmp); + otmp->opoisoned = 0; + otmp->ox = trap->tx, otmp->oy = trap->ty; + return otmp; +} + void dotrap(trap, trflags) register struct trap *trap; @@ -862,8 +874,7 @@ unsigned trflags; nomul(0); /* KMH -- You can't escape the Sokoban level traps */ - if (Sokoban && (ttype == PIT || ttype == SPIKED_PIT - || ttype == HOLE || ttype == TRAPDOOR)) { + if (Sokoban && (is_pit(ttype) || is_hole(ttype))) { /* The "air currents" message is still appropriate -- even when * the hero isn't flying or levitating -- because it conveys the * reason why the player cannot escape the trap with a dexterity @@ -875,7 +886,7 @@ unsigned trflags; /* then proceed to normal trap effect */ } else if (already_seen && !forcetrap) { if ((Levitation || (Flying && !plunged)) - && (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE + && (is_pit(ttype) || ttype == HOLE || ttype == BEAR_TRAP)) { You("%s over %s %s.", Levitation ? "float" : "fly", a_your[trap->madeby_u], @@ -885,7 +896,7 @@ unsigned trflags; if (!Fumbling && ttype != MAGIC_PORTAL && ttype != VIBRATING_SQUARE && ttype != ANTI_MAGIC && !forcebungle && !plunged && !conj_pit && !adj_pit - && (!rn2(5) || ((ttype == PIT || ttype == SPIKED_PIT) + && (!rn2(5) || (is_pit(ttype) && is_clinger(youmonst.data)))) { You("escape %s %s.", (ttype == ARROW_TRAP && !trap->madeby_u) ? "an" @@ -914,12 +925,9 @@ unsigned trflags; trap->once = 1; seetrap(trap); pline("An arrow shoots out at you!"); - otmp = mksobj(ARROW, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); - otmp->opoisoned = 0; - if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */ - ; + otmp = t_missile(ARROW, trap); + if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { + ; /* nothing */ } else if (thitu(8, dmgval(otmp, &youmonst), &otmp, "arrow")) { if (otmp) obfree(otmp, (struct obj *) 0); @@ -942,14 +950,12 @@ unsigned trflags; trap->once = 1; seetrap(trap); pline("A little dart shoots out at you!"); - otmp = mksobj(DART, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); + otmp = t_missile(DART, trap); if (!rn2(6)) otmp->opoisoned = 1; oldumort = u.umortality; - if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */ - ; + if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { + ; /* nothing */ } else if (thitu(7, dmgval(otmp, &youmonst), &otmp, "little dart")) { if (otmp) { if (otmp->opoisoned) @@ -979,13 +985,11 @@ unsigned trflags; trap->once = 1; feeltrap(trap); - otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); + otmp = t_missile(ROCK, trap); + place_object(otmp, u.ux, u.uy); pline("A trap door in %s opens and %s falls on your %s!", the(ceiling(u.ux, u.uy)), an(xname(otmp)), body_part(HEAD)); - if (uarmh) { if (is_metallic(uarmh)) { pline("Fortunately, you are wearing a hard helmet."); @@ -994,7 +998,6 @@ unsigned trflags; pline("%s does not protect you.", Yname2(uarmh)); } } - if (!Blind) otmp->dknown = 1; stackobj(otmp); @@ -1642,7 +1645,7 @@ static struct { xchar x, y; } launchplace; -static void +STATIC_OVL void launch_drop_spot(obj, x, y) struct obj *obj; xchar x, y; @@ -2075,8 +2078,8 @@ register struct monst *mtmp; mtmp->mtrapped = 0; /* perhaps teleported? */ } else if (mtmp->mtrapped) { /* is currently in the trap */ if (!trap->tseen && cansee(mtmp->mx, mtmp->my) && canseemon(mtmp) - && (trap->ttyp == SPIKED_PIT || trap->ttyp == BEAR_TRAP - || trap->ttyp == HOLE || trap->ttyp == PIT + && (is_pit(trap->ttyp) || trap->ttyp == BEAR_TRAP + || trap->ttyp == HOLE || trap->ttyp == WEB)) { /* If you come upon an obviously trapped monster, then * you must be able to see the trap it's in too. @@ -2086,7 +2089,7 @@ register struct monst *mtmp; if (!rn2(40)) { if (sobj_at(BOULDER, mtmp->mx, mtmp->my) - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { + && is_pit(trap->ttyp)) { if (!rn2(2)) { mtmp->mtrapped = 0; if (canseemon(mtmp)) @@ -2150,10 +2153,7 @@ register struct monst *mtmp; break; } trap->once = 1; - otmp = mksobj(ARROW, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); - otmp->opoisoned = 0; + otmp = t_missile(ARROW, trap); if (in_sight) seetrap(trap); if (thitm(8, mtmp, otmp, 0, FALSE)) @@ -2169,9 +2169,7 @@ register struct monst *mtmp; break; } trap->once = 1; - otmp = mksobj(DART, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); + otmp = t_missile(DART, trap); if (!rn2(6)) otmp->opoisoned = 1; if (in_sight) @@ -2190,9 +2188,7 @@ register struct monst *mtmp; break; } trap->once = 1; - otmp = mksobj(ROCK, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); + otmp = t_missile(ROCK, trap); if (in_sight) seetrap(trap); if (thitm(0, mtmp, otmp, d(2, 6), FALSE)) @@ -2818,7 +2814,7 @@ int x, y; struct obj *otmp; struct trap *t; - if ((t = t_at(x, y)) && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)) + if ((t = t_at(x, y)) && is_pit(t->ttyp) && (otmp = sobj_at(BOULDER, x, y))) { obj_extract_self(otmp); (void) flooreffects(otmp, x, y, "settle"); @@ -2865,8 +2861,7 @@ long hmask, emask; /* might cancel timeout */ if (Punished && !carried(uball) && (is_pool(uball->ox, uball->oy) || ((trap = t_at(uball->ox, uball->oy)) - && ((trap->ttyp == PIT) || (trap->ttyp == SPIKED_PIT) - || (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) { + && (is_pit(trap->ttyp) || is_hole(trap->ttyp))))) { u.ux0 = u.ux; u.uy0 = u.uy; u.ux = uball->ox; @@ -4313,7 +4308,7 @@ boolean force; if (ttmp) { Strcpy(the_trap, the(trapdescr)); if (boxcnt) { - if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) { + if (is_pit(ttmp->ttyp)) { You_cant("do much about %s%s.", the_trap, u.utrap ? " that you're stuck in" : " while standing on the edge of it"); @@ -4615,8 +4610,7 @@ boolean *noticed; /* set to true iff hero notices the effect; */ /* if no trap here or it's not a falling trap, we're done (note: falling rock traps have a trapdoor in the ceiling) */ if (!t || ((t->ttyp != TRAPDOOR && t->ttyp != ROCKTRAP) - && (trapdoor_only || (t->ttyp != HOLE && t->ttyp != PIT - && t->ttyp != SPIKED_PIT)))) + && (trapdoor_only || (t->ttyp != HOLE && !is_pit(t->ttyp))))) return FALSE; if (ishero) { @@ -4875,8 +4869,8 @@ boolean u_entering_trap2; if (!trap1 || !trap2) return FALSE; if (!isok(trap2->tx, trap2->ty) || !isok(trap1->tx, trap1->ty) - || !(trap2->ttyp == PIT || trap2->ttyp == SPIKED_PIT) - || !(trap1->ttyp == PIT || trap1->ttyp == SPIKED_PIT) + || !is_pit(trap2->ttyp) + || !is_pit(trap1->ttyp) || (u_entering_trap2 && !(u.utrap && u.utraptype == TT_PIT))) return FALSE; dx = sgn(trap2->tx - trap1->tx); @@ -4894,21 +4888,21 @@ boolean u_entering_trap2; return FALSE; } -void +STATIC_OVL void clear_conjoined_pits(trap) struct trap *trap; { int diridx, adjidx, x, y; struct trap *t; - if (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { + if (trap && is_pit(trap->ttyp)) { for (diridx = 0; diridx < 8; ++diridx) { if (trap->conjoined & (1 << diridx)) { x = trap->tx + xdir[diridx]; y = trap->ty + ydir[diridx]; if (isok(x, y) && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { + && is_pit(t->ttyp)) { adjidx = (diridx + 4) % 8; t->conjoined &= ~(1 << adjidx); } @@ -4918,15 +4912,15 @@ struct trap *trap; } } -boolean +STATIC_OVL boolean adj_nonconjoined_pit(adjtrap) struct trap *adjtrap; { struct trap *trap_with_u = t_at(u.ux0, u.uy0); if (trap_with_u && adjtrap && u.utrap && u.utraptype == TT_PIT && - (trap_with_u->ttyp == PIT || trap_with_u->ttyp == SPIKED_PIT) && - (adjtrap->ttyp == PIT || adjtrap->ttyp == SPIKED_PIT)) { + is_pit(trap_with_u->ttyp) && + is_pit(adjtrap->ttyp)) { int idx; for (idx = 0; idx < 8; idx++) { if (xdir[idx] == u.dx && ydir[idx] == u.dy) @@ -4955,7 +4949,7 @@ struct trap *trap; y = trap->ty + ydir[diridx]; if (isok(x, y)) { if ((t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { + && is_pit(t->ttyp)) { trap->conjoined |= (1 << diridx); join_adjacent_pits(t); } else @@ -4973,7 +4967,7 @@ uteetering_at_seen_pit(trap) struct trap *trap; { if (trap && trap->tseen && (!u.utrap || u.utraptype != TT_PIT) - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) + && is_pit(trap->ttyp)) return TRUE; else return FALSE; @@ -4987,8 +4981,8 @@ register struct trap *ttmp; /* some of these are arbitrary -dlc */ if (ttmp && ((ttmp->ttyp == SQKY_BOARD) || (ttmp->ttyp == BEAR_TRAP) || (ttmp->ttyp == LANDMINE) || (ttmp->ttyp == FIRE_TRAP) - || (ttmp->ttyp == PIT) || (ttmp->ttyp == SPIKED_PIT) - || (ttmp->ttyp == HOLE) || (ttmp->ttyp == TRAPDOOR) + || is_pit(ttmp->ttyp) + || is_hole(ttmp->ttyp) || (ttmp->ttyp == TELEP_TRAP) || (ttmp->ttyp == LEVEL_TELEP) || (ttmp->ttyp == WEB) || (ttmp->ttyp == MAGIC_TRAP) || (ttmp->ttyp == ANTI_MAGIC))) { diff --git a/src/uhitm.c b/src/uhitm.c index 0e482d6ec..b240eef26 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1484,6 +1484,9 @@ struct attack *mattk; setmnotwielded(mdef, otmp); otmp->owornmask = 0L; update_mon_intrinsics(mdef, otmp, FALSE, FALSE); + /* give monster a chance to wear other equipment on its next + move instead of waiting until it picks something up */ + mdef->misc_worn_check |= I_SPECIAL; if (otmp == stealoid) /* special message for final item */ pline("%s finishes taking off %s suit.", Monnam(mdef), diff --git a/src/vision.c b/src/vision.c index 2dcc85b8b..be87051d9 100644 --- a/src/vision.c +++ b/src/vision.c @@ -1916,7 +1916,7 @@ char *limits; /* points at range limit for current row, or NULL */ * shadow limit imposed by the far block (right) then use the far * wall as our new far block when we recurse. * - * If the limits are the the same, and the far block really exists + * If the limits are the same, and the far block really exists * (fb_row >= 0) then do the same as above. * * Normally, the check would be for the far wall being closer OR EQUAL diff --git a/src/worn.c b/src/worn.c index e7860c655..1eb1ed671 100644 --- a/src/worn.c +++ b/src/worn.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 worn.c $NHDT-Date: 1526728754 2018/05/19 11:19:14 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.51 $ */ +/* NetHack 3.6 worn.c $NHDT-Date: 1537234121 2018/09/18 01:28:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.55 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -710,6 +710,13 @@ clear_bypasses() struct obj *otmp, *nobj; struct monst *mtmp; + /* + * 'Object' bypass is also used for one monster function: + * polymorph control of long worms. Activated via setting + * context.bypasses even if no specific object has been + * bypassed. + */ + for (otmp = fobj; otmp; otmp = nobj) { nobj = otmp->nobj; if (otmp->bypass) { @@ -741,10 +748,19 @@ clear_bypasses() continue; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->bypass = 0; + /* long worm created by polymorph has mon->mextra->mcorpsenm set + to PM_LONG_WORM to flag it as not being subject to further + polymorph (so polymorph zap won't hit monster to transform it + into a long worm, then hit that worm's tail and transform it + again on same zap); clearing mcorpsenm reverts worm to normal */ + if (mtmp->data == &mons[PM_LONG_WORM] && has_mcorpsenm(mtmp)) + MCORPSENM(mtmp) = NON_PM; } for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) { for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->bypass = 0; + /* no MCORPSENM(mtmp)==PM_LONG_WORM check here; long worms can't + be just created by polymorph and migrating at the same time */ } /* billobjs and mydogs chains don't matter here */ context.bypasses = FALSE; diff --git a/src/zap.c b/src/zap.c index 8c4458347..7a5ab3416 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 zap.c $NHDT-Date: 1525012627 2018/04/29 14:37:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.277 $ */ +/* NetHack 3.6 zap.c $NHDT-Date: 1537234123 2018/09/18 01:28:43 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.287 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -222,7 +222,11 @@ struct obj *otmp; case WAN_POLYMORPH: case SPE_POLYMORPH: case POT_POLYMORPH: - if (resists_magm(mtmp)) { + if (mtmp->data == &mons[PM_LONG_WORM] && has_mcorpsenm(mtmp)) { + /* if a long worm has mcorpsenm set, it was polymophed by + the current zap and shouldn't be affected if hit again */ + ; + } else if (resists_magm(mtmp)) { /* magic resistance protects from polymorph traps, so make it guard against involuntary polymorph attacks too... */ shieldeff(mtmp->mx, mtmp->my); @@ -238,6 +242,7 @@ struct obj *otmp; if (polyspot) for (obj = mtmp->minvent; obj; obj = obj->nobj) bypass_obj(obj); + /* natural shapechangers aren't affected by system shock (unless protection from shapechangers is interfering with their metabolism...) */ @@ -261,6 +266,22 @@ struct obj *otmp; || (u.uswallow && mtmp == u.ustuck))) learn_it = TRUE; } + + /* do this even if polymorphed failed (otherwise using + flags.mon_polycontrol prompting to force mtmp to remain + 'long worm' would prompt again if zap hit another segment) */ + if (!DEADMONSTER(mtmp) && mtmp->data == &mons[PM_LONG_WORM]) { + if (!has_mcorpsenm(mtmp)) + newmcorpsenm(mtmp); + /* flag to indicate that mtmp became a long worm + on current zap, so further hits (on mtmp's new + tail) don't do further transforms */ + MCORPSENM(mtmp) = PM_LONG_WORM; + /* flag to indicate that cleanup is needed; object + bypass cleanup also clears mon->mextra->mcorpsenm + for all long worms on the level */ + context.bypasses = TRUE; + } } break; case WAN_CANCELLATION: @@ -2306,7 +2327,7 @@ boolean ordinary; case WAN_CANCELLATION: case SPE_CANCELLATION: - (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE); + (void) cancel_monst(&youmonst, obj, TRUE, TRUE, TRUE); break; case SPE_DRAIN_LIFE: @@ -2675,25 +2696,45 @@ boolean youattack, allow_cancel_kill, self_cancel; /* now handle special cases */ if (youdefend) { - if (Upolyd) { - if ((u.umonnum == PM_CLAY_GOLEM) && !Blind) - pline(writing_vanishes, your); - - if (Unchanging) + if (Upolyd) { /* includes lycanthrope in creature form */ + /* + * Return to normal form unless Unchanging. + * Hero in clay golem form dies if Unchanging. + * Does not cure lycanthropy or stop timed random polymorph. + */ + if (u.umonnum == PM_CLAY_GOLEM) { + if (!Blind) + pline(writing_vanishes, your); + else /* note: "dark" rather than "heavy" is intentional... */ + You_feel("%s headed.", Hallucination ? "dark" : "light"); + u.mh = 0; /* fatal; death handled by rehumanize() */ + } + if (Unchanging && u.mh > 0) Your("amulet grows hot for a moment, then cools."); else rehumanize(); } } else { - mdef->mcan = TRUE; - - if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN) + mdef->mcan = 1; + /* force shapeshifter into its base form */ + if (mdef->m_ap_type != M_AP_NOTHING) + seemimic(mdef); + /* [not 'else if'; chameleon might have been hiding as a mimic] */ + if (mdef->cham >= LOW_PM) { + /* note: newcham() uncancels shapechangers (resets m->mcan + to 0), but only for shapechangers whose m->cham is already + NON_PM and we just verified that it's LOW_PM or higher */ + newcham(mdef, &mons[mdef->cham], FALSE, FALSE); + mdef->cham = NON_PM; /* cancelled shapeshifter can't shift */ + } + if (is_were(mdef->data) && !is_human(mdef->data)) were_change(mdef); if (mdef->data == &mons[PM_CLAY_GOLEM]) { if (canseemon(mdef)) pline(writing_vanishes, s_suffix(mon_nam(mdef))); - + /* !allow_cancel_kill is for Magicbane, where clay golem + will be killed somewhere back up the call/return chain... */ if (allow_cancel_kill) { if (youattack) killed(mdef); @@ -3373,8 +3414,7 @@ struct obj **pobj; /* object tossed/used, set to NULL The(distant_name(obj, xname))); /* lame */ range = 0; } else if (Sokoban && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT - || t->ttyp == HOLE || t->ttyp == TRAPDOOR)) { + && (is_pit(t->ttyp) || is_hole(t->ttyp))) { /* hero falls into the trap, so ball stops */ range = 0; } diff --git a/sys/wince/mhcmd.c b/sys/wince/mhcmd.c index 98730dbce..c82bf7624 100644 --- a/sys/wince/mhcmd.c +++ b/sys/wince/mhcmd.c @@ -1161,7 +1161,7 @@ CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE pWindowSize) hdc = GetDC(hWnd); /* if windows size is specified - attempt ro stretch cells across - the the window size. If not - make default cell size based on + the window size. If not - make default cell size based on 10 points font. Make sure that cell cesize does not exceeds 20 points */ if (pWindowSize->cx > 0) diff --git a/sys/wince/mhmsgwnd.c b/sys/wince/mhmsgwnd.c index 818f72aed..1c8976564 100644 --- a/sys/wince/mhmsgwnd.c +++ b/sys/wince/mhmsgwnd.c @@ -34,7 +34,7 @@ typedef struct mswin_nethack_message_window { int yMax; /* maximum vertical scrolling position */ int xPage; /* page size of horizontal scroll bar */ int lines_last_turn; /* lines added during the last turn */ - int dont_care; /* flag the the user does not care if messages are lost */ + int dont_care; /* flag the user does not care if messages are lost */ } NHMessageWindow, *PNHMessageWindow; static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass"); diff --git a/sys/wince/mswproc.c b/sys/wince/mswproc.c index 7137a062a..d04c2156c 100644 --- a/sys/wince/mswproc.c +++ b/sys/wince/mswproc.c @@ -1048,7 +1048,7 @@ identifier outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with - the menu command (or their user defined alises), it loses. + the menu command (or their user defined aliases), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the diff --git a/win/Qt/qt_win.cpp b/win/Qt/qt_win.cpp index c809c48e5..bd281d3c5 100644 --- a/win/Qt/qt_win.cpp +++ b/win/Qt/qt_win.cpp @@ -2906,7 +2906,7 @@ int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list) if (dialog->result()<0) qApp->enter_loop(); } - //if ( (nhid != WIN_INVEN || !flags.perm_invent) ) // doesn't work yet + //if ( (nhid != WIN_INVEN || !iflags.perm_invent) ) // doesn't work yet { dialog->hide(); } @@ -4840,7 +4840,7 @@ void NetHackQtBind::qt_update_inventory() if (main) main->updateInventory(); /* doesn't work yet - if (program_state.something_worth_saving && flags.perm_invent) + if (program_state.something_worth_saving && iflags.perm_invent) display_inventory(NULL, FALSE); */ } diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp index 27db51868..b143b8e8d 100644 --- a/win/Qt4/qt4bind.cpp +++ b/win/Qt4/qt4bind.cpp @@ -401,7 +401,7 @@ void NetHackQtBind::qt_update_inventory() if (main) main->updateInventory(); /* doesn't work yet - if (program_state.something_worth_saving && flags.perm_invent) + if (program_state.something_worth_saving && iflags.perm_invent) display_inventory(NULL, false); */ } diff --git a/win/X11/winX.c b/win/X11/winX.c index 318fb4e41..5c1de3c12 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -2404,7 +2404,7 @@ void nh_XtPopup(w, g, childwid) Widget w; /* widget */ int g; /* type of grab */ -Widget childwid; /* child to recieve focus (can be None) */ +Widget childwid; /* child to receive focus (can be None) */ { XtPopup(w, (XtGrabKind) g); XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1); diff --git a/win/X11/winmenu.c b/win/X11/winmenu.c index 75c99b57a..a3287737c 100644 --- a/win/X11/winmenu.c +++ b/win/X11/winmenu.c @@ -826,7 +826,7 @@ menu_item **menu_list; * each time. */ if (menu_info->valid_widgets - && (window != WIN_INVEN || !flags.perm_invent)) { + && (window != WIN_INVEN || !iflags.perm_invent)) { XtDestroyWidget(wp->popup); menu_info->valid_widgets = FALSE; menu_info->is_up = FALSE; diff --git a/win/gnome/gnbind.c b/win/gnome/gnbind.c index bc3521497..42152eeb9 100644 --- a/win/gnome/gnbind.c +++ b/win/gnome/gnbind.c @@ -702,7 +702,7 @@ identifier outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with - the menu command (or their user defined alises), it loses. + the menu command (or their user defined aliases), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index 6c6bfea7d..41e7733fa 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -700,7 +700,7 @@ mswin_layout_main_window(HWND changed_child) GetNHApp()->rtInvenWindow.bottom = GetNHApp()->rtMenuWindow.bottom; /* adjust map window size only if perm_invent is set */ - if (flags.perm_invent) + if (iflags.perm_invent) GetNHApp()->rtMapWindow.right = GetNHApp()->rtMenuWindow.left; } @@ -712,7 +712,7 @@ mswin_layout_main_window(HWND changed_child) /* kludge - inventory window should have its own type (same as menu-text as a matter of fact) */ - if (flags.perm_invent && i == WIN_INVEN) { + if (iflags.perm_invent && i == WIN_INVEN) { mswin_get_window_placement(NHW_INVEN, &rt); } else { mswin_get_window_placement(GetNHApp()->windowlist[i].type, diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index c8d71b4e6..6b0b4fda2 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -251,7 +251,7 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, /* If we just used the permanent inventory window to pick something, * set the menu back to its display inventory state. */ - if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN + if (iflags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN && how != PICK_NONE) { data->menu.prompt[0] = '\0'; SetMenuListType(hWnd, PICK_NONE); @@ -322,7 +322,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); - if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) + if (iflags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) mswin_update_window_placement(NHW_INVEN, &rt); else mswin_update_window_placement(NHW_MENU, &rt); @@ -334,7 +334,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); - if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) + if (iflags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) mswin_update_window_placement(NHW_INVEN, &rt); else mswin_update_window_placement(NHW_MENU, &rt); diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index feabf49b2..77432f751 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1102,7 +1102,7 @@ identifier outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with - the menu command (or their user defined alises), it loses. + the menu command (or their user defined aliases), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the @@ -1194,7 +1194,7 @@ mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected) ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW); nReturned = mswin_menu_window_select_menu( GetNHApp()->windowlist[wid].win, how, selected, - !(flags.perm_invent && wid == WIN_INVEN + !(iflags.perm_invent && wid == WIN_INVEN && how == PICK_NONE) /* don't activate inventory window if perm_invent is on */ ); @@ -1211,7 +1211,7 @@ void mswin_update_inventory() { logDebug("mswin_update_inventory()\n"); - if (flags.perm_invent && 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); } @@ -2118,6 +2118,7 @@ initMapTiles(void) HBITMAP hBmp; BITMAP bm; TCHAR wbuf[MAX_PATH]; + DWORD errcode; int tl_num; SIZE map_size; extern int total_tiles_used; @@ -2131,8 +2132,13 @@ initMapTiles(void) NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE); if (hBmp == NULL) { - raw_print( - "Cannot load tiles from the file. Reverting back to default."); + char errmsg[BUFSZ]; + + errcode = GetLastError(); + Sprintf(errmsg, "%s (0x%x).", + "Cannot load tiles from the file. Reverting back to default", + errcode); + raw_print(errmsg); return FALSE; } @@ -2243,7 +2249,7 @@ mswin_popup_destroy(HWND hWnd) DrawMenuBar(GetNHApp()->hMainWnd); /* Don't hide the permanent inventory window ... leave it showing */ - if (!flags.perm_invent || mswin_winid_from_handle(hWnd) != WIN_INVEN) + if (!iflags.perm_invent || mswin_winid_from_handle(hWnd) != WIN_INVEN) ShowWindow(hWnd, SW_HIDE); GetNHApp()->hPopupWnd = NULL;