ValveSoftware / halflife

Half-Life 1 engine based games
Other
3.59k stars 598 forks source link

[Half-Life] Gargantua's Stomp attack is broken at higher framerates #2876

Open BlackShadow opened 4 years ago

BlackShadow commented 4 years ago

Gargantua's stomp attack is broken at higher framerates because his attack movement/velocity based on framerate.

As it can be seen here: https://streamable.com/uajuq

To fix this:

https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/gargantua.cpp#L146-L148

Change:

pev->framerate = pev->framerate + (gpGlobals->frametime) * 1500;

To:

pev->speed = pev->speed * 1.3;

SamVanheer commented 3 years ago

That doesn't really fix the problem. The attack speed will still be dependent on the framerate, just in a different way. Depending on the framerate the think method will execute more often since it can't execute exactly at the time set in pev->nextthink.

The proper way to fix this is to use the same solution as the turn rate fix (#2458).

After this line: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/gargantua.cpp#L84

Add this:

int     Save(CSave& save) override;
int     Restore(CRestore& restore) override;
static  TYPEDESCRIPTION m_SaveData[];

float m_flLastThinkTime;

After this line: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/gargantua.cpp#L91

Add this:

TYPEDESCRIPTION CStomp::m_SaveData[] =
{
    DEFINE_FIELD(CStomp, m_flLastThinkTime, FIELD_TIME),
};

IMPLEMENT_SAVERESTORE(CStomp, CBaseEntity);

Rework this code: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/gargantua.cpp#L124-L148

To this:

if (m_flLastThinkTime == 0)
{
    m_flLastThinkTime = gpGlobals->time - gpGlobals->frametime;
}

//Use 1/4th the delta time to match the original behavior more closely
const float deltaTime = (gpGlobals->time - m_flLastThinkTime) / 4;

m_flLastThinkTime = gpGlobals->time;

TraceResult tr;

pev->nextthink = gpGlobals->time + 0.1;

// Do damage for this frame
Vector vecStart = pev->origin;
vecStart.z += 30;
Vector vecEnd = vecStart + (pev->movedir * pev->speed * deltaTime);

UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr );

if ( tr.pHit && tr.pHit != pev->owner )
{
    CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );
    entvars_t *pevOwner = pev;
    if ( pev->owner )
        pevOwner = VARS(pev->owner);

    if ( pEntity )
        pEntity->TakeDamage( pev, pevOwner, gSkillData.gargantuaDmgStomp, DMG_SONIC );
}

// Accelerate the effect
pev->speed = pev->speed + deltaTime * pev->framerate;
pev->framerate = pev->framerate + deltaTime * 1500;

Instead of gpGlobals->frametime the code now uses the time between think method executions, which is the correct delta time. That time divided by 4 is a close enough match to the frametime at 30 FPS to consistently move the stomp at the same speed.