Commit Graph

143 Commits

Author SHA1 Message Date
PatR
8a092aef0e timer code readability
Something else noticed while looking for something unrelated.  The
original code is correct but I think the revised code is a little
easier to take in when looking at it.
2022-05-25 12:30:48 -07:00
PatR
a230034af7 github issue #715 - losing stoning resistance \
while wielding a cockatrice corpse without gloves

Reported by vultur-cadens:  if safely wielding a cockatrice corpse
without gloves due to temporary stoning resistance or wearing yellow
dragon scales/mail, having the resistance be lost to timeout or to
taking off the dragon armor should have turned the hero to stone but
didn't.

Extend the handling for taking off gloves to cover these other two
cases too.  The feedback for these deaths is usually too verbose to
fit on the tombstone but does show up in logfile.

Fixes #715
2022-03-31 04:48:26 -07:00
PatR
071d79dce2 stoning resistance revisited
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.
2022-03-26 11:23:06 -07: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
48bca11d67 Accessibility: give message for created monsters
Always give a message when creating a detected monster
during gameplay (as opposed to during level creation).
To prevent the message, use the MM_NOMSG flag for makemon.

Most places already handled their own messaging, but there
were some, such as bag of tricks, create monster magic
and random monsters created during gameplay that didn't.
2022-01-06 14:06:49 +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
4eb0592959 sickness countdown
Give messages when sickness countdown has nearly expired to warn
player that hero is dying and also so that death at the end doesn't
seem so abrupt after an arbitrary period with just "TermIll" and/or
"FoodPois" on the status line.

Also, abuse constitution each turn when Sick (either variation, but
not a double amount if both).
2021-12-22 19:36:52 -08: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
0bc396282d additional urgent messages
Now I've remembered why I didn't follow through with these back when
I originally laid the groundwork.  New urgent messages:

 having an item of armor be destroyed
 having weapon be grabbed by a monster's bullwhip
 becoming engulfed
 being grabbed by an eel
 subsequently being drowned by an eel
 dying of petrification
 turning into slime then dying due to genocide
 dying due to fatal illness

There are lots more candidates.
2021-12-20 08:42:58 -08:00
PatR
e2ca016484 decaying globs of {ooze,pudding,slime}
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.
2021-11-06 18:24:36 -07:00
SHIRAKATA Kentaro
bfd79f5c9d use %lu for unsigned long
`curr->tid` is unsigned long, so use `%lu`.
2021-10-23 01:07:40 +09:00
nhmall
17165e3b92 melting ice timeout issues
Reported directly to devteam by entrez via email:
>
> I noticed some potential issues with (melting) ice:
>
>   * Digging down into ice, or setting a land mine on the ice and
>   triggering it, doesn't remove the melt_ice timeout, so it can result
>   in a sequence like dig down -> pit fills with water -> freeze water
>   -> freezing water tries to set melt_ice timeout -> duplicate timeout
>   impossible.  Or if you don't freeze the water again, melt_ice will
>   run on a non-ice surface, which might at least produce strange
>   messages.
>
>   * Setting a land mine on ice: melting ice doesn't do anything with
>   the trap, so there is still a land mine which you can trigger by
>   flying over the water (the land mine's trigger is also still
>   described as being 'in a pile of soil', despite being underwater at
>   this point).  Similar thing happens with bear traps.
>
>   * Not really related to _melting_ ice, but an exploding land mine
>   doesn't reset the typ from ICE to FLOOR (like normal digging does),
>   so it will result in a square with a pit that is also an ice square,
>   where the ice can melt under the pit and produce a combination
>   pit/moat.  If you then freeze the moat, the pit reappears on top of
>   the ice.
2021-10-16 22:22:33 -04:00
copperwater
f855fb5e45 Remove g.monstermoves
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.
2021-08-28 16:22:38 -07:00
Pasi Kallinen
20cbadcf85 Unlock your quest by killing your quest leader
Allow killing your quest leader, just to make games winnable if you
converted before doing the quest.
Boost the quest leaders and give them some equipment. King Arthur
gets Excalibur. Killing quest leader gives really bad luck and
makes your god angry at you, and killing quest guardians gives
smaller penalties.

This is based on both the EvilHack implementation by
k21971 <keith.simpson1971@gmail.com>, and xNetHack
implementation by copperwater <aosdict@gmail.com>.
2021-05-23 11:11:58 +03:00
nhmall
5b1d668c44 enable -Wformat-nonliteral for linux and equivalent for windows compilers
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’
2021-02-02 19:03:12 -05: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
7e87abb66f wizard mode buglet: simultaneous Lev+Fly timeout
Noticed while working on Qt status highlighting:  if levitation
and flying timed out at the same time, first Lev timeout called
float_down() which reported
 You have stopped levitating and are now flying.
and then Fly timeout left stale "Fly" on the status line due to
an optimization which got subverted.  ('was_flying' flag was
False due to Fly being blocked by Lev; that's correct behavior,
but the flag is effectively a cached value that becomes stale
when the Lev timeout code executes.)

The bug was wizard mode only because #wizintrinsic is the only
way to get timed flying.
2020-11-24 10:43:12 -08:00
Pasi Kallinen
22ca1ae4da Fix monster hiding under hatching egg staying hidden 2020-10-24 18:32:08 +03:00
Pasi Kallinen
aeb0ea65e3 Mild Zombie Apocalypse
When a zombie (or lich) kills a monster in melee without a weapon,
the monster can rise few turns later as a zombie.

The only creatures that can be zombified are ones that actually have
a zombie counterpart monster. A zombie cannot turn a jackal into
a zombie, for instance. But it could turn a shopkeeper into a human
zombie, or a dwarf king into a dwarf zombie.

Zombies will fight with monsters that can be turned into zombies.

Originally this was a SliceHack feature, but this is based on xNetHack
version of it, with some modifications.
2020-10-23 19:47:10 +03:00
PatR
3f81bd5af6 fix pull request #380 - turning into slime
The turn-to-slime countdown is one of the ones that uses turns/2
to stretch the sequence out longer and it was displaying the hero
as green slime when there was another turn before it happened.
(In theory anyway.  I could not get my hero to be shown as slime
and still have one move left, even when hasted.)

Make the hero mimic green slime starting on the last turn before
being polymorphed instead of next to last.

Fixes #380
2020-08-27 16:14:17 -07:00
nhmall
ac9ba38449 file header bump from "NetHack 3.6" to "NetHack 3.7" 2020-08-03 22:07:36 -04:00
PatR
22b4ed0be5 Lev vs Fly via #wizintrinsic
I noticed that Qt status showed both Lev and Fly at the same time
when they should be mutually exclusive (Levitation overrides Flying).
I wasted a bunch of time trying to track down a Qt problem but it
turned out to be a core issue.  If Flying is set first (which won't
happen if both are set in the same #wizinstrinsic operation), setting
Levitation via #wizintrinsic was attempting to update the flag that
indicates that Flying is blocked, but doing so too soon and failing.
Setting Lev via other means while Fly was already set didn't have
this problem so it wouldn't occur during normal play.

Also, #timeout lists timed properties which can have a timeout value
in normal play, then a separator, followed by properties that can
only become timed due to #wizintrinsic.  Move Displacement from the
second group to the first now that it can be obtained as a timed
value by eating a displacer beast corpse.
2020-08-01 06:11:20 -07:00
PatR
16562b2892 displacer beast as food
Make eating a displacer beast corpse or a tin of displacer beast
meat confer temporary Displacement lasting 6d6 turns.
2020-05-04 09:50:11 -07:00
PatR
09f9b3598f fix issue #339 - duplicate feature messages
while 'mention_decor' is enabled.  When stepping onto different
terrain and one or more objects remained on the new spot after
autopickup, describe_decor() was issuing its new-terrain message
right before look_here()'s similar under-the-objects message.  If
autopickup grabbed everything or there weren't any objects to begin
with, look_here() doesn't issue any dfeature (terrain) message.
describe_decor() isn't smart enought to know whether that is going
to happen.  Give look_here() a new flag argument so that its caller
can ask for the dfeature message to be skipped for the case where a
similar message has already been given.
2020-04-27 04:25:26 -07:00
PatR
2e177a7fc4 fix gibhub issue #320 and more - 'mention_decor'
Fixes #320

Avoid giving "you are back on the bottom" nearly every step when
moving around underwater.

Avoid "you are back on floor" followed by "you trip over <object>"
when fumbling in case that fumbling was due to being on ice when
taking the step to floor.  Done for all fumbling rather than just
one-turn fumbling instigated by ice.

When moving from ice or water to ground, show "you are back on floor"
before listing objects at that spot instead of after.

I think there was at least one more thing but have lost track.  At
any rate, 'mention_rate' potentially has a new set of bugs.
2020-04-08 18:33:55 -07:00
copperwater
63d3d7b688 You may survive food poisoning with a Con/100 chance
Another feature from SliceHack. Randomly averting an instadeath might
seem a little too generous, but the only time you get food poisoning is
if you're a new player who hasn't learned about tainted corpses yet or
if you just did something stupid. So, be a little nicer in those
scenarios.

If you survive, your Con silently decreases by 1. Hey, it's better than
dying.
2020-04-05 15:15:30 +03:00
PatR
ae27942cd6 haste timeout, vomit countdown feedback
Change a couple of messages.  When speed/haste-self times out:
"you feel yourself slowing down" -> "you feel yourself slow down"
because the former was too close to the turn-to-stone countdown and
the loss of speed is immediate rather than gradual.

The vomiting countdown causes confusion and stun; vary the messages
for those if already confused or stunned:
"you feel slightly confused" -> "you feel slightly more confused";
"you can't seem to think straight" -> "you can't think straight".
2020-02-28 13:30:59 -08:00
nhmall
1dfab5fe11 remove an argument that is no longer necessary from a few functions
Passing a boolean 'ghostly' argument to some functions that are also passed
an NHFILE * is unnecessary now.
2020-02-02 22:54:44 -05:00
nhmall
480c3eb6e0 include/lev.h is an empty header file so just get rid of it 2019-12-14 17:18:48 -05:00
nhmall
2592db64e3 Merge branch 'NetHack-3.7' 2019-12-13 17:41:03 -05:00
nhmall
f48ac58561 Merge branch 'NetHack-3.6' 2019-12-13 17:37:46 -05:00
PatR
8a57029503 spelling and typo fixes
Submitted for 3.7.0; all but one also apply to 3.6.3.

I rewrote the curses terminal-too-small message instead of just
fixing the spelling of "minumum".
2019-12-11 12:35:45 -08:00
nhmall
bc8c1f8f56 remove field-level savefile code 2019-12-08 07:27:01 -05:00
nhmall
a701c5870d quiet a number of macosx warnings 2019-12-05 11:52:21 -05: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
899311efde merge correction bit 2019-08-14 08:21:21 -04:00
nhmall
c425c37097 Merge branch 'NetHack-3.6' 2019-08-13 16:32:53 -04:00
PatR
c814ca8e04 fix #H9117 - bookeeping for fatal status condition
When Stoned, Slimed, Strangled, Sick (TermIll or FoodPois or both)
counts down to 0 without being cured, keep it listed as an active
condition while killing off the hero.  It will show in the status
section when disclosing final attributes and in both that section
and map's status lines when producing a dumplog.
2019-08-11 18:56:43 -07:00
nhmall
dbc2e69110 Merge branch 'NetHack-3.6' 2019-08-02 22:50:13 -04:00
PatR
ed18ebc545 timer validations
Add the contributed code that checks for attempting to start a
duplicate timer.  It's based on a comment which must have been there
at least 25 years and doesn't solve any known problems, but it is
conceptually similar to the large amount of sanity checking which has
gone into 3.6.x.

It didn't work as is because it was comparing two unions with '=='.
I don't know offhand whether C++ supports that but C doesn't (through
C11 at least; don't know about C17).  The union ('anything') is simple
enough that two instances can be compared without jumping through hoops.

I've also added another check for timer 'kind' (level, object, monster,
or global).
2019-07-27 16:12:24 -07:00
nhmall
0d34f43830 remove STATIC_DCL, STATIC_OVL, STATIC_VAR, STATIC_PTR from core 2019-07-14 17:24:58 -04:00
nhmall
7054e06e42 NetHack minor release checklist items - savefiles
Make some progress on a couple of next minor release checklist
items, hopefully without introducing too many new bugs. This
is just the initial commit, and work continues.

Checklist items:

Savefiles compatible between Windows versions, whether 64-bit
or 32-bit in little-endian field format.

Selection of file formats:
 historical (structlevel saves),
 lendian (little-endian, fieldlevel saves),
 and just for proof-of-concept, ascii fieldlevel saves
 (the ascii is huge! 10x bigger than little-endian).

For the fieldlevel save, all complex data structures recursively
get broken down until until it is one of the simple types that
can't be broken down any further, and that gets when it gets
written to the output file.

New files needed for this build:

hand-coded:
include/sfprocs.h
src/sfbase.c      - really a dispatcher to one of the
                    output/input format routines.
src/sflendian.c   - little-endian output writer/reader.
src/sfascii.c     - ascii text output writer/reader.

auto-coded (generated):
include/sfproto.h
src/sfdata.c

This is just one approach. I'm sure there are countless others
and they have different pros and cons.

For producing the auto-coded files a utility called
universal-ctags, that is actively maintained and evolving,
was used to do all the heavy-lifting of parsing the
NetHack C sources to tabulate the data fields, and store
them in an intermediate file called util/nethack.tags
(not required for building NetHack if you already have a
generated include/sfproto.h and src/sfdata.c)

util/readtags (also not required for building NetHack
itself) will decipher the nethack.tags file and produce
the functions that can deal with the NetHack struct data
fields.

You can obtain the source for universal-ctags by cloning it
from here:
https://github.com/universal-ctags/ctags.git

The combination universal-ctags + util/readtags has been
tried and tested under both Windows and Linux, so it is
not tied to a particular platform.

Note: util/readtags will work only with universal-ctags
output, so other ctags are unlikely to work as-is.
Universal-ctags can be build from source very easily
under Linux, or under Windows using visual studio.
2019-06-23 00:11:46 -04: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
58f2218c4e Merge branch 'NetHack-3.6.2' 2019-01-09 07:24:18 -05:00
Bart House
0763046c38 zeroX, tc_gbl_data and fqn_prefix moved to instance globals. 2018-12-25 08:09:37 -08:00
Bart House
1c65e6afe0 context to g.context 2018-12-25 07:29:38 -08:00
Bart House
8c1a4d9a97 invent, youmonst, hackdir moved to g. 2018-12-24 21:04:15 -08:00