Issue reported by Umbire: if a mind flayer got turned to stone by
hitting a hero who is polymorphed into a cockatrice and the first
tentacle drain missed but a subsequent one hit, any remaining ones
would keep being applied even though the mind flayer was dead.
This works but doesn't feel right to me. A more substantial change
to mhitm_ad_drin() didn't work as expected so I've settled for this.
Fixes#1378
gcc has recognized various "magic comments" for white-listing
occurrences of implicit fallthrough in switch statements for
a long time:
The range and shape of "falls through" comments accepted are
contingent upon the level of the warning. (The default level is =3.)
-Wimplicit-fallthrough=0 disables the warning altogether.
-Wimplicit-fallthrough=1 treats any kind of comment as a "falls through" comment.
-Wimplicit-fallthrough=2 essentially accepts any comment that contains something
that matches (case insensitively) "falls?[ \t-]*thr(ough|u)" regular expression.
-Wimplicit-fallthrough=3 case sensitively matches a wide range of regular
expressions, listed in the GCC manual. E.g., all of these are accepted:
/* Falls through. */
/* fall-thru */
/* Else falls through. */
/* FALLTHRU */
/* ... falls through ... */
etc.
-Wimplicit-fallthrough=4 also, case sensitively matches a range of regular
expressions but is much more strict than level =3.
-Wimplicit-fallthrough=5 doesn't recognize any comments.
Plenty of other compilers did not recognize the gcc comment convention,
and up until now the compiler warning for detecting unintended
fallthrough had to be suppressed on other compilers. That's because the code
in NetHack has been relying on the gcc approach, and only the gcc approach.
The C23 standard introduces an attribute [[fallthrough]] for the
functionality, when implicit fallthrough warnings have been enabled.
Several popular compilers already support that, or a very similar attribute
style approach, today, even ahead of their C23 support:
C compiler whitelist approach
--------------------------- -------------------------------------
C23 conforming compilers [[fallthrough]]
clang versions supporting
standards prior to
C23 __attribute__((__fallthrough__))
Microsoft Visual Studio
since VS 2022 17.4.
The warning C5262 controls
whether the implict
fallthrough is detected and
warned about with
/std:clatest. [[fallthrough]]
This adds support to NetHack for the attribute approach by inserting a
macro FALLTHROUGH to the existing cases that require white-listing, so
other compilers can analyze things too.
The definition of the FALLTHROUGH macro is controlled in include/tradstdc.h.
The gcc comment approach has also been left in place at this time.
If eating a tin killed the hero (choked, turned to stone, poly'd into
a new man with new Xp too low to survive) and bones were saved, the
tin remained intact in them.
When hero who is poly'd into metallivore form eats a tin, give a
little extra nutrition for the tin itself. Also, eat it immediately
by skipping the "It smells like <creature>" message and "Eat it? [yn]"
prompt. (The message while eating it also reports <creature>, so
skipping the 'smells' one doesn't end up hiding anything.)
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.
From a change made about two and half months ago: eating a pyrolisk
egg tried to use it up from inventory even when it was on the floor.
That would trigger an object lost panic.
'Polyfodder' is already a term frequently used by players to describe
items which are useful to hang on to specifically to zap polymorph at
(for example, extra unicorn horns, which can be turned into magic
markers). Using it as the name of a macro which tests whether a food
item will polymorph the creature consuming it is somewhat confusing, and
I think 'polyfood' is a lot clearer.
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
Eating from a stack while inventory is full drops the partly eaten
food. If over lava and it is flammable it gets used up without the
eating code being aware of that. (Dropping into a hole or trap door
shouldn't have the same problem because the dropped object is still
accessible via the migrating objects list.)
Have touchfood() return NULL if the food item gets used up due to
being dropped. By itself, that wasn't enough. Callers needed to be
updated to handle that.
I didn't look at other callers of dropx/dropy/dropz; they might have
similar issues. Perhaps they should return the dropped object or
take a pointer to an obj pointer so that there can be just one check
for obj->where==OBJ_DELETED after dropping, but their callers would
still need to updated to cope with that.
Lembas wafers give more than normal nutrition for elves and less than
normal for orcs. Cram rations give more that nomral for dwarves. The
way that was implemented affected the weight of those items, at least
after they were partly eaten. Polymorphing to or from any of the
affected races resulted in inconsistent partly eaten food.
Change how the nutritional bonus or penalty is applied so that there
isn't any affect on item weight.
I haven't incremented EDITLEVEL, so any wafers/rations with incorrect
weight in existing save files will continue to have that wrong weight.
I suppose that it matters more for bones files but even they should be
ok living with this instead of being forced to be thrown away.
There were few places where the object weight was not updated:
- container when the contents were broken by impact
- starting to eat but getting stopped by rotten food
- using lua, container when putting an object inside it
- when a single egg of a larger stack hatched
Pull request by mkuoppal: some objects which use the corpsenm field
to access the mons[] array can have a corpsenm value of NON_PM (-1)
and weren't avoiding array access in those cases.
In addition to a fixes entry for it, this makes some revisions to the
commited code, handling a few of the cases differently.
Closes#1175
and having temporary stoning resistance timeout before finishing.
Issue reported by Umbire: hero was able to finish eating Medusa's
corpse safely after getting the message about no longer being
protected against stoning that is given when temporary resistance
times out.
The eating code was extending temporary resistance--when eating
something protected by such--to avoid just that. I thought this
was probably a message sequencing situation but it turns out that
the code was using touch_petrifies() to test the meal. It should
use flesh_petrifies() instead; Medusa doesn't pass touch_petrifies().
I didn't figure that out until after rewriting how the duration is
extended. The old way probably would have worked as desired with
the revised petrify test but I'm checking in the new version anyway.
Fixes#1186
cg.zeroobj was originally added (under its previous unprefixed name)
for providing a one-line way to zero out the fields of a struct obj.
struct obj tempobj;
tempobj = cg.zeroobj;
initfn(struct obj *otmp)
{
if (otmp)
*otmp = cg.zeroobj;
}
More recently, the address of cg.zeroobj began to be used as a return
flag to indicate some things, but the 'const struct obj zeroobj' wasn't
an ideal fit for the purpose and required a number of casts, including
casting away const.
Provide a better fitting variable (gi.invalid_obj) and eliminate a
number of casts.
b_trapped was treating 0 as a null value for its bodypart parameter, but
0 is actually the value of ARM, so b_trapped(..., ARM) would be treated
as intending no A_CON abuse. Add NO_PART = -1 to the bodypart_types
enum, and use that instead of 0 as the "no body part" value in
b_trapped, so that ARM can be passed to it without any ambiguity.
aosdict identified this issue in xNetHack and handled it differently; he
added NO_PART with a value of 0, incremented the existing bodypart_types
values, and padded the body part arrays so the actual body parts would
start at index 1. I think using NO_PART = -1 is simpler, but that's an
alternative approach that can be used instead -- it is advantageous in
that it automatically fixes any other places where 0 is assumed to be a
non-body-part value that I may have overlooked.
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.
This is fairly ridiculous but it prevents the bogus complaints
when compiling eat.c with 'gcc -fanalyzer' about some fields in
gc.context.victual being used without having been initialized.
There's bound to be a better way to handle this and I'm curious
whether it will work with the 'onefile' testing.
scan-build from llvm-14 (clang) doesn't complain about bite() or
maybe_finished_meal() so this is unlikely to fix those. But this
does fix one bogus complaint it has for doeat(). Testing whether
the result from touchfood() is Null was fooling it into thinking
that that was a possibility when it's not.
Also, use plain 1 and 0 instead of TRUE and FALSE when assigning
to the victual bit-fields. The analyzer doesn't care but the type
was mismatched due to the cast to (boolean) hidden in their macro
definitions.
Insert the calls to trigger a number of potential soundeffects
into the core.
If no additional soundlib support is integrated into the
build, then the Soundeffect macro (sndprocs.h) expands to nothing:
[#define Soundeffect(seid, vol)
]
If, however, at least one additional soundlib support is integrated
into the build, then the Soundeffect macro gets defined as this
in sndprocs.h:
[#define Soundeffect(seid, vol) \
do { \
if (!Deaf && soundprocs.sound_soundeffect \
&& ((soundprocs.sndcap & SNDCAP_SOUNDEFFECTS) != 0)) \
(*soundprocs.sound_soundeffect)(emptystr, (seid), (vol)); \
} while(0)
]
That macro definition checks for the hero not being Deaf; it checks
to ensure that the active soundlib interface has a non-null
sound_soundeffect() function pointer; and it checks to ensure
that the active soundlib interface has declared that it supports
soundeffects by setting the SNDCAP_SOUNDEFFECTS bit in its sndcap
entry. That just means that the interface routines are prepared to
accept and deal with the calls from the core, whether or not it
actually produces the desired soundeffect.
The complaint is that victual.canchoke might be used without having
been initialized. I'm fairly sure that that isn't correct but get
dizzy trying to trace through the eating code.
This might improve the situation, or maybe not.