Commit Graph

184 Commits

Author SHA1 Message Date
nhmall
be76727265 granular verbose message suppression mechanics
Switch to using a macro invocation Verbos(n, s) in place of the
flags.verbose checks.

Provide the mechanics for individual suppression of any of the
existing messages that were considered verbose.

Mechanics only - this code update does not provide any means of
setting the suppression bits.

iflags.verbose = 0
is still a master suppression of all the verbose messages.

iflags.verbose = 1
turns on the verbose messages only for those whose suppression
bit is 0 (not set).
2022-06-09 13:53:20 -04:00
Michael Meyer
4d82094e8b Handle spiders, cockatrices in mbodypart
Spiders and cockatrices were using the default animal_parts, which was
noticeably inaccurate in describing certain parts of their bodies.  Add
specific handling for both types of monsters: for spiders, add a
spider-specific body part list (the best I could figure out from online
sources, not being a spider anatomy expert), and for cockatrices, use
bird_parts with "scales" from snake_parts thrown in to emphasize their
unusual nature.
2022-03-22 14:30:21 -07:00
PatR
b150594d68 hide-under webmakers...
Offer the chance to explicitly hide via #monster when poly'd into a
hides-under creature.  hides_under() doesn't pass the is_hider() test
so wasn't being allowed before.

If poly'd hero's monster form is both a webmaker and can hide-under,
have #monster prompt the player for which is intended.  When poly'd
hero successfully spins a web, say so.

If poly'd hero deliberately tries to hide under a cockatrice corpse,
turn to stone.
2022-03-21 18:21:07 -07:00
Pasi Kallinen
39acd095b2 Add helpless monster macro 2022-03-18 10:19:04 +02:00
PatR
ab2bcf4dac trap followup
Make the flags argument to dotrap() and mintrap() and the constants
passed to them all have consistent type: unsigned int.
2022-02-24 12:17:21 -08:00
PatR
96ba3c04d1 logging experience level changes again
The livelog message for losing a level had an off-by-1 error, showing
the level the hero ended up at rather than the level that was lost.

There was a message for regaining a previously lost level when rank
title stayed the same but no such message if the title changed (the
achievement of gaining a particular title only occurs once).

Say "regained" rather than "gained" when gaining a previously lost
level.  (Blessed potions of full healing regain levels but can also
reduce u.ulevelmax so a different way to remember peak experience
level has been added.)

Report level change due to polymorphing into new man/woman/elf/&c.
I hadn't realized that that hasn't been recording achievement for new
rank when applicable and decided to leave things that way.

Report gender change when putting on an amulet of change or becoming
a new man/&c unless hero is polymorphed at the time or experience
level is also changing.
2022-02-10 05:45:07 -08:00
Pasi Kallinen
1e90f89203 Chronicle of major events, and livelog
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.
2022-02-09 22:49:25 +02:00
Michael Meyer
f5e3bc3d96 Remove gendered mons indices from roles, races
There are no longer distinct gendered versions of monsters, so femalenum
is unused (i.e. set to NON_PM) for all roles and races. Take a pass at
removing all uses of/references to femalenum, and rename 'malenum' to
'mnum' since it no longer has any particular association with
gender or sex.
2022-01-14 13:51:26 -08:00
nhmall
e4e65c4b8b whitelist several non-literal format strings
djgpp cross-compiler was griping about several.

This also removes these lines from sys/unix/hints/include/compiler.370.
    CFLAGS+=-Wno-format-nonliteral
    CCXXFLAGS+=-Wno-format-nonliteral

-Wformat-nonliteral should not be incompatible with the printf
argument-checking capabilities on literal format strings and there
shouldn't be any new warnings created.

-- &< --

artifact.c: In function 'artifact_hit':
artifact.c:1309:23: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1309 |                       mon_nam(mdef));
      |                       ^~~~~~~
artifact.c:1328:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1328 |                 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "you");
      |                 ^~~~~

ball.c: In function 'drop_ball':
ball.c:896:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  896 |                 pline(pullmsg, "pit");
      |                 ^~~~~
ball.c:899:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  899 |                 pline(pullmsg, "web");
      |                 ^~~~~
ball.c:904:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  904 |                 pline(pullmsg, hliquid("lava"));
      |                 ^~~~~
ball.c:908:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  908 |                 pline(pullmsg, "bear trap");
      |                 ^~~~~

dig.c: In function 'liquid_flow':
dig.c:747:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  747 |         pline(fillmsg, hliquid(typ == LAVAPOOL ? "lava" : "water"));
      |         ^~~~~

fountain.c: In function 'floating_above':
fountain.c:28:5: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
   28 |     You(umsg, what);
      |     ^~~

invent.c: In function 'hold_another_object':
invent.c:1018:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1018 |                 pline(drop_fmt, drop_arg);
      |                 ^~~~~
invent.c:1073:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1073 |         pline(drop_fmt, drop_arg);
      |         ^~~~~
invent.c: In function 'silly_thing':
invent.c:1811:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1811 |         pline(silly_thing_to, word);
      |         ^~~~~

lock.c: In function 'pick_lock':
lock.c:375:19: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  375 |             pline(no_longer, "hold the", what);
      |                   ^~~~~~~~~
lock.c:379:19: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  379 |             pline(no_longer, "reach the", "lock");
      |                   ^~~~~~~~~
lock.c: In function 'pick_lock':
lock.c:375:19: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  375 |             pline(no_longer, "hold the", what);
      |                   ^~~~~~~~~
lock.c:379:19: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  379 |             pline(no_longer, "reach the", "lock");
      |                   ^~~~~~~~~
mcastu.c: In function 'cast_cleric_spell':
mcastu.c:670:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  670 |             pline(fmt, Monnam(mtmp), what);
      |             ^~~~~

mhitu.c: In function 'hitmsg':
mhitu.c:68:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
   68 |             pline(pfmt, Monst_name);
      |             ^~~~~

mkobj.c: In function 'insane_object':
mkobj.c:2848:20: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2848 |         impossible(altfmt, mesg, fmt_ptr((genericptr_t) obj), where_name(obj),
      |                    ^~~~~~
mkobj.c:2852:20: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2852 |                    objnm);
      |                    ^~~~~

mon.c: In function 'mon_givit':
mon.c:1469:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1469 |         pline(msg, Monnam(mtmp));
      |         ^~~~~
mon.c: In function 'mondead':
mon.c:2485:33: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2485 |                                 | SUPPRESS_INVISIBLE), FALSE));
      |                                 ^

muse.c: In function 'mon_reflects':
muse.c:2438:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2438 |             pline(str, s_suffix(mon_nam(mon)), "shield");
      |             ^~~~~
muse.c:2445:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2445 |             pline(str, s_suffix(mon_nam(mon)), "weapon");
      |             ^~~~~
muse.c:2450:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2450 |             pline(str, s_suffix(mon_nam(mon)), "amulet");
      |             ^~~~~
muse.c:2458:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2458 |             pline(str, s_suffix(mon_nam(mon)), "armor");
      |             ^~~~~
muse.c:2464:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2464 |             pline(str, s_suffix(mon_nam(mon)), "scales");
      |             ^~~~~
muse.c: In function 'ureflects':
muse.c:2476:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2476 |             pline(fmt, str, "shield");
      |             ^~~~~
muse.c:2483:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2483 |             pline(fmt, str, "weapon");
      |             ^~~~~
muse.c:2487:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2487 |             pline(fmt, str, "medallion");
      |             ^~~~~
muse.c:2493:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2493 |             pline(fmt, str, uskin ? "luster" : "armor");
      |             ^~~~~
muse.c:2497:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2497 |             pline(fmt, str, "scales");
      |             ^~~~~

polyself.c: In function 'polyman':
polyself.c:201:5: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  201 |     urgent_pline(fmt, arg);
      |     ^~~~~~~~~~~~

potion.c: In function 'make_hallucinated':
potion.c:423:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  423 |             pline(message, verb);
      |             ^~~~~
potion.c: In function 'peffect_gain_level':
potion.c:1033:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1033 |                 You(riseup, ceiling(u.ux, u.uy));
      |                 ^~~
potion.c:1044:21: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1044 |                     You(riseup, ceiling(u.ux, u.uy));
      |                     ^~~

priest.c: In function 'intemple':
priest.c:487:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  487 |                 You(msg1, msg2);
      |                 ^~~

read.c: In function 'doread':
read.c:522:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  522 |         pline(silly_thing_to, "read");
      |         ^~~~~

shk.c: In function 'shk_names_obj':
shk.c:2576:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2576 |         pline(fmtbuf, obj_name, (obj->quan > 1L) ? "them" : "it", amt,
      |               ^~~~~~
shk.c:2579:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2579 |         You(fmt, obj_name, amt, plur(amt), arg);
      |         ^~~
shk.c: In function 'shk_chat':
shk.c:4506:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 4506 |             pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))], shkname(shkp));
      |             ^~~~~
shk.c: In function 'check_unpaid_usage':
shk.c:4633:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 4633 |         verbalize(fmt, arg1, arg2, tmp, currency(tmp));
      |         ^~~~~~~~~

sounds.c: In function 'dosounds':
sounds.c:66:21: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
   66 |                     pline(throne_msg[2], uhis());
      |                     ^~~~~
sounds.c:259:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  259 |                 You_hear(msg, halu_gname(EPRI(mtmp)->shralign));
      |                 ^~~~~~~~

timeout.c: In function 'choke_dialogue':
timeout.c:269:26: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  269 |                          body_part(NECK));
      |                          ^~~~~~~~~
timeout.c:274:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  274 |                 urgent_pline(str, hcolor(NH_BLUE));
      |                 ^~~~~~~~~~~~
timeout.c: In function 'levitation_dialogue':
timeout.c:339:26: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  339 |                          danger ? surface(u.ux, u.uy) : "air");
      |                          ^~~~~~
timeout.c: In function 'slime_dialogue':
timeout.c:379:34: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  379 |                     urgent_pline(buf, hcolor(NH_GREEN));
      |                                  ^~~
timeout.c:381:30: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  381 |                 urgent_pline(buf, an(Hallucination ? rndmonnam(NULL)
      |                              ^~~

uhitm.c: In function 'hmon_hitmon':
uhitm.c:1398:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1398 |         pline(fmt, whom);
      |         ^~~~~
uhitm.c:1421:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1421 |         pline(fmt, whom);
      |         ^~~~~
uhitm.c: In function 'stumble_onto_mimic':
uhitm.c:5301:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 5301 |         pline(fmt, what);
      |         ^~~~~

../win/tty/wintty.c: In function 'tty_clear_nhwindow':
../win/tty/wintty.c:1649:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1649 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_display_nhwindow':
../win/tty/wintty.c:2339:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2339 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_dismiss_nhwindow':
../win/tty/wintty.c:2432:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2432 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_destroy_nhwindow':
../win/tty/wintty.c:2477:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2477 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_curs':
../win/tty/wintty.c:2503:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2503 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_putsym':
../win/tty/wintty.c:2599:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2599 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_add_menu':
../win/tty/wintty.c:2967:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2967 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_end_menu':
../win/tty/wintty.c:3032:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 3032 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_select_menu':
../win/tty/wintty.c:3140:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 3140 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
2022-01-09 14:18:10 -05:00
Pasi Kallinen
68b822e4dc Add "user canceled" as extended command return value
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.
2022-01-08 20:04:57 +02:00
Pasi Kallinen
d53cd28d46 Make extended commands return defined flags
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.
2021-12-30 19:16:33 +02:00
PatR
75fe21d00f more urgent_pline()'s
countdown messages for turning to stone or slime or being strangled
drowning
burning in lava
feeling feverish
changing form
2021-12-22 18:29:01 -08:00
PatR
495cda17b7 some reformatting
Replace some
  (foo &&
   bar)
that had crept back into the code with
  (foo
   && bar)
to match the reformatting which took place before 3.6.0.  There are a
couple of lines ending in '||' still present but they look intentional.
isaac64.c has some trailing '|' bit operators that could/should be
moved to the start of the next line but I didn't touch that file.

While in the affected files, I tried to shorten most overly wide lines
(the right margin is supposed to at column 78 and there are quite a
few lines which are 79 characters long, but I left most of those
rather than introduce new line splits).  Also replace a handful of
tabs with spaces.  I was a little surprised not find any trailing
spaces (in the dozen or so files being updated).  I didn't look for
trailing arithmetic or '?'/':' operators which aught to be moved to
the start of the next line.
2021-12-14 07:43:40 -08:00
PatR
a80969f280 wizard mode polyself to "priest"
When polymorphing while already polymorphed, picking your own role
will rehumanize (wizard mode only; restores old characteristics and
experience level, unlike becoming a new man which can change those
and even be fatal if level drops below 1).  But it didn't work if
you were a priest or priestess because name_to_mon() yields aligned
cleric monster rather than cleric role.
2021-12-08 16:08:57 -08:00
PatR
5ce53f4d17 shape change while strangling
Polymorphing into a vulnerable form while wearing an amulet of
strangulation says "your amulet still constricts your neck" if your
previous form was also vulnerable or "your amulet beings constricting
your neck" if previous form wasn't vulnerable.  But a change nearly
6 years ago to have the status line be updated to say "Strangling"
during the message--instead of next status update after it--caused
the "still constricts" variation to always be given even when the
"begins constricting" was appropriate.
2021-12-08 15:31:06 -08:00
PatR
f0f9701a37 attempting to polymorph into a unique monster
Noticed while testing revised "the" handling and trying to trigger
"you can't polymorph into [the] Oracle", if the character was human
it would turn into a new man or woman instead of having the unique
form be rejected.
2021-11-24 00:46:44 -08:00
PatR
fdf0bfd8a4 wizard mode light source bug
In wizard mode if you're already polymorphed and you choose your
role's form when polymorphing again, polyself() calls rehumanize()
to restore your original shape.  rehumanize() turns off any light
the hero is emitting from polymorph form.  After it returned,
polyself() then tried to do the same thing based on a cached value.
If the previous form had been emitting light, that resulted in an
impossible() warning "del_light_source: not found type=1, id=N".

Couldn't happen in normal play because a request to polymorph into
any role monster is usually rejected; it's only honored in wizard
mode for current role.  Noticed when testing something while in
gold dragon form but this bug predates addition of that monster.

Clear the cached value when rehumanize() returns to polyself().
2021-08-04 13:26:56 -07:00
PatR
5a09a01a13 gold dragon and scales
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.
2021-07-23 10:41:57 -07:00
PatR
91248a2b7e fix pull request #548 - encumbrance feedback
when polymorphing into "new man".  Characteristic stats are shuffled
if turning into new man, but when already polymorphed those get
overridden by the old pre-polymorph characteristics, resulting in
another encumbrance check which might contradict the one that just
happened.  Skip the encumbrance check done when shuffling stats so
that there's only one and it comes after all changes are finished.

Fixes #548
2021-07-14 18:29:03 -07:00
Pasi Kallinen
075844b4d6 Adjust shopkeeper damage fixing
Allow shopkeeper to remove webs and pits.

Change the damage fix messaging to be more specific when
shopkeeper removes a trap. Before this the message was
"A trap was removed from the floor", which sounds really silly
when it comes to holes.

Change the damage fixing so the shopkeeper will fix one damage spot
at a time (instead of all at once), so it's more like a monster action.

Some code cleanup, splitting into smaller functions.

While doing this, I noticed that shopkeepers don't actually bill
the hero for the damage, but that'll have to be another commit...
2021-06-25 20:02:06 +03:00
PatR
a646764cc7 fix github issue #462 - line not displayed
Fix a latent bug in unreachable code.  As the comment preceding
the cited code states, hero polymorphed into an eel isn't offered
a chance to use #monster to hide, so program execution won't ever
get to the bad code.  Using formatting routine The() where message
delivery routine pline_The() is intended is certainly a bug though.

Fixes #462
2021-02-17 14:27:00 -08:00
nhmall
f963c5aca7 switch source tree from k&r to c99 2021-01-26 21:06:16 -05:00
nhmall
0c3b9642e4 pmnames mons gender naming plus a window port interface 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.
2020-12-26 11:23:23 -05:00
PatR
d48e730700 ki-rin body parts
Use horse/unicorn body parts.  The result for HAIR is "mane"
which is appropriate.  There's no field for SKIN so the question
of whether to specify "scales" is moot.  (Snakes and dragons
describe HAIR as "scales" but that wouldn't be right for ki-rin.)
2020-11-21 03:46:53 -08:00
Pasi Kallinen
6a35a84c56 Fire sources can ignite candles, lamps, and potions of oil
... on the floor, in monster inventory, and in hero's inventory.

Items in your inventory being ignited produce a message even if you're
blind - you can see the lit-state by viewing inventory anyway, so just
give player the message.

(via xNetHack)
2020-09-30 19:49:10 +03:00
nhmall
ac9ba38449 file header bump from "NetHack 3.6" to "NetHack 3.7" 2020-08-03 22:07:36 -04:00
PatR
a37975b625 fix pull request #367 - mind flayer psychic blast
hitting a hidden monster didn't reveal that monster.  It stayed
hidden despite the feedback describing it as if it could be seen.

The pull request's two line fix handled a monster's blast hitting
another monster but left two related issues as-is:  monster's blast
hitting hidden poly'd hero left hero unrevealed and poly'd hero's
blast left hidden monster unrevealed.  Same code, different bug:
poly'd hero's blast affected mindless monsters.

This unhides an affected target before the message about it being
hit rather than after.  That would look better if preceded by a
message describing the object (mimic or hides-under) or furniture
(mimic) or empty spot (ceiling hider) as being or concealing a
monster but I didn't put in sufficient effort to accomplish that.

Fixes #367
Fixes #362
2020-07-14 04:55:53 -07:00
Pasi Kallinen
cf1c725148 Purple worm changes
Shriekers only spawn purple worms when they're appropriate difficulty.
Non-tame Purple worms eat corpses off the ground.
Baby purple worms attack shriekers.
Hero polyed into baby purple worm is warned against shriekers.

Original changes by copperwater <aosdict@gmail.com>, added with some
formatting adjustments and consolidation.
2020-04-05 12:44:25 +03:00
PatR
99035e72ee throw-and-return vs !fixinv
Implement the request that a wielded+thrown aklys be given the same
inventory letter when it returns and is caught and rewielded, even for
the !fixinv setting where inventory letters don't stick.  Works for
Valkyrie-thrown Mjollnir and returning (ie, didn't hit) boomerangs as
well as for aklys.

I'm not sure how useful this really is, because on the rare occasions
that it either doesn't return or fails to be caught, it won't be given
the same letter when subsequently picked up.  So the player who relies
on it will still be vulnerable to using the wrong letter next time a
throw is attempted.  But at least picking it up explicitly displays
the new inventory letter, unlike catching it upon return.
2020-03-01 06:46:37 -08:00
PatR
cbdda9dc9d adopt github pull request #286 - rndmonst()
Eliminate the cache that was supporting rndmonst() and pick a random
monster in a single pass through mons[] via "weighted reservoir
sampling", a term I'm not familiar with.

It had a couple of bugs:  if the first monster examined happened to
be given a weighting of 0, rn2() would divide by 0.  I didn't try
to figure out how to trigger that.  But the second one was easy to
trigger:  if all eligible monsters were extinct or genocided, it
would issue a warning even though the situation isn't impossible.

Aside from fixing those, the rest is mostly as-is.  I included a bit
of formatting in decl.c, moved some declarations to not require C99,
and changed a couple of macros to not hide and duplicate a call to
level_difficulty().

Fixes #286
2020-02-22 17:40:55 -08:00
PatR
3981e3e6e5 controlling u.ustuck
Setting or clearing u.ustuck now requires that context.botl be set,
so make a new routine to take care of both instead of manipulating
that pointer directly.
2020-02-16 13:04:12 -08:00
PatR
424750867a wizard mode un-polymorph
When already polymorphed, polymorphing into 'human' (or character's
species) to revert to normal when at low level has the infuriating
tendency to yield "your new form isn't healthy enough to survive".
Allow specifying your own role as a way to rehumanize() instead of
going through newman() and level/sex/characteristics randomization
which that performs.
2020-01-21 18:29:23 -08:00
PatR
a13d6c03c9 no more headless eyewear
Noticed while working on something else:  hero kept wearing a towel
after polymorphing into a form without any head.  And when not already
wearing one, could put on a blindfold/towel/lenses while in a headless
form.
2020-01-21 15:36:33 -08:00
nhmall
afec87a766 Merge branch 'NetHack-3.6' 2019-11-09 12:24:10 -05:00
PatR
0615387f95 fix #H9391 - slippery gloves
Slippery fingers would transfer from bare hands to gloved hands if
you put gloves on.  The reverse, transfering from gloves to bare
hands when taking gloves off, was already being prevented for
directly taking them off, but still allowed the slipperiness to
transfer when gloves were lost.  This prevents putting on gloves
when fingers are slippery and attempts to handle cases where gloves
get unworn by ways other than 'T' (or 'R') or 'A'.

There's no slippery attribute for objects (way too much work for too
little value); slippery gloves is just the combination of wearing
gloves and having slippery fingers (which now has to have happened
while already wearing those gloves).  This changes inventory to use
"(being worn; slippery)" when applicable and much of the patch deals
with funnelling Glib changes through new make_glib() to try to make
sure that persistent inventory adds or removes "; slippery" right
away when changes happen.

If gloves are taken off involuntarily (shapechange to a form that
can't wear them, destruction via scroll of destroy armor or monster
spell of same or via overenchantment, theft), slippery fingers ends
right away instead of the usual few turns later.
2019-11-09 01:07:09 -08:00
nhmall
2f49d34019 Merge branch 'NetHack-3.6' 2019-10-04 22:31:35 -04:00
PatR
f3bc5e5c78 fix #H9272 - "object lost" panic
when polymorph causes loss of levitation boots or water walking boots
while over water.  If discarding stuff while trying to crawl out got
rid of the taken-off boots, they wouldn't be in inventory any more
when break_armor() tried to drop them after taking them off.
2019-10-04 16:12:08 -07:00
nhmall
0d34f43830 remove STATIC_DCL, STATIC_OVL, STATIC_VAR, STATIC_PTR from core 2019-07-14 17:24:58 -04:00
PatR
a27ca52b03 vampshifting by poly'd hero
Hero polymorphed into a vampire or v.lord can use #monster to switch
to vampire bat or fog cloud [or wolf for lord] but it was a one shot
polymorph.  Remember when current form is a shape-shifted vampire and
allow #monster in shifted form to pick another shifted form or the
vampire form.

Genocide of the alternate shape forces back to base vampire.  Genocide
of base vampire does too, then reverts to human (or dwarf, &c) as
vampires go away.  Being killed while shafe-shifted reverts all the
way to human rather than to vampire.  [Just realized:  interaction
with Unchanging wasn't taken into consideration so hasn't been tested.]

Since 'youmonst' isn't saved and restored, I had to add a field to 'u'
to hold youmonst.cham during save/restore.

Tested with 3.6.2+ and seemed to be working (except saving while
shape-shifted restored as ordinary bat/cloud/wolf because new u.mcham
wasn't there to hold youmonst.cham yet).  Builds with 3.7.0- but not
execution tested yet (I didn't want to clobber my current playground).
2019-06-06 16:51:43 -07:00
nhmall
bfc4445537 Merge branch 'NetHack-3.6' 2019-06-05 08:08:32 -04:00
PatR
ac79fedf60 fix github issue #196 - green slime feedback
Fixes #196

If you didn't die from turning into green slime but then died because
green slimes had been genocided, the message given assumed that you
had just seen "OK, you don't die" from answering No to "Really die?".
Its wording didn't make sense if the reason you didn't die was an
amulet of life-saving.  Give a different message for that case.

Also, if you survive turning into slime (via either method) and either
green slimes are still around or you answer No to "Really die?" when
they've been genocided, give a message after "You survived that attempt
on your life" pointing out that you have done so in green slime form.
Useful since prior to 3.6.2 you would have reverted to original form--
despite the Slimed countdown saying you had turned into green slime.
2019-06-04 09:16:00 -07:00
nhmall
5ddd6d7005 Merge branch 'NetHack-3.6.2' 2019-04-29 07:50:25 -04:00
PatR
c4ae9115cb fix github issue #187 - 'reassess' panic with Qt5
Fixes #187

Qt5 gave "status 'reassess' before init" panic at start of new game.
Don't call status_initialize(REASSESS) from set_usamon()--used for
hero setup as well as for hero polymorph--unless it was previously
called from display_gamewindows() with !REASSESS [which happens when
windowprocs.wincap2 has WC2_STATUS_HILITES or WC2_FLUSH_STATUS set].
2019-04-28 17:32:16 -07:00
nhmall
6d93eb7cdd Merge branch 'NetHack-3.6.2' 2019-04-26 19:52:16 -04:00
PatR
75db8e004d fix #H8612 - splashes of venom might stay intact
If a poly'd hero spits venom and it lands at a 'soft' spot such as
water, it would remain as an intact venom object.  (Venom spat by
monsters seems to always be used up regardless of where it lands.)
2019-04-25 07:11:42 -07:00
nhmall
20ca1ab0e4 Merge branch 'NetHack-3.6.2' part 2 2019-04-22 14:42:49 -04:00
nhmall
d15496ba31 Merge branch 'NetHack-3.6.2' 2019-04-22 14:36:58 -04: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
nhmall
4f679352b7 Merge branch 'NetHack-3.6.2' 2019-02-27 08:20:38 -05:00
nhmall
be3092bed4 some fish should lay their eggs in the water rather than on land
Generally, fish should lay their eggs in the water and
not on land, but the game was only allowing the opposite.

Eels are catadromous and lay their eggs in the Sargasso Sea,
not in the dungeon.
2019-02-26 19:49:24 -05:00