Make yellow dragon breath destroy iron bars (unless their wall_info
is marked as non-diggable, which I think is currently impossible for bars).
The shop handling is untested; no shop has iron bars for its walls or
includes them as interior obstacles. (The latter would require changes
to shop repair because lost bars will become solid wall if/when rebuilt.)
Thrown potions of acid and spat or thrown splashes of acid venom
don't affect bars--at least so far--because those always pass through
without hitting. Monsters who have a non-ranged attack which does acidic
damage can't use such attacks against iron bars.
A fairly recent change had a mistake in it which allowed monsters to
throw, shoot, and zap through walls and closed doors if there was at least
one unobstructed spot between the attacker and the wall or door.
From a bug report: if you
attempted to engrave with an empty wand while levitating, it wouldn't use
a turn unless you successfully wrested an extra charge out of the wand.
So you could always get such charge in a single elapsed turn of game time
if you didn't care about zapping in any particular direction; extremely
useful for wishing.
Noticed when checking this: when you did wrest the extra charge,
the engraving code accessed freed memory for the wand after it had been
used up.
Lastly, wands producing certain effects always become discovered,
even when you don't yet know what they look like. (This part of the patch
is trunk-only since it utilizes the routine which fixes similar case for
zapping.)
From a bug report: if you
were at one of the map edges and kicked away from map center while blind,
you'd get impossible("show_glyph: bad pos ..."). That was due to calling
feel_location() for the out of bounds location, which occurred after the
kick code had made use of invalid data so other problems might occur too.
Now you kick "nothing" as if it was something (hence possibly wounding
your leg, taking some damage, potentially dying). I didn't want to try to
classify the surrounding terrain as rock or air or whatever, and the thing
being kicked only shows up if the kick is fatal.
From the newsgroup: if polymorphed into a metallivore, you could eat
artifacts that you couldn't touch with your hands. Now you can't eat ones
which evade your grasp, and you take some damage from other touchy items
on--actually, prior to--the first bite. (Those still "taste delicious" if
you survive; I'm not sure whether this ought to be changed.)
Attempting to loot while suffering from confusion and not on top
of a container will drop gold if hero is carrying some, but it behaved
differently for GOLDOBJ config (gold dropped over a hole or down stairs
always stayed on current level) than for !GOLDOBJ (gold had a chance to
fall to lower level) when done at some location other than a throne.
This makes GOLDOBJ use dropx() instead of dropy(), same as !GOLDOBJ.
And with access to a throne it can be used to repeatedly summon
monsters until they're extinct. This makes it check for confusion before
finding containers, but the chest/exchequer code doesn't always kick in
so can't be attempted as many times before confusion expires, throttling
summoning a little. Also, when placing hero's gold into a chest, it now
clears the contents-known flag and relocks the chest.
Fix a typo in some conditional (NOSAVEONHANGUP) code, and tweak
SAFERHANGUP so that it doesn't defer hangup handling if the game hasn't
started yet or has already finished (it's possible to be waiting for a
--More-- prompt at end of game code before the hangup handler is reset,
so the regular handler could be called in that state). Also, undefine
SAFERHANGUP if NOSAVEONHANGUP is defined, since there's no point in
deferring hangup for the latter.
The last of my intended hangup overhaul. Once hangup is detected,
replace currently loaded windowing routines with stubs that never do any
terminal I/O. Real interface routines call their siblings directly rather
than via the windowprocs pointers, so this shouldn't pull the rug out from
under them, but it also can't prevent whatever they have in progress at
the time of hangup from attempting further I/O once the handler returns.
[We might want to change nhwindows_hangup() into winprocs.hangup_nhwindows()
so that each interface has more control over its own fate.]
This assumes that user input of ESC and menu selection result of -1
everywhere in the core will eventually cause active function calls to
unwind their way back to moveloop() rather than to continually re-prompt.
(This assumption is not a new one, just a bit more explicit now.)
[See cvs log for src/cmd.c for more complete description.]
This turns clearlocks() into a no-op during the period when the UNIX
port is asking the user to confirm whether to overwrite an existing game.
Also, this removes the duplication of code and function between hangup()
and end_of_input(), and it simplifies the check for whether hangups are
supported by adding new macro HANGUPHANDLING. (I don't think global.h is
the best place to be defining that but I couldn't figure out where else
it would fit, other than repeating for individual xxxconf.h files.) And
adds a couple more done_hup checks to try to cope with situations where
rhack() is being bypassed. Lastly, having readchar() return EOF was
ignored for non-UNIX configs; now everybody gets ESC instead of letting
EOF be seen further inside the core.
The previous "hangup cleanup" didn't accomplish much (other than to
give everyone a good view of extern.h). This one achieves more, and also
tries to fix the bug From a bug report:
> Buglet: Destroy old game -prompt can make game unrecoverable
>
> I haven't confirmed this myself, but few people playing on NAO
> have had the following happen:
> 1) play nethack
> 2) your network connection gets cut
> 3) reconnect, and get "Destroy old game" -prompt
> 4) your network connection gets cut, again, before you get to answer 'n'
> 5) game is not recoverable, because the level 0 file is gone.
The reason for #5 is simple to explain; it's the expected behavior of
current hangup() routine (although that hasn't always called clearlocks();
I don't know why it was added). The puzzle is why #2 left any lock files
around in the first place. I suspect it was because SAFERHANGUP defers
until rhack(), and rhack() doesn't get called if the hero is immobilized or
in the midst of a counted operation. I don't know how long a disconnected
process is allowed to run, but I don't think it's forever. (Alternatively,
nethack might be attempting further terminal I/O and getting stuck on the
hung connection; this won't help much if that's the case.)
This turns clearlocks() into a no-op during the period when the UNIX
port is asking the user to confirm whether to overwrite an existing game.
Also, this removes the duplication of code and function between hangup()
and end_of_input(), and it simplifies the check for whether hangups are
supported by adding new macro HANGUPHANDLING. (I don't think global.h is
the best place to be defining that but I couldn't figure out where else
it would fit, other than repeating for individual xxxconf.h files.) And
adds a couple more done_hup checks to try to cope with situations where
rhack() is being bypassed. Lastly, having readchar() return EOF was
ignored for non-UNIX configs; now everybody gets ESC instead of letting
EOF be seen further inside the core.
From the newsgroup: slash'em lychanthrope character could throw
while in wolf form. That came straight from nethack; any animal capable
of manipulating an object--possibly with its mouth--could throw things.
Now hands are required. This doesn't require free hands, although it
probably should; it's kind of tough to imagine making a competent throw
while your hands are stuck to a cursed two-handed weapon.
While looking at a bug report from two months ago about how having
hangup take place while at the "destroy old game?" prompt causes an
interrupted game to become unrecoverable, I decided to try to clean up
convoluted hangup() a bit. Didn't achieve much there, but did notice that
the Unix port was handling SIGXCPU (whatever that is...) inconsistently.
This attempts to fix that, but I have no way to test it.
The original bug report is still unresolved.
makedefs ought to add something for SAFERHANGUP and NOSAVEONHANGUP
to the #version output.
[ This is the missing bit from the patch on Monday which accidentally
included all of extern.h as its log entry message. ]
From a bug report: shopkeeper
wouldn't move to block his doorway if there was a grave at that location.
Nothing supernatural; shopkeeper and temple priest movement was too
specific about what sort of terrain might be present and didn't know that
room floor might be replaced by a grave.
Simplify the insertion into and removal from of gold in inventory for
the !GOLDOBJ configuration. If GOLDOBJ ever becomes unconditional this
will be superfluous, but in the mean time it unclutters the container and
drop code. Also, tweak a recent getobj() hack so that its purpose might
be a bit clearer.
A recent change to force gold in inventory (during multi-item Drop or
applying/looting containers) to have '$' for its inventory letter for the
!GOLDOBJ configuration has revealed a bug which 3.4.3 has for the GOLDOBJ
configuration. Specifying a count followed by '$' to use a subset of
carried gold didn't work under tty; the $ was treated as a group accelator
and overrode the count, so full stack was always used. (The code a few
lines above this which counts the occurrences of group accelators already
includes this same fix: ignore an item's group accelator when it matches
the selector.)
I wouldn't be surprised if other interfaces are subject to the same
problem; since I can't test those I'm not attempting to fix them blindly.
"You carefully open the <container>..." is rather tedious after
you've opened that container multiple times, so omit "carefully" once the
contents and lock-status are both known. (I don't think it's possible
for a container to still be trapped in such circumstances, but even if it
is, you'll now stop being careful....)
"<The container> is empty." becomes "<The container> is now empty."
if it just released Schroedinger's Cat. Do the same if a cursed bag of
holding just destroyed the last of its contents. Also, there's no need
to count the number of items inside a container; that dates to before the
container-and-contents overhaul done for 3.1.0.
And for the loot menu, change "q - do nothing" to "q - done" if some
prior action (prodding the Cat into life or death, loss of any cursed bag
contents, or using ':' to look inside when contents aren't yet known) has
been enough to cause this container access to use up a turn. I haven't
bothered to do the same in the help text for non-menu looting, which seems
like more trouble than it'd be worth.
- force time_t to be 32 bits via Makefile. (If struct u gets changed to not
store a time_t field, this can be removed).
- Latest Windows SDK (supporting Vista) causes a warning due to
a prototype in sys/winnt/nttty. Since we don't actually link with that
function and rely on a DLL find procedure at run time, comment out
the prototype. The function is now officially in the SDK in the
windows header files anyway.
Reduce the number of questions issued when applying or looting a
container, and offer the opportunity to put things inside before taking
things out. Instead of "Do you want to take something out? [:ynq]",
followed by "Do you want to put something in? [ynq]", this gives just one
prompt; the result is similar to menustyle:full where you start out by
choosing between out, in, and both. There are now two additional choices:
reversed, for both in the opposite order, and stash, to put a single item
inside. Prompt phrasing is rather clumsy; I wanted to keep it short:
"Do what with <the container>? [:oibrsq or ?]", where picking '?' pops
up a brief help window. Inappropriate choices (like 'o'and 'b' when
container is empty) are suppressed from the prompt but still acceptable as
input; " or ?" is suppressed if the cmdassist option has been toggled off,
but entering '?' still works to get help.
Menu mode wouldn't allow 'b' when inventory was empty, despite the
fact that first taking things out might change that. Now 'b' is a viable
choice if the container isn't empty, and the new 'r' is a vialble choice
when inventory isn't empty even if the container is.
Some miscellaneous changes preparatory to enhancing the container
interface. This also fixes a minor inconsistency in object manipulation:
askchain() wouldn't let you split a stack of welded weapons but getobj()
would, so you couldn't get rid of part of the stack using 'D' or #loot,
but you could with 'd' (and post-3.4.3, with #adjust). Now getobj() will
behave like askchain(); if you have 3 cursed daggers welded to your hand,
you won't be able to drop 1 or 2 of them anymore.
From the newsgroup: you weren't charged anything if you broke the
lock of a box or chest which was owned by a shop. Force the hero to pay
for the damaged container; any contents remain owned by the shop and don't
affect the cost of the forced purchase. This existing entry in fixes35.0
is adequate to cover the fix:
various actions--such as enchanting--performed on an unpaid shop object
either force the hero to buy the item (when its value is lowered) or
increase the current bill (when its value is raised)
Don't use the phrase "seems to be locked" when you discover that a
container is indeed locked. Also, using an alternate naming routine is
a simpler way to avoid redundant "the empty <container> is empty" than
suppressing the contents-known handling for xname.
Newsgroup posts mention "boulder forts" from time to time, where the
player surrounds the hero with boulders in order to prevent the majority
of monsters from being able to attack. Since the hero can shoot or throw
or zap over/around/through boulders, monsters ought to be able to do so
too. This makes the test for whether a monster is lined up properly for
its ranged attacks try harder when the original line-of-sight check fails.
If there aren't any terrain obstacles found, it allows a chance to attack
based on the number of locations in the path that contain any boulders.
Giants and any monster carrying a boulder-destroying wand of striking get
to ignore boulders, overriding the random chance.
Implement <Someone>'s suggestion/request that co-aligned unicorn not be
used for statue traps, so that the hero won't get hit with a big luck
penalty for killing such a unicorn when the trap releases one which is
hostile. I think that set_malign() probably ought to override that, but
this just changes the monster type selection for the trap's statue.
Also, noticed in adjoining code: avoid counting the template monster
used to generate inventory for the statue towards extinction. It gets
immediately discarded, and later statue activation counts the resulting
monster then.
Someone in the newsgroup claims to have reported this in mid-October,
but he uses a fake address in news and maybe he did so with his mail too,
resulting it not being delivered. Anyway, arming a land mine on the Plane
of Air, then setting it off, produced a pit in the air. This fixes that
directly, in case someone manages to do it again, and it also prevents
land mines and bear traps from being armed in midair in the first place.
Ditto for Plane of Water; water/pool locations were already covered (can't
arm there), and the bubbles ought to be treated similarly to Plane of Air.
When testing this, I managed to get a crash while restoring a saved
game. I had worn a blindfold and armed a land mine on the water level
(with just the no-pit part of the patch in place), then saved. When
restoring, I got a crash in restore_waterlevel() at one or the other of
these lines (traceback pointed at the first, but it has to have actually
been the second; an access violation from an address derived by applying
a small offset to a null pointer):
ebubbles = b;
b->next = (struct bubble *)0;
After that, I couldn't reproduce it with a wished-for trap and couldn't
stay in one place long enough again to successfully arm a trap object.
So there may be a nasty bug still present, perhaps now hidden by no longer
being able to create a new trap on that level.
Thrown boomerangs travelled in a clockwise path, appropriate for
left-handed throwing. But nethack heroes are treated as right-handed by
the weapon wielding and shield wearing code, so make boomerangs travel
counterclockwise instead. Switching is straightforward, in case we ever
implement user-specified or random handedness.
Noticed while testing crysknives; a post-3.4.3 change (not present in
the branch code) introduced a bug that prevented scrolls of enchant weapon
from being used up properly when read.
Make worm teeth and crysknives be stackable. Positively enchanting
a stack of multiple worm teeth produces a single crysknife, negatively
enchanting a stack of multiple crysknives produces a single worm tooth.
A dropped stack of N fixed crysknives has 90% of remaining N crysknives,
10% of becoming a stack of N worm teeth, rather than produce an average
of 0.9*N crysknives and 0.1*N worm teeth. (The code which handles that
transformation operates on loose objects so cannot handle stack splitting
because it wouldn't have any idea of what to do with extra objects.)
Terminate multi-shot volley throwing of boomerangs if one comes back
and isn't caught. The sequence throw-catch-throw-catch is odd, but would
take a substantial amount of code and effort to be changed to the more
intuitive (for rapid volley throwing) throw-throw-catch-catch. Even if
feasible, doing that for underused boomerangs would be a waste of effort.
Reading the comments in the previous patch, I realized that keeping
the old behavior for monsters who are shooting multiple missiles was
leaving an obscure but potentially serious bug. I haven't attempted to
trigger it but 3.4.3 is bound to be vulnerable.
Make all stackable weapons capable of multi-shot volleys when thrown.
Affects knives, spears & javelins, and boomerangs; requires advanced skill
assignment (skilled: 1-2 missiles per throw, expert: 1-3 missiles) or
role-specific bonus (ranger class's general +1 bonus is the only one that
applies to any of these weapon types). For monsters, prince-caste get 1-3
missiles and lord-caste get 1-2, as before, with fake player monsters now
also getting 1-2; those counts apply to all stackable weapons regardless
of whether the species or role ordinarily uses whatever is being thrown.
Related changes: monks now get a role-based +1 count for shuriken,
throwing 1-2 instead of just one (they're only allowed to achieve basic
skill so won't reach any higher volley count). Monster monks and ninjas
get that too; ninjas now get the same for darts and they're guaranteed
weapons in starting inventory. Also, fake player rogues now sometimes
get orcish daggers instead of short sword, providing a decent chance to
occasionally have Grimtooth be randomly generated on the Astral level.
Potentially controversial: wizards can still become expert in dagger
skill and receive the to-hit and damage bonuses for that when throwing as
well as when wielding, but the number of missiles for them has now been
reduced to 1-2 (in other words, going from skilled to expert no longer
improves the max count for the volley amount for wizard role). They're
supposed to be spellcasters; being able to throw up to three +7 daggers
at a pop was a big temptation for resorting to brute force, particularly
since they'll already want highest dagger skill for wielding Magicbane.
To do: throwing multiple boomerangs either needs to behave as if
they're all in flight before the first returns, or else the volley needs
to be cut short if one comes back and isn't successfully caught. The
latter is a lot easier to do but the former fits better with what multi-
shot volley is supposed to represent. Another alternative is to change
them to no longer be stackable, then this sequencing issue goes away.
To do too: make worm teeth and crysknives become stackable like the
other knife-skill weapons.
A suggestion from the newsgroup: when potions are hit by fire and
get the "boil and explode" result, potions of oil should burn instead of
boil. Even though oil can be heated to boiling, nethack's potions of oil
are noticeably flammable [just (a)pply one...] so having them burn makes
sense. It's just a message change; no actual explosion has been added.
destroy_strings[] was implemented as an {N} x {3} array that used
manually computed indices into one-dimension. This changes it into a two-
dimensional array instead. However, it's still being indexed by a bunch
of magic numbers.
Refine a recent change: Moloch should only have a chance to blast
you for offering the Amulet at an ordinary altar (instead of high altar)
when you're still in Gehennom (Orcus' Level or Valley of the Dead), not at
the unaligned altars in a couple of quests.
Part of "multi-shot throwing proposal" last January. Unfortunately
some of the bits that I had implemented back then have vanished, so I'm
doing it over from scratch. There were three main parts:
1) allow multi-shot volley throwing for all stackable weapons (affects
knives, javelins, spears, and boomerangs; other weapons either don't
stack or are already multi-shot);
2) make worm teeth and crysknives be stackable like ordinary knives;
3) merge spear and javelin skills, so that allocating skill points to
their use becomes more attractive and they might get used more.
This patch only does #3.
Since the monk skill set shrinks by more than any of the other roles,
I bumped max skill for escape spells (haste self, invisibility, jumping,
levitation, and teleport away) from basic to skilled; that's the only
skill adjustment included here. For the couple of roles had different
max values for spear and javelin skill; this keeps the higher of the two.
From the newsgroup: ``Something is engraved here on the water.''
An engraving written on a lowered drawbridge would be transfered to the
underlying terrain when the bridge was raised. The coverse was also true;
if you plugged the moat and then engraved on the ground, that engraving
would remain visible--and touchable if blind--when the bridge was lowered
to cover its spot. Rather than try to handle two different engravings at
the same coordinates (with one of those two changing locations when the
bridge is raised or lowered), this just wipes out any engraving at both
span and portcullis locations whenever the bridge state changes, like is
done for traps.
There's some discussion in the newsgroup about an engraving bug, and
while verifying that it's reproducible I've come across an unintentional
change between the current code and 3.4.3. A recent change made engraving
use accessible(), and that routine wasn't yielding an appropriate value
when applied to a raised drawbridge if the terrain in front of it was ice
or floor (ie, moat or lava had been filled in). Several places which used
the ACCESSIBLE() macro instead of the function suffer from same problem.
This doesn't attempt to address the newsgroup bug (which is that an
engraving written on a lowered bridge transfers to the underlying terrain
if the bridge is raised, even when that terrain is water or lava; the
converse case applies too, an engraving on the ground gets transfered to
the bridge when it lowers).
There's no need to restrict the menu of restoreable games to 52 in
order to stay within a-zA-Z for entries; just let add_menu() do its own
selector assignments (reusing letters on each page).
Typing a response at the "Who are you?" prompt didn't allow digits in
the character's name under Unix and VMS; something like "arc15" came out
as "arc__". This allows them to be used anywhere except for the first
character. "arc15" now works; "15arc" ends up as "_5arc" so that there
still won't be a leading digit abutting the uid value when they're joined
to form the save file name.
Move the code to use a nethack menu for restoring a saved game. It
was inline in tty_askname() but is now a separate routine, restore_menu()
in restore.c. There was no port-specific code and only a small amount of
tty-specific code; it should be useable by anyone (but Qt doesn't have to
switch over if it doesn't want to).
The original behaved strangely if there were exactly 26 saved chars;
the "start new game" menu entry ended up using "{" as selection character.
There wasn't any comparable problem at 52; it was limiting the menu to 51
games. Now it will allow 52 (with "start a new game" bumped into "#" if
there are that many), and adds an explicit quit entry (unless there are
52 or more games so that # is already used by new-game, then quit remains
implicit rather than resort to some other none-of-the-above character).
makedefs wasn't including this optional feature in dat/options for
display via ``#version''. It doesn't affect save and bones files but it
is something that may be of interest to users. This change won't work for
UNIX+QT_GRAPHICS because that config is defining SELECTSAVED in files.c
instead of in unixconf.h.
I think there are some other new things which are missing here too.
First cut at implementing SELECTSAVED for VMS. Unfortunately, it only
works by default if the player is using a [probably] shared account called
"games" or "nethack", and displaying a menu of games available to restore
will likely have the side-effect of encouraging other players sharing that
account to steal each others saved games. To use it with a normal account,
the player has to include "-ugames" or "-unethack" on the command line
(or OPTIONS=name:games in config file) to force the program to reach the
"Who are you?" stage.
I've added a flag argument to set_savefile_name() so regularization
can be suppressed, allowing it to be used to construct a wildcarded file
specification. I'm using that for VMS and have attempted to put in place
for WIN32CON, but the latter is not tested.
The current WIN32CON and UNIX+QT_GRAPHICS methods of collecting save
file names is bug-prone if used on a shared playground directory. Counting
matching file names first, then allocating memory and retraversing the
directory to copy those names into the allocated memory has a window of
vulnerability where the number of matching files could increase between the
counting and the copying.