Redo the recent artifact creation stuff by replacing several nearly
identical routines with one more general one. Also adds a tracking
bit for one or two more creation methods. That changed artiexist[]
from an array of structs holding 8 or less bits to one holding 9, so
bump EDITLEVEL in case the total size changed.
This should have been broken up into multiple pieces but they're
all lumped together. I did ultimately throw away a fourth change.
Implement artiexist[].bones and artiexist[].rndm artifact creation
tracking bits that were added recently. Doesn't need to increment
EDITLEVEL this time.
Add a new wizard mode feature: if you use `a to show discovered
artifacts, it will prompt about whether to show the tracking bits
for all artifacts instead. If not using menustyle traditional,
you need at least one artifact to have been discovered in order to
have 'a' choice available when selecting what class of discovered
objects to show for the '`' command.
artifact_gift(), aritfact_wish(), and so forth return a value that
none of the existing callers use, so cast their calls to (void).
Since the struct used for elements of artiexist[] has a lot of unused
bits, add some new ones to extend it to indicate how artifacts have
been created. It had
| .exists (has been created) and
| .found (hero is aware that it has been created)
introduce
| .gift (divine gift),
| .wish (player wish),
| .named (naming elven weapon Sting or Orcrist)
| .viadip (made Excalibur by dipping long sword into fountain)
| .rndm (randomly created), and
| .bones (from bones file--how it got created in earlier game isn't
tracked). The first four are implemented, fifth and sixth aren't.
Some of the feedback when receiving an artifact or spellbook has been
revised.
When artiexist[] was changed from an array of booleans to an array of
structs a couple of days ago, EDITLEVEL should have been incremented
but I overlooked that at the time. This commit does so now.
Log artifacts found on the floor, or carried by monsters if hero sees
those monsters do something with them. Shown to player via #chronicle
and included in dumplog.
For most cases, finding is based on having the artifact object be
formatted for display. So walking across one won't notice it if pile
size inhibits showing items at its location, even if the artifact is
on top. Taking stuff out of a container won't notice an artifact if a
subset of the contents chosen by class or BUCX filter doesn't include
it unless player has used ':' to look inside. Seeing an artifact be
picked up by a monster (even if the monster itself is unseen) or being
dropped (possibly upon death) will find an artifact even if beyond the
normal range of having it be treated as seen up close. Random treasure
drop items are excluded since they are placed directly on the floor
rather than going into a dying monster's inventory and then dropped
with its other stuff.
Requested by k21971 (hardfought admin): classify the gameover event
as something other than achievement so that live-logging can exclude
it in order to use the xlogfile end-of-game entry instead.
It had been classified as an achievement because that was the only
category being treated as 'major' so written to final dumplog. Give
is a new classification 'dump' which is distinct from achievement
and intended to explicitly request that an event go into dumplog.
The gameover event is the only one in that category, at least for now.
Add a bunch of other classifications besides achievement and dump to
be treated as 'major' for dumplog. The new list is
wish, achieve, umonst (death of unique monster), divinegift,
lifesave (via amulet, not explore-/wizard-mode decline to die),
artifact, genocide, dump
and may still need further tuning. Currently excluded are
conduct (first violation of any conduct), killedpet, alignment
(changed, either via helmet or conversion), minorac (minor
achievement such as level gain or entering the mines), and spoiler
(currently only applies to finding Mines' End luckstone which is
also 'achieve' so will be in dumplog).
This doesn't remove the reference to unimplemented LLC_TURNS that is
mentioned in the template sysconf.
Closes#688
When hallucinating, use nonsensical names for the rays
(wands, spells, and breath weapons), and random ray glyphs.
Original code from xNetHack by copperwater <aosdict@gmail.com>,
inspired by a YANI by Kahran042.
Log game events, such as entering a new dungeon level, breaking
a conduct, or killing a unique monster, in a new "Major events"
chronicle. The entries record the turn when the event happened.
The log can be viewed with #chronicle -command, and the entries
also show up in the end-of-game dump, if that is available.
This feature is on by default, but can be disabled by
defining NO_CHRONICLE compile-time option.
This also contains "live logging", writing the events as they
happen into a single livelog-file. This is mostly useful for
public servers. The livelog is off by default, and must be
compiled in with LIVELOG, and then turned on in sysconf.
Mostly this a version of livelogging from the Hardfought server,
with some changes.
Implement the suggestion that falling rock traps and rolling boulder
traps be harmless to xorns. I've extended that to all missiles made
of stone (rocks, gems, boulders, a handful of other things that will
only matter if poly'd hero throws in '<' direction or is hit by stuff
scattered by an explosion).
I excluded ghosts because they would become even harder to kill and
the missile handling would need extra checks to test for blessed objs.
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.
Always give a message when creating a detected monster
during gameplay (as opposed to during level creation).
To prevent the message, use the MM_NOMSG flag for makemon.
Most places already handled their own messaging, but there
were some, such as bag of tricks, create monster magic
and random monsters created during gameplay that didn't.
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.
Special abilities conferred by wearing dragon armor was implemented in
a somewhat half-assed fashion; extend it to 3/4-assed. Abilities came
from wearing dragon armor but not from being poly'd into a dragon or
for monsters that were wearing dragon armor or actually were dragons.
This covers much of that.
There are umpteen calls of 'resists_foo(mon)' and some are now
'resists_foo(mon) || defended(mon, AD_FOO)' but the second part ought
to be incorporated into update_mon_intrinics() so that the extra
'|| defended()' doesn't have to be spread all over the place and the
ones being put in now could/should be removed.
While testing, I noticed that a monster wielding Fire Brand did not
resist being hit by a wand of fire. This fixes that and should also
fix various comparable situations for other artifacts. But so far it
has only been done for zapping (and any other actions which use the
zapping code). Folding defended() checks into update_mon_intrinsics()
matters more than that probably sounds.
Follow up on some old groundwork. For tty, if the core has designated
a message as 'urgent', override any message suppression taking place
because of ESC typed at the --More-- prompt. Right now, "You die"
messages, feedback about having something stolen, feedback for
"amorous demon" interaction (mainly in case of armor removal), and
exploding a bag of holding are treated as urgent.
The "You die" case is already handled by a hack in top-line handling;
I left that in place so the conversion of 3 or 4 pline("You die.*")
to custompline(URGENT_MESSAGE, "You die.*") was redundant. There
are probably various non-You_die messages which precede done() which
should be marked urgent too.
Other interfaces might want to do something similar. And we ought to
implement MSGTYPE=force or MSGTYPE=urgent to allow players to indicate
other messages that they want have to override suppression. But I'm
not intending to work on either of those. I mainly wanted to force
the magic bag explosion message to be shown since a sequence of "You
put <foo> into <bag>." messages is a likely candidate for --More--ESC.
Some messages about owing a shopkeeper money would use 'it' when blind,
with weird results such as "You owe It 267 zorkmids for goods lost." It
seems maybe like these were missed in 6591f8b since they were outside of
shk.c/shknam.c. Bring those messages into alignment with most other
shopkeeper-related messages, which use the shopkeeper's name even if the
hero is blind or can't see them at the moment.
Some of the 'it gets angry' ones don't seem so bad, but similar 'gets
angry' messages in shk.c use Shknam so I changed those as well for
consistency's sake.
Reported by entrez, wielding something fragile (potion of acid
perhaps), and using F to smash it against iron bars called breaktest()
directly, then a second time indirectly through hero_breaks() via
hit_bars(). There is a random chance to resist breaking (99% for
artifacts, 1% for other items) so breaktest() might say that something
will break on the first call and that it will not break on the second
call, or vice versa. That could remove uwep from inventory then leave
it in limbo without destroying it, or destroy uwep without removing it
from inventory first triggering impossible "obfree: deleting worn obj".
Noticed when testing the "wall_angle: unknown" fix, if there is a
boulder rather than a door in the breach in a vault's walls at the
spot where the guard arrives, the guard would walk onto it, tell the
hero to drop any gold and follow, then move back. The boulder would
remain in the hero's way and couldn't be pushed because the guard was
in the boulder's way. Have the guard smash any such boulder(s) into
rocks when arriving (with no explanation for how that is accomplished,
just a message about seeing or hearing boulder(s) shatter). Later
when repairing the walls, delete any rocks or boulders at all vault
wall locations (even when no gap-to-wall repair is needed).
Reported directly to devteam by entrez via email:
>
> I noticed some potential issues with (melting) ice:
>
> * Digging down into ice, or setting a land mine on the ice and
> triggering it, doesn't remove the melt_ice timeout, so it can result
> in a sequence like dig down -> pit fills with water -> freeze water
> -> freezing water tries to set melt_ice timeout -> duplicate timeout
> impossible. Or if you don't freeze the water again, melt_ice will
> run on a non-ice surface, which might at least produce strange
> messages.
>
> * Setting a land mine on ice: melting ice doesn't do anything with
> the trap, so there is still a land mine which you can trigger by
> flying over the water (the land mine's trigger is also still
> described as being 'in a pile of soil', despite being underwater at
> this point). Similar thing happens with bear traps.
>
> * Not really related to _melting_ ice, but an exploding land mine
> doesn't reset the typ from ICE to FLOOR (like normal digging does),
> so it will result in a square with a pit that is also an ice square,
> where the ice can melt under the pit and produce a combination
> pit/moat. If you then freeze the moat, the pit reappears on top of
> the ice.
The gas will expand from its chosen center point via breadth-first
search instead of hardcoding a diagonal shape. The search is performed
with a randomized list of directions, and has 50% chance of not spreading
to a space it otherwise would have spread to. This has the effect of fuzzing
the cloud edges in open areas, helping the clouds on, for instance,
the Plane of Fire not be big rhombuses.
Also some other code refactoring related to stinking clouds in read.c
This comes from xNetHack by copperwater <aosdict@gmail.com>
even when protection from shape changers is in effect. I'm not sure
why mimicking other things doesn't trigger the same sanity check
warning. This fix works for the strange object case and I assume
that it doesn't break the more general case.
When investigating, I noticed that save and restore (even leaving
the level and then returning) causes cancelled shape changers to be
uncancelled. Treat being cancelled similarly to having to having
protection from shape changers in effect: shape changer is forced
to revert to its innate form and not allowed to change shape.
Sanity check caught an eel hiding on floor; this was caused by
an exploding flaming sphere boiling off the pool the eel was
hiding in. The freezing water case was already handled, so
add the same, rather lackluster handling, to the fire case.
Add some vomiting effects:
Trigger divine wrath if hero vomits at an altar's location. (What
about adding throne and maybe sink special effects too?)
If poly'd into a yellow dragon, breathe (acid) on self. (I'm not
sure why.)
If on ice and poly'd into an acidic form, melt the ice. Also,
change melt_ice() to give its message when melting happens at the
hero's location even if hero can't see.
Fixes#519Fixes#510
Revive some code from 5 or so years ago that's been sitting in a
defunct local git branch. There are a couple of references to
figurines having gender; the old, unfinished code did already have
support for that, the current code doesn't. It probably won't take
much effort to add it in but I want to get this first part out of
the way.
Replace some of the
pmname(mon->data, Mgender[mon]) calls with simpler
mon_pmname(mon) and some
pmname(&mons[statue->corpsenm],
(statue->spe & CORPSTAT_GENDER) == ... ? ... : ...) with simpler
obj_pmname(obj). There are other instances of them which haven't
been changed but could be.
Dead monsters that had traits saved with the corpse would revive as
the same gender, but ordinary corpses revived with random gender so
could be different from before they got killed.
Since corpses of monsters lacked gender, those for monsters with
gender-specific names were described by the neuter name.
This is a fairly big change for a fairly minor problem and needs a
lot more testing.
Fixes#531
Despite active explosion attacks being called explosions in-game,
they only affected a single target, and were handled differently
from actual explosions. Make them do an actual explosion instead.
This should make spheres more interesting and inspire different
tactics handling them.
Because spheres deal more damage on average and can destroy items
in their explosions, their difficulty has been increased slightly.
Polyselfed hero exploding won't cause elemental damage to their
own gear.
Originally from xNetHack by copperwater <aosdict@gmail.com>.
If monsters see you resist something, generally elemental or magical
attack, or if they see you reflect an attack, they learn that and
will adjust their attack accordingly.
Originally from SporkHack, but this version comes via EvilHack with
some minor changes.
---
insight.c: In function ‘status_enlightenment’:
insight.c:937:28: warning: ‘ (’ directive writing 2 bytes into a region of size between 0 and 255 [-Wformat-overflow=]
937 | Sprintf(buf, "%s %s (%s)", ustick ? "holding" : "held by",
| ^~
In file included from ../include/config.h:631,
from ../include/hack.h:10,
from insight.c:15:
../include/global.h:274:24: note: ‘sprintf’ output 5 or more bytes (assuming 260) into a destination of size 256
274 | #define Sprintf (void) sprintf
insight.c:937:9: note: in expansion of macro ‘Sprintf’
937 | Sprintf(buf, "%s %s (%s)", ustick ? "holding" : "held by",
| ^~~~~~~
insight.c:918:29: warning: ‘%s’ directive writing up to 255 bytes into a region of size 252 [-Wformat-overflow=]
918 | Sprintf(buf, "%s by %s",
| ^~
919 | is_animal(u.ustuck->data) ? "swallowed" : "engulfed",
920 | heldmon);
| ~~~~~~~
In file included from ../include/config.h:631,
from ../include/hack.h:10,
from insight.c:15:
../include/global.h:274:24: note: ‘sprintf’ output 5 or more bytes (assuming 260) into a destination of size 256
274 | #define Sprintf (void) sprintf
insight.c:918:9: note: in expansion of macro ‘Sprintf’
918 | Sprintf(buf, "%s by %s",
| ^~~~~~~
---
zap.c:475:1: warning: old-style function definition [-Wold-style-definition]
475 | release_hold()
| ^~~~~~~~~~~~
zapped at corpse flagged as "no revive". A fairly recent change
made undead turning override no-revive if it hit someone carrying
a corpse flagged that way (corpse of a troll killed by Trollsbane
or stuffed in an ice box or explicitly cancelled) but neglected to
do so for corpses zapped while on the floor. This fixes that, for
undead turning zapped by monsters as well as by the hero.
Fixes#505
Zapping wand of opening or spell of knock at engulfer while swallowed
would make the engulfer expel the hero; this change makes zapping
other holders release their hold. Zapping self now achieves the same
effect, as does breaking a non-empty wand of opening. When poly'd
hero is holding a monster rather than being held, that monster will
be released.
Engulfers can't re-engulf for 1 or 2 turns after releasing the hero
in order to prevent hero from being immediately re-engulfed. Impose
the same limitation on other holders.
Change Trollsbane versus troll corpse revival: instead of revival
failing if Trollsbane is wielded at time of revival attempt, mark
the corpse no-revive if killed by Trollsbane (whether by the hero
or a monster).
If a no-revive corpse is within view when time to revive occurs,
give "the troll corpse twitches feebly" even when the hero isn't
responsible. That used to only apply if the hero zapped the
corpse with undead turning, which would have become inoperative
because now being zapped by undead turning clears the no-revive
flag and revives as normal. In other words, undead turning magic
overrides killed-by-Trollsbane or non-ice troll having been in an
ice box.
Player's pet killed a troll with Trollsbane and the corpse later
revived. He assumed that killing a troll with Trollsbane is what
prevents troll corpse revival but that is inhibited by the hero
be wielding Trollsbane at the time revival is attempted.
Having killed-by-Trollsbane be the reason for blocking revival
would be much better but looks like a lot of work for something
which was supposed to be a one-line enhancement to an under-used
artifact. This extends revival inhibition to having anyone on
the level be wielding Trollsbane rather than just the hero.
Not a proper fix but I think it's better than nothing.
Closes#475
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’