combat/slomo/TimeManager.cs
using System;
using Sandbox;
public sealed class TimeManager : Component
{
public static TimeManager Instance { get; private set; }
[Property, Group( "1. Kick Armé" )]
public TimeImpactProfile KickWindupProfile { get; set; }
[Property, Group( "2. Jet d'Arme Connecté" )]
public TimeImpactProfile WeaponThrowHitProfile { get; set; }
[Property, Group( "3. Knockdown Infligé" )]
public TimeImpactProfile KnockdownProfile { get; set; }
[Property, Group( "4. Coup Fatal (Kill)" )]
public TimeImpactProfile KillProfile { get; set; }
private TimeImpactProfile _activeProfile;
private RealTimeSince _realTimeSinceImpact = 100f;
private float _currentTargetTimeScale = 1.0f;
private float _currentDuration = 0f;
private float _currentRecoverySpeed = 8f;
private int _currentPriority = 0;
private bool _isImpactActive = false;
protected override void OnAwake()
{
Instance = this;
}
protected override void OnStart()
{
CombatEvents.OnPlayerKickWindup += HandleKickWindup;
CombatEvents.OnPlayerKickReleased += HandleKickReleased;
CombatEvents.OnPlayerWeaponThrowHit += HandleWeaponThrowHit;
CombatEvents.OnPlayerKnockdownEnemy += HandleKnockdownEnemy;
CombatEvents.OnPlayerKillEnemy += HandleKillEnemy;
}
protected override void OnDestroy()
{
CombatEvents.OnPlayerKickWindup -= HandleKickWindup;
CombatEvents.OnPlayerKickReleased -= HandleKickReleased;
CombatEvents.OnPlayerWeaponThrowHit -= HandleWeaponThrowHit;
CombatEvents.OnPlayerKnockdownEnemy -= HandleKnockdownEnemy;
CombatEvents.OnPlayerKillEnemy -= HandleKillEnemy;
if ( Scene != null && Scene.IsValid )
Scene.TimeScale = 1.0f;
}
private void HandleKickWindup()
{
var profile = KickWindupProfile ?? new TimeImpactProfile
{
TargetTimeScale = 0.25f,
RealDuration = 0.35f,
RecoverySpeed = 14f,
Priority = 1
};
ApplySlowdown( profile );
}
private void HandleKickReleased()
{
if ( _isImpactActive && _currentPriority <= 1 )
{
Scene.TimeScale = 1.0f;
_isImpactActive = false;
_currentPriority = 0;
_activeProfile = null;
}
}
private void HandleWeaponThrowHit( Weapon weapon, Fighter victim, DamageContext ctx, bool willImpale )
{
var profile = WeaponThrowHitProfile ?? new TimeImpactProfile
{
TargetTimeScale = willImpale ? 0.08f : 0.12f,
RealDuration = willImpale ? 0.28f : 0.22f,
RecoverySpeed = 10f,
Priority = 2
};
ApplySlowdown( profile );
}
private void HandleKnockdownEnemy( Fighter victim, DamageContext ctx )
{
var profile = KnockdownProfile ?? new TimeImpactProfile
{
TargetTimeScale = 0.10f,
RealDuration = 0.28f,
RecoverySpeed = 8f,
Priority = 3
};
ApplySlowdown( profile );
}
private void HandleKillEnemy( Fighter victim, DamageContext ctx, bool victimWasUnarmed )
{
var profile = KillProfile ?? new TimeImpactProfile
{
TargetTimeScale = 0.05f,
RealDuration = 0.38f,
RecoverySpeed = 6f,
Priority = 4
};
ApplySlowdown( profile );
}
public void ApplySlowdown( TimeImpactProfile profile )
{
if ( profile == null ) return;
if ( _isImpactActive && _currentPriority > profile.Priority && _realTimeSinceImpact < _currentDuration )
return;
_activeProfile = profile;
_currentTargetTimeScale = profile.TargetTimeScale;
_currentDuration = profile.RealDuration;
_currentRecoverySpeed = profile.RecoverySpeed;
_currentPriority = profile.Priority;
_realTimeSinceImpact = 0;
_isImpactActive = true;
Scene.TimeScale = _currentTargetTimeScale;
}
protected override void OnUpdate()
{
if ( !_isImpactActive ) return;
if ( _realTimeSinceImpact >= _currentDuration )
{
Scene.TimeScale = MathX.Lerp( Scene.TimeScale, 1.0f, _currentRecoverySpeed * RealTime.Delta );
if ( MathF.Abs( Scene.TimeScale - 1.0f ) < 0.02f )
{
Scene.TimeScale = 1.0f;
_isImpactActive = false;
_currentPriority = 0;
_activeProfile = null;
}
}
else
{
Scene.TimeScale = _currentTargetTimeScale;
}
}
}