Fixes#177
The monst struct has 'mintrinsics' field which attempts to handle
both mon->data->mresists and extrinsics supplied by worn armor, but
polymorph/shape-change was clobbering the extrinsics side of things.
Potentially fixing that by changing newcham() to use set_mon_data(...,1)
instead of (...,0) solved that but exposed two other bugs. Intrinsics
from the old form carried over to the new form along with extrinsics
from worn armor, and update_mon_intrinsics() for armor being destroyed
or dropped only worked as intended if the armor->owornmask was cleared
beforehand--some places were clearing it after, so extrinsics from worn
gear could persist even after that gear was gone.
So, fixing the set_mon_data() call in newcham() was a no go. This
fixes update_mon_intrinsics() and adopts the suggested code from
github pull request #177 to have mon->mintrinsics only handle worn
gear instead of trying to overload innate intrinsics with that. This
is a superset of that; the flag argument to set_mon_data() is gone
and mon->mintrinsics has been renamed mon->mextrinsics. (The routine
update_mon_intrinsics() ought to be renamed too, but I didn't do that.)
A polymoprh zap which creates a long worm can hit and transform the
same monster again depending upon tail segment placement. Similar
behavior occurs if monpolycontrol is set in wizard mode and player
chooses 'long worm' for what to transform an existing one into (in
which case polymorph fails and zap might hit that same worm again
in another segment, prompting player to choose its new shape again).
Simplest fix would be to make tail segments be immune to polymorph,
but that would prevent players from deliberately attacking the tail
(for polymorph attacks only). Next simplest would be to make long
worms M2_NOPOLY so that polymorph can't create them, then just live
with multiple promptings when monpolycontrol is set. This fix
tracks whether a long worm has just been created via polymorph (or
explicitly retained its shape via monpolycontrol) and makes further
hits on same creature on same zap have no effect. It does so by
setting mon->mextra->mcorpsenm to PM_LONG_WORM when a long worm is
result of polymorph, and setting context.bypasses to get end-of-zap
cleanup. (It doesn't bother discarding mon->mextra if reset of
mcorpsenm leaves mextra empty.)
Redo how updates of permanent inventory window are suppressed during
restore. Reverses part of e9f1e03271
which included a simpler attempt to deal with this.
It looks like we should have been getting impossible "unpaid_cost:
object wasn't on any bill" but segfault was reported; I haven't tried
to figure out why. The band in xname() ought to be redundant now but
is included for bulletproofing.
Fixes#106
If dipping a worn amulet into a potion of polymorph turns it into an
amulet of change, the game panics while trying to use up that amulet
when the new one hasn't replaced the old one in inventory yet. Simply
reordering the relevant code isn't sufficient to fix things: once it
is in inventory and can be successfully used up, later code would end
up deferencing a stale pointer because it was unaware of the deletion.
H7205 - full-pack identify might skip items if perm_invent is on
because updating the inventory window might reorder 'invent'
while the identify code is in the midst of traversing it;
H7120 - pickup that doesn't pick anything up can change the glyph
shown on the map because the pile might be reordered such
that a different item is on top;
H5216 - performing a sortloot operation on a pile and then switching
back to sortloot:none doesn't restore pile's original order.
The 'revamp' that changed the contributed sortloot feature to switch
to simpler usage (object list itself was sorted rather than having a
parallel array that needed to be constructed, sorted, traversed, and
discarded) turns out to have too many problems. This reverts to a
hybrid solution that constructs an array for traversal, leaving the
linked list in its original order, but hides most of the details of
that from sortloot() callers. The 'revamp' benefit of being able to
use normal list traversal is lost, as is the potential to skip
sorting when the list turns out to already be in the desired order.
This could stand to have a lot more testing than it's had so far.
> [1. perm_invent is kept in flags so persists across save/restore, but
> perm_invent capability can change if player restores with a different
> interface--or same one running on a different-sized display--so it
> ought to be in iflags instead.]
Not addressed here.
> 2. perm_invent window does not get updated when charging a wand (or
> other chargeable item presumably), with a scroll of charging.
Most scrolls rely on useup() -> update_inventory(), but charging uses up
the scroll early so that it will be gone from inventory when choosing an
item to charge. It needed an explicit update_inventory() after charging.
> 3. update_inventory(), is called from setworn(), which is called from
> dorestore(), when loading a save. Segfaults have been observed in
> variants based on this code (though not yet in vanilla 3.6.1), so it's
> possible this may be unsafe. The update_inventory() call in setworn()
> could be protected with "if (!restoring) ..."
tty doesn't support perm_invent, so this might be a win32 issue.
I've made the suggested change, but a better fix would be to turn off
perm_invent as soon as options processing (new game) or options restore
(old game unless/until #1 gets changed) has finished setting things up,
then turn it back on at the end of moveloop()'s prolog when play is
about to start.
= =
Most of the read.c change is reordering prototypes to match the order
of the corresponding functions. I did this when adding a new static
routine, then ended up discarding that routine.
I think this finally quashes the "cursed without otmp" issue.
Various ways of destroying wielded weapon used setnotworn() rather
than unwield(), so the previous change to have unwield() clear the
pending W_WEP bit from takeoff.mask wasn't sufficient to prevent
'A' moving on from another item (blindfold--it's the only thing
processed before primary weapon) to weapon which wasn't there any
more. Also, if weapon was already set in takeoff.what to be
processed on the next move, clearing W_WEP from takeoff.mask wasn't
sufficient either.
Move the previous unwield() 'fix' to setworn() and setnotworn() and
extend it to include cancel_don() if the item being replaced or
removed is in progress or scheduled for next. (Most of the time,
remove_worn_item() has already done that before setworn() or
setnotworn() is called.)
timeout.c: the luck timeout expression caused a bit of thought trying
to decide whether it was doing what was intended (it was). Add some
parentheses so that thought is no longer required. ;-)
worn.c: fix up a macro where automated reformatting mistook a
bitwise-and operation for a cast applied to the address of something.
The automated reformatting put a space in casts of the form
'(type)(expression)', yielding '(type) (expression)', but it didn't
do that for '(typedef)(expression)'. There are lots of instances of
'(boolean)(expression)'; (uchar) and (xchar) also occur. I haven't
noticed other types, but I haven't looked in very many files yet.
End of first pass, but '[&|?:][ \t]*$' doesn't catch trailing operater
followed by end-of-line comment so more needs to be done. As with the
past couple of batches, I've removed redundant parentheses from 'return'
statements but only for files that had continuation fix-ups.
I've also removed tabs from comments in some of the files, but didn't
start until part way through this subset of the sources.
While looking at clear_bypasses() I noticed some excluded code [#if 0]
which could be risky to include, so update the comment there. Also,
excluded code tends to need formatting fix-up.
I'll push a formatting guide at some point. There may still be
outstanding changes, but please feel free to resolve those as you arrive
a them.
To the best of my knowledge, there is no changes to the actual code
content, but the formatter does have the occasional bug. If you run into
an issue, please fix it!
For those pro players who really want to try their hand
at that zen samurai, without needing to reroll thousands
of times to start with blindfold. Nudist starts without
any armor, and keeps tabs whether you wore any during
the game, for even more bragging rights.
Also makes the Book of the Dead readable even while
blind, for obvious reasons.
From a bug report, dropping a lit
(burning) potion of oil while levitating can produce an explosion which can
destroy inventory. If in the process of dropping multiple items, the ones
after the oil might be gone, resulting in use of stale pointers and possibly
triggering an "extract_nobj: object lost" panic or even a crash. While
testing my fix, I discovered that being killed by an exploding potion of oil
could produce an "object_is_local" panic if bones are saved (and reproduced
with unmodified 3.4.3).
In #H1820, <email deleted> reported that helms
of opposite alignment didn't work for monsters. There's never been
any attempt to implement that, and it wasn't omitted by accident, so
I wouldn't classify it as a bug. But it does seem buggy that temple
priests and minions of <deity> would be willing to put such helms on
and risk changing allegiance to another deity. This lets other types
of monsters still wear helms of opposite alignment as ordinary head
protection, but the explicity aligned creatures won't do so anymore.
Like their use of lizard corpses to defeat being turned into stone,
let monsters use wands of fire, fire horns, and scrolls of fire to try to
defeat being turned into slime. If the scroll is read while confused, it
won't succeed. Otherwise, monsters who don't resist fire will take some
damage in the process and might end up killing themselves (although with
the testing I've gone I've yet to see that happen--I guess that means
that handling for dying-in-the-process hasn't been adequately tested...).
So far, they don't know how to jump onto adjacent fire traps, nor
will fire breathing monsters breath at themselves. I don't know whether
I'll get around to tackling either of those.
Extend rotouch_equipment() to cover all items in use, worn/carried/
invoked in addition to wielded. Done when you change alignment, change
shape, or catch lycanthropy. No-longer-touchable items inflict modest
damage; worn/wielded ones will be unworn/unwielded. For the shape change
and lycanthropy cases, unwieled weapons are also dropped. Other unworn
stuff stays in inventory, as do weapons for the alignment change case.
It ought to force off gloves if worn silver--or hypothetical
artifact--ring has become untouchable and gets unworn. Instead it just
curses the gloves, if necessary, so that there's some plausibility to
having the ring come off.
From a bug report: zapping wand
of speed monster (or slow monster) at an immobile monster would give the
usual '<mon> is moving faster" (or slower) message even though the monster
couldn't move at all. This fixes that for monsters who can never move
and also for monsters who are temporarily paralyzed or asleep, although I
wonder whether speed change magic ought to also snap the latter out of it.
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.
simple_typename and obj_typename operate on item types rather than
particular objects so have to assume that the item involved has been seen.
That means that simple_typename(obj->otyp) is not suitable; if obj->dknown
hasn't been set, it gives away information. This adds mininal_xname(obj)
to be used for that purpose. I'm not aware of any straightforward way to
actually expose the original problem; it's more than hypothetical but not
something anyone's likely to have come across.
Not fixed: test driver program reveals that obj_typename(GOLD_PIECE)
and simple_typename(GOLD_PIECE) yield "coin of gold piece". But I don't
think there's any way to get nethack to show that to the user.
From the newsgroup: non-cursed dunce cap or helm of opposite alignment
which would glow black and become cursed if worn by the hero wasn't doing
the same when worn by a monster. Fixing this gives players a new way to
recognize bad hats--drop on altar, then drop in front of approaching goblin
or other wimpy monster capable of wearing armor--but I think that's fair.
Since helms of opposite alignment are usually already cursed it won't make
much difference for them; most players seem to avoid all conical hats so it
won't make much difference for dunce caps either.
Pat Rankin wrote:
> collect them all into some new struct and
> save that separately rather than jamming more non-option stuff
> into struct flags.
This patch:
- collects all context/tracking related fields from flags
into a new structure called "context."
It also adds the following to the new structure:
- stethoscope turn support
- victual support
- tin support
Building with an old version of gcc with various warnings enabled
generated a lot of noise. Most of it was due to not guarding string
literals with `const', but there were a couple of actual problems too.
Some recent newsgroup discussion claiming that a pet ki-rin was
wearing a helmet (I think poster was hallucinating) caused me to look
at some of the hat handling code. There were a couple of noticeable
problems and one latent one in code added for 3.4.1. Polymorphing
into a minotaur pushes hard helmets off hero's head, but nothing
prevented you from putting one right back on. Helmet wearing monsters
who polymorphed into minotaurs weren't affected at all. And message
handling always assumed multiple horns even though we have some singled
horned monsters, but since all those have no hands they can't wear any
armor and that potential pluralization issue wasn't noticeable.
<Someone> wrote: "Also, hobbits can't wear armour,
at least, you can't wear armour when polymorphed into a hobbit, even
though hobbits do tend to be carrying elven mithril-coats.
It's tempting to suggest adding an explicit exception in
sliparm() for elven mithril just to keep the Tolkienness."
- added a general routine for adding race-based /object
combination exceptions.
- hobbits can wear elven mithril-coats
Forwarded from the newsgroup: when a monster gets hit by wand or
spell of polymorph, any armor that fell off was protected from being
hit by that same zap, but a dropped weapon wasn't. Nor was the whole
dropped inventory in the case where the monster is killed by system
shock rather than transformed. Protect its entire inventory.
Provide more control over message handling for monsters' use
of equipment. This fixes the statue revival problem (inappropriate
feedback when monster puts on speed boots) mentioned in the earlier
"intrinsics of dead monsters" patch.
Someone posted in the newsgroup about using stone-to-flesh
to reanimate a petrified pet and having it come back to life with
boosted speed intact. When the character gets petrified, stripping
speed is one of the first things which happens, so now do that for
monsters too. I decided not to make monsters who have normal speed
become slow; there isn't any analogous case for the player.
Possible bug: while testing this, I zapped a wand of probing
at a hill orc which had just eaten a lizard corpse to save itself
from stoning. The feedback said "eating" but the orc immediately
hit and killed me as if it wasn't affected by any movement delay.
Make wands of speed or slow monster known if their effect
on monsters is observed; likewise for speed boots. Also, avoid
giving odd "the bat is moving faster" when seeing a bat created
in gehennom and inaccurate "the monster is moving slower" when
a monster puts on speed boots.
Summary of spell changes:
-- wimpiness of 'default' spell fixed by doing half damage for magic resistance
instead of 1 damage, and using half monster level instead of 1/3. It may
still need tweaking, but is much better than before.
-- 'default' spell for cleric monsters is now the wounds spell, by analogy with
wizard monsters.
-- added clerical lightning strike, flame strike, gush of water
-- all spells should now say the monster is casting a spell, and all spells
should have messages. (Side effect: monsters speeding up by other means
also give a message saying so).
-- casting undirected spells is not affected by whether the monster knows
where you are. Monsters that are attacking your displaced image, that are
several squares away, or that are peaceful can use undirected spells.
-- messages should correctly say whether the spell is undirected (a monster
was always casting at thin air or pointing at you and cursing, without checking
to see if the spell wouldn't require pointing)
-- Monsters which are attacking your displaced image, etc. use up mspec_used.
If they are casting an undirected spell, the spell still works.
-- Monsters which are not attacking can cast spells that don't attack.
-- If a monster didn't have ranged spellcasting ability (which most don't),
it would print a curse message from buzzmu() every round it was at range,
creating a useless stream of constant curse messages
I still haven't made spellcasters "smarter" in the sense of noticing whether
you have reflection, fire resistance, etc. That opens a big can of worms
because it would mean giving monsters a memory.
Known bug: the higher level a monster is, the more spells it has; since it
chooses a noncombat spell by randomly picking a spell and casting if it
happens to be noncombat, the higher level the monster is the greater the
chance of getting nothing.