Demon lords and princes have a chance to resist the effect.
Demons in quest when nemesis is alive have a very high chance
of resisting.
When invoked in Gehennom, teleports the demons within the same
level.
Add macros to convert AD_foo, WAN_foo, and SPE_foo to relative values
for passing to BZ_U_foo and BZ_M_foo macros.
Change some return values in monster spellcasting function from
magic numbers to MM_MISS or MM_HIT.
Make buzzmu consider hero resistances - previously the
monster with innate zapping ray (Angels and Asmodeus) would
just keep doing that attack, but they will now just curse if
it saw the hero resist the attack.
When a monster at least two sizes larger hits another one,
there's a chance the smaller defender will be knocked back.
This applies also to hero, attacking when polymorphed to
a large monster, or defending from a large monster.
Most of the monsters that can knock back are giants and dragons.
Idea and some of the code from EvilHack.
... unless there's some other form that would override the choice,
such as a worn dragon armor, lycanthropy, or vampirism.
The polymorph will be in effect for 10-24 turns.
Long swords are overused, and Knights already start with a long sword.
No other roles start with a spear. Lawful Valks shouldn't have an easy
way to get Excalibur.
There's also historical precedence for valkyries with spears, see eg.
Wagner's Ring Cycle.
This makes Valks early game damage slightly lower, although dwarven spear
does the same damage to small monsters as long sword, and there should be
plenty of chances to get one from the mines. Spears can also be thrown.
This change has been done in several variants, eg. xNetHack and Fourk.
My changes were too drastic, so reduce the drain and damage so it
matches all the other traps. Now the anti-magic trap will always
ding your max energy a bit, in addition to the physical damage done
if wearing magic resistance.
Make the trap routine claim the trap killed the monster even
though it was drowning that did it, otherwise callers cannot
rely on the trap routine return value.
When a monster with innate teleporting stepped on a fire trap on ice,
the ice melted and the monster teleported away before falling
into the pool. If the monster's new location had a trap, the code
tried to access the deleted fire trap.
Add some basic functions to iterate through the monster list,
ignoring dead monsters. Mainly just to allow splitting up code
into discrete functions.
Not quite happy with the get_iter_mons_xy - should probably have
a pointer to iterator data struct, which gets passed through instead,
but this works for now.
When you're swallowed and throw a missile that kills the swallower,
the thrown missile is picked up by the swallower before death.
This caused a panic when you threw a potion, which was first picked up
by the swallower, which upon death dropped the potion on the floor,
but then throw code was trying to destroy the potion ...
Instead of hardcoding the lava terrain change in core, if the stairs
are created in a fixed location, force the terrain to room floor first.
Move the surrounding lava changing to room floor to the Val-goal lua
file.
While testing the new mouse action menus, it was quite annoying
to try and hit some shorter entries. Make all the selectable entries
the same maximum length, and with text left justified.
Allow selecting an item from inventory and show a menu of actions
applicable for that particular item. Some of the entries might
be slightly spoilerish (eg. it'll reveal that you can read T-shirts),
but the improved usability for new players is more than worth it.
Generally known as "item actions", this was first implemented
in AceHack by Alex Smith.
My fixes to the travel stuck oscillation did not fix all of them,
and I've even seen a 3-step loop - which my fixes cannot detect.
I guess there could be arbitrary-sized loops too.
To definitely fix this, keep track of all the map locations travel
has moved the hero through, and if it tries to go on a location already
used, stop travel and give the unsure -message.
When creating stairs in a random location in a special level lua file,
there was a chance it overwrote eg. other stairs. Make randomly placed
stairs pick locations with room, corridor, or ice terrain.
Fixes github issue #702
There were at least two cases of travel oscillation that occurred,
even after my previous fix. To fix those, the guessing routine
would also have to consider distance to original target location.
I opted not to make that part more complex - as there was
no guarantee those changes would catch all of the oscillation cases.
Instead, when we're guessing where to move, and we would actually move
back to where we came from, stop travel, and give a message.
This should fix (and fuzzing seems to confirm) all of the travel
oscillation bugs for good, and it shouldn't affect actual good travel.
(Other than the player getting a YAFM in the occasional case of trying
to travel to a location with no travel path)
There's been occasional reports (perhaps once or twice a year)
of travel getting stuck moving repeatedly between two locations
next to each other, but it has never been reproduced before.
This special level lua code fragment is a minimal test case
which triggers it:
--- special level lua fragment, indented
des.map([[
--##---
###----
#-+----
####--L
]]);
des.door("open", 2,2)
--- end of special level lua fragment
The open door is required.
Magic map the level. Start from somewhere NW of the door, and try
to travel to the lava pool. Hero will get stuck oscillating between NW
of the door and two steps west of the door.
Here are the maps of the travel[][] array values from findtravelpath()
in those two steps in the above map:
------------- -------------
| . . 2 3 | | . . 1 2 |
| 1 1 2 . | | 1 @ 1 . |
| @ . . . | | 1 . 2 . |
| 1 1 2 . | | 2 . 3 4 |
------------- -------------
There are two possible closest locations to the lava pool,
the one marked with "3" on the left map, and "4" on the right map.
Based on that alone, both would be valid places to path to.
But, in the left case, hero could not see the bottom location, so
the code won't even consider pathing to it, so it will start moving
towards the "3".
When hero moves to the second position, in the right map, now the "4"
could be seen. Now there are two possible closest locations we could
choose from. The code that scans the possible locations goes from top-left
to bottom-right, first going down (y-axis). So, the code sees the
"2" on the right. distmin() to there is 2. Good, we pick that location
to path to. Next, going down, the code considers the "4" ... which is
also equally close to the lava pool. and distmin does not consider terrain,
so ignores the door, so it has the same distmin value of "2", so the
code picks this location.
But: this was just a guess, because there's no known valid path to the
lava pool. The code loops back up to rebuild the travel[][] array
with a new starting location as the "4" from the right map, pathing
back to hero.
This is that travel array map:
-------------
| . . . . |
| 4 @ 3 . |
| 3 . 2 . |
| 3 2 1 x |
-------------
The way travelstepx and travelstepy arrays are built means that the first
location that considers the hero's location is the "3" SW of hero, so
hero will move there next. Repeat from beginning. If there was no door,
the travelsteps would reach hero's location first from SE.
(I left the travel[][] array rebuild and travelstepx/travelstrepy build
off from the other movement position, as it's not relevant)
The fix: When considering which of the two possible closest places to the
lava pool to path to, use the one with the lowest value in the travel array.
That value is the real number of moves it takes for the hero to walk there,
so the code will consistently path to the upper location, as it is "2",
instead of considering the "4" below it.
Also some minor code reorg, so it considers couldsee first instead of
later in two separate places.
Make selection rndcoord return a table with x and y keys.
Allow (most) coordinate parameters accept such a table.
Fix selection and des lua tests broken by the above changes and
an earlier change, because selections tried to set terrain
at column 0, and it now causes a complaint.
When a monster hit hero with an artifact with drain-life attack
(Stormbringer or The Staff of Aesculapius), and hero lost a level
and hero had more max hp in the lower xp level, the math made the
attacker lose hp. This could put the monster hp in the negative,
causing "dmonsfree: 1 removed doesn't match 0 pending"
If special level lua code creates a melting ice timeout, but
later in the code places stairs, or a trap which might change
the ice to room floor, the timer sanity checking doesn't
like that.
Expose map-location specific timers to lua scripts. For example:
nh.start_timer_at(x,y, "melt-ice", 10);
Currently only available timer type is "melt-ice".
When applying some tools (whips, polearms, grapples), or rubbing
a lamp, or when fireassist is on and you fire something without
wielded launcher, the automatic wielding should take as much time
as wielding the item normally does.
Fixes#696
Expose object timers to lua scripts. For example:
local o = obj.new("cockatrice egg");
o:placeobj(5, 5);
o:start_timer("hatch-egg", 3);
Available methods are:
- obj.has_timer("rot-corpse")
returns true if object has attached timer, false otherwise.
- obj.peek_timer("hatch-egg")
returns an integer value, which is the turn when the timer
attached to the object would trigger. returns 0 if no such timer.
- obj.stop_timer("shrink-glob")
stops attached timer, or if no timer type is given, stops all
timers attached to the object.
- obj.start_timer("zombify-mon", 15)
starts a timer with a trigger time in that many turns in the future.
replaces any previous timer of the same type.
Valid timers are "rot-organic", "rot-corpse", "revive-mon",
"zombify-mon", "burn-obj", "hatch-egg", "fig-transform",
and "shrink-glob". Also "melt-ice" is recognized, but does nothing
to objects.
Allow defining rolling boulder launching location in special level
lua scripts:
des.trap({ type="rolling boulder", coord={7, 5}, launchfrom={-2, -2} });
launchfrom is relative to the trap coord.
Gulping can move the trapped monster to another location, while
still being marked as trapped. I don't want to deal with this,
so just say purple worms can't swallow trapped monsters...
Make gods avoid giving blank spellbooks as gifts, if you're
illiterate. But if you do get a blank spellbook as a gift,
don't force-learn that non-existent spell.