There was a transcription error in the comments in cstd.h for
the standard list of header files, where only the description
remained for <stdlib.h>, not the name of the file itself.
Remove several extraneous inclusions of the standard C99 headers.
Tested on the following afterwards:
Linux (using hints/linux.370) including tty, curses, qt6, and X11
macOS (using hints/macOS.370) including tty, curses, qt5, and X11
Windows MSYS2 using sys/windows/GNUmakefile
Windows Visual Studio using sys/windows/Makefile.nmake
msdos cross-compile on Ubuntu using djgpp cross-compiler
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.
Changes to setuhpmax() a couple of days ago to deal with sanity_check
for "current hero health as monster better than maximum" ended up
triggering sanity_check about "current hero health better than maximum"
when gaining experience level(s) while polymorphed.
being greater than u.mhmax
I think this will fix the situation where current HP as a monster
was greater than maximum HP as a monster, triggering a sanity_check
failure. No promises though.
[poisoned() needs some missing Upolyd handling.]
Sanity check failure generated by running the fuzzer, reported
by mkuoppal. The check discovered that the hero's current hit
points were greater than the maximum.
Comments by elunna pointed out where the problem most likely was,
and this attempts to fix the situation, but without a test case
I can't be sure that the fix works.
Both cases being fixed are for formerly fatal incidents (random
chance that poison is fatal, monster touch of death spell) being
'softened' to heavy HP damage (including reduction of maxHP).
The earlier commit I made (045d608) was done without having seen
the relevant comments. It didn't fix anything but did attempt
to make finding the problem(s) easier. It wasn't much help.
Fixes#1252
I recently realized that I've been editing sources in a terminal
window that was widened in order to fit curses borders for testing
something or other. That has resulted in some new wide lines in the
source. There were lots of old ones too.
This updates some source files to try to achieve the goal of 78
characters or less. As in the past, I've been inconsistent about
lines with 79 characters. Lines with 80 or more have been wrapped
or shortened (usually by trimming an end of line comment or removing
redundant parantheses, sometimes just by reducing the indentation
of the continuation portion of an already wrapped line).
I eliminated one instance of warning manipulation for non-constant
format string, and simplified stone_luck() where Ken had a silly
comment about the function argument's name.
Reported by ars3niy, the curses interface could behave strangely on
the first turn if the 'pauper' option/conduct was specified.
There isn't any definitive flag indicating whether or not the game
has started. Since 'moves' has traditionally been initialized to 1
rather than to 0, there were several instances of
| if (moves <= 1 && invent != NULL)
being used to determine the starting state on the assumption that
once hero has inventory, the game has begun. Introduction of the
'pauper' option made the test for non-Null invent become unreliable.
For paupers, the program would behave as if the game hadn't started
yet until the player finally made a time-consuming move.
This changes compile-time initialization of 'moves' from 1 to 0,
then sets it to 1 when initial inventory would be bestowed (even
when 'pauper' inhibits that). That's probably not the best place
for it, but testing for 'moves==0' now should produce an identical
effect as 'moves<=1 && invent!=NULL' used to accomplish.
It would have been much simpler just to give paupers 1 gold piece,
or perhaps one rock, in place of usual starting gear so that their
initial inventory wouldn't be empty, but the moves+invent way of
checking for start-of-play has always bothered me.
Should 'pauper' be preventing 'nethack -X' from giving its starting
wand of wishing? Conducts and explore mode don't really overlap so
maybe it doesn't matter.
Fixes#1275
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
The recent acurr() changes introduced a bug that caused Str less
than 25 to be limited to 18/07. 25 was treated correctly as a
special case but 18/01 through 18/100 and 19 through 24 were not.
The cap of 25 imposed on the other characteristics is the same as
encoded Str 18/07.
When not on Astral, make it a roll based on alignment abuse whether an
erinys is summoned. Also make helm of opposite alignment use contribute
to alignment abuse, so that repeated uses to attempt to clear erinyes
before astral will make them stronger.
A helmet psychically reaching inside your head and twiddling knobs in
your brain must be a confusing experience. And the instant rejection of
your god (not to mention the vow that you made to find the amulet for
them), perhaps on the very cusp of their ascendance over the other gods,
is sort of the ultimate oathbreaking, so it interests the erinyes.
Consistent with their mythological role of punishing those who had
violated societal taboos -- oathbreakers, hosts who attacked their
guests, etc -- erinyes scale with the cumulative amount of alignment
abuse the hero has committed over the course of the game. This is
tracked separately from the alignment record, and cannot be cleared by
the hero improving her favor with her god via "good deeds" as the normal
alignment record can. Erinyes will gain abilities, levels, and attacks
as the hero's alignment abuse worsens. They will also aggravate
monsters when near the hero.
Replace the early returns in acurr() and acurrstr(), eliminating a
bunch of casts. I hope this doesn't reintroduce 'WIN32_BUG' (judging
by the previous workaround, I think that's extremely unlikely).
Also add an introductory comment to newhp().
I was working on this at the time 3.6.0 was released and set it aside
until later. Later has finally arrived. Redo the Blind, Blinded,
Blindfolded,&c macros to make more complete use of intrinsic property
handling. Blinded was being treated as a number which could be added
to or subtracted from; now that has to be done via TIMEOUT mask
because it has FROMOUTSIDE (OPTIONS:blind) and FROMFORM (poly'd into
!haseyes() form) bits included. Object definitions for blindfold and
towel now specify the BLINDED property; overriding blindness via the
Eyes of the Overworld is accomplished via props[BLINDED].blocked.
Code generated for the scores of Blind and !Blind tests throughout
the program should be smaller.
One bug that has been fixed is that putting on the Eyes of the
Overworld cured permanent blindness (from OPTIONS:blind). The
u.uroleplay.blind flag was cleared and stayed so after taking them
off. Putting the Eyes on still breaks blind-from-birth conduct but
now blindness will resume when they are removed.
This was untested at the time it was set aside and is only lightly
tested now. A large number of the changes here are just to switch
from Blinded to BlindedTimeout for current timed value and to call
set_itimeout() for setting a new value.
I felt it was strange that archeologist started out both
fast and stealthy, but didn't gain searching until level 10.
So, archeologists now start with searching, gain stealth at 5,
and fast at 10.
Similarly valkyries starting out stealthy felt odd, so now they'll
get it at level 3.
This leaves only the rogue starting out innately stealthy, which
feels appropriate.
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
^ ^
When strength loss is so big as to cause HP damage, but reduce
strength if the damage causes hero to revert to normal form. There's
no point in adjusting strength before rehumanization and not fair to
do so afterward.
Also, validate strength and its intended adjustment before doing
anything else. (Just paranoia; there's no reason to suspect that any
bad data ever gets passed in.)
Try again to make losestr() do what's intended. If it would take
strength below 3, it takes away HP and max HP instead. If hero is
poly'd, those come from the hero-as-monst values. If hero was
poly'd but isn't any more, hero-as-monst died and rehumanized as
previous self; leave max HP alone. If hero wasn't poly'd, take
HP and max HP from their usual values, but don't take max HP below
the threshold of minimum max HP (experience level times 1). The old
check for max HP going below minimum can't happen anymore, unless
hero was below that threshold already (which shouldn't happen; if it
does somehow, don't punish hero further).
If this still isn't right, I'll throw up my hands and my lunch.
Refine pull request #802 by entrez. Applying damage within a loop
could potentially damage the hero multiple times, maybe using up
an amulet of life saving and then killing hero anyway, or causing
rehumanization and taking further HP from normal form, or both,
causing rehumanization and then using up amulet of life saving.
Accumulate the damage in the loop and then apply it as a unit.
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).
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.
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>".
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
Switch to using a macro invocation Verbos(n, s) in place of the
flags.verbose checks.
Provide the mechanics for individual suppression of any of the
existing messages that were considered verbose.
Mechanics only - this code update does not provide any means of
setting the suppression bits.
iflags.verbose = 0
is still a master suppression of all the verbose messages.
iflags.verbose = 1
turns on the verbose messages only for those whose suppression
bit is 0 (not set).
Issue #752 by vultur-cadens: initialization of characteristics had
off by one errors when reducing over-allocation and when increasing
under-allocation, biasing Str over Cha.
This simplifies the code very slightly but it still seems somewhat
confusing to me.
A couple of reformatting bits are included.
Closes#752
Life-saving has been setting u.uhpmax to max(2 * u.ulevel, 10)
and if it took place during level drain that could make u.uhpmax
increase instead of decrease, confusing healing which gets applied
to a monster who has drained the hero with Stormbringer or the
Staff of Aesculapius. Change the setting to be max(u.ulevel, 10)
(removing the times two part) and also have level drain force it
to be set back to previous value if/when it gets increased.
Max HP loss due to strength trying to drop below 3 or to fire trap
or to being hit by Death now uses a mininum max HP of u.ulevel
rather than 1. They don't have the alternate minimum of 10; I'm
uneasy that there are still two different minimum values.
I changed adjattrib() to set the flag to request a status update
before it gave its optional message rather than after so that the
new characteristic value would be visible during the message. That
resulted in not updating status when eating royal jelly changed HP
or max HP after boosting strength. But the same missing update
would have occurred--or rather, failed to occur--without the change
in sequencing if the strength boost causes a change in encumbrance.
Add a type to force g.{command_count,last_command_count,multi} to have the
same type (because cmd.c: g.multi = g.command_count;) and some resulting
cleanup.
Log game events, such as entering a new dungeon level, breaking
a conduct, or killing a unique monster, in a new "Major events"
chronicle. The entries record the turn when the event happened.
The log can be viewed with #chronicle -command, and the entries
also show up in the end-of-game dump, if that is available.
This feature is on by default, but can be disabled by
defining NO_CHRONICLE compile-time option.
This also contains "live logging", writing the events as they
happen into a single livelog-file. This is mostly useful for
public servers. The livelog is off by default, and must be
compiled in with LIVELOG, and then turned on in sysconf.
Mostly this a version of livelogging from the Hardfought server,
with some changes.
The priest/cleric quest provides unlimited wraiths and a player
(not a robot with limitless patience) posting on reddit gave up
building up his character by killing them and eating the corpses
after accumulating 40K HP and 20K En. (Or something close to that;
I can't get back to the post right now.) His character might have
been capable of surviving decapitation or bisection.
Make it very much harder to get to 5 digits of HP or En via level
gains after reaching level 30. If maxhp < 300, new gains will be
capped at 5 extra HP; 300..599, cap is 4; 600..899, cap is 3;
900..1199, cap is 2; and once 1200 is reached, further level gains
will only add 1 HP. For maxen < 200, extra En is capped at 4;
200..399, cap is 3; 400..599, cap is 2; and once 600 is reached,
further gains only add 1 En. Note: this only kicks in when gaining
levels while already at level 30.