> if (strlen(simpleoname) > BUFSZ - sizeof "the ")
> simpleoname[sizeof "the "] = '\0';
The second line should have been
| simpleoname[strlen(simpleoname) - sizeof "the "] = '\0';
but fixing that isn't adequate. The BUFSZ limit is not valid when
dealing with object names since xname() leaves room for a prefix so
doesn't return the start of a BUFSZ-sized buffer.
Strangely enough, the complaint that caused me to add those two lines
isn't being triggered any more. Some other change at the same time,
perhaps splitting
Strcpy(simpleoname, obufp = the(simpleoname));
into
obufp = the(simpleoname);
Strcpy(simpleoname, obufp);
pacified the analyzer. However, it didn't resolve the valid complaint
that inserting "the " might result in overflow.
I've added a comment about simpleonames(), ansimpleoname(), and
thesimpleoname() about the possible overflow, but I don't think that
such overflow can actually happen when user-applied object name is
being suppressed.
This construct triggered several complaints about passing Null to
Strcpy(simpleoname, obufp = the(simpleoname));
Changing that to
obufp = the(simpleoname);
Strcpy(simpleoname, obufp);
prevents it, but the original complaint is bogus and the "fix"
doesn't do anything to deal with Null arguments.
A couple of other changes introduce different code in order to get
different behavior. I updated from llvm-16 to llvm-19 but didn't
eliminate any of the spurious complaints.
Clear "next" boulder so that when pushing a pile of boulders, only
the first message for each of the 2nd, 3rd, &c will be formatted as
"next boulder". If any of them trigger additional messages, those
messages will use normal "boulder".
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.
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.
Issue reported by elunna: sleeping mimics can grab the hero, and
zapping a concealed mimic with a wand of sleep describes the target
as a mimic but doesn't bring it out of concealment.
The grab-when-asleep case is reasonable. It's a reflexive counter-
attack by a magical creature. And the mimic wakes up in the process.
But the mimic wasn't being brought out of concealment. Do that.
Unconceal mimics hit by wand of sleep unless already sleeping.
Fixes#1299
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
Finish shop changes begun in 2674a9904d.
Fix the longstanding bug where shop paying with itemized buying would
reveal container contents if any unpaid items were inside containers,
regardless of whether the containers' contents were known yet, even
when the container was a locked box/chest or a cursed bag of holding.
Paying by menu made that be more noticeable but it has been present
ever since itemized paying was introduced. I can't find any old bug
reports for it though. I did find an old message of mine that claims
it's in bugzilla with a "#Hnnnn" tag.
This changes how buying containers and their contained items behaves.
It's now an all or nothing operation. Itemized billing will list
the container but not contents, and to buy what is inside you need
to pay for the whole thing as a single unit. If the container itself
is unpaid then its price is part of that item's total cost. If it is
hero-owned than it is listed as an item to buy but doesn't increase
the cost derived from its unpaid contents. (If you decline to pay,
hero will still own the container and still owe for unpaid contents.)
Issue reported by ars3niy: unpaid containers containing one or
more other unpaid items appear on the menu for 'p' along with
separate menu entries for those other items. Buying the container
buys the contents too, then if any of the contents were also picked
in the menu, an attempt will be made to pay for them separately.
Since they are no longer on the bill by that point, that triggers
an impossible warning.
This fixes that by paying for the container but not its contents.
(Temporarily, until more extensive changes get implemented.) Then
those contents will still be on the bill. It they've been chosen
in the 'p' menu, paying for them will work as expected.
This also fixes the pay menu for the case where the bill contains
any instances of a partly used up portion of some stack and also
the unpaid intact portion of the same stack. With itemized billing,
you are allowed to buy the used up portion separately, then maybe
drop the unpaid portion. (If you try to pay for the intact portion,
the shk won't accept the payment and will tell you to pay for the
used up portion first.) With the recently added menu for billing,
they were lumped together as a single item and you had to pay for
their whole stack.
And it fixes a much older bug dealing with the cheapest item on
the shop bill. If you don't have enough to pay for that, the rest
of buying gets skipped. But stacks that had used up and intact
portions were lumping those together instead of separately checking
the two portions for possibly being the cheapest, so it was possible
to have enough gold to pay for one portion but be told that you
couldn't affort to pay for anything. If it was the intact portion,
you wouldn't be able to buy it anyway, but if the cheapest item was
used up portion, being told you didn't have enough gold was wrong.
This commit does not fix the longstanding bug that itemized billing
reveals the contents of containers which haven't been opened. It
was intended to do so but I've run out of steam.
(There is groundwork for that, where buying a container would
include payment for its unpaid contents without revealing what those
are, and they couldn't be purchased separately unless they get taken
out of the container. Uncommenting '#define CONTAINED_BUYING' will
enable it, with updated pay menu handling but without being able to
pay for non-empty containers.)
Fixes#1249
I still haven't found any explanation for the report by a hardfought
player recently that going down some stairs with a pair of leashed
pets got one into a confused state where it was flagged as leashed
but the corresponding leash was no longer in use.
This adds some new object and monster sanity checks regarding leashes,
and it changes o_unleash(obj) to clear obj->leashmon even if/when the
monster can't be found.
It also changes behavior for dipping an attached leash into a potion
of polymorph when that happens to yield another leash--now the new
one will end up being pre-attached.
Add a way to request that unpaid_cost() produce the cost for a single
item, which is necessary for the price adjustment made in
bill_dummy_object. Another option would be to simply divide by quan in
bill_dummy_object, but this might be more future-proof in case
unpaid_cost ever involves more than simple multiplication by quan
(e.g. the use of alternate units vs the base price, as are used for
globs).
Fixes#1236
This doesn't directly affect nethack, but it should prevent HTML
dumplog for variants that include that from showing T-shirt and
apron slogan text in tooltips for the 'gameover' map. And it makes
end-of-game attribute disclosure slightly less susceptible to being
unintentionally reverted.
Code in pull request #300 shows that it uses do_screen_description()
for tooltips and do_screen_description() uses distant_name() for
objects so that's where I added this change that will trigger the
code from commit c6992777f5.
Disclosing final inventory while wearing an alchemy smock reported
the apron's slogan accurately but then disclosing attributes gave
different text if it was conferring poison resistance and/or acid
resistance. The extra text was unneeded/unwanted there anyway, so
simply suppress it rather than force it to be accurate.
3.6.x had the same issue but it wasn't detectable there because it
only had extra text for T-shirts and they don't confer attributes.
Previously when wishing for "ring of protection from shape shifters",
you got a random ring instead of the protection from shape changers,
because the string matching alias was "protection from shape shifters"
without the object class. Now, we'll check if the wish matched any
object class, but not existing object or alias, and try matching
the aliases again, but only those of the already matching obj class.
Add an alias for the ring of increase accuracy: "ring of accuracy",
and tests for it.
+/-N for charged rings with known enchantment was clobbering the
BUC formatting that had occurred earlier. #K4088 thought it was a
problem with the implicit_cursed option; followup #K4089 from same
user correctly pointed out that the problem was present for any BUC
state.
This is the same line of code that inadvertently omitted the space
between +/-N and "ring of <type>". That was fixed by commit
1a2b2a8cae a couple of days ago.
While in doname(), fix a potential issue calling corpse_xname().
That assigns a new value to gx.xnamep, clobbering the value that
doname() relied on when it was first called (but doesn't look at
again, so doesn't matter now but could conceivably in the future).
When ready to return, check for overlooked overflow (shouldn't happen)
and panic, or report the first excessively long but not overflown
description to paniclog, similar to xname.
Make ConcUpdate() more robust by not needing bp_eos to be previously
set. Less efficient but I think that boat has left the barn? :=}
Fix a comment typo.
Avoid two new warnings in xname_flags() about strncpy() not supplying
a terminating '\0'. That's exactly why strncpy() was being used.
The gcc manual lists -Wno-stringop-truncation to suppress the warning
but not -Wstringup-truncation to voluntarily enable it, so the pragma
stuff in warnings.h probably won't work for this. Just switch from
strncpy() to memcpy() instead even though it seems like obfuscation.
Try harder to prevent buffer overflow when formatting objects.
I don't have any test cases where overflow has been happening so
don't really know whether this works reliably. And it doesn't try
to check prefix construction by doname(). [Yet?]
If you wished for "lit candle" you'd get an unused candle that
is pre-lit but the feedback as it's added to inventory would be
"partly used candle (lit)". If snuffed out immediately, it reverts
to "candle" (ie, not partly used).
This fixes the first aspect: you will get "candle (lit)" added to
inventory. On the next turn it changes to partly used as expected.
The second aspect, reverting to not-used-yet after being lit during
the wish is left as-is.
When trying to reproduce the wand of striking "interesting effect (0)"
report, I tried wishing for lava under the castle drawbridge. That
wasn't handling drawbridges properly. This fixes wishing for moat,
lava, ice, or floor at a drawbridge span location whether the bridge
is currently open of closed. It also allows wishing for room or floor
or ground at room spots; that hasn't had much testing.
Wishing for furniture, pool|moat|water, or lava at an ice location
wasn't cancelling any pending melt timer.
ice_descr() was declared as returning const but returns its non-const
output buffer argument. Change to 'char *' so that wizterrainwish()
can capitilize that output without jumping through any hoops.
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.
Modifying an() [actually just_an()] to treat "<thickness> ice" and
"frozen <hallucinatory liquid>" as special cases which shouldn't be
prefixed with "a" or "an" affected using something like "shaved ice"
or "frozen yogurt" as named fruit.
|a) shaved ice
|b) frozen yogurt (weapon in hand)
now have article "a" preceding them:
|a) a shaved ice
|b) a frozen yogurt (weapon in hand)
However, the existing cases
|c) iron bars
|d) an iron bars (weapon in hand)
still get item 'c' wrong. 'd' is slightly odd but that's because the
fruit name is ambiguous as to whether it's singular or plural.
Classify nearby ice as "solid" (no melt timer), "sturdy" (more than
1000 turns left), "steady" (101 to 1000 turns left), "unsteady" (51
to 100 turns left), "thin" (15 to 50 turns left), or "slushy" (1 to
14 turns left, matching walking on ice with the Warning attribute).
[I'm not thrilled with "steady" and particularly "unsteady".]
I was originally going to do this just for probing downward, but ended
up also doing it for look-here and getpos's autodescribe. It nearly
got out of hand and touched more files than anticipated.
'mention_decor' ought to treat moving from ice firmer than thin to
thin or slushy, from thin to slushy, from slushy to any other, and
from thin to firmer as if moving onto different terrain but I haven't
attempted to tackle that.
The melt timer could work more like a candle's burn timer, triggering
at intermediate stages and resetting itself, so that ice which changes
to a weaker state under the hero could be reported to the player. But
this doesn't implement that.