2025-09-24 11:24:38 +05:00

138 lines
3.3 KiB
C#

using UnityEngine;
using Fusion;
namespace TPSBR
{
public class Flashbang : ContextBehaviour
{
// PRIVATE MEMBERS
[SerializeField]
private float _innerRadius = 10f;
[SerializeField]
private float _outerRadius = 25f;
[SerializeField]
private float _innerFlashValue = 1f;
[SerializeField]
private float _outerFlashValue = 0.1f;
[SerializeField]
private float _maxFlashDuration = 4f;
[SerializeField]
private float _minFlashDuration = 0.5f;
[SerializeField]
private float _flashFalloffDelayMultiplier = 0.8f;
[SerializeField]
private float _maxFlashDot = 0.7f;
[SerializeField]
private float _minFlashDot = -0.5f;
[SerializeField]
private float _minDotMultiplier = 0.3f;
[SerializeField]
private bool _affectsOwner = true;
[SerializeField]
private float _despawnDelay = 3f;
[SerializeField]
private GameObject _effectRoot;
private TickTimer _despawnTimer;
// NetworkBehaviour INTERFACE
public override void Spawned()
{
base.Spawned();
ShowEffect();
Explode();
}
public override void FixedUpdateNetwork()
{
if (HasStateAuthority == false)
return;
if (_despawnTimer.Expired(Runner) == false)
return;
Runner.Despawn(Object);
}
// MONOBEHAVIOUR
protected void OnEnable()
{
_effectRoot.SetActive(false);
}
// PRIVATE METHODS
private void Explode()
{
if (HasStateAuthority == false)
return;
var position = transform.position + Vector3.up * 0.5f; // Take position slightly above
var flashFalloff = _innerRadius < _outerRadius && _innerFlashValue != _outerFlashValue;
foreach (var player in Context.NetworkGame.ActivePlayers)
{
if (player == null)
continue;
if (_affectsOwner == false && player.Object.InputAuthority == Object.InputAuthority)
continue;
var agent = player.ActiveAgent;
if (agent == null || agent.Health.IsAlive == false)
continue;
var agentHead = agent.transform.position + Vector3.up * 1.8f;
var directionToAgent = agentHead - position;
if (directionToAgent.sqrMagnitude > _outerRadius * _outerRadius)
continue;
float distance = directionToAgent.magnitude;
directionToAgent /= distance; // Normalize
if (Context.Runner.GetPhysicsScene().Raycast(position, directionToAgent, distance, ObjectLayerMask.Default) == true)
continue;
float flash = _innerFlashValue;
float duration = _maxFlashDuration;
if (flashFalloff == true && distance > _innerRadius)
{
float progress = (_outerRadius - _innerRadius) / (distance - _innerRadius);
flash = Mathf.Lerp(_innerFlashValue, _outerFlashValue, progress);
duration = Mathf.Lerp(_maxFlashDuration, _minFlashDuration, progress);
}
if (_minDotMultiplier < 1f)
{
float dot = Vector3.Dot(agent.Character.CharacterController.Data.LookDirection, -directionToAgent);
float dotMultiplier = MathUtility.Map(_minFlashDot, _maxFlashDot, _minDotMultiplier, 1f, dot);
flash *= dotMultiplier;
duration *= dotMultiplier;
}
agent.Senses.SetEyesFlash(flash, duration, duration * _flashFalloffDelayMultiplier);
}
_despawnTimer = TickTimer.CreateFromSeconds(Runner, _despawnDelay);
}
private void ShowEffect()
{
if (Runner.Mode == SimulationModes.Server)
return;
_effectRoot.SetActive(true);
}
}
}