That #H number isn't a typo. This finally fixes--at least improves--
something reported eight years ago. The monster types chosen by
mkclass() could be way off in some circumstances. Cited example was
repeated same-race sacrifice by chaotic hero on dungeon level 20; it
produced about twice as many incubi as succubi even though they're
the same as far as difficulty goes. (No changes in the intervening
years had any discernable effect; that was still reproducible.)
The report also mentioned that ndemon() threw away the result from
mkclass() and retried quite often and suggested that mkclass() be
taught to filter by alignment when caller cared about that.
This seems to even things out, although it also made harder monsters
chosen more often. A test program generated these numbers when
picking a chaotic demon 10000 times (level 1 hero on dungeon level 20,
so not realistic; actually probably level 0 hero since the program
didn't initialize struct u.) Third column is the number of times the
monster type was chosen with the old mkclass(), fourth is same for
the new one.
mkclass() calls 27315 10000
286 succubus 2800 3309
288 incubus 5552 3262
291 marilith 973 780
292 vrock 477 1617
293 hezrou 150 626
294 bone devil 46 247
295 ice devil 2 107
296 nalfeshnee 0 23
297 pit fiend 0 15
298 sandestin 0 4
299 balrog 0 10
Note that vrock has generation frequency 2 and marilith only 1, so
getting twice as many vrocks as mariliths should be expected.
I temporarily changed ndemon() to ask for lawful demons instead of
chaotic ones and got this.
mkclass() calls 15762 10000
287 horned devil 3197 3375
289 erinys 4991 3339
290 barbed devil 1812 3286
I also ran it for dragons with any alignment (so the outcome was
never thrown away; 10000 calls were needed for 10000 picks) instead
of demons of specific alignment and am suspicious of the outcome.
mkclass() calls 10000 10000
140 baby yellow dragon 1124 0
141 gray dragon 1096 1096
142 silver dragon 1073 1099
143 red dragon 1061 1126
144 white dragon 1077 1128
145 orange dragon 1141 1118
146 black dragon 1154 1049
147 blue dragon 1137 1123
148 green dragon 1137 1154
149 yellow dragon 0 1107
There may be a flaw in the test program. Or else old mkclass() was
not very good at picking dragons.
add MM_NOGRP makemon() flag as a means of suppressing groups of monsters in
a couple places that warrant it when a specific monster type isn't
specified on the call to makemon()
If hero was carrying Schroedinger's Box at end of game, disclosing
inventory converted it into an ordinary box. That interferred with
subsequent disclosure when writing DUMPLOG, which saw an empty box
if inventory had been shown or the special box with newly-determined
contents if not. I tried a couple of ways to fix it and decided
that redoing it was better in the long run.
Schroedinger's box is still flagged with box->spe = 1, but instead
of having that affect the box's weight, now there is always a cat
corpse in the box. When opened, that will already be in place for
a dead cat or be discarded for a live one, but the weight will be
standard for container+contents and when box->cknown is set it will
always be "containing 1 item" (which might turn out to be a monster).
Some temporary code fixes up old save/bones files to stay compatible.
TODO: food detection used to skip Schroedinger's Box; now it will
always find a corpse, so some fixup like the ridiculous probing code
is needed.
mons[].difficulty takes over for monstr[]
Invoking "makedefs -m" gives a deprecation message; it is also included
in the (now mostly empty) monstr.c.
Ports should now remove "makedefs -m" from their build procedures but this
commit does not include that change.
Remove trailing spaces, and remove tabs from the files that had
trailing spaces.
Also, rndorcname() was using a random value to terminate a loop
and was recalculating a new one each iteration.
Change the phrasing when a pet grows up into another monster type:
(old) "The pony grows up into a horse."
(new) "Your pony grows up into a horse."
No effect if it has been assigned a name:
(before and after) "Foo grows up into a horse."
Changes to be committed:
modified: include/decl.h
modified: include/dungeon.h
modified: include/extern.h
modified: include/hack.h
modified: src/decl.c
modified: src/do_name.c
modified: src/dog.c
modified: src/dokick.c
modified: src/makemon.c
modified: src/mkmaze.c
modified: src/mkobj.c
modified: src/pager.c
This commit is an attempt to address the complaints about
the orc town variation taking away lots of stuff that is
normally available in mine town. The statement in the level
description says "A tragic accident has occurred in Frontier
Town...It has been overrun by orcs."
The changes in this commit attempt to uphold that premise,
while making things a bit more interesting and perhaps
more palatable for the player.
This update does the following in keeping with the mythos:
- While many of the orcs still remain to wander about the
level, many of the orcs took off deeper into the mines with
some of the stuff that they plundered. You may now be
able to hunt some of it down.
- Adds some appearance of this particular horde of marauding
orcs working as part of a larger collective.
- This evolves the Orc Town mine town variation into a
a feature over multiple levels of The Gnomish Mines,
rather than just the single-level "feature" that it was
previously.
- You may have to work longer and a bit harder for some
things than other mine town variations, but at least with
these changes, there is hope that some of it may be found
elsewhere.
Game mechanics notes (maybe spoily?)
- Add mechanism to place objects into limbo (okay, really
place them onto the migrating_objs list for transferring
between levels etc.) and destine them
to become part of the monster inventory of a particular
species. In this particular usage case, it's using the
M2_ORC flag setting to identify the recipients.
- At present, there is no mechanism in the level compiler
for placing objects onto the migrating objects, nor
with more sophisticated landing logic, so a somewhat
kludgy hard-coded fixup and supporting routines were used.
Some day the need for that might change if additional
capabilities move to the level compiler.
This is a NetHack-3.6.2-beta01 update. Please give it a workout.
Fixes#127
Implement the suggestion that since teleporting away from the vault
while being confronted by the guard results in a shrill whistling
sound, the vault guard ought to have a tin whistle in his inventory.
I also added a check that he does have the whistle and to give an
alternate message if not, but after half a dozen tries to have a
squad of beefed up monkeys steal the whistle, they never accomplished
that. At least three times they took everything except the whistle
but I never succeeded in verifying the alternate message.
This issue has been around for a while but wasn't noticable to players
until some post-3.6.0 tweaking of end of game disclosure. When testing
the DUMPLOG artifact_score fix, I level teleported to the Astral Plane
and performed a cheat ascension. Final disclosure listed high priests
as extinct. Same thing would happen after visiting Moloch's Sanctum
instead. (The latter didn't interfere with creating the Astral high
priests if you got that far, just as creation of the first one there
didn't prevent the other two.)
I forget why high priests are flagged as unique (something I think
I'm responisble for...), but they shouldn't share unique's setting of
extinct during monster creation. (They could be set that way after 4
are created, but this fix doesn't do that. It just treats them like
ordinary monsters so you'd need 127 or 255 or some such to make them
become extinct. Unlike other creatures with a special creation limit,
high priests can be produced when aligned priests gain experience--an
event that I don't recall ever noticing happen.)
When a female dwarf grows (via level gain) into a dwarf lord, it
changes sex as well as base monster form because all dwarf lords
are male. The earlier fix for #H4276 (16-Mar-2016, to give an
alternate grow-up message acknowledging the change) used the wrong
monster form (monst's old one instead of new one).
A few things which might conceivably pass negative values to ctype
routines. Some are post-3.6.0. None of them explain the sporadic
Windows assertion failure.
Using tolower() without verifying the argument isupper() should be
completely safe when tolower() is a function but might not be when
it's a macro. (Likewise for toupper() without islower().) NetHack's
lowc() function is always safe, at least for ASCII.
I've hunted for other instances where monster hit points were set
to zero or less without calling the routine that kills off the
monster (see recent mon_unslime() vs zhitm()) and didn't find any
for mhp subtraction. I haven't checked for direct assignment yet.
For a while I thought I'd found several cases where a monster was
intended to be killed but got left with positive hit points, but
it turned out that lifesaved_monster(), of all places, was setting
them to zero. I've moved that to its callers so that it isn't so
well hidden. And changed several ''if ((mon->mhp -= dmg) <= 0)''
into separate subtraction and 'if' just so the mhp manipulation is
a bit more visible.
I think the only actual change here is the message for monster
being killed by lava, where glass golems now melt instead of burn.
Make the handling of unique monsters consistent between vanquished
monsters and genocided/extinct monsters. No visible difference to
players.
This also prevents Nazgul and erinys from being polymorphed into
some other form to reduce the chance that their kill count fails
to match the expected number when they're reported to be extinct.
[My long test game (with 3451 total dead critters as of the last
save file) used for exercising the sorting of vanquished monsters
included
120 soldiers
111 wolves
9 Nazgul
2 erinyes
and the genocided/extinct list had none genocided, those four
extinct. No doubt the missing third erinys was alive somewhere
rather than counted as something else after getting polymorphed,
so this band-aid wouldn't have helped this particular game.]
Make 'zeromonst' global instead of local to makemon.c. Its address
isn't used as a special value like &zeroobj, but it is useful to
have available for initializing various pseudo-monsters.
modified:
include/decl.h
src/decl.c, makemon.c, mkobj.c, mplayer.c, teleport.c
Most of the humanoid species have Lords and several have Kings,
but none of them have Ladies or Queens. When a female grows up
to reach that level of monster, she changes into male. This fix
gives an alternate message acknowledging that change rather than
prevent taking on the stronger form. A better fix would be to
add ogre ladies and dwarf queens as separate monsters, but doing
so will break 3.6.0 save file compatibility.
(I started out with an alternate fix, adding mons[].fname for the
dozen or so creatures which warrant an alternate name for females.
But that requires statues, figurines, corpses, tins, and maybe
even eggs to track gender [some statues already do, and corpses
and statues with attached mtraits also implicitly do] and to not
stack with equivalent ones of the opposite gender. Plus glyphs
to track them, and new tiles. It was becoming too complicated
for such a relatively unimportant feature. Separate monsters is
the way to go, deferred until save file format changes again.)
Suppress a couple of 'dead increment' diagnostics from the clang static
analyzer. The assignments are dead, but keeping the variable up to date
is more valuable (in case someone someday changes the code to use the
affected variable somewhere farther along in that function) than changing
the code to avoid the assignments in order to prevent the diagnostic.
This will only work to suppress the analyzer's diagnostic messages if
either FORCE_ARG_USAGE or GCC_WARN is defined when compiling makemon.c.
With DEBUG suppressed, I started getting
16 warning: empty body in an if-statement
and 2 warning: empty body in an else-statement
from gcc.
Using braces for an empty block instead of just ';' avoids the warning:
if (foo)
debugpline("foo");
is bad,
if (bar) {
debugpline("bar");
}
is good. ;-)
The changes to lint.h are just precautionary.
modified:
include/lint.h
src/attrib.c, bones.c, dbridge.c, dig.c, eat.c,
makemon.c, mkmaze.c, mon.c, sp_lev.c
Fixing up mis-indented block comments, but hit some files that hadn't
had the earlier mixture of tab replacement, etc, so it's bigger than I
expected. If I get to it, they'll be another round of this tomorrow.
Somewhere along the line I started removing redundant parentheses from
return statements, but only in files that needed continuation fixups
so it's not comprehensive.
This time try random locations up to 50 times, then start going
through the map in order to find a good position. First round
tries to pick a location not in sight, if that fails, it might
try stair or ladder location. If that fails, then it will pick
any good position, whether in sight or not.
Outside field of vision restriction and trying stair or ladder
locations does not happen when the monster is placed from special
level code.
mtmp->cham was NON_PM, which select_newcham_form interpreted as a completely
random form. This also resulted Vlad getting a random shape, and not getting
the Candelabrum, making the game unwinnable.
Limit vampire shapeshifting on rogue level to vampire bats (only
choice represented by uppercase letter) and have other shapeshifting
try for uppercase. The latter isn't rigorous because shapeshifters
(chameleon=':', doppelganger='@', sandestin='&') aren't uppercase
themselves, so won't be created there under ordinary circumstances.
It applies to the "summon nasties" monster spell and post-invocation/
post-Wizard's-death harassment effect too.
Gnomes in mines during level generation have 1/20 chance of getting a candle
(should give approximately 4 candles in all of the mines total), and every
randomly generated gnome has 1/60 chance.
The code that intended to have mimics occasionally take on the form
of "strange object" always produced downstairs instead because
S_MIMIC_DEF is greater than MAXOCLASSES.
This problem was present in 3.4.3. I didn't try to go back to see
how long it's been there, but strange objects used to occur once
upon a time. Either nobody noticed that they'd gone away or there's
an alternate way to produce them.
I'll push a formatting guide at some point. There may still be
outstanding changes, but please feel free to resolve those as you arrive
a them.
To the best of my knowledge, there is no changes to the actual code
content, but the formatter does have the occasional bug. If you run into
an issue, please fix it!
Bag of tricks that had been used at least once was being described
as "empty" regardless of charge count, because it always fails the
Has_contents() test. After half this patch fixed that, it started
being flagged as "empty" as soon as the last charge was used rather
than after attempting to use it again after that, since 'cknown' was
being set whenever it was used. Only set that flag when applying
the bag has been observed to fail.
* Replace variadic debugpline() with fixed argument debugpline0(str),
debugpline1(fmt,arg), and so on so that C99 support isn't required;
* showdebug() becomes a function rather than a macro and handles a
bit more;
* two debugpline() calls in light.c have been changed to impossible();
* DEBUGFILES macro (in sys.c) can substitute for SYSCF's DEBUGFILES
setting in !SYSCF configuration (I hope that's temporary).