Fix excessive lavafall damage

Like many things in the main game loop, lavafall handling was
historically done on a per-frame basis, then its effects were scaled to
FrameTime to normalize the results.  Ignoring rounding errors, this
produced roughly equivalent damage for high framerate users (who
experienced many but small damage hits) and low framerate users (who
experienced few but large damage hits).  However, the randomized
movement was not scaled to FrameTime, which caused differing results for
high framerate users versus low framerate users.  Commit b36c6f20c7
tried to fix this by forcing scrape_player_on_wall to run at a capped
maximum effective frame rate, then scaling the damage in
check_volatile_wall accordingly, so that high framerate users would
experience fewer damage hits, but the ones they received were larger,
thus maintaining approximately the same damage as before.

Prior to b36c6f20c7, damage was always scaled to FrameTime.  In
b36c6f20c7 and later, damage scaled to max(FrameTime,
DESIGNATED_GAME_FRAMETIME), causing users with a high frame rate (and
thus low FrameTime) to take more damage on each pass.  This damage
increase was balanced by an added hack in scrape_player_on_wall to limit
the frequency of the scrape so that high framerate users would skip some
scrapes, giving them a virtual frame rate appropriate to
DESIGNATED_GAME_FRAMETIME.  However, the damage is only balanced if the
new governor is used consistently.  It is not used consistently, so it
caused a regression for passable lava surfaces.  Scraping on a solid
lava surface goes through scrape_player_on_wall and respects the
governor.  Touching a passable lava surface (only available in Descent
2) bypasses scrape_player_on_wall and jumps directly to
check_volatile_wall, thereby bypassing the governor.  This allows high
framerate users touching a passable lava surface to take many hits (as
they always did), but not receive the full benefit of downward scaling
the damage (as they once did) due to the new max() expression.  Thus,
they are damaged frequently, but still take damage consistent with being
damaged infrequently.

Fix this by moving the hack from scrape_player_on_wall to
check_volatile_wall, so that both solid lava surfaces and passable lava
surfaces respect the governor.  The governor is still an ugly hack that
should not be global, but this is a spot fix for the immediate problem.

Fixes: b36c6f20c7 ("Made scrape_player_on_wall() based on a timer. Due to the player being pushed away from the lava/water surface in every frame in a random vector (wrong, too), player movement per frame was not enough to counter this on FPS rates > ~120 which made damage scaling per frame nonsensical in these situations. Instead, execute scrape results in intevals based on DESIGNATED_GAME_FRAMETIME (or per frame if FrameTime>DESIGNATED_GAME_FRAMETIME) which fixes the issues and generally works much better for the purpose of this function.")
This commit is contained in:
Kp 2017-09-08 00:56:37 +00:00
parent aeedadba89
commit 0548384d2a

View file

@ -443,6 +443,10 @@ volatile_wall_result check_volatile_wall(const vmobjptridx_t obj, const segment
if (get_player_id(obj) == Player_num)
#endif
{
if (!((GameTime64 > Last_volatile_scrape_time + DESIGNATED_GAME_FRAMETIME) || (GameTime64 < Last_volatile_scrape_time)))
return volatile_wall_result::none;
Last_volatile_scrape_time = GameTime64;
#if defined(DXX_BUILD_DESCENT_II)
if (d > 0)
#endif
@ -484,10 +488,6 @@ bool scrape_player_on_wall(const vmobjptridx_t obj, const vmsegptridx_t hitseg,
if (obj->type != OBJ_PLAYER || get_player_id(obj) != Player_num)
return false;
if (!((GameTime64 > Last_volatile_scrape_time + DESIGNATED_GAME_FRAMETIME) || (GameTime64 < Last_volatile_scrape_time)))
return false;
Last_volatile_scrape_time = GameTime64;
const auto type = check_volatile_wall(obj, hitseg, hitside);
if (type != volatile_wall_result::none)
{