Skip to content

Bumping into unseen peacefuls doesn't anger them#231

Closed
Ardub23 wants to merge 20 commits into
copperwater:10.0-savebreakingfrom
Ardub23:patch-2
Closed

Bumping into unseen peacefuls doesn't anger them#231
Ardub23 wants to merge 20 commits into
copperwater:10.0-savebreakingfrom
Ardub23:patch-2

Conversation

@Ardub23
Copy link
Copy Markdown
Contributor

@Ardub23 Ardub23 commented May 19, 2026

If the hero walked into a creature without attacking, the creature would react as if the hero had attacked violently—but only if the creature was peaceful (not tame), and only if the hero couldn't see them. There is no clear reason for this to occur, given that the hero's action is both innocent and harmless. And it can cause frustration if a strong peaceful creature (such as a quest leader) decides to go invisible or hide.

Now, bumping into an unseen peaceful creature will awaken it without being treated as an attack.

copperwater and others added 20 commits May 8, 2026 08:10
This monster comes from SLASH'EM by way of Hack'EM. I figured that
the existing standard scorpions on the Ranger quest don't actually pose
much of a threat to the player, and there ought to be an intermediate
scorpion-like enemy between them and Scorpius.

There are a few changes from Hack'EM scorpions:
 - They're orange rather than red (small scorpions are red) because when
   the player is fighting both types on the Ranger quest, an easy visual
   shorthand for the more threatening type is a good thing to have. This
   is in line with xNetHack monster color principles anyway.
 - They're faster, with a speed of 18 rather than 15.
 - They have only one claw attack; the other claw attack is moved to the
   third slot, after the sting, and changed to a grapple attack. I did
   that mainly because a poison resistant Ranger would otherwise still
   only treat giant scorpions as larger, higher-HP-and-damage enemies;
   letting them grapple and crush the hero in one of their claws makes
   them tactically different.
 - Scorpions can grow up into giant scorpions; that seems like an
   omission in Hack'EM rather than an intentional choice.

The giant scorpion tile is the same as the SLASH'EM/Hack'EM one.
It seemed like it should be possible to ride a tame giant scorpion into
battle if one has a saddle for it. Giant spiders becoming saddleable is
a side-effect, but one that also makes sense. (Yes, a standard saddle
probably isn't equipped to fit around an arachnid's exoskeleton, but
that gets handwaved just like with other weird body shape creatures like
jabberwocks.)
This is in preparation for a new object which will be made of hard
light. It isn't really intended to take part in the object materials
system where other objects can be made out of it, but some design
thoughts if that ever becomes a thing (and which did inform the numbers
assigned to this material):

    Hard light is a magical construct which can be conjured without that
    much difficulty by intermediately skilled magic users, but which
    does take a lot of effort and skill to form into a useful shape and
    hold it. Typically maintaining one of these constructs takes
    concentration, and an enchantment placed to hold it in its shape
    without concentration will rely on proximity to a living body and
    degrade rapidly without it. Consequently, it's unheard of to find an
    item made of it just lying around, and shopkeepers won't pay well
    for it because they're aware it will disintegrate before they'll be
    able to sell it.

    It's exceedingly lightweight, and strong but not impervious to
    attacks. It's one of the few materials that can hit incorporeal
    beings like shades regardless of its beatitude.

This commit also sets the array size of the various material arrays to
NUM_MATERIAL_TYPES; there's no good reason why they should remain
indefinite-length.
In preparation for Ranger quest story changes. This commit merely
changes the name. For backwards compatibility, searching the
encyclopedia for "Longbow of Diana" will still produce the correct
entry.
This is also an key part of the Ranger quest overhaul, being the
primary weapon they will get as a reward for completing it. Arrows of
light are designed to be very powerful, one-shotting a lot of monsters
with their devastatingly high HP damage, but also very limited in order
to avoid being exploitable. To that end, they're fragile enough to
disintegrate when used or even when dropped (though they can be stolen
or put in containers), and there is a hard cap of 5 on how many arrows
can exist at once.

As of this commit, you can only obtain them by wishing and then only one
at a time, but the plan is to have the Longbow create them upon invoke -
the hard cap therefore serves to prevent the hero from sitting in a
closet, stowing arrows away somewhere the game didn't think to look for
them, and building up a huge stockpile.

I considered implementations that would avoid using a global variable to
track the amount of arrows, but ended up discarding them. The easiest
way to do that would be to make the arrow disintegrate upon simply
leaving the hero's inventory. The "proper" way to do this would be an
obj_no_longer_held or freeinv refactor where those functions become
capable of deleting the object, but then this has to be passed up to all
direct and indirect callers to make them aware of their obj argument
possibly being destroyed, making it quite a big refactor which I didn't
want to undertake. If other hard light objects are ever added, this
should probably be reconsidered, or else they should trigger a
destruction timer in obj_no_longer_held which adds possible timer
headaches but at least would allow the code to assume obj_no_longer_held
still won't outright destroy any objects.

At the same time, I realized that a simple, hacky implementation which
inserts arrow disintegration hooks into common places where the arrow
leaves the hero's inventory (adding to a container, being stolen,
hitting the floor for any reason) would be prone to exploits, because
any method that can get an item out of the inventory some other way
would be used to circumvent the intended limit on light arrows you can
have at one time. Also, it would be odd not to be able to put arrows of
light into a carried container.

The flavor text for when light arrows interact with monsters is
primarily based on how they work in The Legend of Zelda: The Wind Waker.

This commit also slightly modifies the defer_breakwep uhitm code (since
arrows of light now use it alongside glass weapons), adding an
impossible if something sets defer_breakwep but the weapon doesn't
appear to be eligible for breakage, and not setting defer_breakwep on
ordinary non-glass weapons.
This is the key buff to the Longbow, making it the primary source of
arrows of light. The initial idea was to have it top you up with as many
new arrows as the game can allow to exist, but I think it is slightly
better balanced and more strategical if it provides 3 instead (allowing
people to stockpile if they want, but in order to get the most out of a
second invoke, you need to use at least one arrow...)

The old create-regular-arrows effect is still present, occurring when no
arrows of light can be created. I slightly improved these too, since it
was considered a pretty underpowered invoke: now the arrows will match
your race if you're an elf or gnome (not that this matters if you plan
on using the Longbow to fire them) and have their enchantment set to the
Longbow's enchantment, providing an incentive to enchant the Longbow.
Arrows of light will /not/ get free enchantment, since they do enough
damage already.

This also adds a message describing the arrows appearing, since it was
kind of weird to invoke the Longbow and get no feedback except the
addinv message. Unless the inventory was full, but I also changed the
hold_another_object message because the arrows "falling out" of the bow
is kind of weird too.
This is the first Ranger quest change that's directly about the changed
story: Orion's not in the picture because Scorpius slew him.

In his place, calling you to the quest, is his lieutenant, servant and
guide, Cedalion. He is a lesser known but still well-attested figure in
most Orion myths, assigned to guide Orion from atop his shoulder as he
wandered after having his eyes put out.

I kept most of the statblock unchanged on the basis that it's adjusted
for making it tough to kill him to get early entry to the quest, but he
is regular human size instead of MZ_HUGE, because he's not a giant like
Orion is.

I also did not give Cedalion the ability to tear webs that Orion had;
the only quest enemies in here seem to be giants, and again Cedalion
isn't a giant.
Final Longbow buff: make it much better for multishot and therefore
combat in general. Late-game it's very annoying to be facing a crowd of
foes and randomly only fire 1 arrow at them; the swinginess of this
approach makes it harder to justify using a ranged weapon instead of
melee.

Note that it doesn't enable you to multishoot better than you could
otherwise. This minimum takes into account what you would naturally get
as your highest possible multishot, and lowers the floor to that
accordingly.
This is not a significant overhaul since this level was already heavily
modified from the infamous 1-wide labyrinth in xNetHack 3.0. Mostly I
just moved the downstair to the middle of the top/bottom edge, removed
Sirius (due to quest story changes and Orion no longer being the
leader), and changed up the centaur generation a bit.

I also took advantage of the recent feature to block monster spawning in
certain areas and made the central grove a no-spawning area.

One of the friendly hunters was generating on top of iron bars for some
reason; this appeared to be a coordinate error in a previous xNetHack
change to the level, so I adjusted that.
Because I can't help but come up with entirely new algorithms when
implementing the most basic filler levels, I found myself making a
Ranger upper filler level that involved Yet Another Spanning Tree
Algorithm. Since I keep coming up with ideas that involve spanning
trees, I decided to just bite the bullet and make a general-purpose
algorithm and put it in nhlib.lua.

This algorithm is basically a generalization of the one that was in the
wizard1 level, and this commit replaces the wizard1 code with a call to
make_spanning_tree as a proof of concept. There are other places like
the Super Honeycomb themed room (but NOT wizard2) that could be
refactored to use this function, but aren't done in this commit.
The level I replaced in this commit got points for at least being
distinctive for a cavern fill, due to the walls being trees, but once
you got past that it was still just a boring cavern.

As with most quest fillers, this level had randomized stairs implying a
downward traverse (especially out of place in this quest; you're
descending from the sky?) so this fixes one stairway at the middle top
of the map and the other stairway inside one of two caverns. The idea
there is that it's not clear which of the two is the actual Cave of the
Wumpus.

I threw out the cavern fill and replaced it with an algorithm that makes
a spanning tree between various "junction" waypoints on the map,
conveying a better sense of following trails through the forest.
Hopefully this creates a better "exploration" gameplay sense.

A fair bit of code is dedicated to avoiding both inaccessible holes in
the forest and diagonal gaps that would require squeezing or cutting a
tree down.

I added in 1 waiting giant scorpion to the monster loadout on this
level to make it a possibility but not a guarantee that the player will
see one before the lower filler level.
The Ranger quest story isn't among the most poorly differentiated of
them - the ongoing conflict with the centaurs is all right as a reason
for the start level being beseiged - but it did suffer from some things
that made it bland and some things that didn't make sense. (Scorpius is
the mortal enemy of Orion - so why is he sending YOU to kill him while
he sits around in the grove? And why would he ally with centaurs? And
why is he building a palace with a throne he shouldn't physically be
able to occupy anyway?)

The most significant change to the story that drives all the other
changes is that Scorpius has already killed Orion, and Cedalion is
leading the remaining hunters in his stead. Many of these other changes
make the story draw on the mythology of Orion, such as Scorpius being
sent by Gaia after he intended to kill all the beasts on the earth, and
both of them being placed in the sky as constellations afterwards.

During writing the story I decided that the bow cannot create arrows of
light until you successfully kill Scorpius, because the arrows of light
derive directly from Orion's blessing from the stars. (How it still does
this for non-Rangers who wish for the bow is another matter I don't have
the answer to.)

Another experimental change in the story is to make Scorpius entirely
mute, because again, scorpion. I always felt like his dialogue was a
little odd, even if imagining him as a talking animal. So this is an
attempt to see if it'll work with mere descriptive messages instead of
dialogue, within the constraints of the existing system for delivering
those messages - for instance, you still get a big multiline text window
when you first face him, but it's entirely description and threatening
behavior.

The centaur conflict is kept, because I liked the thematic parallels and
gameplay of fighting a lot of enemies who use ranged weapons themselves
and try to keep their distance. I also didn't really change anything
with the Cave of the Wumpus, other than to make references to how the
Wumpus can deliver instant death (it can't yet but will soon). This
level is a wholesale reference to Hunt the Wumpus, including in its
quest text, and I think it works fine as the Ranger locate level.

Due to the nature of quest overhauls, some parts of the changed text
reflect things that are not part of the previous commits and don't exist
yet.
This is intended to be another incremental experiment in Quest
diversity: in all other quests the nemesis hoards the artifact and you
have to get it from them. Here, the artifact is not integral to the
quest story or accomplishing the mission, so there's no reason why
Cedalion can't just give it to you in the hopes it'll help you succeed.

To balance this out, and to align it with the quest story changes, the
bow cannot make light arrows until Scorpius dies.
In line with how many quest artifacts aren't as effective if you've
wished them up as another role, so too is the Longbow. It will summon
one arrow of light per invoke (still maxing out at 5) and the arrows
don't deal as much damage. But multishooting them will still be pretty
devastating. This might be an overnerf, but I'd rather err on that side
rather than possibly overbuffing non-Rangers by letting the Longbow
create the same amount of light arrows for everybody.

Rangers who have the Longbow but have not yet killed Scorpius are
treated the same as non-Rangers for all purposes except acquiring arrows
of light via invoke, which they cannot do until they kill Scorpius.
With the greater focus on scorpions in the Quest, it didn't make sense
to continue to spawn lots of centaurs as time goes on. Scorpions and
other creepy-crawlies are mentioned as emerging out of the earth to
fight, so them popping up makes more thematic sense too. Centaur
presences on levels are better provided by initial generation (primarily
on the first three levels; there will be fewer of them on the late
levels).

Ideally the specific monster to generate most of the time would be a
little stronger than the regular scorpion but not as strong as the giant
scorpion (which I don't want spawning frequently on the home level, for
instance). I suppose I could buff the regular scorpion a bit but I
overall like the balance of the two.
This is partly for giant scorpions, since I imagine no one would even
know they could tame and saddle one otherwise, but now it's
discoverable (especially since a reaction of players to seeing a giant
scorpion may be to use monster lookup on it). Otherwise, it's a nice
small improvement to monster lookup.

I did have to move the logic out of can_saddle into a new saddleable()
function; there's nothing in can_saddle that requires anything besides
the permonst, so I don't know why it requires a struct monst.
Regardless, I felt it was better to leave can_saddle's signature as-is
and not change all its callers.
If the hero walked into a creature without attacking, the creature would react
as if the hero had attacked violently--but only if the creature was peaceful
(not tame), and only if the hero couldn't see them. There is no clear reason
for this to occur, given that the hero's action is both innocent and harmless.
And it can cause frustration if a strong peaceful creature (such as a quest
leader) decides to go invisible or hide.

Now, bumping into an unseen peaceful creature will awaken it without being
treated as an attack.
@copperwater copperwater added the fixed-in-feature-branch Completed on a feature branch, not merged into main yet label May 24, 2026
@copperwater
Copy link
Copy Markdown
Owner

This is now in the master branch and part of the 10.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fixed-in-feature-branch Completed on a feature branch, not merged into main yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants