264 lines
5.4 KiB
C#
264 lines
5.4 KiB
C#
|
using System.Collections.Generic;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Events;
|
||
|
using UnityEngine.Networking;
|
||
|
|
||
|
namespace RoR2;
|
||
|
|
||
|
[RequireComponent(typeof(TeamFilter))]
|
||
|
public class BuffWard : NetworkBehaviour
|
||
|
{
|
||
|
public enum BuffWardShape
|
||
|
{
|
||
|
Sphere,
|
||
|
VerticalTube,
|
||
|
Count
|
||
|
}
|
||
|
|
||
|
[Tooltip("The shape of the area")]
|
||
|
public BuffWardShape shape;
|
||
|
|
||
|
[Tooltip("The area of effect.")]
|
||
|
[SyncVar]
|
||
|
public float radius;
|
||
|
|
||
|
[Tooltip("How long between buff pulses in the area of effect.")]
|
||
|
public float interval = 1f;
|
||
|
|
||
|
[Tooltip("The child range indicator object. Will be scaled to the radius.")]
|
||
|
public Transform rangeIndicator;
|
||
|
|
||
|
[Tooltip("The buff type to grant")]
|
||
|
public BuffDef buffDef;
|
||
|
|
||
|
[Tooltip("The buff duration")]
|
||
|
public float buffDuration;
|
||
|
|
||
|
[Tooltip("Should the ward be floored on start")]
|
||
|
public bool floorWard;
|
||
|
|
||
|
[Tooltip("Does the ward disappear over time?")]
|
||
|
public bool expires;
|
||
|
|
||
|
[Tooltip("If set, applies to all teams BUT the one selected.")]
|
||
|
public bool invertTeamFilter;
|
||
|
|
||
|
public float expireDuration;
|
||
|
|
||
|
public bool animateRadius;
|
||
|
|
||
|
public AnimationCurve radiusCoefficientCurve;
|
||
|
|
||
|
[Tooltip("If set, the ward will give you this amount of time to play removal effects.")]
|
||
|
public float removalTime;
|
||
|
|
||
|
private bool needsRemovalTime;
|
||
|
|
||
|
public string removalSoundString = "";
|
||
|
|
||
|
public UnityEvent onRemoval;
|
||
|
|
||
|
public bool requireGrounded;
|
||
|
|
||
|
private TeamFilter teamFilter;
|
||
|
|
||
|
private float buffTimer;
|
||
|
|
||
|
private float rangeIndicatorScaleVelocity;
|
||
|
|
||
|
private float stopwatch;
|
||
|
|
||
|
private float calculatedRadius;
|
||
|
|
||
|
public float Networkradius
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return radius;
|
||
|
}
|
||
|
[param: In]
|
||
|
set
|
||
|
{
|
||
|
SetSyncVar(value, ref radius, 1u);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void Awake()
|
||
|
{
|
||
|
teamFilter = GetComponent<TeamFilter>();
|
||
|
}
|
||
|
|
||
|
private void OnEnable()
|
||
|
{
|
||
|
if ((bool)rangeIndicator)
|
||
|
{
|
||
|
rangeIndicator.gameObject.SetActive(value: true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void OnDisable()
|
||
|
{
|
||
|
if ((bool)rangeIndicator)
|
||
|
{
|
||
|
rangeIndicator.gameObject.SetActive(value: false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void Start()
|
||
|
{
|
||
|
if (removalTime > 0f)
|
||
|
{
|
||
|
needsRemovalTime = true;
|
||
|
}
|
||
|
if (floorWard && Physics.Raycast(base.transform.position, Vector3.down, out var hitInfo, 500f, LayerIndex.world.mask))
|
||
|
{
|
||
|
base.transform.position = hitInfo.point;
|
||
|
base.transform.up = hitInfo.normal;
|
||
|
}
|
||
|
if ((bool)rangeIndicator && expires)
|
||
|
{
|
||
|
ScaleParticleSystemDuration component = rangeIndicator.GetComponent<ScaleParticleSystemDuration>();
|
||
|
if ((bool)component)
|
||
|
{
|
||
|
component.newDuration = expireDuration;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void Update()
|
||
|
{
|
||
|
calculatedRadius = (animateRadius ? (radius * radiusCoefficientCurve.Evaluate(stopwatch / expireDuration)) : radius);
|
||
|
stopwatch += Time.deltaTime;
|
||
|
if (expires && NetworkServer.active)
|
||
|
{
|
||
|
if (needsRemovalTime)
|
||
|
{
|
||
|
if (stopwatch >= expireDuration - removalTime)
|
||
|
{
|
||
|
needsRemovalTime = false;
|
||
|
Util.PlaySound(removalSoundString, base.gameObject);
|
||
|
onRemoval.Invoke();
|
||
|
}
|
||
|
}
|
||
|
else if (expireDuration <= stopwatch)
|
||
|
{
|
||
|
Object.Destroy(base.gameObject);
|
||
|
}
|
||
|
}
|
||
|
if ((bool)rangeIndicator)
|
||
|
{
|
||
|
float num = Mathf.SmoothDamp(rangeIndicator.localScale.x, calculatedRadius, ref rangeIndicatorScaleVelocity, 0.2f);
|
||
|
rangeIndicator.localScale = new Vector3(num, num, num);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void FixedUpdate()
|
||
|
{
|
||
|
if (!NetworkServer.active)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
buffTimer -= Time.fixedDeltaTime;
|
||
|
if (!(buffTimer <= 0f))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
buffTimer = interval;
|
||
|
float radiusSqr = calculatedRadius * calculatedRadius;
|
||
|
Vector3 position = base.transform.position;
|
||
|
if (invertTeamFilter)
|
||
|
{
|
||
|
for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
|
||
|
{
|
||
|
if (teamIndex != teamFilter.teamIndex)
|
||
|
{
|
||
|
BuffTeam(TeamComponent.GetTeamMembers(teamIndex), radiusSqr, position);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BuffTeam(TeamComponent.GetTeamMembers(teamFilter.teamIndex), radiusSqr, position);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void BuffTeam(IEnumerable<TeamComponent> recipients, float radiusSqr, Vector3 currentPosition)
|
||
|
{
|
||
|
if (!NetworkServer.active || !buffDef)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
foreach (TeamComponent recipient in recipients)
|
||
|
{
|
||
|
Vector3 vector = recipient.transform.position - currentPosition;
|
||
|
if (shape == BuffWardShape.VerticalTube)
|
||
|
{
|
||
|
vector.y = 0f;
|
||
|
}
|
||
|
if (vector.sqrMagnitude <= radiusSqr)
|
||
|
{
|
||
|
CharacterBody component = recipient.GetComponent<CharacterBody>();
|
||
|
if ((bool)component && (!requireGrounded || !component.characterMotor || component.characterMotor.isGrounded))
|
||
|
{
|
||
|
component.AddTimedBuff(buffDef.buffIndex, buffDuration);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void OnValidate()
|
||
|
{
|
||
|
if (!buffDef)
|
||
|
{
|
||
|
Debug.LogWarningFormat(this, "BuffWard {0} has no buff specified.", this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void UNetVersion()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public override bool OnSerialize(NetworkWriter writer, bool forceAll)
|
||
|
{
|
||
|
if (forceAll)
|
||
|
{
|
||
|
writer.Write(radius);
|
||
|
return true;
|
||
|
}
|
||
|
bool flag = false;
|
||
|
if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
|
||
|
{
|
||
|
if (!flag)
|
||
|
{
|
||
|
writer.WritePackedUInt32(base.syncVarDirtyBits);
|
||
|
flag = true;
|
||
|
}
|
||
|
writer.Write(radius);
|
||
|
}
|
||
|
if (!flag)
|
||
|
{
|
||
|
writer.WritePackedUInt32(base.syncVarDirtyBits);
|
||
|
}
|
||
|
return flag;
|
||
|
}
|
||
|
|
||
|
public override void OnDeserialize(NetworkReader reader, bool initialState)
|
||
|
{
|
||
|
if (initialState)
|
||
|
{
|
||
|
radius = reader.ReadSingle();
|
||
|
return;
|
||
|
}
|
||
|
int num = (int)reader.ReadPackedUInt32();
|
||
|
if (((uint)num & (true ? 1u : 0u)) != 0)
|
||
|
{
|
||
|
radius = reader.ReadSingle();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void PreStartClient()
|
||
|
{
|
||
|
}
|
||
|
}
|