Whitelist all the verified existing triggers:
makedefs.c: In function ‘name_file’
attrib.c: one compiler balks at a ? b : c for fmtstring
cmd.c: In function ‘extcmd_via_menu’
cmd.c: In function ‘wiz_levltyp_legend’
do.c: In function ‘goto_level’
do_name.c: In function ‘coord_desc’
dungeon.c: In function ‘overview_stats’
eat.c: one compiler balks at a ? b : c for fmtstring
end.c: one compiler balks at a ? b : c for fmtstring
engrave.c: In function ‘engr_stats’
hack:c one compiler balks at a ? b : c for fmtstring
hacklib.c: one compiler balks at a ? b : c for fmtstring
insight.c: one compiler balks at a ? b : c for fmtstring
invent.c: In function ‘let_to_name’
light.c: In function ‘light_stats’
mhitm.c: In function ‘missmm’
options.c: In function ‘handler_symset’
options.c: In function ‘basic_menu_colors’
options.c: In function ‘optfn_o_autopickup_exceptions’
options.c: In function ‘optfn_o_menu_colors’
options.c: In function ‘optfn_o_message_types’
options.c: In function ‘optfn_o_status_cond’
options.c: In function ‘optfn_o_status_hilites’
options.c: In function ‘doset’
options.c: In function ‘doset_add_menu’
options.c: In function ‘show_menu_controls’
options.c: In function ‘handle_add_list_remove’
pager.c: In function ‘do_supplemental_info’
pager.c: In function ‘dohelp’
region.c: In function ‘region_stats’
rumors.c: sscanf usage
sounds.c: In function ‘domonnoise’
spell.c: In function ‘dospellmenu’
timeout.c: In function ‘timer_stats’
topten.c: In function ‘outentry’, fscanf, sscanf, fprintf usage
windows.c: In function ‘genl_status_update’
zap.c: one compiler balks at a ? b : c for fmtstring
win/curses/cursstat.c: In function ‘curses_status_update’
win/tty/wintty.c: In function ‘tty_status_update’
win/win32/mswproc.c: In function ‘mswin_status_update’
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.
further adjustments to the window port interface to pass a pointer
to a glyph_info struct which describes not just the glyph number
itself, but also the ttychar, the color, the glyphflags, and the
symset index.
This affects two existing window port calls that get passed glyphs
and does the parameter consistently for both of them using the
glyph_info struct pointer:
print_glyph()
add_menu().
The recently added glyphmod parameter is now unnecessary and has been
removed.
This got out of hand pretty quickly. can_reach_floor() had
different criteria than trap activation. Objects dropped at a
hole locations that don't fall through were treated as if they
were at the bottom of an abyss, so couldn't be examined or
picked up.
This a bunch of changes; it is bound to introduce some new bugs.
Death will revive faster than the other riders.
Make all the riders revive after 67 turns, instead of 500.
There was practically a zero chance a rider would revive at 500,
so keep it somewhat sensible.
Use a linked list to store stair and ladder information, instead
of having fixed up/down stairs/ladders and a single "special" (branch)
stair.
Breaks saves and bones.
Adds information to migrating objects and monsters for the dungeon
and level where they are migrating from.
When a zombie (or lich) kills a monster in melee without a weapon,
the monster can rise few turns later as a zombie.
The only creatures that can be zombified are ones that actually have
a zombie counterpart monster. A zombie cannot turn a jackal into
a zombie, for instance. But it could turn a shopkeeper into a human
zombie, or a dwarf king into a dwarf zombie.
Zombies will fight with monsters that can be turned into zombies.
Originally this was a SliceHack feature, but this is based on xNetHack
version of it, with some modifications.
Noticed when fixing 'D$'. Some commands, including D, which should
have been handling venom weren't doing so.
I'm not sure whether I got all the applicable cases.
After modifications to amnesia, `deja vu' messages are now displayed
upon entering a level containing bones of a previous character of the
current player. This test is done simply by checking for a ghost on the
level that shares a name with the current character.
However, since ghosts generated in other circumstances (such as in the
Valley of the Dead and other special levels) can have names pulled
randomly from the high score list, etc, this message can be displayed on
non-bones levels where a ghost has been generated with the character's
name. Additionally, when a bones pile doesn't include a ghost (such as
when the character in question was slimed, killed by a wraith, etc), the
`deja vu' message will not be displayed when it should be. This is all
described in in NetHack/NetHack#322.
This commit changes the method of testing for `familiarity' by adding a
function to iterate through any bones data for the current level,
searching for a match to the hero's name.
Should fixNetHack/NetHack#322.
A check into github issue 364 confirmed that
ba6edbe5dc
had incorrectly updated the bwrite sizeof entry for sysflags.
The SYSFLAGS and MFLOPPY code is all in the outdated part of the tree, so just
remove it rather than re-correct it.
Closes#364Closes#207
when the drop is being caused by encumbrance or punishment triggering
a fall while going down stairs.
Also, remove a couple instances of 'if (obj==GOLD) contexl.botl=TRUE'
when dropping gold. They were held over from the obsolete !GOLDOBJ
configuration. Both are immediately followed by freeinv() which
calls freeinv_core() whichs starts off by setting the botl flag when
taking gold out of inventory.
and out of save files so restore doesn't need to clear stale data.
Behavior should be the same as before, except that when entering
the endgame branch and discarding the main dungeon and its other
branches, lua theme context is now discarded for those too.
Move the recently adopted swallower-eats-dropped-corpse code into
a separate routine to unclutter dropz(). Eat all corpses (also
globs and meatball/meat ring/meat stick/huge chunk of meat) rather
than just the few types which trigger special effects (polymorph,
turn to stone, etc).
Also guard against using a freed pointer if somehow a dropped edible
item merges with an existing inventory item (something carried prior
to shape change perhaps?) before having the worm eat it.
This reverses all of c67f1dd710
except for the fixes37.0 entry and does a better job in a cleaner
fashion. If Sting is going to start glowing and "you materialize
on a different level" is pending, give the materialize message
before the glowing message. Otherwise handle both stop-glowing
and/or you-materialize in the normal fashion.
When level teleporting, Sting/Orcrish/Grimtooth would start or stop
glowing based on occupants of the new level before "you materialize
on another level". That wasn't necessarily incorrect for the glow
stopping but was clearly wrong for it starting. This fix uses a flag
as a hack to avoid finding and changing all the calls to docrt() and
see_monsters(). It ought to be fixed properly....
Issue was for dropping glob of green slime while swallowed by a
purple worm but also applied to pet eating habits. Green slime
corpse doesn't exist any more; check for glob instead.
Fixes#333
... deleting the ball & chain, but keeping a boulder in the pit.
Noticed a segfault when fuzzing, teleport while punished caused
a segfault via fill_pit -> flooreffects -> bury_objs -> unpunish,
and then the next line in teleds tried to look up uchain.
Guard against that particular case.
Fix the case of boulder being in a pit, triggered by you being in
a pit and a giant throwing a boulder on top of you.
When rest and search refuse to operate because a hostile monster is
adjacent, include a reminder of how to force them to operate. Every
time if 'cmdassist' is On, or just once until after some subsequent
try actually does something.
This new rest and search behavior probably needs to be optional and
default to the old behavior. It isn't uncommon to deliberately rest
while adjacent to a hostile monster if also adjacent to a peaceful
one and trying to wait for Stun or Confusion to time out, or maybe
search while next to such a monster hoping to find a secret door to
run away through. A count prefix won't work and needing an extra
keystroke each time is going to be an annoyance.
Generally speaking there's no reason to wait or search next to
a hostile monster, so let's just prevent those actions. You can
still do those commands by prefixing them with the 'm' prefix.
I got "The chain mail rusts." seemingly out of the blue, then when
moving around the corner of the building on Valk home level I saw a
spot of remembered ice be redrawn as water. Before that I checked
for any mapped objects (via ';' 'o' 'o' ... so I didn't overlook
anything; there were only a couple of objects shown on the map and
none of them were piles) and didn't see any remembered chail mail or
anything at all on that ice spot, so I'm assuming that it was carried
by a monster. I may be leaving out some steps in the call chain here:
melt_ice -> minliquid -> mondead -> m_detach -> relobj -> mdrop_obj
-> flooreffects -> water_damage -> erode_obj
erode_obj() uses bhitpos for visibility check of eroding objects not
carried by the hero or by a monster, with a comment expressing doubt
about doing that. It wouldn't have yielded the right answer for the
possible call chain here unless it got set by some monster activity.
I had been zapping a wand just before and bhitpos would have been set
to a coordinate I could see at the time, fooling erode_obj()'s check
if the value was stale.
Anyway, this only addresses objects eroded from flooreffects(),
water_damage_chain(), and fire_damage_chain(). There are lots of
other indirect calls to erode_obj().
When swallowed by an air elemental, going down into a pit
placed the attached iron ball on the floor. Saving (or
using #wizmakemap) then deallocated the iron ball.
Check being swallowed before trying to go down.
Instead of forgetting maps and objects, make amnesia forget skills.
Forgetting maps and objects could be circumvented with taking notes,
or by using an external tool to remember the forgotten levels.
Forgetting skills allows the player to optionally go down another
skill path, if they trained the wrong weapon in the early game.
Amnesia still forgets spells.
As a replacement for the deja vu messages when entering a forgotten
level, those messages will now indicate a ghost with your own name
existing on the level, given only when the level is entered for
the first time.
These changes based on fiqhack, with some adjustments.
In wizard mode, if you angered your quest leader and got expelled from
the quest (which removes the quest portal from the dungeon), then used
the wizmode level teleport menu to teleport back to the quest start and
talked with the angry leader, you would get booted back to the dungeon,
and the game panicked because the dungeon end of the portal didn't
exist anymore.
Eliminate the cache that was supporting rndmonst() and pick a random
monster in a single pass through mons[] via "weighted reservoir
sampling", a term I'm not familiar with.
It had a couple of bugs: if the first monster examined happened to
be given a weighting of 0, rn2() would divide by 0. I didn't try
to figure out how to trigger that. But the second one was easy to
trigger: if all eligible monsters were extinct or genocided, it
would issue a warning even though the situation isn't impossible.
Aside from fixing those, the rest is mostly as-is. I included a bit
of formatting in decl.c, moved some declarations to not require C99,
and changed a couple of macros to not hide and duplicate a call to
level_difficulty().
Fixes#286
Mounting a steed while legs are wounded would offer to cure them
but wasn't going through the heal_legs() routine so didn't update
the status line when Wounded_legs condition is enabled.
Move some common code for describing left/right/both legs into a
new routine used for feedback by jumping, kicking, and ridiing.
For ^X, distinguish between one wounded leg and both but don't
bother with left vs right when it is just one.
Setting or clearing u.ustuck now requires that context.botl be set,
so make a new routine to take care of both instead of manipulating
that pointer directly.
Several conditions result in stale data on the status line when
starting or stopping because things which didn't used to affect it
haven't been setting context.botl to force an update. This wasn't
systematic; there are bound to be lots more.
Introduce eight achievements that can be attained by more players.
Entered Gnomish Mines - self explanatory
Entered Mine Town - the town portion, not just the level
Entered a shop - any tended shop on any level
Entered a temple - likewise for temple
Consulted the Oracle - bought at least one major or minor oracle
Read a Discworld Novel - read at least one passage
Entered Sokoban - like mines
Entered the Big Room - not always possible since not always present
The novel and bigroom ones aren't always achieveable since novels are
only guaranteed if a book or scroll shop gets created and bigroom is
only guaranteed in wizard mode. No one ever claimed that every
possible achievement can be attained in a single game. (If one for
entering the Fort Ludios level--or perhaps entering the Fort itself--
eventually gets add, that won't be possible in every game either.)
The mine town one probably needs some tweaking. Two of the town's
seven variants have no town boundary (despite a rectangular area of
pre-defined map) and at present simply arriving on either of those
levels is enough to be credited with the entered-town achievement.
Bump EDITLEVEL because u.uachieved[] has increased in size. This
time it has been expanded to the maximum that xlogfile's bitmask of
achievements can handle, enough for up to 9 more achievements without
another EDITLEVEL increment.
Instead of an assortment of bits, assign numeric indices to the
potential achievements and keep an array of those in the order they
were attained. So disclosure might show the same subset occurring
differently in different games depending on the player's actions.
The encoded field in xlogfile doesn't care about that and remains
the same.
Modifies 'struct u', so EDITLEVEL has been incremented and existing
save files are invalidated.
While testing the changes to dungeon and special level handling, I got
|A mysterious force prevents you from descending!
|You materialize on a different level!
The mystery force is handled by goto_level() so level_tele() doesn't
know that the failure is going to happen when it sets up the message
for deferred delivery. Suppress the message if you don't change levels.
If level teleport took you somewhere special, things like shop entry
or quest summons or valley atmosphere messages were being given first,
then "you materialize on a different level" after. schedule_goto()
takes before-change-message and after-change-message arguments; it
ought to be extended to have a mid-change-message one too but I didn't
think of that until just now.
Subtracting one dungeon depth value from another had the subtraction
backwards and that yielded a negative value where a positive one is
expected. If NH_RELEASE_STATUS were to be set to NH_STATUS_RELEASED
then this was at risk of crashing (if the bad subtraction yields -2,
rn2(diff+2) would divide by 0) since rn2()'s argument isn't validated
for released version.
fixes37.0 was confused, listing a couple of things that aren't bugs
in 3.6 as general fixes. I suspect that the DLB one was fixed before
being exposed via git, so shouldn't be there at all.
Poly'd hero hiding on the ceiling was told "you can't go down here"
if using '>' at a spot that didn't have down stairs, trap door, hole,
or pit. Let '>' bring a ceiling hider out of hiding; lurker above
resumes flying, piercer falls to floor or whatever is underneath it.