Reported by k2: tipping one container's contents directly into
another container allowed transferring a wand of cancellation (not
mentioned: or a bag of holding or a bag of tricks) into a bag of
holding without blowing it up.
That's now fixed. There are other issues that this doesn't touch:
I think it's odd that you can transfer stuff from one carried
container to another but not from a carried container to a floor
container nor from one floor container to another one at same spot.
I didn't test shop billing so an not sure what happens when #tip
blows up a bag of holding and there are some unpaid items involved.
Using #tip on horn of plenty treats it like a container, but doing
that when it's carried doesn't offer the chance to tip its contents
directly into a carried container.
Tipping a carried container does not require free hands or even
limbs (for playability) but tipping such into another container
should require at least one free hand.
Fixes#872
Renaming got_from_config[] (something that was done in the past)
to set_in_config[] (something to do in the future) is sufficient to
remove any confusion about why it is being set from 'O'. Since that
is the name of an enum value, use opt_set_in_config[] instead.
The definition of enc_stat[] got changed by a pull request nearly a
year ago ('const char *enc_stat[]' -> 'const char *const enc_stat[]')
but the separate declarations for it weren't changed to match.
Make the same change for hu_stat[]. Not sure why the pull request
didn't include it since the old declaration and the usage are same.
The curses one is in code that isn't used.
Reported seven and a half years ago: if you are in a vault but not
carrying any gold and the guard arrives, you're told "Follow me."
Then if you pick up gold while the guard is still in the wall breach
rather than out in the corridor, you would be told "I repeat, drop
that gold and follow me!" "Repeat" refers to the follow part but
sounds as if it refers to the drop-gold part which isn't actually
being repeated. Keep track of whether the guard has issued a drop
gold demand and use that to vary the wording of subsequent "I repeat"
message.
Modifies monst->mextra->egd so save and bones files are invalidated.
When fuzzing, noticed a trap generated inside a wall. Culprit
was one of the themed rooms that generates a rectangular room and then
puts freestanding wall columns inside. Note in somexy that it can
return a non-accessible location, and change the places that used
it and absolutely needed a space to somexyspace.
For a compound option's value that uses getlin(), cancelling with
ESC wasn't dismissing the menu and could eventually result in a
"No window slots!" panic. Clean up properly after ESC.
doset() and doset_simple() were sharing a format string but those
weren't the same if the longest option name differed. Stop sharing.
doset_simple() didn't support menu_tab_sep. Now it does. (Tested
with Qt; really needs to be tested with WinGUI. Enabling that is
expected to produce strange looking results with tty or curses.)
While testing the secret door message handling, I wanted to phaze
through solid rock to get near some secret corridors. Instead of
polymorphing into a xorn, I used #wizintrinsic to get temporary pass
through walls. That let me move orthogonally through rock but not
diagonally. Polymorph to xorn did allow diagonal movement. I think
the difference was gaining 18/100 strength in that form.
Have wall phazing override narrow diagonal checks.
When zapping a wand of secret door detection or casting spell of
detect unseem instead of displaying
|You reveal secret doors.
|You reveal a secret corridor.
|You reveal traps.
|You reveal a hidden monster.
show
|You reveal 2 secret doors, a secret corridor, 3 traps, and a hidden monster.
as a single message.
Detecting invisible monsters is still a separate message; those get
re-mapped as "remembered, unseen monster" but not actually revealed.
The pull request included some changes that were neither accidental nor
unintentional, so only a subset of the changes from pull request #869
submitted by klorpa were manually applied.
behaviour -> behavior
speach -> speech
knowlege -> knowledge
incrments -> increments
stethscope -> stethoscope
staiway -> stairway
arifact -> artifact
extracing -> extracting
The uses of "iff" were left alone.
Close#869
Move the guts of doset_simple() into a separate routine. Initially
that was just to avoid having to increase indentation when replacing
'goto' with 'do { ... } until ()'. It ends up making the flow of
control easier to see.
doset() and doset_simple() each had their own static flag indicating
whether 'fmtstr_doset' had been assigned a value. Redundant
assignment produced the same value so it wasn't an actual problem.
doset_simple() probably needs to add menu_tab_sep support for WinGUI.
Qt is able to get by without it, but that's because it forces use of
fixed-width font when any line in a menu or text window has 4 or more
consecutive spaces. I don't think WinGUI does that.
Wizard-mode command to cast any spell without checks that would
prevent casting, and with no energy use.
Mainly to allow the fuzzer to exercise the spell code paths.
Some static analyzers flagged the last-resort values as
out of bounds (which they were).
There's a small number of other complaint-suppression items in here too,
but nothing drastic.
The menu for #herecmdmenu includes "look at map symbol" but if you
choose that it auto-picks the hero's location. Looking at your own
'@' isn't particularly useful so only include that menu option if
the symbol or tile being displayed isn't the normal one.
Avoid potential impossible "obfree: deleting worn object" warnings
when entering the endgame.
The code to get rid of items migrating to non-endgame levels passes
those items to obfree(). It needs to clear obj->owornmask first
because that's used for migration flags (undelivered orctown loot
has a non-zero value).
mkmap creates mines-style full-level maps, so it should wipe
out all the room numbers in the level away. Also, it uses
temporary rooms for making sure the map is fully joined together;
those temporary rooms were left on the map, but should've
been cleared away.
When putting down map-parts on the level, don't remove the room
data which would be under that map; the map may have holes in them
(using the "x" map char), so a room may still exist there.
I don't think it matters if there is any room data which doesn't
have any room numbers referring to it in the level.
(Usually the special levels use map right after level_init anyway,
so there wouldn't be any rooms in the level)
Calling des.mineralize() with no arguments was equivalent to calling it
and manually specifying gem_prob = 0, gold_prob = 0, etc. Which meant
that no mineralization would actually happen.
Instead, make this match the intuitive behavior, and pass in -1
probabilities as defaults -- which the mineralize() function interprets
as the caller wanting to use the standard probabilities for a level of
that depth, as if it were not a special level.
This change does not affect any special level files since des.mineralize
is not currently used in any of them.
Nothing about read_simplemail is incompatible with using const, and the
lack of const required some contortions (copying ADMIN_SERVER_MSG to
another buffer with nonconst() to prevent a compiler warning).
This was the last place nonconst() was used, so I removed it.
Make admin message use urgent_pline so it's less likely to be skipped
and inadvertently missed, make ending punctuation conditional on message
itself not containing any (similar to what's done for T-shirt messages
in read.c), guard against printing an empty message (from a line like
"name:\n"; it does mean that subsequent messages in a single batch will
be discarded, but that's true of the existing guard against malformed
lines as well, and it should make the overwriting of characters past the
'msg' ptr safer).
If the summon nasties spell creates a single monster, the feedback
changes from "Monsters appear" to "A monster appears" but if you
were invisible or displaced it still said "around". Avoid
| A monster appears around a spot near you!
or
| A monster appears around your displaced image!
Reported by entrez: when a monster casts the "summon nasties" spell,
double feedback was given. First it produced "a <monster> appears"
for each visible monster and then "<monsters> appear from nowhere" at
the end. The latter would have been ok at the begining but made it
seem as if even more monsters were arriving when given at the end.
Skip the monster-by-monster feedback and just give the summary at the
end. That's enough information for a blind player to know to check
the map for new monsters.
When summon nasties is performed as randomly chosen harassment after
killing the Wizard, it still gives the enumerated "a <monster> appears"
feedback but does not give the "from nowhere" message at the end.
Reported by entrez: fake player monsters on the Astral Plane level
were giving "<role> suddenly appears!" feedback if they could be
seen or sensed when the hero arrived on that level.
They're generated separately from the level itself so the message
suppression in place during level creation didn't guard against it.
This is a large iteration on a previous implementation of making
nh.getmap() parse its coordinates as relative to the last defined map or
room rather than absolute to the entire level. Now, everything in the
nh.* and obj.* functions interprets coords as relative rather than
absolute. (By default; if no map or room has been defined, or if the lua
code is executing after level creation is done, they will interpret the
coordinates as absolute).
The general motivation is basically the same - routines that use
absolute coordinates are difficult to use in level creation routines,
because then the designer has to remember to convert the relative
coordinate to an absolute one (and that was impossible before
nh.abscoord was added, particularly in themed rooms). And once
nh.getmap() takes relative coordinates, it would be very strange to have
all the other functions (setting timers, burying objects, etc) remain
with absolute ones.
In a couple places, code is changed to account for coordinates that are
relative to a *room* (which uses g.coder->croom->[lx,ly] as an offset,
instead of relative to a *map*, which uses [xstart,ystart].
Specifically, selection.iterate did not account for this, and without
this the ice themed room timer was not being started in the proper
place.
All tests are updated to respect the new behavior. Most of the modified
functions are not actually used anywhere in level files; the one
exception is starting a timer in a themed room, and that has been
adjusted.
Documentation updated as well to clarify when various things are tossing
around relative and absolute coordinates, both in comments and in
lua.adoc.
There are many possible use cases for nh.getmap during level creation,
but it's rendered mostly unusable by virtue of always returning data
about the exact x,y coordinate in g.level.locations. (In particular,
it can't currently be used in themed rooms at all, because the themed
room could be anywhere on the level.) This is inconsistent with how most
other coordinate-based functions work following a des.map, which use
coordinates relative to the 0,0 point of the map.
This changes it so that during level creation only, if nh.getmap is used
following a des.map statement, it will look up the coordinates relative
to the origin of the map, consistent with the other functions.
delivered across level change checkpointing
Reported by entrez. Simplest test case: give level 1 a short
annotatation, level teleport to level 2, and level teleport back to
level 1. The message window will show
|You materialize on another level. You remember this level as <note>.
but ^P message history will show
|You materialize on another level.
| You remember this level as <note>.
Spaces inserted to separate two messages that fit together on the
top line become part of the second message when saving a checkpoint
during level change flushes the top line into message history.
Change insurance checkpointing to record the full message history
without flushing the current top line so that toggling 'checkpoint'
doesn't affect what shows up on the screen or in message recall.
Fix a bunch of "suggest braces around initialization of subobject"
warnings from clang. If gcc didn't warn about these before, it might
start complaining about too many braces now.
It doesn't attempt to do anything about missing field initializers
because I'm not seeing any warnings for those.
Formatting became strange when '#ifdef WIZARD' became unconditional
several years ago, then the bitmask testing code itself became a bit
strange when amnesia got changed a couple of years ago.
(unconnected to the current dungeon branch, that is)
Level teleporting allows you to type in the name of a level instead of
its number. This normally only works for levels within your current
dungeon branch (main dungeon <-> Gehennom levelports are the exception):
entering "medusa" as a destination won't work while the hero is in the
Gnomish Mines, but it will work fine to get to the Medusa level from
elsewhere in the main dungeon.
Teleporting to a particular branch entrance didn't apply the same
restriction. The teleport would still happen even if the destination
branch was unreachable from the current branch, and in such a case the
game would just try to get the hero to the depth of the branch entrance,
within the current branch. For example, entering "quest" as a
destination within the Gnomish Mines would bring the hero to Mines' End,
since that's the closest depth-wise it's possible to get to the quest
portal level. Apply the same rules to branch entrances as exist for
named levels, excluding destinations that are unreachable from the
current branch.
The sections of the dumplog can be broadly organized into two
categories: 'current state' and 'game overview'. Current state includes
information about what exactly was happening when the game ended: the
map, recent messages, current inventory, and current attributes. Game
overview is more like a history of the game up to that point: vanquished
monsters, extinct species, conducts, and dungeon overview.
All the current state sections are listed first, followed by the game
overview sections -- I'm not sure if this was a deliberate move to break
the dumplog into two distinct 'chapters', but it's convenient for
readers who may only want to know the circumstances of a death without
seeing the nitty-gritty details of the entire game up to that point.
The one section that wasn't ordered with its category was major events,
which was positioned near the top of the 'current state' group, above
the inventory listing. This commit moves it into the 'game overview'
group. I put it at the top, since it can serve as a sort of summary of
the game for those who are interested but don't care about some of the
details of monsters killed, etc.
I was never too happy with how this was a silent effect that required
you to watch the map to see if anything changed. It might count as
an accessibility issue as well, not sure.
This change adds specific feedback for all the possible things that
might get revealed by detecting unseen. If you reveal a secret door or a
trap, you now get a message indicating that.
One slight behavior change here: if the only thing detected is invisible
monsters, the game previously did not return a result of "detected
a non-zero number of things" to the caller of findit(); now it does.
(This allows the wand to be automatically identified when it prints a
message about detecting invisible monsters.)
If you had both warning and ESP, you would get the message "Your danger
sense causes you to take a second look close by" when moving next to a
monster that is technically "undetected" (according to mundetected) but
was actually apparent to the player via ESP. For instance, moving next
to an eel hiding in the water would produce this.
Since there was no follow-up message ("You find a <monster>".) and no
new information being given to the player, the "danger sense" message
was pointless, and so I removed it in this case when the warning doesn't
lead you to find anything new.
When a monster did something trying to get out of a boulder fort,
it usually meant teleporting or going down stairs or a hole.
The code didn't check for the action return value, and resulted
in a migrating monster being able to throw a potion at hero.
When you were busy with an occupation, such as digging with
a pickaxe, and a prompt showed up to ask you enter something,
the game just hung with infinite loop.
Remove the occupation check returning a NUL from the input
function. I didn't notice any side effects, but I would not
be surprised if something comes up ...
I didn't investigate which commit caused this, but I suspect my
rhack or parse changes.