Commit Graph
100 Commits
Author SHA1 Message Date
Michael Meyer 3653649ed3 Fix: nonadjacent grabber after move
A monster which has grabbed you could move away without becoming unstuck
if it hit the "move and shoot" or "helpless" conditions in the dochug
MMOVE_MOVED case (since those lead to early return or break), leaving
the hero stuck to a monster which is no longer adjacent.  Put the
'grabber moved away -> become unstuck' stuff at the top of the block so
that it will always be evaluated if a grabber has moved.

I would have liked to move the whole "grabber checks" block up, but I
think it'd change behavior to have the u.uswallow attack come before the
early return for a helpless monster, so I split it up instead.
2022-10-08 16:43:45 -07:00
Michael Meyer b80cf6138c Don't hardcode min Str in losestr
Min Str is typically 3 no matter the hero's race, but could be higher
(at least in theory?).  Using ATTRMIN makes losestr respect the same
minimum as other kinds of attribute loss (I'm operating under the
assumption that this wasn't an intentional move to fix the minimum at 3
regardless of other factors).
2022-10-08 16:29:56 -07:00
Michael Meyer 02367077bd Use function for combined str/hp loss from poison
Since losestr and losehp calls go together most of the time, this feels
like it probably makes more sense than repeating the killer name/format
twice in a row all over the place.
2022-10-08 16:29:56 -07:00
Michael Meyer 70fe2ce5cd Don't make callers responsible for losestr death
Remove callers' responsibility to deal with possible hero death when
calling losestr.  This is less fragile and error-prone than leaving it
in the caller's hands, but it means that death from the monster spell
'weaken target' no longer goes through done_in_by, and the death reason
is no longer "killed by <monster name>".
2022-10-08 16:29:55 -07:00
Michael Meyer c0dfa40cd3 Don't use boolean for losehp killer format type
Killer format isn't a boolean, since it has 3 possible values
(KILLED_BY_AN, KILLED_BY, NO_KILLER_PREFIX).  It shouldn't make any
difference behind the scenes, but it's confusing to use 'boolean' for
it.
2022-10-08 16:29:55 -07:00
Michael Meyer 4b32f8b3bd Fix: 'weaken target' spell against poly'd hero...
...could leave hero in creature form with negative u.mh

losestr can subtract HP, but doesn't directly kill its target.  The
caller is responsible for possibly killing the hero if losestr reduces
her HP to 0 or lower; most callers do this by combining losestr with a
losehp call, which can kill off the hero if necessary.

MGC_WEAKEN_YOU calls done_in_by if u.uhp < 1 after losestr, but didn't
handle the Upolyd u.mh case, so could leave a polymorphed hero with
negative health.  Add a rehumanize call in that case.

This could also be done by changing losestr to call losehp itself for
the HP loss it deals out, but this would interfere with
cast_wizard_spell's use of done_in_by to generate the death reason:
either all strength loss is described one way ("terminal frailty" or
something -- not great) or else losestr must be passed a death reason
and is described a different way than other attack spells (because it
wouldn't go through done_in_by).
2022-10-08 16:29:54 -07:00
Michael Meyer c78e7af013 Digestion attack can grant hero intrinsics
Monster purple worms can now gain intrinsics from swallowing foes whole,
so maybe the hero should be able to do so too.  Intrinsics aren't
granted immediately upon swallowing (that would probably have been
easier), but only once a corpse is created and then entirely digested.

I'm not sure if this is too powerful and was being avoided deliberately
for that reason, since it includes potential level gain from wraith
corpses in addition to other intrinsics.  That's consistent with monster
purple worms but may be a bit too much in the hands of the hero, though
it is limited by needing the corpse creation roll to succeed.
2022-10-08 16:06:50 -07:00
Michael Meyer 7caa113cc0 Fix HANGUPHANDLING ifdef for TTY
The SIGHUP handling for the TTY windowport added in 594cb5f was wrapped
in '#ifdef HANGUP_HANDLING', but the actual define is 'HANGUPHANDLING'
without the underscore.
2022-10-04 15:06:32 -07:00
Michael Meyer 44dcf95e04 Fix: X11 extcmd menu heap buffer overflow
Instead of allocating space for ((n + 1) * size) (to make room for all
entries plus terminator), it allocated space for (n * size + 1).
init_extended_commands_popup would therefore write past the end of the
memory allocated for command_list and command_indx when trying to store
their respective terminator entries.  This meant the X11 windowport
would crash when accessing the extended command menu, if NetHack had
been compiled with -fsanitize=address.

I also did some minor cleanup/refactoring to eliminate variables and
lines that were made redundant or useless by 9d64d13, which changed the
way the function worked and removed the need for things like tracking
indices in the source and destination arrays with separate variables.
2022-09-30 08:16:19 -07:00
Michael Meyer 365d728be7 Show genocide prompt help iff 'cmdassist' enabled
The "[type the name]" prompt seems appropriate for handling via
cmdassist, so experienced players who don't need the help can hide it.
I also added a corresponding help note for the class genocide prompt.
2022-09-28 14:47:56 -07:00
Michael Meyer fc7a2a9869 Don't screen out empty input in class genocide
So that a blank line wouldn't use up one of the player's "tries" for
class genocide, the game would continue to prompt until the input was
non-blank (or the user hit <esc>), with a tight loop around the getlin
call that only exited when it got some non-empty input.  This apparently
risked leaving the game endlessly looping under some worst-case-scenario
hangup conditions.  It was also inconsistent with normal genocide, which
doesn't have special handling of blank lines.  Make the class genocide
prompt behave like the normal genocide prompt by removing the "blank
input" loop (and consequently treating a blank line the same way as any
other attempt to write a name).
2022-09-28 14:47:56 -07:00
Michael Meyer d1f4e7df85 Fix: IS_SUBROOM_INDEX range
The macro (currently unused, I think) for checking whether a particular
index designates a subroom was off by one on the maximum allowable
value.

Because of the dedicated extra space for the g.rooms array terminator
flag (hx == -1), subroom indices in g.rooms are set out in the range
[MAXNROFROOMS+1, MAXNROFROOMS*2], inclusive.

Also some minor formatting tweaks.
2022-09-28 14:11:05 -07:00
Michael Meyer 82337beedd Prevent impossible fall dmg if falling up
The way hole destinations work now theoretically allows for a
cross-branch hole or trap door to move you across branches in a way that
decreases your overall depth.  If this happened, it would cause an
impossible when the negative result of (depth(new) - depth(old)) was
used to calculate fall damage.  Limit fall damage to 1d6 if dist <= 0.
2022-09-22 11:36:48 +03:00
Michael Meyer e148d5e925 Apply trap door destination restrictions in dodown
Missed this way to use the trap door (in a block added in 05761ba) in
previous commits, though I'm a little confused about whether that block
in dodown is even reachable given how various trap scenarios are handled
with dotrap earlier in the function.
2022-09-22 11:36:48 +03:00
Michael Meyer 81285b661e Apply dest. limit to monster trap door usage
To prevent monsters from falling past the bottom level or into the
sanctum early, and to maintain consistency between monster and hero hole
usage.
2022-09-22 11:36:48 +03:00
Michael Meyer 9f5b362601 Refine attempt to clamp trap door fall destination
This should prevent anyone from exploiting falling into the sanctum (by
taking advantage of a trap door in a bones file from a differently
laid-out dungeon, as described in the previous commit) to bypass the
invocation, in addition to falling past the actual end of the dungeon.
2022-09-22 11:36:48 +03:00
Michael Meyer 1830b206c7 Prevent hero from falling past end of dungeon
Similar story with saved trap door destinations: if a bones file near
the end of the dungeon came from a longer dungeon (i.e. with a
lower-depth castle) than the one the bones file is loaded into, the
trap door destination could be past the dungeon end.  Clamp the
destination so it won't be lower than the bottom level of the dungeon.
2022-09-22 11:36:48 +03:00
Michael Meyer 9bb09d48f1 Have monsters' hole destination match the hero's
The fixed destination of a hole or trap door was being used for the hero
but not for monsters.  Make everyone land in the same place, so you can
chase a monster into a hole and actually find it.
2022-09-22 11:36:48 +03:00
Michael Meyer f8ec9dc32e Fix: antigravity trap doors
Trap doors saved their destinations as an absolute level, rather than a
relative one, so if you loaded bones from a special level their
destinations would reflect the dungeon layout from the bones player's
game.  For example, die on the Oracle level, on dlvl5, with a trap door
that goes to dlvl6.  Another player gets those bones on their Oracle
level, which is dlvl8... the trap door would still go to dlvl6.  Pretty
amazing trap door -- something you might see in a funhouse!

Include relative rather than absolute destinations in save and bones
files, much like stairs do, to avoid this problem.

I bumped EDITLEVEL because although this won't break save files in an
obvious way, it will interpret the (absolute) destinations in existing
save and bones files as relative, leading to some crazy long falls. :)
2022-09-22 11:36:47 +03:00
Michael Meyer 951a99f5e6 Fix: starving herbivore pet vs polymorphing corpse
The special handling of polymorphing corpses included an "is acceptable
food if starving" rule which ignored the pet's other food preferences,
so a starving herbivorous pet would become willing to eat a
non-vegetarian corpse iff the corpse would polymorph it when eaten.
Along the same lines but latent: if there were a vegan polymorphing
corpse, a carnivorous pet would eat it not only if starving, but also if
maltreated and on the verge of becoming feral.

Instead of trying to fix this by reimplementing all the herbi vs carni
rules specifically for polymorphing corpses, just have a "don't eat
polymorphing corpses if neither starving nor almost untame" rule, and
fall back to the normal palatable corpses tests once it's been
determined that the pet is willing to eat even a polymorphing corpse.

I rephrased the comment just to make it negative (about avoiding
polymorph, rather than polymorph being OK under certain circumstances)
to match the new form of the rule.
2022-09-20 17:25:18 -07:00
Michael Meyer 34aabca74b Describe engulf attacks a bit more consistently
Use verbiage for mon vs mon and hero (mostly hero) engulf attacks that
matches recent changes to monster vs hero engulf attacks more closely
(e.g. "swallows whole" instead of "engulfs" for purple worm, other
changes in b07fe59...).  Also ensure non-AD_DGST engulf attacks
(e.g. from revamped trapper or lurker above polyforms) aren't treated as
"eating" (or as involving "debris").

Also change the enfolds and digests macros so they produce booleans
rather than attack pointers (I got a compiler warning about casting
struct attack * to boolean when I did 'boolean b = digests(ptr);').
2022-09-20 16:54:23 -07:00
Michael Meyer 74704c8836 Improve description of invisible mon revival
An invisible monster reviving would be called "it" (as in, "It rises
from the dead!").  Improve on this a bit by instead saying that "the
troll corpse disappears!" (similar to the messaging used when undead
turning is used on an invisible monster's corpse), or calling the
revived monster "something" (as in "something escapes from a sack!")
instead of "it".  Distinguish between the original location of the
corpse and the location of the revived monster when describing seeing
things that have happened to the corpse, since revival may not place it
on the corpse's location.
2022-09-20 13:51:37 -07:00
Michael Meyer 7e96026b44 Fix: impossible from splitting named stack on bill
Trying to split an unpaid stack of named items in a shop, with
perm_invent enabled, would cause an impossible 'unpaid_cost: object
wasn't on any bill' because copy_oextra -> oname triggered an inventory
update while the newly created split stack was marked unpaid but before
the billing information had been split to match.  Defer the copy_oextra
call until the billing info has already been split.
2022-09-19 18:44:42 -07:00
Michael Meyer 51d568319b Use const char * for read_simplemail 'mbox' param
Nothing about read_simplemail is incompatible with using const, and the
lack of const required some contortions (copying ADMIN_SERVER_MSG to
another buffer with nonconst() to prevent a compiler warning).

This was the last place nonconst() was used, so I removed it.
2022-09-01 17:02:30 +03:00
Michael Meyer b18d768b26 Some minor read_simplemail improvements
Make admin message use urgent_pline so it's less likely to be skipped
and inadvertently missed, make ending punctuation conditional on message
itself not containing any (similar to what's done for T-shirt messages
in read.c), guard against printing an empty message (from a line like
"name:\n"; it does mean that subsequent messages in a single batch will
be discarded, but that's true of the existing guard against malformed
lines as well, and it should make the overwriting of characters past the
'msg' ptr safer).
2022-09-01 17:02:30 +03:00
Michael Meyer 93842fbb1b Fix: overwriting stairs in movement tests
Like some of the other coordinates in testmove.lua (addressed in
70008fc), the attempt to overwrite the stairs was targeting a spot
one space to the left of the actual position of the stairs, causing it
to have no effect (discussion suggested this may have been a result of
99715e0).  Update it so the stairs are properly erased and won't
interfere with movement tests by stopping a running/rushing hero early.
2022-08-31 18:24:26 +03:00
Michael Meyer a345fc8dfb Fix: levelport by name to unconnected branch
(unconnected to the current dungeon branch, that is)

Level teleporting allows you to type in the name of a level instead of
its number.  This normally only works for levels within your current
dungeon branch (main dungeon <-> Gehennom levelports are the exception):
entering "medusa" as a destination won't work while the hero is in the
Gnomish Mines, but it will work fine to get to the Medusa level from
elsewhere in the main dungeon.

Teleporting to a particular branch entrance didn't apply the same
restriction.  The teleport would still happen even if the destination
branch was unreachable from the current branch, and in such a case the
game would just try to get the hero to the depth of the branch entrance,
within the current branch.  For example, entering "quest" as a
destination within the Gnomish Mines would bring the hero to Mines' End,
since that's the closest depth-wise it's possible to get to the quest
portal level.  Apply the same rules to branch entrances as exist for
named levels, excluding destinations that are unreachable from the
current branch.
2022-08-28 15:33:47 -07:00
Michael Meyer fe04b4a632 Move 'major events' section in dumplog
The sections of the dumplog can be broadly organized into two
categories: 'current state' and 'game overview'.  Current state includes
information about what exactly was happening when the game ended: the
map, recent messages, current inventory, and current attributes.  Game
overview is more like a history of the game up to that point: vanquished
monsters, extinct species, conducts, and dungeon overview.

All the current state sections are listed first, followed by the game
overview sections -- I'm not sure if this was a deliberate move to break
the dumplog into two distinct 'chapters', but it's convenient for
readers who may only want to know the circumstances of a death without
seeing the nitty-gritty details of the entire game up to that point.

The one section that wasn't ordered with its category was major events,
which was positioned near the top of the 'current state' group, above
the inventory listing.  This commit moves it into the 'game overview'
group.  I put it at the top, since it can serve as a sort of summary of
the game for those who are interested but don't care about some of the
details of monsters killed, etc.
2022-08-28 14:32:47 -07:00
Michael Meyer e05f326d1c Add makesingular to test_src
There are already pretty solid tests of makeplural, so add some in the
other direction, since it's similarly complicated and has to implement
many of the same special cases and exceptions in the other direction.  I
originally tried just running the makeplural tests backwards to this
end, but several of them are tests to guarantee already-plural words
aren't further pluralized, so are not reversible.
2022-08-26 18:08:37 +03:00
Michael Meyer 3f3f530e43 Fix: test_src -eaux plurals
These plurals (e.g. "gateau" -> "gateaux") were added to makeplural and
makesingular in 0c0262e, so the test was outdated and failed.  I also
added another test for "Federal Bureau of Investigation", since 'bureau'
is an exception to the -eau rule (pluralizes as 'bureaus') and the
exception was originally implemented in a way that would have caused the
"Federal Bureau of Investigation" test to fail -- so it seems like a
good pitfall to test for.
2022-08-26 18:08:37 +03:00
Michael Meyer 70008fc684 Fix: movement tests
Movement tests weren't working because terrain was being positioned one
square to the left of where it was expected, and the error message
printed something other than the expected coordinates.

I wasn't able to figure out why they were like this in the first place
(referring to one spot to the left of the hero with <u.ux-2, u.uy>), so
it's quite possible that I am missing some context here, but the test
failed consistently for me before making these changes, and now works.
2022-08-26 18:08:37 +03:00
Michael Meyer 719a85f37c Allow lua test files to call error()
Enable 'debugging' function calls, including error(), from the lua files
called by the wizard-mode #wizloadlua command.  Without enabling them,
calling error() still produces an error but with a message like
"attempt to call a nil value (global 'error')" instead of the one
specified in the lua file.

I think this is the right way to do this without just enabling
everything across the board (which I assume would contradict the goals
of NHL_SANDBOX), but I will admit to being a little confused by trying
to understand exactly how the sandbox permissions work, so it's possible
this isn't the right solution.

Incidentally, I am probably misunderstanding this, but considering a lua
error still occurs when error() is called, just with a different error
message, is the function really "disabled" successfully by NHL_SANDBOX?
2022-08-26 18:08:37 +03:00
Michael Meyer cee6c9a919 Fix: engulf/digest intrinsic granting
Engulfing pets were getting a double chance to get an intrinsic from a
digestion attack, because they got the mon_givit call in mhitm_ad_dgst
and then also the one in mdamagem.

There is a bit of inconsistency here, in that mhitm_ad_dgst requires
corpse creation to grant nutrition, but the non-nutrition effects of
eating a corpse like polymorph, extra health, etc, in mdamagem don't
have any such requirement.  As a result, one of the mon_givit calls
required a corpse to be "created" before granting an intrinsic, and the
other didn't.   In choosing which one to remove, I figured intrinsic
granting is probably closer to those special effects than providing
nutrition (and also putting it in mhitm_ad_dgst is not ideal w/r/t
message ordering: it causes the 'intrinsic granted' message to appear
before the monster kill message).
2022-08-23 18:34:22 -07:00
Michael Meyer 66e98e1344 Don't describe sleep explosion as a "ray"
When breaking a wand of sleep, don't print the message "the sleep ray
hits you!" since it produces an area effect/explosion rather than a ray.
For a couple other wands, !ordinary (wand breakage) effects don't
produce a message (I assume because the do_break_wand feedback is
considered sufficient), but I put in an alternative message for the
explosion since I think it's important to inform the player the hero has
fallen asleep.
2022-08-18 15:57:53 -04:00
Michael Meyer 8a549b0a60 Shopkeepers hold a grudge against past thieves
When you steal from a shop, its shopkeeper will remember you as a thief
and charge you higher prices in the future (as well as be more curt and
less polite in interactions with you, though not outright hostile) even
if you pacify them, or die on the level and revisit it later as a bones
file.  This was an idea aosdict had, and I think it makes sense that a
shopkeeper doesn't forgive and forget, immediately returning to treating
you exactly like anyone else, just because you were terrorized into
paying her back.  Paying a shopkeeper off may cause her to stop actively
attacking you, but it feels like she'd have her eye on you as a known
thief going forward (and maybe would hang up a sign with your picture,
saying something like "DO NOT ACCEPT CHECKS FROM THIS HERO").

This surchage already existed, but since it was tied to active anger
(which typically causes a shopkeeper to quickly abandon their shop to
follow you) it was somewhat rare to see it in action.

I did not implement it here, but one possible further tweak might be to
clear the surcharge if the shopkeeper is pacified via taming magic
(which more-or-less magically brainwashes the target to feel positively
towards the hero) but not if you simply pay your debts.
2022-08-10 20:02:33 +03:00
Michael Meyer 94e8141c01 Fix: lookaround trap detection
Whether a trap exists is independent on the underlying terrain type, so
putting a check for traps in a block structured like

| if (IS_ROCK(levl[x][y].typ) || levl[x][y].typ == ROOM)
|     ; /* do nothing */
| else if (levl[x][y].typ == CORR)
|     do_corridor();
| else if ((trap = t_at(x, y)))
|     avoid_trap(trap);

would mean that the check for traps only happens on terrain other than
normal room and corridor spots.  As a result, it wasn't being evaluated
in most places where traps might actually occur.

Move the test for traps outside of the terrain type evaluation if/else
series, so that it happens independent of terrain (and remove the
'continue' so it doesn't preclue evaluation of the terrain).

Once the rule actually started coming into play, it became clear the
avoid_moving_on_trap message was being printed in cases where the hero
didn't actually stop (i.e. shift-dir runmode, the "if you must" case),
so I also modified the value for that parameter so it will match the
situations where the hero stops running.
2022-08-10 20:01:22 +03:00
Michael Meyer ce0107aff9 Restore old behavior for running onto trap
The refactor of domove made it impossible to run onto a trap (or water,
if blind), even in the shift-dir mode where the hero is meant to stop
only upon "hitting a wall or running into something".  I use this
runmode to sprint large distances across the map, and the change to this
behavior meant that it was no longer possible to press shift-dir again
to continue past the trap.  This restores the old behavior of allowing
shift-dir running to carry you onto a trap (though the hero will still
stop before hitting a trap in less breakneck runmodes).
2022-08-10 20:01:22 +03:00
Michael Meyer 9d28a8dc76 Update lit corridor display if dark_room toggled
The dark_room option determines whether remembered but unseen waslit
corridor spaces are displayed with S_litcorr or not.  When it is
disabled, a remembered permanently-lit corridor spot will be shown
as "lit corridor" when out of sight.  When it is enabled,
corridors are only shown as lit if they are currently in view.

Toggling this option was not immediately refreshing how corridors on the
map were displayed: an unseen spot shown as a lit corridor because
dark_room was disabled would continue to be shown as a lit corridor
when it was toggled on, until the hero's memory was refreshed by
visiting the spot and then leaving.

Slightly extend the existing function for updating how room spaces are
displayed when dark_room is toggled so that it will update the glyph
used for unseen lit corridors in a similar way.
2022-08-10 19:59:44 +03:00
Michael Meyer c2393344b7 Don't show corridors as lit in #terrain
Because back_to_glyph assumes the hero can directly see the spot, when
used for #terrain (e.g. when a spot was covered by a remembered object)
it would display corridors as lit if lit_corridor was enabled.  Instead
of trying to suppress back_to_glyph's S_litcorr result only under
circumstances where it would be unusual, just show all corridor spots
with S_corr, so that none of them appear as "lit corridor".  This
is consistent with what is already done for room spots for #terrain
(S_darkroom is forced to the basic S_room across the board).
2022-08-10 19:59:44 +03:00
Michael Meyer ddce73502e Improve feedback for trying to bribe the watch
Members of the watch can never be bribed, no matter how much gold is
thrown at them, but when a bribe was attempted they would say "that's
not enough" (implying incorrectly some higher amount would be enough to
pacify them).  Also, an already-peaceful mercenary would take on an
unusually aggressive tone when given any amount of gold, giving the
player the same message to "beat it" as when a bribe succeeds in
pacifying them.

Adjust the mercenary bribery code a bit so that a more friendly message
is given if the monster is already peaceful, and so that unbribeable
monsters don't imply they are just not being given enough gold.  I think
the actual effects of bribery shouldn't be affected by this commit, just
the messages/feedback.
2022-08-10 19:57:48 +03:00
Michael Meyer beb99c0e72 Describe engulf attack by animal as "swallowing"
Suggested by aosdict: instead of describing all gulp attacks as
"engulfing you", say "The <monster> swallows you whole" for purple worms
(or any other animal engulfer) to visibly differentiate between
engulfing and swallowing.
2022-08-10 19:56:53 +03:00
Michael Meyer 9c9a8ff797 Fix: m-prefix looting a container
Using #loot with the 'm' prefix would claim there was nothing to loot
even if the hero was standing on a box, as long as there was no adjacent
monster.  'm' prefix is an explicit request to select a direction so
make it work regardless of whether a monster is there.  Once I did that
I noticed that it was providing no feedback for using '.' or '>' as the
direction if no container was available, so adjust that to give the
"there is nothing here to loot" feedback.
2022-08-10 19:55:42 +03:00
Michael Meyer 2b51a22c6c Fix: command counts greater than 2
Entering a count to repeat an action stopped working for counts greater
than 2 after 93db2a8: the unconditional call to reset_cmd_vars at the
top of rhack was resetting many more variables than had previously been
cleared at that point, including g.multi (which in this context tracks
how many more times the requested action should be repeated).  As a
result any count would perform the requested action twice at most.
Reduce the list of variables zeroed out at the start of rhack back to
what it was before 93db2a8.
2022-08-06 16:42:17 +03:00
Michael Meyer 76d9d65884 Fix: get_count and altmeta
M-<key> shortcuts with altmeta enabled weren't working when preceded by
a count (e.g. 2 M-j for "jump twice"): g.program_state.getting_a_command
determined whether <esc> should be read as staring a potential meta key
combination, and was being reset by readchar on the first digit entered
without being reactivated for subsequent input.  As a result, by the
time the player entered the actual command to be modified by the count,
readchar wasn't bothering to look for M-<key> sequences.
2022-08-06 16:42:17 +03:00
Michael Meyer fec7c724a3 More Guidebook formatting 2022-08-04 09:01:19 +03:00
Michael Meyer adf451e421 Guidebook fixes/formatting 2022-08-03 16:42:11 +03:00
Michael Meyer a18859ddb5 Let fleeing monsters dig pits in undiggable floor
When the hero zaps a wand of digging down in an undiggable level, it
creates a pit.  When a fleeing monster did the same thing, it had no
effect.  Bring this closer to the behavior experienced by the hero: if a
monster tries to use a wand of digging to create a hole in an undiggable
floor, a pit will be made (and the monster will fall into it, if not a
flyer).
2022-07-29 15:05:55 -07:00
Michael Meyer 47a35ba8a7 Another getpos cmap followup
Hot on the heels of my previous commit, here's a way to do it without
any assumptions about the order of defsyms.
2022-07-23 17:04:12 -07:00
Michael Meyer e9fb226dbf getpos cmap vs glyph followup
This is a bit more efficient, since everything up to S_hcdoor is
skipped anyway, but it's a little harder to understand so needs more
comments.  Not sure if it's worth it or not...
2022-07-23 17:04:12 -07:00
Michael Meyer 8fe02be5ae Fix: getpos cmap vs typ/glyph confusion
When some parts of getpos were rearranged in 7404597, tests of terrain
types and glyphs were moved to a loop which iterated through the defsyms
array without being updated to handle cmap values instead.  Consequently
they weren't excluding certain terrain types from being 'jumped to' as
intended.  (Though it seems as though they actually worked by chance to
some extent, just because there's some overlap between terrain types and
defsyms in terms of where the 'walls/doors' blocks start and end.)

I also noticed that cmap_to_type was missing S_darkroom (it fell through
to the default case so that the function returned STONE), so I added it.
2022-07-23 17:04:12 -07:00
Michael Meyer ac0d6a98ce Prevent amorphous mon from carrying hero into door
An amorphous engulfer like a fog cloud could engulf the hero, then carry
him into a closed door.  If it was killed or decided to spit out the
hero, he would be left occupying the same spot as a closed/locked door.
Make an amorphous monster unable to move into a door if currently
engulfing the hero.

Something more complicated could be done along the lines of allowing the
move if the hero is himself in an amorphous polyform, but that verges on
being a little too silly, maybe.

I also included fixes to a couple miscellaneous, unrelated formatting
issues that I noticed recently.
2022-07-22 14:38:14 -07:00
Michael Meyer cc46da90e0 Fix #812: recovered stair dlevel
Stair dlevels weren't being restored with the correct values when
recovered after the game crashed, apparently because they weren't being
reset back to their 'absolute' level from a 'relative' level.  I'm not
totally sure of why this affected only recovered games (maybe that's the
only time when the 'relative' stair values are used?) but this fix seems
to work.

Fixes #812
2022-07-17 16:12:39 -07:00
Michael Meyer 0c517679c4 Silence some -Wunused-but-set-variable warnings
If NH_DEVEL_STATUS was set to NH_STATUS_RELEASED or NetHack was compiled
without DEBUG defined, the 'vlen' variable in a couple pline.c functions
wasn't used.  This could trigger compiler warnings.
2022-07-16 00:15:29 -04:00
Michael Meyer 3e38c720ad Don't describe 'more info' prompt in #glance help
When using #glance, the player is never prompted about whether she wants
'more info' about something on the map, even if flags.help is true and
she has pressed '.' -- the 'more info' prompt is exclusive to #whatis.
getpos_help already changed its description of '.' based on whether
'help' was on or off; adjust those criteria so that the description of
the 'more info' prompt is only included for #whatis, where it is
actually relevant.

I recently looked at the help while using #glance and got confused
about why the 'more info' prompt was never appearing, so hopefully this
should help forestall that sort of thing.  #glance also prompts only
once, so there's some other information about "moving to another spot"
in the help text which is not relevant -- that could definitely be
addressed as well but I think it's less likely to be confusing, so I
didn't bother with it in this commit.
2022-07-03 17:32:38 -07:00
Michael Meyer 59cf69085a Fix: non-swimming pets eating underwater food
Commit 32234b1d in 2003 mentioned in its commit message that pet dragons
shouldn't be able to eat underwater food items.  This was mostly true:
non-swimming pets wouldn't select underwater food as a goal, and
wouldn't spend an action eating something unreachable on their current
position.  But the "combined eat and move" case in dog_move didn't check
could_reach_item, so if a non-swimming pet happened to move to a spot
with underwater food for some reason, they could eat it on that turn
anyway.  This commit should close this loophole and prevent non-swimming
monsters from eating underwater food (or other unreachable food) even if
they happen to fly over its position.
2022-07-03 17:08:25 -07:00
Michael Meyer d5232c7693 allow_category: honor 'goldX' more consistently
A comment in allow_category states that if gold is explicitly selected
as a category, it should be included in the results regardless of what
other BUCX filters may have also been applied.  That makes sense to me:
there's only one thing in the gold category, and it always has the same
BUCX status, so it's pointless to try to "filter" the gold category with
a BUCX filter.  Considering it a "also add gold, on top of the filtered
results" category adds utility.

However, other categories which may include gold (specifically
justpicked; unpaid is in the code too, but that can't actually happen
in-game) were treated the same way: if the category included gold, no
filter could exclude it.  As a result, if the hero had just picked up
gold, 'P'+'C', 'P'+'U', 'P'+'X', and 'P'+'B' all showed the just-picked
gold pieces -- there was no way to filter justpicked to exclude gold
the BUCX categories.  This approach made less sense to me: justpicked as
a category may include gold, but filtering by BUCX actually has utility
there, and selecting it doesn't carry a "show me gold in addition to the
other filtered items" implication.

Maintain the same special treatment of selecting the coins category, but
drop it for justpicked and unpaid.  In those cases whether gold is
listed in the justpicked result will depend on it not being filtered out
by the selected BUCX categories (and which one it belongs to, in turn,
depends on the 'goldX' option).
2022-07-03 16:52:06 -07:00
Michael Meyer 7a008b62b7 Permit gold to be included in justpicked typeinv
Just-picked-up gold was included in the list of items in the just-picked
category for most category-based menus like 'D' or #loot, but special
handling of gold for 'I'/#inventtype (to accomodate the 'goldX' option)
caused it to be excluded from consideration as a just-picked item.
Include recently picked up gold in 'P'/justpicked when doing type
inventory, consist with other category-menu-based actions.
2022-07-03 16:52:06 -07:00
Michael Meyer 1ee9e6ae3d wizmgender: include corpstat gender in object name
Add another use to wizmgender: when it is enabled, include the gender
specified in corpstat flags in the name of a statue, corpse, or
figurine, since it can influence various things but otherwise remains
invisible (for monsters without gendered names).  A little while ago
lichen corpses weren't stacking because, despite being a neuter monster,
the corpses they produced were being flagged as female or male; this
could be useful for debugging issues along those lines.
2022-07-03 16:34:29 -07:00
Michael Meyer 406faad879 Get wizmgender working again
The wizard-mode option to highlight female monsters stopped having any
in-game effect after cb0c21e.  Formerly it caused female monsters to be
highlighted with a red background (red color + inverse); this commit
uses inverse video only without overriding their color.  Ensuring the
color override works consistently with the ENHANCED_SYMBOLS 24-bit color
doesn't seem worth it for what is a very niche debugging option, and I
think inverse video should probably suffice.

It also used to be a TTY-only option, but this enables it in curses as
well.
2022-07-03 16:34:28 -07:00
Michael Meyer ee002ee91e Don't prompt to continue eating with one bite left
There was already handling in place to prevent showing the "continue
eating?" prompt for one-gulp food (like a wraith corpse), since the hero
would finish eating the food on that turn regardless of what the player
answered to the prompt.  Resuming an interrupted multi-bite meal with
only a single bite remaining had the same problem, but wasn't accounted
for in the special "one gulp" handling.  Modify the condition so it
checks for the number of bites remaining in the food, not the number of
bites total, and show the prompt only when there's more than one bite
left.
2022-07-02 15:27:49 -07:00
Michael Meyer 6d222e88b0 Allow travel on water with IDed water walking
If you have a known source of water walking (i.e. are wearing formally
IDed water walking boots), allow travel to path you over water and allow
running over water.  A transition from land to water will still cause
the hero to stop in modes other than the shift+dir "move until you hit
something" running mode, so that you don't careen across the entire
level unless you really want to.

Also, fix running over water when levitation or flying is equipped.
This stopped working after f88dce6970, only allowing the hero to move
one square at a time.  And prevent travel from pathing the hero into a
wall of water even if flying or levitation is equipped, since they don't
allow you to bypass that terrain.
2022-07-02 15:10:54 -07:00
Michael Meyer 141b568944 Make monsters trigger landmines based on weight
The 1/3 likelihood of a monster setting off a landmine seemed a little
arbitrary to me, especially in that it applied equally to all monsters,
from giants to insects.  Change the flat 33% chance to one based on the
monster's body weight, so that lightweight monsters have little to no
chance of setting off a mine, with the likelihood increasing from there
with the monster's weight.

With a trigger weight of 400, as it is in this commit, a dingo has a 0%
chance of setting off a landmine, a gelatinous cube the same 33% chance
as before, an elf a 50% chance, a human a 72% chance, and something the
size of a dragon (ignoring the reduced likelihood for flying monsters) a
91% chance.
2022-07-02 15:02:32 -07:00
Michael Meyer 721c4b77aa Fix: running through quest expulsion
If a player was in the process of running past the quest leader when she
got expelled from the quest, she would continue running out of the quest
portal on the portal level.  Interrupt any running (or other multi-turn
action) when expelling the hero from the quest level.
2022-06-29 18:17:07 -07:00
Michael Meyer 0eadf8dfe1 Allow intrinsic gain from pet's digestion attack
Add possible pet intrinsic gain from swallowing a monster in one gulp
(in situations where a corpse is created and eaten by the engulfer),
making it equivalent in this regard to eating the corpse off the floor.

One possible extension or modification would be to reduce the chance of
receiving an intrinsic when the corpse is consumed via digestion attack,
similar to how the corpse nutrition is 50% of its normal value.  I
didn't incorporate that into this commit since the chance of receiving
an intrinsic is tied to monster level rather than nutrition, so I wasn't
sure if it made sense.
2022-06-29 17:40:46 -07:00
Michael Meyer bc2427167a Fix: vampire shapeshifting in a door
Someone mentioned in #nethack today that a vampire had turned into a fog
cloud, moved under a door, then turned back into a vampire while still
sharing a space with a closed door.  There already existed some code
intended to prevent this in cases where the vampire is killed in one
form and revives in another, but voluntary transformations (from
decide_to_shapeshift) weren't included.  The existing code in mondead
and vamp_stone also apparently missed a minor edge case: because the
code between the definition of in_door and its use included an expels
call, it would be outdated/incorrect in cases where expels() placed the
fog cloud onto a closed door.
2022-06-08 20:23:24 -04:00
Michael Meyer fd3f50ebba Reset justpicked only when picking up items
With reset_justpicked called unconditionally near the top of pickup, it
was impossible to pick up some items, walk over to a chest, and use 'P'
to deposit the items with autopickup on: pickup is called with every
move, and autopickup allowed execution to reach the reset_justpicked
call whenever the hero stepped on a square with an item in it.  As a
result, stepping onto a square with a container would clear all the
justpicked flags in inventory (pressing ',' and then declining to pick
anything up would have a similar effect).

Instead, call reset_justpicked only when the hero (or autopickup) has
actually selected an item to pick up.  This makes the code a bit more
complicated than before -- I don't think there's a way to do it with
just one reset_justpicked call any more, due to the structure of pickup
and the need to call reset_justpicked before actually putting any items
into inventory -- but it means that justpicked info will be much less
ephemeral and more useful when managing stashes, etc.
2022-06-03 12:48:38 -07:00
Michael Meyer 092e8c37fd Fix: wished-for doors in wizmode always vertical
Wishing for a door is intended to retain the existing 'horizontal' value
of the surrounding wall or door (see comment in the wizterrainwish
'door' case).  However, the field was being reset by mistake, causing
all door wishes to create vertical doors.  Preserve it as intended.
2022-06-03 15:17:03 -04:00
Michael Meyer fd55dfba1f Fix: segfault on wizmode terrain wish
The new livelogging of wish results caused a segfault when attempting to
handle the results of a wizard mode terrain wish, since a successful
terrain wish returns a nonzero obj which nonetheless is just a dummy
object.  Move the existing check for that further up to skip all the
livelogging stuff entirely, since such wishes will never happen in a
real game and exist purely for debugging purposes.
2022-06-03 14:53:57 -04:00
Michael Meyer 991e739af4 Fix: loot regression, auto-select with justpicked
When using 'A'/autopick with the 'items you just picked up' category,
instead of autoselecting all items within that category, it selected
every item in your inventory (like it used to work before 3.7).  Just
blew up a bag of holding because of this.

While testing the fix for that, I noticed 'P' wasn't working at all
with menustyle:traditional -- you could select it as a filter, but it
didn't actually get applied to anything, so it would end up prompting
you for every item in inventory.  Fix both those things.
2022-05-28 16:56:25 -07:00
Michael Meyer 4e3812b5e4 Fix: mdisplacem stoning and gloves
Apparently this is a bug that's existed since mon-vs-mon displacement
was introduced in 2003 (in 89c785e): if a monster displaced a footrice,
having gloves on would make it vulnerable to being stoned, while having
bare hands would protect it.  Switch it around so wearing gloves blocks
petrification, as it does under other circumstances.

Also add a message explaining why the displacing monster was stoned (if
the displacement attempt is visible to the hero), so the "Foo turns to
stone!" message has some context.
2022-05-27 15:58:12 -04:00
Michael Meyer 66c70eb453 Fix: invisible pudding globs
When a pudding was killed by a monster (player-caused deaths were exempt
because of a 'backup' newsym call in xkilled), and the resulting glob
ended up on the pudding's square (whether because there were no adjacent
globs, or because the adjacent glob merged into the new one rather than
vice-versa), the glob wouldn't be drawn onto the map until the squre was
redrawn with ^R or similar.  This was because the early return for globs
in make_corpse skipped the typical newsym call near the end of the
function.

In this commit I just added a newsym call to the glob case in
make_corpse, but adding a newsym call to monkilled as a guard against
similar cases (equivalent to the one in xkilled) seems like a possible
extension.  I wasn't sure if there's a particular reason it's not
included in monkilled, so I didn't mess with it.
2022-05-25 12:34:59 -07:00
Michael Meyer 0c0262eab0 Handle -eaux plurals in makeplural/makesingular
I noticed a comment about -eau pluralizing as -eaux, e.g. "gateau" ->
"gateaux", was not consistent with the actual output of makeplural.
Same thing with "VAX" -> "VAXen" in the line below it; they're very old
comments, so maybe they were originally meant to point out some plurals
makeplural got wrong?  Since they predate the addition of "oxen" and
"geese" to one_off[] (and the array itself), it seems like the other
special cases mentioned in the comments would also have been wrong at
the time they were written.

Address this horrifying pastry-related oversight by adding handling for
'-eaux' plurals to makeplural, with an exception for 'bureau' (plural
'bureaus'; according to the dictionary, 'bureaux' is an acceptable
variant but 'bureaus' is more common, at least in American English).
There's also an exception for 'Bordeaux' (as in a bottle of the wine),
since the singular and plural are the same.

A bit surprised this wasn't already in there, since 'gateau' is a real
food item and seems like a much more likely fruit name than some of the
inedible items makeplural has special rules for.

Also add " au " to compounds[] in singplur_compound, so that 'gateau au
chocolat' will pluralize correctly to 'gateaux au chocolat'.  Without
that change, the result is 'gateau au chocolats'.
2022-05-20 17:37:02 -04:00
Michael Meyer 92999914c8 Prevent hero from writing Pratchett books
The hero's ability to channel Pratchett and write his books with a magic
marker once she had read or IDed at least one of them seemed strange,
especially cases like an illiterate hero doing it as her first
introduction to the written word.  Block the hero from writing random
novels with a marker.

The image of the hero sitting down in the dungeon to write a novel is
funny, so it feels like a good spot for a funny message.  I'm not
sure if what I have there is perfect, but it can always be changed.
2022-05-13 16:01:04 -07:00
Michael Meyer ba871d44bc Fix coloring of unaligned temple altars
They were showing up as gray/neutral, rather than red/unaligned.
2022-05-05 10:27:04 -04:00
Michael Meyer 0585fee5ff Designate high altars with dedicated altarmask bit
High altars and normal temple altars had identical altarmasks, so
there was no way to distinguish between the two based on the altarmask
alone.  Instead, anywhere it was necessary to determine whether an altar
was a high altar included a check whether the hero was currently the
Astral Plane or Moloch's Sanctum, and assumed any temple altar was the
high altar.

Since there's an extra, unused bit in altarmask anyway, use it to
explicitly mark high altars -- the lua level files already distinguish
between normal temple altars and so-called 'sanctum' altars anyway, so
rather than throwing away this distinction when generating the level,
keep it in the altarmask and use it in place of various u.uz checks.

I think this would require incrementing EDITLEVEL again...
2022-05-05 10:26:58 -04:00
Michael Meyer d3d5f7f88b Fix: force-fight 'unknown obstacle' descriptions
This is intended to address a couple quirks with force-fighting an
unoccupied spot that I noticed:

 * Now that furniture is considered 'solid', an object is much more
   likely to be sitting on the square, obscuring the terrain glyph.  As
   a result, the current glyph is no longer sufficient to accurately
   describe the contents of the spot -- e.g., an altar with a corpse on
   top of it was being described as "an unknown obstacle", even when the
   hero knew exactly what furniture was there.

 * When blind and attacking an unexplored 'solid' square, the attacked
   position would always be described as 'the stone', even something
   like a fountain or sink which didn't seem likely to be confused with
   a stone wall.

 * The feedback for attacking stone was previously changed from 'solid
   rock' to 'stone' in order to be consistent with the feedback for
   attacking an unseen wall, but they still weren't quite the same
   ("stone" vs "the stone").

 * The 'stone' feedback for all STONE/SCORR spots was incorrect on
   levels flagged as arboreal, where stone is rendered and described as
   trees.

This relies on back_to_glyph for positions where the hero is aware of
the terrain and certain other spots (like stone, walls, etc) for which
back_to_glyph produces good results even if they're unseen, and falls
back to the generic "unknown terrain" in other cases.

Pretty long commit message for such a small commit, but oh well...
2022-04-28 01:10:46 -07:00
Michael Meyer a384f0353b Fix: "in the the purple worm's entrails"
The message printed if the hero threw gold while swallowed by an animal
used "the <mon_nam>'s entrails", which produced a doubled 'the'.  It
could also use the wrong possessive form, since it doesn't take
advantage of any of the special case handling in s_suffix.  I think the
only way that could ever be a problem with the current cast of engulfers
is if the hero was swallowed by a purple worm while hallucinating, but I
changed it to use s_suffix anyway.
2022-04-20 00:09:02 -07:00
Michael Meyer 6bf7ba991f Fix: object detection vs mimic statue disguise
Cursed potions of object detection were showing all mimics disguised as
statues as 'i' glyphs, because object_detect used PM_TENGU as the
corpsenm of any mimic disguise.  Instead, use MCORPSENM when available
so that hidden mimics will be mapped with glyphs corresponding to their
actual disguises.
2022-04-08 10:22:14 -07:00
Michael Meyer bf53ff9de5 Add message for failed fountain monster detection
When the fountain quaffing monster detection effect was triggered on a
level without any monsters, no message would be printed.  I think this
was the only scenario where drinking from a fountain wouldn't print
anything, so it stood out as unusual.

Print a messsage in the case monster detection fails, to make it
consistent with other fountain effects and ensure it's clear the hero
did still drink from the fountain on that turn.  I used "the water
tastes like nothing" for the (sort of tenuous) connection to there being
nothing living on the level, but there might be a better message to put
in there.
2022-04-08 10:11:20 -07:00
Michael Meyer 4d82094e8b Handle spiders, cockatrices in mbodypart
Spiders and cockatrices were using the default animal_parts, which was
noticeably inaccurate in describing certain parts of their bodies.  Add
specific handling for both types of monsters: for spiders, add a
spider-specific body part list (the best I could figure out from online
sources, not being a spider anatomy expert), and for cockatrices, use
bird_parts with "scales" from snake_parts thrown in to emphasize their
unusual nature.
2022-03-22 14:30:21 -07:00
Michael Meyer fb512bac4f Fix: repeated 'hit with a wielded weapon' logging
The "hit with a wielded weapon for the first time" livelog line could be
produced repeatedly: it was triggered by hitting a monster with a
wielded object of any sort, but the u.uconduct.weaphit counter was only
incremented if hitting with an actual 'weapon' (a WEAPON_CLASS or
is_weptool item).  As a result, if a non-weapon-using hero whipped out a
non-weapon item -- a cockatrice corpse, for example -- and started going
to town on some monsters, the livelog message would be repeated with
every hit.
2022-03-19 18:10:11 -07:00
Michael Meyer 480ba917a1 Collisions while hurtling can stone participants
Hurtling into a monster is described as "bumping into" it, so it makes
sense that hurtling willy-nilly into a cockatrice (or vice-versa) could
result in petrification.  Since hurtling for the hero usually involves
"floating in the opposite direction" (presumably backwards) after
throwing an item, check whether the hero is wearing any body armor which
would cover their torso rather than looking for gloves.  Do the same for
monsters on the general basis that it's a bodily collision, and for the
sake of consistency.
2022-03-18 06:42:19 +02:00
Michael Meyer c6363d74a7 Fix: levitating/flying monsters moving over liquid
Commit c1a6dd4 was meant to prevent flying, levitating, and clinging
monsters from considering walls of water as acceptable movement
destinations, even outside of the Plane of Water.  However, it was
evaluating the monster's starting position instead of possible places to
move to, and the evaluation was 'backwards' (the equivalent of
IS_WATERWALL, instead of !IS_WATERWALL).

The result was that non-swimming monsters could only move onto any kind
of water or lava square if the position they were moving from was a
WATER square.  Change this so that instead of the starting position,
each potential destination spot's status as a wall of water is evaluated
in turn, and reverse the effect of the test so that it blocks walls of
water instead of allowing them.
2022-03-16 07:39:52 +02:00
Michael Meyer 1e951db9bc Fix: monster hurtling and liquid
A monster hurtling over liquid would drown immediately the instant it
touched the first square of water, even if normally it would have kept
moving (e.g. hurtling over a short moat).  Additionally, its placement
on liquid would not take into consideration other monsters, so it could
overwrite an existing monster on that spot and lead to an impossible,
and/or two monsters occupying a single position.

Fix these issues, so that liquid effects like drowning only happen if
the monster ends up in liquid at the end of the hurtle, and so that
other monsters in the way will stop it early even if they're floating
over or swimming on a pool/water/lava square.

Also use canspotmon instead of canseemon for the wiztelekinesis debug
command.
2022-02-24 14:53:48 +02:00
Michael Meyer dc21b3d657 Make ravens oviparous
Ravens are birds, so they should be able to lay eggs.
2022-02-19 17:31:34 -08:00
Michael Meyer 89bbe77010 Fix: tty map weirdness after 'full-screen' menu
When a 'full-screen' (cw->offx and cw->offy both 0) menu was immediately
followed by an offset menu -- as in the case of selecting certain
options from the options menu, or using loot to take out/put in items
after using ':' to describe the contents of a very full container --
there were some odd interactions with the map.

Only certain parts of the map near/under the menu window would be
redrawn if the first offset menu was followed by another one, while
a getlin prompt would cause the entire map to be redrawn, with parts
intersecting the window being drawn on top of it and obscuring it.
Flushing the display immediately after the docrt call when closing a
full-screen menu seems to fix both these issues.
2022-02-12 06:13:50 -08:00
Michael Meyer 79b3a624e4 Use verbalize for player monster speech
Attempting to chat with a player monster would inspire a witty retort,
but it was presented without quotation marks and so differed from other
types of monster speech.
2022-02-02 11:55:38 -08:00
Michael Meyer f5e3bc3d96 Remove gendered mons indices from roles, races
There are no longer distinct gendered versions of monsters, so femalenum
is unused (i.e. set to NON_PM) for all roles and races. Take a pass at
removing all uses of/references to femalenum, and rename 'malenum' to
'mnum' since it no longer has any particular association with
gender or sex.
2022-01-14 13:51:26 -08:00
Michael Meyer 70f263f0ce Fix: unpaid_cost regression
Recent commit 5c14f3e fixed an issue with unpaid_cost when the hero is
in two shops at once (e.g. phasing through a shared wall), but
introduced new problems with finding the cost of a container with unpaid
contents -- an unpaid item in a player-owned container would generate
the same "unpaid_cost: object wasn't on any bill" impossible as the
issue the commit fixed.

The main issue was that finding the bill entry used to depend on finding
the shopkeeper, but after the change, finding the shopkeeper depended on
finding the bill entry; for a container with unpaid items which has a
shopkeeper, but no bill entry, this caused issues.

Revert part of 5c14f3e and tackle the problem another way, which should
correctly handle unpaid items in inventory or a container, even if they
belong to a mixture of different shops and/or the hero is on a space
shared between multiple shops.
2022-01-14 13:29:55 -08:00
Michael Meyer 7efba965d9 Don't 'fall' and self-stone when flying down
When a flying hero deliberately "swoops" through a trap door or hole,
consider the movement down to the next level to be controlled flight
rather than falling, preventing the sort of inadvertent touching of a
carried cockatrice corpse that happens when falling between levels.
2022-01-14 11:53:37 -05:00
Michael Meyer 221e4a760d Fix: chameleon quickmimic not reset after eating
finish_meating was checking whether the monster in question was a
chameleon/shapechanger, rather than whether it was a mimic, in deciding
which monsters should be allowed to maintain their current appearance
once they finish eating.  This meant that true mimics had their
appearance reset, while a chameleon, vampire, etc, who ate a mimic
would maintain their appearance as a tripe ration even after they had
finished eating and resumed their normal behavior.  The result?  An
amazing living tripe ration which followed the hero around throughout
the level.
2021-12-30 21:14:08 +02:00
Michael Meyer 4b20ed6211 Fix: gender, historicity of stoned monster statue
The way statues of stoned unique monsters were marked as "historic" was
not changed when mkcorpstat flags were updated in 04a8ddc, resulting in
unique statues which were no longer marked as historic and were instead
marked as female.

While fixing that, also use the gender-related mkcorpstat flags to
assign the gender of a stoned monster to the resulting statue.
2021-12-17 16:28:48 -08:00
Michael Meyer a606f83e7a Fix: 'you owe It for goods lost'
Some messages about owing a shopkeeper money would use 'it' when blind,
with weird results such as "You owe It 267 zorkmids for goods lost."  It
seems maybe like these were missed in 6591f8b since they were outside of
shk.c/shknam.c.  Bring those messages into alignment with most other
shopkeeper-related messages, which use the shopkeeper's name even if the
hero is blind or can't see them at the moment.

Some of the 'it gets angry' ones don't seem so bad, but similar 'gets
angry' messages in shk.c use Shknam so I changed those as well for
consistency's sake.
2021-12-01 18:34:20 -08:00
Michael Meyer ce2615a316 Fix: zoo monsters spawning in hallways
If a random G_[SL]GROUP monster was generated in a zoo, the resulting
group of monsters could spill out into nearby hallways and other
surrounding areas.  Disregard G_GROUP flags when filling a zoo with
monsters to avoid this problem.
2021-11-30 12:51:11 -08:00
Michael Meyer 90313d443d Magical breathing helps fish survive out of water
The hero in an aquatic polyform loses HP for time spent out of the
water; allow magical breathing to prevent this, just as it allows the
hero in her non-aquatic natural form to breathe underwater.

Also add a similar rule for monster fish-out-of-water HP loss, even
though currently monsters can't use amulets of magical breathing and
there's no non-breathing fish/eel -- just in case this changes at some
point.
2021-11-18 18:36:54 -08:00
Michael Meyer 9e94226235 Fix: bad cast making sp_lev chameleon light source
Giving new_light_source '(genericptr_t) mtmp' leads to the light
source's id.a_monst being set to 'mtmp->nmon' rather than 'mtmp',
since that's what is stored in the initial byte of the monst struct.
When mtmp->nmon == 0x0 this can cause a segfault in do_light_sources.
2021-10-28 18:00:27 -04:00
Michael Meyer c9cef70d51 Writing scrolls by type-name followup
Don't allow type-name of a scroll that has since been formally
identified to override a real scroll name.

For example, if a user typenames a scroll of fire 'earth', then IDs
fire but doesn't change the typename (reasonable, since it doesn't show
up anywhere in inventory at that point), if they try to write 'earth'
with a magic marker, don't produce a scroll of fire just because it's
still type-named 'earth'.  At that point they know it's not a scroll of
earth and it's no longer reasonable to assume they mean to use the
typename.

In other words, if a user-assigned typename matches a real scroll type,
write the scroll with the typename -- unless the player knows for sure
it doesn't match the actual scroll (whether because the actual scroll is
already IDed, or the typenamed scroll has been IDed as something else).
In that case write (or attempt to write) the actual scroll as though the
typename didn't exist.
2021-10-28 17:18:20 -04:00
Michael Meyer 00b3b955af Fix: baalz_fixup didn't account for level rotation
Because some spots in the fly's 'legs' on the Baalzebub lair level are
specified as pools in the level file, then later converted to walls in a
post-generation fixup routine, monsters can be generated on those spots
and then left walled up and inaccessible, Cask of Amontillado style.
For the love of God, makemon-tresor!

Some code already existed to relocate these monsters after generating
the level, but it depends on misorientated 'leg segments' being fixed up
in a particular way.  That wasn't being triggered because it didn't
account for the possible rotation of the level; as a result, the
monsters in the leg segments wouldn't be relocated, and the leg segments
themselves would continue to have the wrong orientation.

Account for possible level rotation so that the monsters are relocated
properly (and the leg segments are 'fixed').
2021-10-27 15:48:26 -07:00
Michael Meyer 2abe08d0bf Formally block artifacts as random box contents
Another (latent) case of an artifact possibly being generated and
immediately deleted: part of the process of a mimic disguising itself as
an item involves generating a random object, then deleting it.  If this
item is a box or sack, it will generate with random contents, which will
be deleted along with the container. If artifacts are allowed as random
box contents, this can silently remove an artifact from being available
in the game.

This is effectively blocked already, since none of the artifacts
eligible for random generation are items from classes marked as valid
box contents (see boxiprobs[] in mkobj.c).  Nonetheless, formally
preventing artifacts from generating as box contents will guarantee this
issue won't crop up if a randomly generated artifact tool, ring, etc, is
added in the future.
2021-10-26 11:55:00 -07:00
Michael Meyer b242fbce5a Fix: artifacts silently removed from the game
Death drops will generate a random item, which may be an artifact.
After the object is created, some rules are applied to check whether its
size matches the monster that dropped it; if it fails these checks,
the item is deleted.  aosdict recently pointed out that if the death
drop was an artifact, this would permanently remove it from the game.

Use artifact_exist(..., FALSE) in various cases where potential
artifact objects are created, then immediately removed.  This will
prevent artifacts from being removed from play by marking the artifact
as available to create again.
2021-10-26 11:54:59 -07:00