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
^ ^
For nethack -s name1 [name2 [name3]]
allow any or all of the name arguments to be preceded by -u. Both
'-u name1' and '-uname2' forms are accepted same as when specifying
character name at start of play.
It has been accepting '-s<anything>' and ignoring the <anything>.
Treat such as a separate argument instead. That means it will accept
'-s-v' which is silly but if used intentionally, <anything> would most
likely be a name.
'nethack -s' without any character name(s) supplied and PERS_IS_UID
set to 0 now defaults to "all" instead of to "hackplayer". For Unix,
the default name will be in place, so that gets used instead of "all".
'nethack -s all' or 'nethack -s -u all' can be used to see all scores.
When no matches are found, feedback is a full sentence but terminating
punctuation was omitted except for the special case of "Cannot find
any entries for you." Add the final period all the time.
Instead of using index() macro defined to strchr, use C99 strchr.
Instead of using rindex() macro defined to strrchr, use C99 strrchr.
If you want to try building on a platform that doesn't offer those
two functions, these are available:
define NOT_C99 /* to make some non-C99 code available */
define NEED_INDEX /* to define a macro for index() */
define NEED_RINDX /* to define a macro for rindex() */
Lay groundwork for generating a log event when finding an artifact
on the floor or carried by a monster. This part should not produce
any change in behavior.
Move g.artidisco[] and g.artiexist[] out of the instance_globals
struct back to local within artifact.c. They are both initialized
at the start of a game (and only used in that file) so don't need
to be part of any bulk reinitialization if restart-instead-of-exit
ever gets implemented.
Convert artiexist[] from an array of booleans to an array of structs
containing a pair of bitfields. artiexist[].exists is a direct
replacement for the boolean; artiexist[].found is new but not put to
any significant use yet. If will be used to suppress the future
found-an-artifact event for cases where a more specific event (like
crowning or divine gift as #offer reward) is already produced.
Remove g.via_naming altogether and add an extra argument to oname()
calls to replace it.
Add an extra argument to artifact_exists() calls.
Use up the last available bit for achievements:
"You learned the tune to open and close the castle's drawbridge."
(More can still be added but xlogfile will need another field to
track a second set of 31 in order to keep its achievement bitmask(s)
within portable size.)
As achievements go, it's not very exciting, but players who normally
destroy the drawbridge have to choose whether to earn an achievement
first since once it's gone, there's no way to find out the tune
(either via prayer reward or successful Mastermind). I'm guessing
that most will probably decide to ignore this achievement since it
has no effect on the outcome of the game. However, that might not
be true for future tournament play.
There's no need to bump EDITLEVEL for this; room for recording one
additional achievement is already allocated.
This fixes the broken code that was using a boolean as an integer.
I didn't try to track down when it changed or what it looked like
before the change. The intended effect is fairly straightforward;
just padding a bold line with spaces. I've no idea why someone
deciced that that was useful though.
It also fixes something I broke six years ago: tty_exit_nhwindows()
releases the termcap data needed for turning bold on and off, so
raw_print_bold() used by topten() stopped working on tty then.
Not fixed: the code in really_done() for dealing with topten() vs
the 'toptenwin' option really ought to be redone.
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.
The code has been assuming that time_t is some number of seconds.
That's valid for traditional Unix systems and for Posix compliant
systems but is not something guaranteed by the C standard. (We ran
into a long time ago when trying out an alternate way to calculate
phase of moon. That code made a similar assumption and broke one
of the ports.)
'ubirthday' also warrants being re-done but I've run out of energy.
'final_fpos' shouldn't have been moved to the 'g' struct. Even if
a game went all the way through topten and was restarted as a new
game that also went all the way through topten, 'final_fpos' would
get a new value rather than being messed up by a stale old one.
From a beta tester six years ago: specifying 'scores:own' resulted
in an option setting of 'scores:3 top/2 around/own' when player
wanted 'scores:0 top/0 around/own'. Change it so that when fewer
than all three fields are given new values, the others are reset
rather than having their old values merge with new settings.
Also, 'scores:none' can be used to get 'scores:0 top/0 around/!own'
to skip the scores at the end without skipping notification of
whether the ending game's score made it into the top N list.
Options parsing accepts '!scores' and then ignores the negation.
Changing the optlist flags for 'scores' to allow negation resulted
in a complaint about missing value; I gave up instead of pursuing
that. 'scores:none' should suffice.
Setting 'scores:!top/own' or 'scores:!around/own' would behave as
'scores:1 top/!own' or 'scores:1 around/!own', respectively.
'scores:!top/!around/own' behaved as 'scores:1 top/1 around/own'
(note affect of two prior negations on final field compared to
single negation in the earlier two variations). This fixes those.
Whitelist all the verified existing triggers:
makedefs.c: In function ‘name_file’
attrib.c: one compiler balks at a ? b : c for fmtstring
cmd.c: In function ‘extcmd_via_menu’
cmd.c: In function ‘wiz_levltyp_legend’
do.c: In function ‘goto_level’
do_name.c: In function ‘coord_desc’
dungeon.c: In function ‘overview_stats’
eat.c: one compiler balks at a ? b : c for fmtstring
end.c: one compiler balks at a ? b : c for fmtstring
engrave.c: In function ‘engr_stats’
hack:c one compiler balks at a ? b : c for fmtstring
hacklib.c: one compiler balks at a ? b : c for fmtstring
insight.c: one compiler balks at a ? b : c for fmtstring
invent.c: In function ‘let_to_name’
light.c: In function ‘light_stats’
mhitm.c: In function ‘missmm’
options.c: In function ‘handler_symset’
options.c: In function ‘basic_menu_colors’
options.c: In function ‘optfn_o_autopickup_exceptions’
options.c: In function ‘optfn_o_menu_colors’
options.c: In function ‘optfn_o_message_types’
options.c: In function ‘optfn_o_status_cond’
options.c: In function ‘optfn_o_status_hilites’
options.c: In function ‘doset’
options.c: In function ‘doset_add_menu’
options.c: In function ‘show_menu_controls’
options.c: In function ‘handle_add_list_remove’
pager.c: In function ‘do_supplemental_info’
pager.c: In function ‘dohelp’
region.c: In function ‘region_stats’
rumors.c: sscanf usage
sounds.c: In function ‘domonnoise’
spell.c: In function ‘dospellmenu’
timeout.c: In function ‘timer_stats’
topten.c: In function ‘outentry’, fscanf, sscanf, fprintf usage
windows.c: In function ‘genl_status_update’
zap.c: one compiler balks at a ? b : c for fmtstring
win/curses/cursstat.c: In function ‘curses_status_update’
win/tty/wintty.c: In function ‘tty_status_update’
win/win32/mswproc.c: In function ‘mswin_status_update’
- record number of encountered bones levels in xlogfile
- add bonesless to extended conducts field in xlogfile
- show bones levels information in enlightenment at end of game or in
explore and wizmode
Gcc 9 has become more vocal with sprintf buffer overflow
checking. Remove these sprintf warnings by changing the
offending calls to a snprintf wrapper that will explicitly
check the result.
When SCORE_ON_BOTL is enabled, you could tell how much gold is
inside a container with unknown contents by having 'showsore' On
and watching how much the score changed on the status line when
picking the container up.
Record reaching experience level 3, 6, 10, 14, 18, 22, 26, and 30,
the levels where the character gets a new rank title, and report
those as achievements at end of game. These achievements persist
even if enough levels to lose a rank are lost, and if lost ranks
are regained the original achievement is the one that gets tracked
and disclosed.
Introducing two new xlogfile fields "achieveX" and "conductX" which encode
achievements and conducts as a series of comma-separated strings which are
more easily parseable and also somewhat interpretable independent from knowing
the source code.
Example for a player that died shortly after picking up the luckstone from the
gnomisch mines:
achieveX=entered_the_gnomish_mines,entered_mine_town,entered_a_shop,entered_a_temple,obtained_the_luckstone_from_the_mines
conductX=polyless,polyselfless,wishless,artiwishless,genocideless
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 an assortment of bits, assign numeric indices to the
potential achievements and keep an array of those in the order they
were attained. So disclosure might show the same subset occurring
differently in different games depending on the player's actions.
The encoded field in xlogfile doesn't care about that and remains
the same.
Modifies 'struct u', so EDITLEVEL has been incremented and existing
save files are invalidated.
When disclosing conduct at end of game (but not during except in
wizard mode), display achievements too. They're also included in
dumplog if it's enabled. Previously they were only output as an
extra field in xlogfile.
Prevent extremely long command line arguments from overflowing local
buffers in raw_printf or config_error_add. The increased buffer
sizes they recently got to deal with long configuration file values
aren't sufficient to handle command line induced overflows.
choose_windows(core): copy and truncate the window_type argument in
case it gets passed to config_error_add().
process_options(unix): report bad values with "%.60s" so that vsprintf
will implicitly truncate when formatted by raw_printf().
Dungeon level wasn't included in ^X output, so it wasn't actually
giving all status fields and attempting to rely on it when turning
off 'status_updates' was leaving a gap in feedback for the player.
Add an extra line to the first section where character's name and
patron deity are reported, giving current location.
|You are in the Dungeons of Doom, on level 5.
or
|You are in the endgame, on the Elemental Plane of Fire.
The information is more explicit than the basic status field, but
you can already get similar information via #overview so it isn't
giving away extra info.
Augmented death reason with appended "while <helpless-reason>" was
broken in 3.6.0 and got fixed shortly after release (too late to
prevent high-score files from being corrupted). Then within a
couple of weeks it got broken again, and doesn't work in 3.6.1
either (but in this case, it is omitted instead of being cloned
to all following score entries). The problem is in both record
and logfile, but not xlogfile, so we could create a fix up routine
that would use the last to repair record (and perhaps logfile).
But having two fixup routines would probably lead to confusion.
The problem this time was bad logic in the fix for
|alter name of monster causing hero's death if name contains
| characters that could cause confusion when using record,
| logfile, or xlogfile later
killerformat() was going out of bounds of the input string and
using up all of 'siz' so that there was never room to append the
", while helpless" suffix.
Prevent commas, equal signs, and tabs in reason for death. Comma
can make while-helpless reason ambiguous in record and basic logfile.
Equal sign can do the same for fixrecord.awk, the awk program that
can be used to fix up corrupted 3.6.0 record files, if it resorts to
constructing logfile records out of xlogfile records. And tab could
break parsing of xlogfile (it should already be excluded though; the
code that lets players assign names to monsters uses mungspaces(), and
one of the things that does is to convert any tab into a space before
squeezing consecutive spaces down to one).
The name alteration shows up for tombstone as well as for file entries.
That could be changed but hardly seems worth the effort. Perhaps the
name sanitizing ought to be moved to the initial naming? At least then
it would be pretty obvious that it was intentional rather by mistake.
Avoid the possibility of a user-supplied name interfering with killer
reason truncation. A monster named ", while" that killed the hero
would result in "killed by <mon-type> called " being displayed on the
tombstone after stripping while-helpless reason to shorten the text.