Linux and BSD system have random number source devices that can be used
as source for a unguessable seed source.
Other platforms fall back to generate the seed with gettime().
new domove_core() assessment results
potentially smudge engravings
Proceed to wipe engraving after domove_core() now, but only under
all of the following conditions:
- you can reach the floor
- preceding domove_core() move attempt was marked as
having succeeded in domove_core()
- there is actually an engraving there to impact at
your original spot, or your new spot, or both
Since no one has come up with a better fix for has_colors() being
implicitly declared, add a hack for suppressing a compiler complaint
about has_colors() on linux and/or sco unix that use sufficiently old
<curses.h>.
Report was right after release of 3.6.0 but my fix at the time broke
compile when using more recent <curses.h>.
I did much of this quite some time ago, as prequisite for a different
bug report about monsters vs shades, then set it aside. It ended up
being more complicated than I anticipated.
When deciding whether various non-weapon attacks might hit a shade,
hmonas() was not checking for blessed or silver armor that should have
been applicable. It did check boots when kicking, but not gloves or
rings (when no gloves) when touching, or outermost of cloak/suit/shirt
when hugging, or helmet when head-butting. (The last one is actually
moot because nothing with a head-butt attack is able to wear a helm.)
The problem was more general than just whether attacks might hit and
hurt shades. Various undead and/or demons are also affected by blessed
and/or silver attack but weren't for non-weapon attacks by poly'd hero.
At least two unrelated bugs are fixed: a rope golem's AT_HUGS attack
gives feedback about choking but was fully effective against monsters
which fail the can_be_strangled() test. And it was possible to hug a
long worm's tail, rendering the entire worm immobile.
The report also suggested that all artifacts be able to hit shades for
full effect, but by the time shades are encountered everyone has an
artifact so that would nullify a shade's most interesting ability.
TODO: monster against hero and monster against other monster need to
have similar changes.
Both u_on_rndspot() and losedogs() might result in having a monster
and the hero be at the same location. Have wiz_makemap() use the
same fixup for that as goto_level().
Give the enum lists in several header files explicit values. Adding
or removing new entries will be more tedious, but doing that is rare
and being able to grep the headers for numeric values in addition to
names is very useful.
rm.h also has a bunch of tabs replaced with spaces.
Take a first step towards making the mons[] array be readonly.
The only other place that updates it is when changing succubus and
incubus AD_SSEX attacks to AD_SEDU ones and that can be handled
via existing getmattk(), but so far has proven to be trickier than
anticipated.
They're never modified. Minor complication: &zeroobj is used as
a special not-Null-but-not-an-object value in multiple places and
needs to have 'const' removed with a cast in that situation.
The recent attempt to have looking inside a container show shop
prices had multiple problems. Worst one was showing shop prices as
if the hero would be buying for items already owned by the hero.
Item handling inside containers on shop floor was inconsistent: if
shop was selling those items, they would include a price, but if not
selling--either already owned by hero or shopkeeper didn't care about
them--they were only marked "no charge" if hero owned the container.
This is definitely better but I won't be surprised if other obscure
issues crop up. Gold inside containers on shop floor is always owned
by the shop (credit is issued if it was owned by the hero) but is not
described as such.
Fixes#172
Casting teleport-away via ^T used different requirements for energy,
strength, and hunger than casting it via 'Z'. The strength and hunger
requirements were more stringent, the energy one more lenient. When
it rejected a cast attempt due to any of those, it used up the move,
but 'Z' didn't.
When testing my fix, I wanted an easier way than a debugger to control
how ^T interacts with wizard mode, so finally got around to a first
cut at being able to invoke it via wizard mode but not override those
energy/strength/hunger requirements. It uses the 'm' prefix to ask
for a menu. 'm^T' gives four options about how to teleport. (There
are other permutations which aren't handled.)
Also noticed while testing: ^T wouldn't attempt to cast teleport-away
if you didn't know the corresponding spellbook. 'Z' will attempt that
because it is possible to forget a book and still know its spell.
The 'O' handling for bouldersym was updating the display value for
boulder even if the value had been rejected, and if it still had the
default of '\0', the map would end up with <NUL> characters. (When
examined via '//' or ';', those matched dummy monster class #0 and
led to the impossible "Alphabet soup: 'an("")'" that was suppressed
yesterday.)
Attempting to set bouldersym to ^@ or \0 would also be rejected as
duplicating a monster symbol. That is now accepted and used to reset
the boulder symbol to default. However, other control characters are
also accepted--not due to this patch, they already are, and from a
config file in addition to via 'O'--so bouldersym can still disrupt
the map. But that's no different from putting control characters
into a symbol set or setting them from config file via S_foo:^C.
Fixes#170
Monsters never throw athames or scalpels but some fake player monsters
on the Astral Plane are given those. Since they're stackable the
quantity usually gets boosted but there's no point in having more than
one if they won't be thrown.
This could have been fixed by letting monsters throw those two items,
but I prevented the quantity from being boosted instead.
Player came across a stack of 2 gray stones in a shop and kicked one.
That one ended up with a different (in his case, lower) price once it
was separate. This behavior only applies to non-glass gems which add
a price variation derived from internal ID (obj->o_id) number. Make
splitting stacks always yield the same price per item in the new stack
as was being charged in the old stack by choosing a similar o_id. Do
it for all splits (that can vary price by ID, so just non-glass gems),
not just ones performed inside shops.
He picked up the lower priced one and dropped it back on the original
higher priced one; the combined stack took on the lower price. That
will no longer happen if they come from splitting a stack, but this
fix doesn't address merging with different prices when they start out
as separate stacks. (Unpaid items won't merge in inventory if prices
are different, but shop-owned items will merge on floor.)
Dropping an existing fragile item while levitating will usually
break it. Getting a new wished-for fragile item and dropping it
because of fumbling or overfull inventory never would.
Some callers of hold_another_object() held on to its return value,
others discarded that. That return value was unsafe if the item
was dropped and fell down a hole (or broke [after this change]).
Return Null if we can't be sure of the value, and make sure all
callers are prepared to deal with Null.
Another one from 6.5 years ago, identifying a type of gem should give
a new price for any unpaid gems of that type and adjust shopping bill
accordingly. Report was for rubbing with touchstone and learning
worthless glass with price not changing until the learned 'gem' was
dropped. Fix works for that and also other forms of identification
(and for amnesia, raising prices of forgotten gems); no dropping is
required for the price to change.
Theoretically could apply to any type of item, but prices of gems are
by far the most sensitive to whether or not they're identified.
The Unix Makefile.{src,utl} use the compiler name 'gcc' by default on
OSX, and that invokes clang which defines __GNUC__ to deal with gcc
extensions. But when invoked via the Xcode IDE, it evidently uses its
own name instead, and wasn't defining __GNUC__. tradstdc.h started
down the road of duplicating gcc features; switch to pretending to be
gcc instead.
Casting to (void) to discard a function return value doesn't satisfy
gcc's -Wunused-result (which we aren't enabling but is apparently
being activated for particular functions by glibc header files). Turn
it into a no-op to suppress three dozen warnings from Travis builds.
I don't know why we have two different functions which do exactly
the same thing (checking whether an item is unpaid or is a container
that holds at least one unpaid item), but switch the #H2504 fix to
use 'the other one' and reverse one of the changes made when using
the inventory one.
I thought that the earlier fix for #H2504 was too easy for anything
shop related. It didn't deal sensibly with containers owned by hero
but holding unpaid shop goods.
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.
The relatively recent change to lev_comp do deal with apparent junk
in some places in its generated data has triggered a bunch of
"cast to 'vA' (aka 'const char *') from smaller integer type 'int'
[-Wint-to-pointer-cast]"
from clang when building with USE_OLDARGS. Probably should have
added a zillion explicit casts to long and 'L' suffix for 0 rather
than trying to handle both int and long. Or maybe just turned off
that particular warning, which must be coming from -Wall or -Wextra.
This modification has no effect for USE_STDARG or USE_VARARGS configs.
When options processing encountered OPTIONS=windowtype:X,
the code would immediately attempt to switch over to that
windowtype right in the midst of options processing.
This stores the chosen option into
chosen_window[WINTYPELEN]
thus allowing the startup code to choose it after
options processing has been completed.
Jumping or teleporting while levitating in xorn form wouldn't toggle
blocking of levitation when moving from open spots to wall/stone and
unblocking of same when moving the opposite way.
This handles those cases but there are no doubt others. The only
other one I checked was when failed #untrap moves hero onto trap.
That case works correctly--at least after this fix is in place.
Noticed while working on it: change of terrain didn't always update
the status line. When levitation became blocked, it still said Lev
and when unblocked, didn't say that. Next status update got status
condition back in sync.
Changes to be committed:
modified: include/winprocs.h
modified: src/options.c
modified: sys/share/pcmain.c
new file: sys/share/safeproc.c
modified: sys/winnt/Makefile.msc
modified: sys/winnt/stubs.c
new file: sys/winnt/windmain.c
modified: sys/winnt/winnt.c
modified: win/win32/vs2017/NetHack.vcxproj
modified: win/win32/vs2017/NetHackW.vcxproj
modified: win/win32/winhack.c
Because multiple window ports are supported on Windows
now, even in the same executable and selectable via
config file in some cases, some adjustments became
necessary. There will likely be some further refining
of this over the next day or two.
List of changes:
Move Windows startup from sys/share/pcmain.c and
into its own sys/winnt/windmain.c so that it can
be modified to fix some current breakage, and
allow altering the order of some things.
There is startup processing code that is common to
all of the Windows WindowPorts, but that startup
processing code needs to have no dependency on
any one of those WindowPorts.
Yet, during startup processing, some of the initialization
routines can end up calling NetHack functions that
expect an active Window port underneath, and if there
isn't one, routines like pline, impossible, panic can
end up invoking null function pointers.
Place a new file sys/share/safeproc.c, in which a complete
window port is available for early startup processing
purposes. It's WindowPort name field is set to
"safe-startup" just for reference. The prototypes in
include/winprocs.h require that SAFEPROCS be
Usage:
windowprocs = get_safe_procs(0);
initializes a set of winprocs function pointers that ensure
none of the function pointers are left null, but that's all it does.
windowprocs = get_safe_procs(1);
initializes a set of winprocs functions pointers that ensure
none of the function pointers are left null, but also
provides some basic output and input functionality using nothing
other than C stdio routines (no platform or OS specific code).
The conditional code related to WIN32 has been removed from
sys/share/pcmain.c
The code common to all of the Windows WindowPorts calls
get_safe_procs() almost immediately to ensure that
there is a set of WindowPort winprocs available.
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()
hmon() can destroy the weapon being used, and known_hitum() would
still pass the pointer to the freed object to cutworm(). Remember the
relevant weapon attribute before using and maybe freeing the object,
then pass that attribute instead of the whole weapon. Also pass
'more-likely-to-cut' for axes in addition to blades.
thimonst() behaved similarly, although due to much different code
paths none of the objects that might get to hmon() were then passed to
cutworm(), so it wasn't vulnerable. But pass 'more-likely-to-cut'
for axes instead of for blades when thrown.
Change the command list to always include #shell and #suspend so that
a user's preferred key bindings can span platforms without worrying
about whether those exist or not. They're still effectively no-ops
when compiled out.
'#?' suppresses them from the list of displayed commands. Interface-
specific extended command handling may want to check new extcmd.flag
value CMD_NOT_AVAILABLE to do the same, but failing to do so shouldn't
pose a problem. They behave sanely if executed when not supported.
Some bits from another feature by Tangles had
slipped into our merge of curses a while back.
Remove the partial bits as feature bits should
be complete or not at all, unless foundational
for something to come.