If the first monster on the migrating_mons list couldn't arrive and
was put back on the list to try again later, 'later' would happen
immediately and the program looped forever trying and failing to
bring that monster to the level.
Defer repeat attempts at migration until losedogs() has been through
the whole migrating_mons list. mon_arrive() now populates a new
list called failed_arrivals and losedog() moves its contents, if any,
to migrating_mons prior to returning.
One of the drivers of this change was that screen coordinates require a
type that can hold values greater than 127. Parameters to the window
port routines require a large type in order to be able to have values
a fair bit larger than COLNO and ROWNO passed to them, particularly for
their use to the right of the map window.
This splits the uses of xchar into 3 different situations, and adjusts
their type and size:
xchar
|
-----------------------
| | |
coordxy xint16 xint8
coordxy: Actual x or y coordinates for various things (moved to 16-bits).
xint16: Same data size as coordxy, but for non-coordinate use (16-bits).
xint8: There are only a few use cases initially, where it was very
plain to see that the variable could remain as 8-bits, rather
than be bumped to 16-bits. There are probably more such cases
that could be changed after additional review.
Note: This first changed all xchar variables to coordxy. Some were
reviewed and got changed to xint16 or xint8 when it became apparent that
their usage was not for coordinates.
This increments EDITLEVEL in patchlevel.h
From a followup comment to a reddit post: a vampire who has gained
levels loses them when reverting to base form. This fixes the case
where it grows into a vampire lord; change the base form from plain
vampire to lord when that happens.
It does not fix the case where shapechanging to fog or bat or wolf
and then back to base form yields a new vampire or vampire lord
instead of the one that built itself up. Mainly affects pet vampires
since wild oees don't tend to grow very much.
Reverse the sense of dochugw()'s new 'X' argument. Use True for the
usual case and False for the special case rather than the other way
around.
Call the special case variant when a monster teleports so that hero
stops occupation if the monster jumps to a position where it becomes
a threat.
Fix the problem reported by entrez of a zombie corpse reviving and
crawling out of the ground while the hero was busy doing something
(searching, digging, &c) and having the hero fail to react and just
keep doing whatever the thing was because the zombie was already
inside the range where a monster changes from no-threat to threat.
Done in the monster creation routine so any new monster (including
one revived from a corpse) that is visible,&c will cause the hero's
action to be interrupted. Teleport arrival probably needs this too.
Only interrupts an occupation, not other voluntary multi-turn
actitivy such as running or traveling. That would be trivial to
change ['if (g.occupation...' to 'if ((g.occupation || multi > 0)...']
but I'm not sure whether it ought to be extended to that.
Reported by entrez. Don't make 50% of neuter monsters be flagged as
female. It doesn't matter for live monsters but gets inherited by
their corpses, where female and non-female corpses stack separately.
monster and Elbereth unless there's no other choice.
Suggested by NetSysFire, don't create new monsters on top of scrolls
of scare monster. Not mentioned in the suggestion: unless they are
a type of monster that isn't affected by such scrolls. This extends
it to teleport destination too.
Avoid placing a monster on a scroll of scare monster or on engraved
Elbereth if there are other locations available. Only performed for
callers of goodpos() who explicitly request it, which at the moment
are makemon(), rloc(), and enexto().
Also, propagate 'mmflags_nht' to a bunch of places that were left
using long or unsigned for makemon() and goodpos() flags. I didn't
attempt to be systematic about that though.
Implements #717
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.
get lawful artifacts
Reported by vultur-cadens, Angels can be given Sunsword or Demonbane
for starting equipment even when they aren't lawful so won't attempt
to use those.
This should fix it but it's a pain to test.
Closes#691
Lay groundwork for generating a log event when finding an artifact
on the floor or carried by a monster. This part should not produce
any change in behavior.
Move g.artidisco[] and g.artiexist[] out of the instance_globals
struct back to local within artifact.c. They are both initialized
at the start of a game (and only used in that file) so don't need
to be part of any bulk reinitialization if restart-instead-of-exit
ever gets implemented.
Convert artiexist[] from an array of booleans to an array of structs
containing a pair of bitfields. artiexist[].exists is a direct
replacement for the boolean; artiexist[].found is new but not put to
any significant use yet. If will be used to suppress the future
found-an-artifact event for cases where a more specific event (like
crowning or divine gift as #offer reward) is already produced.
Remove g.via_naming altogether and add an extra argument to oname()
calls to replace it.
Add an extra argument to artifact_exists() calls.
For ^G, throttle the monster creation feedback. Don't say "suddenly"
and don't exclaim the message, just say "<Mon> appears." Also, use
Norep() so creating lots of similar monsters at once only gives a few
messages (just one unless varied by "next to you" vs "nearby" vs no
qualifier for farther away). And for mimics created as objects or
furniture, report the sudden appearance of new object or furniture.
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.
If persistent inventory is displayed and contains an entry for a leash
attached to a pet and the pet's type or name changes, the perm_invent
window didn't get updated to reflect the new leash information:
x - leash (attached to <mon>)
Report was for polymorph but applied to growing into bigger form and
to being (re-/un-)christened as well.
Reported by eakaye. Selection of equipment when creating a soldier
or watchperson can pick a polearm, but random selection among those
had a chance to choose dwarvish mattock which doesn't use polearms
skill and isn't appropriate for a human soldier or watchperson.
Not mentioned, but lance was in the same boat.
Change the selection to only pick something which uses polearms
skill, then make that moot by moving lance and dwarvish mattock out
of the midst of the polearms so that they're no longer candidates
for special case rejection.
A couple of other things which might have had a similar issue were
already ok. Giving a polearm when creating a troll selects between
a few choices rather than among all the polearms. And wishing for
"polearm" only considers items which use polearms skill.
While changing objects.h to reorder the two non-polearms, I removed
a bunch of tabs that were present in the scroll definitions.
EDITLEVEL is incremented due to objects[] reordering, so existing
save and bones files will be invalidated.
Fixes#623
for helm of opposite alignment.
Discovered and described by vultur-cadens.
The #adjust command can be used to split an object stack and if the
shop price of the two halves are different, the new stack will have
its obj->o_id modified to make the prices the same. That could be
used to tip off the player as to what the low bits of the next o_id
will be. Since no time passes, no intervening activity such as
random creation of a new monster can take place, so the player could
wish for something that depends on o_id with some degree of control.
Matters mainly for helms of opposite alignment intended to be used
by neutral characters since the player isn't supposed to be able to
control that. (Other items like T-shirt slogan text and candy bar
wrapper text had a similar issue but controlling those wouldn't have
had any tangible difference on play.)
The issue writeup suggested allowing the player to specify a helm's
alignment during a wish. That would defeat the purpose of having
o_id affect the helm's behavior in an arbitrary but repeatable way
so is rejected.
I implemented this fix before seeing a followup comment that suggests
using a more sophisticated decision than 'obj->o_id % N' for the
arbitrary effect. This just increments context.ident for the next
obj->o_id or mon->m_id by 1 or 2 instead of always by 1 and should
be adequate. It also has the side-effect that two consecutive wishes
for helm of opposite alignment won't necessary give one for each of
the two possible 'polarities', even with no intervening activity by
monsters, reinforcing the lack of player control.
Minor bonus fix: it moves the incrementing check for wrap-to-0 into
a single place instead of replicating that half a dozen times. Ones
that should have been there for shop billing and for objects loaded
from bones files were missing.
Fixes#596
Adds the following lua functions:
- nh.pushkey("x")
Pushes a key into the command queue. Support is spotty,
currently only the keys handled in rhack.
- nh.doturn()
Runs one turn of main loop, or if optional boolean param
is true, until g.multi == 0
- nh.monster_generation(false)
Disable monster generation, and kill off all monsters.
Adds a testmove.lua script to test hero movement. Currently
covers only hjklyubn and HJKLYUBN.
Shop population code set the mimic shape to strange object
without checking for protection from shape changers.
Let set_mimic_sym (via makemon) handle it correctly instead.
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.
add MALE, FEMALE, and gender-neutral names for individual monster species
to the mons array. The gender-neutral name (NEUTRAL) is mandatory, the
MALE and FEMALE versions are not.
replace code uses of the mname field of permonst with one of the three
potentially-available gender-specific names.
consolidate some separate mons entries that differed only by species into a
single mons entry (caveman, cavewoman and priest,priestess etc.)
consolidate several "* lord" and "* queen/* king" monst entries into
their single species, and allow both genders on some where it makes some
sense (there is probably more work and cleanup to come out of this at some
point, and the chosen gender-neutral name variations are not cast in stone
if someone has better suggestions).
related function or macro additions:
pmname(pm, gender) to get the gender variation of the permonst name. It
guards against monsters that haven't got anything except NEUTRAL naming
and falls back to the NEUTRAL version if FEMALE and MALE versions are
missing.
Ugender to obtain the current hero gender.
Mgender(mtmp) to obtain the gender of a monster
While the code can safely refer directly to pmnames[NEUTRAL] safely in the
code because it always exists, the other two (pmnames[MALE] and
pmnames[FEMALE] may not exist so use:
pmname(ptr, gidx)
where -ptr is a permonst *
-gidx is an index into the pmnames array field of the
permonst struct
pmname() checks for a valid index and checks for null-pointers for
pmnames[MALE] and pmnames[FEMALE], and will fall back to pmnames[NEUTRAL] if
the pointer requested if the requested variation is unavailable, or if the
gidx is out-of-range.
Allow code to specify makemon flags to request female or male (via MM_MALE
and MM_FEMALE flags respectively)to makedefs, since the species alone doesn't
distinguish male/female anymore. Specifying MM_MALE or MM_FEMALE won't
override the pm M2_MALE and M2_FEMALE flags on a mons[] entry.
male and female tiles have been added to win/share/monsters.txt.
The majority are duplicated placeholders except for those that were
separate mons entries before. Perhaps someone will contribute artwork in the
future to make the male and female variations visually distinguishable.
tilemapping via has the MALE tile indexes in the glyph2tile[]
array produced at build time. If a window port has information that the
FEMALE tile is required, it just has to increment the index returned
from the glyph2tile[] array by 1.
statues already preserved gender of the monster through STATUE_FEMALE
and STATUE_MALE, so ensure that pmnames takes that into consideration.
I expect some refinement will be required after broad play-testing puts it to
the test.
consolidate caveman,cavewoman and priest,priestess monst.c entries etc
This commit will require a bump of editlevel in patchlevel.h because it alters
the index numbers of the monsters due to the consolidation of some. Those
index numbers are saved in some other structures, even though the mons[] array
itself is not part of the savefile.
Window Port Interface Change
Also add a parameter to print_glyph to convey additional information beyond
the glyph to the window ports. Every single window port was calling back to
mapglyph for the information anyway, so just included it in the interface and
produce the information right in the display core.
The mapglyph() function uses will be eliminated, although there are still some
in the code yet to be dealt with.
win32, tty, x11, Qt, msdos window ports have all had adjustments done to
utilize the new parameter instead of calling mapglyph, but some of those
window ports have not been thoroughly tested since the changes.
Interface change additional info:
print_glyph(window, x, y, glyph, bkglyph, *glyphmod)
-- Print the glyph at (x,y) on the given window. Glyphs are
integers at the interface, mapped to whatever the window-
port wants (symbol, font, color, attributes, ...there's
a 1-1 map between glyphs and distinct things on the map).
-- bkglyph is a background glyph for potential use by some
graphical or tiled environments to allow the depiction
to fall against a background consistent with the grid
around x,y. If bkglyph is NO_GLYPH, then the parameter
should be ignored (do nothing with it).
-- glyphmod provides extended information about the glyph
that window ports can use to enhance the display in
various ways.
unsigned int glyphmod[NUM_GLYPHMOD]
where:
glyphmod[GM_TTYCHAR] is the text characters associated
with the original NetHack display.
glyphmod[GM_FLAGS] are the special flags that denote
additional information that window
ports can use.
glyphmod[GM_COLOR] is the text character
color associated with the original
NetHack display.
Support for including the glyphmod info in the display glyph buffer
alongside the glyph itself was added and is the default operation.
That can be turned off by defining UNBUFFERED_GLYPHMOD at compile time.
With UNBUFFERED_GLYPHMOD operation, a call will be placed to map_glyphmod()
immediately prior to every print_glyph() call.
Only quantum mechanics are supposed to have a chance of death-dropping the
Schroedinger's cat box.
Slash'Em already had this but it was missed when Genetic engineers were ported
over.
commit 03d7d64d15:
| [...] but fixing this specific case is trivial.
Not trivial enough to avoid getting the details wrong. An old
commit log message (58137a608a,
June of 2006) claimed that this was fixed for bag of tricks but
that was for monsters in general; mimics could still be wrong.
From an old bug report (sent directly to devteam, June of 2017):
wand or scroll of create monster becomes discovered if it makes
a mimic that is concealed as an object or as furniture within
the hero's view. Fixing this in the general case [when does
seeing a mimic as something other than a monster mean that the
mimic is being seen?] is a massive can of worms, but fixing this
specific case is trivial.
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.
The recently added sanity check for monster maximum HP was giving
false complaints when Nd8 monster had N mhpmax. Most noticeable
for level 1 monsters (level 0 monsters use 1d4 instead of 0d8 and
weren't affected) but possible for higher level ones if they were
unlucky--from their own perspective--with all their d8 rolls.
Give level N monsters a minimum of N+1 HP, so minimum of 2 for
level 1 monsters, making 1/8 of those stronger. Same minimum for
level 0 monsters, 25% of which will become stronger now. (The pull
request's patch gave every Nd8 monster 1 extra HP; this only does
so for Nd8 and 1d4 ones which have rolled lowest possible amount.)
Also relax the sanity check so that existing to-be-3.7 save files
don't continue to trigger sanity complaints for existing monsters
that have the old minimum.
Fixes 365
montraits() didn't have any handling for long worm tails, makemon()
didn't have any provision for creating a long worm without a tail,
replmon() uses place_wegs() to put tail segments on the map when
replacing a dummy new monster with the mtraits one but place_wsegs()
wasn't updating the head segment since it isn't put on the map.
That turned out to be key because there is always an extra segment
co-located with the monster and when its coordinates were wrong,
worm_known() gave bad results for visibility checking. The
statue-goes-away message was the one for not being able to see the
monster that it just animated into, even though 'w' appeared at the
spot. It took quite a while to track down what was going on there.
Sanity checking for worms has been updated and could conceivably
start triggering complaints about things that it used ignore.
The recent change to mkclass() was letting genocided monsters be
created when role-specific monsters were chosen for quest levels.
makemon(Null) -> rndmonst() -> qt_montype() -> mkclass() -> mk_gen_ok()
was accepting members of the quest-specified class even when they
should have been rejected. I'm still not sure why the revised bit
manipulation didn't work as intended; the re-revised code does.
G_IGNORE was a bug waiting to happen since it gets passed to
mkclass() as a mons[].geno flag but is used to control the use of
mvitals[].mvflags values. It's still being misused but at least
it doesn't conflict with any of the other flags now.
Fixes#352
Accept or ignore the in-hell-only and non-in-hell-only flags on
a monster type by monster type basis instead of all or nothing
for a given mkclass() call. Prevents demon summoning outside of
Gehennom from bringing in only succubi and incubi 10 times out
of 11 and mixture of demons the other time.
Change mkclass() to always honor the hell-only monster generation
flag for L class, preventing master and arch-liches outside Gehennom.
For other classes, honor hell-only and outside-hell-only most (89%)
of the time. When not honored (11%), it allows demons and devils to
appear outside of Gehennom as they have in the past. [That part
might need to be re-done since it is done for all monsters in the
class on any mkclass() call instead of being done on a class-member
by class-member basis within each such call.]
This prevents out of depth liches in the Castle and ought to do same
for themed rooms of type 'Mausoleum' although I haven't figured out
how to test that.
Fixes#349
I added another goodpos flag to simplify handling displacer beast
and that pushed the total number of makemon and goodpos flags past
16. 'int' and 'unsigned' might be too small, so change the flags
and several function arguments to 'long'.
Make a mimic that picks special VEGETARIAN_CLASS look like food
instead of a random object. Also, at least a couple of Minetown
variants are classified as mazes so had a 50% chance of not even
making that choice and look like a statue instead. Override maze
when 'in_town()' yields True.