Tame earth elemental picked up a no_charge object from a shop and moved
it out of the shop, causing "no_charge obj not inside tended shop"
impossible. Non-tame monsters picking up no_charge items cleared that
bit, so make the same happen for pets.
GitHub issue #1315 points out that it is possible for
a downstream function to change an object's nobj field
to point to a completely different chain.
The cited example by @vultur-cadens was:
for (obj = gi.invent; obj; obj = obj->nobj)
if (obj->oclass != COIN_CLASS && !obj->cursed && !rn2(5)) {
curse(obj);
++buc_changed;
}
curse() drops the weapon with drop_uswapwep(),
which calls dropx(),
which calls dropy(),
which calls dropz(),
which calls place_object().
place_object alters the nobj pointer, to point to the floor chain:
otmp->nobj = fobj;
fobj = otmp;
The result was that the next loop iteration was then using floor
objects from the floor chain.
This alters several for-loops to use a more consistent approach,
particularly when the obj is being handed off to a function,
where a downstream function might, or might not, alter the nobj
field.
References:
https://github.com/NetHack/NetHack/issues/1315https://www.reddit.com/r/nethack/comments/1gkc9ub/even_if_you_drop_an_item_before_drinking_from_the/
Issue reported by ars3niy: non-fireproof water walking boots are
supposed to be destroyed if worn on lava, but a post-3.6 change
made that only happen if the hero died and left bones.
The boots remained intact if hero was fire resistant or survived
6d6 damage. Staying intact should only happen if they're fireproof.
This seems to work but each time lava_effects() gets modified it
becomes more fragile. Having deleted objects stick around doesn't
help with this problem, which is to keep an item which is being
stolen--and whose loss causes the hero to drop into lava--from
being burned up before being transferred to the thief's inventory.
Fixes#1291
Some_Monnam() returns "Someone" or "Something", not "Someone" or "It".
Removing the redundant '&& uchain != NULL' test shouldn't produce any
change in behavior.
Issue reported by Meklon2007: some theft feedback during nymph
attacks refers to the attacker as "she" and others as "it" if hero
is blind.
The "she" references are intentional. However, mixing them with
"it" references when a series of messages occurs is jarring. This
changes "it" to "someone", which is still different from "she" but
hopefully enough less so to be tolerable.
That resulted in monkeys also being referred to as "someone" because
they're classified as humanoid. Change x_monnam()'s AUGMENT_IT
handling, which chooses between "someone" and "something" when the
monster is not seen, to override humanoid for animals (affects 'Y'
class) and for mindless (affects zombies, mummies, and golems).
So an unseen monkey will be "it" again.
The final message for current item was relying on a cached monster
name value. If an unseen nymph or monkey stole a worn blindfold
so that hero's vision was restored: "It <stole> item" before the
changes and "Someone|Something <stole> item" after. So update the
cached name if sight gets regained, to give "<Mon> stole <item>."
(If the item is worn armor and the thief is a nymph, it was and
still is "She stole <item>".)
The message for having any worn item be stolen, which got split
into two parts within the past year, was giving "<Mon> takes off
<alt weapon>". When not dual-wielded, the alternate weapon isn't
really worn. Rather than suppress it outright, change the message
for uwep/uswapwep/uquiver to say "disarms" instead of "takes off".
For accessories, change "takes off" to "removes". Those are more
or less interchangeable these days but "removes" matches R instead
of T.
While testing, my pet evidently killed a nymph (I was blinded and
couldn't see it happen) while she stole my gloves and the next
message I got was "You finish taking off your suit." The gloves
weren't worn anymore so equipname() defaulted to suit. Get rid of
equipname() altogether and switch to armor_simple_name() which
doesn't rely on the worn-armor pointers.
Fixes#1257
If a punished hero's inventory is empty, have a nymph usually take
off the attached chain and indirectly fix punishment. If hero is
trapped by being chained to a buried iron ball, sometimes take off
the implicit chain and indirectly release hero from the trap.
Monkeys won't do this and nymphs will only do so if there is no
inventory (aside from gold and/or embedded dragon scales which they
aren't allowed to target).
It's a lot simpler than I was expecting when I wrote the TODO about
it recently.
lava_effects() item destrunction had the logic for handling Book of
the Dead wrong. (However, that didn't matter since the obj_resists()
check earlier would prevent it from being burned up. Fix it anyway.)
Teleporting due to loss of protection against water or lava isn't
the only way a visible thief might produce "It stole <item>" prior
to the fixup the comment explains.
The late comment about uball and uchain becoming Null was there to
explain why they weren't referenced when inserting the phrase
| (was_punished && !Punished) ? " removed your chain and" : "",
into "<Mon> stole a heavy iron ball." That isn't there anymore so
get rid of the comment.
Yesterday's commit to add a "<Mon> takes off <item>" during theft
of a worn item used uchain instead of uball when the item was uball.
That works as intended when uball is just carried, but if it is also
wielded, alt-wielded, or quivered then the pointers for those weapon
slots weren't updated (because uchain doesn't have the corresponding
owornmask bits set when removal performs unpunish()). Check for that
and call remove_worn_item() again if necessary.
Also, the subsequent "<Mon|She> stole <item>" message was inserting
"removed the chain and" before "stole" when item is uball, but that
isn't needed anymore since the preface message "<Mon> takes off the
iron chain (attached to you)" will have just been given.
When a nymph or monkey successfully steals a worn item from hero,
first the item is unworn, side-effects of that take place (most
noticeably descending when losing levitation or flight) including
feedback about such side-effects, finally "<Mon> steals <item>" and
transfer from invent to thief's minvent. If the side-effects were
fatal (such as drowning or burning up in lava), the player wouldn't
see any explanation for why that happened.
When a thief removes a worn item, give a message to that effect:
"<Mon> takes off your <item>." That will usually be immediately
followed by "She stole <item>." When the thief isn't a nymph or if
any messages were delivered after the "takes off" one, the monster
will be described by name: "<Mon> stole <item>."
Having an item that allowed being in/on water/lava be stolen could
result in the hero teleporting. If the thief wasn't visible from
hero's new location, the message given was "It stole <whatever>."
Save the thief's name/description before removing the item and
potentially dropping hero into trouble and triggering teleport, then
use that in the eventual message.
Adds a new boolean option, accessiblemsg. If on, some game messages
are prefixed with direction or location information, for example:
(west): The newt bites!
(northwest): You find a hidden door.
I added the info to the most common messages, but several are
still missing it.
If a monster picks up an item thrown by the hero, change its 'how_lost'
flag from LOST_THROWN to LOST_STOLEN and pickup_stolen will be used
instead of pickup_thrown to decide whether to override pickup_types
and autopickup exceptions when hero eventually steps on it. If a
monster picks up an item dropped by the hero, change its flag to
LOST_NONE and autopickup will work normally without being overridden
by dropped_nopick. If item is flagged as stolen, leave it that way.
Add pickup_stolen option to autopick items stolen from you by a nymph or
monkey, even if they don't match your normal autopickup settings.
Replace was_dropped, was_thrown with a 2-bit bitfield that can contain
values LOST_DROPPED, LOST_THROWN, and LOST_STOLEN (or 0), since they
should all be mutually exclusive anyway as they track the most recent
way the item left the hero's inventory.
[Rebase/merge conflict fixed up. PR]
"object lost" panic occurred when hero's worn amulet of magical
breathing was stolen. This prevents drown() -> emergency_disrobe()
from dropping an item while in the midst of it being stolen, avoiding
the possibility of it no longer being in inventory when the theft
completes. There may be variations other than drowning that lead to
unwear -> drop-or-destroy that are still vulnerable, and this fix can
potentially cause items to vanish from hangup save files.
It also has a side-effect of not being able to drop levitation boots
to lighten encumbrance enough to crawl out of water if the drowning
occurs while they are being taken off, not just when being stolen,
even though they should be easily droppable in such circumstance. The
hero will just need to drop other things instead.
tinklebear on IRC noticed that a hero paralyzed by a floating eye was
still "charmed" and capable of "removing her armor" as part of a nymph's
theft attack. The same thing was true of foocubus seduction: a
paralyzed hero was still able to respond to the questions about whether
particular pieces of armor should be removed (and also do whatever else
may be involved in a successful attack...).
I think paralysis should prevent both those things. Nymph theft will
still work, unless she needs the hero's active cooperation in removing a
bulky piece of armor. Foocubus attacks will be prevented entirely by
paralysis, making it interfere like unconsciousness already does.
Apply a similar constraint to hero vs monster seduction, as well.
Revise sanity_check to acknowledge that buried objects might be unpaid
or no_charge. (For unpaid, drop shop-owned object in a gap in the
shop wall or in the free spot; for no_charge, drop something the shk
doesn't care about, or drop any hero-owned item and decline to sell.
Dig a pit. Push or drop a boulder to fill the pit.)
Change 'I' to look for unpaid objects on the floor and for buried ones
when deciding when to include 'u' in the list of candidate object
classes and pseudo-classes.
Change 'Iu' to mention buried unpaid objects as well as floor ones.
For both non-invent categories, show a combined count without cost
info.
Have sanity_check of monster inventory test for unpaid and no_charge.
When a monster (including pet) picks up an item that's marked unpaid
(so one dropped on shop boundary, not an ordinary for-sale one), take
it off hero's shopping bill. If dropped--pet behavior or monster
death--inside the shop, it will become for-sale rather than no_charge
or back on bill. [Removal from bill is needed to prevent an unpaid
object ending up outside the shop if a monster carries it out, and
current sanity_check complains about an unpaid item in mon->minvent.]
The consolidation of global variables from scattered source
files into decl.c and declared in decl.h was begun in 3.7.0.
Their placement in common files was done for centralized
initialization and potential re-initialization during a
"play again" scenario.
It wasn't really necessary for all of them to be housed in a
single huge structure to meet the "play again" requirement,
and the single huge structure has been a little unwieldy when
it comes to maintenance.
Following this commit, instead of one single extremely large structure
named 'g' to house all of the relocated global variables, they
are distributed into several ga through gz.
To make things easy for the developer, each variable is placed
into the struct corresponding to the starting letter of the variable.
That way, no lookup is required in order to know which struct houses
a particular variable, it is a simple match to the starting letter
for all the centralized global variables.
A global variable named 'amulets', would be found in ga.
ga.amulets
^ ^
A global varable named 'move', would be found in gm.
gm.moves
^ ^
A global variable named 'val_for_n_or_more' would be found in gv.
gv.val_for_n_or_more
^ ^
A global variable named 'youmonst' would be found in gy.
gy.youmonst
^ ^
Instead of using index() macro defined to strchr, use C99 strchr.
Instead of using rindex() macro defined to strrchr, use C99 strrchr.
If you want to try building on a platform that doesn't offer those
two functions, these are available:
define NOT_C99 /* to make some non-C99 code available */
define NEED_INDEX /* to define a macro for index() */
define NEED_RINDX /* to define a macro for rindex() */
There was a TODO about this; not exactly a great challenge but it feels
like a worthwhile change since the name was misleading. I also updated
the name of the do_intrinsics parameter of extract_from_minvent(worn.c),
since it was in a similar situation (and directly related, since it
controls whether to call update_mon_{in/ex}trinsics).
The pull request included some changes that were neither accidental nor
unintentional, so only a subset of the changes from pull request #869
submitted by klorpa were manually applied.
behaviour -> behavior
speach -> speech
knowlege -> knowledge
incrments -> increments
stethscope -> stethoscope
staiway -> stairway
arifact -> artifact
extracing -> extracting
The uses of "iff" were left alone.
Close#869
Switch to using a macro invocation Verbos(n, s) in place of the
flags.verbose checks.
Provide the mechanics for individual suppression of any of the
existing messages that were considered verbose.
Mechanics only - this code update does not provide any means of
setting the suppression bits.
iflags.verbose = 0
is still a master suppression of all the verbose messages.
iflags.verbose = 1
turns on the verbose messages only for those whose suppression
bit is 0 (not set).
I polymorphed into something wimpy and became overloaded or even
overtaxed so I dropped everything. The status line still showed
overloaded or overtaxed until my next move. That didn't happen in
3.6.x or 3.4.3 but I didn't pursue trying to figure out what caused
this misbehavior.
I wanted to add an encumber_msg() call to freeinv() but that would
cause message sequencing issues. Instead, add a call to it in a
few places where items are leaving hero's inventory, particularly
for the chain of calls for dropping stuff. I've left it off in a
bunch of other potential places.
Also add a few missing (void) casts where the return value of
existing encumber_msg() calls is being ignored.
Move some code that was used to decide whether to call distant_name
or doname into distant_name so that the places which were doing that
don't need to anymore and fewer places can care about whether an
artifact is being found. There were two or three instances of
distant_name maybe being called, based on distance from hero, and
yesterday's artifact livelog change added two or three more and made
all of them override the distance limit for artifacts.
After that change to distant_name, make sure that conditional calls
to it become unconditional--just not displayed for the cases where
!flags.verbose had been excluding them. That way distant_name can
decide whether an item is up close and arrange for xname to find it
if it as an artifact.
Also, implement an old TODO. Wearing the Eyes of the Overworld
extends the distance that an item can be from the hero and still be
considered near anough to be seen "up close" when monsters pick it
up or drop it. The explicit cases were using distu(x,y) <= 5, the
distance of a knight's jump. Each quadrant around the hero is a 2x2
square with the diagonal corner chopped off. The replacement code in
distant_name calculates a value of 6, which is functionally equivalent
since the next value of interest beyond 5 is 8. Wearing the Eyes
(deduced by having Xray vision) extends that threshold an extra step
in addition to overriding blindness and seeing through walls: 15,
a 3x3 square in each quadrant, still with the far diagonal corner (16)
treated as out of range.
Log artifacts found on the floor, or carried by monsters if hero sees
those monsters do something with them. Shown to player via #chronicle
and included in dumplog.
For most cases, finding is based on having the artifact object be
formatted for display. So walking across one won't notice it if pile
size inhibits showing items at its location, even if the artifact is
on top. Taking stuff out of a container won't notice an artifact if a
subset of the contents chosen by class or BUCX filter doesn't include
it unless player has used ':' to look inside. Seeing an artifact be
picked up by a monster (even if the monster itself is unseen) or being
dropped (possibly upon death) will find an artifact even if beyond the
normal range of having it be treated as seen up close. Random treasure
drop items are excluded since they are placed directly on the floor
rather than going into a dying monster's inventory and then dropped
with its other stuff.
Lay groundwork for generating a log event when finding an artifact
on the floor or carried by a monster. This part should not produce
any change in behavior.
Move g.artidisco[] and g.artiexist[] out of the instance_globals
struct back to local within artifact.c. They are both initialized
at the start of a game (and only used in that file) so don't need
to be part of any bulk reinitialization if restart-instead-of-exit
ever gets implemented.
Convert artiexist[] from an array of booleans to an array of structs
containing a pair of bitfields. artiexist[].exists is a direct
replacement for the boolean; artiexist[].found is new but not put to
any significant use yet. If will be used to suppress the future
found-an-artifact event for cases where a more specific event (like
crowning or divine gift as #offer reward) is already produced.
Remove g.via_naming altogether and add an extra argument to oname()
calls to replace it.
Add an extra argument to artifact_exists() calls.
Follow up on some old groundwork. For tty, if the core has designated
a message as 'urgent', override any message suppression taking place
because of ESC typed at the --More-- prompt. Right now, "You die"
messages, feedback about having something stolen, feedback for
"amorous demon" interaction (mainly in case of armor removal), and
exploding a bag of holding are treated as urgent.
The "You die" case is already handled by a hack in top-line handling;
I left that in place so the conversion of 3 or 4 pline("You die.*")
to custompline(URGENT_MESSAGE, "You die.*") was redundant. There
are probably various non-You_die messages which precede done() which
should be marked urgent too.
Other interfaces might want to do something similar. And we ought to
implement MSGTYPE=force or MSGTYPE=urgent to allow players to indicate
other messages that they want have to override suppression. But I'm
not intending to work on either of those. I mainly wanted to force
the magic bag explosion message to be shown since a sequence of "You
put <foo> into <bag>." messages is a likely candidate for --More--ESC.
Teleporting a monster only updated the map. Give a message
so blind players can get the same information.
Making a monster invisible gives the same message, if you
cannot detect invisible.
Several other places where monsters teleported themselves
now also give the same message.
when an unseen monster picks up an item that the hero knows some
things about. That's intentional, but vision is turned off while
engulfed so throwing or dropping something while swallowed always
treated it as being handled by an unseen monster.
If hero is swallowed or held by a monster or poly'd and holding a
monster, behave as it the monster can 'seen' by touch when items are
added to its inventory.
Closes#586
Issue was about being asked what to call a previously seen potion
which has been picked up and thrown by an unseen monster. Hero
shouldn't remember what the item description was. This is a much
more general change than just fixing that. Any item picked up by
an unseen non-tame monster will have all its *known flags cleared
since the hero can't see what that monster does to it. Same if an
item is picked up while seen but then used when unseen.
Unseen pets are excluded from the pick up case--but not the use
case--because they pick up and drop stuff continually and players
would just slaughter them if they caused item information to be
forgotten.
Fixes#493
Post-3.6 change to monster inventory handling could result in hero
remaining mounted on an unsaddled steed (if saddle was removed via
opening magic).
Hero falling out of saddle would fall to the ground and take damage
even if levitating or flying without steed's help after dismount.
Fixes#470
The code for doing this (basically an obj_extract_self() call plus
handling if the object was worn or wielded) was duplicated all over, and
inconsistent - for instance, though all of them updated the monster's
misc_worn_check to indicate it was no longer wearing something in
whatever slot, only one call also set the bit that flags the monster to
consider putting on other gear afterwards.
Under a new function, extract_from_minvent, all this extra handling is
checked in one function, which can simply replace the obj_extract_self
call.
A few callers (such as stealing) have some common code *after* the
object is extracted and some other things happen such as message
printing, such as calling mselftouch if the object was worn
gloves. extract_from_minvent does not handle these cases.