Add some basic spellcasting stuff to the tutorial: read a spellbook,
cast a spell. If the hero doesn't have enough energy, just adds
a note saying so.
Remove/restore the known spells when entering/leaving the tutorial.
Seems like several new players did not find the "hidden" stairs.
Add iron bars to show a glimpse of them - the hero still needs
to find the secret door in to the room.
Noticed a strange oversight in knockback: Hero hitting a monster
did not cause knockback, unless polymorphed into a monster.
Add knockback chance if we're using a weapon, not twoweaponing,
and dealing some damage.
Weapons that can do knockback are lucern hammer, bec de corbin,
dwarvish mattock, (silver) mace, morning star, war hammer,
club, quarterstaff, aklys, flail, pick-axe, and grappling hook.
Iterating over a large set of locations in a selection caused a memory leak.
Lua couldn't do garbage collection in the middle of the iterator function,
so it eventually ran out of space, and just quietly dropped stuff.
When I reworked amnesia to not forget levels or objects, I removed
the forgetting from the mind flayer attacks. I intended to add
something to replace it, but forgot ...
Grimtooth is now permanently poisoned, protects the wielder from
poison, and can be invoked to throw poison.
Permapoison code comes from xNetHack by copperwater <aosdict@gmail.com>.
If user has changed the stone glyph to something other than a space
(or uses a tileset), Sokoban levels showed the unreachable stone outside
the map area. Prevent marking those areas as seen, so the stone
glyphs aren't shown.
Those places that use get_table_str_opt() to get an optional string
value can instead use a function that returns a string.
This can be used for example in quest data lua table, or some table
fields in the lua api bindings, or the dungeon definition.
For example, in quest.lua
text = "You again sense %l pleading for help.",
could be replaced with
text = function() return "You again sense %l pleading for help."; end,
which of course allows using lua to build the string.
There were couple reports of doors being generated in a corner
of a room. This happened for randomly generated irregular rooms,
because the code that was deciding if a corridor starting or
ending location was good did not handle irregular rooms at all.
This changes the corridor code so it can now generate start and
end points properly for any valid position in irregular rooms,
instead of only on the edges. This means the corridor sometimes
meanders a bit more than before, because it tries to find
the end point away from the edge of the room rectangle.
Also added is sanity checking for the randomly generated rooms
and corridors level, testing for door placement and room connectivity.
And another fix for a rare special case where dig_corridor
created a zero-tile long corridor; the entrance door was placed,
but there was nothing behind it.
Fixes github #1269 and #1385
Instead of packing a coordinate into unsigned long, store the goal in
a coord struct, making the code a bit cleaner. Monster struct is
of course slightly bigger, but that should not really matter.
No change in monster behaviour.
Breaks saves and bones.
An assumption of monster generating code is that monsters within a class
appear in increasing order of difficulty. This wasn't the case with
some monsters, but swapping the monsters around is rather intrusive,
and doesn't really lend to changing monster difficulties when needed.
As a result, for example ghouls would not randomly generate when they
should have at certain level difficulties (where a ghoul is weak enough
to generate but an ettin zombie would be too strong).
Keep a separate array of monster indexes sorted correctly, generate it
when required by mkclass()
Description of this bug via copperwater <aosdict@gmail.com>
Tutorial code doesn't handle saving and reloading the game gracefully,
and manually saving has been disabled in there already.
Also disable automatic saving in the tutorial when the terminal goes away.
Tame earth elemental picked up a no_charge object from a shop and moved
it out of the shop, causing "no_charge obj not inside tended shop"
impossible. Non-tame monsters picking up no_charge items cleared that
bit, so make the same happen for pets.
If one or more boulders were next to lava and hero broke a wand of digging
next to that location, the boulder(s) stayed over the lava causing a sanity
checking error.
Casting charm monster with pets nearby could reset the edog struct.
If the pet ate a mimic corpse and was pretending to be something else
when that edog reset happened, the sanity checking would issue an impossible.
The error happened because meating was reset, but the pet appearance was not,
but the edog struct reset is the part being wrong. Lets not do that.
To reproduce, turn on sanity checking, create a tame dog, give it a mimic corpse
to eat, #wizcast charm monster next to it.
This time the no_charge object was being carried by a pet.
To trigger, drop an object into shop, decline to sell it,
pick up an object belonging to shopkeeper, decline to buy it,
wait for your pet to pick up the no_charge object you dropped,
teleport out of the shop, wait for shopkeeper to walk out of
the shop.
- Add a vision sanity checking routine
- Recalc block point when digging a door for temporary clouds
- Add recalc_block_point after cvt_sdoor_to_door, because doorways
on the Rogue level have no doors, and otherwise the sanity checking
would complain. This doesn't actually change how the Rogue level
vision works, as it uses a different vision system
- Monster using a trap in a secret corridor revealed the corridor,
but didn't unblock the vision unless you saw the location
Sanity checking was complaining about a no_charge obj in untended shop.
Angry shopkeeper was accepting thrown items as no_charge objects:
To reproduce the impossible, kick down the shop door angering
the shopkeeper. While the shopkeeper is still in their shop,
throw an item they don't want into the shop. Wait for the shopkeeper
to get out of the shop.
Move the anger checking before the sell auto-accept code,
so the shopkeeper will charge for the object.
remove_object cleared the vision when the last boulder was removed
from a location, without considering temporary [poison] clouds.
This particular case happened when pushing a boulder.
We can't just unconditionally unblock vision for a location when a boulder
falls into a pool, because the location may also have a (poison) cloud on it.
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 ...)
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.)
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.
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.