Weapons/ToolGun/Modes/Hoverball/HoverballMorphs.cs
using Sandbox.Utility;
public sealed class HoverballMorphs : Component
{
private HoverballEntity _hoverball;
private SkinnedModelRenderer _renderer;
private Material _glowMaterialCopy;
private float _coils;
private float _pins;
private float _brightnessTarget;
private float _brightnessCurrent;
private float _brightnessTimer;
private float _coilsFrom;
private float _coilsTo;
private float _coilsTime;
private float _pinsFrom;
private float _pinsTo;
private float _pinsTime;
[Property] public float Speed { get; set; } = 15f;
[Property] public float TransitionDuration { get; set; } = 0.5f;
[Property] public Material GlowMaterial { get; set; }
[Property, Group( "Illumination" )] public Color IllumTint { get; set; } = Color.FromBytes( 20, 165, 200 );
[Property, Group( "Illumination" )] public float IllumBrightness { get; set; } = 8f;
[Property, Group( "Illumination" ), Title( "Flicker Min" )] public float IllumFlickerMin { get; set; } = 6f;
[Property, Group( "Illumination" ), Title( "Flicker Max" )] public float IllumFlickerMax { get; set; } = 8f;
[Property, Group( "Illumination" ), Title( "Flicker Interval Min" )] public float IllumFlickerIntervalMin { get; set; } = 0.1f;
[Property, Group( "Illumination" ), Title( "Flicker Interval Max" )] public float IllumFlickerIntervalMax { get; set; } = 0.4f;
[Property, Group( "Illumination" ), Title( "Flicker Approach Speed" )] public float IllumFlickerSpeed { get; set; } = 7f;
[Property, Group( "Morphs" ), Title( "Pin Range Max" )] public float PinRangeMax { get; set; } = 5f;
[Property, Group( "Morphs" ), Title( "Pin Deployed" )] public float PinDeployedValue { get; set; } = 1f;
[Property, Group( "Morphs" ), Title( "Coil Deployed" )] public float CoilDeployedValue { get; set; } = 1f;
protected override void OnStart()
{
_hoverball = GetComponent<HoverballEntity>();
_renderer = GetComponentInChildren<SkinnedModelRenderer>();
if ( GlowMaterial is not null && _renderer.IsValid() )
{
_glowMaterialCopy = GlowMaterial.CreateCopy();
_renderer.MaterialOverride = _glowMaterialCopy;
_renderer.SceneModel.Batchable = false;
}
}
protected override void OnUpdate()
{
if ( !_hoverball.IsValid() || !_renderer.IsValid() ) return;
var targetCoils = _hoverball.IsEnabled ? CoilDeployedValue : 0f;
var targetPins = Math.Clamp( _hoverball.AirResistance / PinRangeMax, 0f, 1f ) * PinDeployedValue;
if ( targetCoils != _coilsTo )
{
_coilsFrom = _coils;
_coilsTo = targetCoils;
_coilsTime = 0f;
}
if ( targetPins != _pinsTo )
{
_pinsFrom = _pins;
_pinsTo = targetPins;
_pinsTime = 0f;
}
_coilsTime = Math.Min( _coilsTime + Time.Delta / TransitionDuration, 1f );
_pinsTime = Math.Min( _pinsTime + Time.Delta / TransitionDuration, 1f );
_coils = MathX.Lerp( _coilsFrom, _coilsTo, Easing.BounceOut( _coilsTime ) );
_pins = MathX.Lerp( _pinsFrom, _pinsTo, Easing.BounceOut( _pinsTime ) );
_renderer.SceneModel?.Morphs.Set( "Coils_Deployed", _coils );
_renderer.SceneModel?.Morphs.Set( "Pins_Deployed", _pins );
UpdateGlowMaterial();
}
void UpdateGlowMaterial()
{
if ( _glowMaterialCopy is null ) return;
var brightness = _hoverball.IsEnabled ? IllumBrightness : 0f;
if ( _hoverball.IsEnabled )
{
_brightnessTimer -= Time.Delta;
if ( _brightnessTimer <= 0f )
{
_brightnessTarget = Random.Shared.Float( IllumFlickerMin, IllumFlickerMax );
_brightnessTimer = Random.Shared.Float( IllumFlickerIntervalMin, IllumFlickerIntervalMax );
}
_brightnessCurrent = MathX.Approach( _brightnessCurrent, _brightnessTarget, Time.Delta * IllumFlickerSpeed );
brightness = _brightnessCurrent;
}
_glowMaterialCopy.Set( "g_vSelfIllumTint", _hoverball.IsEnabled ? IllumTint : Color.Black );
_glowMaterialCopy.Set( "g_flSelfIllumBrightness", brightness * _coils );
}
}