src/wield.c(745): warning: Dereferencing NULL pointer 'obj'.
See line 685 for an earlier location where this can occur
In wield_tool(), the comparisons against uwep were intended
for when uwep wasn't null.
gcc/clang analyzers now have some awareness of obj arg being
notnull for wield_tool() since the extern.h prototypes
were changed to declare that, but other compilers/analyzers
do not necessarily have that information, and this:
'if (obj == uwep)'
would be a match if both were NULL.
src/wield.c(254): warning: Dereferencing NULL pointer 'wep'.
See line 190 for an earlier location where this can occur
This seems to be a case where an unnecessary null test (A) caused
the analyzer to call into question whether or not wep
is null at (B):
if (!wep) {
} else if (wep->otyp == CORPSE && cant_wield_corpse(wep)) {
} else if (uarms && bimanual(wep)) {
} else if (!retouch_object(&wep, FALSE)) {
} else {
/* Weapon WILL be wielded after this point */
if (will_weld(wep)) {
} else {
}
if (was_twoweap && !u.twoweap && flags.verbose) {
}
/* KMH -- Talking artifacts are finally implemented */
A ==> if (wep && wep->oartifact) {
}
if (artifact_light(wep) && !wep->lamplit) {
}
B ==> if (wep->unpaid) {
}
}
Removing the extraneous wep test from (A) resolves the complaint.
drop_uswapwep() avoided calling makeplural() in a pline which also
had a call to Yobjname2(), with a comment about the possibility of
clobbering its static return buffer. uswapwep might be a stack that
results in Yobjname2 indirectly calling makeplural to produce a
plural description. But makeplural() has used xname's pool of obufs
since before uswapwep became a thing, so the code was evidently
cloned from some other out of date usage.
I was going to just move the makeplural() call into pline() but it
dawned on me that uswapwep must be one handed, so don't pluralize
hands at all. And since uswapwep might have the same description as
uwep, explicitly mention "left hand" to distinguish.
When testing 'm )' I noticed that weapon and alternate weapon weren't
offering the chance to toggle two-weapon mode. When already on,
providing it as a choice to toggle it off is simple, but when at is
off that isn't the case. There are lots of reasons why attempting
to toggle it on might fail and it is silly to offer as a choice if
failure is sure to occur. This tries to filter out the majority of
reasons why the player can't toggle it on when deciding whether to
include 'X' as a choice.
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.
To get the Magic Mirror of Merlin to speak, you could apply it in
any direction (or wield it). To get the Master Key of Thievery to
speak, you had to apply it toward an adjacent doorway or down while
on a container (or wield it). Make the key behave like the mirror.
If punished and the attached iron ball was both cursed and wielded,
falling while going down stairs would drop it instead of leaving it
welded to hero's hand. ( Didn't happen for iron ball that wasn't
chained to hero's leg.)
I thought that this was going to be a one or two line fix but ball
and chain stuff is never that simple.
Fixes#949
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
^ ^
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).
When not wielding anything, ^X reports "you are empty handed" if
wearing gloves or "you are bare handed" if no gloves. The ')',
'w-', and 'A)' commands were using "empty handed" unconditionally.
Make them be consisitent with ^X.
After this, body part HANDED is no longer used anywhere except in
body_part().
The fire command could claim that time passed when it hadn't (fill
quiver with ammo, which takes no time, then queue commands to switch
to matching launcher, which should also take no time while queueing,
only during subsequent execution).
If quiver is empty or has ammo in it, give wielded thrown-and-return
weapon (aklys) priority over filling quiver or switching to ammo's
launcher. Don't do that if quiver has non-ammo in it, otherwise
players running Valks who wield Mjollnir with super strength but
want to throw quivered daggers would complain.
When player is being asked what to fill the quiver with, use the
\#quiver command to do that. Using it honors a count to split a
stack, handles switching uwep or uswapwep to uquiver, and gives
feedback. This is actually a fairly substantial change.
For 'fireassist', when switching to a launcher that isn't already
uswapwep pick one known to be blessed or uncursed over one having
unknown BUC status. But use the latter as last resort.
I polymorphed into something wimpy and became overloaded or even
overtaxed so I dropped everything. The status line still showed
overloaded or overtaxed until my next move. That didn't happen in
3.6.x or 3.4.3 but I didn't pursue trying to figure out what caused
this misbehavior.
I wanted to add an encumber_msg() call to freeinv() but that would
cause message sequencing issues. Instead, add a call to it in a
few places where items are leaving hero's inventory, particularly
for the chain of calls for dropping stuff. I've left it off in a
bunch of other potential places.
Also add a few missing (void) casts where the return value of
existing encumber_msg() calls is being ignored.
When you have a polearm as secondary weapon, have a fireassist on,
and press 'f' to fire, the code tries to swapweapon to the polearm.
This failed badly and got stuck in a loop if you were also wearing
a shield - as polearms are two-handed and shield prevents wielding
those.
Add a new "command failed" result, and clear the command queue
in that case. Also make swapweapon and wield actually return
the ECMD flags back to the rhack loop.
Investigating github issue #664 by argrath turned up a more
significant problem. Prefixes other than 'm' preceding commands
that don't use a prefix didn't get rejected but didn't do anything.
Fixes#664
Instead of returning ECMD_OK, the commands now return ECMD_CANCEL
when user declined to pick a direction or an object to act on.
Note that this can be ORed with ECMD_TIME, if the command still
took a turn.
For now this has no gameplay meaning.
Instead of returning 0 or 1, we'll now use ECMD_OK or ECMD_TURN.
These have the same meaning as the hardcoded numbers; ECMD_TURN
means the command uses a turn.
In future, could add eg. a flag denoting "user cancelled command"
or "command failed", and should clear eg. the cmdq.
Mostly this was simply replacing return values with the defines
in the extended commands, so hopefully I didn't break anything.
Allows the fire-command to autowield a launcher; it will now
do either swapweapon or wield an appropriate launcher, if you
have ammo quivered.
This assistance can be turned off with the fireassist boolean option.
Adds a rudimentary command queue, which allows the code to add keys
or extended commands into the queue, and they're executed as if
the user did them. Time passes normally when doing the queue,
and the queue will get cleared if hero is interrupted.
Assigning a partial stack of gold to quiver (Qnn$) resulted in
an extra '$' slot in inventory, one for the unquivered part and
another for the quivered part.
Throwing a non-quivered partial stack of gold at self (tnn$.)
also resulted in an extra '$' slot after throwing at self was
rejected.
For the first case, reject the quiver-subset-of-gold attempt.
For both cases, recombine the two stacks back to original amount.
Fixes#469
This replaces the arcane system previously used by getobj where the
caller would pass in a "string" whose characters were object class
numbers, with the first up to four characters being special constants
that effectively acted as flags and had to be in a certain order.
Because there are many places where getobj must behave more granularly
than just object class filtering, this was supplemented by over a
hundred lines enumerating all these special cases and "ugly checks", as
well as other ugly code spread around in getobj callers that formatted
the "string".
Now, getobj callers pass in a callback which will return one of five
possible values for any given object in the player's inventory. The
logic of determining the eligibility of a given object is handled in the
caller, which greatly simplifies the code and makes it clearer to read.
Particularly since there's no real need to cram everything into one if
statement.
This is related to pull request #77 by FIQ; it's largely a
reimplementation of its callbacks system, without doing a bigger than
necessary refactor of getobj or adding the ability to select a
floor/trap/dungeon feature with getobj. Differences in implementation
are mostly minor:
- using enum constants for returns instead of magic numbers
- 5 possible return values for callbacks instead of 3, due to trying to
make it behave exactly as it did previously. PR #77 would sometimes
outright exclude objects because it lacked semantics for invalid
objects that should be selectable anyway, or give slightly different
messages.
- passing a bitmask of flags to getobj rather than booleans (easier to
add more flags later - such as FIQ's "allow floor features" flag, if
that becomes desirable)
- renaming some of getobj's variables to clearer versions
- naming all callbacks consistently with "_ok"
- generally more comments explaining things
The callbacks use the same logic from getobj_obj_exclude,
getobj_obj_exclude_too and getobj_obj_acceptable_unlisted (and in a few
cases, from special cases still within getobj). In a number of them, I
added comments suggesting possible further refinements to what is and
isn't eligible (e.g. should a bullwhip really be presented as a
candidate for readying a thrown weapon?)
This also removed ALLOW_COUNT and ALLOW_NONE, relics of the old system,
and moved ALLOW_ALL's definition into detect.c which is the only place
it's used now (unrelated to getobj). The ALLOW_ALL functionality still
exists as the GETOBJ_PROMPT flag, because its main use is to force
getobj to prompt for input even if nothing is valid.
I did not refactor ggetobj() as part of this change.
When dual-wielding and you wield a different weapon, two weapon combat
was silently toggled off even when the new weapon was eligible to be
dual-wielded. If the verbose flag is On, explicitly tell the player
when wielding something toggles off two-weapon mode. Wielding '-' is
an exception because you already get told that you're empty handed.
Reject arrows and darts as candidates for wielding two weapons at
once.
Make the check for being able to two-weapon when polymorphed be more
robust. Instead of just testing whether the monster form's second
atttack is a weapon attack and then assuming that the first one is
too, test the first three to validate that at least two of those are
AT_WEAP. The existing code works but seemed fragile.
Don't allow dual-wielding if either wielded or alternate weapon
(or both) is a launcher: bow, crossbow, or sling. (I thought that
this had been addressed ages ago.)
Refine the "can't twoweapon" feedback. The message for having
either or both hands empty is the same, but sentence construction
is different. The not-a-weapon feedback is slightly different, now
mentioning whether it's the wielded or alternate weapon which isn't
allowed. The case where neither are acceptable still just reports
uwep; mentioning both it and uswapwep would be too verbose.
Make more things be described as "(wielded)" instead of "(weapon in
hand)". It was just stacks with quantity more than 1. That's now
joined by ammo and missiles (any stack size, but in reality just 1
since greater was already being caught here) and any quantity of
non-weapon, non-weptool. It's overridden if dual-wielding so that
right/left stay matched.
When dual-wielding, list primary as "(wielded in right hand)" and
secondary as "(wielded in left hand)" instead of "(weapon in hand)"
and "(wielded in other hand)". The vaguer wording was better for
bows since they're held in the off hand but now that they can't be
dual-wielded that doesn't matter. (Single-wielding a bow is still
"(weapon in hand)".)
When not dual-wielding, the item in the alternate weapon slot is
still described as "(alternate weapon; not wielded)" even if it's
not actually a weapon. I couldn't think of better phrasing.
There was a concern that some things resulted in "is not a weapon"
when trying to twoweapon, then were subsequently refered to in
menus as "weapon in hand."
Remove any perceived inconsistency by simply adjusting the first
message.
After the "make 'w' parallel with 'Q'" patch, wielding bare hands
was erroneously treating object id 0 as a split of zeroobj. That
isn't in inventory so seems 'lost'. Fixed by testing for nonzero.
There was another bug: you could wield a partial stack even if your
current weapon was cursed. Fixed by reordering if/else-if/end-if.
If you're wielding a stack of N items, issuing the command to quiver
them asks whether you want to quiver N-1 of them (implicitly leaving
one wielded). If you answer no then you're asked whether to quiver
all of them. You could also give a count when picking the item to be
quivered and the stack would be split based on that.
However, if you have a stack of N items quivered, issuing the command
to wield them just did so, leaving the quiver empty. And picking an
item ignored any count, so even explicitly asking for 1 (out of N)
wielded the whole stack. Change 'w' to parallel 'Q'; if you try to
wield a quivered stack, you'll be asked whether to wield just 1 of
them. For no, ask whether to wield the whole stack. Or you can give
an explicit count when picking any stack in inventory to wield.
Both 'w' and 'Q' probably ought to handle the alternate/secondary
weapon similarly when it contains a stack. This doesn't address that.
Changing an inventory item's bknown flag wasn't followed by a call to
update_inventory() in many circumstances, so information which should
have appeared wasn't showing up until some other event triggered an
update.