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.
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.
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.
Something's wrong with the way lava was being handled in moveloop().
If you were trapped in lava (ie, moved into some but didn't die on the
spot thanks to fire resistance), you could sink and ultimately die without
ever taking another actual turn (typing ``i<space>'' repeatedly is an easy
way to reproduce). [`didmove' was only being checked for the sinking
deeper case and not for the decrement which ultimately leads to the fully
sunk case.] On the other hand, if you could manage to start an occupation
and avoid being interrupted, you would never sink while it was in progress.
[Lava handling followed ``if (multi && occupation) { ...; continue; }''.]
While testing some other code (lava vs slime, coming shortly) I ended
up with the cursor sitting on the status line while the game was waiting
for me to enter my next move. I don't really understand what's going on
there, and moving the lava handling before bot() might have hidden that
particular problem now by changing the point at which Slime will get taken
off the status line, but this attempts to fix it anyway.
From a bug report: zapping a wand of striking or locking or spell of
force bolt or wizard lock up or down when standing at an open drawbridge's
portcullis didn't affect the bridge if the portcullis was positioned north
of the open span. One of the two drawbridges on the Valkyrie quest goal
level has that orientation. is_drawbridge_wall()'s name is somewhat
misleading; it isn't boolean and returns -1 rather than 0 for "no".
From a bug report. That's hard to fix in the general case because armor
and tools might not fit back into the same equipment slot, but most other
types of worn items can be re-worn after being transformed. This makes
any transformed worn item stay worn if it is wearable in the same slot.
Pat wrote:
> <Someone> has a patch (we've added a couple of
> his earlier ones) which changes the statue display from a single
> one size fits all "`" to a gray monster symbol instead.
> But I think the idea is a good one, and along with the
> bouldersym option could make the fairly hard to
> distinguish back-tick character go away.
Sources tagged before applying NETHACK_PRE_STATUE,
and afterwards with NETHACK_POST_STATUE for easy
rollback.
About six weeks back, <email deleted> suggested that
bear traps should deal out damage and be escapable via opening magic.
This doesn't do anything about the first part, but it does allow opening
magic (wand of opening, spell of knock, blessed Bell of Opening) to get
the hero out of bear traps and webs if zapped either at self or downwards.
Zaps across the floor which hit monsters will free them from such traps,
with a chance that releasing a hostile monster will pacify it (using
existing #untrap code). Conversely, if you are at a web or bear trap
location but not currently trapped, closing magic (wand of locking, spell
of wizard lock) will cause the trap to activate; you may or may not become
trapped. Likewise for zaps at monsters who are at such locations, which
is treated as an attack.
Opening magic which hits the hero or a monster located at a trap door
or falling rock trap spot will cause the trap to activate; as above, it's
an attack for the monster case. At the moment, zapping opening magic
downwards at the hero's location (but not zapping at self or at monsters)
will also cause holes, pits, and spiked pits to activate. (Zapping down
triggers falling rock traps and zapping up doesn't; that'll need to be
changed.) Zapping opening down while mounted will untrap, if stuck in a
web or bear trap, and will trap, for the falling cases, in precedence over
releasing the saddle and forcibly dismounting. The latter still occurs
when there is no applicable trap present though.
Zapping locking magic downwards at a hole location will convert the
hole into a trap door. Zapping breaking magic (wand of striking, spell of
force bolt) down at a trap door location will convert the trap door into a
hole. (Neither conversion currently alters the made-by-you flag for the
trap. However, the rationalization that distinctive style is what makes
made-by-you recognizable suggests that conversion should clear the flag.)
Lastly, the old behavior (which pre-dated bare holes) of destroying trap
doors when zapping down at them with locking magic has been removed--it
didn't seem to fit very well with the new cases. I'm starting to have
second thoughts about that but am going to commit this before discovery of
some more niggling details drags it out for another six weeks.
Mentioned by <Someone>, who suspected that the fix for C343-114 dealt with
this. When a giant picks up a boulder from a location where more than one
is present, line-of-sight would be inappropriately cleared, as if the
remaining boulders were transparent. (He said that he got no pickup
message when the giant picked up the boulder. I do, and have not tried to
figure out whether this is a post-3.4.3 difference.) Pushing a boulder
onto a landmine had the same bug, although you wouldn't notice unless there
were at least three boulders to be pushed (mysterious ability to push more
than one boulder in a turn strikes again: first one triggers the trap and
is destroyed, allowing hero to see through any others; second fills in the
resulting pit; third gets moved to the former trap spot and [probably--I
haven't checked] re-blocks vision; fourth, if any, stays put; if only one
or two are present, the change in vision is expected and the fact that it
happens too soon in the two boulder case would probably go unnoticed.
Polymorph of a boulder also opened up vision without checking whether any
others are present.
An existing, evidently overly optimistic, fixes34.4 entry covers this.
Remove some more code that forced pointers into a long int, and
vice versa where information could be lost (P64 platforms such as
WIN64 have a 64 bit pointer size, but a 32 bit long size.)
This 2nd part deals with timeout functions switching
some arguments from type genericptr_t to 'anything'.
Like part 1, this needs to increment EDITLEVEL in patchlevel.h.
Provide a common routine that always does the right
thing with respect to timers and weight when altering
obj->corpsenm, and use it throughout the code.
From a bug report, a steed hit by disintegration
breath survived via life-saving, but the program was confused about whether
the hero could still ride and issued some impossible warnings. The code
to disintegrate a monster's inventory didn't bother to unwear worn items as
it destroyed them, presumeably assuming that the monster was sure to die,
so steed was left with a flag bit set claiming it was saddled even though
the saddle was gone. This fixes that, and the rider will end up being
dismounted as the saddle gets destroyed, regardless of whether the steed
ultimately survives. [Since the steed is still present at the time of
dismounting, the hero will get bumped to some other location, possibly to
the next spot about to be hit by the same black dragon breath attack which
just vaporized the steed. That's suboptimal, to put it mildly....]
I couldn't test the circumstances of the original report. Post-3.4.3,
ki-rin has been marked no-hands and is no longer capable of wearing armor
or amulets. I looked to see whether any other potential steed could wear
an amulet of life-saving and couldn't find one. But the original bug also
applied to conferred properties of special armor worn by non-steed monsters
too, so the fix was needed anyway.
The branch and trunk patches are different. For the trunk, I moved a
big chunk of code out of buzz() into a seperate routine. That actual fix
is the same in both variants.
move oattached and oname and other things that vary
the size of the obj structure into a separate
non-adjacent oextra structure, similar to what has
already been done for mextra. The obj structure
itself becomes a fixed size.
New macros:
#define ONAME(o) ((o)->oextra->oname)
#define OMID(o) ((o)->oextra->omid)
#define OMONST(o) ((o)->oextra->omonst)
#define OLONG(o) ((o)->oextra->olong)
#define OMAILCMD(o) ((o)->oextra->omailcmd)
#define has_oname(o) ((o)->oextra && ONAME(o))
#define has_omid(o) ((o)->oextra && OMID(o))
#define has_omonst(o) ((o)->oextra && OMONST(o))
#define has_olong(o) ((o)->oextra && OLONG(o))
#define has_omailcmd(o) ((o)->oextra && OMAILCMD(o))
changed macros:
has_name(mon) becomes has_mname(mon) to correspond.
The CVS repository was tagged with
NETHACK_PRE_OEXTRA
before commiting these, and
tagged with
NETHACK_POST_OEXTRA
immediately after. The diff
between those two tags is this oextra patch.
The associated mail daemon changes to use an oextra
structure instead of a hidden command located in the
name after the terminating NUL, have not been tried
or tested.
<Someone> reported that thitu() was adding d20 damage for silver object
hitting silver-hating hero even though all the callers were using dmgval()
which also does that, resulting in doubled silver bonus/penalty. This
fixes that (including for boomerangs thrown by player, which weren't using
dmgval(), to handle a hyptothetical silver boomerang). While testing it,
I noticed that there was no "the silver sears your flesh" message when a
monster hit you with a wielded silver weapon, so this fixes that too.
(How did we miss that? And how did <Someone>? :-)
- restore intended behaviour of kill_genocided_monsters().
It has been incorrect since the chameleon overhaul in June 2004.
- eliminate CHAM_ORDINARY and use NON_PM instead.
<email deleted> wrote:
> * Doors absorb the blast of a broken wand of striking. What's more, the message
> reads "The door absorbs your bolt!" rather than "blast".
passes wand type to explode() as a negative value for the case
where the wand type isn't mapped to an AD_* explosion type.
Then explode() converts it to a positive and passes it to zap_over_floor().
Implement the following suggestion by <email deleted>
- Reading a scroll of light while confused should
create a hostile yellow light (black light if cursed).
It only creates the light monster effect 1 out of 5 times.
From a bug report... some
special case handling for polymorph of spellbooks never worked as intended.
It's possible to polymorph a spellbook, use it to learn a new spell, and
then repeat as many times as you like unless/until you run out of polymorph
magic or the small chance of "object shuddering" causes it to be destroyed.
Polymorph was incrementing the book's ``number of times read'' field with
the intent that it would fade to blank after being read 3 times (which
turns out to the 4 times since the check is actually for re-reading 3 times
after the first). That didn't work because the spestudied field was ignored
when learning a new spell, only checked when relearning a known spell.
Now it will be checked when learning a new spell, and also the book
tweaking during polymorph is slightly more elaborate. If you happen to
get a blank book during the item selection, it will have a read counter
of 0 and can be re-polymorphed into something readable. But if you get
some other book, its read counter will be set to one greater than than the
original book's (same as before). And then the counter will be checked
to see if it has gone over the limit, in which case the book will be made
blank and its counter will be reset to a random value. Re-polymorphing
that blank book again has 1/4 chance apiece among the following cases
book gets blanked again; goto step 1...
book is non-blank but too faint to read; reading attempt will fail
book can be read normally and then re-read once
book can be read normally and then re-read twice
which is more inline with the intent of the original special case code.
It's actually slightly nastier since you'll occasionally get a book for a
spell you don't know yet but then not be able to learn it from that book.
Noticed recently when a user reported that an unseen monster zapping
an unseen wand caused wand of striking to become discovered. [That was
because the zap also hit a door and the code for the latter didn't check
whether the wand had been seen, and it got fixed a couple of weeks ago.]
When the player zaps wands while the hero is blinded, it was discovering
(for the cases where the effect can be observed without sight) the wand
even though the wand's description was unknown (showed in inventory as
"a wand"). This replaces the calls to makeknown() in zap.c with calls to
new learnwand(), which checks whether the wand description is known; you
no longer discover something you've never seen. Reverse effect has also
been added: if the type of wand has been discovered earlier, zapping an
unseen wand (another of the same type, picked up when blind and zapped
while still blind) will now mark it as seen (to show up in inventory as
"a wand of <whatever>" instead of just a "a wand"). The latter aspect
really ought to be independent of prior discovery, but we currently have
no way to record "we know what this particular item does even though we
don't know what type of item it is yet". [If we add that, it would be
applicable to potions (when operating on stacks) and rings too.]
Minor change: zapping yourself with wand of opening or spell of
knock will remove attached ball&chain rather than give a "chain quivers"
message. Explicitly zapping the chain already did that; if the unlocking
magic works on the chain connected to your leg then it really should also
work on your leg connected to the chain. Zapping unlocking at yourself
probably should also scan inventory to check for carrying locked chests,
but I didn't add that. (If added, then locking magic will need to be
augmented likewise.)
This also fixes <Someone>'s recent complaint: zapping an unknown
wand of teleportation at yourself didn't make it become discovered.
Now it will be, under the same circumstances as when you're riding: if
teleport control causes you to be prompted for destination, or if random
destination moves you more than jumping distance away from your original
position. (The Stunned exception to teleport control, which was missing
in zap_steed, perhaps ought to be moved into the macro definition of
Teleport_control itself so that all code always handles it consistently.)
Note: The CVS repository was tagged with NETHACK_PRE_MEXTRA
prior to application of this patch to allow easy withdrawal if necessary.
Adds a new mextra structure type that has a set
of pointers to various types of monster structures
including:
mname, egd, epri, eshk, emin, edog
Replaces the mextra bits in the monst structure
with a single pointer called mtmp->mextra of type
(struct mextra *).
The pointer can be null if there are no additional
structures attached. The mextra structure is not
adjacent to the monst structure.
Reduces the in-memory footprint of the monst that
has no other structures attached, at the cost
of adding 6 extra long ints per monster to
the save file
The new mextra structure has the mextra fields
independent of each other, not overlapping as was
the case with previous NetHack versions.
This patch doesn't do anything to capitalize on
that difference however.
Consolidates vault.h, epri.h, eshk.h, emin.h and edog.h
into mextra.h
Adds a macro for checking for whether a monster has
a name:
has_name(monst)
This fixes the magic trap panic
expels() -> spoteffects() -> dotrap() ->
domagictrap() -> tamedog()
because the monst no longer varies in size so no
replacement is required.
Extend the capabilities of corpse_xname() so that various callers can
be simplified. It can how handle an article prefix, effectively turning it
into corpse_doname() (not quite; still need doname() to see a count when
quantity is more than one, or to see bless/curse state). It can also handle
inclusion of adjectives like "partly eaten" or "bite-covered". For unique
monsters those come out in the form
the Chromatic Dragon's partly eaten corpse
instead of the old
partly eaten Chromatic Dragon corpse
[so wishing probably needs to be taught about potentially finding a monster
name before assorted adjectives such as blessed; also, name_to_mon() needs
to learn how to cope with the possessive suffix].
A sizeable chunk of this patch deals with consolidating some of the
redundant "petrified by a cockatrice corpse" handling. It may be possible
to consolidate all remaining instances together since they're quite similar,
but I didn't think about that until just now and I want to get this patch
over with.
Couple of post-3.4.3 things: using ':' to view the contents when
looting or applying a container wasn't setting its cknown flag (contents
known); probing a container wasn't setting lknown flag (lock state known).
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.
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.
<email deleted>, attempting to #chat
with quest leader who was raised from the dead yielded "impossible: invalid
quest character". The code attempted to handle that but the conditional
logic for preserving the m_id field was backwards. 3.4.3 only dealt with
the corpse revival case; dev code tried to support it for statue animation
too but still had the same problem.
Several apparent bugs remain: if the leader is angry (perhaps hero
killed him before reviving him) he won't give an angry response if the
player initiates #chat rather than wait for adjacent leader to do so. If
it's an archeologist reviving the statue of petrified Lord Carnarvon, hero
gets a rather ironic message about feeling guilty for destroying historic
statue. Lastly, shouldn't there be a comparable quest_status.nemesis_m_id
so that if one player lugs the corpse or statue of his quest nemesis back
into the main dungeon and another one revives that, it won't start behaving
like 2nd player's nemesis? Live nemesis is explicitly kept out of bones
but I don't think the corpse or statue of one is blocked and its monster
behavior after revival is based on mon->data->msound==MS_NEMESIS rather
than on m_id of current game's active nemesis monster.
Reviving a corpse or statue restores the monster to life before
deciding whether the object which was used up in the process belongs to a
shop. This resulted in a rather strange situation when the revived monster
was the shopkeeper involved. The object can't have been stolen; there was
no shk to own it at the time it got used up.
Manlobbi's statue of a shopkeeper comes to life.
You owe Manlobbi N zorkmids for it.
Suppress "of a shopkeeper" in such a case, and do not charge the hero for
using up the statue. The corpse case only needed the second part.
This revises post-3.4.3 code so doesn't warrant a fixes entry.
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.]
[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.
[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.
Reported last December by <email deleted>. Using
a wand or spell of undead turning inside a shop used up corpses without
checking whether they were owned by the shop. Although the report didn't
mention it, using stone-to-flesh on statues had the same problem.
I'm not completely satisfied by some aspects of this code, but if I
don't commit what I've got now I probably never would. My original notes
are lost; I thought that there were some additional fixes present, but
looking at these diffs I don't see anything else significant enough to
warrant mention in the fixes file.
From a bug report: fracture_rock() was unintentionally propagating
the boulder or statue's dknown flag to the resulting rocks, producing a
trivial but noticeable difference in description of "rock" vs "stone" if
the source object had been seen up close prior to being broken and the
rocks are then examined remotely or while blind.
The curse/bless state is propagating too, but this seems reasonable
so I've left it alone.
- can shift into fog clouds, vampire bats, and vampire lords into wolves
- after being "killed" in shifted form, they transform back rather than get
destroyed, and you must take them on in vampire form to defeat them
- can deliberately shift into fog clouds to pass under closed doors
This is a foundation patch for patches to follow.
- use a full short index for mon->cham field.
- The current system of providing CHAM_XXX values
was limited to the 3 bits allocated in the bitfield and invalidated
save/bones if the field was expanded.
- The current system didn't provide an easy backwards change
if multiple monster types wanted to use the bit, there was a one
to one mapping: For instance, if you wanted a CHAM_VAMPIRE,
and you wanted vampires, vampire lords, and Vlad to use it, you
would have to have CHAM_VAMPIRE, CHAM_VAMPIRE_LORD,
and CHAM_VLAD defined to achieve that with the one-to-one backward
mapping.
- This new way just uses the mon[] index in the mon->cham field and
eliminates the need for CHAM_XXX (CHAM_ORDINARY is still used).
- no longer requires the cham_to_pm mappings
Play a character without see invisible. Wear speed boots. Generate a troll.
Zap it with a wand of make invisible. Kill it. Stand on the same square and
wait for it to rise from the dead. It will appear as a 'T'. Hitting it then
produces the normal "Wait, there's something here you can't see!"
[ incorporate slashem-Bugs-951439 fix ]
<Someone> reported that freezing the swamp on Juiblex' level would result
in message about a frozen moat. Avoid this by using waterbody_name
to to determine if it's a moat or not.