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.
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
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
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.
Adds a more general way to handle gameplay tips, and adds
a boolean option "tips", which can be used to disable all
tips. Adds a helpful longer message when the game goes
into the "farlook" mode.
Also adds a lua binding to easily show multi-line text
in a menu window.
Breaks save compat.
Redo the details about giving or suppressing "with great effort you
push the boulder". It works the same except that if push a different
boulder than previously, you'll get a new message. If you do it
while riding, you have the same lack-of-message for successive pushes
instead of getting a message every turn.
Don't exercise strength when pushing a boulder if poly'd into a giant.
The consolidation of global variables from scattered source
files into decl.c and declared in decl.h was begun in 3.7.0.
Their placement in common files was done for centralized
initialization and potential re-initialization during a
"play again" scenario.
It wasn't really necessary for all of them to be housed in a
single huge structure to meet the "play again" requirement,
and the single huge structure has been a little unwieldy when
it comes to maintenance.
Following this commit, instead of one single extremely large structure
named 'g' to house all of the relocated global variables, they
are distributed into several ga through gz.
To make things easy for the developer, each variable is placed
into the struct corresponding to the starting letter of the variable.
That way, no lookup is required in order to know which struct houses
a particular variable, it is a simple match to the starting letter
for all the centralized global variables.
A global variable named 'amulets', would be found in ga.
ga.amulets
^ ^
A global varable named 'move', would be found in gm.
gm.moves
^ ^
A global variable named 'val_for_n_or_more' would be found in gv.
gv.val_for_n_or_more
^ ^
A global variable named 'youmonst' would be found in gy.
gy.youmonst
^ ^
One of the drivers of this change was that screen coordinates require a
type that can hold values greater than 127. Parameters to the window
port routines require a large type in order to be able to have values
a fair bit larger than COLNO and ROWNO passed to them, particularly for
their use to the right of the map window.
This splits the uses of xchar into 3 different situations, and adjusts
their type and size:
xchar
|
-----------------------
| | |
coordxy xint16 xint8
coordxy: Actual x or y coordinates for various things (moved to 16-bits).
xint16: Same data size as coordxy, but for non-coordinate use (16-bits).
xint8: There are only a few use cases initially, where it was very
plain to see that the variable could remain as 8-bits, rather
than be bumped to 16-bits. There are probably more such cases
that could be changed after additional review.
Note: This first changed all xchar variables to coordxy. Some were
reviewed and got changed to xint16 or xint8 when it became apparent that
their usage was not for coordinates.
This increments EDITLEVEL in patchlevel.h
Demote "completed sokoban {1,2,3,4}" from major achievement to minor
at the request of hardfought. OR on the 'dump' flag so that those
entries appear in dumplog.
Change "completed Sokoban" (for the whole branch) to "acquired the
Sokoban <prize object>" since that's what triggers the event and it
is possible to pass through the first level without completing that.
This event is still classified as a major achievement. It has has
the 'spoiler' flag added to prevent #chronicle from showing that event
which now discloses the type of item the prize is. (Note: suppression
of spoiler events is ignored in wizard mode.)
The "attained rank N" achievements are classified as minor for ranks
1..3 (gaining levels 3, 6, 10); OR the 'dump' flag for those. [Rank 0
for levels 1 and 2 isn't an achievement and 4..8 for Xp levels 14, 18,
22, 26, and 30 are classified as 'major' achievements so don't need
that flag to make it into dumplog.]
In the name of accessibility: Prevent moving into dangerous liquids.
Now with themed rooms, water and lava are more common, and it's
unreasonable to expect blind players to check every step for those.
With paranoid:swim, just prevent normal walking into those liquids,
unless you prefix the movement with 'm', or if the liquid would not
harm you.
Doesn't completely prevent an accidental dunking - for example
if the hero is impaired or couldn't see the liquid.
This comes from xNetHack by copperwater <aosdict@gmail.com>
with some changes to the code.
'moves' is actually turns and there hasn't been any straightforward
way to track actual hero moves. Add hero_seq for that. It isn't a
counter but is distinct each time the hero makes a move. I wanted
it for curses ^P support but so far use it for checking stethoscope
usage and for shopkeeper behavior when items in a shop are broken by
the hero.
Increment EDITLEVEL due to change in save file contents.
Instead of inexplicably paralyzing the player for the duration of their
engraving. Many a character has died by trying to engrave something and
then sitting there diligently writing it while monsters surround and
attack them. (This was especially prominent back in the 3.4.3 era when
repeated Elbereths were viable, but it still occurs today with e.g.
using a hard stone to engrave Elbereth). There were also some other
oddities - for instance, if something teleported the player away while
they were engraving, they would continue to "engrave" (be paralyzed) on
their new location, but would not produce any text there; the full
engraving would be placed on their initial position.
In this commit, I have converted engraving to use the occupation
framework, which treats it as an interruptible activity. This
necessitated some logical restructuring, mostly involving the engraving
being written out in chunks as the player spends more uninterrupted time
on it.
I've tried to keep this free of regressions except for those inherent to
the occupation system.
What has NOT changed:
- The rate of engraving is still 10 characters per turn, or 1 character
using slow methods.
- The formulas for determining how much a bladed weapon or marker can
engrave before getting exhausted are kept. Though this is a bit
convoluted, and if it's not considered important to preserve the
existing behavior, I would recommend simplifying it by decreasing the
maximum engraving length for weapons by 1 so that each point of
enchantment simply gets you 2 characters' worth of engraving (e.g. a
-2 weapon will only engrave 1 or 2 characters before dulling to -3,
rather than giving it a third "grace character".
- The input buffer is still modified based on confusion/blindness/etc
only at the time when the player inputs it (if they gain a
debilitating status while engraving, it will not affect the text). My
personal preference is to make the text affected in scenarios like
that, but it's not strictly necessary to do here, so I didn't.
- Wand messages such as "The floor is riddled by bullet holes", and
blinding from engraving lightning, still appear before the hero starts
to take any time engraving. As noted above, getting blinded by the
wand still has no effect on accurately engraving the text, unless the
hero was already blind or impaired.
What has changed:
- Moving off the engraving or losing the object being engraved with
causes the player to stop engraving.
- Wands can still engrave an arbitrary amount of text using a single
charge, but if the hero is interrupted and decides to start engraving
again, they will consume a second charge.
As it adds a new field to g.context, this is a save-breaking change.
Introduce eight achievements that can be attained by more players.
Entered Gnomish Mines - self explanatory
Entered Mine Town - the town portion, not just the level
Entered a shop - any tended shop on any level
Entered a temple - likewise for temple
Consulted the Oracle - bought at least one major or minor oracle
Read a Discworld Novel - read at least one passage
Entered Sokoban - like mines
Entered the Big Room - not always possible since not always present
The novel and bigroom ones aren't always achieveable since novels are
only guaranteed if a book or scroll shop gets created and bigroom is
only guaranteed in wizard mode. No one ever claimed that every
possible achievement can be attained in a single game. (If one for
entering the Fort Ludios level--or perhaps entering the Fort itself--
eventually gets add, that won't be possible in every game either.)
The mine town one probably needs some tweaking. Two of the town's
seven variants have no town boundary (despite a rectangular area of
pre-defined map) and at present simply arriving on either of those
levels is enough to be credited with the entered-town achievement.
Bump EDITLEVEL because u.uachieved[] has increased in size. This
time it has been expanded to the maximum that xlogfile's bitmask of
achievements can handle, enough for up to 9 more achievements without
another EDITLEVEL increment.
Instead of hardcoding the "prize" type and then watching for that
to be created, specify it in the level description.
Also, instead of giving both Sokoban end levels 50:50 chance for
either prize, bias the one that used to always have the bag of
holding to now have 75% chance for that and 25% chance for amulet
of reflection, with the other one having those chances reversed.
So still 50:50 overall.
This turned out to be a lot more work than I anticipated, but it is
definitely simpler (other than having #wizmakemap take achievements
away if you replace the level that contains the 'prize', which wasn't
handled before).
I cheated and made Mine's End into a no-bones level because the new
flagging scheme for luckstone, bag, and amulet can't carry over from
one game to another. It probably should have been no-bones all along.
Sokoban didn't have this issue because it's already no-bones.
Existing save files are invalidated.
When the hero has random clairvoyance, the code used
| (moves % 15) == 0 && rn2(2) != 0
(where 'moves' is actually the turn number) to decide when it would
kick in and show a portion of the map. If the hero was fast enough
to get an extra move when the turn value met the (moves % 15) == 0
condition then clairvoyance could happen twice (or more if poly'd)
on the same turn.
The changes (one new field, reordering a few others) in 'struct
context' invalidate existing 3.7.0-x save files.
Fixes#266
Izchak implemented the mysterious force and as far as I'm concerned,
it's here to stay. But it can be fine tuned. This is an experimental
attempt to make it happen less. Each time it happens, the chance for
it happening again later will usually go down by an amount proportional
to how far it sent the hero back. So chaotics will be sent back--or
"side to side"--less often than in 3.6.x but the tapering off of such
occurrences will be slower for them. Lawfuls will also be sent back
less often--still potentially farther down than others--but tapering
off of send backs for them will be quicker.
I'll let somebody else figure out the before and after values for
number of attempts to climb up it takes to finally get out of Gehennom.
The numbers might need tuning.
I was thinking about iflags rather than context and didn't realize
that the change to maxinum number of passages would breal save files.
Put the tribute context back to 3.6.0 size.
Anyone who grabbed from public git yesterday is potentially in for
some temporary trouble. That's the risk they take for trying to stay
on the bleeding edge.
Death Quotes have reached the current limit of 30 passages per 'book'.
Instead of increasing that, change the selection code to be able to
operate on a subset (dropped from 30 down to 20) at a time while
keeping the excess available for later selection.
Chatting with Death (more than 20 times since he also delivers non-
tribute messages) should cycle through 20 of his 30 passages without
repeating. After that, another subset of 20 out of the 30 will be
chosen, independent of the first set so might contain all, some, or
none of the 10 that left out before.
When reading a novel, select a random passage which hasn't been shown
already. Once you've run through all the passages, it resets to get
them all again (with new random order that might happen to the be same
order if there aren't many passages). Switching to a different novel--
even another copy of the same one--will cause the previous passage
selection to be discarded and restarted from scratch if the prior book
is read again. Passage tracking for the most recently read novel is
kept across save and restore. (That means I needed to bump EDITLEVEL,
so it will need to be reset to 0 again before release.)
Replace the code that Dean objected to with something a little bit more
robust. It doesn't rely on the two stacks being adjacent or having the
same inventory letter. It is still vulnerable to having another
splitobj() occur between the offending split and its attempted unsplit,
or to either of the two halves of a split being extracted from their
object chain. As before, failure to unsplit only results in the two
halves of the split remaining separate stacks, not anything more drastic
like the panic() that prompted all this.
Simplification of hallucinated currency names got mixed in with this
patch. I haven't bothered separating it back out.
Whoever reset PATCHLEVEL to 0 jumped the gun. This patch increments it
since change to the 'context' structure breaks save file compatibility,
so it will need to undergo another reset before release.
Changes to be committed:
modified: include/context.h
modified: include/extern.h
modified: src/files.c
modified: src/invent.c
modified: src/sounds.c
modified: src/spell.c
Add a couple more tribute easter eggs.
- can lead to a remark by Death if you happen to have a pratchett book on
your person, as suggested by M. Stephenson (fat chance you will, or
think to #chat if you do, but it could be a tournament novelty or something
obscure to strive for).
- can draw some additional Death quotes from the tribute file. (There's two
in there right now. If anyone wants to add or suggest some more, please go
ahead. The Death quotes are at the end of the tribute file. One-liners
only please or the code will only pull the last line.
I did my best to exempt some of the bigger aligned blocks from the reformatting
using the /* clang-format off */ and /* clang-format on */ tags. Probably some
that shouldn't have been formatted were anyway; if you encounter them, please
fix.
The clang-format tags were left in on the basis that it's much easier to prune
those out later than to put them back in, and it means that, modulo my custom
version of clang-format, I should be able to run clang-format on the source tree
again without changing anything, now that Pat has fixed the VA_DECL issues.
Pat noted that I neglected to drop the SCCS lines on the files I've been
committing, so clean up those and any others I could find where the SCCS
line date is out of date.
I almost abandoned this when Michael beat me to it, but besides
handling the fruit rename bug it also moves `current_fruit' into the
context structure to eliminate separate save/restore for that.
There is a quote in data.base for squeaky board traps:
A floorboard creaked. Galder had spent many hours tuning them,
always a wise precaution with an ambitious assistant who walked
like a cat.
D flat. That meant he was just to the right of the door.
"Ah, Trymon," he said, without turning, and noted with some
satisfaction the faint indrawing of breath behind him. "Good
of you to come. Shut the door, will you?"
[ The Light Fantastic, by Terry Pratchett ]
This patch makes each squeaky board trap on a level produce
a unique sound. If you had visited the trap yourself prior
to hearing a monster on it, you could actually know where
a monster was by the unique pitch of the squeak.
If someone wants further refinement of the roles, this could
be adjusted to only work for musically adept roles/species,
with the others only hearing a generic squeak. As it stands
right now, everyone benefits. Does anyone thing the
separation by role or species would be good? If so, which
roles/species are musically proficient, and which are not?
Since this patch increments editlevel anyway, it also sneaks in a
context structure change for an upcoming patch.