Commit Graph

8795 Commits

Author SHA1 Message Date
nhmall
0440eb5091 missing punctuation 2023-06-14 08:36:28 -04:00
PatR
fb0509a6b3 fix #3841 - steed and engulfer on same map spot
Reported five months ago, a save was performed while a mounted hero
was engulfed.  Restore issued a warning about the engulfer being
placed on top of the steed (who shouldn't have been on the map).

The report arrived at about the same time as engulfing a riding
hero was changed to force a dismount instead of engulfing both hero
and steed so nothing further was done about it.  This changes
restore to not put a steed on the map and then take it off again.
It also attempts to simplify usteed and ustuck handling during save
and restore.

Testing so far indicates that things are still working correctly.
Keep makeplural(body_part(FINGER)) crossed.

Existing save and bones files are invalidated.
2023-06-14 00:04:21 -07:00
PatR
bf47cc878e fountain and sink bookkeeping
This replaces most of commit 0ca2af4d8b
from a couple of days ago with something more robust.  That change
actually introduced redundant code that caused fountain and/or sink
count to be off instead of preventing it.

Revise set_levltyp() to update level.flags.nfountains and
level.flags.nsinks if setting the type to or from fountain or sink.
A bunch of places that were setting levl[x][y].typ directly needed
to be revised to use set_levltyp() instead.  set_levltyp() itself
hadn't been updated to handle LAVAWALL (to force such to be lit).
2023-06-12 15:07:34 -07:00
PatR
0ca2af4d8b wizwish fountain and sink bookkeeping
Noticed while considering the pull request about loosening
restrictions on trap creation at furniture locations.  If you wish
for a terrain feature while on a fountain or sink, the counters
used to control whether sounds for those should be given will be
off by one.

It was incrementing the appropriate counter if you wished for a
fountain or sink, but it shouldn't do that if recreating the same
feature (perhaps to reset a magic fountain or looted sink) and it
needed to decrement when replacing either of those with some other
feature.  After the count became wrong, if all fountains or sinks
on the level were destroyed, those splashing, gurgling, &c sounds
would continue to be generated periodically.
2023-06-10 01:46:35 -07:00
PatR
9079250cfc testing for Vlad
Redo the check for whether a monster is Vlad when deciding whether to
keep it out of a bones file.  Use the new check in find_defensive()
where Vlad won't waste a turn attempting to use a wand of digging when
in his undiggable own tower.  (Failing to check for vampshifted Vlad
in the latter case wasn't actually a bug because if/when shifted,
he's unable to use items so couldn't attempt to use wand of digging.
Switch to the new check anyway.)
2023-06-09 16:09:26 -07:00
PatR
e475dca209 add 'montelecontrol' option (wizard-mode only)
Add a new debugging option, 'montelecontrol', that allows a wizard-
mode player to choose a teleporting monster's destination.  If player
picks a bad spot, confirmation will be requested.  If accepted, the
spot will be used even though the consequences could be bad; that's
on the player.  If rejected, the destination will be assigned as if
no control had been attempted rather than try again.

The fuzzer isn't allowed to override a bad spot if it tries to pick
one.  That would probably trigger a sanity_check warning; the fuzzer
causes impossible warnings to behave as if panic, so accepting a bad
spot would just be fuzzer suicide.  It is allowed to randomly set the
option and maybe--though extremely unlikely--randomly pick a valid
controlled destination.
2023-06-09 00:56:53 -07:00
PatR
62eacb11c4 bhit()'s use of bhitpos
bhit() updates the value of bhitpos as a zap or missile progresses
and it also maintains a copy in local x,y.  But it was using the
latter inconsistently and also used x,y to fetch drawbridge location,
which might retain the same value or might change one of the two
values by +1 or -1.  Use different local variables for drawbridege
handling and use x,y instead of bhitpos throughout bhit().

Also, zapping the spot in front of a closed bridge with striking or
force bolt would destroy the bridge even though the zap was just
passing over moat.  Don't destroy the bridge in that situation.
Zapping striking/force bolt across the span of an open bridege still
destroys the bridge.
2023-06-07 15:58:47 -07:00
nhmall
4034ec915c curses_putmixed() initial attempt
The curses interface was using genl_putmixed() which doesn't
preserve the symbol actually used for a glyph on the display.
This is a first-attempt at implementing curses_putmixed().

On Linux you'll need to distribute the Makefiles again
    sh sys/unix/setup.sh sys/unix/hints/linux.370

On macOS, you'll need to distribute the Makefiles again
    sh sys/unix/setup.sh sys/unix/hints/macOS.370
2023-06-06 17:50:08 -04:00
PatR
7e4be52a6c fix issue #1046 - unseen monster reading scroll
Reported by copperwater "on behalf of Maud":  when hero hears an
unseen monster read a not-yet-discovered scroll of create monster
and doesn't see any new monster appear, the player is given a chance
to call the scroll something.  When hearing an unseen monster read
a not-yet-discovered scroll of teleportation, the label is revealed
but no such 'call it' opportunity is offered, so the player could
deduce which of the two scroll types it was for either case.

Provide an opportunity to supply a 'called' name for scrolls of
teleportation when heard being read, same as with create monster.
Surprisingly complicated to achieve.

Eliminated a couple of goto's in the process.

Fixes #1046
2023-06-04 16:22:38 -07:00
PatR
ee27ec97d1 tutorial tweaks
Replace tests against tutorial_dnum with 'In_tutorial()' predicate.

Give a message when entering the tutorial (via level change mechanism).

Likewise, give a message when resuming regular play.

If player uses #quit or ^C in the tutorial, ask whether to cut the
tutorial short and resume regular play; skip "Really quit?" if the
answer is yes.  Behavior is a bit odd for ^C + yes; it just sits there
until player types something.
2023-06-04 00:22:14 -07:00
PatR
2bbfed2183 fix github issue #1046 - tutorial anomalies
Reported by Noisytoot:  going from level tut-1 to tut-2 returned the
hero's starting equipment too soon, and exiting the tutorial from
tut-2 let the hero keep any equipment acquired within the tutorial.

Entering and leaving the tutorial was being handled by lua code in
the level description of tut-1 and adding a second level messed that
up.  I didn't see any way of handing that with level-specific lua
code so I made it become the core's responsibility.  gotolevel()
knows when the hero is moving from one dungeon branch to another so
it can recognize entry to or exit from the tutorial easily.

While fixing this, prevent #invoke of the Eye of the Aethiopica from
offering the tutorial as a candidate destination (was feasible if it
had been entered at start of game).

Not fixed:  levels visited in the tutorial become part of #overview.

Show location as "Tutorial:1" instead of "Dlvl:1" on status lines.
Only tested with tty; some interfaces handle location themselves and
may need their own fixup for this.

Fixes #1046
2023-06-03 16:39:12 -07:00
nhmall
d74e84fb05 warning suppression
files.c: In function 'do_write_config_file':
files.c:2146:66: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
 2146 |             pline("An error occurred, wrote only partial data (%lu/%lu).",
      |                                                                ~~^
      |                                                                  |
      |                                                                  long unsigned int
      |                                                                %u
 2147 |                   wrote, len);
      |                   ~~~~~
      |                   |
      |                   size_t {aka unsigned int}
files.c:2146:70: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
 2146 |             pline("An error occurred, wrote only partial data (%lu/%lu).",
      |                                                                    ~~^
      |                                                                      |
      |                                                                      long unsigned int
      |                                                                    %u
 2147 |                   wrote, len);
      |                          ~~~
      |                          |
      |                          size_t {aka unsigned int}
2023-05-31 22:17:07 -04:00
Ray Chason
9037592ea1 parent 97edec62b5
author Ray Chason <ray.chason@protonmail.com> 1684372172 -0400
committer nhmall <nhmall@nethack.org> 1685414340 -0400

Add configuration to support Curses on WinGUI

and enable support for Unicode on Curses.

Allow NetHackW to select the Curses interface

Reorder drawing of extended command prompt

Curses on WinGUI needs this change. This may be a bug in PDCursesMod,
but it seems to be harmless to the other ports.

Avoid calling Curses after the windows are closed

Provide erase_char and kill_char for WinGUI Curses

Set Lua version to 5.4.6
2023-05-29 22:39:43 -04:00
nhmall
b35d8a34ed update Lua version supported 2023-05-28 22:58:47 -04:00
PatR
b48cb5bcd9 sp_lev.c reformatting typo 2023-05-28 15:24:44 -07:00
PatR
d75862450e uhitm.c formatting 2023-05-28 15:22:43 -07:00
PatR
17d867d084 fix github issue #1038 - vampshifted Vlad in bones
Reported by vultur-cadens:  if Vlad made it to a level which allowed
bones and was in wolf or bat or cloud form when the hero died, he
would not be excluded from the bones file as intended.  When those
bones got loaded in another game, Vlad would become flagged as
extinct.  If that happened before his own level was reached, he
wouldn't be created when hero arrived thus there would be no way to
acquire the Candelabrum of Invocation.  (Even if his vampshifted
form had been carrying it, it wouldn't be present in the bones data
because it would have been converted into candles.)

Fixes #1038
2023-05-28 15:17:51 -07:00
PatR
6dac3c2183 mondata.c oversight
One recent 'reformatting' change which was more than just source
formatting introduced an unintentional change, turning locomotion
strings from local to mondata.c into global.  Make them be local
again.
2023-05-28 13:19:53 -07:00
PatR
3ccbfc4d6c sp_lev.c formatting 2023-05-28 00:49:53 -07:00
PatR
5cd7f1823c feedback when seeing hider-under hide under
If an monster hides under and object or under water while in view,
say so.

Also, the sanity check for a hidden eel wasn't consistent with the
hiding criteria for it.  An eel can't hide on the Plane of Water even
when it's in the water rather than in an air bubble.
2023-05-27 08:52:45 -07:00
PatR
b6a5be8d77 fix #K3922 - magic whistle vs hidden pet
When a hidden pet was relocated via magic whistle, a message was given
about "your <pet> appears" but it didn't show up on the map.

It was being marked as no longer undetected, but that was after rloc()
had moved it and redrawn its location.  use_magic_whistle() needed to
redraw its location again after clearing monst->mundetected.
2023-05-27 08:47:26 -07:00
PatR
e6521448f0 dungeon.c formatting 2023-05-27 02:47:23 -07:00
PatR
b19062d2c4 mondata.c formatting 2023-05-27 02:44:49 -07:00
PatR
2abe156516 potion of gain level tweak
Eliminate a use of non-literal format string and consequent need to
manipulate compiler warning settings.  Should be no change in behavior.
2023-05-26 14:03:48 -07:00
PatR
aa63aa8d98 issue #1027 - sticky 'nofollowers' flag
Reported by copperwater:  entering the tutorial sets 'u.nofollowers',
changing to the tutorial level saves a copy of 'u', post-level change
from entering the tutorial level resets u.followers, but subsequently
changing levels to return to the original level 1 restores 'u' from
the saved copy with has 'u.nofollowers==True', overriding the reset.

Move the nofollowers flag from 'u' to 'iflags'.  Invalides save and
bones files.

Fixes #1027
2023-05-25 17:08:53 -07:00
PatR
202afc3b55 choosing whether to run the tutorial
Revise the menu that asks whether to run the tutorial so that it will
accept ESC for "no".

Also, in its hint about how to suppress the menu, change vague "the
config file" to the actual configuration file name.  (This might need
a new 'sysconf' directive to control what's shown on servers where
the player doesn't have access to the file system, but the vague
description wasn't adequate for single player systems.)
2023-05-25 15:43:37 -07:00
PatR
cf8a49cae6 use to "feature" in DEBUGFILES
The code to lookup a value in DEBUGFILES usually operates on a file
name, but there are few non-file uses.  The latter wouldn't work on
VMS because of the way it was manipulating the name:  first stripping
away path, suffix, and version, then adding hardcoded ".c" suffix on.

I thought we already had a routine to get the base part of a name
from a full path, but if so, I haven't been able to find it.  This
adds new nh_basename() to do that, with the option of either keeping
or discarding the suffix or type portion.

The VMS usage that prompted this hasn't actually been tested.
2023-05-25 15:35:49 -07:00
PatR
5dc8e98efa a couple of miscellaneous formatting bits 2023-05-24 11:23:15 -07:00
PatR
42356daec0 pull request #1024 - keep hero movement points
Pull request from saltwaterterrapin:  record current move's pending
movement points in save file.  They were being thrown away during
save and hero given 12 at time of restore.  Hero had to have had at
least 12 in order for player to issue the S command, but might have
had more than that if able to move faster than normal speed.

This implements it differently from the suggested commit.  Add new
field umovement to 'struct u' instead of using youmonst.movement and
needing to save and restore that separately.

Invalidates existing save and bones files.

Closes #1024
2023-05-24 11:16:23 -07:00
PatR
6586cc84b2 trap setting bit
Treat a trap object that has become the focus of trap setting
occupation as if it had already been used up.  (No discernable change
in behavior unless someone adds an artifact bear trap or landmine
that talks.)

Shouldn't 'trapinfo' be part of 'context' and be saved and restored?
(If so, it will need to include o_id and undergo pointer fixup during
restore.)  When trap arming is in progress hero will be too busy for
player to issue S(ave) command but a hangup save could take place.
2023-05-23 15:34:58 -07:00
copperwater
d813f534ad Fix: use-after-free when applying an object that got destroyed
Found this running the fuzzer with address sanitizer. After applying an
object, the game checks whether it's a talking artifact so that it can
speak to you afterwards.

If, however, the object got destroyed in the process of applying it,
this will read and dereference obj after they have been freed. I found
this with a cream pie, which is always destroyed when someone applies
it.

To fix this, I tracked the obj pointer for what I think are the only two
cases in the big switch statement that don't track this - royal jelly
and cream pie. Royal jelly is only conditionally destroyed depending on
further input, so its function had to be refactored to take a struct
obj**, but cream pies are unconditionally destroyed so it can just be
set to null.
2023-05-23 15:03:02 -07:00
Pasi Kallinen
39530f9228 Fix the mind flayer attacking without knowing your location
This was caused by the mind flayer mind blasting polymorphed hero,
causing them to revert back to human form, and dropping into a pool,
doing an automatic teleport to save them from drowning.
After that the mind flayer tried to hit them in melee, but the hero
was far away.

Recalculate the nearby and inrage variables after mind blast.
2023-05-23 19:24:19 +03:00
nhmall
4761bf190e OpenVMS update follow-up 2023-05-22 20:50:35 -04:00
PatR
ae0b306f9d sanity_check suppression
Handle ^P vs 'sanity_check' differently, and treat ^R similarly.
2023-05-22 14:43:01 -07:00
nhmall
ff727e916f work around a build issue with a compiler
One compiler was issuing an error diagnostic for cmap_to_glyph() macro (see below).
This just works around that by using cmap_a_to_glyph() which does not suffer the same fate.

mkmaze.c

    static const struct rm water_pos = { cmap_to_glyph(S_water), WATER, 0, 0,
.........................................^
%CC-E-NEEDCONSTEXPR, In the initializer for water_pos.glyph, "In_mines(...)" is not constant, but occurs in a context that requires a constant expression.
at line number 1448 in file mkmaze.c

    static const struct rm water_pos = { cmap_to_glyph(S_water), WATER, 0, 0,
.........................................^
%CC-E-NEEDCONSTEXPR, In the initializer for water_pos.glyph, "In_hell(...)" is not constant, but occurs in a context that requires a constant expression.
at line number 1448 in file mkmaze.c

    static const struct rm water_pos = { cmap_to_glyph(S_water), WATER, 0, 0,
.........................................^
%CC-E-NEEDCONSTEXPR, In the initializer for water_pos.glyph, "gd" is not constant, but occurs in a context that requires a constant expression.
at line number 1448 in file mkmaze.c

    static const struct rm water_pos = { cmap_to_glyph(S_water), WATER, 0, 0,
.........................................^
%CC-E-NEEDCONSTEXPR, In the initializer for water_pos.glyph, "on_level(...)" is not constant, but occurs in a context that requires a constant expression.
at line number 1448 in file mkmaze.c

    static const struct rm water_pos = { cmap_to_glyph(S_water), WATER, 0, 0,
.........................................^
%CC-E-NEEDCONSTEXPR, In the initializer for water_pos.glyph, "(&u.uz)->dnum" is not constant, but occurs in a context that requires a constant expression.
at line number 1448 in file mkmaze.c

    static const struct rm water_pos = { cmap_to_glyph(S_water), WATER, 0, 0,
.........................................^
%CC-E-NEEDCONSTEXPR, In the initializer for water_pos.glyph, "gd.dungeon_topology.d_sokoban_dnum" is not constant, but occurs in a context that requires a const
ant expression.
at line number 1448 in file mkmaze.c

    static const struct rm air_pos = { cmap_to_glyph(S_cloud), AIR, 0, 0, 0,
.......................................^
%CC-E-NEEDCONSTEXPR, In the initializer for air_pos.glyph, "In_mines(...)" is not constant, but occurs in a context that requires a constant expression.
at line number 1450 in file mkmaze.c

    static const struct rm air_pos = { cmap_to_glyph(S_cloud), AIR, 0, 0, 0,
.......................................^
%CC-E-NEEDCONSTEXPR, In the initializer for air_pos.glyph, "In_hell(...)" is not constant, but occurs in a context that requires a constant expression.
at line number 1450 in file mkmaze.c

    static const struct rm air_pos = { cmap_to_glyph(S_cloud), AIR, 0, 0, 0,
.......................................^
%CC-E-NEEDCONSTEXPR, In the initializer for air_pos.glyph, "gd" is not constant, but occurs in a context that requires a constant expression.
at line number 1450 in file mkmaze.c

    static const struct rm air_pos = { cmap_to_glyph(S_cloud), AIR, 0, 0, 0,
.......................................^
%CC-E-NEEDCONSTEXPR, In the initializer for air_pos.glyph, "on_level(...)" is not constant, but occurs in a context that requires a constant expression.
at line number 1450 in file mkmaze.c

    static const struct rm air_pos = { cmap_to_glyph(S_cloud), AIR, 0, 0, 0,
.......................................^
%CC-E-NEEDCONSTEXPR, In the initializer for air_pos.glyph, "(&u.uz)->dnum" is no
t constant, but occurs in a context that requires a constant expression.
at line number 1450 in file mkmaze.c

    static const struct rm air_pos = { cmap_to_glyph(S_cloud), AIR, 0, 0, 0,
.......................................^
%CC-E-NEEDCONSTEXPR, In the initializer for air_pos.glyph, "gd.dungeon_topology.
d_sokoban_dnum" is not constant, but occurs in a context that requires a constant expression.
at line number 1450 in file mkmaze.c
2023-05-22 14:58:29 -04:00
nhmall
68b8e84aa3 changes to build with VSI C compiler
The changes from past OpenVMS compilers are #ifdef'd VMS9
2023-05-22 14:43:10 -04:00
PatR
1f8b3dfef5 ^P vs sanity_check
Normally when sanity_check is enabled it will take place for every
command executed.  Avoid that when the command is ^P because if a
sanity warning is a recurring one and the msg_window setting is
single or combination (tty-only) which shows one message, ^P will
just repeat each new warning without having any chance to cycle back
to earlier messages.
2023-05-22 00:32:25 -07:00
PatR
4e46a7de69 change enexto() to use collect_coords()
Greatly simplify enexto().  The new code might does more work up front
but less overall when/if a nearby spot is hard to find.
2023-05-21 17:30:06 -07:00
PatR
92a993a0b6 fix github issue #1029 - erroneous death feedback
for monsters that haven't died, when being removed from play to keep
them out of bones.

Reported by copperwater:  if the quest nemesis was present on a level
being saved as bones, it was removed from the map to keep it out of
the bones level but the quest feedback for nemesis death was given
in the process.  Would happen for blessed genocide of "*" too.  (It
didn't happen for #wizmakemap and I'm not sure why.)

This was an unintended side-effect of moving some common stuff from
mondead() and mongone() into m_detach().  The quest feedback isn't
actually common to both.  Instead of moving that back, pass a flag
that m_detach() can use to determine which routine called it.

Fixes #1029
2023-05-20 16:44:18 -07:00
PatR
9052bd5099 fix #K3925 - u.ustuck of long worm tail
Don't allow stick/wrap/engulf attacks directed at long worm tails
to succeed.  Achieved by making sure that 'notonhead' is up do date
in a bunch of places and utilizing the fairly recent can't-{stick,wrap,
engulf}-unsolid-monsters code.

Should prevent a 'sanity_check' warning about being too far from
u.ustuck that would happen when holding the tail while the head was
not adjacent to the hero.

Also don't let pet ranged attacks from choosing a long worm's tail
as target.  They'll still be able to target long worms provided that
the head is lined up and not shielded by tail segment(s).
2023-05-20 15:34:32 -07:00
PatR
f176318c45 covetous fixe(es)
Extracted from a larger pending commit.  While trying to make sure
that bhitpos and notonhead are up to date when attacks are processed,
I noticed that covetous monster handling was buggy.  For dist2(),
a value of 1 means adjacent in an orthogonal direction, so testing
for less than 2 unintentionally excluded diagonal adjacency.
2023-05-20 15:26:36 -07:00
PatR
f8e4c3e078 give fuzzer some protection against brainlessness
With the LifeSaved property (via amulet), hero being killed by
brainlessness gets killed twice.  But for explore|wizard mode where
the answer to "Die?" might be "no" and for the fuzzer where it's
always "no", a mind flayer's 3 drain-Int attacks or master flayer's
5 drain-Int attacks will usually kill the hero all over again (and
again, ...).  Skip remaining ones, like happens when one of them
hits and discovers that the target has no head or is mindless, for
the rest of the flayer's current move.

Monsters wearing life-saving don't get killed twice.  That doesn't
seem very fair, but this hasn't touched that.
2023-05-20 01:58:30 -07:00
PatR
925ebf6ea1 fix #K3924 - teleport as giant eel
The safe_teleds() change that restored picking random destination
attempts prior to making an exhaustive search contained a typo tjat
accidentally only accepted invalid positions instead of valid ones.
So unless it randomly picked 40 good spots, erroneously rejecting
all of them and then falling back to the try-everywhere situation
(which has its own testing without any typo), it would yield strange
results by placing the hero in walls or solid rock via choosing the
first inappropriate spot it tried.

Not part of that bug but related, sort of:  for rloc(), use
rloc_pos_ok() instead of goodpos() during the exhaustive search as
well as during the random tries, but hang on to the first (after
randomization) position that passes goodpos() for a last resort.

The collect_coords() flag for 'skip-inaccessible' intended to be a
quick way to filter out walls and solid rock was using !ACCESSIBLE()
which also rejects water and lava locations.  So such spots wouldn't
be picked by either safe_teleds() or rloc() when they were finding
a spot for aquatic or lava-tolerant forms.  Instead of duplicating
a bunch of code to decide whether the hero's current form or the
teleporting monster should avoid !ACCESSIBLE() for a reason other
than having Passes_walls, make collect_coords(CC_SKIP_INACCS) use
!ZAP_POS() which rejects walls and rock but allows pools.
2023-05-17 18:51:28 -07:00
PatR
49e93760a8 collect_coords() revisited
Make recently added collect_coords() global even though it is still
only being used in teleport.c.

Add CC_SKIP_INACCS flag to only collect accessible locations so that
there's no need for a custom filter callback or of collecting spots
that will always be rejected when put to use.  Caller needs to check
Passes_walls/passes_walls() to decide whether that is suitable.

Merge some of the old safe_teleds() with the new, making it try
randomly 40 times before collecting coordinates for an exhaustive
selection.  Prior to the recent change which added collect_coords()
it was trying 400 times and giving up if that didn't find a good spot.

Start using collect_coords() for rloc() as well as for safe_teleds().
Only try to pick a spot randomly 50 times now instead of 1000.  If
those all fail, it does an exhaustive search of a randomized list of
candidates instead of old left-to-right, top-to-bottom map traversal.
Has not had nearly as much testing as safe_teleds() underwent.

rloc() was explicilty ignoring map column 1 for some reason.  Unlike
reserved column 0, column 1 is part of every level and should be
considered for monster teleport destination even though most levels
don't utilize it.
2023-05-17 00:33:54 -07:00
nhmall
d7f581d8ad fix compiler complaint
a check for baselen being less than or equal to zero drew a compiler
complaint because the variable is unsigned
2023-05-15 23:14:26 -04:00
nhmall
420048b8d3 keep external identifiers under length of 31 char 2023-05-15 23:11:34 -04:00
PatR
59677e7440 rewrite safe_teleds()
The teleport to safety routine would try to find a viable spot 400
times, the first 200 rejecting trap locations and the last 200
accepting such.  While testing various escape from lava variations
recently, I noticed that I could fail to reach safety even when there
was an open spot immediately adjacent to me.  I added a BandAid(tm)
to make another 400 tries if the first attempt failed, but that was
clumsy and still didn't guarantee picking a viable spot.

This adds a new routine, collect_coords(), which will gather a list
of coordinates for the entire map.  safe_teleds() goes through them
one by one until either finding a spot or exhausting the possibilies,
without randomly trying and retrying the same spot multiple times and
without missing other potential spots, also without just scanning the
map from left to right and top to bottom or similar.

Various other things which retry over and over, and especially the
ones which make a bunch of random attempts and then fallback to trying
every spot on the map, could be switched over to this, at least for
the falling back phase.  Right now collect_coords() is local to
teleport.c but that could be easily changed.

The try-at-random method is much quicker when there are lots of
available spots but the gather-shuffled-candidates method is
guaranteed to succeed if success is possible.  The way safe_teleds()
is presently using it collects the list with all locations within
2 steps first, then those within 3 to 4, then 5 to 6, and so on out,
randomized within each block of ranges.  So the destination will be
within one step of being as close to the starting spot as possible
but not always immediately adjacent when that happens to be available.
2023-05-15 01:42:13 -07:00
PatR
2646688e2d back_on_ground()
Replace a couple of hardcoded "back on solid ground" messages with
something more versatile.

Also, make life-saving handling for failed rescue from drowning
similar to that of failed rescue immolation by lava.  If there are
any cases where more than two tries is needed, they elude me.  The
new code doesn't confer temporary water walking if emergency teleport
fails; perhaps it should.
2023-05-15 01:08:04 -07:00
nhmall
ec9d3cb88e keep external identifiers under 31 characters length 2023-05-13 13:49:57 -04:00
Pasi Kallinen
a54b6ba75c Split object init out of mksobj
Move the random erosions in there, as those should only be done if
the object is getting a random initialization.
2023-05-13 12:12:36 +03:00