Record reaching experience level 3, 6, 10, 14, 18, 22, 26, and 30,
the levels where the character gets a new rank title, and report
those as achievements at end of game. These achievements persist
even if enough levels to lose a rank are lost, and if lost ranks
are regained the original achievement is the one that gets tracked
and disclosed.
Adds two monsters originally from slash'em. I used the slash'em
tiles this time, also its code as a starting point but made various
revisions. Both the tiles could benefit from some touch-ups.
displacer beast: blue 'f'. Attempting a melee hit (ie, trying to
move to its spot) has a 50:50 chance for it to swap places with you.
Fairly tough monster to begin with, then half your ordinary attacks
effectively miss and if you try to face a mob by retreating to a
corridor or backing into a corner you can end up being drawn back
into the open. I added bargethrough capability, and also it won't
be fooled about hero's location by Displacement. [It only swaps
places during combat when contact is initiated by the hero, not
when attacked by another monster or when attacking.]
genetic engineer: green 'Q'. Its attack causes the target to be
polymorphed unless that target resists. Hero will almost always
have magic resistance by the time this monster is encountered, but
it can make conflict become risky by hitting and polymorphing other
monsters. Slash'em flagged it hell-only but I took that flag off;
I also took away its ability to teleport. Slash'em polymorphs the
hero if a genetic engineer corpse is eaten; that's included and I
introduced that for monsters too.
I added both of these to the list of candidates for monster spell
'summon nasties' and for post-Wizard harassment.
I also gave all the 'f's infravision. Probably only matters if the
hero polymorphs into a feline.
Displacer beast is originally from AD&D which depicts it as a six-
legged cougar with a pair of tentacles; it has Displacement rather
be able to affect an attacker's location. I think genetic engineer
is original to slash'em where it expands Q class but seems mainly to
be the base monster for Dr.Frankenstein (a unique monster with a
one-level side-branch lair in slash'em's incarnation of Gehennom).
From the newsgroup: if cloned Wizard arrives out of view of the
hero (and vice versa), it will sit and wait until hero moves into
his view or until suffering some damage (usually via pet). So if a
mob causes the clone to arrive on the far side of a wall, he might
not come into play until the hero goes to another level and some
future harassment action pulls him off the migrating monsters list.
Treat clones like the resurrected Wizard: don't start out waiting.
Part of github issue #338 that isn't about shops: objects at the
spot where a dug pit fills with lava (or water) weren't being
effected by that.
While fixing it, I noticed that hero's steed wasn't affected either.
Also, when conjoined pits are filled in, monsters other than the
steed are at risk but weren't being handled. Presumably they fell
in on their next move.
If hold_another_object() decides that the object must be droped, drop
it into u.ustuck's minvent when swallowed instead of magically through
the engulfer direct to the floor.
When a failed #untrap attempt while mounted caused hero to be moved
onto the trap, it neglected to set the steed's coordinates to match.
If 'sanity_check' was On, that would trigger warnings about steed's
anomalous position. Eventually a normal move would put steed's
coordinates back in sync with the hero's.
The pull request code set u.usteed->{mx,my} directly. I've used
u_on_newpos() instead. I also replaced some direct manipulations of
u.{ux,uy} with u_on_newpos() so that if clipping is in effect it will
be updated.
Fixes#340
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....
while 'mention_decor' is enabled. When stepping onto different
terrain and one or more objects remained on the new spot after
autopickup, describe_decor() was issuing its new-terrain message
right before look_here()'s similar under-the-objects message. If
autopickup grabbed everything or there weren't any objects to begin
with, look_here() doesn't issue any dfeature (terrain) message.
describe_decor() isn't smart enought to know whether that is going
to happen. Give look_here() a new flag argument so that its caller
can ask for the dfeature message to be skipped for the case where a
similar message has already been given.
One monster hitting another with an artifact within the hero's view
gave "<Mon1> swings his <Artifact> at <Mon2>." followed either by
"<Mon1> misses <Mon2>." _or_ the two messages "<Mon1> hits <Mon2>."
and "The <Artifact> hits <Mon2>." Defer the <Mon1> hits <Mon2> one
when Mon1 is using an artifact and only deliver it if there is no
artifact hit message.
Tested but not exhaustively so....
Fixes#332
Introducing two new xlogfile fields "achieveX" and "conductX" which encode
achievements and conducts as a series of comma-separated strings which are
more easily parseable and also somewhat interpretable independent from knowing
the source code.
Example for a player that died shortly after picking up the luckstone from the
gnomisch mines:
achieveX=entered_the_gnomish_mines,entered_mine_town,entered_a_shop,entered_a_temple,obtained_the_luckstone_from_the_mines
conductX=polyless,polyselfless,wishless,artiwishless,genocideless
Change obj->oextra->omid from a usually-Null pointer field in
oextra to a simple 'unsigned' that doesn't need any allocation
beyond obj->oextra itself. Value 0 means that it is not in use;
it is used to hold a monst.m_id and those are always non-zero.
Delete unused obj->oextra->olong. 'olong' used to be the last
field in struct obj, put there to force alignment of anything
which followed it back when obj structures were over-allocated to
append extra information. It had a comment about being used for
temporary gold but whatever that was, temporary gold was gone long
before obj->oextra got introduced.
Bump EDITLEVEL since this invalidates existing 3.7 save files.
Remove a bunch of tabs from obj.h and save.c.
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
Applying a bullwhip down while levitating or riding gives a chance
to pick up items from the unreachable floor. Doing so over water
yields "you wrap your bullwhip around <item> on the water" when
that item is actually on the bottom. Same for lava. Don't fetch
items from beneath the surface. Also, for the lava case subject
the whip to fire damage.
This has actually broken the seal on a can of worms. Every item
at a water location sinks to the bottom even if it should float.
I'm not opening that can....
Fixes#319
Fix "objects[0] class #1 not in order!" panic. The new check to
make sure that the elements of objects[] were in ascending order
by object class uses a plain 'char' index so -1 to indicate 'no
previous value' didn't work on a system using unsigned chars.
Verfied by temporarily adding '-funsigned-char' to CFLAGS before
and after the revision. Before: panic, after: no panic.
Fixes#337
This matches the nurses' hitting behavior with their chatting messages.
Chatting to them suggested that the heal attack would happen but the check in
mhitu.c was just for wielding anything.
This opens up the possibility of a YAFM in MS_NURSE when wielding something
that allos the heal attack to proceed. But I couldn't come up with a good
one.
Have 'makedefs -m' output default mons[].difficulty values in the
stub 'monstr.c' that still gets generated for that option. It
would be better to allow specifying which monsters are of interest
but I didn't want to get bogged down by interface issues.
I needed it for mons[PM_ELF].difficulty after changing that monster's
level, so it still has a purpose. Code is from 3.4.3, reformatted
manually.
Monster detection skipped dead monsters during fmon traversal but
found semi-dead guard parked at <0,0> waiting to remove temporary
vault corridor. If that happened to be the only monster found then
the feedback was incorrect (a blank map showing no found monsters
instead of a strange feeling). Object detection found semi-dead
guard's inventory and might report incorrectly too although the
chance of that being the only objects found on the level is a lot
less than it being the only monster.
Wishing allowed "royal jelly" to match "lump of royal jelly" as a
special case, but not "wolfsbane" to match "sprig of wolfsbane" or
"tricks" to match "bag of tricks". Handle that sort of match in a
more general way.
While in there, add a minor glob bit: instead of giving a random
corpse (because monster is flagged as no-corpse) if someone wishes
for "gray ooze corpse" give "glob of gray ooze".
Fixes#325
After 05403182eb (I think, possibly the
change to objnam.c which followed that one) from a couple of days ago,
wishing for a monster name dereferenced a Null pointer and crashed.
"were{rat,jackal,wolf}" each occur twice in mons[], once for the
beast form and second time among '@' for the human form. Wishing
for werecreature corpse or tin always matches the first entry so
yields the beast form, but all their beast forms are flagged as
no-corpse so the wish would fallback to a corpse with random monster
type. Wishing for werecreature figurine worked but always produced
one that created its beast form if/when activated.
This fix allows specifying "human werecreature" to match the second
entry. It's optional for corpse and tin; the wish code will now
switch to that implicitly if it gets a no-corpse were-form for
those. It has to be specified explicitly to get a figurine that
will activate as the human form. It works for ^G too.
Fixes#326
name_to_mon() has a bunch of alternate monster names, such as
"gray-elf" to match "grey-elf" and "ki rin" to match "ki-rin". Those
worked as intended when they occurred at the end of a wish, but only
worked in the middle if their length was the same or one character
less than the canonical name in mons[].mname.
djinni figurine -> h - a figurine of a djinni
genie figurine -> i - a figurine of a djinni
figurine of mumak -> j - a figurine of a mumak
mumak figurine -> k - a figurine of a mumak
figurine of mumakil -> l - a figurine of a mumak
mumakil figurine -> nothing fitting that description exists
(The one-less case worked because its following space ended up being
implicitly removed when skipping ahead by the length of mons[].mname;
subsequent explicit removal didn't find a space so was a no-op.)
Water locations on Medusa's level didn't show steam clouds. It
wasn't because the location was a moat rather than a pool, it was
because the moat location was unlit (and in line of sight) and
tested pool locations were lit. Poison gas clouds explicitly
override the lit/unlit issue but other region types weren't.
Fixes#331
Allows creating shaped or themed rooms for the Dungeons of Doom
via lua script.
Invalidates bones and saves.
Makefiles updated for unix/linux by adding themerms.lua, but other
OSes need to have that added.
This adds a superset of the code from github pull request #328
to create a short-lived cloud of steam when fire hits a pool or
fountain. The original code required C99; this doesn't. It also
allowed vapor clouds on the Plane of Water where they don't work
sanely becaure regions don't understand air bubble movement and/or
vice versa. This inhibits the clouds there [the same ought to be
done for scrolls of stinking cloud]. It also left as-is the code
that reported when fountains got used up even though conceptually
the steam should interfere with being able to see that. This adds
a glyph-check hack to augment cansee() so that fountains that boil
away entirely are hidden at the time.
Regions that block line of slight should be calling block_point()
when created and unblock_point() when removed but a naive attempt
to introduce that didn't work as expected so I'm giving up on.
Fixes#328
Screen erasure leaves the map set to spaces. If S_unexplored is
something other than <space>, tty wasn't drawing with S_unexplored
after a menu or long message line got erased following temporary
overwrite of part of the map.
This seems to work but is not the correct way to do things.
clear_screen(), cl_eos(), and cl_end() should all be taught to
flag the map as needing to be refreshed after they erase part of it.
tty_clear_nhwindow(WIN_BASE) is also lacking since it erases the
message line, full map, and status lines but leaves their internal
windows with stale data about what is shown instead of marking them
blank.
When a food shop gets converted into a health food shop (minetown
when playing as a monk), the shop type and underlying room type
weren't changed to match.
Unicorn horns are just too good. Nerf it in similar way several
other variants have done: don't let it restore attribute loss.
This makes potion of restore ability more valuable, and the
int loss from the (nerfed) mind flayers matter more.
When polymorphed into a nymph and melee hit steals items from the
target, the same-gender charm message vs opposite-gender seduce
message is being chosen by hero's base gender rather than nymphs
always being female. The seduce message used dynamic pronouns for
the target monster but the charm message used hardcoded She and her
for female nymph attacking female target. I'm not sure why hero's
base gender is used so left that alone; this changes charm message
to use dynamic pronouns that correctly match the target monster.
Losing all of your items in one go is really frustrating.
If you blow up your bag of holding, make the contents scatter around
instead of outright deleting them. This will destroy fragile objects.
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.
Testing a forthcoming extension of monsters using wands of undead
turning revealed a couple of pre-existing bugs. Previously only
noticeable if hero zaps self or breaks a wand of undead turning so
unlikely to have happened much.
"Your <mon> corpse comes alive" was given even if it was revived
as an undead. Also, it was "your <mon> corpse" instead of "one of
your <mon> corpses" even when one from a stack was involved. If
done by hero to self that message follows "one of your <mon>
corpses glows iridescently" so the comes alive message was ok but
verbose. Change that to "it comes alive" or "it reanimates" when
following the glow message.
when hero is wielding a cockatrice corpse. Wands of undead turning
aren't generated as starting equipment but they will now be picked
up if come across while the hero is carrying any corpse, and used
in preference to any other item when carried and non-empty and hero
is wielding a petrifier's corpse.
Fixes#320
Avoid giving "you are back on the bottom" nearly every step when
moving around underwater.
Avoid "you are back on floor" followed by "you trip over <object>"
when fumbling in case that fumbling was due to being on ice when
taking the step to floor. Done for all fumbling rather than just
one-turn fumbling instigated by ice.
When moving from ice or water to ground, show "you are back on floor"
before listing objects at that spot instead of after.
I think there was at least one more thing but have lost track. At
any rate, 'mention_rate' potentially has a new set of bugs.
"You materialize at another location," was delivered while the
previous location still controlled line of sight. Very noticeable
if you started from underwater and landed on the surface in an area
which hadn't been mapped yet.
The fix to try to avoid messages about out-of-view objects taking
erosion damage made water_damage_chain() vulnerable to dereferencing
a null pointer, leading to a crash if you create a pool via wizard
mode wishing.
Eating a tin of one of the Riders and being life-saved or declining
to die would crash when trying to revive a non-existent corpse. An
old comment stated that since such tins were impossible it could
assume that it was dealing with a corpse, but wishing for tins of
the Riders is possible in wizard mode.
They can't be passed along to normal mode via bones because they're
changed to empty tins as bones are saved. So there doesn't seem to
be much point in allowing wizard mode wishing to create them, but
I've left that as is.
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().
Adds a new level init type which directly creates a maze,
optionally setting corridor width and wall thickness,
and removing dead ends.
des.level_init({ style = "maze", corrwid = 3, wallthick = 1, deadends = false });