We used to have the contents of chests and large boxes be immune to
water damage, oilskin sacks immune unless the sack was cursed, other
containers be vulnerable. Some reddit discussion about ice boxes in
unnethack indicates that they are treated like oilskin sacks, which
makes sense. This adds that to nethack and also makes chests and
large boxes behave similarly. So it's now: nothing is immune even
when cursed (except statues); oilskin sacks, ice boxes, and other
boxes are immune to water damage unless cursed; all other containers
vulnerable even when not cursed.
|
| Old New
|immune all statues, statues
| the time chests, large boxes
|
|immune when BU, oilskin sacks oilskin sacks,
| vulnerable if C ice boxes,
| chests, large boxes
|
|vulnerable ordinary sacks, ordinary sacks,
| all the time bags of holding, bags of holding
| ice boxes
|
I suspect that the old ice box classification might have been an
accident caused by the Is_box() predicate yielding False for it.
The changes won't make much difference to actual play. Chests and
large boxes are rarely carried and never start out cursed, ice boxes
even more so, and sacks/bags haven't been changed. However, players
might intentionally curse a container to keep strong pets from
picking it up, or be carrying a box because they haven't found a bag
yet and then muck about with fountains or thrones and get it cursed.
Another mystery. Candles and oil lamps have obj->spe set to 1
but that isn't used by begin_burn() and such so I don't know why.
Magic lamp has spe set to 1 to indicate that there is a djinni
inside, but letting the djinni out converts it into an oil lamp.
I don't know if there is any case where it might actually be 0.
(Wishing yields an oil lamp rather than an empty magic lamp so
that isn't it. Cancellation magic doesn't affect it either.)
uball->spe used to be used during restore way back in 2.3e.
There hasn't been any any point in setting it when starting
punishment and clearing it when ending punishment for decades
so get rid of that.
Nearly as ancient--but not quite--back in 3.10 patchlevel N,
obj->spe was set to -1 when the Amulet of Yendor was saved in
a bones file. That was to flag it as fake, before the cheap
plastic imitation got added as a separate object.
So obj->spe isn't "special for uball and amulet" any more.
Started out adding spe==2 for eggs but ended up changing other
things too.
FIXME? The line "special for uball and amulet" baffles me:
uball->spe is set to 1 during punishment (with an ambiguous
comment "special ball (see save)"), and back to 0 afterwards, but
otherwise seems to be unused.
"and amulet" is ambiguous; it should either be "and the Amulet"
or "and amulets". I assume it probably referred to the former but
it doesn't seem to be used for either kind as far as I can tell.
Cap overall AC at -99 instead of -128. Put the same limit of 99
on enchantment and charge count of individual objects.
^X now reports if/when AC has reached its limit since players
could see that reaching that limit and then enchanting worn items
will change the worn items but not the total. (Same thing would
have happened with -128, just without any explanation and less
likely to accomplish.)
Won't affect normal play for any reasonable definition of normal.
Use a linked list to store stair and ladder information, instead
of having fixed up/down stairs/ladders and a single "special" (branch)
stair.
Breaks saves and bones.
Adds information to migrating objects and monsters for the dungeon
and level where they are migrating from.
Some eggs and tins could cause an out of bounds index into the
mons[] array. Post-3.6 bug: the faulty part of the test is only
relevant for 3.7 genetic engineer monster. Earlier versions just
called pm_to_cham() which does it's own index validation.
Fixes#406
ignitable() was excluding magic lamp and then every place that
used it did so as 'ignitable(obj) || obj->otyp == MAGIC_LAMP'
so just include magic lamp.
I noticed that while hunting for an explanation for report #K2734
where returning to a previously visited level triggered the
warning "begin_burn: unexpected eggs". I've decided that the
zombie apocalypse is probably the cause. It inserted a new type
of timer in the list of such but it didn't bump EDITLEVEL to
invalidate save and bones files which relied on indices into the
old list. I'm not sure whether we should bump that now.
Tin handling code used tin->cknown to indicate that the variety
(soup, deep fried, pureed, &c) was known, but neither object
identification nor end of game disclosure was setting cknown for
that type of object.
^I behaves as if cknown is set, so the problem was hidden during
times when anyone was likely to be paying attention.
Adopt the suggestion that candy bar stacks which get split should
keep the same wrapper text for both halves of the stack. The patch
stuck with using obj->o_id to manage the wrapper which prior to the
patch wasn't a factor in merging and splitting. Switch to obj->spe
instead, comparable to tin varities, so mergability is already
taken care of.
End of game disclosure tacks on T-shirt text to formatted items.
Do the same for candy bar wrappers.
Rot and revive timers are turned off when a corpse gets put inside
an ice box. They get turned back on when taken out of the ice box
by the hero but were being left off if taken out by a monster.
That resulted in corpses of arbitrary type behaving like lizard
corpses and never rotting away.
This fixes that. It also changes troll corpse behavior. Once put
in an ice box, a troll corpse will not get a new revive timer when
taken out, just an ordinary rot timer.
Adds two monsters originally from slash'em. I used the slash'em
tiles this time, also its code as a starting point but made various
revisions. Both the tiles could benefit from some touch-ups.
displacer beast: blue 'f'. Attempting a melee hit (ie, trying to
move to its spot) has a 50:50 chance for it to swap places with you.
Fairly tough monster to begin with, then half your ordinary attacks
effectively miss and if you try to face a mob by retreating to a
corridor or backing into a corner you can end up being drawn back
into the open. I added bargethrough capability, and also it won't
be fooled about hero's location by Displacement. [It only swaps
places during combat when contact is initiated by the hero, not
when attacked by another monster or when attacking.]
genetic engineer: green 'Q'. Its attack causes the target to be
polymorphed unless that target resists. Hero will almost always
have magic resistance by the time this monster is encountered, but
it can make conflict become risky by hitting and polymorphing other
monsters. Slash'em flagged it hell-only but I took that flag off;
I also took away its ability to teleport. Slash'em polymorphs the
hero if a genetic engineer corpse is eaten; that's included and I
introduced that for monsters too.
I added both of these to the list of candidates for monster spell
'summon nasties' and for post-Wizard harassment.
I also gave all the 'f's infravision. Probably only matters if the
hero polymorphs into a feline.
Displacer beast is originally from AD&D which depicts it as a six-
legged cougar with a pair of tentacles; it has Displacement rather
be able to affect an attacker's location. I think genetic engineer
is original to slash'em where it expands Q class but seems mainly to
be the base monster for Dr.Frankenstein (a unique monster with a
one-level side-branch lair in slash'em's incarnation of Gehennom).
Change obj->oextra->omid from a usually-Null pointer field in
oextra to a simple 'unsigned' that doesn't need any allocation
beyond obj->oextra itself. Value 0 means that it is not in use;
it is used to hold a monst.m_id and those are always non-zero.
Delete unused obj->oextra->olong. 'olong' used to be the last
field in struct obj, put there to force alignment of anything
which followed it back when obj structures were over-allocated to
append extra information. It had a comment about being used for
temporary gold but whatever that was, temporary gold was gone long
before obj->oextra got introduced.
Bump EDITLEVEL since this invalidates existing 3.7 save files.
Remove a bunch of tabs from obj.h and save.c.
This turned out to be a lot more work than I anticipated, but it is
definitely simpler (other than having #wizmakemap take achievements
away if you replace the level that contains the 'prize', which wasn't
handled before).
I cheated and made Mine's End into a no-bones level because the new
flagging scheme for luckstone, bag, and amulet can't carry over from
one game to another. It probably should have been no-bones all along.
Sokoban didn't have this issue because it's already no-bones.
Existing save files are invalidated.
If the core frees the obj struct referred by lua, don't free it,
just mark it as OBJ_LUAFREE - lua will free it in gc once all
the references to it are gone.
Whenever a lua script references a core struct obj, increment a counter
in the obj struct. Core code will not free the obj, if there are any
lua references pointing to it, just makes it free-floating.
When lua script ends, the lua gc will free the free-floating objects.
Also exposes u.inventory to lua.
Breaks save and bones compat.
The followup message about the fix for #5056 was trapped by the spam
filter so didn't reach us for a while.
xlogfile has an extra field to track various achievements made during
the game it logs, two of which are fully exploring the gnomish mines
and fully exploring sokoban. Those are accomplished by finding the
special 'prize' item on the final level of their branch: luckstone
for mines and bag of holding or amulet of reflecition for sokoban.
3.6.0 had a bug where any item of the target type found anywhere in
the dungeon resulted in achieving the relevant goal. A post-3.6.1 fix
for that required that the item be found on the end level of the branch
and attempted to require that it an item explicitly placed there by the
special level loader, but the latter aspect had a bug which meant that
random items of the appropriate type placed on final level would count
as the prize. Chance of extra luckstones on mines' end is fairly high,
so potential for false completion of the achievement was also high.
The second complaint was that since the achievement was only recorded
if the special prize item was found on final level, then if a monster
took it to another level then the achievement became impossible. (Not
true, the player could take it back, drop it, and pick it up again, but
that is admittedly a pretty silly hoop to jump through.) On the other
hand, if a monster removed the item before the hero found it, then a
case could be made that the hero hadn't really fully explored the
level. However, this fix records the achievement no matter where the
hero picks up the item. The final level must be entered--otherwise no
monster could possibly acquire and transport the item--but it isn't
guaranteed to have been fully explored. Big deal....
The prize could also be acquired in bones data. Before the second
portion of this fix, that wouldn't have mattered. But now it does, so
clear the prize indicator when saving bones unless it happens to be the
same level where that item is created (impossible for sokoban, where no
bones are left; not sure offhand about mines' end). The former prize
stone or bag or amulet becomes an ordinary one of its type.
This can all be done in a much cleaner fashion once we give up on the
current save file compatability. Putting obj->o_id values into new
context.mines_prize and context.soko_prize, plus a hack to mkobj() to
not reuse those two values if the o_id counter ever wraps back to 0,
would cover most of the details. Adding an achievement tracking flag
to lev_comp's object handling for use by the special level loader
would cover most of the rest.
Adjust the Candelabrum of Invocation's weight when it has candles
attached. This has been a known issue ever since the candelabrum and
candles were introduced.
When the candelabrum burns out, update persistent inventory window to
show that it no longer has candles.
thitu() is mostly used for arrows and darts "thrown" by traps, but
scatter() uses it on items launched by a land mine explosion. Traps
had no need for potion handling, but scattering does. Changing thitu()
to call potionhit() required that more information be passed to the
latter in case killer reason was needed, and thitu()'s callers needed
to be updated since it now might use up its missile (only when that's
a potion, so scatter() is only caller which actually needed to care).
Quite a bit of work--especially the testing--for something which will
never be noticed in actual play. In hindsight, it would have been
much simpler just to make scatter destroy all potions rather than
allow the 1% chance of remaining intact (via obj_resists()), or else
leave any intact ones at the explosion spot instead of launching them.
Bug report was:
> "Completed sokoban" achievement was logged when picking up
> a randomly generated bag of holding in the gnomish mines.
The picking-up code was missing checks for the branches, so
you could get the achievements outside the correct branches.
"Your pair of speed boots glow silver for a moment." should be
"Your pair of speed boots glows silver for a moment.". The fix
reverses a post-3.6.0 change to is_plural(). Also, add new
pair_of() to test for object formatted as "pair of Bars". For verb
usage, that's definitely singular, but for pronoun usage, sometimes
plural seems better (although it might actually be incorrect).
I fixed up the formatting of a block comment in obj.h, but it is
still a candidate for tab cleanup.
Some worthwhile stuff from abandoned 'git stash':
is_plural() macro wasn't comprehensive;
a couple of return values where writing with a magic marker was
causing time to elapse even though nothing happened;
comment formatting for saddle being left in shop by dying steed.
Change the sortloot option to use qsort() instead of naive insertion
sort. After sorting, it reorders the linked list into the sorted
order, so might have some subtle change(s) in behavior since that
wasn't done before.
pickup.c includes some formatting cleanup.
modified:
include/extern.h, hack.h, obj.h
src/do.c, do_wear.c, end.c, invent.c, pickup.c
Two different reports complaining that having the Wizard steal the
hero's quest artifact is a bad thing. This doesn't change that,
but it does make all quest artifacts become equal targets so that
wishing for other roles' artifacts doesn't offer such a safe way to
have whichever special attributes they provide.
Quest artifacts are actually higher priority targets for theft than
the Amulet. I suspect that probably wasn't originally intended,
but I left things that way. Taking quest artifacts leaves the hero
more vulnerable to future thefts, and once they're gone the Amulet
has priority over the invocation tools.
Flesh out wet towels a bit:
1) wielding a wet towel--or a dry one which becomes wet--won't give a
"you begin bashing with your wet towel" message when attacking;
2) if a formerly wet towel dries out completely while wielded, *do* give
"you begin bashing with your towel" on the next attack;
3) successfully hitting with a wet towel no longer always loses wetness;
4) water damage to dry towel always confers at least 1 point of wetness;
5) taking fire damage (via burnarmor() which is used for most types of
fire damage) has a chance to partially or fully dry a wet towel
(regardless of whether it's wielded at the time; applies to monsters
as well as hero; each towel being carried is checked until one is
affected, then any others escape drying.
Not done:
-) attacking with a wielded wet towel perhaps ought to be treated as a
weapon attack using whip skill rather than an augmented arbitrary-
junk-by-weight attack;
-) throwing a wet towel should probably ignore wetness--it's just a wet
piece of cloth when not finishing with a whip snap; right now, it
loses a point of wetness when thrown and usually--#3 above--another
point if it hits...;
-) hitting burning creatures is no different than hitting anything else;
-) likewise for hitting wet creatures.
I did my best to exempt some of the bigger aligned blocks from the reformatting
using the /* clang-format off */ and /* clang-format on */ tags. Probably some
that shouldn't have been formatted were anyway; if you encounter them, please
fix.
The clang-format tags were left in on the basis that it's much easier to prune
those out later than to put them back in, and it means that, modulo my custom
version of clang-format, I should be able to run clang-format on the source tree
again without changing anything, now that Pat has fixed the VA_DECL issues.
flooreffects() covers most dropped/thrown/etc. cases, and the hooks in
invent and mon handle "deathdrops" along with picking up items.
still need to check putting into/removing from containers