They're never modified. Minor complication: &zeroobj is used as
a special not-Null-but-not-an-object value in multiple places and
needs to have 'const' removed with a cast in that situation.
More shop price determination fallout. After the most recent change
to get_cost_of_shop_item(), using ':' inside an engulfer carrying at
least one item while inside a shop would try to follow the item's
obj->ocontainer back-link and crash when that led to the engulfing
monster rather than to a container.
Some object classes (such as armor and weapons) are split into
"subclasses" when sortloot applies an ordering (for armor, all helms,
then all gloves, then all boots, and so on). Give gem class subsets.
Simple (1) valueable gem, (2) worthless glass, (3) gray stone, (4) rock
would give away information; instead, factor in discovery state and use
(1) unseen gems and glass ("gem")
(2) seen but undiscovered gems and glass ("blue gem"),
(3) discovered gems ("sapphire"),
(4) discovered glass ("worthless pieced of blue glass"),
(5) unseen gray stones and rocks ("stone"),
(6) seen but undiscovered gray stones ("gray stone"),
(7) discovered gray stones ("touchstone"),
(8) seen rocks ("rock").
If everything happens to be identified, the simpler ordering happens
(via 3, 4, 7, and 8) because the other subsets will be empty.
It was possible to have the guaranteed luckstone at Mines' End become
merged with a random one and lose its specialness for achievement
tracking. Mark it 'nomerge' when created and clear that if/when the
achievement is recorded.
stolen_value() treated hero-owned container holding shop-owned goods
as free for the taking.
The fix I'm working on which led to discovering this first added
stolen_value() then eventually stopped using it so I don't have an
example of where it is giving the wrong result.
Dropping an existing fragile item while levitating will usually
break it. Getting a new wished-for fragile item and dropping it
because of fumbling or overfull inventory never would.
Some callers of hold_another_object() held on to its return value,
others discarded that. That return value was unsafe if the item
was dropped and fell down a hole (or broke [after this change]).
Return Null if we can't be sure of the value, and make sure all
callers are prepared to deal with Null.
I don't know why we have two different functions which do exactly
the same thing (checking whether an item is unpaid or is a container
that holds at least one unpaid item), but switch the #H2504 fix to
use 'the other one' and reverse one of the changes made when using
the inventory one.
I thought that the earlier fix for #H2504 was too easy for anything
shop related. It didn't deal sensibly with containers owned by hero
but holding unpaid shop goods.
Add a new line for one last missing status field: gold.
Also add one for proficiency with current weapon.
Move a few lines from 'characteristics' to 'background' and a few
more from 'characteristics' to new 'basics', leaving characteristics
with the six original characteristics: Str, Con, Dec, &c.
Remove trailing spaces, and remove tabs from the files that had
trailing spaces.
Also, rndorcname() was using a random value to terminate a loop
and was recalculating a new one each iteration.
Get rid of bold/non-bold distinction in #wizidentify inventory menu
by only showing items which aren't yet fully identified instead of
full inventory with bold for unID'd. Support for bold text might
be lacking.
I was considering this even before the report that X11 menus ignore
attribute. The "_ - (use ^I for all)" menu entry is still present,
but it could be discarded in favor of '.' to pick everything via
ordinary menu selection.
Bug report #H7156 listed three items, all relating to perm_invent:
1) it shouldn't persist across save/restore since restore might be
on a system which doesn't have enough room to display it (report
actually complained that config file setting was ignored when
restoring old games, which is an expected side-effect for options
that persist across save/restore);
2) permanent inventory wasn't updated when using scroll of charging;
3) attempts to update permanent inventory during restore could lead
to crash if it tries to access shop cost for unpaid items.
Items (2) and (3) have already been fixed. This fixes (1).
Replace 'flags.perm_invent' with a dummy flag, preserving save files
while removing it from flags. Add 'iflags.perm_invent' to hold the
value of the perm_invent option.
The win32 files that are updated here haven't been tested. Whichever
branch contains the curses interface needs to be updated; ditto for
any other pending/potential interfaces which support perm_invent.
Don't display the selection to identify all items if there are none.
Complete an item marked ToDo in cmd.c: allow selection of one or more
particular items to permanently identify rather than just all or nothing.
Fixes#124
Fix github pull request #124 which was also reported directly (but not
through the contact form so #Hxxx number). Using ^I or #wizidentify
displays inventory with everything ID'd for that command only and adds
a menu entry "_ - use '^I' to identify" that can be chosen to make
those ID's persistent. Picking underscore would work but picking the
alternate '^I' wouldn't work if the platform had unsigned characters
for plain 'char'. Switch the return value from magic number -1 to
magic number ^I which isn't a valid inventory letter and isn't subject
to sign conversion. Casting -1 to '(char) -1' would have worked too
despite some confusion expressed in discussion of the pull request.
If ^I has been bound to some other command and #wizidentify hasn't
been bound to any keystroke, temporary ID didn't disclose any extra
information (ie, acted like ordinary inventory display) and the extra
menu entry to make temporary ID become persistent wasn't available.
This fixes that too.
Fixes#110
NetHack dumped core while qsort was executing for sortloot. Fix a
logic error introduced by adding filtering capability to sortloot()
which could result in a sparsely populated array instead of having
the number of elements be less than the list size.
I don't know why this didn't show up sooner.
Build fix, avoid use of 'class'
include\hack.h(199): error C2236: unexpected token 'class'. Did you forget a ';'?
include\hack.h(199): error C2332: 'class': missing tag name
include\hack.h(199): error C2027: use of undefined type 'sortloot_item::<unnamed-tag>'
The code that formats an object for use in alphabetic comparisons
during sorting is forcing off wizard mode to avoid any alternate
formatting that might produce. Add a guarantee that doing this can't
be used as a backdoor to create a normal mode panic file if someone
figures out a way to make xname() panic.
When objects are in the same class, sortloot orders them by their
formatted name. It was reformatting each object every time it got
compared to another object. Change that to remember the formatted
name so that any given object is formatted at most once (during the
current sort; future sorts will need to format it again).
Armor and weapon classes are subdivided into smaller subclasses
and the formatting plus alpha compare is only done for items in
the same subclass, so helms come out before cloaks and don't get
their names compared, for instance. [That was from my 'revamp'
rather than the original implementation.] This adds a couple more
subclass sets: food (named fruit, 'other' food, tins, eggs, corpses,
globs) and tools (containers, pseudo-containers [bag of tricks and
horn of plenty once those have become discovered; prior to discovery,
bag of tricks is classified as a container and horn of plenty as an
instrument], instruments, 'other' tools).
The main difference, aside from the formatting efficiency improvement,
is to change the previous sort order
| pink potion
| potion of enlightenment
| purple-red potion
to be
| pink potion
| purple-red potion
| potion of enlightenment
by grouping undiscovered items before discovered items when class and
subclass match. So discovery state is essentially a sub-subclass and
formatting plus string comparison is only done for members of the
same sub-subclass. There are actually four state values: unseen
(which applies to particular objects rather than to their type),
unknown (not discovered and not named), named (not discovered but has
player-assigned type name), and discovered (either fully discovered
or considered not interesting to discover [no alternate description,
not nameable]).
My testing was primarily done with pickup ('m,' with menustyle:T)
and sortloot:Loot (the default) plus !sortpack (not the default and
not a setting I ordinarily use, but less verbose without the class
separators). It won't astonish me if oddities crop up with other
usage combinations.
Yesterday's sortloot() overhaul didn't include some cockatrice corpse
handling for pickup. If there's an object class filter in place and
pickup has been told to care about cockatrice corpses, have sortloot()
include them in the loot array even if food class isn't accepted by
the filter. In the pre-sortloot days, and in 3.6.[01] which didn't
attempt to deliver a filtered subset of loot, the check for such
corpses was done before pickup checks the filter. They need to be in
the loot array to retain the same behavior.
H7205 - full-pack identify might skip items if perm_invent is on
because updating the inventory window might reorder 'invent'
while the identify code is in the midst of traversing it;
H7120 - pickup that doesn't pick anything up can change the glyph
shown on the map because the pile might be reordered such
that a different item is on top;
H5216 - performing a sortloot operation on a pile and then switching
back to sortloot:none doesn't restore pile's original order.
The 'revamp' that changed the contributed sortloot feature to switch
to simpler usage (object list itself was sorted rather than having a
parallel array that needed to be constructed, sorted, traversed, and
discarded) turns out to have too many problems. This reverts to a
hybrid solution that constructs an array for traversal, leaving the
linked list in its original order, but hides most of the details of
that from sortloot() callers. The 'revamp' benefit of being able to
use normal list traversal is lost, as is the potential to skip
sorting when the list turns out to already be in the desired order.
This could stand to have a lot more testing than it's had so far.
The comment I added to data.base--to explain that despite what the
short description says, an aklys wouldn't return to sender after being
thrown--was bugging me, so I've made aklyses behave like Mjollnir.
If thrown when wielded as primary weapon, it will usually return and
usually be re-wielded. I also added a new message when either thrown
Mjollnir or thrown aklys is expected to return and fails to do so.
Most of the diff to dothrow.c is a change in indentation level. The
amount of code needed was quite small.
Autopickup for thrown Mjollnir which had failed to return was putting
it into the quiver slot if that was empty. Note quite an outright bug,
but it started wielded and can't be thrown if quivered, so exclude it
from the stuff that will auto-fill the quiver slot when added to invent
(post-3.6.0 issue).
An inventory of unpaid items where more than one was present would
show
|> bag's contents N zorkmids
if any of the items were inside a container whose contents aren't
known. But if there was only one item (so container must be owned
by hero) the 'Iu' output menu was skipped for pline and yielded
|> scroll of magic mapping 133 zorkmids
Force the menu display if the lone unpaid item is inside a container
whose contents are unknown.
I'm not sure whether a hero-owned container can have both unknown
contents and an unpaid item in normal play. I managed it while
trying to fix a reported problem--except I can no longer find the
relevant report--where itemized shop billing also revealed unseen
container contents (for any number of items, not just 1). That isn't
fixed yet, but I want to get the simpler 'Iu' part out of the way.
Make the suggested change that only adjusting something into its own
slot be the way to collect/merge compatible stacks with it, instead
of any #adjust without a split count. This removes the previous
special case for a count that matches the stack size. Having to
know the exact count was not a burden on the player, but being able
to move things around without merging with other stacks makes more
sense than the original behavior or the hack to work-around that
behavior.
The report stated that '#adjust a c' after '#adjust 1a b' moved all
the original 'a' to 'c' instead of leaving the one in 'b' alone.
That's true, but it is also the intended behavior. Splitting off
with a count explicitly avoids gathering compatible stacks (but
does merge into the destination if compatible, instead of swapping).
Moving a whole stack gathers compatible ones and puts the whole
merged group into the destination.
But that leaves a gap in functionality: there's no way to get the
don't-collect-other-stacks without splitting; there ought to be.
So, allow the player to specify full count to move a stack from one
slot to another without collecting compatible stacks (the behavior
when no count is given) or splitting (the behavior when count is
less than full amount). In the example above, if 'a' started with
5 doodads and had 4 left after splitting one to 'b', '#adjust 4a c'
will move those 4 (all of 'a') to 'c' without merging 'b' into them.
The method is a bit obscure but it's also something which doesn't
come up very often.
Report was for tty, but X11 exhibited the same behavior. With the
perm_invent option enabled, when the permanent inventory window is
displayed, it would be empty if not carrying anything. For tty, that
meant a naked "(end) " selection prompt. Put a separator line of "Not
carrying anything" into the menu so that it won't be completely empty.
The selection prompt is still present but it is attached to something.
(The behavior is different from !perm_invent, where you get that same
text via pline without any menu at all.)
The followup message about the fix for #5056 was trapped by the spam
filter so didn't reach us for a while.
xlogfile has an extra field to track various achievements made during
the game it logs, two of which are fully exploring the gnomish mines
and fully exploring sokoban. Those are accomplished by finding the
special 'prize' item on the final level of their branch: luckstone
for mines and bag of holding or amulet of reflecition for sokoban.
3.6.0 had a bug where any item of the target type found anywhere in
the dungeon resulted in achieving the relevant goal. A post-3.6.1 fix
for that required that the item be found on the end level of the branch
and attempted to require that it an item explicitly placed there by the
special level loader, but the latter aspect had a bug which meant that
random items of the appropriate type placed on final level would count
as the prize. Chance of extra luckstones on mines' end is fairly high,
so potential for false completion of the achievement was also high.
The second complaint was that since the achievement was only recorded
if the special prize item was found on final level, then if a monster
took it to another level then the achievement became impossible. (Not
true, the player could take it back, drop it, and pick it up again, but
that is admittedly a pretty silly hoop to jump through.) On the other
hand, if a monster removed the item before the hero found it, then a
case could be made that the hero hadn't really fully explored the
level. However, this fix records the achievement no matter where the
hero picks up the item. The final level must be entered--otherwise no
monster could possibly acquire and transport the item--but it isn't
guaranteed to have been fully explored. Big deal....
The prize could also be acquired in bones data. Before the second
portion of this fix, that wouldn't have mattered. But now it does, so
clear the prize indicator when saving bones unless it happens to be the
same level where that item is created (impossible for sokoban, where no
bones are left; not sure offhand about mines' end). The former prize
stone or bag or amulet becomes an ordinary one of its type.
This can all be done in a much cleaner fashion once we give up on the
current save file compatability. Putting obj->o_id values into new
context.mines_prize and context.soko_prize, plus a hack to mkobj() to
not reuse those two values if the o_id counter ever wraps back to 0,
would cover most of the details. Adding an achievement tracking flag
to lev_comp's object handling for use by the special level loader
would cover most of the rest.
The recent fix to prevent #adjust from letting the player move things
into slot '-' (if compactify() reduced any sequence of consecutive
letters to x-y, introducing dash into the string of characters that
could be chosen from) was triggering a complaint about mixing &&
and || without parentheses. Fixing that was trivial, but I ended up
making a much more substantial change.
If the '#' overflow slot is in use, you can move something into it
even when you no longer have all 52 regular slots in use. (When it
isn't already in use, you can't access it. Previously you could swap
from '#' to any letter but not vice versa.) If you manage to get
gold in multiple slots or in some slot other than '$', you can move
or merge it into the '$' slot. And when that situation isn't present
(if even possible--I had to force it with a debugger to test), then
gold will no longer be listed among the inventory letters to adjust.
(That became an issue when GOLDINV came into use, but either nobody
ever noticed or at least never reported. "Adjust what? [$abd]",
then pick '$' and be told you can't adjust gold. Prior to GOLDINV,
'$' wasn't included in the list of candidates.)
The #adjust command allowed, due to compactified buf, putting
items into the '-' inventory letter, which is usually reserved
for "empty hands", zeroobj. This caused problems down the line
when user was allowed to pick that letter for dropping.
Turning the boolean option force_invmenu makes all the commands
that ask for an inventory item pop up a menu instead of asking
a text query. This should be much more friendlier to new
players, and is very useful for window ports on systems
with touch screens and no physical keyboard, such as cell phones.