PlayerAbilities.cs

Component attached to a player that provides two abilities, dropping a heavy object onto a targeted game object and activating a temporary shield that increases the player's rigidbody mass. Handles input checks, cooldowns, spawn and network spawn of the heavy object, and shield timing and mass override.

NetworkingFile Access
using Sandbox;
using System;

public sealed class PlayerAbilities : Component
{
    [Property] public GameObject HeavyObjectPrefab { get; set; }

    [Property] public float DropCooldown { get; set; } = 8f;
    [Property] public float ShieldCooldown { get; set; } = 6f;
    [Property] public float ShieldDuration { get; set; } = 2f;

    public bool IsShieldActive { get; private set; } = false;

    private TimeSince _timeSinceDrop = 100f;
    private TimeSince _timeSinceShield = 100f;
    private TimeSince _shieldActiveTimer = 0f;

    private Rigidbody _rb;
    private float _originalMass = 0f;

    protected override void OnStart()
    {
        _rb = Components.Get<Rigidbody>();
        if ( _rb.IsValid() )
        {
            _originalMass = _rb.MassOverride;
        }
    }

    protected override void OnUpdate()
    {
        if ( IsProxy ) return;

        if ( IsShieldActive && _shieldActiveTimer > ShieldDuration )
        {
            DeactivateShield();
        }

        if ( Input.Pressed( "attack2" ) || Input.Pressed( "use" ) )
        {
            TryDropObject();
        }

        if ( Input.Pressed( "run" ) )
        {
            TryActivateShield();
        }
    }

    private void TryDropObject()
    {
        if ( _timeSinceDrop < DropCooldown )
        {
            Log.Info( $"[Способности] Сброс на перезарядке! Осталось: {DropCooldown - _timeSinceDrop:F1} сек." );
            return;
        }

        var headPos = WorldPosition + Vector3.Up * 50f;
        var forwardPos = headPos + WorldTransform.Forward * 600f;

        var tr = Scene.Trace.Ray( headPos, forwardPos )
                            .IgnoreGameObjectHierarchy( GameObject )
                            .Run();

        if ( tr.Hit && tr.GameObject.IsValid() )
        {
            var targetPos = tr.GameObject.WorldPosition;
            var spawnPos = targetPos + Vector3.Up * 180f;

            if ( HeavyObjectPrefab.IsValid() )
            {
                var obj = HeavyObjectPrefab.Clone( spawnPos );
                if ( obj.IsValid() && Network.Active )
                {
                    obj.NetworkSpawn();
                }

                _timeSinceDrop = 0;
                Log.Info( "[Способности] Тяжелый объект сброшен прямо на врага!" );
            }
            else
            {
                Log.Warning( "[Способности] HeavyObjectPrefab не назначен в Инспекторе!" );
            }
        }
        else
        {
            Log.Info( "[Способности] Никого не нашли перед собой для атаки!" );
        }
    }

    private void TryActivateShield()
    {
        if ( _timeSinceShield < ShieldCooldown || IsShieldActive ) return;

        IsShieldActive = true;
        _shieldActiveTimer = 0;
        _timeSinceShield = 0;

        if ( _rb.IsValid() )
        {
            _originalMass = _rb.MassOverride;
            _rb.MassOverride = 1000f; 
        }

        Log.Info( "[Способности] ЩИТ АКТИВИРОВАН!" );
    }

    private void DeactivateShield()
    {
        IsShieldActive = false;

        if ( _rb.IsValid() )
        {
            _rb.MassOverride = _originalMass; 
        }

        Log.Info( "[Способности] Действие щита закончилось." );
    }
}