* Replace variadic debugpline() with fixed argument debugpline0(str),
debugpline1(fmt,arg), and so on so that C99 support isn't required;
* showdebug() becomes a function rather than a macro and handles a
bit more;
* two debugpline() calls in light.c have been changed to impossible();
* DEBUGFILES macro (in sys.c) can substitute for SYSCF's DEBUGFILES
setting in !SYSCF configuration (I hope that's temporary).
This finally eliminates all direct increases of `oeroded` and `oeroded2`
and moves them all to go via `erode_obj()`. They are still manipulated
directly in a few places, but not to erode objects.
This now merges the `fire_damage()` function to a common codepath, used
for items on lava and burning oil, but fire needs more work. There is
still a duplication between `destroy_item()` and `fire_damage()`; the
two codepaths should eventually be merged in some manner so that there
is only one codepath to say "an object was affected by fire". This path
might require some parameters, such as whether the fire will just erode
objects or burn them outright, but that can happen another day.
Move debugging output into couple preprocessor defines, which
are no-op without DEBUG. To show debugging output from a
certain source files, use sysconf:
DEBUGFILES=dungeon.c questpgr.c
Also fix couple debug lines which did not compile.
This also includes fixes due to Derek Ray to depugpline to work better
on other platforms.
There is a lot of code affected by this, and Pat Rankin correctly
observes that it would be better to store roguelike as a level flag
rather than just using Is_rogue_level. A note for the future.
* Replace variadic debugpline() with fixed argument debugpline0(str),
debugpline1(fmt,arg), and so on so that C99 support isn't required;
* showdebug() becomes a function rather than a macro and handles a
bit more;
* two debugpline() calls in light.c have been changed to impossible();
* DEBUGFILES macro (in sys.c) can substitute for SYSCF's DEBUGFILES
setting in !SYSCF configuration (I hope that's temporary).
This finally eliminates all direct increases of `oeroded` and `oeroded2`
and moves them all to go via `erode_obj()`. They are still manipulated
directly in a few places, but not to erode objects.
This now merges the `fire_damage()` function to a common codepath, used
for items on lava and burning oil, but fire needs more work. There is
still a duplication between `destroy_item()` and `fire_damage()`; the
two codepaths should eventually be merged in some manner so that there
is only one codepath to say "an object was affected by fire". This path
might require some parameters, such as whether the fire will just erode
objects or burn them outright, but that can happen another day.
Move debugging output into couple preprocessor defines, which
are no-op without DEBUG. To show debugging output from a
certain source files, use sysconf:
DEBUGFILES=dungeon.c questpgr.c
Also fix couple debug lines which did not compile.
This also includes fixes due to Derek Ray to depugpline to work better
on other platforms.
There is a lot of code affected by this, and Pat Rankin correctly
observes that it would be better to store roguelike as a level flag
rather than just using Is_rogue_level. A note for the future.
Introduce some variation in monster movement by adding and substracting
small random amounts to the fixed increment from the main monster table. The
amount added is potentially bigger (average is +2) than the amount substracted
(average is +1), so monsters will tend to be slightly faster. Probably not
noticeable except for super-slow monsters not being so glacially slow, since
net +1 is a bigger relative increase for such critters' low movement rates.
In practice, the noticeable effect will be that ordinary speed monsters will
occasionally get an extra move even if/when player keeps the hero unburdened.
Possible extension (although I'm not planning to do it): sort the
monster list by pending movement points, so that faster monsters move before
slower ones. The random variation would become noticeable because groups of
same-speed monsters would alter their movement order depending upon who got
a bigger increment or smaller decrement on that turn.
Fix several obscure bugs that can happen when a guard leads someone
out of a vault:
1) non-pit traps created in the temporary corridor would persist inside
solid rock after the corridor was removed (pits dug by the hero were
explicitly removed but several other trap types are possible);
2) lighting the corridor with scroll/wand/spell left the affected spots
flagged as lit after they reverted to rock; tunneling through that
area, either by digging or by teleporting back to the vault and having
another guard appear, unearthed lit corridor there;
3) if you became encased in solid rock because you were in the temporary
corridor when it was removed (which will happen if the guard is killed
while you're in his corridor), you were only told so if you saw part of
it revert to rock; when blind, you simply found yourself unable to move;
4) dragging an iron ball in the temporary corridor could result in part
of that corridor becoming permanent if the guard was killed; in 3.4.3,
it would only occur if the cause of death took away all the guard's
hit points (which happens for most but not all deaths); in development
code after my recent patch, that would be every cause of death.
#4 could also yield "dmonsfree: <N+1> removed doesn't match <N> pending"
warning in 3.4.3 when the fmon list was scanned and a guard at <0,0> with
no hit points was found but hadn't passed through to the end of mondead()
and m_detach(). The previous patch fixed that, I think/hope. Most guard
deaths won't trigger that; grddead() moves the guard to <0,0> but then
removes the temp corridor on its second try, returns true, and mondead()
finishes normally.
From the newsgroup: after killing a vault guard on a level where
every object had been removed or was held by the hero, object detection
gave feedback about finding something but was unable to show anything.
It was finding the dead guard's inventory at <0,0>, a part of the map
which never gets shown. A dying guard is sent to that location instead
of being killed and deleted, because the data for his temporary corridor
to/from the vault is kept in the egd structure attached to him. That's
somewhat obscure but works; dying guards just need to drop inventory
before being transfered there rather than after.
Depending upon how they're killed, it's possible that the umpteen
places in the code that loop over fmon might have been processing them
as if still in play. This sets their mhp to 0 so such loops will ignore
them, and teaches dmonsfree() not to release them. Once the temporary
corridor has been removed, their isgd flag is cleared and they become
ordinary dead monsters and get deleted from the fmon list the next time
it's purged.
This also lets you throw gold to/at the guard when he tells you to
drop it. He already would catch it, but now he won't treat the throw as
an attack. Any gold he carries will eventually disappear when he does,
so dropping it remains a better option for the player.
Something I've had in mind for a long time and finally gotten around
to implementing: when you fill in the last pit or hole of a sokoban level,
it's considered to be completed so luck penalties for unsokobanish things
(breaking a boulder, dropping everything and squeezing onto a boulder's
spot, reading a scroll of earth) stop being assessed and most Sokoban-
specific movement restrictions (against pushing boulders diagonally,
squeezing diagonally between boulders, floating over a pit or hole without
falling in, digging of new holes by monsters) are lifted. Teleporting,
level teleporting, and phasing through walls are still prohibited when in
the sokoban branch of the dungeon. (Keeping the non-phasing one in place
prevents taking a shortcut to the final prize in order to bypass the
treasure zoo monsters.)
This adds level.flags.sokoban_rules, defines Sokoban macro to access
it, and replaces most In_sokoban(&u.uz) tests to check it instead. It
gets set when a sokoban level is pre-mapped at the end of level creation,
and if it is set then whenever a trap is deleted, the flag gets cleared
if there are no more pits or holes present on the level.
Rename ``kickobj'' to ``kickedobj'' so that the tense matches that
of ``thrownobj''. Also, move their declarations to decl.h and their
definitions to decl.c since usage has spread from dokick.c/dothrow.c to
various files and is about to expand to another one.
A mimic posing as a statue was displayed as a tengu statue (and
recognizeable as such now that statues are displayed as the corresponding
monster rather than rock-class back tick), but the lookat code described
it as a giant ant statue (since there was no obj->corpsenm available to
indicate the monster type, it defaulted to 0). This adds monst->mextra
field `mcorpsenm' so that mimics have a place to remember what sort of
statue or corpse they are mimicking. And it picks a random monster type
when they take such forms so that the old tengu hack becomes irrelevant.
newmextra() and newoextra() initialized pointers via memset(...,0)
which is not portable; switch to explicit assignments. The wizard mode
code to display memory used for monsters and objects added in amounts
for the miscellaneous things pointed to by monst->mextra and obj->oextra
structs but didn't include memory for those structs themselves; add it.
Simplify monster save/restore slightly; there's no need for extra zeroes
to represent monst->mextra->X sizes when monst->mextra is null.
Update the startup banner for 2009. I should have done this with a
separate patch but I'm taking a shortcut. :-]
I) When testing the shopkeeper polymorph fix a couple of days ago, I
tried to pick a form without a head (which is now rejected for shk) by
specifying "trapper" via #monpolycontrol. It worked, in the sense that
the shopkeeper didn't take that form, but it also retried with "lurker
above". After trapper was rejected, it matched "trapper or lurker above"
for monster class and picked at random from that class (and in this case,
the second try was rejected for being headless too). The code I added
(a couple of years ago?) to prevent picking invalid forms for vampire
shapeshifting was a bit sloppy with its retry attempts.
II) I also noticed that monpolycontrol would let you pick forms that
newcham subsequently rejected, like placeholder monster "giant", so that
select_newcham_form got called again, resulting in a new prompt from
monpolycontrol to choose a form without seeing any explanation why the
first try was ignored. Now you'll get the same "it can't become that"
feedback and immediate reprompt as for an invalid monster, instead of
returning newcham a form that it won't accept.
III) The change in shopkeeper polymorph was rejecting forms without hands.
That was way too restrictive; the notake() filter is sufficient.
This is all modification of post-3.4.3 stuff, so no fixes entry.
[Not 100% true. newcham() doesn't explicitly reject humans anymore,
relying on polyok() test instead. Kops are the only humans who pass it.
If they're not supposed too, they need M2_NOPOLY in their definition.]
From a bug report, a shopkeeper who's been
polymorphed into a limbless creature shouldn't be able to come take your
possessions when you die since you can't pick up items when in that shape.
Rather than add new special case handling for shopkeepers, prevent them
from taking on shapes that render them unable to behave like shopkeepers
so that they can continue to catch thrown pick-axes and assorted other
things that would otherwise need a lot of extra checking introduced.
Ditto for temple priests, vault guards, and quest leaders. Restriction
also applies to wizard mode use of #monpolycontrol, the only place where
players can actually notice this.
It could--perhaps should--restrict them even further, forcing forms
that retain speech capability, but I didn't go that far.