Commit Graph

8869 Commits

Author SHA1 Message Date
nhmall
d421e2512e tab to spaces 2023-08-16 10:07:01 -04:00
PatR
341b1ad289 sortloot details
The sortloot classification routine had some inappropriate casts to
'coordxy' for things had nothing to do with map coordinates.  I was
going to change the relevant fields to 'short' but that seems iffy
for 'indx' so I changed them all to 'int'.
2023-08-15 15:48:41 -07:00
Michael Meyer
3ce3128e09 Release obufs used by sortloot
Some further application of e43ec0c logic, which was intended to fix odd
messages produced by obufs clobbered by inventory updates (like "the
ogre lord yanks Cleaver from your corpses!").  That issue was still
lurking around because sortloot(), via sortloot_cmp(), was continuing to
call for obufs via loot_xname() without releasing them immediately.  It
was going through the entire inventory doing that, much like
display_pickinv() was prior to Pat's fix in e43ec0ce, so could cause
the contents of obufs to still be clobbered by perm_invent updates.
This changes sortloot_cmp() to releases the obufs it calls for as soon
as possible so that won't happen any more.
2023-08-15 14:33:17 -07:00
nhmall
b5dcb58d52 two minor comment typos 2023-08-15 14:12:52 -04:00
nhkeni
9ba47555c9 Merge remote-tracking branch 'origin/keni-versioncopy' into NetHack-3.7 2023-08-15 09:33:59 -04:00
PatR
1e47b4e824 third typo on same line as previous two... 2023-08-12 16:11:50 -07:00
PatR
fe919f91b3 couple of comment typos
The second one has two on the same line.
2023-08-12 15:04:10 -07:00
PatR
7ea091048c count_level_features() bit
The relatively recent code to recalculate the number of fountains and
sinks on a level was including column 0.  levl[*][0] is not used for
the map.
2023-08-12 15:01:02 -07:00
Pasi Kallinen
491cc9933f Unhide a water monster using a polymorph trap 2023-08-08 16:49:03 +03:00
PatR
9f16eaa0a5 fix 'up' and 'down' status highlighting for HP
If there was a status_hilite rule for hitpoints:up, it got used for
both up and down changes.  If there was one for hitpoints:down, it got
ignored even if there was no 'up' rule.  The flag for which direction
the value changed was always positive even when the value went down.

I'm reasonably sure that at some point HP up/down worked correctly.
This problem was present in 3.6.4; I didn't go back any farther.
2023-08-05 12:50:47 -07:00
PatR
70791271dd update PR #1071 - highlighting critical HP
If status field 'hitpoints' has rules for both 'criticalhp' and 'up'
or 'down' or 'changed', make critical-hp take precedence.  Otherwise
critical-hp might never be seen because of the value changing every
move (if hero has regeneration attribute).  Normally up/down/changed
take precedence over other types of highlighting.

Something is messed up with up/down/changed HP though.  I'm seeing
the 'up' highlight when it goes either up or down and not seeing the
'down' highlight at all.  'up' and 'down' for gold work as expected.
2023-08-04 22:33:29 -07:00
PatR
651a5b210f fix github issue #1085 - strength of orc captain
Issue reported by Umbire:  Uruk-Hai have strength 18/100 and can grow
into orc captains, but orc captains' strength was limited to 18/50.

Cap strength at 18/100 for hero poly'd into an orc captain, same as
when poly'd into an Uruk-hai.  Since poly'd heroes don't grow into
larger forms, the only way to notice is to polymorph into an Uruk-Hai
at some point and into an orc captain at some other point.

Fixes #1085
2023-08-04 15:12:33 -07:00
nhkeni
1663ecf85d Add --version:copy, deprecate --version:paste. 2023-08-03 21:51:25 -04:00
PatR
9d9042e94b fix #K3968 - objfree: obj not worn
New feature to sometimes hit twice for skilled martial-arts/bare-handed
was unconditionally using uswapwep for the second hit.  If it was a
breakable object, hitting could break it and produce impossible "objfree:
obj not free".

Only use uswapwep for u.twoweap; use Null for second bare-handed hit.
2023-08-01 10:28:21 -07:00
PatR
af387db16d bare-handed combat warning fix 2023-07-31 10:26:37 -07:00
nhmall
7cec01748e Revert "warning after commit 60c19568"
This reverts commit d32208562e.
2023-07-31 10:16:35 -04:00
nhmall
d32208562e warning after commit 60c19568
uhitm.c:843:63: warning: operator '?:' has lower precedence than '|'; '|' will be evaluated first [-Wbitwise-conditional-parentheses]
                   | (hmd->twohits == 0 || hmd->twohits == 2) ? W_RINGL : 0L);
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
uhitm.c:843:63: note: place parentheses around the '|' expression to silence this warning
                   | (hmd->twohits == 0 || hmd->twohits == 2) ? W_RINGL : 0L);
                                                              ^
                                                             )
uhitm.c:843:63: note: place parentheses around the '?:' expression to evaluate it first
                   | (hmd->twohits == 0 || hmd->twohits == 2) ? W_RINGL : 0L);
2023-07-31 10:10:19 -04:00
PatR
60c1956850 revamp 'special' combat
This is a re-creation of a project that was lost years ago while not
quite finished.  The old version included some instrumentation to
measure how many hits it takes to kill things during actual play; that
wasn't ready for prime time and this hasn't attempted to redo it.

Changes:
1) improves martial arts and bare-handed combat:  they now have a
   chance to hit twice when skill is better than 'basic'; 20% chance
   for second hit at skilled, 40% at expert, 60% at master, and 80% at
   grandmaster; when attacking more than once, strength bonus is
   handled as in #2;
2) nerfs two-weapon combat a bit:  hitting twice uses only 3/4 strength
   bonus on each hit, but when both attacks hit that's 3/2 bonus from
   strength which is still more than you get for one hit at a time;
3) beefs up two-handed weapons:  hitting via melee with a two-handed
   weapon uses 3/2 of stength bonus to reflect the increased influence
   of strength; isn't done for applied polearms though.

The reduction in strength bonus for two-weapon has far less impact
than it might sound, due to rounding up with the low values involved.
| full   3/4
|  +1 -> +1
|  +2 -> +2
|  +3 -> +2
|  +4 -> +3
|  +5 -> +4
|  +6 -> +5
The small reduction also doesn't matter if/when current hit happens to
deal a killing blow anyway.

Rings of increase damage apply at full value to every hit, same as
before.

When hitting bare-handed (#1 without gloves), a silver ring on either
hand continues to give a damage bonus against silver haters when you
make an ordinary single attack.  However if you attack twice, a silver
ring only applies on the first hit when it is worn on the right hand
and only applies on the second hit when worn on the left hand.  (Two
hits with a silver ring on each hand will give silver bonus for both.)

We might conceivably need to add support for a count prefix of 1 to
let player explicitly avoid a second bare-handed/martial-arts hit
attempt (similar to how throw and fire accept a count to limit missile
volley amount).

Kicking has been ignored.
2023-07-30 14:08:30 -07:00
PatR
eb5bb2b989 weapon.c formatting bit
Fix some overly-wide lines.  I didn't look through the file for other
stuff that might need reformatting.
2023-07-27 13:11:22 -07:00
PatR
06d7b0561c double klick (not what you think...)
When testing water-vault chests, I kept getting
|Klick!  Klick!
when zapping them with a wand of opening.  This had me scratching my
head for a while, but it seems to have been caused by partially adding
a sound effect.  pline("Klick!") became duplicated and presumeably one
of the two was intended to be edited into a sound-effect call but got
overlooked.

Sound_effect(se_klick,) doesn't make any sound though.
2023-07-22 17:54:12 -07:00
PatR
d99b549bb0 more PR #1051 - water-vault escape item
When generating an "escape item" inside one of the chests in the
"water-surrounded vault" theme room, make sure that the chest is not
locked if the item is made of glass or crystal.  Otherwise kicking the
chest to get access to its contents might destroy the item.

I imagine that this could be done more cleanly, but after quite a bit
of thrashing about I have something which seems to work.  To test, I
temporarily modified object shuffling to force wand of digging to be
made out of crystal and gave the water-vault a very high generation
frequency.
2023-07-21 15:00:54 -07:00
PatR
ca99dfaeeb avoid "<mon> slithers under the water" for fish
Don't use "slither" for movement action when observing an aquatic
monster go into hiding underwater.  Use "dive" instead.

Shark, pirahna, and jellyfish had been flagged M1_SLITHY but aren't
anymore.  Giant eel and electric eel are still M1_SLITHY and kraken
wasn't and still isn't.

There may be some odd cases that used to use slither and it went by
unnoticed where now use of the default verb might become noticeable.
2023-07-19 12:12:41 -07:00
PatR
8d60b92407 cleanup when exiting tutorial
When returning to play from within the tutorial, remove the level files
similar to how they're discarded for the rest of the dungeon when going
into the endgame.  It turned out to be a bit messier than anticipated.

The dungeon.c bit is sufficient for #overview, which now hides regular
level 1 while in the tutorial and hides all tutorial levels once exited.
Those will still appear in end-of-game disclosure.
2023-07-17 14:27:28 -07:00
PatR
7f635ad25b fix github issue #1082 - Prot from shape changers
vs lycanthropes

Issue reported by Umbire:  when hero had Protection_from_shape_changers
extrinsic, a lycanthrope in human form that attacked could change into
critter form.  It would change back to human on its next move.

Prevent werecreatures from transforming from human form to critter form
if hero has Protection_from_shape_changers.  That attribute does not
prevent a human werecreature from summoning animal companions.

Fixes #1082
2023-07-15 12:20:47 -07:00
vultur-cadens
df2799faff add a statushilite option for critically low HP
This allows players to specify a highlight for critically low HP in
the config file, for example:

OPTIONS=hilite_status:hitpoints/criticalhp/purple&inverse

This will cause the hitpoints field to be highlighted when HP is low
enough to be considered a major trouble.  The new "criticalhp" setting
only applies to the hitpoints field.

Since the critical HP threshold changes with level (and most of the
fractions are not integer percents) it was impossible to set
highlights to match the critical HP threshold using percentage
settings.
2023-07-13 13:58:26 -07:00
nhmall
9dce424145 Merge branch 'cmap_confusion_planes' of https://github.com/entrez/NetHack into NetHack-3.7 2023-07-12 15:29:16 -04:00
Michael Meyer
93e578bf6f Fix: wrong glyphs for clouds and water on Planes
ff727e9 introduced an issue where unseen water and cloud on the
respective planes were shown with open and closed drawbridge glyphs
instead of the appropriate glyphs.  This is because they fall into cmap
section B, but the translation from symbols/cmap index to glyphs was
being done as though they were in cmap section A (ff727e9 manually used
that particular cmap section macro instead of the general cmap_to_glyph
to work around some compiler warning).
2023-07-12 15:21:00 -04:00
PatR
dbd39f2cd5 prevent weightless statues
From a reddit thread:  statue weight is one and half times corpse
weight and some monsters that don't leave a corpse are defined as
having mons[].cwt==0 so statues of those weighed nothing.

Rather than assigning a non-zero corpse weight to every type of
creature, statues that weigh less than an arbitrary value based on
monster size have their weight increased to that value.  The weight
of a statue of a killer bee jumps from 1 to 100, that of a leprechaun
increases from 90 to 100, that of a yellow light is changed from 0
to 300, wraith from 0 to 500, and air elemental from 0 to 900.  That
last one is actually too low but making the formula more complex
doesn't seem worth it.
2023-07-12 09:48:24 -07:00
PatR
4fc96b0218 another paranoid_confirmation revision
Add support for
 |OPTIONS=paranoid_confirm:+foo !bar
to enable confirmation for foo and disable it for bar while leaving
other settings intact.  Drop support for
 |OPTIONS=!paranoid_confirm:bar
since paranoid_confirm:-bar and paranoid_confirm:+!bar accomplish the
same thing.  !paranoid_confirm still works as paranoid_confirm:none.

Update the documentation for paranoid_confirmation.  It doesn't spell
out all the ins and outs but should cover enough for actual use.

The revised Guidebook.tex is untested.
2023-07-10 23:38:18 -07:00
PatR
1b79f00a39 more PR #1077 - #sit on floor trap while Flying
Sitting on a squeaky board wasn't triggering it even after the
handler for that type of trap allowed VIASITTING to override Flying.
The check_in_air() test for floor traps didn't have the same override,
so the squeaky board handler didn't get called.

This fixes that, which led to inconsistency with some other trap
types, and additional fixes for pits and bear traps.  There might be
others that still behave oddly.  For example, if flying over a hole,
using #sit yields
 |You land.  There's a gaping hole under you!  You don't fall in.
I think that's a message phrasing issue rather than a falling trap
issue; if you want to go down, use '>' instead of #sit.  On the other
hand, you do now fall into pit traps for #sit while flying over them.
2023-07-09 14:51:30 -07:00
Ardub23
6406c9d055 Sit to trigger squeaky board even if flying
If the hero deliberately sits on the floor while flying over a squeaky
board, then either they're trying to squeak it on purpose or they haven't
noticed it. Either way, sitting should trigger it.
2023-07-09 09:28:09 -06:00
PatR
7b32ce02ea fix github issue #1072 - pets pick up cursed items
Issue reported by vultur-cadens:  tame monsters capable of using items
would pick up cursed ones and even wear cursed armor.

The report cites commit 6c9700ab25 but
I don't see any reason why it would be the cause.  However, I was able
to reproduce the misbehavior and this commit seems to fix it.

Fixes #1072
2023-07-08 15:24:40 -07:00
vultur-cadens
72213bf48f writing an unknown spellbook when the spell is known
Allow hero to write an unknown spellbook if the spell is freshly known
(from divine knowledge).  If the spell is going stale, the chance of
successfully writing the spellbook depends on Luck, but only rnl(5)
(like a Wizard) instead of rnl(15).  Forgotten spells do not help when
writing unknown spellbooks.
2023-07-07 12:13:52 -07:00
Michael Meyer
ab37888b36 Restore altar destruction from magical digging
Especially powerful magic is meant to be able to destroy altars
(breaking a wand of digging or using a drum of earthquake), but it was
being blocked by a check added to maketrap() in a7f6460 designed to
prevent wizard-mode trap wishing from overwriting stairs.  The check was
refined in 6a3d82c to add an exception for digging up graves, but
continued to prevent the destruction of other types of
previously-destructible terrain.

Since this block was a side effect of an attempt to add some guard rails
to wizmode terrain wishes, and the code to explicitly permit the
destruction of other furniture with especially powerful magic is still
present, it doesn't seem like it was actually intended.  Open up terrain
destruction by digging magic a bit more by excluding only
non-destructible terrain, not all furniture other than graves, from
being overwritten by pits and holes.

Also, use AM_SANCTUM to more precisely identify non-destructible high
altars in dig_check() rather than checking whether the hero is on the
Astral or Sanctum levels.
2023-07-07 10:41:18 -07:00
Michael Meyer
95b410ee94 Provide escape item in water-surrounded vaults
Water vaults are one of the few places that can/will generate completely
sealed off in a normal level.  Other such spots are designed to provide
a guaranteed means of escape (vault guard, scrolls of teleportation in
niches, etc) -- water vaults were an exception that didn't do this, so a
hero who fell into one from above could have ended up in a position
where she had no choice but to wait to starve to death or #quit. Provide
an escape item in one of the vault's chests to give a hero more options
in that position.

Also fix a minor mistake (I'm pretty sure, though I'm not a Lua expert
enough to be certain) in an nhlib.c comment describing how to use
obj.addcontent() -- when called as box.addcontent(contents) as the
comment suggested it produces an error, but works OK when called as
box:addcontent(contents) or obj.addcontent(box, contents).
2023-07-07 09:42:43 -07:00
PatR
60a3263a85 fix github issue #1070 - Minetown achievement
Issue reported by vultur-cadens:  arriving on the Mine Town level
via falling or level teleport won't register the "entered Minetown"
achievement if hero doesn't arrive inside a room.

Reorder some code in check_special_room() so that town entry will be
tested before the early return if no room entry has occurred.  This
adds 'level.flags.has_town' to make the town test be cheaper when
the hero hasn't attained the achievement yet and is wandering around
the mines.

Fixes #1070
2023-07-06 13:18:19 -07:00
Michael Meyer
3064228ca7 Fix: levltyp[] desynchronization
The "temporary?" levltyp[] array became desynchronized from the level
types enum with the addition of lava walls.  This caused all level types
past that to be given the wrong description when it was used.

Add an explicit length to the array so that future additions to the enum
should produce a compiler warning if it's not updated at the same time.
2023-07-04 22:56:52 -07:00
Michael Meyer
d57a359bba Add correct Cyclops pluralization
The correct plural of "Cyclops" is "Cyclopes", not "Cyclopses".  I don't
know if anyone would actually use that as a fruitname, but it wouldn't
hurt to add it -- especially since a Cyclops does appear in the game.
2023-07-04 22:37:38 -07:00
SHIRAKATA Kentaro
97edd4b845 split offering fake amulet into separate function 2023-07-04 22:19:04 -07:00
nhmall
1c8a5d62bc suppress four new warnings
src/sp_lev.c(5348) : warning C4702: unreachable code
src/sp_lev.c(5608) : warning C4702: unreachable code
src/sp_lev.c(6281) : warning C4702: unreachable code
src/sp_lev.c(6334) : warning C4702: unreachable code
2023-07-04 23:44:36 -04:00
copperwater
0e01828ed8 Fix: when a themeroom failed, xstart/ystart weren't reset
Revealed this bug when testing the previous commit:

Themed room generation with a randomly placed map involves picking a
single random point on the map at which to plop it down, and then
declaring the themed room failed and exiting if it would go beyond the
map bounds or overlaps with an existing room. In the process,
xstart/ystart/xsize/ysize have been modified, but weren't getting reset.
(They would get reset if the map successfully got placed and it had a
contents function, as of commit 4af086b, but there wasn't handling for
the failure to place it.)
2023-07-04 16:19:28 -07:00
copperwater
2ae5ce8ab3 Fix and guard against out-of-bounds writes in splev code
I traced a memory corruption bug in xNetHack to a themed room that
looked something like this:

    function()
       des.room({ type="themed", contents = function()
          des.feature({ type='sink' })
          ...
       end })
    end

Placing a feature at a random spot within a room or region is a
reasonable thing for the parser to handle, but the code was not equipped
to handle it, and so the unspecified x and y set as -1 got passed
directly to SP_COORD_PACK, ending up as coordinates way off the map.
Since sel_set_feature does not do an isok() check, this ended up writing
data to unrelated memory.

This commit does the following things:

- Enables des.feature() with no coordinates specified, both via a table
  with 'type' set, and as the single string argument. When no
  coordinates are specified, it will pick a random normal-floor spot
  within the enclosing room or region if there is one, or anywhere
  on the level if there isn't.
- Prevents sel_set_feature from corrupting memory outside
  g.level.locations. Additionally, if EXTRA_SANITY_CHECKS is defined and
  this gets attempted, it causes an impossible.
- Guards the existing "door coord not ok" Lua error with an immediate
  return from lspo_door.
- Adds similar "coord not ok" errors to all the other locations in
  sp_lev.c which did not already check for a unspecified/invalid
  coordinate and for which a random coordinate is nonsensical:
  des.terrain(), des.drawbridge(), and des.mazewalk().
2023-07-04 16:19:27 -07:00
copperwater
9e291234f5 Implement builds_up correctly, resolving its FIXME
The FIXME comment noted that builds_up would return an incorrect false
value for a dungeon branch that builds upwards but is only 1 level, but
that this is a latent problem because no such branch exists in NetHack.
Such a branch does exist in xNetHack, and it causes the debug fuzzer to
crash ("mon_arrive: no corresponding portal" because it can't find the
correct-direction stairs), so I figured I might as well fix it upstream.
2023-07-04 16:05:52 -07:00
copperwater
cba85d2314 Allow des.object "trapped" field to be a boolean
I thought there were more object fields that currently only accept ints
but ought to accept booleans, but when I checked I found that most of
them do already, and the ones that take ints are the ones that the
number carries meaning (spe, recharged, etc).

Except for trapped. In struct obj, otrapped is a 1-bit flag, so there's no
good reason for the level parser to treat it as a type error if someone
intuitively makes a des.object call with trapped=true or trapped=false.
Change it to an optional boolean argument, like the other boolean flags
(locked, greased, etc).

Note that get_table_boolean_opt still accepts ints, so existing uses of
trapped=0 or trapped=1 won't be affected.
2023-07-04 15:38:26 -07:00
copperwater
c6fa9c3099 Fix chained selection xor and subtraction operations
Something that's reasonable to expect to see in Lua files is something
like:

    local sel4 = sel1 - sel2 - sel3

or more generally, producing a selection from subtraction that will then
be used in subsequent selection math.

I discovered this wasn't actually working correctly, and that it also
applied to the xor operation. The reason behind this is that
l_selection_sub and l_selection_xor create a new selection from nothing,
which by default has "lower" bounds of COLNO, ROWNO and "upper" bounds
of 0,0. Iterating across the intersecting rectangle of both selections
does not reliably set the bounds of the resulting selection properly,
since the first selection_setpoint with a value of 0 will cause the
selection's bounds_dirty flag to be set, at which point they will cease
to change as more points are added.

Then this selection with its incorrect boundaries is pushed back onto
the Lua stack, and becomes the first operand of the next subtraction
(i.e. selr in the first l_selection_sub becomes sela in the second
l_selection_sub). Depending on how broken the bounding box is, results
may vary, but if the bounding box is still (COLNO,ROWNO,0,0), the
resulting selection will have no points selected at all.

This fixes this problem by forcibly recalculating the bounds of the
result selection, so any subsequent operations on it will be valid.
2023-07-04 14:53:16 -07:00
PatR
0e97f8901a glyph_to_cmap() usage
I was looking to see what the impact of converting glyph_to_cmap() to
a function might have and noticed a couple of places where the macro
edition is passed a non-trivial argument.  Since it evaluates that
argument many times, there is hidden overhead.  Fetch the glyph once
and pass that to glyph_to_cmap().

This will no longer be very useful--but won't need to be reverted--if
PR #1022 gets incorporated.

do_positionbar() has bugs (only matters for MS-DOS).
2023-07-03 13:24:56 -07:00
PatR
2d6d151b28 PR #1009 - higher statue trap difficulty
Pull request from NulCGT:  make statues created for statue traps be
5 to 10 points higher in difficulty than the default would be.

5 to 10 points of difficulty higher is already used for figurines.
The pull request chose the same amount but I've reduced it to 3 to 6.
Partly so that they won't be the same, partly so that they won't be
too hard when activated, and partly so that the creature won't be
quite as obvious a give away that the statue is a trap.

Closes #1009
2023-07-02 15:27:58 -07:00
Kestrel Gregorich-Trevor
2dd0af630e Adjust statue traps to be biased toward more difficult monsters. 2023-07-02 15:16:57 -07:00
PatR
5daec07300 PR #1008 - get doppelganger form from 'record'
Pull request from NulCGT:  when a doppelganger is choosing to become
a fake player, get role from an entry in the high scores file.  Use
that entry's name too if the doppelganger is within view at the time.

I'm not sure how well this will work for a single user score file if
the player always runs the same role and name.  I've given it a small
chance (1/13) to ignore the topten and stay with random role instead.

Closes #1008
2023-07-02 14:58:11 -07:00
Kestrel Gregorich-Trevor
8e43b684e8 Doppelgangers mimic top ten list members.
I saw this in the YANI archive, and I think it's fairly interesting.
Doppelgangers are known for commiting identity theft, but in NetHack
they function as just another shapeshifter. This commit makes them
a bit more interesting, I think.

Original YANI by aosdict and Andrio.
2023-07-02 14:43:29 -07:00