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(); } 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(); 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 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(); 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() { } }