Commit Graph

540 Commits

Author SHA1 Message Date
nhmall
0792e5fe9e expand implicit fallthrough detection to non-gcc compilers
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.
2024-11-30 14:16:27 -05:00
nhmall
d428beb8dd remove an unused prototype 2024-11-10 17:58:04 -05:00
nhmall
c87a373b11 more follow-up related to #1320 2024-11-10 10:06:07 -05:00
nhmall
5cc529efc8 follow-up related to #1320
This is additional groundwork related to
https://github.com/NetHack/NetHack/issues/1320

This additional groundwork just puts some safeguards
in place to make it rather tough to end up with an
instant death from handling a cockatrice corpse in
your inventory without appropriate protection.

At this point, still no actual petrification will occur.
2024-11-09 23:49:10 -05:00
nhmall
9c554895b1 adjust wish for cockatrice corpse
Wishing is powerful, so if you cannot safely handle a cockatrice
corpse, then have a wish for one result in the corpse materializing
on the floor rather than in your inventory.

Resolves #1320
2024-11-09 14:06:43 -05:00
nhmall
e863583c56 iterating gi.invent (github issue #1315)
GitHub issue #1315 points out that it is possible for
a downstream function to change an object's nobj field
to point to a completely different chain.

The cited example by @vultur-cadens was:

     for (obj = gi.invent; obj; obj = obj->nobj)
         if (obj->oclass != COIN_CLASS && !obj->cursed && !rn2(5)) {
             curse(obj);
             ++buc_changed;
         }

    curse() drops the weapon with drop_uswapwep(),
        which calls dropx(),
            which calls dropy(),
                which calls dropz(),
                    which calls place_object().

place_object alters the nobj pointer, to point to the floor chain:
    otmp->nobj = fobj;
    fobj = otmp;

The result was that the next loop iteration was then using floor
objects from the floor chain.

This alters several for-loops to use a more consistent approach,
particularly when the obj is being handed off to a function,
where a downstream function might, or might not, alter the nobj
field.

References:

https://github.com/NetHack/NetHack/issues/1315
https://www.reddit.com/r/nethack/comments/1gkc9ub/even_if_you_drop_an_item_before_drinking_from_the/
2024-11-06 16:59:51 -05:00
PatR
02cc7c76e6 add '?' choice after choosing '* for force_invmenu
If the force_invmenu option is On for choosing an inventory item
and the set of likely candidates is only a subset of full inventory,
then "* (list everything)" is an extra menu choice.  If the player
picks that, the menu is reissued showing entire inventory (with the
extra "* (list everyhing)" choice omitted this time).

When that happens, add "? (list likely candidates)" instead, so that
the menu can be toggled back to how it initially was.

If the menu allows choosing anything in inventory (the 'd' command,
for instance), it will already show full inventory and neither '*'
nor '?' gets included as helper choices.
2024-09-26 09:57:31 -07:00
nhmall
60dc14952d overflow if 'word' arg points to full QBUFSZ buf
This prevents a buffer overflow that was encountered during fuzzing,
but the underlying issue in the caller dodip() is still pending.

That appears to be the result of 'obuf' not being filled with
appropriate content prior to being used at line 2343 in potion.c.
2024-09-14 12:54:34 -04:00
PatR
aa043f0ddf some reformatting (2 of 4) 2024-09-05 14:51:21 -07:00
PatR
65b5f2cff1 farlook & probing feedback for monsters in regions
When looking at a monster that's inside a gas cloud, include that
fact in the output for farlook and for probing.  When the monster
being examined is sensed rather than seen, you'll sense the presense
of the cloud as well as the monster even if the cloud can't be seen.

Do likewise for self when using look-here (':').  Bonus fix: zapping
wand of probing at self while engulfed reported that you were just
held by the engulfer.

Also fix an old comment typo/thinko.
2024-08-19 13:10:28 -07:00
nhmall
0eb7f109e0 follow-up, program_state 2024-07-13 16:31:35 -04:00
nhmall
6c0ae092c6 distinguish global variables that get written to savefile
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
2024-07-13 14:57:50 -04:00
PatR
f634bb863f refine context-sensitive inventory action 'w'
|w - wield this item in your hands
is "suboptimal" when poly'd into some form which lacks hands.  Don't
offer 'w' as a choice if in a form what can't wield anything, and
substitute "claws" for "hands" when in forms that warrant it.

Include iron ball as a type of item leading to 'w - wield as weapon'
instead of falling through to 'w - wield in hands'.
2024-05-21 14:27:49 -07:00
PatR
a1692a8061 update context-sensitve inventory actions
Since inventory actions can be used as teaching aids for regular
command usage, change picking a potion in inventory from
|q - Quaff this potion
to
|q - Quaff (drink) this potion

When picking the uquiver item in inventory, add
|f - {Shoot|Throw} this item
and for the shoot case, tack on "with wielded <launcher>".

That makes 't - {Shoot|Throw} this item' nearly redundant (but only
for an item in uquiver slot) so tack on "(same as 'f')".

For the 'Q' choice (only offered for weapons or rocks/gems), have it
mention what the quiver is for rather than just that choosing that
menu entry would put the stack in the quiver slot.

For 'E - Write on the floor with this object', change the verb to
"Engrave" when the object is a bladed weapon, hard gem, hard gem
ring, or wand.  It also changes 'floor' to surface() which might
need some refinement.

For non-weapons, change 'w - Hold this tin opener...' and 'w - Hold
this item in your hands' to 'w - Wield this...'.  The concept of
holding an item in hero's hands isn't applicable in general, and in
particular any "held" item replaces wielded weapon.

For a bunch of instances of "this item", when the quantity of the
selected inventory entry is more than 1, change to "one of these
items" or "this stack" depending on how the specified action deals
with stacks.
2024-05-21 11:28:12 -07:00
Pasi Kallinen
312a4bcd26 Fix weight of merged partially eaten food
Due to integer rounding, merging two partially eaten food rations
will have wrong weight if we add the old weights together.
Recalculate the weight instead.

quan = 1, weight = 6  (6.675)
quan = 2, weight = 13 (13.35)
2024-05-06 12:06:33 +03:00
Michael Meyer
b662134eba Fix: bill_dummy_obj billed excessively for stacks
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
2024-04-27 18:42:50 -07:00
PatR
f801863e5c misbehavior by #adjust
Reported directly to devteam:  using '#adjust a a' to collect
invent stacks compatible with the one in slot 'a' all into 'a' gave
feedback of "Merging: a - ..." even though "Collecting: a - ..."
was intended.  Also, if there weren't any such compatible stacks,
so that the whole operation didn't accomplish anything, it reported
"Collecting a - ..." without the intended colon between the action
and the inventory letter.

Test case was trivial:  start with a stack of 2 of something in 'a'
and use '#adjust 1a b' to split into two stacks, then '#adjust a a'
to collect them back again.

While fixing this, I noticed that '#adjust a b' and '#adjust b a'
(from same starting situation) just swapped a and b instead of the
intended behavior of merging them back together.
2024-03-21 22:32:31 -07:00
nhmall
295d6e257c used, unused variables
some variables marked as unused, are now actually used
some unused variables are eliminated or commented out
2024-03-16 12:53:58 -04:00
nhkeni
9c0ed8ae63 NOSTATICFN for src/* 2024-03-14 17:41:51 -04:00
RainRat
a3658f85ac fix typos 2024-02-28 20:15:56 -08:00
Erik Lunna
eb22a81088 Refactor, unify, and nerf item destruction
Note: Original change is from xNetHack by copperwater <aosdict@gmail.com>,
      but this commit comes from HACKEM-MUCHE by Erik Lunna, with
      some minor code formatting.

From xNetHack commit a0a6103bea:

'The original goal: nerf item destruction using a method I initially
 proposed for SpliceHack, in which the number of items subject to
 damage from any single source is limited by the amount of damage the
 effect caused. The intent was to be more fair all around and prevent
 aggravating situations where, for instance, a chest shock trap zaps
 you for 4 damage and immediately ten of your rings and wands blow up.

 Problem 1: no easy way to limit the items destroyed without biasing
 heavily towards the start of the invent chain. The old code was able
 to get away without bias by just indiscriminately destroying
 everything eligible with a 1/3 chance. Here, I had to introduce
 reservoir sampling in a somewhat more complex form than I've applied
 it elsewhere, since there are a pool of potential items.

 Problem 2: destroy_item no longer worked remotely like destroy_mitem,
 which still destroyed 1/3 of items indiscriminately. Commence the
 process of squishing them into one function that handles both the
 player and monsters. (Which required making a lot of adjustments to
 destroy_one_item, now named maybe_destroy_item, on nits such as
 messaging and when to negate damage. An annoying consequence of the
 merge is that in the player case, their HP is deducted and they can
 be killed directly, but for monsters they need to add up the
 destruction damage and return it.)

 Unifying destroy_item and destroy_mitem has some advantages: in
 addition to the obvious code duplication removal, it ensures monsters
 now take the same damage as players for destruction (previously they
 took a piddly 1 damage per destroyed item). Now when you hit
 something with Mjollnir and their coveted wand of death breaks apart
 and explodes, you at least get the satisfaction of knowing they took
 the standard amount of damage from it.  Monsters also now get
 symmetry with players in having extrinsic elemental resistance
 protect them from item destruction, and damage negation from item
 destruction if they were appropriately resistant.

 Problem 3: a lot of callers didn't preserve the "amount of incoming
 damage" that this refactor relies on. E.g. if the defender resisted
 that element, the local dmg variable would be set to 0. So I had to
 do some wrangling with callers to save that original damage
 value. The rule of thumb is: all *incoming* damage counts. So that
 includes the player's spellcasting bonus if applicable, but not
 things like half damage, negation due to resistance, or extra damage
 due to being vulnerable to cold/fire.

 Then I figured, while I'm here let's get rid of all those silly cases
 where destroy_items is called multiple times for various different
 object classes, and cut the object class parameter out of it. This
 has a few minor effects:

 - Places where different object classes previously rolled
   independently for destruction to happen at all now roll
   once. (Which, by my calculation, generally means less incidences of
   destruction - a fire attack now won't have three separate chances
   to hit your scrolls, potions, and spellbooks. On the flip side, a
   lucky roll will no longer save an entire object class in your
   inventory.)

 - Callers can no longer specify different probabilities for
   destroying different object classes. The only place this was really
   used was to call destroy_item with a slightly lower probability on
   SPBOOK_CLASS.  With the nerf in this commit, less of them ought to
   be destroyed anyway.

 - A very edge case of where explosion-vs-monster damage was totted up
   differently for golems, which could result in differences of a hit
   point here or there.

 - All object classes being processed in one go means that less items
   are destroyed than would be if they were still processed
   independently.  This is not really visible compared to the old
   baseline of just destroying 33% of everything, but would be a
   marked difference versus a copy of the game that still called
   destroy_items separately for different object classes. To
   compensate, I adjusted my planned damage-to-destruction-limit
   scaling factor down from 8 to 5.

 Not done: merging in ignite_items(), though that would probably be
 really easy now.'

Notes from porting from xNetHack:

- It might be necessary to reexamine at all the conditional checks for
calling destroy_items. Because item destruction is much more
restrained and uses the actual damage from an effect, we might now
need to check 'if (!rn2(3))' and similar in all the places item
destruction occurs.
2024-02-20 22:03:54 +02:00
nhmall
688ac6ffbe remove register from variable declarations 2024-02-19 16:30:07 -05:00
nhmall
3a9e53a629 issue #1205 - crash using the curses interface
curses_yn_function() was returning a value that wasn't in the
subset of legal return values. This fixes that.

The unexpected return value of 32 (or space) then brought to
light an indexing error in the core that's been there a while,
apparently since at least 3.2.0, and that caused a null pointer
dereference in a strlen() call, which is what actually caused
the crash in issue #1205. This fixes that too.

Close #1205
2024-02-06 13:12:04 -05:00
PatR
899cca50ef alternate fix for merge_choice() with Null invent
merge_choice() doesn't need the address of its list argument, just to
return Null if that list is Null.  Could have been solved by having
its callers check for Null invent and skip the call if necessary but
this is simpler.

Finishes reverting commit 378648bd9c.
2024-02-01 14:38:28 -08:00
PatR
16f4bdb5a6 Revert "fix crash on NULL gi.invent"
This reverts commit 378648bd9c.

The problem was triggered by marking the 'objlist' argument in
merge_choice() prototype with __attribute__((nonnull)) when it
shouldn't have been, then a followup which relied on that.  The
'objlist' argument might be Null.  Instead of passing its address to
force it to be non-Null, remove the attribute.
2024-02-01 14:25:23 -08:00
nhmall
378648bd9c fix crash on NULL gi.invent 2024-01-31 12:51:33 -05:00
Pasi Kallinen
90cc3102f5 Don't use static buffer 2024-01-23 17:56:02 +02:00
Pasi Kallinen
a45f07c9b4 Comment typo 2024-01-23 17:32:32 +02:00
Pasi Kallinen
50df01c3e1 Split out empty hands menu option text 2024-01-23 17:27:07 +02:00
PatR
593a93d254 obj->how_lost fix
PR #1140 added checking the thrown, stolen, and dropped flags of an
item when testing whether it would merge (at my suggestion...) with
a stack in the target list (hero's invent).  That interferred with
picking it back up--whether via autopickup or explicit pickup--while
inventory was full even when the item would otherwise be mergable.

There was some trial and error involved when trying to figure where
to put the fix but things seem to be working.

This replaces a static analyzer workaround and could possibly bring
its unwarranted complaint back.
2024-01-21 01:17:18 -08:00
nhmall
4e19221e55 variable 'display' causes shadow variable warnings in X11 build
display.botl      -> disp.botl
display.botlx     -> disp.botlx
display.time_botl -> disp.time_botl
2024-01-05 05:58:51 -05:00
nhmall
49a5d043c0 consistent use of TRUE vs 1 with botl and botlx 2024-01-04 23:48:38 -05:00
nhmall
22e52ee905 bundle the display-related hints, that tell bot() and others
that an update is required, into a struct. Remove it from
context since there is no reason to save those.
2024-01-04 23:16:27 -05:00
nhmall
547adae5f9 follow-up invent.c 2023-12-24 00:23:15 -05:00
nhmall
2e35f04c1d static analyzer bit for invent.c
src/invent.c(4882): warning: Dereferencing NULL pointer '((otmp))->oextra'.
2023-12-24 00:19:41 -05:00
nhmall
c5a5b55c15 nonnull for some static functions during recent analysis 2023-12-16 10:51:59 -05:00
nhmall
6467b983eb part2: remediate some nonnull-related compiler warnings
do.c:296:16: warning: nonnull parameter 'obj' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion]
  296 |         while (obj && (otmp = obj_nexto_xy(obj, x, y, TRUE)) != 0) {
      |                ^~~ ~~
../include/extern.h:538:43: note: declared 'nonnull' here
  538 |                             const char *) NONNULLPTRS;
      |                                           ^
../include/tradstdc.h:378:36: note: expanded from macro 'NONNULLPTRS'
  378 | #define NONNULLPTRS __attribute__((nonnull))
      |                                    ^
1 warning generated.

invent.c:807:12: warning: nonnull parameter 'objlist' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion]
  807 |     while (objlist) {
      |     ~~~~~  ^~~~~~~
../include/extern.h:1230:61: note: declared 'nonnull' here
 1230 | extern struct obj *merge_choice(struct obj *, struct obj *) NONNULLPTRS;
      |                                                             ^
../include/tradstdc.h:378:36: note: expanded from macro 'NONNULLPTRS'
  378 | #define NONNULLPTRS __attribute__((nonnull))
      |                                    ^
1 warning generated.

monmove.c:2091:23: warning: nonnull parameter 'mtmp' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion]
 2091 |     boolean is_pet = (mtmp && mtmp->mtame && !mtmp->isminion);
      |                       ^~~~ ~~
../include/extern.h:1844:67: note: declared 'nonnull' here
 1844 | extern boolean undesirable_disp(struct monst *, coordxy, coordxy) NONNULLARG1;
      |                                                                   ^
../include/tradstdc.h:379:36: note: expanded from macro 'NONNULLARG1'
  379 | #define NONNULLARG1 __attribute__((nonnull (1)))
      |                                    ^
1 warning generated.

nhlua.c:2095:9: warning: nonnull parameter 'L' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion]
 2095 |     if (L)
      |     ~~  ^
../include/extern.h:1985:35: note: declared 'nonnull' here
 1985 | extern void nhl_done(lua_State *) NONNULLARG1;
      |                                   ^
../include/tradstdc.h:379:36: note: expanded from macro 'NONNULLARG1'
  379 | #define NONNULLARG1 __attribute__((nonnull (1)))
      |                                    ^
1 warning generated.

steal.c:59:12: warning: nonnull parameter 'chain' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion]
   59 |     while (chain && chain->otyp != GOLD_PIECE)
      |            ^~~~~ ~~
../include/extern.h:2910:43: note: declared 'nonnull' here
 2910 | extern struct obj *findgold(struct obj *) NONNULLARG1;
      |                                           ^
../include/tradstdc.h:379:36: note: expanded from macro 'NONNULLARG1'
  379 | #define NONNULLARG1 __attribute__((nonnull (1)))
      |                                    ^
1 warning generated.

utf8map.c:232:9: warning: nonnull parameter 'gmap' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion]
  232 |     if (gmap) {
      |     ~~  ^~~~
../include/extern.h:3318:28: note: declared 'nonnull' here
 3318 |               long ucolor) NONNULLPTRS;
      |                            ^
../include/tradstdc.h:378:36: note: expanded from macro 'NONNULLPTRS'
  378 | #define NONNULLPTRS __attribute__((nonnull))
      |                                    ^
1 warning generated.

worn.c:895:15: warning: nonnull parameter 'objchain' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion]
  895 |     if (on && objchain)
      |            ~~ ^~~~~~~~
../include/extern.h:3664:51: note: declared 'nonnull' here
 3664 | extern void bypass_objlist(struct obj *, boolean) NONNULLARG1;
      |                                                   ^
../include/tradstdc.h:379:36: note: expanded from macro 'NONNULLARG1'
  379 | #define NONNULLARG1 __attribute__((nonnull (1)))
      |                                    ^
worn.c:897:12: warning: nonnull parameter 'objchain' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion]
  897 |     while (objchain) {
      |     ~~~~~  ^~~~~~~~
../include/extern.h:3664:51: note: declared 'nonnull' here
 3664 | extern void bypass_objlist(struct obj *, boolean) NONNULLARG1;
      |                                                   ^
../include/tradstdc.h:379:36: note: expanded from macro 'NONNULLARG1'
  379 | #define NONNULLARG1 __attribute__((nonnull (1)))
      |                                    ^
worn.c:908:12: warning: nonnull parameter 'objchain' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion]
  908 |     while (objchain) {
      |     ~~~~~  ^~~~~~~~
../include/extern.h:3665:53: note: declared 'nonnull' here
 3665 | extern struct obj *nxt_unbypassed_obj(struct obj *) NONNULLARG1;
      |                                                     ^
../include/tradstdc.h:379:36: note: expanded from macro 'NONNULLARG1'
  379 | #define NONNULLARG1 __attribute__((nonnull (1)))
      |                                    ^
3 warnings generated.
2023-12-14 20:06:57 -05:00
Michael Meyer
1736f3caaa Add 'pickup_stolen' option
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]
2023-12-08 15:19:54 -08:00
Michael Meyer
ecda85cc32 Don't merge stacks w/ different was_thrown/dropped
Previously, if you threw a dagger into a pile of daggers, you'd pick up
the entire pile with pickup_thrown on.  Since pickup_thrown and
dropped_nopick options are supposed to apply specifically to items
you've handled, don't merge items with different values in those fields.
2023-12-08 15:19:05 -08:00
Michael Meyer
d7d1c1476d Add option to exclude dropped items from autopick
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.
2023-12-08 15:19:04 -08:00
PatR
c41cb1a7fa source reformatting
Fixup some of the inconsistently formatted code that has been
introduced recently or been building up for a while.  Done manually.
I wasn't systematic except for looking for lines ending in '&' or '|'
(which wouldn't find such things if they're followed by a comment)
so there might be lots more.  I changed a bunch of C++-style //...
comments to old style C /*...*/ so that they'll match the rest of
the core's code rather than because they shouldn't be used.
2023-12-08 00:30:10 -08:00
PatR
2bd967fe8a a few fewer update_inventory() calls
A couple of things I noticed while running umpteen tests for tty
perm_invent.  Remove the update_inventory() from unmul(), and limit
the one that deals with seeing inventory when recovering from blindness.

Just a drop in the bucket overall, and the screen updates nearly
instantly for update_inventory() except when debugging perm_invent so
players aren't likely to notice this.
2023-12-07 22:47:57 -08:00
Pasi Kallinen
5dc94f3d83 Macro for picking random entry from array 2023-12-05 10:06:27 +02:00
PatR
2713853f28 another uhandedness bit
For the accessories section of '*' and perminv_mode=InUse, show the
ring on main hand first (after amulet) and the one on off hand after
(before blindfold).  Main hand ring is more significant due to the
potential of a one-handed weapon becoming cursed, preventing it from
being removed.
2023-12-04 00:54:42 -08:00
Michael Meyer
03801773a8 Allow #dipping bare hands from pickinv menu
This wasn't being provided as an option because apparently all actions
which allow hands needed to be explicitly added to the list in getobj().
Add a fallback default 'hands' entry for any action which permits hands,
which both allows #dipping your hands and means that future additions of
hands as a target to other actions will work with OPTIONS=force_invmenu
without needing to remember this.

I made it so that hands will only be presented in the pickinv menu if
they are actually one of the suggested/likely items, which was a little
tricky because pickinv was only looking at actual inventory to determine
whether some items were excluded and the "show everything" option should
be presented.  I had to add a parameter to inform it that hands are
allowed so it would know to display that option if they were allowed but
no 'hands' entry was passed in xtra_choice.  Not sure if there was a
better way to let it figure that out...
2023-11-30 18:36:09 -08:00
nhmall
d7fef5f194 avoid another magic number
Some of the hardcoded +1 scattered about are likely
invlet_gold or invlet_overflow, but I didn't hunt those down.
2023-11-30 11:15:32 -05:00
PatR
f6e70bbc58 two-weapon combat on/off via inventory item action
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.
2023-11-28 01:15:04 -08:00
PatR
e6a7eb25d4 item actions for '* ) [ = " (' commands
Make the various item-in-use commands put up a menu--which allows
choosing an item for context-sensitive item action--if/when preceded
by the 'm' prefix.  Some of them do that even without the prefix ('*',
'[', or '=' when more than one ring is worn).  By default '(' shows
primary weapon, then secondary one if dual-wielding.  'm (' shows a
menu of primary, alternate whether dual-wielding it or not, and quiver.
2023-11-28 00:31:21 -08:00
PatR
6c5b5c0688 more '*' and perminv_mode==inuse
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.
2023-11-25 14:11:43 -08:00
PatR
99ccb7a26f revamp '*' (#seeall command)
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.
2023-11-24 16:13:39 -08:00