My change to make items thrown by monsters landing on altar
caused doaltarobj being called twice when hero dropped an item
on it. Call the newer instance only when monsters are moving.
Two error cases with the map generation in minetn-6:
first one was the lregion placement impossible, caused by randomly
generated mines not going past the map either left or right, and
the stair generation being restricted outside the fixed map.
second was one side of the map being unreachable, because the
mines layout joined to the other side right at the edge of map
behind the small room with the "x" mapchars.
... if the boulder is in a position they want to move to.
Shopkeepers, priests, and the quest leader can break one boulder
and then need to take several turns before being able to break
another. Riders can break a boulder every turn.
If for some reason a shop room has multiple doors, try all of them
to find a good shop door, instead of just the first one, and failing
if it wasn't a good one.
This only matters for wizard-mode with SHOPTYPE environment var.
Wizmode testing shop generation, I encountered impossible
"Where is shopdoor" - the room that was being turned into
a shop had a subroom sharing the outer south wall with
the parent room, with a random niche placed such that it was
actually in the subroom wall. The niche door was still added
to the parent room, and the shop generation was trying to use
that door as the shop entrance.
As random niches are only used in room-and-corridor style
levels, subrooms aren't that common, so I just opted to
skip the niche generation if it was going to be placed
without being directly attached to the room it wanted.
The niche generation could be changed at a later date to actually
add the niche door to the correct room instead, if we ever feel
it's necessary to have random niches in subrooms.
As an interesting side note, I had no idea random niches were
only placed in the south or north walls of rooms, never to
east or west.
The "butterfly" shaped bigroom was missing the four fountains
in the corners of the room - this was due to my copy-paste error
when converting the bigrooms from des to lua.
Also add some variation to the bigroom.
In curses, selecting a partial stack, then unselecting the entry,
and then selecting it normally, the entry still kept the quantity
from the partial selection. Make it behave like all the other
windowports by resetting the quantity when the entry is unselected.
Previously when monster was interested to pick up an item,
the code went through the whole object chain, so going through
all the items on the level. This caused problems with some games,
for example where the player created thousands of meatballs
in separate stacks.
Changed the code so it now looks at the map locations inside
the search radius, and the stacks in those map locations,
skipping locations as early as possible.
This should have no difference in behavior, except on Amiga;
as it is no longer supported, I removed all the amiga-specific
config-line handling. If anyone steps forward to support
that platform in the future, it shouldn't be too hard to
add those back.
- add a themeroom with random buried zombifying corpses
- disturbing buried zombies makes them revive much faster
- lua des.object() now returns the object it created
Setting protection from shape changers via wizintrinsics
caused a sanity error on the next turn, if any monsters affected
by it were in changed shaped on the level.
Call rescham after setting the timeout, so the monsters will
immediately revert to their own form.
While fuzzing, the game got stuck here trying to generate
a random stoneable monster for a Medusa level statue.
I didn't investigate deeper why it failed to find a matching
monster type.
Defining des.object({ id="large box", locked=false })
was the same as random locked state. Make it actually mean unlocked,
and not defining locked at all means random.
Previously the fuzzer usually stayed in the Dungeons of Doom,
only very rarely going to other dungeon branches. Now, it will
randomly choose a dungeon branch and a level in that branch
to level teleport to.
Special level creation could make levels with boulders on top
of lava or water; this was caused by mazewalk populating the maze
before the rest of the level was created.
Add a post-level-creation map cleanup routine, where boulders
and traps on liquid terrain are removed.
While watching a ttyrec, I noticed strange behaviour in
the cursor updates; it was moved to approximately middle
of the map window every so often, usually when doing ranged
attacks. This wasn't really noticeable in normal gameplay,
as it was moving the cursor there, and then almost immediately
to where it was supposed to be.
I managed to trace it down to the refresh() in curses_delay_output().
That call updates the terminal to match the ncurses stdscr window,
but the stdscr window cursor position wasn't updated by NetHack.
I happened to notice when looking at a ttyrec that farlooking
with automatic description would blink the cursor on hero for
one frame, and then back on the farlooked map location.
parse_escape_sequence changed getch timeout, but when receiving
a certain escape sequence, it returned without changing the
timeout back. This caused all subsequent getch calls be
non-blocking, and getch returns ERR when there's no input
waiting in that mode.
NetHack interprets ERR as the terminal going away, so performs
an automatic save.
Doors weren't getting added to the correct subrooms in certain cases.
Also fix one of the themerooms, because doors have to be added
after subrooms; there was a possibility of no door to the subroom(s)
in that themeroom, because the subrooms overwrote the doors in
the parent room.
Test case for the subroom doors:
Large room, with a medium subroom, with a tiny subroom inside that.
The doors go from outermost room <-> tiny innermost room <-> middle room.
des.room({ type = "ordinary", x = 1, y = 1, w = 10, h = 10,
contents = function()
des.room({ type = "ordinary", w = 6, h = 6, x = 2, y = 2,
contents = function()
des.room({ type = "ordinary", w = 2, h = 2, x = 0, y = 0,
contents = function()
des.door({ state="random", wall="south", pos = 1 });
end
});
des.door({ state="random", wall="north", pos = 1 });
end
});
end
});
Before this fix:
ROOM: ndoors:1, subrooms:1
SUBROOM: ndoors:1, subrooms:1
SUBROOM: ndoors:1, subrooms:0
after this fix:
ROOM: ndoors:1, subrooms:1
SUBROOM: ndoors:1, subrooms:1
SUBROOM: ndoors:2, subrooms:0
I felt it was strange that archeologist started out both
fast and stealthy, but didn't gain searching until level 10.
So, archeologists now start with searching, gain stealth at 5,
and fast at 10.
Similarly valkyries starting out stealthy felt odd, so now they'll
get it at level 3.
This leaves only the rogue starting out innately stealthy, which
feels appropriate.
Adds a more general way to handle gameplay tips, and adds
a boolean option "tips", which can be used to disable all
tips. Adds a helpful longer message when the game goes
into the "farlook" mode.
Also adds a lua binding to easily show multi-line text
in a menu window.
Breaks save compat.
Can't use gc.context.mon_moving to check if the ray was caused
by hero, as some rays can happen while hero is moving in response
to their action - for example a bolt of lightning from a god.
dobuzz() uses positive type values for magic rays caused by hero,
so just use that.
maybe_unhide_at tried to handle both a monster and hero, but
hero being hidden is in u.uundetected flag, and the code was
only checking the monster mundetected field.
The code should probably be changed, either to change all uses
of the u.uundetected to gy.youmonster.mundetected, or perhaps
use a macro ... but these changes are all too big for me
to tackle for now.
Add "walls of lava", basically lava which blocks vision and
require a bit more than just levitation or flight to move through.
No levels use this yet, as testing isn't thorough enough.