When eating a meal that is affected by acid resistance or stoning
resistance and protected by temporary resistance, increase the timeout
so that the resistance doesn't expire until after the meal finishes.
That avoids getting the "you no longer feel safe from {acid,stoning}"
during the meal and not being affected by the dangerous food despite
that message. Useful because the protection is checked at the start
of the meal and not rechecked during; extending the duration hides
the latter.
It turns out that there were a bunch more monsters with the corpse-
conveys-stoning-resistance flag than just green mold. Instead of
stripping it off, give them (including green mold) a chance to confer
timed resistance against stoning and also against acid.
All of these can convey either of those two resistances. Like other
intrinsics obtained via eating, at most one can be obtained from any
given corpse.
green mold, acid blob, spotted jelly, ochre jelly, black naga,
yellow dragon, Chromatic Dragon
These can confer temporary stoning resistance but not acid resistance:
lizard, chickatrice, cockatrice, gargoyle, winged gargoyle,
xorn, Medusa
There aren't any that confer just acid resistance without a chance for
stoning resistance.
The effect lasts for 3d6 turns, or is extended by 3d6 more if randomly
chosen and applied when already in effect.
Having temporary acid resistance time out during another meal when
eating a corpse that ends up conferring acid resistance seems strange.
The protection against acid is granted at the start of the meal and
continues to the end (in regards to eating, not external attacks) even
when the intrinisic is lost in between. I'm not sure whether that
needs some form of fixing, and if so, what that fixing should be.
Fix a minor 'fixme': if hero breaks vegetarian conduct by eating
something made of bone, leather, or dragon-hide while polymorphed
into a shape which can eat such things, change the message from
"ate meat for first time" to "ate meat by-products for first time".
It took me a while to arrive at a sequence of actions which would
successfully test this. You need to break foodless and vegan
conducts first, then break vegetarian with leather/bone separately
or it won't trigger a livelog event for that. Wish for and eat a
candy bar to break vegan conduct, polymorph into a gelatinous cube,
wish for and eat leather armor, then use the #chronicle command.
Life-saving has been setting u.uhpmax to max(2 * u.ulevel, 10)
and if it took place during level drain that could make u.uhpmax
increase instead of decrease, confusing healing which gets applied
to a monster who has drained the hero with Stormbringer or the
Staff of Aesculapius. Change the setting to be max(u.ulevel, 10)
(removing the times two part) and also have level drain force it
to be set back to previous value if/when it gets increased.
Max HP loss due to strength trying to drop below 3 or to fire trap
or to being hit by Death now uses a mininum max HP of u.ulevel
rather than 1. They don't have the alternate minimum of 10; I'm
uneasy that there are still two different minimum values.
I changed adjattrib() to set the flag to request a status update
before it gave its optional message rather than after so that the
new characteristic value would be visible during the message. That
resulted in not updating status when eating royal jelly changed HP
or max HP after boosting strength. But the same missing update
would have occurred--or rather, failed to occur--without the change
in sequencing if the strength boost causes a change in encumbrance.
trycall() is a short docall() wrapper that is a no-op if the item is
already identified or the player has called the object type already. For
some reason, many calls to docall() did those same exact checks
beforehand.
This commit eliminates that redundancy by converting those calls into
trycall(), which is now made extern rather than local to do.c. No
behavior should be changed by this commit; I've checked that none of the
affected places could take a different code path now that the
oc_name_known and oc_uname checks are removed.
Shorten the livelog messages for food conduct a little by changing a
bunch of "the first time" to just "first time". Will result in fewer
instances of tty condensing whitespace for a too-wide line written
into a text window. That includes stripping off indentation, which
messes up the alignment of #chronicle output.
Also, eliminate one redundant livelog printf. Breaking vegan conduct
by eating wax when poly'd can be folded into same message for eating
leather/bones/dragon hide. [The breaking vegetarian conduct for those
says "eating meat" which seems wrong but hasn't been changed.]
This is just reformatting some relatively recently added code.
There's a lot of redundancy in eating conduct tracking and livelog
reporting of that, but this doesn't attempt to streamline it. I may
try again some other time....
Log game events, such as entering a new dungeon level, breaking
a conduct, or killing a unique monster, in a new "Major events"
chronicle. The entries record the turn when the event happened.
The log can be viewed with #chronicle -command, and the entries
also show up in the end-of-game dump, if that is available.
This feature is on by default, but can be disabled by
defining NO_CHRONICLE compile-time option.
This also contains "live logging", writing the events as they
happen into a single livelog-file. This is mostly useful for
public servers. The livelog is off by default, and must be
compiled in with LIVELOG, and then turned on in sysconf.
Mostly this a version of livelogging from the Hardfought server,
with some changes.
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.
Wounded_legs was changed from (HWounded_legs || EWounded_legs) to
just (HWounded_legs), but when the timeout code decremented the timer
to 0, HWounded_legs became 0 and heal_legs() operated as if there was
nothing to repair and hero didn't recover from temporarily lost Dex.
Change Wounded_legs back to (HWounded_legs || EWounded_legs).
Instead of returning ECMD_OK, the commands now return ECMD_CANCEL
when user declined to pick a direction or an object to act on.
Note that this can be ORed with ECMD_TIME, if the command still
took a turn.
For now this has no gameplay meaning.
Instead of returning 0 or 1, we'll now use ECMD_OK or ECMD_TURN.
These have the same meaning as the hardcoded numbers; ECMD_TURN
means the command uses a turn.
In future, could add eg. a flag denoting "user cancelled command"
or "command failed", and should clear eg. the cmdq.
Mostly this was simply replacing return values with the defines
in the extended commands, so hopefully I didn't break anything.
Keep track of the highest value that u.uhpmax and u.uenmax have
attained, in new u.uhppeak and u.uenpeak. They aren't used for
anything yet. u.mhmax (max HP while polymorphed) isn't interesting
enough to track.
Not save and bones compatible so increments EDITLEVEL.
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.
Popeye, used to check whether eating a particular tin is a potential
lifesaving action, considered tins of chameleon meat a cure for sliming
(since you can polymorph into a fiery monster), but didn't credit the
same possible curative power to other tins which can polymorph the hero.
Use the polyfodder macro (used elsewhere to check whether eating
something will polymorph a monster/pet) to determine whether a tin will
polymorph the hero.
It's redundant with g.moves, so there is no more need for it.
Way, way back, it looks like g.moves and g.monstermoves can and did
desync, where g.moves would track the amount of moves the player had
gotten (and would therefore increase faster if the player were hasted)
and g.monstermoves would track the amount of monster move cycles, aka
turns. But this has not been the case for a long time, and they both
increment together in the same location in allmain.c. There are no
longer any cases where they will not be the same value.
This is a save-breaking change because it changes struct
instance_globals, but I have not updated the editlevel in this commit.
Add some vomiting effects:
Trigger divine wrath if hero vomits at an altar's location. (What
about adding throne and maybe sink special effects too?)
If poly'd into a yellow dragon, breathe (acid) on self. (I'm not
sure why.)
If on ice and poly'd into an acidic form, melt the ice. Also,
change melt_ice() to give its message when melting happens at the
hero's location even if hero can't see.
Fixes#519Fixes#510
... and make them actually deal damage based on the energy
it would've drained, if you have Antimagic.
Also prevent them appearing too early in the dungeon.
Allow drain energy attacks (and anti-magic traps) drain more
than your level of energy.
Make eating magical monsters such as wizards and shamans give
the same tiny buzz bonus as eating a newt.
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
Homemade tin would yield a flat 50 points of nutrition even when
made from a corpse that provides less than 50 points. Take the
minimum of the two amounts instead of always 50.
Fixes#478
Whitelist all the verified existing triggers:
makedefs.c: In function ‘name_file’
attrib.c: one compiler balks at a ? b : c for fmtstring
cmd.c: In function ‘extcmd_via_menu’
cmd.c: In function ‘wiz_levltyp_legend’
do.c: In function ‘goto_level’
do_name.c: In function ‘coord_desc’
dungeon.c: In function ‘overview_stats’
eat.c: one compiler balks at a ? b : c for fmtstring
end.c: one compiler balks at a ? b : c for fmtstring
engrave.c: In function ‘engr_stats’
hack:c one compiler balks at a ? b : c for fmtstring
hacklib.c: one compiler balks at a ? b : c for fmtstring
insight.c: one compiler balks at a ? b : c for fmtstring
invent.c: In function ‘let_to_name’
light.c: In function ‘light_stats’
mhitm.c: In function ‘missmm’
options.c: In function ‘handler_symset’
options.c: In function ‘basic_menu_colors’
options.c: In function ‘optfn_o_autopickup_exceptions’
options.c: In function ‘optfn_o_menu_colors’
options.c: In function ‘optfn_o_message_types’
options.c: In function ‘optfn_o_status_cond’
options.c: In function ‘optfn_o_status_hilites’
options.c: In function ‘doset’
options.c: In function ‘doset_add_menu’
options.c: In function ‘show_menu_controls’
options.c: In function ‘handle_add_list_remove’
pager.c: In function ‘do_supplemental_info’
pager.c: In function ‘dohelp’
region.c: In function ‘region_stats’
rumors.c: sscanf usage
sounds.c: In function ‘domonnoise’
spell.c: In function ‘dospellmenu’
timeout.c: In function ‘timer_stats’
topten.c: In function ‘outentry’, fscanf, sscanf, fprintf usage
windows.c: In function ‘genl_status_update’
zap.c: one compiler balks at a ? b : c for fmtstring
win/curses/cursstat.c: In function ‘curses_status_update’
win/tty/wintty.c: In function ‘tty_status_update’
win/win32/mswproc.c: In function ‘mswin_status_update’
Gcc 9 has become more vocal with sprintf buffer overflow
checking. Remove these sprintf warnings by changing the
offending calls to a snprintf wrapper that will explicitly
check the result.
This replaces the arcane system previously used by getobj where the
caller would pass in a "string" whose characters were object class
numbers, with the first up to four characters being special constants
that effectively acted as flags and had to be in a certain order.
Because there are many places where getobj must behave more granularly
than just object class filtering, this was supplemented by over a
hundred lines enumerating all these special cases and "ugly checks", as
well as other ugly code spread around in getobj callers that formatted
the "string".
Now, getobj callers pass in a callback which will return one of five
possible values for any given object in the player's inventory. The
logic of determining the eligibility of a given object is handled in the
caller, which greatly simplifies the code and makes it clearer to read.
Particularly since there's no real need to cram everything into one if
statement.
This is related to pull request #77 by FIQ; it's largely a
reimplementation of its callbacks system, without doing a bigger than
necessary refactor of getobj or adding the ability to select a
floor/trap/dungeon feature with getobj. Differences in implementation
are mostly minor:
- using enum constants for returns instead of magic numbers
- 5 possible return values for callbacks instead of 3, due to trying to
make it behave exactly as it did previously. PR #77 would sometimes
outright exclude objects because it lacked semantics for invalid
objects that should be selectable anyway, or give slightly different
messages.
- passing a bitmask of flags to getobj rather than booleans (easier to
add more flags later - such as FIQ's "allow floor features" flag, if
that becomes desirable)
- renaming some of getobj's variables to clearer versions
- naming all callbacks consistently with "_ok"
- generally more comments explaining things
The callbacks use the same logic from getobj_obj_exclude,
getobj_obj_exclude_too and getobj_obj_acceptable_unlisted (and in a few
cases, from special cases still within getobj). In a number of them, I
added comments suggesting possible further refinements to what is and
isn't eligible (e.g. should a bullwhip really be presented as a
candidate for readying a thrown weapon?)
This also removed ALLOW_COUNT and ALLOW_NONE, relics of the old system,
and moved ALLOW_ALL's definition into detect.c which is the only place
it's used now (unrelated to getobj). The ALLOW_ALL functionality still
exists as the GETOBJ_PROMPT flag, because its main use is to force
getobj to prompt for input even if nothing is valid.
I did not refactor ggetobj() as part of this change.
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.
Monsters with rust attacks (rust monster) and corrosion attacks
(black pudding, gray ooze) can eat or otherwise destroy iron bars
but xorns could only move through the iron bars spot without being
able to eat the metal there. Change xorn to eat bars instead of
phazing through them. Lets rock moles eat bars too.
Hero polymorphed into a rust monster would eat bars if trying to
move to their location but couldn't do so if already there (maybe
was in xorn form and now in rust monster form). Xorns could pass
through them but not eat them. Allow hero metallivores to eat
bars at the current location via 'e', similar to eating food off
the floor. Hero as rock mole behaves like rust monster.
Eliminate the feasibility of micro-managing ring hunger by swapping
back and forth between a pair of rings of slow digestion. Wearing
one at a time causes normal ring hunger (wearing both at once just
increases such hunger), but being able to put on the second ring
and take off the first just before the 1 out of 20 turns where it
affects hunger, then vice versa a few turns later, is an insanely
tedious way to avoid any hunger at all, made possible by the 'time'
option. Make the turns where extra hunger get imposed be randomized
so that that can't be done reliably.
Also closes githib issue #336: hunger caused by melee attacking
adds ring and amulet hunger a second time for that turn. That has
always been intentional behavior; now the amount varies for any
given attack due to the randomization, but on average is the same
as before.
Closes#336
is nonsense, grammatically speaking. Change the variant wording of
"you resume your meal" to be "you consume the last bite of your meal".
The alternate wording is intended to handle the case where no "you're
finally finished" message occurs (#H8922) but I don't remember how to
reproduce that so got both "you consume last bite" and "you finish".
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).
We haven't added any new objects or monsters in a really long time.
This adds two new useful amulets, putting more pressure on the
decision over which type of amulet to wear.
amulet of flying: idea from slash'em, implemented from scratch.
Should be self-explanatory. Polymorphing into a form capable of
eating amulets and then eating one does not confer intrinsic
flight. (I've no idea how slash'em behaves is in that regard.)
amulet of guarding: adds +2 AC, which is fairly negligible, also
+2 MC, which is not. Initially called amulet of protection but MC
of 2 is referred to as 'guarded' by enlightenment so I changed it.
(By that reasoning, rings of protection ought to be called rings of
warding; oh, well.) Successfully eating one confers +2 AC without
any MC benefit. When wearing one of these, rings of protection
only confer AC, their +1 MC gets superseded rather than combined.
Monsters will wear an amulet of guarding and gain both the AC and
MC benefit, but if not cursed and they acquire one of life-saving or
reflection, they'll swap. They won't wear an amulet of flying.
I cloned two extra copies of the tile for one of the existing amulets
and ran sys/share/objects.txt through renumtiles.pl. The result
appears to be ok but on X11 the tiles map ends up looking psychedelic
so something beyond the tile art itself needs to be fixed here.
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.
Another SliceHack feature. It's possible for you to eat the chameleon
tin and turn into a fiery monster that burns off the slime in its
natural form, either extremely luckily at random or if you have
polymorph control.
Handling botl updates for 'time' was inconsistent. Set the flag to
do that when moves is incremented (where the update is suppressed if
running) or when running stops short.
losehp() would cancel running/traveling if called when in normal form
but not if called when polymorphed, so theoretically you could take
damage and keep on running. I don't have a test case to verify that.