Add a way to get rid of specific monsters in wizard mode without
fighting, zapping, &c. #wizkill command lets you kill creatures by
picking them with getpos().
You can pick multiple monsters by targetting them one after another.
You don't have to be able to see or sense them but if you target a
spot that has no monster, the command ends.
By default, the hero gets credit or blame as if having killed the
targets but #wizkill can be preceded by 'm' prefix to treat their
deaths as if they had been caused by a monster.
The change to add a menu choice for naming an adjacent monster via
\#therecmdmenu was unintentionally requiring that the monster have
monst->mextra. So it worked on pets (regardless of whether they
were already named) because they have mextra for 'edog' extension,
but not on the majority of monsters. And when it failed the program
would crash with a 'segmentation fault' error.
Fix the check for whether a target monster already had a name when
deciding to use "name <mon>" or "rename <mon>" in the menu entry.
Reported by jeremyhetzler and confirmed by k2: dead monsters weren't
leaving corpses at the spot they died.
Don't set a monster's mx,my coordinates to 0,0 when taking it off the
map (unless it is migrating to another level; mx==0 is the bit of data
used to indicate that). Corpse drop happens after that and expects
the dead monster's former map coordinates to be intact.
Fixes#764
Pull request by entrez: don't create a Pratchett novel by writing
"novel" or "paperback book" on a known blank spellbook with a magic
marker.
Blanking a novel produces a blank spellbook; there isn't any blank
novel. That's intentional. Writing "novel" on a blank spellbook
and getting a randomly chosen Pratchett one wasn't intentional.
Closes#761
Reported directly to devteam by a hardfought player and also by
entrez. The recent mon_leaving_level() change resulted in objects
dropped by a dying monster not being displayed immediately.
It justed needed the relobj(mon, 0, FALSE) to relobj(mon, 1, FALSE)
change in m_detach() but this does some related cleanup in
mon_leaving_level()'s callers. wormgone() takes a long worm off the
map but leaves its stale coordinates set because some code relied on
that. This takes away the need for that but still doesn't actually
clear them.
This adds redundant 'return' statements at the end of a few void
functions that are longer than fits within a typical screen display.
They make searching for the end of the current routine in an editor
or pager easier without resorting to regular expressions and can
also be used to search for the beginning if/when preceding routine
ends in 'return' too.
Reported directly to devteam by entrez, the rloc() monst vanishes/
appears nearby/&c message was being given before "satisified, <shk>
suddenly disappears" making the latter redundant. As discussed, the
fix isn't as simple as suppressing one message or the other because
both are given conditionally.
This seems to solve it but has only been lightly tested.
Restore old behavior of magic whistle causing pets to be moved to
different locations even when already adjacent to the hero.
This lets rloc() give its relatively new, more verbose messages if
a magic whistle isn't discovered yet but suppresses those when
already discovered in order to issue its own message. For a single
pet that starts within view and arrives elsewhere within view it says
"shifts location" rather than "vanishes and reappears". For multiple
pets, it gives one summary message instead of a separate one for each
pet affected by whistling.
A new feature, enabled by default to maximize testing, but one which can
be disabled by commenting it out in config.h
With this, some additional information is added to the glyphmap entries
in a new optional substructure called u with these fields:
ucolor RGB color for use with truecolor terminals/platforms.
A ucolor value of zero means "not set." The actual
rgb value of 0 has the 0x1000000 bit set.
u256coloridx 256 color index value for use with 256 color
terminals, the closest color match to ucolor.
utf8str Custom representation via utf-8 string (can be null).
There is a new symset included in the symbols file, called enhanced1.
Some initial code has been added to parse individual
OPTIONS=glyph:glyphid/R-G-B entries in the config file.
The glyphid can, in theory, either be an individual glyph (G_* glyphid)
for a single glyph, or it can be an existing symbol S_ value
(monster, object, or cmap symbol) to store the custom representation for
all the glyphs that match that symbol.
Examples:
OPTIONS=glyph:G_fountain/U+03A8/0-150-255
(Your platform/terminal font needs to be able to include/display the
character, of course.)
The NetHack core code does parsing and storing the customized
entries, and adding them to the glyphmap data structure.
Any window port can utilize the additional information in the glyphinfo
that is passed to them, once code is added to do so.
Also, consolidate some symbol-related code into symbols.c, and remove it from
files.c and options.c
Issue #752 by vultur-cadens: initialization of characteristics had
off by one errors when reducing over-allocation and when increasing
under-allocation, biasing Str over Cha.
This simplifies the code very slightly but it still seems somewhat
confusing to me.
A couple of reformatting bits are included.
Closes#752
Fix the problem reported by entrez of a zombie corpse reviving and
crawling out of the ground while the hero was busy doing something
(searching, digging, &c) and having the hero fail to react and just
keep doing whatever the thing was because the zombie was already
inside the range where a monster changes from no-threat to threat.
Done in the monster creation routine so any new monster (including
one revived from a corpse) that is visible,&c will cause the hero's
action to be interrupted. Teleport arrival probably needs this too.
Only interrupts an occupation, not other voluntary multi-turn
actitivy such as running or traveling. That would be trivial to
change ['if (g.occupation...' to 'if ((g.occupation || multi > 0)...']
but I'm not sure whether it ought to be extended to that.
Implement 'untrap' as an 'autounlock' action. Quite a bit more work
than anticipated. The new documentation is rather clumsy; too many
if-this and if-not-that clauses have intruded.
I'll be astonished if all the return values are correct....
[A couple of places were checking for (rx != 0 && ry != 0) to decide
whether they were performating an autounlock action at <rx,ry> but
that erroneously excludes the top line of the map if the current
level extends that far. Just check rx for zero/non-zero.]
This gives the player more control over what autounlock does. It is
now a compound option rather than a boolean, and takes values of
autounlock:none
!autounlock or noautounlock (shortcuts for none)
autounlock:untrap + apply-key + kick + force (spaces are optional
or can be used instead of plus-signs, but can't mix "foo bar+quux")
autounlock (without a value, shortcut for autounlock:apply-key).
Default is autounlock:apply-key.
Untrap isn't implemented (feel free to jump in) so is suppressed from
the 'O' command's new sub-menu for autounlock. It's parsed and
accepted from .nethackrc but won't accomplish anything.
[Just musing: it should be feasible to kick in direction '.' to break
open a container or #force to an adjacent spot to break open a door.
If that was done, autounlock:kick+force (or more likely autounlock:
apply-key+kick+force when lacking a key) would resort to force if hero
couldn't kick due to wounded legs or riding.
This changes struct flags so increments EDITLEVEL again.
This includes pull requests #750 from entrez and #751 from FIQ but was
entered from scratch rather than using use their commits.
Closes#750Closes#751
savelev() gets run to clean up memory even if the player quits before
level 1 is created, and a change made yesterday panicked if it couldn't
figure out what level the hero is on. Caught by entrez, again....
If not actually writing a level's file, don't panic if both u.uz and
g.uz_save are 0. Having one of those be non-zero is only essential
when the level being processed is the Plane of Water or Plane of Air.
It is astounding that after all this time no one noticed that
incrementing EDITLEVEL wasn't doing the job it's intended to do.
Diagnosed by entrez: since VERSION_COMPATIBILITY was defined as
3.7.0-0 and up, increasing the fourth component wasn't resulting in
old 3.7.0-x files being rejected.
This increments EDITLEVEL yet again, because my testing after
commenting out VERSION_COMPATIBILITY still wasn't rejecting older
files. Proably because the oldest I had available already had the
verison info with the preceding EDITLEVEL so weren't actually out
of date yet.
Once I had old files be rejected, I discovered that the rejection
message was invisible (for tty on OSX). The message line showed
spaces, matching the length of the intended message, followed by
--More--. This fixes that too.
The air bubbles on the Plane of Water and the clouds on the Plane of
Air were being saved and restored as part of the current level's state
(which is the 'u' struct and invent and such) rather than with the
current level itself. That was ok for normal play, but for wizard
mode's ^V allowing you to return to a previously visited endgame level
after moving to a different one it meant a new set of bubbles for
Water and new set of clouds for Air. Even that was ok since it only
applied to wizard mode, but using #wizmakemap to recreate Water or Air
while you were on it added a new set of bubbles or clouds to the
existing ones. If repeated, eventually there wouldn't be much water
or air left.
Instead of just adding a hack to #wizmakemap, change save/restore to
keep the bubbles/clouds with the level rather than with the state.
That wasn't trivial and now I know why the old odd arrangement was
chosen. Saving hides u.uz by zeroing it out for levels that the hero
isn't on and it is zero during restore so simple checks for whether a
given level is water or air won't work.
This also adds another non-file/non-debugpline() use of DEBUGFILES:
DEBUGFILES=seethru nethack -D
will make water and clouds be transparent instead of opaque. It also
makes fumaroles and other light-blocking gas clouds be transparent
which wasn't really intended, but avoiding it would be extra work that
doesn't accomplish much.
Increments EDITLEVEL for the third time this week....
Noticed when testing the forcefight against obscured furniture fix:
if you attempted forcefight against the edge of the map, you got
feedback about having already moved as far in <direction> as possible
rather than about forcefight failing to attack anything. Have the
can't move out bounds test check for forcefight before deciding to
give to its normal feedback.
against "unknown obstacle"
Pull request #746 by entrez: give better feedback when 'F' prefix
is used toward furniture covered by objects and towards solid rock
terrain on arboreal levels.
Fixes#746
instead of as fake bear traps
Use the new traps and their tiles when confused gold detection finds
trapped doors and trapped chests. (Large boxes can be trapped too;
they use the trapped chest trap and corresponding tile rather than
have their own.)
Usually these pseudo-traps go away when as soon as they are within
line of sight. (While testing, I noticed that seeing a trapped door
from outside its room rather than inside didn't behave that way.
The door was created by wizard mode wishing; I don't know whether
that was a factor.)
I also discovered that secret doors weren't being handled correctly.
They can't be trapped because of their use of both the doormask and
wall_info overlays of levl[][].flags, but I had a secret door be
falsely displayed as a trap. This fixes that.
We should have obj->tknown and rm->D_TRAPKNOWN so that the hero won't
forget about these traps after declining to attempt to untrap them.
But that's more work than I care to tackle.
Issue #745 by k2: when using two-weapon combat, the second attack
would still take place even if the first attack caused the hero to
become paralyzed (hitting a floating eye or g.cube).
Cleaver's up-to-three attacks had the same problem but did stop if
the hero underwent life-saving after some fatally damaging counter-
attack. Two-weapons didn't. Make them both stop early if either
paralysis or life-save occurs.
Multiple attacking monster against monster and against poly'd hero
already deal with paralysis; life-saving doesn't apply.
Fixes#745
Reported directly to devteam: when a Rider revived, its corpse
didn't get used up.
The change to have delobj() never destroy Rider corpses, like it
won't destroy the Amulet or invocation items, didn't take into
account that they should be destroyed when Riders revive from them.
Add delobj_core() to be able to do that without changing existing
delobj() usage.
I'm surprised hardfought players haven't been all over this one.
Reported directly to devteam: changing levels while riding gave an
impossible warning, "no monster to remove".
mon_leaving_level() was trying to take hero's steed off the map but
that isn't on the map in the first place. Only noticable if built
with EXTRA_SANITY_CHECKS enabled. Normally remove_monster(x,y) just
sets level.monsters[x,y] to Null but with extra checks enabled it
first checks whether that is already Null.
Commit 593c3532fc took the 'catchup'
argument away from repair_damage() and calculated it in the routine.
Commit 699a25c00b put the argument
back but neglected to remove calculating and assigning it, making
the passed value be ignored. Take that away, finishing 699a25c00b.
That affected shop repair messages but wasn't enough to prevent a
shop wall repair display glitch. This seems to make things work
properly but is little iffy.
If you have 'fixinv' set to Off and and an inventory of three items,
they'll always be a and b and c. #adjust had you pick 'from' slot
among [abc] and the prompt for 'to' was supposed to show the letter
you picked plus 'd' for 'move to last'. But it was only showing
the 'from' letter itself as likely candidate, omitting the last+1
choice. (Anything after the last letter in use could be picked and
yield the right result, only the list of likely candidate slots in
the prompt wrong.)
Fixed more by trial and error than by understanding why the old code
didn't do what was intended.
Reported by vultur-cadens: slow digestion from wearing white dragon
scales/mail blocked per-turn hunger and didn't cause any hunger,
unlike ring of slow digestion which blocks per-turn hunger but still
causes some hunger as a worn ring itself. If no rings or amulet
were worn, wearing the suit prevented the hero from ever burning any
nutrition.
Change to treat wearing the suit to be quite a bit like wearing a
ring, unless hero is also wearing an actual ring of slow digestion
(then the hunger cost of the suit is 'free').
Wearing a ring of slow digestion and another ring consumes two units
of nutrition every 20 turns, no matter what suit. Wearing white
dragon scales/mail and two non-slow digestion rings now consumes three
units of nutrition every 20 turns. Using the suit to effectively get
an extra ring finger isn't free.
Fixes#742
Issue #729 by argrath points out that one of the checks in
edibility_prompts() couldn't work.
For the next-meal effect after reading a blessed scroll of food
detection, the check whether a corpse was tainted but not dangerous
because the hero had sickness resistance could never be evaluated.
An earlier condition would cause the routine to return before
reaching that check.
Move it sooner, even though doing so violates the "order by most
to least dangerous" guideline. It was either that or eliminate it
altogether.
edibility_prompts() had a lot of repetitive code that has now been
condensed.
Simplify acid blob corpse handling--for all of eating, not just for
edibility_prompts()--by treating that as "never rots" so that the
'rotted' variable always stays 0. Now checks for that variable
being greater than some threshold don't need to include "and not an
acid blob corpse" as an exception. A side-effect of this change is
that not only do they never become tainted, they'll no longer yield
the "you feel sick" outcome when they're old but not old enough to
exceed the tainted threshold.
Bug fix: edibility testing stopped warning about green slimes.
That worked in 3.6.x, but 3.7 changed the 'cadaver' variable to
exclude them so the check for eating a glob of green slime could no
longer be reached.
Fixes#729
Reported by entrez. Don't make 50% of neuter monsters be flagged as
female. It doesn't matter for live monsters but gets inherited by
their corpses, where female and non-female corpses stack separately.
A change made 5 or 6 weeks ago that was meant to enhance tracking of
artifact creation had an unintended side-effect of making every object
obtained via wishing have its dknown flag be set. That made them
behave differenly from items picked up off the floor, so revert to the
old behavior.
hero when hero is [impatiently waiting...] on stairs
My attempts to cherry-pick this failed, so this was done manually.
It is a reimplementation of
NullCGT:feature/monster-item-use:dc2cef0562542fece1732dd2d4c4f0775308faff
] Pets approach the player if they are standing on the stairs.
]
] One of the most frequent complaints I have seen is that pets refuse
] to follow their owners down the stairs. While this can be resolved by
] waiting, most players, especially new ones, are not willing to spend
] multiple dozens of turns waiting for their pets to approach closely
] enough to follow them. This simple commit makes pets react to a player
] standing on stairs as if the player is holding a tripe ration. Simple,
] non-disruptive, and should solve many headaches.
Something I noticed when testing the item-action handling for name and
call; applies to the C/#name command too. You were allowed to call the
real Amulet something and allowed to call fake ones something [else].
If you did that, xname/doname didn't show it but the discoveries list
did, giving away information when the player had access to more than
one unID'd Amulet of Yendor. Rather than messing about with discovery
handling, make real and fake Amulet be ineligible from being given a
type name. (They can still be given individual names.)
Issue #734 reported as "parse function" by Meklon2007: the change
yesterday intended to make ^A work for commands that were preceded
by a prefix was triggering a crash if used after a keystroke that's
not assigned to any command.
'M^A' or '~^A' would segfault by derefencing a null pointer when
checking whether 'M' or '~' was a prefix. This prevents the check
attempt from doing that, but a better fix would be to not put the
invalid command keystroke into the do-again buffer in the first
place.
Fixes#734
Reported by luxidream via the web contact form and also as github
issue #732: using the repeat command after F+direction would take a
step in direction if there was no target to fight.
The direction was being repeated without the F prefix. It wasn't
specific to F; m+dir misbehaved too. This fix seems to work but it
should be replaced with something more robust.
Fixes#732
placed on lava spot on Valkyrie goal level
Reported by k2, arriving at the final level of the Valkyrie quest
can issue a recently added impossible
| mkstairs: placing stairs up on molten lava at <68,13>
The report said it was easy to reproduce, but it took me multiple
tries (so not hard to do, but not a sure thing on any given attempt).
The stairs on that level are placed at specific coordinates that
are outside the pre-mapped area, so there's no guarantee that their
spot will be suitable for stairs. The underlying terrian changes
from lava to stair, but only after the warning about molten lava.
This hack solves that particular level but is not a general solution
for this type of thing. When about to make stairs on a lava spot,
change that spot to normal floor first. Plus 50:50 chance to change
each adjacent lava spot to floor too so that there's decent chance
for some elbow room upon arrival.
Also, turn the no-flip attribute off for that level so that 'fixed'
location of the stairs can occur in four different places.
Fixes#730
after charging causes a ring to explode
Reported by gebulmer: if charging exploded a ring, the ring's memory
got freed but the stale pointer was passed to cap_spe() which accessed
it again. Fix by setting the object pointer to Null after using up
the ring. This was a post-3.6 bug.
Fixes#731