Commit Graph

310 Commits

Author SHA1 Message Date
Alex Smith
5d3a1e684b Add shields of shock resistance and of drain resistance
These both appear as "wooden shield" when unidentified; so does the
small shield.
2026-03-18 23:27:54 +00:00
Alex Smith
4fae45220e Remember price quotes that have been seen for types of item
These are displayed in discoveries, and a new 'price_quotes' option
allows them to be displayed for un-IDed objects in other contexts
too (the idea is that you turn on the option while identifying
objects and off for general play).

Invalidates existing save files.
2026-03-18 21:08:22 +00:00
nhmall
44fcbb180d bump COPYRIGHT_BANNER_A 2026-01-04 11:16:45 -05:00
Alex Smith
656f58b099 A basic version of starting character rerolling
This adds a "reroll" option that lets players reroll their
character's attributes and starting inventory. Although I generally
think doing this makes the game worse, a) some players are going to
do it regardless and b) if a player is going for a challenge game,
rather than to win, it may be required. So in the absence of an
option like this, players repeatedly start and quit games instead,
creating a large number of junk logfile entries and generally
causing problems for other players on the same shared machine
(because repeatedly reloading the game is very CPU-intensive).

This should in theory be windowport-agnostic (although in practice
it may not be). Tested on tty, X11 and curses; on tty and X11 it
works fine (although X11 treats the change in attributes as
something that needs a status highlight), on curses it is slightly
jankier in terms of what other windows are drawn in the background
(but still plays correctly and I suspect this is a pre-existing
bug).

To form a complete implementation, we will need to consider the
following:

- Should there be a delay on a) starting the game and/or b)
  rerolling? If so, what should it be (maybe configurable via
  sysconf?)

- Should we take more steps to discourage players from rerolling?
  It would be bad if players see the option exists and turn it on
  just because it exists, or (worse) treat it as condoning the
  particular style of play.

- Should we take steps to detect that players are rerolling
  manually and a) tell them to use the option instead, b) tell them
  that this is not an intended way to play (and may make the game
  less enjoyable and/or prevent them getting the practice they need
  to eventually win)?

Breaks save and bones files.
2025-11-30 06:49:14 +00:00
Alex Smith
8c29b20010 Accurately track which items have been discovered, even if not #named
This fixes a couple of bugs: a long-standing bug in which writing a
scroll by label could fail even if you've already seen a scroll with
that label (due to the game not tracking whether or not you've seen a
scroll if it doesn't have a name); and a somewhat newer bug in which
spellbooks auto-identified by Wizard knowledge were marked as having
been encountered (rather than as known but not encountered).

Breaks save file compatibility, but not bones files.
2025-11-25 22:42:38 +00:00
PatR
c08f79b26e more photographing monsters
Don't record hallucinated monsters as having been seen up close or as
photographed.

Treat a tourist's starting pet has having been photographed prior to
bringing the camera and dog or cat into the dungeon.

No extra points to tourist when first long worm tail is photographed.

EDITLEVEL is incremented again, for extra context to track starting
pet.
2025-07-29 15:45:11 -07:00
nhmall
f145cc02f4 photograph experience gains often counted only prior to first move
More details in https://github.com/NetHack/NetHack/issues/1430

track photographed monsters using a distinct bit

also adds a pair of new context fields to track the total number of monsters seen up close,
and the total number of monsters photographed.

So, if somebody wants to add unique end-of-game disclosure statements for tourists that relate to
those, the groundwork should be there.

NOTE: This increments EDITLEVEL, so existing save and bones files will become outdated.

Fixes #1430
2025-07-26 11:03:20 -04:00
Pasi Kallinen
e240efa10b Restoring a game can return to the wishing prompt
In TTY or curses, if the terminal goes away while you're in the wishing
prompt, return to the prompt when the game is restored.

Breaks saves.
2025-07-12 18:21:12 +03:00
Alex Smith
308c5ab237 The Amulet of Yendor gives a wish when initially picked up
Part 4 of implementing wish spreading. (This is now a complete
implementation, although the details are likely to change - but it
makes sense to commit something with the right balance properties,
and then tweak it based on feedback from playtesting.)

This helps to make the Amulet of Yendor feel special, and restores
approximately the same average number of wishes per game as existed
prior to the nerf to wands of wishing.

Placing the wish in allmain helps to avoid the wish happening at an
awkward place in the game's control flow, and is simpler than
testing every possible mechanism for gaining items for bugs (message
order is a common issue when trying to place it in addinv-related
functions, and this also avoids issues with the wished-for item
immediately invalidating an assumption that was made by the calling
code).

It is possible that this would be better as an invoke effect,
although I like the impact of picking up the Amulet and immediately
being given a wish.
2025-05-30 02:10:58 +01:00
Alex Smith
0e50adcc1e Restore monsters.h to its previous order
This causes the difficulties to get out of sequence, but we agreed
that this is a less important rule than keeping monster IDs stable.

Breaks save and bones files, because it changes monster IDs.
2025-05-29 19:14:10 +01:00
Alex Smith
47724f0137 Increase generation depth of soldier ants and killer bees
These two types of monster were extreme outliers in terms of where
they appeared versus how lethal they were (3-4 times as deadly as
other monsters that appeared at similar depth, based on statistics
from actual play), so their generation depth has been manually
modified.

Breaks save and bones files (because monster type IDs have to be
sorted numerically by difficulty, and changing difficulties thus
changes the IDs, but the IDs are used to identify the monsters in
save files).
2025-05-29 17:53:38 +01:00
Pasi Kallinen
035cd4377f Snickersnee can hit at a distance once per turn for free
Once per turn, Snickersnee can be used to hit at a distance,
similar to a polearm, without taking any time.

Breaks saves.
2025-05-12 20:26:53 +03:00
nhmall
502b60d210 follow-up bit
oextra should have been included in the critical bytes
2025-04-15 15:49:36 -04:00
nhmall
a3e12550ea savefile changes - part 1
This is the first of several savefile-related changes to
follow later. This one is groundwork for those later changes.

Remove internal compression schemes (RLECOMP and ZEROCOMP)
and discard the savefile_info struct that was primarily used to
convey which internal compression schemes had been in use.

Relocate some struct definitions into appropriate header files
for use by code to come in later changes.

Remove the two struct size-related fields from version_info and
from the nmakedefs_s. Instead, include a series of bytes near the
beginning of the savefile, representing the size of each
struct or base data type that impacts the historical savefile
content. Those are referred to as the "critical bytes".
(Related note: the "you" struct required two bytes, low and high,
due to its size).

Compare those critical bytes in a savefile against the NetHack
build that is reading the savefile. This allows mismatch detection
early in the savefile-reading process, and a clean exit, rather than
proceeding to read nonsensical values from the file. Include some
feedback on what the first mismatch was when encountering
one.

For arrays stored in the savefile, use loop-logic in the core
to write/read the array elements one at a time, rather than in
a single blob. This will be required for changes to follow later.
(impacts artiexist[], artidisco[], svd.dungeons[], svl.level_info[],
svl.level.locations[][], msrooms[] field of mapseen, svb.bases[],
svb.disco[] objects[], svm.mvitals[], svs.spl_book[], svd.doors[],
go.oracle_loc[], utrack[], wgrowtime[])

This also adds data model to the long version information.

This invalidates existing save and bones files due to the changes in
the information at the start of the file.
2025-04-15 15:35:17 -04:00
Pasi Kallinen
197e6af78c Increment EDITLEVEL for silver maces 2025-04-09 21:26:22 +03:00
Pasi Kallinen
3cb7819c81 Split monster goal coordinate out of mstrategy field
Instead of packing a coordinate into unsigned long, store the goal in
a coord struct, making the code a bit cleaner.  Monster struct is
of course slightly bigger, but that should not really matter.
No change in monster behaviour.

Breaks saves and bones.
2025-02-16 10:46:21 +02:00
nhmall
c24786430f 'struct former' -> 'struct ebones'
Some variants were already using a similar approach
using a struct called 'ebones', so adopt the same naming
so NetHack-3.7, hardfought, and some variants are using
the same name.

As before there are fields in the struct that are not
currently used by NetHack-3.7, but the intent is that
hardfought save and bones files can be loaded by
NetHack-3.7 without code modification, for debugging
bug reports.

This invalidates existing save and bones files.
2025-02-04 15:16:42 -05:00
nhmall
d65d0062a9 follow-up: evolve placeholder content to match variant
suggestion by paxed

Increments EDITLEVEL again.
2025-02-02 12:53:58 -05:00
nhmall
d331029b03 more clobber-detection 2025-02-02 09:08:48 -05:00
nhmall
bda3437eab bump EDITLEVEL 2025-02-02 09:00:21 -05:00
nhmall
e08a9671dc another follow-up: another bit is needed
breaks savefiles and bones.
2025-01-12 14:08:15 -05:00
nhmall
35f2ca44e2 update year in COPYRIGHT_BANNER_A to 2025 2025-01-01 08:46:41 -05:00
nhmall
21d35e768c bump EDITLEVEL for previous two commits DEC19-2024 2024-12-19 17:54:55 -05:00
Pasi Kallinen
87694e1a95 Hero remembers trapped boxes
After finding a trap on a chest or a large box, remember it
as trapped: "You see here a trapped large box."
Randomly generated chests and boxes can be obviously trapped.
Allow defining obviously trapped containers via lua.

Invalidates saves and bones.
2024-12-19 13:11:25 +02:00
nhmall
1f8b75b8c6 different ls content values, so bump EDITLEVEL 2024-12-09 16:21:31 -05:00
Pasi Kallinen
89c4c3a722 Tourists gain experience by seeing new types of creatures up close
Experience equivalent to killing a monster is gained when starting a turn
adjacent to and being able to see the monster.

Breaks saves.

Idea and parts of code via dNetHack
2024-12-06 21:30:23 +02:00
PatR
d32ab55b84 new property: BLND_RES
Add enlightenment feedback for Sunsword's blocking of becoming blind
from light flashes.  It uses an extra property so that wizard mode
can report the reason.

EDITLEVEL is being incremented, so existing save and bones files are
invalidated.
2024-11-26 20:57:11 -08:00
PatR
11a4fe42de 'selectsaved' again - update EDITLEVEL again
The role, race, gender, and alignment string values are 3 letters
preceded by a dash.  I was looking at "name-race-role-gend-algn"
and mistakenly treated them as 4 letters preceded by a dash.

Fixing that changes PL_NSIZ_PLUS and there is one item of that size
written into save files, so the fix invalidates existing save files.
2024-10-11 22:35:38 -07:00
PatR
1f36b98b8f 'selectsaved' extension
Instead of a menu listing
 a - hero1
 b - hero2
 n - New game
 q - Quit
show
 a - hero1-role1-race1-gend1-algn1
 b - hero2-role2-race2-gend2-algn2
 n - New game
 q - Quit
or
 a - - hero1-role1-race1-gend1-algn1
 b - X hero2-role2-race2-gend2-algn2
 c - D wizard-role3-race3-gend3-algn3
 n - New game
 q - Quit
when any game in the list wasn't saved during normal play.  (Those
are sorted by character name; the playmode is just coincidence.)

The dash for 'normal' doesn't look great but -/X/D are codes used in
entries written to paniclog.  The whole playmode prefix doesn't look
particularly good but I suspect that most players relying on restore
via menu won't see it.

It should work when the character name has dashes in it but that
hasn't been properly tested.

The gender and alignment suffices reflect their value at the time of
save rather than at the start of the game.  That might be considered
a bug but it was easiest.

Increments EDITLEVEL; existing save and bones files are invalidated.
2024-10-10 23:14:25 -07:00
PatR
cf6509dde9 some reformatting (5 of 4)
Take care of most of include/*.h.  I punted on extern.h.

For both src/*.c and include/*.h, I used mismatched checks of
width > 79 to decide which files to look at and then width > 78
to decide which lines to maybe revise, so I didn't look at a bunch
of the files.

I don't plan to go back and do it right.  Shortening lines that are
80 or wider to less than 80 is the significant part.  Otherwise
emacs puts a backslash in column 80 and the rest of the line of text
on the next line of the screen, making things harder to read.
2024-09-06 13:08:07 -07:00
Pasi Kallinen
e645c0b4bb Allow starting game as pauper, without any inventory
And also without spells, skills, or preidentified items.
This also implies nudist.

Breaks saves and bones.
2024-08-29 20:51:13 +03:00
nhmall
6c0ae092c6 distinguish global variables that get written to savefile
The g? structs had a mix of variables that were written to
the savefile, and those that were not.

For better clarity and to distinguish those that end up in
the savefile, relocate some g? variables that get written
directly to the savefile into different structs.

This updates EDITLEVEL, although technically it probably
didn't need to, since savefile contents are not changing.

Details:

    gb.bases            -> svb.bases
    gb.bbubbles         -> svb.bbubbles
    gb.branches         -> svb.branches
    gc.context          -> svc.context
    gd.disco            -> svd.disco
    gd.dndest           -> svd.dndest
    gd.doors            -> svd.doors
    gd.doors_alloc      -> svd.doors_alloc
    gd.dungeon_topology -> svd.dungeon_topology
    gd.dungeons         -> svd.dungeons
    ge.exclusion_zones  -> sve.exclusion_zones
    gh.hackpid          -> svh.hackpid
    gi.inv_pos          -> svi.inv_pos
    gk.killer           -> svk.killer
    gl.lastseentyp      -> svl.lastseentyp
    gl.level            -> svl.level
    gl.level_info       -> svl.level_info
    gm.mapseenchn       -> svm.mapseenchn
    gm.moves            -> svm.moves
    gm.mvitals          -> svm.mvitals
    gn.n_dgns           -> svn.n_dgns
    gn.n_regions        -> svn.n_regions
    gn.nroom            -> svn.nroom
    go.oracle_cnt       -> svo.oracle_cnt
    gp.pl_character     -> svp.pl_character
    gp.pl_fruit         -> svp.pl_fruit
    gp.plname           -> svp.plname
    gp.program_state    -> svp.program_state
    gq.quest_status     -> svq.quest_status
    gr.rooms            -> svr.rooms
    gs.sp_levchn        -> svs.sp_levchn
    gs.spl_book         -> svs.spl_book
    gt.timer_id         -> svt.timer_id
    gt.tune             -> svt.tune
    gu.updest           -> svu.updest
    gx.xmax             -> svx.xmax
    gx.xmin             -> svx.xmin
    gy.ymax             -> svy.ymax
    gy.ymin             -> svy.ymin

Related note:
There are some pointer variables that are heads of chains that were not
moved from 'g?' to 'sv?', because they are not actually written to the
savefile directly, but the objects/monst/trap/lightsource/timer in the
chains they point to are. That can be changed, if desired.
Examples: gi.invent, gm.migrating_objs, gb.billobjs, gm.migrating_mons,
          gf.ftrap, gl.light_base, gt.timer_base
2024-07-13 14:57:50 -04:00
PatR
0e4083153c another EDITLEVEL increment
Since save and bones files just got clobbered, make another clobbering
change.  The 'queuedpay' field added to shop's ESHK(shkp)->bill[] was
replaced last week by a similar field in the transient itemizing bill.
At the time, the old field was left in place to avoid incrementing
EDITLEVEL.

shkp->mextra->bill[] is saved and restored, so its queuedpay field was
too.  Eliminate that no longer used field.

Unrelated:  bill[]->useup is declared as boolean but being assigned 1
or 0.  Change the assignments to use TRUE or FALSE.
2024-07-11 10:22:40 -07:00
Patric Mueller
b844632dfd bump EDITLEVEL for 0447a1f10
Commit 0447a1f10 accidentally broke save compatibility.
2024-07-11 16:35:24 +02:00
Pasi Kallinen
7139ee7446 Move light source and timer types so zero means none
Breaks saves and bones.
2024-05-06 19:58:21 +03:00
Pasi Kallinen
28ed8e7962 Unblind telepathy range
Unblind telepathy range depends on the number of telepathy granting
items worn.

Breaks saves.
2024-04-04 23:22:28 +03:00
RainRat
a3658f85ac fix typos 2024-02-28 20:15:56 -08:00
nhmall
b53a43027f generic obj addition broke obj entity count use
yet another EDITLEVEL bump
2024-02-28 16:24:40 -05:00
nhmall
3edd3e5869 catch invalid id on restore
Another EDITLEVEL bump.
2024-02-28 16:15:30 -05:00
nhmall
1a02a2df16 purge a couple of placeholders from context struct
Take advantage of today's EDITLEVEL bump, and add yet another to
remove some field placeholders left behind in when two fields were moved
elsewhere in 22e52ee9.
2024-02-28 15:54:34 -05:00
PatR
41a5565403 new 'showvers' option
Add options 'showvers' (boolean) and 'versinfo' (numeric mask) to
show nethack's version on the status lines during play.  It won't be
particularly interesting to ordinary players but should be useful
when making screenshots or video to be streamed, or for someone who
switches between git branches or between nethack and variants.

I worked on this several months back but it was combined with
unfinished changes to 'hitpointbar'.  I've separated it out so that
it can be put into use.  When enabled, one or more components of
"<name> <branch> <version>" will be shown right justified after
status conditions.  At present the default is "<branch>" if that is
available and overall status isn't 'released', or "<version>" if
'released' or if branch isn't available.  That might need some
refinement.

It works as intended for tty and curses, although some abbreviation
mechanism would be useful if/when the program resorts to abbreviating
status conditions to make things narrow enough to fit.

For X11, it works ok for fancy_status:True (the default, controlled
via NetHack.ad settings) but is messed up for tty-style status.  The
text is positioned correctly but there are gaps in it, making it
appear garbled, similar to what I saw when I tried and failed to
implement statuslines:3 for X11.  [It might be due to having empty
condition widgets be 1 pixel wide instead of being totally removed
but I don't think the situation is that simple.]

For Qt, if the text needs to be truncated in order to fit, the center
portion of the string will be shown, discarding parts from the left
and right.  That ought to discard from left and retain rightmost
portion instead.

For win32|mswin|Win GUI, no attempt to support it has been included.
Things should be ok when 'showvers' is left as False (the default)
but I don't know what will happen if that gets toggled to True.  At a
minimum, the version info won't be right justified.  The information,
or at least some of it, is displayed in the game window's title bar
so there isn't any pressing need to add it to status, but toggling
the option will need to behave sensibly if it doesn't already.
2024-02-28 11:47:16 -08:00
Pasi Kallinen
3160112ece Accessibility: Show a message when monster is spotted
Adds a new boolean option, spot_monsters.  If on, every time
the hero notices a monster which was out of sight before,
a message is given.  Combine with accessiblemsg to get the
monster location:

(3north): You see a newt.

Breaks saves and bones.
2024-01-14 13:33:02 +02:00
PatR
02c675078b PR #1150 - rework erinyes into avenging Furies
Pull request from entrez:  change erinyes from lame devils named
after the Furies of Greek myth into those Furies.

Bumps EDITLEVEL because of changes to saved data.  I augmented the
new data.base entry.

Closes #1150
2024-01-10 23:22:56 -08:00
nhmall
aeab3f69a6 update year in copyright to 2024 2024-01-01 11:04:26 -05:00
PatR
7a533a911c enhance timer sanity checks a bit
Four kinds of timers are defined but only two have ever been used.
Have sanity checking complain if the other two occur or if 'kind'
doesn't match any of the four.

Also, replacing a perfectly normal use of isok() with an inline test
just to pacify static analysis feels like a slippery slope, so handle
that a little differently.

I reordered the shrink_glob timer to put all object timers together.
Unfortunately that warrants incrementing EDITLEVEL which invalidates
existing save files.
2023-12-22 17:48:51 -08:00
Pasi Kallinen
1ceb9d2d91 Show menu when paying items
... and have more than 1 billed item, and using non-traditional
menustyle.

I opted to add an extra field to the bill struct, because
that made the code cleaner.

Breaks saves and bones.
2023-12-09 12:43:41 +02:00
PatR
c459630bf3 bump EDITLEVEL for nopick_dropped+pickup_stolen
Despite the tag on the pull request (#1140), I forgot to increment
EDITLEVEL to reflect the new options' affect on old save files.
2023-12-08 15:49:16 -08:00
Alex Smith
0d508cc936 Implement the spellbook of chain lightning
Prior to this commit, there was no good way to deal with swarms of
weak, good-AC enemies using magic; trying to play a wizard as a
pure spellcaster would make bees and ants very difficult to deal
with (because they would usually dodge force bolts).

This commit adds a new spell designed to be very good against
swarms of weak enemies: "chain lightning", which does 2d6 lightning
damage to every monster around you. It has an initially short range,
but can chain from monster to monster to cover potentially large
distances (as long as none of the monsters en route are shock
resistant or tame/peaceful; the spell can't chain past shock
resistant monsters and avoids peacefuls). Monsters within one
space of the visible lightning bolts are affected. Unlike other
lightning effects, this one does only 2d6 damage, not enough to
blind affected monsters.

This commit breaks existing save and bones files (thus the
EDITLEVEL increase).
2023-12-06 20:02:35 +00:00
Pasi Kallinen
d8421aa219 Save and restore hero tracks
The tracks left by hero were cleared when player saved and
restored the game, or changed levels.  Now the tracks are
saved in the dungeon level, so changing levels keeps the tracks
left by hero in that level.

Also increased the length of tracks from 50 to 100, and
simplify the tracking function.

Thing not done: fade out old tracks when returning to a level.

Breaks saves and bones.
2023-12-04 17:50:48 +02:00
nhmall
3c82780c1c bump patchlevel for u field addition 2023-12-02 11:31:58 -05:00