When trying to reproduce the wand of striking "interesting effect (0)"
report, I tried wishing for lava under the castle drawbridge. That
wasn't handling drawbridges properly. This fixes wishing for moat,
lava, ice, or floor at a drawbridge span location whether the bridge
is currently open of closed. It also allows wishing for room or floor
or ground at room spots; that hasn't had much testing.
Wishing for furniture, pool|moat|water, or lava at an ice location
wasn't cancelling any pending melt timer.
ice_descr() was declared as returning const but returns its non-const
output buffer argument. Change to 'char *' so that wizterrainwish()
can capitilize that output without jumping through any hoops.
cg.zeroobj was originally added (under its previous unprefixed name)
for providing a one-line way to zero out the fields of a struct obj.
struct obj tempobj;
tempobj = cg.zeroobj;
initfn(struct obj *otmp)
{
if (otmp)
*otmp = cg.zeroobj;
}
More recently, the address of cg.zeroobj began to be used as a return
flag to indicate some things, but the 'const struct obj zeroobj' wasn't
an ideal fit for the purpose and required a number of casts, including
casting away const.
Provide a better fitting variable (gi.invalid_obj) and eliminate a
number of casts.
Modifying an() [actually just_an()] to treat "<thickness> ice" and
"frozen <hallucinatory liquid>" as special cases which shouldn't be
prefixed with "a" or "an" affected using something like "shaved ice"
or "frozen yogurt" as named fruit.
|a) shaved ice
|b) frozen yogurt (weapon in hand)
now have article "a" preceding them:
|a) a shaved ice
|b) a frozen yogurt (weapon in hand)
However, the existing cases
|c) iron bars
|d) an iron bars (weapon in hand)
still get item 'c' wrong. 'd' is slightly odd but that's because the
fruit name is ambiguous as to whether it's singular or plural.
Classify nearby ice as "solid" (no melt timer), "sturdy" (more than
1000 turns left), "steady" (101 to 1000 turns left), "unsteady" (51
to 100 turns left), "thin" (15 to 50 turns left), or "slushy" (1 to
14 turns left, matching walking on ice with the Warning attribute).
[I'm not thrilled with "steady" and particularly "unsteady".]
I was originally going to do this just for probing downward, but ended
up also doing it for look-here and getpos's autodescribe. It nearly
got out of hand and touched more files than anticipated.
'mention_decor' ought to treat moving from ice firmer than thin to
thin or slushy, from thin to slushy, from slushy to any other, and
from thin to firmer as if moving onto different terrain but I haven't
attempted to tackle that.
The melt timer could work more like a candle's burn timer, triggering
at intermediate stages and resetting itself, so that ice which changes
to a weaker state under the hero could be reported to the player. But
this doesn't implement that.
Pointed out by entrez: prevent doname() from consuming two obuf[]
buffers when it constructs the plural of "hand" while formatting a
wielded two-handed weapon.
Since only one such item should be able to occur in any list of
objects, it is not likely to be the cause of any message oddities
that might happen when a cached value is in a formatting buffer gets
re-used too soon. However, not releasing a second buffer right away
prevents an attempt to release the first one from succeeding because
it won't be the last one allocated anymore, so some buffer churn was
happening.
The correct plural of "Cyclops" is "Cyclopes", not "Cyclopses". I don't
know if anyone would actually use that as a fruitname, but it wouldn't
hurt to add it -- especially since a Cyclops does appear in the game.
Instead of a 5% chance for crystal plate mail or crystal helmet to
break each time it's subjected to breakage, switch to a 10% chance
but the damage is treated as erosion rather than break/don't-break.
'crystal foo' will need to go through four stages of damage before
breaking: cracked crystal foo, very cracked crystal foo, thoroughly
cracked crystal foo, then gone. Crackproof handling is included,
described as tempered crystal foo.
It mostly still applies to throwing and kicking the item. Having
some hits trigger damage might be worthwhile but isn't implemented.
Object creation within lua code probably needs to be updated, and
when the Mitre of Holiness is created in the priest/priestess quest
it should start out as tempered (erodeproof). Perhaps it ought to
be erodeproof regardless of where/how it's created.
Issue reported by vultur-cadens: changing helm of brilliance to
crystal made it stop being classified as "hard helmet" so it gave
less protection against things falling onto the hero's head.
Change the is_metallic() tests used on helmets to new hard_helmet().
Unlike when thrown, crystal helmets don't break when objects fall
on them.
Fixes#1060
This replaces most of commit 0ca2af4d8b
from a couple of days ago with something more robust. That change
actually introduced redundant code that caused fountain and/or sink
count to be off instead of preventing it.
Revise set_levltyp() to update level.flags.nfountains and
level.flags.nsinks if setting the type to or from fountain or sink.
A bunch of places that were setting levl[x][y].typ directly needed
to be revised to use set_levltyp() instead. set_levltyp() itself
hadn't been updated to handle LAVAWALL (to force such to be lit).
Noticed while considering the pull request about loosening
restrictions on trap creation at furniture locations. If you wish
for a terrain feature while on a fountain or sink, the counters
used to control whether sounds for those should be given will be
off by one.
It was incrementing the appropriate counter if you wished for a
fountain or sink, but it shouldn't do that if recreating the same
feature (perhaps to reset a magic fountain or looted sink) and it
needed to decrement when replacing either of those with some other
feature. After the count became wrong, if all fountains or sinks
on the level were destroyed, those splashing, gurgling, &c sounds
would continue to be generated periodically.
Add "walls of lava", basically lava which blocks vision and
require a bit more than just levitation or flight to move through.
No levels use this yet, as testing isn't thorough enough.
A detected cave spider was hiding under a generic spellbook object;
farlooking at it produced a segfault. OBJ_NAME is null for the generic
objects, so don't try to strcmp it.
When playing as a Samurai, add things like "osaku" to the discoveries
list even though they don't have separate descriptions to be used
when not yet discovered. Non-magic ones are pre-discovered and
players can now use the '\' command to figure out what things like
"tanko" mean without resorting to '/?'.
"wooden harp" has been getting changed to "koto (harp)"; make that be
| koto [wooden harp] (koto)
"magic harp" has been staying as "magic harp (harp)"; add it to the
list of Japanese item names. Since it's magic it isn't pre-discovered.
Once discovered it becomes
| magic koto [magic harp] (koto)
Those two needed special case handling, none of the other items did
aside from forcing them to be discoverable when lacking descriptions.
The discoveries list now has things like
| wakizashi [short sword]
| naginata [glaive] (single-edged polearm)
| gunyoki [food ration]
if--and only if--the hero is a Samurai.
The analyzer complained that the second call to Japanese_item_name()
might return Null after the first one didn't.
| if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
| actualnm = Japanese_item_name(otyp);
even though the code involved is self-contained and deterministic.
Then later in obj_typename() 'actualnm' gets passed to strcat() or
strcpy() where Null isn't acceptable.
Could probably fix that by caching and reusing the first return value:
| if (Role_if(PM_SAMURAI) && (jname = Japanese_item_name(otyp)) != 0)
| actualnm = jname;
but I went a different route, revising that routine to take a second
argument:
| if (Role_if(PM_SAMURAI))
| actualnm = Japanese_item_name(otyp, actualnm);
It now passes back 'actualnm' instead of Null when no substitution
takes place.
The recent introduction of generic objects without names meant that
'actualnm' could actually be Null, but generic objects only occur
for map glyphs and only when dknown is 0, so the actual-name field
shouldn't ever be get used for them. Give actualnm a fallback value
just in case.
Wishing is a place that loops over all of objects[] so have it skip
the generic objects. They're all flagged no-wish so weren't being
chosen, but explicitly skipping them makes the intention clear.
A number of C compiler suites have a math.h library that includes a yn()
function name that conflicts with NetHack's yn() macro:
"The y0(), y1(), and yn() functions are Bessel functions of the second kind,
for orders 0, 1, and n, respectively. The argument x must be positive. The
argument n should be greater than or equal to zero. If n is less than zero,
there will be a negative exponent in the result."
At one point, isaac64.h included math.h, although that has since been removed.
Some libraries used in NetHack (Qt for one) do include math.h and that required
build work-arounds to avoid the conflict.
Rename the NetHack macro from yn() to y_n() and avoid the math.h conflict
altogether, eliminating the need for that particular work-around.
Replace FIRST_GEM and LAST_GEM with FIRST_REAL_GEM, LAST_REAL_GEM,
FIRST_GLASS_GEM, and LAST_GLASS_GEM and define those along with
objects[] rather than separately. Do the latter for FIRST_AMULET
and LAST_AMULET too. Also new FIRST_SPELL and LAST_SPELL used to
compute MAXSPELLS. (That value looks wrong to me, but this defines
it with the same value as before. If it gets fixed, EDITLEVEL will
need to be incremented.)
This started as just proof of concept that extra information could
be collected as objects[] gets initialized at compile time.
Move the new stuff from PR #946 out of xname() into new routine
armor_simple_name().
Noticed while testing: tweak 'call object type' so that it doesn't
list instances of pre-discovered armor as likely candidates since
assigning a name to such wasn't showing up in the discoveries list.
Add "silver shield" as wishing synonym for "polished silver shield".
This will distinguish between a hat and a helmet, shoes and boots, etc,
so that a "conical hat" doesn't turn into a "helmet called dunce" after
type-naming it, and so on. Instead, more specific names will be used
for the base type, consistent with the terms used in various messages
(so "a hat called dunce").
Some of these don't seem like necessary distinctions to make, and some
of them probably don't make a difference at all (e.g. gloves vs
gauntlets, since "gauntlets" only shows up once you've IDed the item so
the user-assigned typename isn't visible), but it probably makes sense
to be consistent in using these functions if it's done for any armor
type.
The consolidation of global variables from scattered source
files into decl.c and declared in decl.h was begun in 3.7.0.
Their placement in common files was done for centralized
initialization and potential re-initialization during a
"play again" scenario.
It wasn't really necessary for all of them to be housed in a
single huge structure to meet the "play again" requirement,
and the single huge structure has been a little unwieldy when
it comes to maintenance.
Following this commit, instead of one single extremely large structure
named 'g' to house all of the relocated global variables, they
are distributed into several ga through gz.
To make things easy for the developer, each variable is placed
into the struct corresponding to the starting letter of the variable.
That way, no lookup is required in order to know which struct houses
a particular variable, it is a simple match to the starting letter
for all the centralized global variables.
A global variable named 'amulets', would be found in ga.
ga.amulets
^ ^
A global varable named 'move', would be found in gm.
gm.moves
^ ^
A global variable named 'val_for_n_or_more' would be found in gv.
gv.val_for_n_or_more
^ ^
A global variable named 'youmonst' would be found in gy.
gy.youmonst
^ ^
Issue reported by Melon2007: when non-deaf hero heard an unseen
monster read a scroll, the monster's type was identified accurately
(unless distorted by hallucination). That was intentional but it
doesn't seem plausible for the hero's hearing to be that acute.
Change it to report the monster type accurately if not hallucinating
and monster is the same species as the hero (as the current form if
hero is poly'd), otherwise report it as "someone" when it's humanoid,
otherwise as "something".
Also, if the monster is heard at a spot that would be visible if
hero could see, draw a "remembered, unseen monster" glyph there.
Fixes#934
Instead of using index() macro defined to strchr, use C99 strchr.
Instead of using rindex() macro defined to strrchr, use C99 strrchr.
If you want to try building on a platform that doesn't offer those
two functions, these are available:
define NOT_C99 /* to make some non-C99 code available */
define NEED_INDEX /* to define a macro for index() */
define NEED_RINDX /* to define a macro for rindex() */
Pull request #607 by Vivit-R proposed renaming "huge chunk of meat"
to "giant meatball" to better reflect the similarity to meatball.
But an object name that contains a monster name prefix requires extra
work in the wishing code. I considered "huge meatball" which retains
more of the original name but decided to go with "enormous meatball"
becaues it seems more evocative.
Supersedes #607Closes#607
Format a horn of plenty whose charge count is unknown but is known to
be empty as "empty horn of plenty" like is done for real containers.
This was too easy; I must have missed something....
begin_burn() was called before the quantity of wished lit candles was
restricted which meant that the light source radius could depend on a
larger quantity than the final object actually had.
The 'wizmgender' option is flagged as 'wizonly' in optlist.h but that
doesn't prevent it from being set in NETHACKOPTIONS or .nethackrc.
Apply the fix from entrez to only honor it when running in wizard
mode.
Add another use to wizmgender: when it is enabled, include the gender
specified in corpstat flags in the name of a statue, corpse, or
figurine, since it can influence various things but otherwise remains
invisible (for monsters without gendered names). A little while ago
lichen corpses weren't stacking because, despite being a neuter monster,
the corpses they produced were being flagged as female or male; this
could be useful for debugging issues along those lines.
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
All the quest artifacts are named "The <something> of <someone>".
Change xname() to force "the" instead of "The" when that occurs in
the middle of "a skeleton key named The Master Key of Thievery" or
"a pair of lenses named The Eyes of the Overworld".
This change isn't applied to user-assigned names; they're used as-is.
Wishing for a door is intended to retain the existing 'horizontal' value
of the surrounding wall or door (see comment in the wizterrainwish
'door' case). However, the field was being reset by mistake, causing
all door wishes to create vertical doors. Preserve it as intended.
Wishing for "N <size> globs [of pudding type]" produces 1 glob
starting at <size> and then multiples weight by N (so possibly
increasing <size>). When not it wizard mode, N can be replaced by
a random amount to prevent the total weight from being huge. When
N was less than 6, it was possible for that random amount to be
larger than what the player asked for.
Change the way the random amount is calculated so that it won't
ever be larger than what player specified. Also for wizard mode
prompt whether to make the substitution so that the player can
choose to abide by the limit or to obtain a huge glob for whatever
testing is being conducted.
I meant to wish for a "wand of cold" and accidentally typed "wand of
ice". Instead of being told that there's no such thing or receiving
a random wand, the spot I was standing on was changed to ice.
Only check for a terrain-change wish if an object class hasn't been
stripped from the wish text.