Add a note about NO_TERMS to include/wintty.h for clarity.
Rename tty_startup and tty_shutdown to term_startup() and
term_shutdown(). They are found in termcap.c for !NO_TERMS
like most of the other term_ routines, as well as having
versions for several of the NO_TERMS platforms. They aren't
part of the tty_interface called from the core. The tty
implementation does call and rely on them.
Remove some conditional #ifdef's around term_shutdown()
(formerly tty_shutdown()) and just ensure that all the
tty platforms have an implementation that they can link
with, even if it is just a stub presently.
Put the protype for nethack_exit in extern.h to reduce
maintenance to a single spot, and remove it from other
locations. A warning in the msdos cross-compile led to
this change.
Issue reported by ostrosablin: having Kick enabled as one of the
values for the 'autounlock' option succeeded it prompting "kick it?"
when walking into a locked closed door, but answering "yes" behaved
the same as answering "no".
There's bound to be a better way of fixing this, but this works.
Fixes#1360
Noticed when I summoned a quantum mechanic in wizard mode with a
starting character who should have no armor protection against their
teleport attack, but every touch resulted in "You are not affected". It
turns out the if statement checking for armor protection is backwards,
so you were never affected when you have no protection and were almost
always affected when you had good protection.
This appears to date back to when the all-purpose 'negated' variable was
removed and "You are not affected" moved to after the negation check;
the new conditional kept the ! by mistake.
Using #monster to make the steed use the breath weapon often
failed because the steed did not want to breathe at weak or
too strong monsters.
Make #monster force the steed use the breath, and if there is
no targets available, make the steed make some noise as feedback.
The tin-eating context was pointing to a non-existent object,
causing an error when the fuzzer somehow managed to continue eating
the freed tin object.
Clear the pointer when the tin leaves inventory or the object
is deleted.
Picking up a shop item and not paying it, getting swallowed
by a monster, and then teleporting the monster out of the shop
with you in it, the shopkeeper didn't notice the theft.
But the object was not marked as paid either.
Also prevent giving a message of the swallower disappearing
and appearing when it was teleported. (Although now there's
no message given, so something should be added ...)
If water walking boots haven't been discovered yet and underwater
hero rises to the surface when putting a pair on, discover them.
(Sinking while removing such on water already discovers them.)
Options processing can be early, even before ttyDisplay is allocated.
If we find that TTY_PERM_INVENT initialization is happening too early,
just set a marker (iflags.perm_invent_pending) to try again a bit later.
The changes in win/share are just to be able to sucessfully
reproduce the original issue on Windows. It was easily reproduced
on Unix, just by building with TTY_PERM_INVENT in include/config.h
and setting OPTIONS=perm_invent in config file.
This originated with a bug in NerfHack in which the developer specified
an inventory for a quest nemesis, but neglected to include the Bell of
Opening in it. Since monsters' inventory contents from makemon() were
tossed out completely, this caused a situation where the Bell was
deleted and the game was unwinnable. The first part of this change is
guarding against that by adding mdrop_special_objs before discarding the
inventory. This does create a possibility where if the programmer *does*
specify a nemesis get the Bell item in their inventory, while neglecting
to remove its special case generation in makemon.c, it would generate
twice - but two Bells is better than none.
Working on that fix led me to think about a limitation of the current
sp_lev.c behavior. You could either have a monster generate with its
species-typical inventory by not specifying an inventory for it, or you
could have it generate with custom inventory but then have to use that
to clumsily reproduce the normal inventory's complex chances and
conditionals in mongets(). So the remainder of this commit implements
another flag for des.monster(), keep_default_invent, that allows for
more flexibility in two ways:
1. When des.monster() contains an inventory function and
keep_default_invent is true, the monster will retain everything it
gets from makemon() and the objects in the inventory function are in
ADDITION to those. This is useful for augmenting a monster's default
kit with something to make them more threatening, or just more loot.
2. When des.monster contains no inventory function and
keep_default_invent is false, the monster will get NO inventory even
if its species is normally supposed to. I'm not sure where exactly
this would be used, but it doesn't hurt to have it available.
When keep_default_invent is not specified at all, the behavior remains
the same as it is now - if inventory is provided, default items are
discarded, and if not, they are kept.
My commit 82f0b1e8ea to make monsters which had nowhere
to move would panic attack the hero if possible, broke the
special unicorn handling; they avoid being in-line with hero,
so often had nowhere to move...
Fixes#1344
Remove the XP gain for tourist seeing a new type of monster
nearby, as it apparently made tourists a bit harder by forcing
early level gains.
Monsters next to hero are still marked as seen close-up, but
fix the code so it doesn't count undetected monsters.
Tourists still gain XP from "taking photos" of new types of monsters,
but only if they haven't seen the monster close up before.
(No actual photos are taken.)
Aka issue #1339 take II
For hero-owned container with some unpaid items, the itemized
shopping bill had a spurious index into the traditional shopping
bill (since it wasn't in that bill due not being unpaid). When mixed
with unpaid items that weren't in the container, that could cause
bill corruption while updating the traditional bill during payment,
leading to impossible warnings.
Fixes#1339Fixes#1350
Issue reported by ars3niy: with the relatively new container
handling, buying multiple items when some were inside a container
sometimes triggered impossible "unpaid_cost: object wasn't on any
bill" warnings and not buy all intended items. Once that occurred,
subsequent inventory display would repeat the warning.
A couple weeks back, I managed to produce a save file which would
reproduce the problem when 'p' was issued, but failed to figure
out why that was happening. I accidentally deleted that save file
and it took quite a lot of further attempts to get another one.
I still don't understand why this fix is needed, but with it in
place the save file no longer triggers any problems. I'm marking
the issue fixed but that could be premature.
Fixes#1339
When glyph updates are on, pline can be called recursively
when the vision is being fully recalculated. This caused
the recursively called pline to output raw_pline text.
Not sure if this is the correct way to fix it, but can't really
turn off or block the glyph update notices either ...
Fuzzer encountered impossible "timer sanity: melt timer on non-ice",
when vault guard entered the vault, changing the vault wall unconditionally
into room floor; in this case the vault wall was ice with a melting timer
attached.
Delete any melting ice timers on that location when turning it into floor.
Dipping a lit potion of oil into another potion could
turn the potion of oil into another potion; this resulted
in "burn_object: unexpected obj" impossible after the lit timer
ran out.
Just make an explosion if trying to dip a lit potion of oil.
If freedynamicdata() gets called twice, for whatever reason, a "double free" can occur.
warning: 44 ./nptl/pthread_kill.c: No such file or directory
(gdb) bt
#0 __pthread_kill_implementation (no_tid=0, signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:44
#1 __pthread_kill_internal (signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:78
#2 __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3 0x00007ffff7c8b26e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4 0x00007ffff7c6e8ff in __GI_abort () at ./stdlib/abort.c:79
#5 0x00007ffff7c6f7b6 in __libc_message_impl (fmt=fmt@entry=0x7ffff7e148d7 "%s\n")
at ../sysdeps/posix/libc_fatal.c:132
#6 0x00007ffff7ceefe5 in malloc_printerr (str=str@entry=0x7ffff7e17bf0 "free(): double free detected in tcache 2")
at ./malloc/malloc.c:5772
#7 0x00007ffff7cf154f in _int_free (av=0x7ffff7e49ac0 <main_arena>, p=<optimized out>, have_lock=0)
at ./malloc/malloc.c:4541
#8 0x00007ffff7cf3d9e in __GI___libc_free (mem=0x555555ad82a0) at ./malloc/malloc.c:3398
#9 0x00005555557c12e9 in free_rect () at rect.c:48
#10 0x00005555557d77a2 in freedynamicdata () at save.c:1240
#11 0x0000555555682754 in nh_terminate (status=0) at end.c:1671
#12 0x000055555589af15 in opt_terminate () at ../sys/unix/unixmain.c:768
#13 0x000055555589af7a in after_opt_showpaths (dir=0x0) at ../sys/unix/unixmain.c:796
#14 0x0000555555693dd9 in do_deferred_showpaths (code=0) at files.c:4491
#15 0x0000555555778405 in initoptions () at options.c:6948
#16 0x0000555555899cd9 in main (argc=2, argv=0x7fffffffdad8) at ../sys/unix/unixmain.c:151
This helps avoid a potential chicken-and-egg scenario
with the system configuration file (sysconf).
If sysconf wasn't accessible at the expected location, it
caused an immediate exit, without relaying any helpful
information. That happened even when using:
'nethack --showpaths'
That's particularly unhelpful, because the --showpaths
output might have been useful towards understanding where
NetHack was looking for such things.
That left you without an easy recourse to identify where
the game is looking for the sysconf file. That might be
especially troublesome if you didn't build the game
yourself.
GitHub 1343 report by @ars3niy:
"When you are blind and see with telepathy a monster whom you then hear read
a scroll, said monster turns into an "I". While it reveals which one exactly
read the scroll, it is strange that you can no longer see it with telepathy
until it moves to another square."
Fixes#1343
There was a transcription error in the comments in cstd.h for
the standard list of header files, where only the description
remained for <stdlib.h>, not the name of the file itself.
Remove several extraneous inclusions of the standard C99 headers.
Tested on the following afterwards:
Linux (using hints/linux.370) including tty, curses, qt6, and X11
macOS (using hints/macOS.370) including tty, curses, qt5, and X11
Windows MSYS2 using sys/windows/GNUmakefile
Windows Visual Studio using sys/windows/Makefile.nmake
msdos cross-compile on Ubuntu using djgpp cross-compiler
Various bits I had in progress before Michael's commit.
Mainly forget engravings when bones are saved instead of leaving them
flagged as seen for the next hero who gets the level.
GitHub issue reported by ars3niy:
https://github.com/NetHack/NetHack/issues/1303
@ars3niy commented on Oct 27:
Stepping on a square with a dust or "graffiti" engraving while blind
produces no message because presumably you can't read them by swiping
the floor with your hands, however the engraving glyph still shows up on
the map afterwards. While this helps zen players, it looks like a bug.
@ville-v commented 3 days ago:
Searching while blind also reveals the engravings. Here is a save file
demonstrating the issue.
[...]
This adds an erevealed bit to engravings, to accompany the the eread
bit that is already there.
eread: refers to the text of the engraving
erevealed: refers to the engraving map symbol
Hopefully, this resolves issue 1303 without creating additional bugs.
This invalidates existing save files and bones.
Fixes#1303
Issue reported by elunna: the message given when zap_over_floor()
hits iron bars with lightning or acid was substituting a couple of
words or phrases in the wrong order, resulting in
|The {melt|dissolve} iron bars somewhat but remain intact.
when the iron bar location is flagged as non-diggable. It should be
|The iron bars {melt|dissolve} somewhat but remain intact.
Not mentioned: the corresponding message for locations that aren't
flagged as non-diggable used "melt" unconditionally. Change it to
keep "melt" for lightning but switch to "corrode away" for acid.
Fixes#1342
After finding a trap on a chest or a large box, remember it
as trapped: "You see here a trapped large box."
Randomly generated chests and boxes can be obviously trapped.
Allow defining obviously trapped containers via lua.
Invalidates saves and bones.
A fix in Janurary to avoid appending engraving text or headstone
text when examining a map location where a monster or object covers
the engraving or headstone inadvently broke the /e and /E variations
of the '/' command, which is intended to list such text even when
covered.
We can't rely on doopen_indir return value to
check whether hero moved and opened a door.
Instead, explicitly check whether the door is still
closed, and whether hero moved.
The ones below marked "left,revisit" might be worthy of code changes
explode.c:removed: arg sx,sy passed to breaks() are coordxy and so are the parameters
invent.c: removed: discover_artifact() parameter is xint16, so change cast to match
mail.c: removed: gv.viz_rmin[] contains coordxy's, and enexto() 2nd param is too
mkmaze.c: removed: x, y are coordxy and so are cc->x, cc->y
mkroom.c: removed: tx, ty are coordxy and so are parameters to occupied()
mplayer.c: left,revisit: x,y declared int, but mk_mplayer() params are coordxy
sp_lev.c 2890: left alone: x,y declared int, but is_ok_location() params coordxy
sp_lev.c 4114: left alone: cast from lua_Integer
sp_lev.c 4123: left alone: cast from lua_Integer
sp_lev.c 4650: left alone: cast from lua_Integer returned from lua_tointeger
sp_lev.c 4765: left alone: cast from int_Integer returned from lua_tointeger
sp_lev.c 4772: left alone: cast from int_Integer returned from get_table_int
teleport.c 366: left alone: cast from int returned from rn2()
timeout.c 2171: left alone: cast from long
vault.c: left,revisit: guardx,guardy declared int, but bestcc fields are coordxy
worm.c 791: left,revisit: wseg.wx, wseg.wy are coordxy, so are nx, ny, but not
ox, oy; why are ox, oy needed at all?
worm.c 955: left alone: wx, wy are coordxy, wseg_at() params are int x, int y
zap.c 5061: left alone: cast from long