Define some macros in include/tradstdc.h, for compilers that support
__attribute__((nonnull)), to assist in identifying which parameters
on functions are not supposed to be null pointers.
Next, for the majority of functions declared in include/extern.h, this
adds the appropriate macro that matches the actual use of each function's
parameters. The additions were done after performing some analysis.
These were the rules that were followed when determining which function
parameters should be nonnul, and which are nullable:
1. If the first use of, or reference to, the pointer parameter in the
function is a dereference, then the parameter will be considered
nonnull.
2. If there is code in the function that tests for the pointer parameter
being null, and adjusts the code-path accordingly so that no segfault
will occur, then the parameter will not be considered nonnull (it can
be null).
The use of the nonnull attributes allows the compiler to detect code in
callers of the function where a null parameter could get passed to the function.
If a warning is received the developer will have to do one of the following:
- If the null being passed to the function is now appropriate,
and the function should be able to expect a null parameter, then the
NONNULLxxx macro will have to be removed from the function's prototype.
or
- If the null being passed to the function is not appropriate,
correct the caller so it is not passing null.
or
- If the warning is about comparing to null, it may indicate an
unnecessary null check in the code involved. If it is deemed to be
unnecessary, it can then be removed.
Some static analysis tools apparently can work with the attribute, as well.
Following this, it was discovered that some functions were using one of the
(now) nonnull parameters in the first argument to the 'is_art(obj, ART)'
macro, which is defined like so:
=> #define is_art(o,art) ((o) && (o)->oartifact == (art))
That macro expansion inline resulted in a diagnostic warning because of the
'(o)' portion of the expanded macro, anywhere the macro was used with one of
the nonnull parameters. A test against null for a 'nonnull parameter' causes
a diagnostic warning.
To work around that, I replaced the is_art() macro with a function in
artifact.c, that accomplishes the same thing as the macro.
=> boolean
is_art(struct obj *obj, int art)
{
if (obj && obj->oartifact == art)
return TRUE;
return FALSE;
}
Some documentation...
These are the macros that have been defined for use when specifying the nonnull
parameters in a function prototype:
----------------------------------------------------------------------------
| Macro | Purpose |
+----------------+---------------------------------------------------------+
| NONULL | The function return value is never NULL. |
+----------------+---------------------------------------------------------+
| NONNULLPTRS | Every pointer argument is declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG1 | The 1st argument is declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG2 | The 2nd argument is declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG3 | The 3rd argument is declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG4 | The 4th argument is declared nonnull (not used). |
+----------------+---------------------------------------------------------+
| NONNULLARG5 | The 5th argument is declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG7 | The 7th argument is declared nonnull (bhit). |
+----------------+---------------------------------------------------------+
| NONNULLARG12 | The 1st and 2nd arguments are declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG13 | The 1st and 3rd arguments are declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG123 | The 1st, 2nd and 3rd arguments are declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG14 | The 1st and 4th arguments are declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG134 | The 1st, 3rd and 4th arguments are declared nonnull. |
+----------------+---------------------------------------------------------+
| NONNULLARG17 | The 1st and 7th arguments are declared nonnull (this |
| | was a special-case added for askchain(), where the |
| | arguments are spread out that way. This macro |
| | could be removed if the askchain arguments in the |
| | prototype and callers were changed to make the |
| | nonnull arguments side-by-side). |
+----------------+---------------------------------------------------------+
| NONNULLARG145 | The 1st, 4th and 5th arguments are declared nonnull |
| | (this was a special-case added for find_roll_to_hit(), |
| | in uhitm.c, where the arguments are spread out that way.|
| | We can't just use NONNULLPTRS there because the 3rd |
| | argument 'weapon' can be NULL). |
+----------------+---------------------------------------------------------+
| NONNULLARG24 | The 2nd and 4th arguments are declared nonnull (this |
| | was a special-case added for query_objlist() |
| | in invent.c). |
+----------------+---------------------------------------------------------+
| NONNULLARG45 | The 4th and 5th arguments are declared nonnull (this |
| | was a special-case added for do_screen_description(), |
| | in pager.c, where the arguments are spread out that |
| | way. We can't just use NONNULLPTRS there because the |
| | 6th argument can be NULL). |
+----------------+---------------------------------------------------------+
| NO_NONNULLS | This macro expands to nothing. It is just used to |
| | mark that analysis has been done on the function, |
| | and concluded that none of the arguments could be |
| | marked nonnull.That distinguishes a function that has |
| | not been analyzed (yet), from one that has. |
+----------------+---------------------------------------------------------+
The NO_NONNULLS macro is meant to place a flag on the prototype to
make people aware that an assessed function was determined to not
be eligible for nonnull parameters. It expands to nothing.
Unfortunately, that macro was added partway through this exercise, so there
aren't many instances of it in the upper parts of include/extern.h, even though
the functions there were likely assessed and categorized as not having any
eligible nonnull parameters. It just never got any macro at all, in that case.
Following the parameter usage analysis that was done, the following was
noted:
Some NetHack functions have added a test to catch a passed null
parameter, and exit the function early as a result, or call
impossible(), and then exit. While that approach prevents segfaults
from dereferencing a null parameter, the early return is silent
(when impossible is not called anyway), and the function's true
purpose is not fulfilled. Also, the calling function may have no
awareness that the function did not complete its intended purpose,
in many instances.
Functions with such a test and early return, cannot have the parameter
declared 'nonnull', because the code to test for 'null' will cause a
diagnostic to be issued if the parameter is nonnull.
It might be good to revisit some of those functions and consider,
on a case by case basis, declaring the parameter nonnull in the
prototype, and the test/code-path commented out.
selection_getbounds() has a check and early return.
Initialization will ensure a known state if that early return
were ever taken.
This is an alternative approach to pr #1163.
The following were listed in extern.h as residing in makemon.c,
but they are actually in mon.c:
copy_mextra(struct monst *, struct monst *);
dealloc_mextra(struct monst *);
usmellmon(struct permonst *);
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.
After the drawbridge was destroyed, playing an instrument on the castle
level while knowing the tune continued to offer a chance to play it.
Then nothing interesting happened even if you were close enough to the
former bridge for it to have been useful prior to the destruction.
I think the hero could also be given the tune as a divine prayer boon
after bridge destruction but I didn't verify that. The player might
not know that the tune is no good anymore, but the hero's patron deity
should.
Hide some of the details about new Stealth.
Streamline mon_break_armor(). Move replicated bypass handling into
m_lose_armor(). Also, eliminate a 'goto'.
Donning elven boots while riding and not already stealthy, you'd get
the message "you walk quietly" when not walking at all. Instead of
just changing the message, make riding a non-flying steed block
stealth. Riding a flying steed (or one you take aloft with an amulet
of flying) does not. It would have been quite a bit simpler to have
made riding anything block stealth, but the hard part is done.
... and have more than 1 billed item, and using non-traditional
menustyle.
I opted to add an extra field to the bill struct, because
that made the code cleaner.
Breaks saves and bones.
During very early startup, Windows may not have loaded
the tty window procs yet, and it is running with safeprocs.
It will eventually load the tty stuff. If the currently
operating window port fails in can_set_perm_invent(),
try the check for WC_PERM_INVENT again explicitly on
the tty windowport.
Pull request from entrez: add 'nopick_dropped' option of not pick up
items dropped by hero via autopickup and 'pickup_stolen' to picup up
items stolen from hero via autopickup, bypassing pickup_types and
autopickup_exceptions like existing 'pickup_thrown'.
This fixes entry commit also fixes the description of pickup_stolen.
Closes#1140
Add pickup_stolen option to autopick items stolen from you by a nymph or
monkey, even if they don't match your normal autopickup settings.
Replace was_dropped, was_thrown with a 2-bit bitfield that can contain
values LOST_DROPPED, LOST_THROWN, and LOST_STOLEN (or 0), since they
should all be mutually exclusive anyway as they track the most recent
way the item left the hero's inventory.
[Rebase/merge conflict fixed up. PR]
This is based on a feature in UnNetHack (and I think some other variants
as well). If the hero intentionally drops an item with 'pickup_dropped'
disabled, don't autopick it back up when walking over that square again.
Typically when the player drops an item, it's because she doesn't want
it in her inventory any more, and this option stops autopickup from
defeating that goal (especially useful for tasks like stash management
without a container). Players have come up with workarounds to this
problem like toggling autopickup when approaching their stash pile or
adding name-based autopickup exceptions to allow them to exclude
individual items from autopickup, but this behavior should reduce the
need for those things.
I think 'pickup_dropped' is a little unfortunate because it suggests
equivalence to 'pickup_thrown' (i.e. any dropped items will be
automatically picked up regardless of autopickup exceptions). Calling
it something like 'nopick_dropped' might be better, but as far as I can
tell options cannot start with the word 'no' because it's interpreted as
a negation of the rest of the option name.
There were 6 brown 'd' monsters; move wolf and werewolf to grey,
and warg to black, as those colors had no canines.
The wolf tiles are already greyish; changed warg tile to be
slightly darker.
There are many red major demons, and hezrous and vrocks
now emit poison gas, so change the symbol color to green.
Also adjust vrock tiles to have green. The hezrou tiles
already are green.
Prior to this commit, there was no good way to deal with swarms of
weak, good-AC enemies using magic; trying to play a wizard as a
pure spellcaster would make bees and ants very difficult to deal
with (because they would usually dodge force bolts).
This commit adds a new spell designed to be very good against
swarms of weak enemies: "chain lightning", which does 2d6 lightning
damage to every monster around you. It has an initially short range,
but can chain from monster to monster to cover potentially large
distances (as long as none of the monsters en route are shock
resistant or tame/peaceful; the spell can't chain past shock
resistant monsters and avoids peacefuls). Monsters within one
space of the visible lightning bolts are affected. Unlike other
lightning effects, this one does only 2d6 damage, not enough to
blind affected monsters.
This commit breaks existing save and bones files (thus the
EDITLEVEL increase).
The same checks were being repeated for every damage type; this
sends them through two centralised functions (one for checking
whether an extrinsic blocks a specific instance of item destruction
and one for the enlightenment message), so that new mechanisms of
item destruction prevention will need to change only one point in
the code.
The tracks left by hero were cleared when player saved and
restored the game, or changed levels. Now the tracks are
saved in the dungeon level, so changing levels keeps the tracks
left by hero in that level.
Also increased the length of tracks from 50 to 100, and
simplify the tracking function.
Thing not done: fade out old tracks when returning to a level.
Breaks saves and bones.
Report was that converting a novel into a blank spellbook via water
damage resulted in a spellbook of blank paper that increased weight
when put into a bag of holding.
Spellbooks weigh 50 units but novels were defined with a weight of 0;
when one was created, a non-zero weight of 1 got assigned. Blanking
it didn't update the weight; that stayed at 1. Putting it into a
container reset the weight to match the new type: spellbook of blank
paper, so its weight increased.
Do that when blanking rather than wait until a container might fix it
up. If it is already in a [possibly nested] container, update that
container's weight too along with any outer ones.
This also changes the base weight of novel from 0 to 10, so it still
gets magically heavier when turned into a spellbook of blank paper.
(The alternative seems to be to destroy it instead.)
The Book of the Dead weighed only 20 units which seemed odd to be so
much less than a spellbook. This changes that to 50 to match those.
Currently, options.c is the only file that #includes "optlist.h".
In theory, if a source file did want to include optlist.h (perhaps
for the struct allopt_t declaration so they could deal with a
pointer to such a struct), they wouldn't be able to include it
because of a static function prototype that it contains.
Add some protection to only include that static function
prototype when optlist.h is included from options.c.
At present, potions of healing generate primarily in Gehennom,
which causes significant balance issues (e.g. you don't have them
to heal in the early game, or even if you do, you can't identify
them in time to use them). In this series of commits, I'm aiming to
make potions of healing a more viable early-game healing source,
which means making them both (much) more likely to generate, and
easier to identify so that they are actually usable in the early
game.
This commit radically increases the generation chance of potions
of healing (reducing the chance of most other potions slightly to
compensate), and gives them a unique base price. This should make
them fairly easy to identify either by price-ID or quantity-ID
(and the unique base price is chosen to be fairly easy to figure
out even for unspoiled players).
Previously, Wizards got a boost to the chance of writing unknown
spellbooks based purely on being a Wizard (with the chance still
luck-based), leading to a very large power spike when the Wizard
gained access to a luckstone and the ability to max out luck.
This had two main issues: this power spike came *after* the major
early-game difficulty spike, often leaving Wizards forced to deal
with it without having appropriate spells; and it promotes
grinding (for Luck and for Magicbane) at an early point in the
game, meaning that the Wizard early game effectively followed a
sequence of extreme difficulty -> grinding -> minimal difficulty,
which isn't very good balance-wise.
With this commit, Wizards lose their advantage to writing unknown
spellbooks by guessing, and instead learn spellbook IDs based on
their spell skills (advancing a skill gives knowledge of higher-
level spellbooks). This means that writing unknown spellbooks
becomes guaranteed with sufficient skill, but has no advantage
over non-Wizards in schools where the Wixard does not have
sufficient skill.
Due to Wizards' skill caps, there are two spells which they can't
ever write guaranteed: create familiar and charm monster. Create
familiar is a fairly niche spell (that doesn't match the Wizard
playstyle that well) and being unable to write it is not a major
problem. The inability to easily write charm monster is
intentional.
This is for completely destroying an altar with extra-powerful magical
digging -- the normal altar_wrath() punishment didn't seem sufficient
for such an outrage to me, so skip straight to slinging the lightning
bolts. Destroying an altar is unlikely to happen by accident (though
it's possible with poorly timed usage of a drum of earthquake).
character_race() was going out of bounds when scanning the races[]
array, relying on a field value that the fencepost entry didn't set.
This incorporates the previous fix for UNDEFINED_RACE but also changes
character_race() to not care about that anymore.
If any items are in use and hero isn't wielding anything, include
| - bare hands
in the primary weapon slot of the display of used items as an alert.
More useful for perm_invent than for #seeall.
If no items at all are in use, continue to show "not using any items"
without any specific weaponless alert.
When sortloot() is called for inuse_only, pass a filter that screens
out items which aren't in use so they won't be needlessly sorted.
For '*' and for persistent inventory with perminv_mode==inuse, show
the items in a specific order and within four labelled groups rather
than within their object classes:
|Accessories
| amulet
| right ring
| left ring
| blindfold
|Wielded/Readied Weapons
| primary weapon
| alternate or secondary weapon
| quiver/ammo pouch
|Armor
| suit
| cloak
| shield
| helmet
| gloves
| boots
| shirt
|Miscellaneous
| lit candles and/or lamps
| attached leashes
The accessories come first due to the default 'packorder' position
for amulets; weapons before armor likewise. If you wield a potion or
quiver some gold, those non-')' items will appear in the weapons
section since the ordering is based on slot rather than object class.
choose_classes_menu was declared extern. The only caller presently
was calling it was optfn_pickup_types() in options.c.
It could have had the extern declaration from include/extern.h and
declare it as static within options.c, if that was the only use
anticipated. Also, if the one existing caller were all there would
ever be, the argument passed to it that was the subject of pr #1146
could have just been removed along with the switch.
Checking the comments above the function, however, it was clearly
designed as a general-purpose function that could be called from
anywhere for the functionality desired, even though there's presently
just the one caller, passing just the one variation of the category
argument.
Relocate the general-purpose function over to src/windows.c, where
several interface-related / menu-related general-purpose functions
already reside.
options.c has gotten *huge* and this is a fitting opportunity to
reduce its size a little.
A very small number of relatively recent macro definitions got
placed in mondata.h, even though they had a 'struct monst *'
argument, rather than a 'struct permonst *' argument.
Relocate the macros with the 'struct monst *' argument to
include/monst.h, leaving the macros with the 'struct permonst *'
argument in include/mondata.h.