Commit Graph

333 Commits

Author SHA1 Message Date
Pasi Kallinen
d53cd28d46 Make extended commands return defined flags
Instead of returning 0 or 1, we'll now use ECMD_OK or ECMD_TURN.
These have the same meaning as the hardcoded numbers; ECMD_TURN
means the command uses a turn.

In future, could add eg. a flag denoting "user cancelled command"
or "command failed", and should clear eg. the cmdq.

Mostly this was simply replacing return values with the defines
in the extended commands, so hopefully I didn't break anything.
2021-12-30 19:16:33 +02:00
Pasi Kallinen
b1ed92abad Apply runmode to multiturn actions 2021-12-21 17:37:48 +02:00
PatR
2278434228 simplify issuing urgent messages
Change
 custompline(URGENT_MESSAGE, mesg, ...);
calls to new
 urgent_pline(mesg, ...);
2021-12-20 08:30:48 -08:00
PatR
420d121f93 'urgent' messages
Follow up on some old groundwork.  For tty, if the core has designated
a message as 'urgent', override any message suppression taking place
because of ESC typed at the --More-- prompt.  Right now, "You die"
messages, feedback about having something stolen, feedback for
"amorous demon" interaction (mainly in case of armor removal), and
exploding a bag of holding are treated as urgent.

The "You die" case is already handled by a hack in top-line handling;
I left that in place so the conversion of 3 or 4 pline("You die.*")
to custompline(URGENT_MESSAGE, "You die.*") was redundant.  There
are probably various non-You_die messages which precede done() which
should be marked urgent too.

Other interfaces might want to do something similar.  And we ought to
implement MSGTYPE=force or MSGTYPE=urgent to allow players to indicate
other messages that they want have to override suppression.  But I'm
not intending to work on either of those.  I mainly wanted to force
the magic bag explosion message to be shown since a sequence of "You
put <foo> into <bag>." messages is a likely candidate for --More--ESC.
2021-12-17 17:46:49 -08:00
Pasi Kallinen
f6b7be49f4 Accessibility: give a message when teleporting a monster
Teleporting a monster only updated the map. Give a message
so blind players can get the same information.
Making a monster invisible gives the same message, if you
cannot detect invisible.
Several other places where monsters teleported themselves
now also give the same message.
2021-12-12 16:50:49 +02:00
PatR
b4908f6928 fix pull request #621 - potential divide by 0
The pull request by argrath changes weight_cap() to never return a
value less than 1 because try_lift() divides by that return value
and a 0 would trigger a crash.  The code involved is used when
attempting to pull a monster out of a pit via #untrap.

I'm fairly sure that weight_cap() can never produce a value that's
less than 1 already, but have put in a variation of the PR's fix.
I've also implemented a different fix that removes the division
from try_lift().  The original code seems to have gone out of its
way to avoid calculating inv_weight() twice, but doing the latter
(for the once in a hundred games where it might happen) greatly
simplifies things by removing details of carrying capacity.

Fixes #621
2021-10-25 14:51:26 -07:00
PatR
6edadc4884 fix github issue #614 - applying polearm at doors
Reported by G7Nation; attacking walls and such with a polearm just
gave lackluster "you miss; nobody's there" feedback.

Make applying a polearm at some non-monster locations give feedback
similar to using 'F'orcefight with melee weapons.  Was
|You miss; there is no one there to hit.
now
|You uselessly attack the closed door.

Also, extend the supported locations to include dungeon furniture.
Was
|You attack thin air. ('F')
now
|You harmlessly attack the throne. ('F')
|You uselessly attack the throne. ('a')

This doesn't address #613:  attempting to hit non-visible locations
with an applied polearm.

Closes #614
2021-10-24 10:06:30 -07:00
PatR
37e63f6829 breaking wielded fragile item against iron bars
Reported by entrez, wielding something fragile (potion of acid
perhaps), and using F to smash it against iron bars called breaktest()
directly, then a second time indirectly through hero_breaks() via
hit_bars().  There is a random chance to resist breaking (99% for
artifacts, 1% for other items) so breaktest() might say that something
will break on the first call and that it will not break on the second
call, or vice versa.  That could remove uwep from inventory then leave
it in limbo without destroying it, or destroy uwep without removing it
from inventory first triggering impossible "obfree: deleting worn obj".
2021-10-22 19:11:51 -07:00
nhmall
592e00b981 melting ice follow-up 2021-10-17 08:20:50 -04:00
nhmall
17165e3b92 melting ice timeout issues
Reported directly to devteam by entrez via email:
>
> I noticed some potential issues with (melting) ice:
>
>   * Digging down into ice, or setting a land mine on the ice and
>   triggering it, doesn't remove the melt_ice timeout, so it can result
>   in a sequence like dig down -> pit fills with water -> freeze water
>   -> freezing water tries to set melt_ice timeout -> duplicate timeout
>   impossible.  Or if you don't freeze the water again, melt_ice will
>   run on a non-ice surface, which might at least produce strange
>   messages.
>
>   * Setting a land mine on ice: melting ice doesn't do anything with
>   the trap, so there is still a land mine which you can trigger by
>   flying over the water (the land mine's trigger is also still
>   described as being 'in a pile of soil', despite being underwater at
>   this point).  Similar thing happens with bear traps.
>
>   * Not really related to _melting_ ice, but an exploding land mine
>   doesn't reset the typ from ICE to FLOOR (like normal digging does),
>   so it will result in a square with a pit that is also an ice square,
>   where the ice can melt under the pit and produce a combination
>   pit/moat.  If you then freeze the moat, the pit reappears on top of
>   the ice.
2021-10-16 22:22:33 -04:00
PatR
07b1d9d396 travelling through boulders
If the hero can move to a boulder's location via m<dir>, allow travel
to do so too.  You will always stop on the boulder spot rather than
keep going toward the destination because of change in visibility at
a boulder spot.

Giants should be able to see over boulders, and doing that for poly'd
hero would probably be straightforward, but when not poly'd, seeing a
giant beyond a boulder and vice versa seems like it would be a can of
giant-sized worms.

A couple of other miscellaneous changes are mixed in with this.
2021-10-16 09:54:08 -07:00
Michael Meyer
121290cde6 fix m-prefix movement into warning symbol (pr573)
https://github.com/NetHack/NetHack/pull/573 by entrez
Pull request comment states:
"Moving into a position containing a warning symbol with m-<direction> to
'safely' move would still attack as though the 'm' prefix was not
specified.  Ensure warning symbols are counted as 'detected' monsters
for this purpose, to avoid falling through to do_attack()."

Closes #573
2021-10-16 10:50:54 -04:00
PatR
e42488ca10 and even more boulders...
Revise the m<dir>-toward-boulder handling to let a hero who would be
able to squeese into the boulder's spot if it was blocked from being
pushed to do the squeeze without any pushing.

Unlike the previous changes, this might have an impact on play.  It
allows squeezing under then stepping past an unblocked boulder that's
in a corridor in order to be able to push it back the other direction
where maybe there's more room to maneuver it out of the way.
2021-10-10 18:05:11 -07:00
PatR
fc00ced6f4 yet more boulders: allow m<dir> to not push them
Allow a hero polymorphed into a giant to move to a boulder's spot
via m<dir> no-pickup move, instead of having to push it until the
way is blocked by something and then having push failure move hero
to the spot.

Also change m<dir> when not a giant to no longer push the boulder.
No time will elapse when not moving unless hero who didn't know
that there was a boulder there learns that one is.  Since no actual
push attempt gets performed, player doesn't learn whether there is
anything beyond the boulder that inhibits it from being pushed.
2021-10-10 15:02:21 -07:00
PatR
0e5b6ed519 better boulder pushing feedback
When you push a pile of boulders, describe the second and remainder
as "the next boulder" rather than just "the boulder".  Matters most
when pushing into water or lava and you keep on pushing when the
first one or more sink into the pool or plug it, but also matters
for an ordinary push where the top-most one moves successfully and
then blocks the continuation attempt to push the second one.  It was
somewhat confusing when all the messages said "the boulder" whether
they were referring to the same boulder or different ones.

Multiple pushes on the same move has always been a bit odd, but this
doesn't change that, just the feedback it generates.
2021-10-09 10:54:47 -07:00
nhmall
d3acd8aa07 Merge branch 'ice-running' of https://github.com/copperwater/NetHack into several-pr 2021-09-26 08:54:47 -04:00
nhmall
026aec1086 Merge branch 'fix-travel' of https://github.com/entrez/NetHack into several-pr 2021-09-26 08:54:10 -04:00
Pasi Kallinen
12800bf84b Walking near buried zombifying corpses wakes them up
Moving without stealth will reduce the zombifying timeout
of buried corpses under and around hero's location.
2021-09-18 21:24:52 +03:00
copperwater
5b0c2033f7 Fix: running on ice sent hero in weird directions
This is because ice was being treated as a type of corridor rather than
a ROOM space, and running has rules for following similar terrain. In
reality it's not a corridor and should behave like normal room for
running purposes.

This was obvious in the valkyrie quest upper levels with ice fields, in
which running into the edges of the map obliquely, or into the corners
of the map, would send the hero flying around the edge in a different,
probably unintended direction.
2021-09-07 15:17:33 -04:00
Pasi Kallinen
2748ac746e lookaround comments
trying to figure this out
2021-08-12 19:38:29 +03:00
Michael Meyer
38d027d1f9 Fix: travel from 'interesting' position
(including resuming travel after being interrupted)

Attempting to travel from an 'interesting' spot that would normally
stop travel mid-attempt (next to a door, next to a monster, etc) would
fail to get off the ground, because the 'interesting thing' would halt
travel before taking the first step.

Prior to 433f0cc, initiating travel would immediately trigger a call to
domove in rhack; as part of refactoring travel, the order of events in
rhack was changed so that this didn't happen immediately as before.  Add
domove to the end of dotravel_target to produce a similar effect to the
previous arrangement.

domove also zeroes out g.domove_attempting, which I think is the reason
c0c617c seemed to mitigate some of the issues associated with this
problem (e.g. travel target selection seemingly not registering right
away).

Fixes #559
2021-08-11 09:19:56 -04:00
Pasi Kallinen
7a9dd64cb5 Use mon_visible 2021-08-09 19:16:36 +03:00
PatR
e5f96cd329 diagonal movement glitch
|..X..
|.X}X.
|..X..
When testing the odd Samuari moats, I discovered that you could
easily walk diagonally between any two of the solid stone pillars
and fall into the water but you would always drown because it's a
no-teleport level and the crawl routine wouldn't let you back out
via that same diagonal.

The crawl routine is also being used by travel for the last step--a
post 3.6 change--so there was an unnecessary restriction on diagonal
movement there too.
2021-08-02 17:44:03 -07:00
Pasi Kallinen
c0c617c413 Try fixing interrupted travel oddities
My earlier commit (433f0cc) changed traveling, and caused some
strange problems when travel was interrupted. This seems to
fix those problems.
2021-07-29 21:21:28 +03:00
Pasi Kallinen
f25a6e26ee Use enums and defines for directions 2021-06-27 15:46:56 +03:00
Pasi Kallinen
76f77ee0cc Add assistance to fire-command
Allows the fire-command to autowield a launcher; it will now
do either swapweapon or wield an appropriate launcher, if you
have ammo quivered.

This assistance can be turned off with the fireassist boolean option.

Adds a rudimentary command queue, which allows the code to add keys
or extended commands into the queue, and they're executed as if
the user did them.  Time passes normally when doing the queue,
and the queue will get cleared if hero is interrupted.
2021-06-16 13:14:32 +03:00
nhmall
254c6c55f5 Windows build warning and Makefile update
.\hack.c(2657): warning C4389: '!=': signed/unsigned mismatch
Visual Studio autodetection update for Makefile.msc
2021-06-04 00:14:37 -04:00
Pasi Kallinen
6b60618e0e Exploding spheres cause real explosions
Despite active explosion attacks being called explosions in-game,
they only affected a single target, and were handled differently
from actual explosions. Make them do an actual explosion instead.
This should make spheres more interesting and inspire different
tactics handling them.

Because spheres deal more damage on average and can destroy items
in their explosions, their difficulty has been increased slightly.

Polyselfed hero exploding won't cause elemental damage to their
own gear.

Originally from xNetHack by copperwater <aosdict@gmail.com>.
2021-05-22 13:37:39 +03:00
Pasi Kallinen
9fa9f00f8a Entering special room, wake up only that room
... instead of doing a level-wide wake-up.

Fixes #429
2021-05-05 20:34:05 +03:00
PatR
b4ae19ed0c fix "Killed by foo, while paralyzed by a monster"
If the killer and the paralyzer are the same monster, truncate
that to "Killed by a foo, while paralyzed".  When not the same,
spell out the paralyzer's monster type instead of using generic
"monster".  "Killed by a fox, while paralyzed by a ghoul", or
"Killed by a ghoul, while paralyzed by a ghoul" *if* they were
two different ghouls.
2021-04-22 16:13:41 -07:00
PatR
8bd08ebb71 level teleporters vs Ft.Ludios
From newsgroup discussion where slash'em changes have revealed a
latent nethack bug:  prevent placing level teleporters in single-
level branches.  The Knox level doesn't have any level teleporters
(or random traps) but wizard mode wishing could create them there.
They wouldn't do anything because the only possible destination
would be the same level.  Pushing a boulder onto one used to trigger
an infinite loop (and still does in slash'em, which has other
single-level branches besides Ft.Ludios) trying to relocate it.

Boulder pushing was changed 15 years ago to prevent the infinite
loop and to avoid giving "the boulder disappears" message when a
level teleporter failed, but rolling boulder traversal lacked that
same change--it wasn't vulnerable to looping but could give an
inaccurate message claiming that the boulder disappeared when it
actually didn't.  Fixing this is a bit late; rolling boulder trap
creation was recently changed to not choose a path that rolls over
teleportation or level tele traps any more.
2021-04-12 13:25:52 -07:00
PatR
7d77267f93 fix pull request #487 - one-step diagonal travel
When travel destination is one step away the code stops probing
for a path and reverts to normal movement, but it wasn't handling
the case where the one step was an impossible diagonal except for
hero being a grid bug.  If the situation was a diagonal that's
too narrow to squeeze through, travel would end and regular move
would fail.

I've rejected the suggested fix and done it differently, without
attempting to figure out why the change to end_running() would
have been wrong.  Clearly it was code that called end_running()
which needed to be fixed.

The test case was
 ..x|.
 ..|@.
 .....
while carrying enough that directly moving from '@' to 'x' will
not be allowed.  '@' would move one step south west and then stop
because findtravelpath() had ended travel due to single step move.
A similar case is
   ###
  |x-#-
  |0@.|
where 'x' is a doorway with intact open door and '0' is a boulder.
Prior to this fix, player would get "a boulder blocks the way" and
not move.  After, '@' will move northeast then northwest then west
to get into orthogonal position and finally south into the doorway.

Even though it definitely fixes both mentioned test cases, I won't
be surprised if this results in regressions for other situations.

Fixes #487
2021-04-04 17:23:46 -07:00
PatR
1e9fc3ddb3 pull request #465 - explding hero waking monsters
A polymorphed hero who exploded when attacking thin air would use a
radius based on experience level rather than the fixed radius that
the monster form itself used.  When exploding at a monster it didn't
wake other monsters at all.

Fixes #465
2021-03-29 09:35:43 -07:00
nhmall
7900632b50 Qt c++ function name shadow warnings
We have a struct called mkroom and a function called mkroom()
so c++ complains about the mkroom() function hiding the
initializer for the struct.

Similarly, we have a struct called attack and a function
called attack().

There may be a more elegant way of eliminating those two
warnings, but renaming mkroom() to do_mkroom() and
attack() to do_attack() was straightforward enough.
2021-02-03 10:55:07 -05:00
nhmall
d79365c6b0 add format string arg to Sprintf in hack.c 2021-02-02 17:20:41 -05:00
Bart House
a54a8c6854 Remove awful kludges dealing with command counts. 2021-01-30 19:06:27 -08:00
nhmall
f963c5aca7 switch source tree from k&r to c99 2021-01-26 21:06:16 -05:00
PatR
4c8a8bcfee fix github issue #431 - failed displacing
Being able to swap places with peaceful monsters instead of just
with pets made it possible to cause them to flee. Shopkeepers
wouldn't abandon the shop door but temple priests would attack
if hero tried to chat while they were fleeing.
2020-12-31 11:23:29 -08:00
nhmall
0c3b9642e4 pmnames mons gender naming plus a window port interface change
add MALE, FEMALE, and gender-neutral names for individual monster species
to the mons array. The gender-neutral name (NEUTRAL) is mandatory, the
MALE and FEMALE versions are not.

replace code uses of the mname field of permonst with one of the three
potentially-available gender-specific names.

consolidate some separate mons entries that differed only by species into a
single mons entry (caveman, cavewoman and priest,priestess etc.)

consolidate several "* lord" and "* queen/* king" monst entries into
their single species, and allow both genders on some where it makes some
sense (there is probably more work and cleanup to come out of this at some
point, and the chosen gender-neutral name variations are not cast in stone
if someone has better suggestions).

related function or macro additions:
    pmname(pm, gender) to get the gender variation of the permonst name. It
    guards against monsters that haven't got anything except NEUTRAL naming
    and falls back to the NEUTRAL version if FEMALE and MALE versions are
    missing.

    Ugender to obtain the current hero gender.
    Mgender(mtmp) to obtain the gender of a monster

While the code can safely refer directly to pmnames[NEUTRAL] safely in the
code because it always exists, the other two (pmnames[MALE] and
pmnames[FEMALE] may not exist so use:
    pmname(ptr, gidx)
      where -ptr is a permonst *
            -gidx is an index into the pmnames array field of the
             permonst struct
pmname() checks for a valid index and checks for null-pointers for
pmnames[MALE] and pmnames[FEMALE], and will fall back to pmnames[NEUTRAL] if
the pointer requested if the requested variation is unavailable, or if the
gidx is out-of-range.

Allow code to specify makemon flags to request female or male (via MM_MALE
and MM_FEMALE flags respectively)to makedefs, since the species alone doesn't
distinguish male/female anymore. Specifying MM_MALE or MM_FEMALE won't
override the pm M2_MALE and M2_FEMALE flags on a mons[] entry.

male and female tiles have been added to win/share/monsters.txt.
The majority are duplicated placeholders except for those that were
separate mons entries before. Perhaps someone will contribute artwork in the
future to make the male and female variations visually distinguishable.

tilemapping via has the MALE tile indexes in the glyph2tile[]
array produced at build time. If a window port has information that the
FEMALE tile is required, it just has to increment the index returned
from the glyph2tile[] array by 1.

statues already preserved gender of the monster through STATUE_FEMALE
and STATUE_MALE, so ensure that pmnames takes that into consideration.

I expect some refinement will be required after broad play-testing puts it to
the test.

    consolidate caveman,cavewoman and priest,priestess monst.c entries etc

This commit will require a bump of editlevel in patchlevel.h because it alters
the index numbers of the monsters due to the consolidation of some. Those
index numbers are saved in some other structures, even though the mons[] array
itself is not part of the savefile.

Window Port Interface Change

Also add a parameter to print_glyph to convey additional information beyond
the glyph to the window ports. Every single window port was calling back to
mapglyph for the information anyway, so just included it in the interface and
produce the information right in the display core.

The mapglyph() function uses will be eliminated, although there are still some
in the code yet to be dealt with.

win32, tty, x11, Qt, msdos window ports have all had adjustments done to
utilize the new parameter instead of calling mapglyph, but some of those
window ports have not been thoroughly tested since the changes.

Interface change additional info:

    print_glyph(window, x, y, glyph, bkglyph, *glyphmod)
            -- Print the glyph at (x,y) on the given window.  Glyphs are
               integers at the interface, mapped to whatever the window-
               port wants (symbol, font, color, attributes, ...there's
               a 1-1 map between glyphs and distinct things on the map).
            -- bkglyph is a background glyph for potential use by some
               graphical or tiled environments to allow the depiction
               to fall against a background consistent with the grid
               around x,y. If bkglyph is NO_GLYPH, then the parameter
               should be ignored (do nothing with it).
                -- glyphmod provides extended information about the glyph
               that window ports can use to enhance the display in
               various ways.
                    unsigned int glyphmod[NUM_GLYPHMOD]
               where:
                    glyphmod[GM_TTYCHAR]  is the text characters associated
                                          with the original NetHack display.

                    glyphmod[GM_FLAGS]    are the special flags that denote
                                          additional information that window
                                          ports can use.

                    glyphmod[GM_COLOR] is the text character
                                       color associated with the original
                                       NetHack display.

Support for including the glyphmod info in the display glyph buffer
alongside the glyph itself was added and is the default operation.
That can be turned off by defining UNBUFFERED_GLYPHMOD at compile time.
With UNBUFFERED_GLYPHMOD operation, a call will be placed to map_glyphmod()
immediately prior to every print_glyph() call.
2020-12-26 11:23:23 -05:00
PatR
1b7c372f5d fix #K3231 - objects vs pits and holes
This got out of hand pretty quickly.  can_reach_floor() had
different criteria than trap activation.  Objects dropped at a
hole locations that don't fall through were treated as if they
were at the bottom of an abyss, so couldn't be examined or
picked up.

This a bunch of changes; it is bound to introduce some new bugs.
2020-12-22 13:48:29 -08:00
PatR
b9535a84f1 displacing pets into water
Don't let hero at water or lava location swap places with a
pet that can't survive there.  This was a regression to 3.4.3
behavior introduced when displacer beast monster was added.
I can't remember whether the regression was intentional at the
time, but guess not because I'm fairly sure that I would have
included a comment about it.
2020-12-18 15:46:13 -08:00
Pasi Kallinen
ec1d01bbe1 Fix monster hide status when moving ball & chain 2020-12-15 17:35:18 +02:00
Pasi Kallinen
36d977f61f Unify HP loss and passing out from overexertion 2020-11-27 23:43:59 +02:00
PatR
6cbd2c5d85 warning fixes
Using 'ladder' as a variable conflicts with 'struct flag flags'
because of a macro in rm.h.  Also remove or hide a couple of
unused variables.

The hack.c diff is unrelated; just a reformatting bit that I had
laying around.
2020-11-13 14:11:54 -08:00
PatR
0e713dc4e9 fix #K2617 - metallivores eating iron bars
Monsters with rust attacks (rust monster) and corrosion attacks
(black pudding, gray ooze) can eat or otherwise destroy iron bars
but xorns could only move through the iron bars spot without being
able to eat the metal there.  Change xorn to eat bars instead of
phazing through them.  Lets rock moles eat bars too.

Hero polymorphed into a rust monster would eat bars if trying to
move to their location but couldn't do so if already there (maybe
was in xorn form and now in rust monster form).  Xorns could pass
through them but not eat them.  Allow hero metallivores to eat
bars at the current location via 'e', similar to eating food off
the floor.  Hero as rock mole behaves like rust monster.
2020-10-23 19:43:10 -07:00
PatR
239620ffd7 fix pull request #386 - monster interaction
The previous teleport scroll fix was mislabeled with this pull
request number.  Too late to fix that now; should have been

Closes #307

Now...  Interaction between voluntarily busy hero (resting,
searching, and so on) with approaching monsters to decide whether
to stop had some inconsistencies.

Really closes #386
2020-09-18 15:53:43 -07:00
nhmall
ac9ba38449 file header bump from "NetHack 3.6" to "NetHack 3.7" 2020-08-03 22:07:36 -04:00
nhmall
e440e9569d change is_safepet macro name
Leaving the word "pet" in the macro name, when it applied to non-pets
seemed too contradictory, even for NetHack.
2020-05-03 21:52:41 -04:00
PatR
7817e69c41 two new monsters from slash'em
Adds two monsters originally from slash'em.  I used the slash'em
tiles this time, also its code as a starting point but made various
revisions.  Both the tiles could benefit from some touch-ups.

displacer beast:  blue 'f'.  Attempting a melee hit (ie, trying to
  move to its spot) has a 50:50 chance for it to swap places with you.
  Fairly tough monster to begin with, then half your ordinary attacks
  effectively miss and if you try to face a mob by retreating to a
  corridor or backing into a corner you can end up being drawn back
  into the open.  I added bargethrough capability, and also it won't
  be fooled about hero's location by Displacement.  [It only swaps
  places during combat when contact is initiated by the hero, not
  when attacked by another monster or when attacking.]

genetic engineer:  green 'Q'.  Its attack causes the target to be
  polymorphed unless that target resists.  Hero will almost always
  have magic resistance by the time this monster is encountered, but
  it can make conflict become risky by hitting and polymorphing other
  monsters.  Slash'em flagged it hell-only but I took that flag off;
  I also took away its ability to teleport.  Slash'em polymorphs the
  hero if a genetic engineer corpse is eaten; that's included and I
  introduced that for monsters too.

I added both of these to the list of candidates for monster spell
'summon nasties' and for post-Wizard harassment.

I also gave all the 'f's infravision.  Probably only matters if the
hero polymorphs into a feline.

Displacer beast is originally from AD&D which depicts it as a six-
legged cougar with a pair of tentacles; it has Displacement rather
be able to affect an attacker's location.  I think genetic engineer
is original to slash'em where it expands Q class but seems mainly to
be the base monster for Dr.Frankenstein (a unique monster with a
one-level side-branch lair in slash'em's incarnation of Gehennom).
2020-05-03 14:13:08 -07:00
PatR
b2b8d508dd comment typo 2020-04-27 11:54:52 -07:00