Player/Mechanics/PostureMechanic.cs
namespace Opium;
/// <summary>
/// The posture of an actor is essentially a second stamina bar, but for block attacks. If you have no posture left, a block will be useless and you'll be hit.
/// </summary>
public partial class PostureMechanic : PlayerMechanic
{
public float Value { get; set; } = 100f;
[Property] public float Default { get; set; } = 100f;
protected TimeSince TimeSinceUsed { get; set; }
protected TimeUntil TimeUntilRegenerate { get; set; }
[Property] public float RegenerateTime { get; set; } = 5f;
[Property] public float RegenerateSpeed { get; set; } = 10f;
public override bool ShouldBecomeActive() => true;
protected override void OnStart()
{
base.OnStart();
Value = Default;
}
public void Remove( float used, float timeUntilNextRegenerate = 0.0f )
{
Value -= used;
Value = Value.Clamp( 0, 100 );
TimeSinceUsed = 0;
if ( timeUntilNextRegenerate != 0f )
{
TimeUntilRegenerate = timeUntilNextRegenerate;
}
else
{
TimeUntilRegenerate = RegenerateTime;
}
}
public void Add( float added )
{
Value += added;
Value = Value.Clamp( 0, 100 );
}
public override void OnActiveUpdate()
{
if ( TimeUntilRegenerate )
{
Add( Time.Delta * RegenerateSpeed );
}
}
public override IEnumerable<string> GetTags()
{
if ( Value <= 0 ) yield return "no-posture";
}
internal float CalculateDamage( Sandbox.DamageInfo damage )
{
if ( damage is Opium.DamageInfo opDamage )
{
var wpn = opDamage.Inflictor.Components.Get<MeleeWeapon>();
if ( wpn is not null )
{
return wpn.Posture;
}
}
return 25f;
}
/// <summary>
/// Called when someone is blocking an attack, we will control how much posture we lose here, and react to it if needed.
/// </summary>
internal bool Compensate( Sandbox.DamageInfo damage )
{
var amount = CalculateDamage( damage );
// Remove posture based on the damage we receive.
Remove( amount );
Log.Info( $"new posture: {Value}, compensating for {amount} posture damage" );
if ( Value <= 0 )
{
// TODO: break posture, animations, events, all that cool stuff.
Actor.TriggerEvent( "posture_break", damage );
return true;
}
return false;
}
}