Commit Graph

313 Commits

Author SHA1 Message Date
PatR
273662c58c monster overflow on Plane of Air
Make Air behave the same as Earth, Fire, and Water if monsters are
forced off the level for some reason.
2019-06-17 10:09:16 -07:00
PatR
f0633e6541 EDIT_GETLIN vs monpolycontrol
For wizard mode 'monpolycontrol', the getlin() answer buffer for the
"Change <monster> @ <x,y> into what kind of monster?" prompt is also
used to format the coordinate portion of that prompt, so when
EDIT_GETLIN is enabled getlin() was inadvertently given "<x,y>" to use
as default response.  Clear it after the prompt is formatted instead
of via an initializer.  Also, shorten the prompt on the first try:
"Change <monster> @ <x,y> into what?", expanding to the old prompt if
retry is needed.

This also allows specifying 'chameleon' when <monster> is a chameleon,
'doppelganger' when it's a doppelganger, and 'sandestin' when it's one
of those (but not 'doppelganger' when it's a chameleon or sandestin,
and so forth), instead of blanket refusal to accept any non-vampire
shapechanger as the choice.
2019-06-15 04:13:34 -07:00
PatR
b982e6c526 location viability on Plane of Water
While testing, I noticed that I could completely fill the Water level
with air elementals.

Hero can't fly or levitate or water walk into/onto water locations
on Water level without drowning/crawling out the water, and monsters
shouldn't have been able to but could, then they were hit by drowning
since minliquid used different criteria than movement.  But goodpos(),
used for teleport destination and new monster creation among other
things, consided water locations acceptable on that level for
non-aquadic creatures with Fly/Lev/Wwalk ability.

It explains why so many dragons and other 'nasty' monsters have been
ending up on the vanquished monsters list when hero uses level
teleport to go directly there from level 1.  They've either been
getting created in water and then they drown when it's their turn to
move or moving into it to approach the hero and drowning (not sure
whether that case is immediate or on next move).  There's no message
since hero doesn't see it, and air elementals didn't drown since thy
don't breathe.
2019-06-05 04:16:34 -07:00
nhmall
bf5878076f more precautions for monster obliteration during overcrowding 2019-06-03 17:11:54 -04:00
nhmall
7d38435a9b don't clear mtmp->mx, mtmp->my even when obliterating 2019-06-02 10:34:38 -04:00
nhmall
5c30cc5890 elemental_clog() should not destroy the very monster trying to be placed 2019-06-02 08:15:41 -04:00
nhmall
852995bbeb remove a couple of debugging lines in mon.c 2019-06-01 17:36:54 -04:00
nhmall
5ee78c5204 improve full level handling in the endgame
Even though a goodpos failure in mnearto() would return 0 to
the caller and trigger proper overcrowding handling for mtmp,
the 'othermon' would be left with its mx,my set to 0,0 under
that circumstance and then trigger a mon_sanity_check()
failure and accompanying impossible() message a short while
afterwards.

This also includes the addition of some flags that proved useful
for troubleshooting the mystery sanity_check failure and helping
to understand some of the code paths the struct monst data had
been through. They are only used for inspection when issues are
reported or when debugging, they don't presently control the
code flow.  Their setting and use is done in an overloaded way
that should not intrude on the existing use of mspare1 for
MIGR_LEFTOVERS. mon->mstate is just a pseudonym for mon->mspare1
and does not alter save file content.
2019-06-01 16:51:10 -04:00
PatR
791b87833b mnearto/mnexto/enexto
This doesn't solve the <0,0> problem but it does prevent mnexto()
from using uninitialized coordinates if enexto() fails.  It also adds
several debugging messages.

enexto() was ignoring map row #0 (unlike column #0, row #0 contains
valid map locations).  Fixing that doesn't matter for Plane of Water
though since that row is stone there--that's probably a bug.  It was
also repeatedly re-testing the top+1 and bottom rows and left and
right columns after they had already failed to be acceptable.  It
still does some of that, but less.
2019-05-30 07:50:38 -07:00
Pasi Kallinen
bed2c2307e Fix monster trapped state being wrong
When cloning a monster, clear the clone trapped and hiding states.
When splitting a monster (eg. a black pudding), the clone could
be placed on a trap, so do mintrap.
When removing a monster from the map, clear the trapped state.
2019-05-05 22:58:27 +03:00
PatR
f441696908 fix #H8619 - hallucination vs vampire transform
|The seemingly dead vampire bat rises as a vampire.
was overriding hallucination when describing both old and new forms.
In 3.6.0 it only overrode the dying shape (explicitly so, presumeably
because the feature was brand new) and honored hallucination for the
revived shape.  The 3.6.1 fix to prevent non-hallucinating:  'The
seemingly dead Foo rises as Foo.' for a named vampire unintentionally
overrode hallucination for the revived shape.

Change it to honor hallucination for both before and after monsters
|The seemingly dead grid bug rises as a microscopic space fleet.
2019-04-24 14:02:09 -07:00
nhmall
dcf4da2150 preserve dknown field between fakeobj instances
Preserve temporary fake object's previous dknown value by storing it
as a flag value within the m_ap_type field of the posing monster, and
recalling it when it is needed.

This is intended to help eliminate observable differences in price display
between real objects and mimics posing as objects.

98% of this is just switching the code to utilize macro M_AP_TYPE(mon)
everywhere to ensure that the flag bits are stripped off when needed.
2019-04-22 14:17:18 -04:00
PatR
bbe4991a7f monster movement comments
A bit of reformatting and a couple of new comments.  No change in
behavior.
2019-04-17 18:57:14 -07:00
PatR
86e5022293 fix #H8534 - thrown pick-axe vs "scum!"
Change in meaning of mnearto()'s return value wasn't progagated to
shkcatch().  Make it an int instead of boolean so that it can
communicate both 'moved successfully' and 'moved but had to move
another monster out of the way to do so'.
2019-04-11 15:38:51 -07:00
PatR
f52e9865f2 fix #H8481 - placing monster at <0,0>
mon_arrive() -> m_into_limbo() -> migrate_to_level() -> wormgone()
followed by place_monster() "for relmon".  relmon() was changed (last
November, cc5bb44a9a) to not require
the monster be on the map, so just get rid of the place_monster() that
was trying to put the "gone" long worm at <0,0>.

Also, another m_into_limbo() bit:  make mdrop_special_objs() check the
location and send any dropped items to random locations if the monster
dropping things isn't on the map, instead of placing them at <0,0>.
2019-04-06 12:57:29 -07:00
PatR
a6ff7210be fix #H8215 - monster intrinsics from worn gear
Fixes #177

The monst struct has 'mintrinsics' field which attempts to handle
both mon->data->mresists and extrinsics supplied by worn armor, but
polymorph/shape-change was clobbering the extrinsics side of things.
Potentially fixing that by changing newcham() to use set_mon_data(...,1)
instead of (...,0) solved that but exposed two other bugs.  Intrinsics
from the old form carried over to the new form along with extrinsics
from worn armor, and update_mon_intrinsics() for armor being destroyed
or dropped only worked as intended if the armor->owornmask was cleared
beforehand--some places were clearing it after, so extrinsics from worn
gear could persist even after that gear was gone.

So, fixing the set_mon_data() call in newcham() was a no go.  This
fixes update_mon_intrinsics() and adopts the suggested code from
github pull request #177 to have mon->mintrinsics only handle worn
gear instead of trying to overload innate intrinsics with that.  This
is a superset of that; the flag argument to set_mon_data() is gone
and mon->mintrinsics has been renamed mon->mextrinsics.  (The routine
update_mon_intrinsics() ought to be renamed too, but I didn't do that.)
2019-02-18 13:17:14 -08:00
PatR
48e7643739 fix monstone() ... dealloc_obj() panic
Fuzzer feebdack.  When turning a monster into a statue, monstone()
builds a linked list of mon->minvent items to put into that statue.
It doesn't use obj_extract_self() to take them off again, leaving
obj->nobj non-Null.  Not noticed for the normal case where each item
gets linked into the container's contents, but triggers panic if an
item merges with something already put inside so gets removed.

Suddenly, the dungeon collapses.
dealloc_obj with nobj
[2] 0x01000c4193 panic + 995
[3] 0x0100155427 dealloc_obj + 71
[4] 0x010021d4de obfree + 686
[5] 0x01000f2f92 merged + 834
[6] 0x010015356e add_to_container + 126
[7] 0x01001628ac monstone + 636

I don't know why the petrified monster's mergeable inventory wasn't
already merged while in inventory.
2019-01-31 04:22:04 -08:00
PatR
d0cc645961 vampshifter resurrection while being held
If poly'd hero is holding a bat/cloud/wolf which dies and revives as a
vampire, release the hold.
2019-01-22 17:54:58 -08:00
PatR
d3682dd5ca monsters on melting ice
Reported seven years ago, when ice melts underneath a monster, it
hovers there until its next move, then falls in and drowns.  Dunk it
immediately, and give hero credit/blame if it happens during the
hero's turn (so presumably the melting was caused by the hero).

Also, let monster with teleport capability who gets dunked teleport
away from the water before getting wet, the way hero does.
2018-12-21 14:36:55 -08:00
PatR
c429cf5584 fix github issue #169 - monst vs vibrating square
Fixes #169

Monsters should not be afraid of stepping on the vibrating square
since it's only a trap for display purposes.  [Perhaps they should
deliberately avoid it if the hero hasn't seen it yet, but I didn't
implement that.]

"You see a strange vibration beneath <mon's> <parts>." was strange
when <parts> was a wolf's "rear paws" or horse's "rear hooves"--was
the vibration magically skipping the front ones?  And it sounded
naughty when it was a snake's "rear regions".  If the creature has no
limbs or is floating or flying, just say "beneath <mon>"; otherwise,
if the part is "rear <something>", omit "rear ".

The message was weird in another way.  Caller removes the monster
from it's old location and places it on the new one, calls newsym()
for the old location to show lack of monster, but then calls mintrap()
before newsym() for monster's new location (the trap's location).  If
pline messages cause buffered map output to be flushed, the monster
will be missing during the time the messages are delivered.  I fixed
that for vibrating square [seetrap()->newsym() before pline() rather
than after] but it should probably be fixed in the caller instead.
2018-12-19 14:52:23 -08:00
PatR
fdec3704fd mon_sanity_check tweak
A change I included with the vault guard fix was triggering fuzzer
panics about dead monsters on the fmons list.  I'm not quite sure why;
I couldn't reproduce it interactively.  [Perhaps caused by hero killing
a monster and then getting another move before monsters get their turn,
but trying to do that still didn't trip the dead monster sanity check.]
Suppress that check so that the fuzzer can run amok.

Also, a waiting-to-exit vault guard could move extra times, uselessly
since ''hero hasn't left temporary corridor yet'' is why he's waiting,
if there were any monsters fast enough to get extra moves before the
hero's next turn.
2018-12-12 15:42:46 -08:00
PatR
9952049a75 fix #H7677 - guard placed twice at <0,0>
"Placing monster over another?" warning was triggered for vault guard
by an earlier change which made m_detach() stop removing monsters at
<0,*> from level.monsters[][].  So one guard would replace another at
<0,0> for however many guards were created, and memory for all but
the last one would be lost.

This involved a lot of flailing about and the patch includes various
things would could have been discarded.  One or two extended monster
sanity checks are included, plus a couple of debugpline()'s for
tracking guard movement.
2018-12-12 01:54:33 -08:00
PatR
234bf7b1b6 fix #H7618 - gas cloud affects underwater monsters
Stinking cloud placed near water or poison gas breathed across it
would affect and potentially kill underwater monsters.  Most swimmers
are on the surface and should be affected, but eels and other fish
shouldn't be.

This also changes minliquid() to not treat flying and levitating as
ways to survive water when on the Plane of Water.

I think goodpos() needs to be taught about that Plane (where many ways
of existing at a water location don't apply).  This doesn't do that.
2018-11-28 17:43:53 -08:00
PatR
bb08a46480 fix #H7596 - magic trap 'deafening roar' outcome
doesn't wake monsters.  Now it does.
2018-11-24 15:01:30 -08:00
PatR
cc5bb44a9a fix #H7591 - migrating monsters vs full levels
During level change, when a monster from mydogs (monsters accompaying
hero, usually pets) couldn't be placed because the level was full, it
was set to migrate to that level (in order to get another chance to
arrive if hero left and returned).  The code sequence
 mon_arrive()-> mnexto()-> m_into_limbo()-> migrate_to_level()-> relmon()
tried to remove the monster from the map, but it wasn't necessarily on
the map (depending upon whether it couldn't arrive at all, or arrived
at the hero's spot and couldn't be moved out of the hero's way).  The
EXTRA_SANITY_CHECKS for remove_monster() issued impossible "no monster
to remove".  relmon() now checks whether monster is already off the map.

While investigating that, I discovered that pets set to re-migrate
to the same level to try again on hero's next visit didn't work at all.
migrating_mons gets processed after mydogs so moving something from
the latter to the former after arrival failure just resulted in
immediate second failure when the more general list was handled during
the hero's current arrival.  And failure to arrive from migrating_mons
would kill the monster instead of scheduling another attempt.

The sanest fix for that turned out to be to have all monsters who
can't arrive be put back on the migrating_mons list to try again upon
hero's next visit.  Pets still fail twice but are no longer discarded
during the second time, and now do arrive when hero leaves and comes
back provided he or she has opened up some space before leaving.  If
there's still no space on the next visit, monsters who can't arrive
then are scheduled to try again on the visit after that.

Recent fix for invalid corpses becomes moot.  Monsters aren't killed
during arrival failure so there are no resulting corpses to deal with.
2018-11-24 01:45:09 -08:00
nhmall
7ad3f32e16 Revert "Renamed instance_variables to global_variables and iv to g."
This reverts commit f9a0db6c44.
2018-11-23 22:17:07 -05:00
Bart House
f9a0db6c44 Renamed instance_variables to global_variables and iv to g. 2018-11-23 15:22:53 -08:00
Pasi Kallinen
030efe84fa Map column 0 is not a valid location 2018-11-21 19:17:08 +02:00
PatR
d15dacc44c fix #H7530 - corpse from corpseless monster
Migrating monster attempting to arrive on a level which is already
full of monsters gets killed off.  It was leaving a corpse without
regard for whether it was a type of of monster which should never
leave corpses.

I'd prefer that it be put back on the migrating_mons list rather
than be killed off, but this just suppresses impossible corpses.
2018-11-20 13:13:23 -08:00
Pasi Kallinen
5acddebb3c Init long worm even if it does not have a tail
Long worms with no tail parts still apparently need to have
the zero-length tail placed.
2018-11-19 22:09:18 +02:00
Pasi Kallinen
2a439af336 More long worm checks when splitting
When a long worm is split into two, perform more checks placing
the segments on the map.
2018-11-19 21:49:52 +02:00
Pasi Kallinen
ebef31ffa5 Check monster relocation degenerate cases more strictly
Just in case we're trying to put the monster on the same location
where it already thinks it is... but actually isn't.
2018-11-19 21:16:50 +02:00
Pasi Kallinen
878ac24037 Fix freeing monsters not on map
Sometimes we free the monster data, but the monster is not on the
map - usually this happens if the map is full of monsters and a new one
is migrated on the level.

Make m_detach check the monster x coordinate, so it knows not to touch the map
if the monster isn't on it.
2018-11-19 21:16:46 +02:00
PatR
e4db2b4721 Elbereth tweaks
Don't "feel like a hypocrite" when on Elberth and attacking a monster
which isn't scared by Elbereth (exception:  peaceful creatures aren't
scared but attacking them in such situation is hypocritical anyway).
This means that players can use Elbereth to scare away some creatures
while continuing to fight others.  Elbereth won't be automatically
erased, but weapon attacks will scuff the engraving; wand zaps don't.

Reduce the -5 alignment penalty when alignment is 5 or less.  Reduced
amount is -(1..5), so -3 average.
2018-10-13 18:14:34 -07:00
PatR
14bef9a02d formatting cleanup src/*.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.
2018-10-02 16:53:22 -07:00
PatR
3a62075070 fix #H7136 - iron bars vs non-diggable walls
Iron bars can be destroyed in some circumstances (hit by yellow
dragon breath or thrown potion of acid, being eaten by rust monser
or black pudding, or by poly'd hero in those forms) and should act
like walls for diggable/non-diggable purposes.  But they aren't
walls, so the non-diggable flag was not being set for them by the
special level loader.  Even once that was changed, they weren't
being handled consistently.  Some places checked for non-diggable
directly (zap_over_floor of acid breath, potion of acid hitting bars)
and started working as intended, others used may_dig() to check
non-diggable (poly'd hero attempting to eat iron bars) but it doesn't
handle iron bars, and still others didn't check at all (bars-eating
monster who moved onto bars location in expectation of eating those
next).
2018-09-25 16:43:06 -07:00
PatR
89237fc96d fix #H7157 - cancel self as clay golem
The report was "doesn't kill even if unchanging", but it does cause
rehumanize() when not Unchanging, the same thing that happens when
you die due to loss of hit points.  But losing the activating word(s)
and then having Unchanging retain the clay golem shape does seem
wrong, so make losing the word(s) while being unable to revert to
normal form be fatal.

Poly'd hero (without Unchanging) reverts to normal when cancelled,
so make monsters behave that way.  Previously, only werecritters in
beast form were forced to human form.  This changes cancellation to
make shapechangers and hiding mimics take on normal form too.

Cancelled shapechangers now behave as if the hero has the
Protection_from_shape_changes attribute and will be unable to change
their shape (after having been forced into normal form).  Getting
polymorphed in any fashion uncancels them prior to giving new shape.
[There may be some newcham() situations that should be disallowed
when cancelled rather proceeding and consequently uncancelling.]
2018-09-15 19:23:29 -07:00
Pasi Kallinen
e031800880 Use is_hole macro to check for trapdoors and holes 2018-09-15 17:57:57 +03:00
Pasi Kallinen
adf070eb04 Use is_pit macro to check for (spiked) pit 2018-09-15 17:19:26 +03:00
PatR
2c231f57bd git pull request #133 - reassess worn equipment
Fixes #133

Monsters who lost an amulet of life saving while having their life
saved wouldn't attempt to put on another amulet unless/until they
picked up some object.  Likewise if they had a worn item stolen.
(There are probably other events which should re-check worn gear.)

The suggested commit had a life-saved monster re-check equipment
during life-saving which might have led to reports about them
effectively getting extra moves, especially if two-weapon fighting
or zap rebound with sequence of kill/life-save/kill-again allowed
the target to put on a replacement amulet of life-saving prior to
the second kill.  It also wasn't amenable to dealing with stolen
equipment.  This alternate fix sets a flag to have monster check
its equipment on its next move.
2018-09-14 15:08:22 -07:00
Pasi Kallinen
d2eba695c8 Use DEADMONSTER instead of checking mhp 2018-08-30 20:05:18 +03:00
PatR
45c59857f7 fix "a Vlad the Impaler"
Killing Vlad while he was in bat/fog cloud/wolf form gave poorly
worded feedback when he reverted to vampire form.
2018-05-12 18:47:34 -07:00
keni
d8c49ec9d1 Add updated copyright lines, part 1. 2018-04-25 15:00:13 -04:00
PatR
f8e64b296c steed sanity check
Wizard mode sanity checking gave spurious "mon not on map" warnings
for steed when hero is mounted.  Steed is in the fmon list but not
expected to be present on the map.
2018-03-31 16:55:29 -07:00
Pasi Kallinen
4eab7b140c Don't store int into unsigned 2018-03-30 20:34:19 +03:00
Pasi Kallinen
94ad7512a6 Compile-time option to allow some prompts remember the input
Define EDIT_GETLIN to make the tty, X11, and Qt4 windowports to
remember the input strings for wishing and annotation.
2018-03-26 23:04:53 +03:00
Alex Smith
5558d62aa8 Wake up monsters, and let them stop eating, before angering them
If we do it the other way round, then mimics will forget what
they're mimicking without a seemimic() call, meaning that the
line-of-sight calculations can get confused if the mimic was
mimicking something opaque.
2018-02-20 21:53:27 +00:00
PatR
bb9738ff0e special level mimics
The special level loader would allow the level description to specify
an alternate monster appearance for any type of monster, and if one
was specified for a mimic then that mimic would be polymorphed into
the appearance instead of masquerading as it.  This changes it to
only use an appearance for mimics, the Wizard, vampires, and general
shapeshifters (chameleons, doppelgangers, sandestins).  The mimic
case doesn't work as expected:  map display shows the symbol for the
specified shape but farlook describes it as a mimic.  The Wizard case
hasn't been tested.  The chameleon and vampshifter cases seem to work.

It also allowed shapechangers (including vampires) to be given an
object or furniture appearance.  I didn't try things out to find out
what what their behavior would be if/when that happened.

I'm not sure whether the farlook issue for mimics-as-monsters is with
the pager code or the monster name formatting code.  (Possibly the
mimic just needs to be flagged has 'hidden' as well has having an
alternate appearance.)  I'm not going to worry about it since none of
our special levels attempt to give mimics a monster shape.  Mimicking
a monster is a feature for clones of the Wizard, not for mimics,
although it might be nice if the latter worked correctly someday.
2017-12-31 17:19:38 -08:00
Alex Smith
e4db58bdf3 It's OK for pets to oscillate near the player
This change was coded by FIQ, who suggested it by email.

The main change here is related to monster anti-oscillation code.
When a monster believes it's stuck in an AI loop, it looks for an
alternative strategy. That applies to pets too. However, if the
pet is currently near the player, we can typically assume that it's
there because it wants to be there, and an oscillation is not
because it's stuck but because it's already in the best possible
place. This commit causes pets to be "allowed" to stay near the
player, rather than running the wrong way down a corridor because
it's the only way to do something different than what they're
currently doing.

If the pet is far from the player, we use the old behaviour unless
the pet is leashed or the player tried to call it with a whistle
or the like, in order to avoid the risk of a genuine AI loop trying
to get back to the player. (Whistling happens rarely enough that it
won't cause AI loops of its own - the player isn't going to whistle
every turn - and it makes flavour sense that a pet might interpret
it as "you're going in the wrong direction!".)
2017-11-01 14:55:40 +00:00
PatR
cb1309cd41 address #H5931 - bug with shape-shifted vampires
[Subject was actually "possible bug with shape-shifted vampires".]
The observation was that a pet vampire which took on fog cloud form
would just stay a fog cloud, rendering it nearly useless as a pet.
Fog clouds are too weak to attack dangerous monsters so are rarely
subject to damage from counter-attacks, so they wouldn't even get
killed to revert to vampire form.

Make a vampire in fog cloud form--hostile or tame--sometimes change
to bat form if not in view or out of missile range (the same criteria
used by vampires to change into alternate shape to begin with).  Bats
are slightly more useful as pets and definitely more prone to revert
to vampire.  The potential transformation from bat to cloud isn't
done randomly; that already occurs when encountering closed doors.
2017-09-12 18:40:14 -07:00