Noticed when incorporating the "vampire dancing" patch: losing a level
while polymorphed would subtract from your normal hit points but didn't
affect your monster hit points. Now they'll lose d8 from max and current,
similar to the amount they increase when gaining a level.
This also addresses an issue from the newsgroup a few weeks back:
someone mentioned an assumption that Stormbringer drained an amount other
than d8 for monsters who use some other formula for their hit points. It
wasn't true, but now it will be (approximately). Most monsters with unusual
hit points aren't subject to level drain, so it shouldn't have much impact.
Fix the problem pointed out by <email deleted>
where polymorphing into a new man at level 1 could be used to approximately
double or triple your hit points and spell power. With means to drain
level back down to 1 and with amulets of life saving to survive those times
you lose levels instead of gain, you could do this repeatedly and end up
with HP and Pw values in the millions.
This uses the earlier patch that records the HP and Pw increments from
level gains. Now when polymorphing into a new man, level based HP and Pw
are removed from the current values, remainder get multiplied by 80%, 90%,
100%, or 110% (average 95%, so tend to drop slightly), then a brand new set
of level gain increments (reflecting new man's Con and Wis) are added in.
Code for calculating spell energy is moved from pluslvl() and u_init()
into new routine newpw(). It and newhp() take over responsibility for
remembering the level based increments from pluslvl() which didn't deal
with the initial amount (stored in slot [0]; earlier patch didn't need it).
<email deleted> sent a report with
subject "Vampire-dancing can give you unlimited maxhp/maxmp" about how you
can manipulate your hit points and spell energy by using equipment to
lower Con and Wis prior to deliberately losing a level, then switching to
alternate gear to raise them prior to gaining the trivial 1 XP needed to
regain the lost level. With Stormbringer (to toss up so that it falls on
your head) or spell of drain level (to cast at yourself), you can do this
level toggling as much as you like since it doesn't consume any resources
in the process. All you is a supply of non-threatening monsters to kill
for the regaining half.
In March he sent "vampire-dancing (patch)" which didn't include a
patch but did give a URL ( http://nethack.angband.pl/vampdance.patch )
for one. That contained his suggested fix: recording the hit points and
energy points given each time you gain a level and then using those exact
amounts when you lose the corresponding level. It's still possible to
manipulate HP and Pw by losing multiple levels after you've boosted Con
and Wis to ascension ready status (you'll lose the original values but can
expect to get better ones when gaining levels back), but can only gain a
modest improvement and repeating it doesn't augment the effectiveness.
Plus it's much harder to regain multiple levels than it is to get just one.
His patch had a couple of bugs which I've fixed. I suppose that there
could be additional potential problems but the idea and its implementation
are both pretty straightforward. (This doesn't address the other recently
reported situation of using polymorph into "new man" while at level one to
multiply HP and Pw.)
I've gotten tired of seeing newsgroup claims along the lines of
"since devteam is aware of this and has chosen not to eliminate it, they
must endorse it", so weaken the tactic of "pudding farming". It is still
possible to gain unlimited experience (past level 15 or so there's not
much point), but will be less effective for gaining items and for providing
sacrifice fodder. Keep track of which monsters have been created via
cloning (mostly puddings; gremlins and blue jellies are affected too but
nobody's likely to care much about them) so that they can receive special
handling. Make cloned monsters progressively less likely to leave corpses
as the number killed for a particular type goes up, and also much less
likely to drop random items at death. This is sure to need some tuning
once hard core farmers point out how they can still abuse it. For the
absurdly extreme case, see
http://scavenger.homeip.net/farmbot/HomePage
FYI, farmbot/PuddingFarmingHOWTO includes an impressive screen shot of a
dungeon level where rampant farming is taking place.
Make it easier for a low level character with ordinary Max HP to get
the healing result from a successful prayer. Mid level characters are the
same as before: will be healed if at 1/7 (or worse) of max. High level
characters, or anyone with Max HP really high for their level, will need
to wait until current HP is lower before being able to obtain that result.
This mainly affects spoilers; the actual impact for any player who doesn't
know the old formula is fairly small. The exception is for "protection
racketeers" who manage to build up a high HP without gaining any levels;
a level 1 character will only get healed when at HP 5 or less, regardless
of what percentage of max their current hit points are.
Under the old system you could get healed at 6 HP if you had 42, at
7 HP out of 49, and so forth. Now you'll need to be at least level 2 to
get healed at 6 HP out of 30 or more, at least level 3 for 7-9 out of 35-45.
"Normal" max is capped at 15 times level and anyone above normal is treated
as if their max was that lesser normal value. Levels 1 to 5 use a new
threshold of current HP being 1/5 (or worse) of max, levels 6-13 use 1/6,
14-21 retain old 1/7 threshold, 22-29 now use 1/8, and level 30 uses 1/9.
The somewhat odd level break points are based on where rank titles change.
I think being asleep or unconscious ought to override vision the way
that being blinded does, but that's a more ambitious change than I care to
tackle. This replaces You("see ...") with You_see("..."), comparable to
You_hear(). It catches the reported door case and several variations of
light sources burning out while on the floor rather than in inventory, but
it probably misses some other cases. zap_over_floor() in particular is
highly suspect.
From a bug report. <Someone> as slashem-Bugs-883643 on 1/24/2004. To avoid
using the possibly invalid object pointer after calling bhit(), changed as
suggested to add another level of indirection allowing bhit to null the
object pointer before returning. Callers that are affected update their
object pointers after bhit returns.
Make petrification initiation or termination go through a new routine,
make_stoned(), instead of manipulating its countdown timer and delayed
killer directly. No change in behavior.
There's no reason in terms of bug risk or game play or saved data why
this shouldn't be done in the branch too, but so much of the surrounding
context has already diverged between trunk and branch that it's trunk only.
Make the names of the macros for handling the hero be similar to those
for monsters (where mis-use of `sensemon()' was the cause of a recently
reported bug). `senseself()' becomes more restrictive in what it specifies,
and current uses of it are replaced by new `canspotself()'.
A post-3.4.3 change dealing with reaching into pits resulted in "you
sit on the air" if you used the #sit command after escaping a pit trap.
Change can_reach_floor() so that caller explicitly controls whether being
on the brink of a pit is a condition that prevents reaching the floor.
This also splits a fairly common message about not being able to reach the
floor into a separate routine.
There is still oddness here: if you're polymorphed into a flyer,
#sit yields "you sit down" followed by "you fly over a pit" (latter occurs
when escaping trap activation). A ceiling hider behaves similarly, but
the second message is "you escape a pit" and doesn't sound quite as silly.
Perhaps #sit should pass TOOKPLUNGE to dotrap(), or maybe there's some
better way to handle this?
> clear stale prompt
[...]
> Can someone who understands the relevant windowing code fix ^R in getpos()?
I still don't understand why it wasn't working as expected, but moving
the existing cursor positioning after flush_screen() instead of before now
makes ^R work ok during getpos(). It doesn't restore the top line text so
isn't a transparent redraw but it now displays a prompt string there instead.
Likewise after typing '?' for help so that it should be move evident that
nethack is still waiting for you to move the cursor somewhere.
Also add support for ^L in numpad mode. I almost never use that and
didn't think of it the first time around.
This uses Michael's suggestion for keeping the display up to date when
removing a djinni or water demon in advance of granting a wish (so that it
won't be present in a bones file if the wish is fatal--problem with earlier
fix was that player could notice monster was already gone while responding
to the wish prompt). It's not quite as straightforward as I was hoping for
and would get a lot messier if it needed to cope with Warning & Warn_of_mon.
Pointed out by <Someone>: engraving with a cursed wand should pose a
risk of having it explode just like zapping does. [At the moment when one
explodes, any existing engraving doesn't get changed.] Suggested by someone
(<Someone>?) some time back: explosion due to recharging could be consolidated
with explosion due to zapping cursed wands. And noted by <Someone> in the
newsgroup: '+' in an engraving--perhaps written by someone trying to leave
bones file notes--should have a chance of being partially rubbed out to '-'.
Implement the suggestion that Fire Brand avoids damage from rust traps
by boiling away the water. Rather than making this be trap-specific, it
applies to all types of erosion which go through erode_obj(). That includes
hitting rust monsters but not dipping into potions or fountains, nor falling
into moats. And it doesn't provide 100% protection, just a high chance of
avoiding rust damage. Also, Frost Brand gets similar protection by freezing.
The message handling needed some rewriting for the branch version.
That compiles ok but hasn't been tested. It would have been simpler just to
move Yobjnam2() over even if nothing else was changed to use it yet....
For cancellation I accidentally used terrain type WATER when I meant
object type POT_WATER, so being charged for cancelling holy or unholy water
wasn't working. When I first put in COST_UNHOLY the name made some sense
based on its usage, but after later adding COST_UNBLSS it didn't any more;
change it to COST_UNCURS.
A shopkeeper's complaint that you're uncursing or unblessing his wares
(only applies to water) now sets bknown flag since you know that the object
has become uncursed. I hadn't realized that confused remove curse only
affects uncursed objects; this greatly simplifies extra code I added there
for costly_alteration().
[No fixes entry needed.]
<Someone> reported that when levitating and blind, he was getting
"You float over the hole" without it showing up on the map. Easiest way
to reproduce: zap a wand of digging downwards while levitating blind,
move off the spot and back over it.
Make sure that all traps created by the player are mapped. For other
traps, it was about 50:50 whether the trap triggering message yields enough
information to warrant forcibly mapping the trap when blind.
[This ought to be suitable for the branch version too but I'm not going to
spend the effort to migrate it there.]
Recently From a bug report, reducing
the value of a shop object via cursed enchantment was ignored by shopkeeper.
This replaces the existing costly_cancel() routine with costly_alteration()
which performs a similar task: bill for any item whose value has been made
less. The hero owns the resulting object but must pay for the original one
before being allowed to leave the shop.
This covers the majority of cases where bill_dummy_object() was already
being used: cancelling a charged or enchanted item, casting drain life at
same, diluting potions or blanking scrolls or books by dipping them into a
potion of water, dulling a weapon by engraving with it, eating unpaid food
or opening unpaid tins, applying a cream pie to hit yourself with it in the
face, applying a wand to break it, burning something by dipping it into lit
potion of oil, and clearing potions by dipping a unicorn horn into them.
The shop billing behavior for those actions hasn't been changed, just
consolidated into one place which delivers a common message for them.
This also covers many cases which weren't being handled: stripping
wand or magic tool charges via cursed scroll of charging, reducing a charged
ring's enchantment via same, reducing weapon or armor enchantment via cursed
scroll of enchant weapon or armor, stripping an item's rustproofing via
confused enchantment, making a crysknife revert to a worm tooth, unblessing
potions of holy water or uncursing potions of unholy water. (That last one
won't be billed if it's the result of prayer rather scroll, spell, or #dip.)
And this tries to handle the reverse situation more thoroughly too:
many actions which improve the value of an unpaid item now also cause the
shop bill to be updated to reflect its new higher price. Aside from the
basic enchanting and charging magic, it covers converting dragon scales into
dragon scale mail and worm tooth into crysknife. Some things which might be
expected to inflate shop prices, like rustproofing or increasing the number
of charges in a wand, don't actually affect the price. And there are bound
to be cases where the price is affected but I've overlooked.
Fix a buglist entry: fracturing a boulder or statue owned by a shop
was ignored by the shopkeeper. The existing vague fixes entry of "some
shop thefts weren't charged" covers this.
Suppress "Mr" or "Ms" title for shopkeepers when they're going by a
first name rather than a surname. The bug report was for Izchak, but it
would have happened with the two last resort names (which I've never seen
in actual use) and for the "hippie names" used in post-3.4.x health food
shops. I have not attempted to specify gender for those, just flagged
them as first names. This prepends a prefix character to the name string
(see comment in shknam.c) to specify gender and/or first name vs surname.
Allow health food stores to carry eggs and tins of veggy contents in
their stock. The tins will almost always contain spinach because random
tins containing meat are converted into that.
Also, allow health food stores to be placed with the level compiler
(not tested) and to be forcibly placed in wizard mode via SHOPTYPE setting
of "V". Increments EDITLEVEL in patchlevel.h because lighting store in
Minetown got renumbered and the special level for it needs to be rebuilt.
Groundwork for having health food shops carry tins as part of their
stock. (That part isn't finished yet.) The choice of which types of tin
preparation might be sold as health food is rather arbitrary. Tweak if
needed--but keep in mind that just because something is marketed as health
food doesn't necessary mean that it's actually healthy; vice versa as well.
Tin handling could be simplified if tin->spe for spinach was changed
from 1 to -1. Then checks for spinach could compare against SPINACH_TIN
instead of a magic number, and with non-spinach tin->spe would be a direct
index rather than needing negating and offsetting.
Revert mostly to <Someone>'s original approach for keeping track of whether
a container being applied or looted had been destroyed by the operation.
askchain() now knows not to attempt to re-merge an item that has been
destroyed (a theorhetical action since no stackable items can trigger a
magic bag explosion) like the earlier change to menu_loot(). Also have
use_container() clean up after itself so that current_container never has
an old pointer value left around.
A user recently complained that he started an activity such as
searching and specified a repeat count, right after getting--and not
realizing the significance of--the first message in the countdown
sequence for turning into stone. He suggested that subsequent messages
interrupt multi-turn activity so that the player has a chance to do
something to prevent imminent death. This implements that, with the
added wrinkle that it won't interrupt if the activity is something that
might save the character's life: attempting to eat a tin that is either
sure to help (if ID'd as food that cures stoning) or a desparate gamble
(if unID'd). Some hooks for similar behavior for other conditions like
turning into slime are included, although no tins can help for anything
other than petrification so far.
Shouldn't fatal illness have an end-is-near countdown too?
Implement a user suggestion that tame humanoids should avoid eating
corpses of their own species. Prevent them--except for kobolds, orcs, and
ogres--from doing so unless starving. Arbitrary: tame elves won't eat
other elves even when starving. A polymorphed character will incur the
effects of cannibalism when eating either his/her underlying race _or_
the current one (player orcs and cavemen aren't affected though).
o Add support for zlib compression via ZLIB_COMP in config.h (ZLIB_COMP
and COMPRESS are mutually exclusive).
o rlecomp and zerocomp are run time options available if RLECOMP and
ZEROCOMP are defined, but not turned on by default if either COMPRESS
or ZLIB_COMP are defined.
o Add information to the save file about internal compression options
used when writing the save file, particularly rlecomp and zerocomp
support.
o Automatically adjust rlecomp and zerocomp (if support compiled in)
when reading in an existing savefile that was saved with those options
turned on. Still allows writing out of savefile in preferred format.
o In order to support zlib and not conflict with compress and uncompress
routines there, the NetHack internal functions were changed to
nh_uncompress and nh_compress as done in the zlib contribution received
in 1999 from <Someone>.
I tagged the sources NETHACK_3_5_0_PREZLIB prior to applying these
changes.
<Someone> reported that if you polymorph into a flying monster while in a
pit, you must take u.utrap turns to first climb out before you can fly. Of
course, once you're out, you can swoop down into the pit to pick things up
w/o delay. Rather that have you automatically fly out (e.g. like quaffing
a potion of levitation), I thought it was better to take a turn to fly out,
so that's what I've implemented.
The code to deal with exiting a pit is moved to a new climb_pit function
and the "up" command now lets you climb from a pit too (something I've
found non-intuitive in the past).
Finally, I noticed that non-moving monsters could still go up/down even
though they couldn't move around. Added non-moving checks in doup/dodown.
Support negation syntax to restrict unwanted race, role, gender, align
options:
OPTIONS=role:!knight, role:!tourist, race:!orc
prevents them from being picked randomly or
appearing in the pick lists at the start of the game.
- always write plname into save file, no longer conditional
- add 'selectsaved' wincap option to control the display of
a menu of save files for ports/platforms that support it.
- add support for win32 tty using normal nethack menus.
- the win/tty/wintty code is generalized enough that any
tty port could support the option if the appropriate port-specific
code hooks for wildcard file lookups are added to src/file.c
specifically in the get_saved_games() routine. There is posix
code in there from Warwick already, and there is findfirst/findnext
code in there from win32. Warwick has the posix code only
enabled for Qt at present, but with wintty support, that could be expanded
to other Unix environments quite easily I would think.
Here is what the tty support looks like:
NetHack, Copyright 1985-2005
By Stichting Mathematisch Centrum and M. Stephenson.
See license for details.
Select one of your saved games
a - Bob
b - Fred
c - June
d - mine3
e - Sirius
f - Start a new character
(end)
The following files existed in the NetHack SAVEDIR directory
at the time:
ALLISONMI-Bob.NetHack-saved-game
ALLISONMI-Fred.NetHack-saved-game
ALLISONMI-June.NetHack-saved-game
ALLISONMI-mine3.NetHack-saved-game
ALLISONMI-Sirius.NetHack-saved-game
Note that despite the file names, the actual character name
is drawn from the savefile.
The WIN32CON support passes
USER-*.NetHack-saved-game
to findfirst/findnext where USER is your login name of course.
Since the trunk breaks savefile compatibility anyway,
remove some code that was inappropriately loading a boolean
with multiple values in order to preserve savefile compatibility in 3.4.x
[Note: this patch increments EDITLEVEL rendering existing bones
and save files obsolete]
From a bug report:
> If the Summon Nasties monster spell gates in two minions instead of one,
> the message still says "A monster appears from nowhere!"
The code wasn't counting any summoned monsters who had an opposite alignment
to the summoner. It also assumed that the 10% chance for demon summoning
in Gehennom always yielded exactly one monster even though that can produce
zero or more than one.
<Someone> wrote:
> From the mkclass() comments:
>
> /* Assumption #2: monsters of a given class are presented in ascending
> * order of strength.
> */
>
> And monst.c:
>
> * Rule #2: monsters of a given class are presented in ascending
> * order of strength.
>
> * Rule #4: monster subclasses (e.g. giants) should be kept
> * together, unless it violates Rule 2. NOGEN monsters
> * won't violate Rule 2.
>
> Inspecting my monster-difficulty spoiler, I see the following places
> that these precepts are violated: do they cause potential problems?
> (Insofar as occasionally incorrectly miscalculating the probabilities
> for monster generation is a "problem", that is...)
>
> SPECIES DIF
> ~~~~~~~~~~~~~~~~~~~~~~ ~~~
> d dog 5
> d large dog 7
> d dingo 5
>
> d warg 8
> d winter wolf cub 7
> d winter wolf 9
>
> u white unicorn 6
> u gray unicorn 6
> u black unicorn 6
> u pony 4
>
> H frost giant 13
> H storm giant 19
> H ettin 13
>
> P black pudding 12
> P green slime 8
>
> S pit viper 9
> S python 8
> S cobra 10
>
> Z giant zombie 9
> Z ghoul 5
>
> @ nurse 13
> @ soldier 8
> @ sergeant 10
>
> & horned devil 9
> & succubus 8
>
> & balrog 20
> & sandestin 15
>
> (I've just realised that these may have already been fixed, and
> waiting on a file-compatibility-breaking release; if so, ignore me :-)
[Attention: This patch increments EDITLEVEL in patchlevel.h, rendering all
previous save and bones files obsolete.]
Here's the first cut at the two recommended flags lknown and cknown.
I've attempted to stay close to Pat's recommendations:
"Containers ought to have two new flags: lknown for lock status known,
and cknown for contents known (ie, `secret'). Formatted box and chest
descriptions should include locked/unlocked/broken when that is known
and empty/nonempty (or something like "holds N items") when contents
are known. The contents indicator would also apply to nonlockable
containers."
I probably overlooked a place where a flag should be adjusted, but this
should give us a good starting point.
I wasn't sure what to do with the case of the auditory feedback for
magical locking "Click" and "Clunk". The question that came to my mind
was: Should those reveal the locked or unlocked status of a box?
I suppose if you knew the type of wand you were zapping or the spell
you were casting, you could argue that they should.
In the end, I opted for setting lknown right off the zap/cast effect
for anyone playing a Wizard role, and not setting it for anyone else,
thus advancing class differentiation a little bit too.
I haven't checked the cknown results under all flags.menu_style options
at this point, only MENU_FULL.
Fix the wizard mode crash From a bug report. Move the WIZKIT
message suppression to a lower level instead of trying to guard against
present and future pline() calls in the wishing code. The way that was
being handling wasn't suitable for dealing with quest feedback.
This also includes a couple of additional wishing synonyms.
Something from <Someone>'s list: some messages have hardcoded references
to "helmet" which sound strange when the character is wearing a hat or cap.
helm_simple_name() is comparable to the existing cloak_simple_name(). It
returns "helm" or "hat" depending upon whether the helmet provides the
same protection that yields the assorted repetitions of "fortunately,
you are wearing a hard helmet". This choice ends up categorizing elven
leather helm as a hat (which I think is ok given that its undiscovered
description is "leather hat"), contrary to <Someone>'s suggestion that the
distinction be made based on whether the helmet was made of cloth.
I started on this a year and a half ago but didn't commit it.
Unfortunately I don't remember why and haven't done any significant
additional work now--just recovered from some intervening bit rot and
confirmed that the patch as is seems to be working ok (in the trunk; the
branch side has not been tested). I suspect that I meant to look for
additional helmet messages which could benefit from conditional headgear
description. (Those "hard helmet" ones don't need it, although they
should perhaps be moved into a common routine instead of being replicated.)
<Someone> reported that she got "your weapon slips from your hands" when
inflicted with slippery fingers while wielding multiple daggers. That
should be "weapons" plural and they're only being dropped from one "hand"
singular. Fix that and also give more specific feedback than "weapon"
for non-swords based on their weapon skill category names. This works
pretty well for most common weapons but might need some more tweaking for
ones where different types have gotten lumped together in the skills.
old feedback:
Your weapon slips from your hands.
Your tool slips from your hands.
Your food slips from your hands.
twoweapon:
Your sword slips from your hands.
Your other sword also slips from your hands.
new feedback:
Your daggers slip from your hand.
Your <one-hander> slips from your hand.
Your <two-hander> slips from your hands.
Your pick-axe slips from your hand.
The corpse slips from your hand.
twoweapon:
Your sword slips from your left hand.
Your other sword also slips from your right hand.