Two small components for NPC gib/dismemberment visuals. NpcDismembermentVisual finds its DemoNpc owner and calls ApplyDismembermentVisuals each update. GibLifetime fades a gib model over time and destroys the GameObject after a solid + fade duration.
using AdaptiveDirectorDemo.Director;
using Sandbox;
using System;
namespace AdaptiveDirectorDemo.Combat;
/// <summary>Body regions understood by the demo's localized damage adapter.</summary>
public enum NpcBodyRegion
{
None,
Head,
Torso,
LeftArm,
RightArm,
LeftHand,
RightHand,
LeftLeg,
RightLeg,
LeftFoot,
RightFoot
}
/// <summary>
/// Applies persistent bone removal after the Citizen animation graph has updated.
/// Kept separate from DemoNpc so the override runs later in component order.
/// </summary>
[Title( "NPC Dismemberment Visual" )]
[Category( "Adaptive Director Demo" )]
public sealed class NpcDismembermentVisual : Component
{
public DemoNpc Owner { get; set; }
protected override void OnUpdate()
{
if ( Owner is null || !Owner.IsValid )
Owner = Components.Get<DemoNpc>();
Owner?.ApplyDismembermentVisuals();
}
}
/// <summary>Fades physical gibs after a short readable lifetime.</summary>
[Title( "Gib Lifetime" )]
[Category( "Adaptive Director Demo" )]
public sealed class GibLifetime : Component
{
[Property] public float SolidSeconds { get; set; } = 12.0f;
[Property] public float FadeSeconds { get; set; } = 3.0f;
private ModelRenderer _renderer;
private Color _baseTint = Color.White;
private TimeSince _age;
protected override void OnStart()
{
_renderer = Components.Get<ModelRenderer>();
if ( _renderer is not null )
_baseTint = _renderer.Tint;
_age = 0.0f;
}
protected override void OnUpdate()
{
if ( _age < SolidSeconds )
return;
var fade = Math.Clamp( (_age - SolidSeconds) / Math.Max( 0.1f, FadeSeconds ), 0.0f, 1.0f );
if ( _renderer is not null && _renderer.IsValid )
_renderer.Tint = _baseTint.WithAlpha( 1.0f - fade );
if ( fade >= 1.0f )
GameObject.Destroy();
}
}