Allow wishes for quantity up to 20 to be granted when asking for
flint. Like rocks, flints are mainly useful as sling ammo.
Also, remove the hardcoded assumption that globs weigh 20 when wish
handling computes glob weight based on user-specified count and/or
relative size.
Using #name and picking an item on the floor to be assigned a type
name allowed any of the four types of globs to be named. After
that, wishing for those by the assigned name bypassed the code that
forced the quantity to stay at 1. Asking for "3 foo" could then
produce "3 small globs of gray ooze" which fails obj_sanity() and
issues an impossible warning (which the fuzzer escalates to panic).
The "getobj refactor" patch changed the return value of call_ok().
When it gets used to check whether an object on the floor could have
a type name assigned (rather than as a getobj() callback), the test
that should have rejected the naming attempt accepted it instead.
Update the wishing code to handle globs differently: you can still
specify the relative size via small, medium, large, or very large,
but now you can specify a count either instead or in addition. A
count of more than 1 is used to multiply the created glob's weight,
although it's less likely to be honored as-is when the size is bigger
than small. Quantity is always forced to 1, at a different place in
readobjnam() than previously.
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.
Move some code that was used to decide whether to call distant_name
or doname into distant_name so that the places which were doing that
don't need to anymore and fewer places can care about whether an
artifact is being found. There were two or three instances of
distant_name maybe being called, based on distance from hero, and
yesterday's artifact livelog change added two or three more and made
all of them override the distance limit for artifacts.
After that change to distant_name, make sure that conditional calls
to it become unconditional--just not displayed for the cases where
!flags.verbose had been excluding them. That way distant_name can
decide whether an item is up close and arrange for xname to find it
if it as an artifact.
Also, implement an old TODO. Wearing the Eyes of the Overworld
extends the distance that an item can be from the hero and still be
considered near anough to be seen "up close" when monsters pick it
up or drop it. The explicit cases were using distu(x,y) <= 5, the
distance of a knight's jump. Each quadrant around the hero is a 2x2
square with the diagonal corner chopped off. The replacement code in
distant_name calculates a value of 6, which is functionally equivalent
since the next value of interest beyond 5 is 8. Wearing the Eyes
(deduced by having Xray vision) extends that threshold an extra step
in addition to overriding blindness and seeing through walls: 15,
a 3x3 square in each quadrant, still with the far diagonal corner (16)
treated as out of range.
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.
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.
There is an event for being crowned "Hand of Elebereth" and so forth
and an event for being given an artifact (any, not just the first) as
reward for #offer, but there wasn't one for the item usually given
along with being crowned.
Now there is. It's not something that an observer (of the events
being logged) can deduce since sometimes an alternative is given
(wizard and monk) and other times nothing is given (artifact already
exists or lawful character isn't wielding non-artifact long sword).
I flagged the spellbook given to a wizard or a monk as
'divinegift | artifact | spoiler'. 'artifact' since even though it
isn't actually an artifact, it is standing in the place for one. And
'spoiler', to hide from #chronicle, in case the hero doesn't know the
spellbook yet.
Allow a wizard mode wish for "wall of water" to create WATER terrain.
Previously there was no way to do that. Wishing for "pool" and "moat"
work but "water" for terrain isn't supported because it yields a potion.
If you want to declare a pointer which the address pointed to is constant,
you should declare it as like `static const char *const var = "...";`.
This commit supplies missing `const` and prevents some programming
error in the future.
Reported by entrez: when fruit name is given the name of an artifact
that doesn't use "the" at the start of its name, messages about the
artifact could be altered. Example was fruit=Excalibur causing usual
|You are blased by Excalibur's power!
to unintentionally change to
|You are blased by the Excalibur's power!
because of a false match during special handling for named fruit in
function the().
This fixes that, and also changes basic inventory formatting. Former
|f - an Excalibur
will now be
|f - Excalibur
for a fruit that has been assigned that name. When sort pack in On,
as it is by default, that will be listed under Comestibles rather than
under Weapons so really shouldn't fool anyone. And
|f - 2 Excaliburs
also breaks the illusion.
This formatting change only affects named fruits. User assigned names
for object types or for individual objects behave the same as before.
Function the() wasn't supposed to be used for monsters because many
of the ones with capitalized names confuse it, but over time multiple
instances of the(mon_nam()) have crept into the code. Instead of
ripping those out, modify the() to handle that situation better.
Pull request #636 by entrez dealt with this with one extra line of
code, but could end up scanning all the names in mons[] repeatedly
if the("Capitalized string") gets called a lot. This uses a similar
one line fix but calls a whole new routine that scans through mons[]
once collecting all the relevant special case names. As a bonus,
it does the same for hallucinatory monster names which name_to_mon()
couldn't handle.
Fixes#626
Globs never rotted away but did become tainted after a relatively
short while, which seemed like a contradiction. Change them to never
be tainted but shrink by 1 unit of weight approximately every 25
turns. An ordinary glob (one that hasn't combined with any others)
starts out weighing 20 units, so it takes about 500 turns to vanish.
That's roughly twice as long as a corpse takes to rot away.
Shrinking globs give feedback when in hero's invent or in a container
in hero's inventory, but rarely (when going from an exact multiple
of 20 weight units; that is, from integral number of N globs to
N-1 + 19/20, or if weight reduction triggers an encumbrance change).
When a glob goes away completely, there is feedback for those two
circumstances and also for seeing the glob vanish from the floor.
I haven't touched how much nutrition eating a glob confers. I have
changed formatting of glob names to use "small", "medium", "large",
"very large" instead of "small", [no adjective], "large", &c. You
still need to have at least five globs coalesced together for the
adjective to become "medium", same amount as before.
I don't think EDITLEVEL needs to be modified but have incremented it
anyway to play things safe.
Guard against any other places besides minimal_xname() that set up a
fake object without being aware that for boulders the corpsenm field
should be 0 rather than NON_PM. If that field is unexpectedly -1,
xname() will format it as ordinary "boulder" rather than producing
special "next boulder". An explict value of 1 is now required for
the latter.
simpleonames() calls minimal_xname() which was setting up a dummy
object and making its corpsenm field be NON_PM. For a boulder, that
yielded "next boulder" instead of the intended "boulder".
When you push a pile of boulders, describe the second and remainder
as "the next boulder" rather than just "the boulder". Matters most
when pushing into water or lava and you keep on pushing when the
first one or more sink into the pool or plug it, but also matters
for an ordinary push where the top-most one moves successfully and
then blocks the continuation attempt to push the second one. It was
somewhat confusing when all the messages said "the boulder" whether
they were referring to the same boulder or different ones.
Multiple pushes on the same move has always been a bit odd, but this
doesn't change that, just the feedback it generates.
Some code from about a month back changed xname() and doname() to
only use a single 'obuf[]'. That was to make sure that perm_invent
update also used at most one obuf. They use some slightly convoluted
code when they called other routines which returned an obuf because
only the most recently allocated one can be explicitly released for
re-use. That works, so I did the same for simpleonames() and
thesimpleoname() and for some reason neglected the convolution for
simpleonames().
For the case where plural was needed, it needs two obufs and tried
to release the first, which is a no-op. So if it was used in a loop
like display_pickinv() uses doname(), it could have cycled through
all the obufs and clobbered one a caller was expecting to remember.
I'm not aware of any instances of this being an actual problem, just
happened to notice that simpleonames() was different from other
similar routines.
Reported and diagnosed by entrez:
"The <mon> yanks <two-handed weapon> from your corpses!"
It became unwielded and that triggered a perm_invent update and
such updates reformat entire inventory, so if that contains a dozen
or more items it will use all the obuf[] static buffers as least
once. In this case, the bullwhip code had plural of "hand" in one
of those buffers and by the time it delivered the message which
used that, the value had been clobbered.
As the diagnosis mentioned, it can be tricky to reproduce since
either &obuf[0] or &obuf[PREFIX] might be used and if the value
being clobbered didn't overlap, the effect wasn't noticeable.
Instead of fixing the bullwhip message, this changes inventory
display so that it should no longer churn through all the buffers.
It also adds a fixes entry for #K3401, which was already fixed for
3.7 but I hadn't been able to reproduce it for 3.6.x (which I now
blame on the PREFIX trickiness).
Add two new monsters and two new objects:
gold dragon
baby gold dragon
gold dragon scale mail
set of gold dragon scales
A couple of variants seem to have added these already, but this came
off my ancient list of monsters to add and was done from scratch.
It's a clone of silver dragon, but instead of having reflection and
breathing cold, a gold dragon emits light and breathes fire; because
of the latter it can be seen with infravision like a red dragon.
Adult gold dragons are lawful as in the AD&D Monster Manual rather
than chaotic as the wiki pages show for the variant versions.
Worn gold dragon scales operate similar to wielded Sunsword: when
blessed, radius is 3 (same as a lamp), if uncursed, radius is 2, and
if cursed, radius is 1 (but functions as 2 when worn by the hero,
otherwise there would be no tangible effect). Gold dragon scale mail
gets an extra +1, making blessed gold DSM have a bigger radius than
lamps. Embedded scales have radius 1 regardless of BUC state; light
for that case comes from the gold dragon monster form the hero is in.
When not worn, gold scales and scale-mail don't emit any light.
The tiles use a mix of yellow (for gold) and red. The two object
tiles seem reasonable variations of the corresponding silver dragon
ones. The two monster tiles definitely need work since the silver
ones were mostly cyan and changing that to red did not produce very
good result; subsequent attempt at a mixture was haphazard at best.
Add "ukulele" to the exceptions that yield "a u<something>" in case
someone names their fruit that. Add the shortened form "uke" too.
While in there, generalize "one" handling to accept "one", "one<space>
<anything>" and "one<underscore><anything>" as exceptions in addition
to existing "one<dash><anything>", and "eu<anything>" to replace
existing "eucalyptus".
Fixes#552
Functionally similar to reading a T-shirt or apron, but rather than
actual text printed on the shirt being displayed, the design of the
Hawaiian shirt is described: for example, "hula dancers on an orange
background" or "tropical fish on an abstract background". Much like
T-shirts have their text included in the game-end inventory list ('a
blessed +2 T-shirt with text "foo"'), Hawaiian shirts now have a brief
description of their design appended to their item name under the same
circumstances.
Because 'reading' a Hawaiian shirt doesn't actually involve reading
text, using the 'r' command in this way doesn't break illiterate
conduct.
Changes in wish parsing included with figurine gender implementation
3 or so weeks ago accidentally broke asking for "large box" and
possibly other stuff.
Re-do "paperback book" handling to accept "paperback" and "paperback
book" but to reject previously accepted "paperback spellbook" when
wishing for a novel by description.
Something I noticed recently: a wish request for "paperback book"
yielded "Nothing fitting that description exists in the game."
Asking for "paperback spellbook" worked though.
I'm not sure whether this is the best way to handle this particular
exception but wishing for "paperback book" now works.
Use (obj->spe & CORPSTAT_GENDER) for figurines as well as for
statues and corpses.
Support wishing for
"{female,male,neuter} {corpse,statue,figurine} [of <monster>]".
and
"{female,male,neuter} <monster> {corpse,statue,figurine}".
Also
"{corpse,statue,figurine} of {female,male,neuter} <monster>"
where the qualifier might be in the middle instead of a prefix.
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
that has no nutritional value. Prevent applying the partly eaten
attribute to wished for food if the full nutrition isn't at least 2.
The problem case was 0 nutrition wraith corpse, yielding "partly
eaten food (1) more nutritious than untouched food (0)" when setting
the corpse's weight. That one was possible in 3.6.x, unlike corpse
that was actually partly eaten and then revived as a zombie (which
was just fixed for triggering the same warning).
Wishing really ought to ignore "partly eaten" for anything that is
normally eaten in one bite but I'm not sure how to handle that.
Fixes#504
It was possible to wish for a secret door, if done at a wall or
door location, but not for a regular door. Add that. (Dig
followed by locking magic possibly followed by open or by kick
could cover most of the details without wish support, but there
wasn't any way to force a closed or locked door to be trapped.)
The wish request can include "trapped" (or "untrapped", the
default) and/or one of the 5 door states: "locked", "closed",
"open", "broken", or "doorless" (default is "closed"). If more
than one state is specified, the last one in the wish text
overrides others. If trapped is specified with open or broken or
doorless, it will be ignored.
Allow "looted" when wishing for a fountain, sink, throne, or tree.
For the ones with multiple loot tracking bits, it sets them all.
Explicitly reject a wish for a wall rather than claiming nothing
of that description exists.
Formatting: wrap various wide lines.
"You hear a [BCDG] note squeak in the distance" is ok, but
"you hear a [AEF] note squeak in the distance" isn't.
Squeaky board notes already had correct a/an handling but that
particular message explicitly suppressed it.
Prevent a wish request of "death wand" (as alternate spelling
for "wand of death") from matching "Death" monster and yielding
a random wand.
"death finger" and "death finger spellbook" produce a "spellbook
of finger of death" even without a similar fix.
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.
Cap overall AC at -99 instead of -128. Put the same limit of 99
on enchantment and charge count of individual objects.
^X now reports if/when AC has reached its limit since players
could see that reaching that limit and then enchanting worn items
will change the worn items but not the total. (Same thing would
have happened with -128, just without any explanation and less
likely to accomplish.)
Won't affect normal play for any reasonable definition of normal.
Adopt the patch to show the writing on any alchemy smocks in
hero's inventory during end of game disclosure.
I also added one more saying among the choices for alchemy
smock/apron. It's based on a T-shirt descibed in a movie.
(I remember the description of the text but I don't remember
noticing anybody wearing the T-shirt that lead to that.)
Since so many of the smock quotes are about cooking, it seems
better to add it as an alchemy quote instead of just another
T-shirt where there'd be no context to explain it.
Closes#417
Move the core's global restoring flag (not the same as main()'s
local resuming flag) to a more logical place. Add a saving flag
in the process, but it isn't being set or cleared anywhere yet.
(Once in use it will probably fix the exception during save that
was just reported, but before that it would be useful to figure
out what specifically caused the event.)
The program_state struct really ought to be standalone rather
than part of struct g but I haven't made that change.
Removing an unused variable for wishing and some reformatting
that whent along with it got mixed in. Removes some trailing
whitespace in sfstruct.c too.
Only lightly tested...