// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts, // for ex. property getter/setter access. To get optimal decompilation results, please manually add the missing references to the list of loaded assemblies. // C:\SteamLibrary\steamapps\common\Risk of Rain 2\Risk of Rain 2_Data\Managed\RoR2.dll // RoR2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // Global type: // Architecture: AnyCPU (64-bit preferred) // Runtime: v4.0.30319 // This assembly was compiled using the /deterministic option. // Hash algorithm: SHA1 using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using AK.Wwise; using Assets.RoR2.Scripts.Platform; using EntityStates; using EntityStates.AI; using EntityStates.AurelioniteHeart; using EntityStates.Barrel; using EntityStates.BrotherMonster; using EntityStates.ChildMonster; using EntityStates.Destructible; using EntityStates.Drone; using EntityStates.Engi.EngiBubbleShield; using EntityStates.Engi.Mine; using EntityStates.Engi.MineDeployer; using EntityStates.EngiTurret; using EntityStates.EngiTurret.EngiTurretWeapon; using EntityStates.FalseSon; using EntityStates.FalseSonBoss; using EntityStates.GreaterWispMonster; using EntityStates.GummyClone; using EntityStates.Headstompers; using EntityStates.Heretic; using EntityStates.ImpBossMonster; using EntityStates.InfiniteTowerSafeWard; using EntityStates.Interactables.GoldBeacon; using EntityStates.LaserTurbine; using EntityStates.LightningStorm; using EntityStates.Loader; using EntityStates.LockedMage; using EntityStates.Mage.Weapon; using EntityStates.MagmaWorm; using EntityStates.MajorConstruct.Stance; using EntityStates.Merc; using EntityStates.Missions.Arena.NullWard; using EntityStates.Missions.Goldshores; using EntityStates.Missions.Moon; using EntityStates.MoonElevator; using EntityStates.ParentMonster; using EntityStates.Railgunner.Backpack; using EntityStates.Railgunner.Reload; using EntityStates.Railgunner.Scope; using EntityStates.Railgunner.Weapon; using EntityStates.RoboBallMini.Weapon; using EntityStates.Scrapper; using EntityStates.Seeker; using EntityStates.ShrineHalcyonite; using EntityStates.ShrineRebirth; using EntityStates.Sniper.Scope; using EntityStates.SurvivorPod; using EntityStates.TimedChest; using EntityStates.Toolbot; using EntityStates.Treebot.UnlockInteractable; using EntityStates.Treebot.Weapon; using EntityStates.VagrantMonster; using EntityStates.VoidJailer.Weapon; using EntityStates.VoidRaidCrab; using EntityStates.VoidRaidCrab.Joint; using EntityStates.VoidRaidCrab.Leg; using EntityStates.VoidSurvivor.CorruptMode; using EntityStates.VoidSurvivor.Weapon; using Epic.OnlineServices; using Epic.OnlineServices.Achievements; using Epic.OnlineServices.Auth; using Epic.OnlineServices.Connect; using Epic.OnlineServices.Ecom; using Epic.OnlineServices.Friends; using Epic.OnlineServices.Leaderboards; using Epic.OnlineServices.Lobby; using Epic.OnlineServices.Logging; using Epic.OnlineServices.P2P; using Epic.OnlineServices.Platform; using Epic.OnlineServices.Stats; using Epic.OnlineServices.UI; using Epic.OnlineServices.UserInfo; using Facepunch.Steamworks; using Generics.Dynamics; using Grumpy; using Grumpy.Util; using HG; using HG.AssetManagement; using HG.AsyncOperations; using HG.BlendableTypes; using HG.Collections.Generic; using HG.Coroutines; using HG.GeneralSerializer; using HG.Reflection; using HGsignup.Service; using JetBrains.Annotations; using KinematicCharacterController; using Rewired; using Rewired.Dev; using Rewired.Integration.UnityUI; using Rewired.UI; using RoR2; using RoR2.Achievements; using RoR2.Artifacts; using RoR2.Audio; using RoR2.CameraModes; using RoR2.CharacterAI; using RoR2.CharacterSpeech; using RoR2.ContentManagement; using RoR2.ConVar; using RoR2.DirectionalSearch; using RoR2.EntitlementManagement; using RoR2.EntityLogic; using RoR2.ExpansionManagement; using RoR2.Hologram; using RoR2.HudOverlay; using RoR2.Items; using RoR2.Mecanim; using RoR2.Modding; using RoR2.Navigation; using RoR2.Networking; using RoR2.Orbs; using RoR2.PostProcess; using RoR2.PostProcessing; using RoR2.Projectile; using RoR2.RemoteGameBrowser; using RoR2.Scripts.GameBehaviors.UI; using RoR2.Scripts.Tutorial; using RoR2.Scripts.Utility; using RoR2.Skills; using RoR2.Stats; using RoR2.UI; using RoR2.UI.LogBook; using RoR2.UI.MainMenu; using RoR2.VoidRaidCrab; using RoR2.WwiseUtils; using SimpleJSON; using SteamAPIValidator; using Tayx.Graphy; using Tayx.Graphy.Utils; using ThreeEyedGames; using TMPro; using UDPHelperSpace; using Unity; using Unity.Collections; using Unity.Jobs; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets.ResourceLocators; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.Experimental.Rendering; using UnityEngine.Networking; using UnityEngine.Networking.Types; using UnityEngine.Playables; using UnityEngine.Profiling; using UnityEngine.Rendering; using UnityEngine.Rendering.PostProcessing; using UnityEngine.ResourceManagement; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.ResourceManagement.ResourceLocations; using UnityEngine.ResourceManagement.ResourceProviders; using UnityEngine.SceneManagement; using UnityEngine.Serialization; using UnityEngine.UI; using Zio; using Zio.FileSystems; [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: HG.Reflection.SearchableAttribute.OptIn] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] public class DevotedLemurianController : MonoBehaviour { private CharacterMaster _lemurianMaster; private DevotionInventoryController _devotionInventoryController; private ItemIndex _devotionItem; private int _devotedEvolutionLevel; private float _leashDistSq = 160000f; private const float minTeleportDistance = 10f; private const float maxTeleportDistance = 40f; public int DevotedEvolutionLevel { get { return _devotedEvolutionLevel; } set { _devotedEvolutionLevel = value; } } public ItemIndex DevotionItem => _devotionItem; public CharacterBody LemurianBody => _lemurianMaster.GetBody(); public RoR2.Inventory LemurianInventory => _lemurianMaster.inventory; private void Start() { StartCoroutine(TryTeleport()); } private bool CheckIfNeedTeleport() { if (!LemurianBody.hasEffectiveAuthority) { return false; } CharacterMaster characterMaster = (_lemurianMaster ? _lemurianMaster.minionOwnership.ownerMaster : null); CharacterBody characterBody = (characterMaster ? characterMaster.GetBody() : null); if (!characterBody) { return false; } UnityEngine.Vector3 corePosition = characterBody.corePosition; UnityEngine.Vector3 corePosition2 = LemurianBody.corePosition; if ((((bool)LemurianBody.characterMotor && LemurianBody.characterMotor.walkSpeed > 0f) || LemurianBody.moveSpeed > 0f) && (corePosition2 - corePosition).sqrMagnitude > _leashDistSq) { return true; } return false; } private IEnumerator TryTeleport() { UnityEngine.Debug.Log("try teleport"); while ((bool)_lemurianMaster) { while (!LemurianBody || !CheckIfNeedTeleport()) { yield return new WaitForSeconds(1f); } CharacterMaster characterMaster = (_lemurianMaster ? _lemurianMaster.minionOwnership.ownerMaster : null); CharacterBody ownerBody = characterMaster.GetBody(); NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); List list = nodeGraph.FindNodesInRangeWithFlagConditions(ownerBody.transform.position, 3f, 20f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false); while (list.Count == 0) { UnityEngine.Debug.Log("no valid node to teleport"); yield return new WaitForSeconds(1f); list = nodeGraph.FindNodesInRangeWithFlagConditions(ownerBody.transform.position, 3f, 20f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false); } while (list.Count > 0) { UnityEngine.Debug.Log("teleporting"); int index = UnityEngine.Random.Range(0, list.Count); NodeGraph.NodeIndex nodeIndex = list[index]; if (nodeGraph.GetNodePosition(nodeIndex, out var position)) { TeleportHelper.TeleportBody(LemurianBody, position); GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(LemurianBody.gameObject); if ((bool)teleportEffectPrefab) { EffectManager.SimpleEffect(teleportEffectPrefab, position, UnityEngine.Quaternion.identity, transmit: true); } break; } } yield return new WaitForSeconds(1f); } UnityEngine.Debug.Log("finish try teleport"); } public void InitializeDevotedLemurian(ItemIndex itemIndex, DevotionInventoryController devotionInventoryController) { _devotionItem = itemIndex; _devotionInventoryController = devotionInventoryController; _lemurianMaster = GetComponent(); } public void OnDevotedBodyDead() { if (_devotionInventoryController.HasItem(RoR2Content.Items.ExtraLife)) { _devotionInventoryController.RemoveItem(RoR2Content.Items.ExtraLife.itemIndex); } else { _devotionInventoryController.RemoveItem(_devotionItem, _devotedEvolutionLevel + 1); _devotionInventoryController.DropScrapOnDeath(_devotionItem, LemurianBody); } _devotionInventoryController.UpdateAllMinions(); } } public class activateGraphy : MonoBehaviour { private void Start() { RoRGraphyControl.verifyInst(default(ConCommandArgs)); } } public class DelusionPickerController : MonoBehaviour { private void Start() { } private void Update() { } } public class UnseenHandIndicator : MonoBehaviour { public UnityEngine.Color customColor = UnityEngine.Color.magenta; private Dictionary pairs = new Dictionary(); private void OnTriggerEnter(Collider other) { AddIndictator(other); } private void OnTriggerExit(Collider other) { DelIndictator(other); } private void AddIndictator(Collider target) { if (pairs.ContainsKey(target)) { return; } CharacterModel characterModel = target.GetComponent()?.modelTransform?.GetComponent(); if (characterModel == null || characterModel.body.teamComponent.teamIndex != TeamIndex.Monster) { return; } CharacterModel.RendererInfo[] baseRendererInfos = characterModel.baseRendererInfos; for (int i = 0; i < baseRendererInfos.Length; i++) { CharacterModel.RendererInfo rendererInfo = baseRendererInfos[i]; if (!rendererInfo.ignoreOverlays) { Highlight highlight = base.gameObject.AddComponent(); highlight.CustomColor = customColor; highlight.highlightColor = Highlight.HighlightColor.custom; highlight.targetRenderer = rendererInfo.renderer; highlight.strength = 1f; highlight.isOn = true; pairs.Add(target, highlight); break; } } } private void DelIndictator(Collider target) { if (pairs.ContainsKey(target)) { UnityEngine.Object.Destroy(pairs[target]); pairs.Remove(target); } } } public class FPSCounter : MonoBehaviour { private TextMeshProUGUI unityText; private TextMeshProUGUI unityVarText; private TextMeshProUGUI cpuText; private TextMeshProUGUI gpuText; private TextMeshProUGUI memText; private static float[] unitySamples; private static float[] cpuSamples; private static float[] gpuSamples; public static int numSamples = 30; private static int sampleIndex = 0; private int frameSampleIndex; public GameObject rootObject; public float timingCaptureFrequency = 2f; private float captureTimer; private char[] tempArray = new char[64]; private uint numTimings = 5u; private FrameTiming[] outTimings; private long prevAllocatedBytes; private static int waitTurn = 0; private static int waitIndex = 0; private static int maxWaitIndex = 5; public static float currentFPS = 30f; private void Start() { RoR2Application.onUpdate += UpdateFPSLimitVars; unitySamples = new float[numSamples]; base.gameObject.SetActive(value: false); } private int PutValue(int value, char[] array, int startIndex, bool addPlusIfPositive = false, bool disableMinusIfNegative = false) { if (value >= 0) { if (addPlusIfPositive) { array[startIndex] = '+'; startIndex++; } } else if (!disableMinusIfNegative) { value = -value; array[startIndex] = '-'; startIndex++; } int num = 10; int num2 = 1; while (num <= value && num != 0) { num *= 10; num2++; } num /= 10; if (num == 0) { num = 1; } for (int i = 0; i < num2; i++) { int digit = GetDigit(value, num); num /= 10; array[startIndex + i] = (char)(digit + 48); } return startIndex + num2; } private int PutValue(int value, char[] array, int startIndex, int numDigits) { int num = 10; int num2 = 1; while (num <= value) { num *= 10; num2++; } num /= 10; if (num2 < numDigits) { for (int i = num2; i < numDigits; i++) { array[startIndex++] = '0'; } } for (int j = 0; j < num2; j++) { int digit = GetDigit(value, num); num /= 10; array[startIndex + j] = (char)(digit + 48); } return startIndex + num2; } private int PutValue(double value, char[] array, int startIndex, int numDecimalPlaces = 0, bool addPlusIfPositive = false) { int value2 = (int)value; startIndex = PutValue(value2, array, startIndex, addPlusIfPositive); if (numDecimalPlaces == 0) { return startIndex; } array[startIndex++] = '.'; double num = 10.0; for (int i = 1; i < numDecimalPlaces; i++) { num *= 10.0; } double num2 = Math.Abs(value); int value3 = (int)((num2 - Math.Floor(num2)) * num); startIndex = PutValue(value3, array, startIndex, numDecimalPlaces); return startIndex; } private int PutValue(float value, char[] array, int startIndex, int numDecimalPlaces = 0, bool addPlusIfPositive = false) { int value2 = (int)value; startIndex = PutValue(value2, array, startIndex, addPlusIfPositive); if (numDecimalPlaces == 0) { return startIndex; } array[startIndex++] = '.'; float num = 10f; for (int i = 1; i < numDecimalPlaces; i++) { num *= 10f; } float num2 = Mathf.Abs(value); int value3 = (int)((num2 - Mathf.Floor(num2)) * num); startIndex = PutValue(value3, array, startIndex, numDecimalPlaces); return startIndex; } private int PutValue(string value, char[] array, int startIndex) { for (int i = 0; i < value.Length; i++) { array[startIndex + i] = value[i]; } return startIndex + value.Length; } private int GetDigit(int value, int place) { if (place == 1) { return value % 10; } int num = place * 10; int num2 = value % num; int num3 = value % place; return (num2 - num3) / place; } public static int GetWaitIndex() { waitIndex++; if (waitIndex > maxWaitIndex) { waitIndex = 0; } return waitIndex; } public static bool CheckFPSQueue(ref int waitIndex) { if (waitIndex == 0) { waitIndex = GetWaitIndex(); } if (currentFPS < 28f && waitIndex != waitTurn) { return false; } return true; } private static void UpdateFPSLimitVars() { waitTurn++; if (waitTurn > maxWaitIndex) { waitTurn = 0; } CalculateFramerate(); } private static void CalculateFramerate() { unitySamples[sampleIndex++] = 1f / Time.unscaledDeltaTime; if (sampleIndex == numSamples) { sampleIndex = 0; } float num = 0f; for (int i = 0; i < numSamples; i++) { num += unitySamples[i]; } num /= (float)numSamples; currentFPS = num; } private void Update() { } } public static class AkGameObjUtil { public static void SetAkGameObjectStatic(GameObject gameObj, bool staticSetting) { if (gameObj.TryGetComponent(out var component)) { component.isStaticAfterDelay = staticSetting; } } } public class ReadOnlyAttribute : PropertyAttribute { } [Serializable] public struct CubicBezier3 { public UnityEngine.Vector3 a; public UnityEngine.Vector3 b; public UnityEngine.Vector3 c; public UnityEngine.Vector3 d; public UnityEngine.Vector3 p0 => a; public UnityEngine.Vector3 p1 => d; public UnityEngine.Vector3 v0 => b - a; public UnityEngine.Vector3 v1 => c - d; public static CubicBezier3 FromVelocities(UnityEngine.Vector3 p0, UnityEngine.Vector3 v0, UnityEngine.Vector3 p1, UnityEngine.Vector3 v1) { CubicBezier3 result = default(CubicBezier3); result.a = p0; result.b = p0 + v0; result.c = p1 + v1; result.d = p1; return result; } public UnityEngine.Vector3 Evaluate(float t) { float num = t * t; float num2 = num * t; return a + 3f * t * (b - a) + 3f * num * (c - 2f * b + a) + num2 * (d - 3f * c + 3f * b - a); } public void ToVertices(UnityEngine.Vector3[] results) { ToVertices(results, 0, results.Length); } public void ToVertices(UnityEngine.Vector3[] results, int spanStart, int spanLength) { float num = 1f / (float)(spanLength - 1); for (int i = 0; i < spanLength; i++) { results[spanStart++] = Evaluate((float)i * num); } } public float ApproximateLength(int samples) { float num = 1f / (float)(samples - 1); float num2 = 0f; UnityEngine.Vector3 vector = p0; for (int i = 1; i < samples; i++) { UnityEngine.Vector3 vector2 = Evaluate((float)i * num); num2 += UnityEngine.Vector3.Distance(vector, vector2); vector = vector2; } return num2; } } public class ElectricEffect : MonoBehaviour { public LineRenderer lightningLineRenderer; public List lightningTextures = new List(); private Material lineRendererMat; private int counter; private int textureNum; public int interval = 3; public float lineWidth = 1f; private void Start() { lineRendererMat = lightningLineRenderer.material; lightningLineRenderer.startWidth = lineWidth; lightningLineRenderer.endWidth = lineWidth; } private void Update() { if (!(Time.timeScale > 0f)) { return; } if (counter >= interval) { if (textureNum == lightningTextures.Count) { textureNum = 0; } lineRendererMat.SetTexture("_MainTex", lightningTextures[textureNum]); textureNum++; counter = 0; } counter++; } } public class FocusedConvergenceAnimator : MonoBehaviour { public bool animateX; public bool animateY; public bool animateZ; private AnimationCurve animCurve; private float xScale; private float yScale; private float zScale; public float scaleTime = 4f; private float tempScaleTimer = 4f; public float rotateTime = 4f; private float tempRotateTimer = 4f; private float scaleMax = 1.2f; private float scaleMin = 0.8f; private bool isScaling; private float xRotate; private float xRotateTop; private float yRotate; private float yRotateTop; private float zRotate; private float zRotateTop; private void Start() { tempScaleTimer = 0f; tempRotateTimer = 0f; animCurve = AnimationCurve.EaseInOut(0f, scaleMin, 1f, scaleMax); } private void FixedUpdate() { if (isScaling) { tempScaleTimer += Time.deltaTime; if (tempScaleTimer <= scaleTime * 0.333f) { float t = tempScaleTimer / (scaleTime * 0.333f); xScale = Mathf.Lerp(1f, scaleMax, t); yScale = Mathf.Lerp(1f, scaleMax, t); zScale = Mathf.Lerp(1f, scaleMax, t); } if (tempScaleTimer > scaleTime * 0.333f && tempScaleTimer <= scaleTime * 0.666f) { float t = (tempScaleTimer - scaleTime * 0.333f) / (scaleTime * 0.333f); xScale = Mathf.Lerp(scaleMax, scaleMin, t); yScale = Mathf.Lerp(scaleMax, scaleMin, t); zScale = Mathf.Lerp(scaleMax, scaleMin, t); } if (tempScaleTimer > scaleTime * 0.666f) { float t = (tempScaleTimer - scaleTime * 0.666f) / (scaleTime * 0.333f); xScale = Mathf.Lerp(scaleMin, 1f, t); yScale = Mathf.Lerp(scaleMin, 1f, t); zScale = Mathf.Lerp(scaleMin, 1f, t); } if (tempScaleTimer >= scaleTime) { isScaling = false; tempRotateTimer = 0f; xRotateTop = UnityEngine.Random.Range(0f, 10f); yRotateTop = UnityEngine.Random.Range(0f, 10f); zRotateTop = UnityEngine.Random.Range(0f, 10f); } else { base.transform.localScale = new UnityEngine.Vector3(xScale, yScale, zScale); } } else { tempRotateTimer += Time.deltaTime; if (tempRotateTimer <= rotateTime * 0.5f) { float t2 = tempRotateTimer / (rotateTime * 0.5f); xRotate = Mathf.Lerp(0f, xRotateTop, t2); yRotate = Mathf.Lerp(0f, yRotateTop, t2); zRotate = Mathf.Lerp(0f, zRotateTop, t2); } else { float t2 = (tempRotateTimer - rotateTime * 0.5f) / (rotateTime * 0.5f); xRotate = Mathf.Lerp(xRotateTop, 0f, t2); yRotate = Mathf.Lerp(yRotateTop, 0f, t2); zRotate = Mathf.Lerp(zRotateTop, 0f, t2); } if (tempRotateTimer >= rotateTime) { isScaling = true; tempScaleTimer = 0f; } else { base.transform.Rotate(new UnityEngine.Vector3(xRotate, yRotate, zRotate)); } } } } public class GrandparentEnergyFXController : MonoBehaviour { public List energyFXParticles = new List(); [HideInInspector] public GameObject portalObject; private bool isPortalSoundPlaying; private void Start() { } private void FixedUpdate() { if (!(portalObject != null)) { return; } if (!isPortalSoundPlaying) { if (portalObject.transform.localScale == UnityEngine.Vector3.zero) { Util.PlaySound("Play_grandparent_portal_loop", portalObject); isPortalSoundPlaying = false; } } else if (portalObject.transform.localScale != UnityEngine.Vector3.zero) { Util.PlaySound("Stop_grandparent_portal_loop", portalObject); isPortalSoundPlaying = true; } } public void TurnOffFX() { for (int i = 0; i < energyFXParticles.Count; i++) { ParticleSystem.EmissionModule emission = energyFXParticles[i].emission; emission.enabled = false; } if (portalObject != null) { ParticleSystem componentInChildren = portalObject.GetComponentInChildren(); if (componentInChildren != null) { ParticleSystem.EmissionModule emission2 = componentInChildren.emission; emission2.enabled = false; } } } public void TurnOnFX() { for (int i = 0; i < energyFXParticles.Count; i++) { ParticleSystem.EmissionModule emission = energyFXParticles[i].emission; emission.enabled = true; } if (portalObject != null) { ParticleSystem componentInChildren = portalObject.GetComponentInChildren(); if (componentInChildren != null) { ParticleSystem.EmissionModule emission2 = componentInChildren.emission; emission2.enabled = true; } } } } public class MaulingRock : NetworkBehaviour { private HealthComponent myHealthComponent; public GameObject deathEffect; public float blastRadius = 1f; public float damage = 10f; public float damageCoefficient = 1f; public float scaleVarianceLow = 0.8f; public float scaleVarianceHigh = 1.2f; public float verticalOffset; [SyncVar] private float scale; public float Networkscale { get { return scale; } [param: In] set { SetSyncVar(value, ref scale, 1u); } } public override void OnStartServer() { base.OnStartServer(); Networkscale = UnityEngine.Random.Range(scaleVarianceLow, scaleVarianceHigh); } private void Start() { myHealthComponent = GetComponent(); base.transform.localScale = new UnityEngine.Vector3(scale, scale, scale); } private void FixedUpdate() { if (NetworkServer.active && myHealthComponent != null && !myHealthComponent.alive) { if (deathEffect != null) { EffectManager.SpawnEffect(deathEffect, new EffectData { origin = base.transform.position, scale = blastRadius }, transmit: true); } UnityEngine.Object.Destroy(base.gameObject); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(scale); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(scale); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { scale = reader.ReadSingle(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { scale = reader.ReadSingle(); } } public override void PreStartClient() { } } public delegate void EmptyDelegate(); public class MaulingRockZoneManager : MonoBehaviour { public List maulingRockProjectilePrefabs = new List(); public Transform startZonePoint1; public Transform startZonePoint2; public Transform endZonePoint1; public Transform endZonePoint2; public static float baseDuration = 60f; public float knockbackForce = 10000f; private UnityEngine.Vector3 vectorBetweenStartPoints = UnityEngine.Vector3.zero; private UnityEngine.Vector3 vectorBetweenEndPoints = UnityEngine.Vector3.zero; private UnityEngine.Vector3 MediumRockBump = UnityEngine.Vector3.zero; private UnityEngine.Vector3 LargeRockBump = UnityEngine.Vector3.zero; private int salvoMaximumCount = 10; private float timeBetweenSalvoShotsLow = 0.1f; private float timeBetweenSalvoShotsHigh = 1f; private float timeBetweenSalvosLow = 3f; private float timeBetweenSalvosHigh = 5f; private int salvoRockCount; private int currentSalvoCount; private void Awake() { if (!NetworkServer.active) { base.enabled = false; } } private void Start() { vectorBetweenStartPoints = startZonePoint2.position - startZonePoint1.position; vectorBetweenEndPoints = endZonePoint2.position - endZonePoint1.position; FireSalvo(); } private void FireSalvo() { salvoRockCount = UnityEngine.Random.Range(0, salvoMaximumCount); currentSalvoCount = 0; FireRock(); } private void FireRock() { GameObject gameObject = maulingRockProjectilePrefabs[UnityEngine.Random.Range(0, maulingRockProjectilePrefabs.Count)]; UnityEngine.Vector3 vector = startZonePoint1.position + UnityEngine.Random.Range(0f, 1f) * vectorBetweenStartPoints; UnityEngine.Vector3 vector2 = endZonePoint1.position + UnityEngine.Random.Range(0f, 1f) * vectorBetweenEndPoints; MaulingRock component = gameObject.GetComponent(); float num = UnityEngine.Random.Range(0f, 4f); num += component.verticalOffset; vector = new UnityEngine.Vector3(vector.x, vector.y + num, vector.z); num = UnityEngine.Random.Range(0f, 4f); num += component.verticalOffset; vector2 = new UnityEngine.Vector3(vector2.x, vector2.y + num, vector2.z); Ray ray = new Ray(vector, vector2 - vector); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = gameObject; fireProjectileInfo.position = ray.origin; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction); fireProjectileInfo.owner = null; fireProjectileInfo.damage = component.damage * component.damageCoefficient; fireProjectileInfo.force = knockbackForce; fireProjectileInfo.crit = false; fireProjectileInfo.damageColorIndex = DamageColorIndex.Default; fireProjectileInfo.target = null; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); currentSalvoCount++; StartCoroutine(WaitToFireAnotherRock()); } public IEnumerator WaitToFireAnotherSalvo() { float seconds = UnityEngine.Random.Range(timeBetweenSalvosLow, timeBetweenSalvosHigh); yield return new WaitForSeconds(seconds); FireSalvo(); } public IEnumerator WaitToFireAnotherRock() { float seconds = UnityEngine.Random.Range(timeBetweenSalvoShotsLow, timeBetweenSalvoShotsHigh); if (currentSalvoCount >= salvoRockCount) { yield return null; StartCoroutine(WaitToFireAnotherSalvo()); } else { yield return new WaitForSeconds(seconds); FireRock(); } } } public class MoveCurve : MonoBehaviour { public bool animateX; public bool animateY; public bool animateZ; public float curveScale = 1f; public AnimationCurve moveCurve; private float xValue; private float yValue; private float zValue; private void Start() { } private void Update() { if (animateX) { xValue = moveCurve.Evaluate(Time.time % (float)moveCurve.length) * curveScale; } else { xValue = base.transform.localPosition.x; } if (animateY) { yValue = moveCurve.Evaluate(Time.time % (float)moveCurve.length) * curveScale; } else { yValue = base.transform.localPosition.y; } if (animateZ) { zValue = moveCurve.Evaluate(Time.time % (float)moveCurve.length) * curveScale; } else { zValue = base.transform.localPosition.z; } base.transform.localPosition = new UnityEngine.Vector3(xValue, yValue, zValue); } } public class OnParticleEndEvent : MonoBehaviour { public ParticleSystem particleSystemToTrack; public UnityEvent onEnd; private bool particleEnded; public void Update() { if ((bool)particleSystemToTrack && !particleSystemToTrack.IsAlive() && !particleEnded) { particleEnded = true; onEnd.Invoke(); } } } public class ParentEnergyFXController : MonoBehaviour { public List energyFXParticles = new List(); public ParticleSystem loomingPresenceParticles; private void Start() { } private void FixedUpdate() { } public void TurnOffFX() { for (int i = 0; i < energyFXParticles.Count; i++) { ParticleSystem.EmissionModule emission = energyFXParticles[i].emission; emission.enabled = false; } } public void TurnOnFX() { for (int i = 0; i < energyFXParticles.Count; i++) { ParticleSystem.EmissionModule emission = energyFXParticles[i].emission; emission.enabled = true; } } public void SetLoomingPresenceParticles(bool setTo) { ParticleSystem.EmissionModule emission = loomingPresenceParticles.emission; emission.enabled = setTo; } } public class RJShroomBounce : MonoBehaviour { private Animator shroomAnimator; public void Start() { shroomAnimator = GetComponent(); } public void Bounce() { shroomAnimator.Play("Bounce", 0); } } public class RootJungleFXController : MonoBehaviour { public int minSystemsActive = 2; public int maxSystemsActive = 4; public float minActiveTime = 10f; public float maxActiveTime = 30f; private int numActive; private float timeActive; private float effectsTimer; private bool timeFX; public List FXParticles = new List(); private void Start() { TurnOffFX(FXParticles.Count); } private void FixedUpdate() { if (timeFX) { effectsTimer -= Time.fixedDeltaTime; if (effectsTimer <= 0f) { timeFX = false; TurnOffFX(numActive); } } } public void SetupParticles() { numActive = UnityEngine.Random.Range(minSystemsActive, maxSystemsActive + 1); timeActive = UnityEngine.Random.Range(minActiveTime, maxActiveTime); effectsTimer = timeActive; FXParticles = Shuffle(FXParticles); TurnOnFX(numActive); timeFX = true; } public void TurnOffFX(int amount) { for (int i = 0; i < amount; i++) { ParticleSystem.EmissionModule emission = FXParticles[i].emission; emission.enabled = false; } SetupParticles(); } public void TurnOnFX(int amount) { for (int i = 0; i < amount; i++) { ParticleSystem.EmissionModule emission = FXParticles[i].emission; emission.enabled = true; } } public static List Shuffle(List list) { System.Random random = new System.Random(); for (int i = 0; i < list.Count; i++) { int index = random.Next(0, i); T value = list[index]; list[index] = list[i]; list[i] = value; } return list; } } public class SetRandomRotation : MonoBehaviour { public bool setRandomXRotation; public bool setRandomYRotation; public bool setRandomZRotation; private void Start() { UnityEngine.Vector3 localEulerAngles = base.transform.localEulerAngles; if (setRandomXRotation) { float x = UnityEngine.Random.Range(0f, 359f); localEulerAngles.x = x; } if (setRandomYRotation) { float y = UnityEngine.Random.Range(0f, 359f); localEulerAngles.y = y; } if (setRandomZRotation) { float z = UnityEngine.Random.Range(0f, 359f); localEulerAngles.z = z; } base.transform.localEulerAngles = localEulerAngles; } private void Update() { } } public class SetRandomScale : MonoBehaviour { public float minimumScale; public float maximumScale; private void Start() { float num = UnityEngine.Random.Range(minimumScale, maximumScale); base.transform.localScale = UnityEngine.Vector3.one * num; } } public class Spinner : MonoBehaviour { private float randRotationSpeed; private int randNumX; private int randNumY; private int randNumZ; private float randZeroOrOneX; private float randZeroOrOneY; private float randZeroOrOneZ; private bool shouldUpdate = true; private void Start() { if (!NetworkServer.active) { base.enabled = false; return; } if (base.gameObject.isStatic) { base.enabled = false; return; } UnityEngine.Random.Range(0f, 360f); UnityEngine.Random.Range(0f, 360f); UnityEngine.Random.Range(0f, 360f); UnityEngine.Random.Range(0f, 360f); base.gameObject.transform.rotation = UnityEngine.Random.rotationUniform; randRotationSpeed = UnityEngine.Random.Range(0.2f, 1f) / Time.deltaTime; randNumX = UnityEngine.Random.Range(0, 2); randNumY = UnityEngine.Random.Range(0, 2); randNumZ = UnityEngine.Random.Range(0, 2); randZeroOrOneX = randNumX; randZeroOrOneY = randNumY; randZeroOrOneZ = randNumZ; if (randZeroOrOneX == 0f && randZeroOrOneY == 0f && randZeroOrOneZ == 0f) { randZeroOrOneX = 1f; randZeroOrOneY = 1f; randZeroOrOneZ = 1f; } } private void OnBecameVisible() { shouldUpdate = true; } private void OnBecameInvisible() { shouldUpdate = false; } private void Update() { if (shouldUpdate) { base.gameObject.transform.Rotate(new UnityEngine.Vector3(randZeroOrOneX, randZeroOrOneY, randZeroOrOneZ), randRotationSpeed * Time.deltaTime); } } } public class JobCleaner : MonoBehaviour { public static JobCleaner instance; public List jobsToClean; private void Awake() { if (instance == null) { instance = this; } jobsToClean = new List(); } private void OnDestroy() { if (instance == this) { instance = null; } if (jobsToClean.Count <= 0) { return; } UnityEngine.Debug.LogError("JOBCLEANER HAS JOBS TO CLEAN BEFORE BEING DESTROYED"); while (jobsToClean.Count > 0) { for (int num = jobsToClean.Count - 1; num >= 0; num--) { if (jobsToClean[num].handle.IsCompleted) { jobsToClean[num].handle.Complete(); jobsToClean[num].Dispose(); jobsToClean.RemoveAt(num); } } } UnityEngine.Debug.LogError("JOBCLEANER FINISHED CLEANING JOBS, CAN DIE HAPPY NOW"); } private void LateUpdate() { if (jobsToClean.Count > 0) { int index = jobsToClean.Count - 1; if (jobsToClean[index].handle.IsCompleted) { jobsToClean[index].handle.Complete(); jobsToClean[index].Dispose(); jobsToClean.RemoveAt(index); } } } } public class JobWrapper { public JobHandle handle; public bool jobScheduled; public bool isComplete { get { if (jobScheduled) { return handle.IsCompleted; } return true; } } public virtual void Dispose() { UnityEngine.Debug.LogError("Error: No overload for JobWrapper.Dispose()"); } public virtual void Initialize(UnityEngine.Object data) { UnityEngine.Debug.LogError("Error: No overload for JobWrapper:Initialize()"); } public virtual void Schedule() { JobHandle.ScheduleBatchedJobs(); jobScheduled = true; } public void Complete() { handle.Complete(); jobScheduled = false; } public bool SendToCleaner() { if (JobCleaner.instance != null) { JobCleaner.instance.jobsToClean.Add(this); return true; } return false; } } public class ConditionalLOD : MonoBehaviour { public int PS4lod = -1; public int XBoxlod = -1; public int Switchlod = 1; public int SwitchHandHeldlod = 2; public int Defaultlod = -1; public int maxlod; private LODGroup lg; private void Start() { } private void OnEnable() { GetRenderers(); int lODState = GetLODState(); SetState(lODState); } public int GetLODPercentage(LOD[] lods, int i) { if (i == 0) { return 100; } return (int)(lods[i - 1].screenRelativeTransitionHeight * 100f + 0.5f); } private void ResetLOD() { GetRenderers(); } private void GetRenderers() { lg = GetComponent(); LOD[] lODs = lg.GetLODs(); int num = -1; for (int i = 0; i < lODs.Length; i++) { if (lODs[i].renderers != null && lODs[i].renderers.Length != 0) { num = i; } } maxlod = num; } public int GetLODState() { return Defaultlod; } private void SetState(int lodState) { LOD[] lODs = lg.GetLODs(); if (lodState == -1) { lg.enabled = true; for (int i = 0; i < lODs.Length; i++) { Renderer[] renderers = lODs[i].renderers; for (int j = 0; j < renderers.Length; j++) { renderers[j].gameObject.SetActive(value: true); } } return; } for (int k = 0; k < lODs.Length; k++) { Renderer[] renderers = lODs[k].renderers; for (int j = 0; j < renderers.Length; j++) { renderers[j].gameObject.SetActive(value: false); } } lodState = Mathf.Min(lodState, maxlod); int num = maxlod - lodState + 1; if (num == 1 || !Application.isPlaying) { lg.enabled = false; Renderer[] renderers = lODs[lodState].renderers; for (int j = 0; j < renderers.Length; j++) { renderers[j].gameObject.SetActive(value: true); } return; } lg.enabled = true; int num2 = 0; LOD[] array = new LOD[num]; for (int l = lodState; l < lODs.Length; l++) { Renderer[] renderers = lODs[l].renderers; for (int j = 0; j < renderers.Length; j++) { renderers[j].gameObject.SetActive(value: true); } array[num2] = lODs[l]; if (l + 1 < lODs.Length) { array[num2].screenRelativeTransitionHeight = lODs[num2].screenRelativeTransitionHeight; } num2++; } lg.SetLODs(array); } } [DefaultExecutionOrder(-5)] public class ConditionalObject : MonoBehaviour { public bool enabledOnSwitch = true; public bool enabledOnXbox = true; public bool enabledOnPlaystation = true; public bool disableInProduction; public bool enabledOnSteam = true; public bool enabledOnEGS = true; public bool disableIfNoActiveRun; private void CheckConditions() { bool flag = false || enabledOnEGS || enabledOnSteam; base.gameObject.SetActive(flag && !disableInProduction); } private void Awake() { CheckConditions(); } } public class EntityStateManager : ScriptableObject, ISerializationCallbackReceiver { [Serializable] private class StateInfo { [Serializable] public class Field { public enum ValueType { Invalid, Int, Float, String, Object, Bool, AnimationCurve, Vector3 } [NonSerialized] public StateInfo owner; [SerializeField] private string _fieldName; [SerializeField] private ValueType _valueType; [SerializeField] private int _intValue; [SerializeField] private float _floatValue; [SerializeField] private string _stringValue; [SerializeField] private UnityEngine.Object _objectValue; [SerializeField] private AnimationCurve _animationCurveValue; [SerializeField] private UnityEngine.Vector3 _vector3Value; public ValueType valueType => _valueType; public int intValue => _intValue; public bool boolValue => _intValue != 0; public float floatValue => _floatValue; public string stringValue => _stringValue; public UnityEngine.Object objectValue => _objectValue; public AnimationCurve animationCurveValue => _animationCurveValue; public UnityEngine.Vector3 vector3Value => _vector3Value; public object valueAsSystemObject { get { switch (_valueType) { case ValueType.Invalid: return null; case ValueType.Int: return intValue; case ValueType.Float: return floatValue; case ValueType.String: return stringValue; case ValueType.Object: if (!objectValue) { return null; } return objectValue; case ValueType.Bool: return boolValue; case ValueType.AnimationCurve: return animationCurveValue; case ValueType.Vector3: return vector3Value; default: return null; } } } public Field(string fieldName) { _fieldName = fieldName; } public void SetFieldInfo(FieldInfo fieldInfo) { _fieldName = fieldInfo.Name; ValueType valueType = ValueType.Invalid; Type fieldType = fieldInfo.FieldType; if (fieldType == typeof(int)) { valueType = ValueType.Int; } else if (fieldType == typeof(float)) { valueType = ValueType.Float; } else if (fieldType == typeof(string)) { valueType = ValueType.String; } else if (typeof(UnityEngine.Object).IsAssignableFrom(fieldType)) { valueType = ValueType.Object; } else if (fieldType == typeof(bool)) { valueType = ValueType.Bool; } else if (fieldType == typeof(AnimationCurve)) { valueType = ValueType.AnimationCurve; } else if (fieldType == typeof(UnityEngine.Vector3)) { valueType = ValueType.Vector3; } if (_valueType != valueType) { ResetValues(); _valueType = valueType; } } public bool MatchesFieldInfo(FieldInfo fieldInfo) { if (fieldInfo == null) { return false; } Type fieldType = fieldInfo.FieldType; switch (_valueType) { case ValueType.Invalid: return false; case ValueType.Int: return fieldType.IsAssignableFrom(typeof(int)); case ValueType.Float: return fieldType.IsAssignableFrom(typeof(float)); case ValueType.String: return fieldType.IsAssignableFrom(typeof(string)); case ValueType.Object: if (!(_objectValue == null)) { return fieldType.IsAssignableFrom(_objectValue.GetType()); } return true; case ValueType.Bool: return fieldType.IsAssignableFrom(typeof(bool)); case ValueType.AnimationCurve: return fieldType.IsAssignableFrom(typeof(AnimationCurve)); case ValueType.Vector3: return fieldType.IsAssignableFrom(typeof(UnityEngine.Vector3)); default: return false; } } public void Apply(FieldInfo fieldInfo, object instance) { fieldInfo.SetValue(instance, valueAsSystemObject); } public void ResetValues() { _intValue = 0; _floatValue = 0f; _stringValue = null; _objectValue = null; _animationCurveValue = null; _vector3Value = UnityEngine.Vector3.zero; } public void SetValue(int value) { ResetValues(); _valueType = ValueType.Int; _intValue = value; } public void SetValue(float value) { ResetValues(); _valueType = ValueType.Float; _floatValue = value; } public void SetValue(string value) { ResetValues(); _valueType = ValueType.String; _stringValue = value; } public void SetValue(UnityEngine.Object value) { ResetValues(); _valueType = ValueType.Object; _objectValue = value; } public void SetValue(bool value) { ResetValues(); _valueType = ValueType.Bool; _intValue = (value ? 1 : 0); } public void SetValue(AnimationCurve value) { ResetValues(); _valueType = ValueType.AnimationCurve; _animationCurveValue = value; } public void SetValue(UnityEngine.Vector3 value) { ResetValues(); _valueType = ValueType.Vector3; _vector3Value = value; } public string GetFieldName() { return _fieldName; } public FieldInfo GetFieldInfo() { return owner?.serializedType.stateType?.GetField(_fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); } } private struct FieldValuePair { public FieldInfo fieldInfo; public object value; } public SerializableEntityStateType serializedType; [FormerlySerializedAs("stateStaticFieldList")] [SerializeField] private List stateFieldList = new List(); private const BindingFlags defaultInstanceBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; private const BindingFlags defaultStaticBindingFlags = BindingFlags.Static | BindingFlags.Public; private static bool FieldHasSerializeAttribute(FieldInfo fieldInfo) { return CustomAttributeExtensions.GetCustomAttributes(fieldInfo, inherit: true).Any(); } private static bool FieldLacksNonSerializedAttribute(FieldInfo fieldInfo) { return !CustomAttributeExtensions.GetCustomAttributes(fieldInfo, inherit: true).Any(); } public void SetStateType(Type stateType) { serializedType.stateType = stateType; stateType = serializedType.stateType; if (stateType == null) { return; } IEnumerable first = stateType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Where(FieldHasSerializeAttribute); IEnumerable second = (from fieldInfo in stateType.GetFields(BindingFlags.Static | BindingFlags.Public) where fieldInfo.DeclaringType == stateType select fieldInfo).Where(FieldLacksNonSerializedAttribute); List list = first.Concat(second).ToList(); Dictionary dictionary = new Dictionary(); foreach (FieldInfo fieldInfo2 in list) { Field field = stateFieldList.Find((Field item) => item.GetFieldName() == fieldInfo2.Name); if (field == null) { UnityEngine.Debug.LogFormat("Could not find field {0}.{1}. Initializing new field.", stateType.Name, fieldInfo2.Name); field = new Field(fieldInfo2.Name); } dictionary[fieldInfo2] = field; } stateFieldList.Clear(); foreach (FieldInfo item in list) { Field field2 = dictionary[item]; field2.owner = this; field2.SetFieldInfo(item); stateFieldList.Add(field2); } } public void RefreshStateType() { SetStateType(serializedType.stateType); } public void ApplyStatic() { Type stateType = serializedType.stateType; if (!(stateType != null)) { return; } foreach (Field stateField in stateFieldList) { FieldInfo field = stateType.GetField(stateField.GetFieldName(), BindingFlags.Static | BindingFlags.Public); if (stateField.MatchesFieldInfo(field) && field.IsStatic) { stateField.Apply(field, null); } } } public Action GenerateInstanceFieldInitializerDelegate() { Type stateType = serializedType.stateType; if (stateType == null) { return null; } List list = new List(); for (int i = 0; i < stateFieldList.Count; i++) { Field field = stateFieldList[i]; FieldValuePair fieldValuePair = default(FieldValuePair); fieldValuePair.fieldInfo = stateType.GetField(field.GetFieldName(), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); fieldValuePair.value = field.valueAsSystemObject; FieldValuePair item = fieldValuePair; if (!(item.fieldInfo == null)) { list.Add(item); } } FieldValuePair[] fieldValuePairs = list.ToArray(); if (fieldValuePairs.Length == 0) { return null; } return delegate(EntityState entityState) { for (int j = 0; j < fieldValuePairs.Length; j++) { FieldValuePair fieldValuePair2 = fieldValuePairs[j]; fieldValuePair2.fieldInfo.SetValue(entityState, fieldValuePair2.value); } }; } public Field FindField(string fieldName) { return stateFieldList.Find((Field value) => value.GetFieldName() == fieldName); } public bool IsValid() { return serializedType.stateType != null; } public IList GetFields() { return stateFieldList.AsReadOnly(); } } [SerializeField] private List stateInfoList = new List(); [HideInInspector] [SerializeField] private string endMarker = "GIT_END"; private static readonly Dictionary> instanceFieldInitializers = new Dictionary>(); private StateInfo GetStateInfo(Type stateType) { if (stateType == null || !stateType.IsSubclassOf(typeof(EntityState))) { return null; } StateInfo stateInfo = stateInfoList.Find((StateInfo currentItem) => currentItem.serializedType.stateType == stateType); if (stateInfo == null) { stateInfo = new StateInfo(); stateInfo.SetStateType(stateType); stateInfoList.Add(stateInfo); } return stateInfo; } private void ApplyStatic() { foreach (StateInfo stateInfo in stateInfoList) { stateInfo.ApplyStatic(); } } public void Initialize() { } private static void SetEntityStateConfigurations(EntityStateConfiguration[] newEntityStateConfigurations) { EntityStateConfiguration[] array = ArrayUtils.Clone(newEntityStateConfigurations); Array.Sort(array, (EntityStateConfiguration a, EntityStateConfiguration b) => a.name.CompareTo(b.name)); for (int i = 0; i < array.Length; i++) { array[i].ApplyStatic(); } instanceFieldInitializers.Clear(); foreach (EntityStateConfiguration entityStateConfiguration in array) { Action action = entityStateConfiguration.BuildInstanceInitializer(); if (action != null) { instanceFieldInitializers[(Type)entityStateConfiguration.targetType] = action; } } } void ISerializationCallbackReceiver.OnBeforeSerialize() { foreach (StateInfo stateInfo in stateInfoList) { stateInfo.RefreshStateType(); } stateInfoList.RemoveAll((StateInfo stateInfo) => !stateInfo.IsValid()); } void ISerializationCallbackReceiver.OnAfterDeserialize() { foreach (StateInfo stateInfo in stateInfoList) { stateInfo.RefreshStateType(); } } private void GenerateInstanceFieldInitializers() { instanceFieldInitializers.Clear(); foreach (StateInfo stateInfo in stateInfoList) { Type stateType = stateInfo.serializedType.stateType; if (!(stateType == null)) { Action action = stateInfo.GenerateInstanceFieldInitializerDelegate(); if (action != null) { instanceFieldInitializers.Add(stateType, action); } } } } public static void InitializeStateFields(EntityState entityState) { instanceFieldInitializers.TryGetValue(entityState.GetType(), out var value); value?.Invoke(entityState); } [ContextMenu("Migrate to individual assets")] public void MigrateToEntityStateTypes() { List list = new List(); foreach (StateInfo stateInfo in stateInfoList) { if (MigrateToEntityStateType(stateInfo)) { list.Add(stateInfo); } } foreach (StateInfo item in list) { _ = item; } foreach (Type item2 in from t in typeof(EntityState).Assembly.GetTypes() where typeof(EntityState).IsAssignableFrom(t) select t) { GetOrCreateEntityStateSerializer(item2); } } private EntityStateConfiguration GetOrCreateEntityStateSerializer(Type type) { return null; } private bool MigrateToEntityStateType(StateInfo stateInfo) { Type stateType = stateInfo.serializedType.stateType; if (stateType == null) { UnityEngine.Debug.LogWarningFormat("Could not migrate type named \"{0}\": Type could not be found.", typeof(SerializableEntityStateType).GetField("_typeName", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(stateInfo.serializedType)); return false; } EntityStateConfiguration orCreateEntityStateSerializer = GetOrCreateEntityStateSerializer(stateType); foreach (StateInfo.Field field2 in stateInfo.GetFields()) { string fieldName = field2.GetFieldName(); FieldInfo field = stateType.GetField(fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); ref SerializedField orCreateField = ref orCreateEntityStateSerializer.serializedFieldsCollection.GetOrCreateField(fieldName); orCreateField.fieldName = fieldName; try { orCreateField.fieldValue.SetValue(field, field2.valueAsSystemObject); } catch (Exception message) { UnityEngine.Debug.LogError(message); } } EditorUtil.SetDirty(orCreateEntityStateSerializer); return true; } } [Serializable] [PostProcess(typeof(RampFogRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/RampFog", true)] public sealed class RampFog : PostProcessEffectSettings { [Range(0f, 1f)] [Tooltip("Fog intensity.")] public FloatParameter fogIntensity = new FloatParameter { value = 0.5f }; [Range(0f, 20f)] [Tooltip("Fog Power")] public FloatParameter fogPower = new FloatParameter { value = 1f }; [Range(-1f, 1f)] [Tooltip("The zero value for the fog depth remap.")] public FloatParameter fogZero = new FloatParameter { value = 0f }; [Tooltip("The one value for the fog depth remap.")] [Range(-1f, 1f)] public FloatParameter fogOne = new FloatParameter { value = 1f }; [Range(-100f, 100f)] [Tooltip("The world position value where the height fog begins.")] public FloatParameter fogHeightStart = new FloatParameter { value = 0f }; [Range(-100f, 600f)] [Tooltip("The world position value where the height fog ends.")] public FloatParameter fogHeightEnd = new FloatParameter { value = 100f }; [Range(0f, 5f)] [Tooltip("The overall strength of the height fog.")] public FloatParameter fogHeightIntensity = new FloatParameter { value = 0f }; [Tooltip("Color of the fog at the beginning.")] public ColorParameter fogColorStart = new ColorParameter { value = UnityEngine.Color.white }; [Tooltip("Color of the fog at the middle.")] public ColorParameter fogColorMid = new ColorParameter { value = UnityEngine.Color.white }; [Tooltip("Color of the fog at the end.")] public ColorParameter fogColorEnd = new ColorParameter { value = UnityEngine.Color.white }; [Tooltip("How much of the skybox will leak through?")] [Range(0f, 1f)] public FloatParameter skyboxStrength = new FloatParameter { value = 0f }; } public sealed class RampFogRenderer : PostProcessEffectRenderer { public override void Render(PostProcessRenderContext context) { PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcess/RampFog")); propertySheet.properties.SetFloat("_FogIntensity", base.settings.fogIntensity); propertySheet.properties.SetFloat("_FogPower", base.settings.fogPower); propertySheet.properties.SetFloat("_FogZero", base.settings.fogZero); propertySheet.properties.SetFloat("_FogOne", base.settings.fogOne); propertySheet.properties.SetFloat("_FogHeightStart", base.settings.fogHeightStart); propertySheet.properties.SetFloat("_FogHeightEnd", base.settings.fogHeightEnd); propertySheet.properties.SetFloat("_FogHeightIntensity", base.settings.fogHeightIntensity); propertySheet.properties.SetColor("_FogColorStart", base.settings.fogColorStart); propertySheet.properties.SetColor("_FogColorMid", base.settings.fogColorMid); propertySheet.properties.SetColor("_FogColorEnd", base.settings.fogColorEnd); propertySheet.properties.SetFloat("_SkyboxStrength", base.settings.skyboxStrength); context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0); } } [Serializable] [PostProcess(typeof(SceneTintRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/SceneTint", true)] public sealed class SceneTint : PostProcessEffectSettings { [Range(0f, 1f)] [Tooltip("The intensity of the tint.")] public FloatParameter tintIntensity = new FloatParameter { value = 0.5f }; } public sealed class SceneTintRenderer : PostProcessEffectRenderer { public override void Render(PostProcessRenderContext context) { PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcess/SceneTint")); propertySheet.properties.SetFloat("_TintIntensity", base.settings.tintIntensity); context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0); } } [Serializable] [PostProcess(typeof(ScreenDamagePPRenderer), PostProcessEvent.BeforeStack, "PostProcess/ScreenDamage", true)] public sealed class ScreenDamagePP : PostProcessEffectSettings { [Tooltip("Screen tint color")] public ColorParameter VignetteTint = new ColorParameter { value = new UnityEngine.Color(0f, 0.5709429f, 0.5955881f) }; [Tooltip("Distortion normal map")] public TextureParameter OffsetMap = new TextureParameter(); [Tooltip("Distortion strength")] public FloatParameter DistortionStrength = new FloatParameter(); [Tooltip("Desaturation strength")] public FloatParameter DesaturationStrength = new FloatParameter(); [Tooltip("Tint strength")] public FloatParameter TintStrength = new FloatParameter(); } public sealed class ScreenDamagePPRenderer : PostProcessEffectRenderer { private static readonly int NormalMap = Shader.PropertyToID("_NormalMap"); private static readonly int Tint = Shader.PropertyToID("_Tint"); private static readonly int DistortionStrength = Shader.PropertyToID("_DistortionStrength"); private static readonly int DesaturationStrength = Shader.PropertyToID("_DesaturationStrength"); private static readonly int TintStrength = Shader.PropertyToID("_TintStrength"); private static readonly int CombinationType = Shader.PropertyToID("_CombinationType"); private Shader shader; private static bool propsSet; private static bool usingTemporaryProps; private static int temporaryPropsSetExpirationFrameStamp; public static ColorParameter temporaryVignetteTint; public static TextureParameter temporaryOffsetMap; public static bool temporaryCombineAdditively; public static ScreenDamageCalculator temporaryPropsCalculator; private int temporaryPropsExpirationFrames = 2; public override void Init() { base.Init(); shader = LegacyShaderAPI.Find("Shaders/PostProcess/HGScreenDamage"); propsSet = false; } public static void ExtendTemporaryProps() { temporaryPropsSetExpirationFrameStamp++; } public static void SetTemporaryProps(ScreenDamageCalculator damageCalculator, ColorParameter tintColor, TextureParameter offsetMap, bool combineAdditively) { usingTemporaryProps = true; temporaryPropsCalculator = damageCalculator; temporaryVignetteTint = tintColor; temporaryOffsetMap = offsetMap; temporaryCombineAdditively = combineAdditively; temporaryPropsSetExpirationFrameStamp = int.MaxValue; propsSet = false; } public static void ClearTemporaryProps(ScreenDamageCalculator damageCalculator) { if (damageCalculator == temporaryPropsCalculator) { temporaryOffsetMap = null; temporaryVignetteTint = null; usingTemporaryProps = false; temporaryCombineAdditively = false; temporaryPropsSetExpirationFrameStamp = int.MaxValue; propsSet = false; } } private void HandlePropsSet(PropertySheet sheet, int frameCount) { propsSet = true; if (usingTemporaryProps && temporaryOffsetMap != null) { sheet.properties.SetTexture(NormalMap, temporaryOffsetMap); } else { sheet.properties.SetTexture(NormalMap, base.settings.OffsetMap); } if (usingTemporaryProps && temporaryVignetteTint != null) { sheet.properties.SetColor(Tint, temporaryVignetteTint); } else { sheet.properties.SetColor(Tint, base.settings.VignetteTint); } if (usingTemporaryProps && temporaryCombineAdditively) { sheet.properties.SetFloat(CombinationType, 1f); } else { sheet.properties.SetFloat(CombinationType, -1f); } if (usingTemporaryProps && (temporaryOffsetMap != null || temporaryVignetteTint != null)) { temporaryPropsSetExpirationFrameStamp = frameCount + temporaryPropsExpirationFrames; } else { temporaryPropsSetExpirationFrameStamp = int.MaxValue; } } public override void Render(PostProcessRenderContext context) { PropertySheet propertySheet = context.propertySheets.Get(shader); int frameCount = Time.frameCount; if (usingTemporaryProps && propsSet && frameCount > temporaryPropsSetExpirationFrameStamp) { ClearTemporaryProps(temporaryPropsCalculator); } if (!propsSet) { HandlePropsSet(propertySheet, frameCount); } propertySheet.properties.SetFloat(DistortionStrength, base.settings.DistortionStrength); propertySheet.properties.SetFloat(DesaturationStrength, base.settings.DesaturationStrength); propertySheet.properties.SetFloat(TintStrength, base.settings.TintStrength); context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0); } } [Serializable] [PostProcess(typeof(SobelOutlineRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/SobelOutline", true)] public sealed class SobelOutline : PostProcessEffectSettings { [Range(0f, 5f)] [Tooltip("The intensity of the outline.")] public FloatParameter outlineIntensity = new FloatParameter { value = 0.5f }; [Range(0f, 10f)] [Tooltip("The falloff of the outline.")] public FloatParameter outlineScale = new FloatParameter { value = 1f }; } public sealed class SobelOutlineRenderer : PostProcessEffectRenderer { public override void Render(PostProcessRenderContext context) { PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcess/SobelOutline")); propertySheet.properties.SetFloat("_OutlineIntensity", base.settings.outlineIntensity); propertySheet.properties.SetFloat("_OutlineScale", base.settings.outlineScale); context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0); } } [Serializable] [PostProcess(typeof(SobelRainRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/SobelRain", true)] public sealed class SobelRain : PostProcessEffectSettings { [Range(0f, 100f)] [Tooltip("The intensity of the rain.")] public FloatParameter rainIntensity = new FloatParameter { value = 0.5f }; [Range(0f, 10f)] [Tooltip("The falloff of the outline. Higher values means it relies less on the sobel.")] public FloatParameter outlineScale = new FloatParameter { value = 1f }; [Range(0f, 1f)] [Tooltip("The density of rain.")] public FloatParameter rainDensity = new FloatParameter { value = 1f }; public TextureParameter rainTexture = new TextureParameter { value = null }; public ColorParameter rainColor = new ColorParameter { value = UnityEngine.Color.white }; } public sealed class SobelRainRenderer : PostProcessEffectRenderer { public override void Render(PostProcessRenderContext context) { PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcess/SobelRain")); propertySheet.properties.SetFloat("_RainIntensity", base.settings.rainIntensity); propertySheet.properties.SetFloat("_OutlineScale", base.settings.outlineScale); propertySheet.properties.SetFloat("_RainDensity", base.settings.rainDensity); propertySheet.properties.SetTexture("_RainTexture", base.settings.rainTexture); propertySheet.properties.SetColor("_RainColor", base.settings.rainColor); context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0); } } public class DoXInYSecondsTracker { private readonly float[] timestamps; private readonly float window; private int lastValidCount; private float newestTime => timestamps[0]; private int requirement => timestamps.Length; public DoXInYSecondsTracker(int requirement, float window) { if (requirement < 1) { throw new ArgumentException("Argument must be greater than zero", "requirement"); } timestamps = new float[requirement]; Clear(); this.window = window; } public void Clear() { for (int i = 0; i < timestamps.Length; i++) { timestamps[i] = float.NegativeInfinity; } } private int FindInsertionPosition(float t) { for (int i = 0; i < lastValidCount; i++) { if (timestamps[i] < t) { return i; } } return lastValidCount; } public bool Push(float t) { float num = t - window; if (t < newestTime) { lastValidCount = timestamps.Length; } int num2 = lastValidCount - 1; while (num2 >= 0 && !(num <= timestamps[num2])) { lastValidCount--; num2--; } int num3 = FindInsertionPosition(t); if (num3 < timestamps.Length) { lastValidCount++; ArrayUtils.ArrayInsertNoResize(timestamps, lastValidCount, num3, in t); } return lastValidCount == requirement; } } public class ChefController : NetworkBehaviour { public delegate void YesChefEnded(); [HideInInspector] public SkillStateOverrideData skillOverrides; private bool localCleaverFired; [SyncVar] public bool _cleaverAway; [SyncVar] public bool _recallCleaver; [NonSerialized] [SyncVar] public bool catchDirtied; [NonSerialized] public CleaverProjectile projectile; [NonSerialized] public CharacterBody characterBody; public Animator chefAnimator; internal float spreadBloom; public bool rolyPolyActive; private bool yesChefHeatActive; public YesChefEnded yesChefEndedDelegate; public bool blockOtherSkills; private bool cleaversAwayCached; public Transform handCleaverBone; public Transform[] cleaverStockBones; private UnityEngine.Vector3[] cleaverStockBones_DefaultLocalPosition; private float[] cleaverStockBones_AnimateInTimer01; private uint soundIDMoving; private uint soundIDServo; private float walkVolume_Target; private float walkVolume_Smoothed; private float servoStrain_Timer; private float servoStrain_VolumeSmoothed; private const float servoStrainFadeInDuration = 0.15f; private const float servoStrainFadeOutDuration = 0.5f; private Queue cachedCleaverProjectileInfo = new Queue(); private Dictionary cleaverDictionary = new Dictionary(); private static int kCmdCmdSetCleaverAway; private static int kCmdCmdSetRecallCleaver; public bool cleaverAway { get { if (!localCleaverFired) { return _cleaverAway; } return true; } set { if (base.hasAuthority) { Network_cleaverAway = value; CallCmdSetCleaverAway(value); } } } public bool recallCleaver { get { return _recallCleaver; } set { if (base.hasAuthority) { Network_recallCleaver = value; CallCmdSetRecallCleaver(value); } } } public bool Network_cleaverAway { get { return _cleaverAway; } [param: In] set { SetSyncVar(value, ref _cleaverAway, 1u); } } public bool Network_recallCleaver { get { return _recallCleaver; } [param: In] set { SetSyncVar(value, ref _recallCleaver, 2u); } } public bool NetworkcatchDirtied { get { return catchDirtied; } [param: In] set { SetSyncVar(value, ref catchDirtied, 4u); } } [Command] public void CmdSetCleaverAway(bool b) { Network_cleaverAway = b; } [Command] public void CmdSetRecallCleaver(bool b) { Network_recallCleaver = b; } private void Awake() { int num = cleaverStockBones.Length; cleaverStockBones_DefaultLocalPosition = new UnityEngine.Vector3[num]; cleaverStockBones_AnimateInTimer01 = new float[num]; for (int i = 0; i < num; i++) { cleaverStockBones_DefaultLocalPosition[i] = cleaverStockBones[i].localPosition; } soundIDMoving = Util.PlaySound("Play_chef_move_loop", base.gameObject); soundIDServo = Util.PlaySound("Play_chef_servo_loop", base.gameObject); if (characterBody == null) { characterBody = GetComponent(); } chefAnimator = characterBody.modelLocator.modelTransform.GetComponent(); } private void Start() { CharacterBody obj = characterBody; obj.onJump = (CharacterBody.JumpDelegate)Delegate.Combine(obj.onJump, new CharacterBody.JumpDelegate(HandleJump)); } private void OnDestroy() { CharacterBody obj = characterBody; obj.onJump = (CharacterBody.JumpDelegate)Delegate.Remove(obj.onJump, new CharacterBody.JumpDelegate(HandleJump)); } public void SetYesChefHeatState(bool newYesChefHeatState) { yesChefHeatActive = newYesChefHeatState; if (!yesChefHeatActive) { yesChefEndedDelegate?.Invoke(); } } private void HandleJump() { ActivateServoStrainSfxForDuration(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ActivateServoStrainSfxForDuration(float duration = 0.5f) { servoStrain_Timer = Mathf.Max(servoStrain_Timer, duration); } public void CacheCleaverProjectileFireInfo(FireProjectileInfo fireProjectileInfo) { cachedCleaverProjectileInfo.Enqueue(fireProjectileInfo); } public bool TryRetrieveCachedProjectileFireInfo(out FireProjectileInfo fireProjectileInfo) { fireProjectileInfo = default(FireProjectileInfo); if (cachedCleaverProjectileInfo.Count < 0 || !base.hasAuthority) { return false; } fireProjectileInfo = cachedCleaverProjectileInfo.Dequeue(); return true; } private void Update() { if ((bool)characterBody && !recallCleaver && cleaverAway) { characterBody.SetSpreadBloom(spreadBloom); } CharacterMotor characterMotor = characterBody.characterMotor; UnityEngine.Vector3 velocity = characterMotor.velocity; float sqrMagnitude = velocity.sqrMagnitude; bool isGrounded = characterMotor.isGrounded; bool @bool = chefAnimator.GetBool("isSprinting"); UnityEngine.Vector3 vector = (characterBody.inputBank ? characterBody.inputBank.moveVector : UnityEngine.Vector3.zero); if (isGrounded && sqrMagnitude > Mathf.Epsilon) { if (rolyPolyActive) { walkVolume_Target = 1f; } else if (vector != UnityEngine.Vector3.zero) { if (@bool) { walkVolume_Target = 0.8f; } else { walkVolume_Target = 0.5f; } } } else { walkVolume_Target = Mathf.MoveTowards(walkVolume_Target, 0f, Time.deltaTime / (1f / 3f)); } walkVolume_Smoothed = Mathf.MoveTowards(walkVolume_Smoothed, Mathf.Clamp01(walkVolume_Target), Time.deltaTime / (4f / 15f)); AkSoundEngine.SetRTPCValueByPlayingID("charChefSpeed", walkVolume_Smoothed * 100f, soundIDMoving); if (servoStrain_Timer > 0f) { servoStrain_Timer -= Time.deltaTime; } if (servoStrain_Timer > 0f) { float maxDelta = Time.deltaTime / 0.15f; servoStrain_VolumeSmoothed = Mathf.MoveTowards(servoStrain_VolumeSmoothed, 1f, maxDelta); } else { float maxDelta2 = Time.deltaTime / 0.5f; servoStrain_VolumeSmoothed = Mathf.MoveTowards(servoStrain_VolumeSmoothed, 0f, maxDelta2); } } private void LateUpdate() { bool flag = cleaverDictionary.Count > 0; if (flag != cleaversAwayCached || flag) { cleaversAwayCached = flag; handCleaverBone.localScale = (flag ? UnityEngine.Vector3.zero : UnityEngine.Vector3.one); } if (!(characterBody != null) || !(characterBody.skillLocator != null) || !(characterBody.skillLocator.primary != null)) { return; } int stock = characterBody.skillLocator.primary.stock; int num = cleaverStockBones.Length; float deltaTime = Time.deltaTime; float num2 = 8f; float num3 = -0.2f; for (int i = 0; i < num; i++) { bool num4 = i + 1 <= stock; float current = cleaverStockBones_AnimateInTimer01[i]; current = ((!num4) ? 0f : Mathf.MoveTowards(current, 1f, deltaTime * num2)); cleaverStockBones_AnimateInTimer01[i] = current; if (current != 1f) { current = 1f - current; current *= current; cleaverStockBones[i].localScale = UnityEngine.Vector3.one * (1f - current); cleaverStockBones[i].localPosition = cleaverStockBones_DefaultLocalPosition[i] + current * UnityEngine.Vector3.up * num3; } } } internal void AddLocalProjectileReference(ushort predictionId, CleaverProjectile cleaverProjectile) { if (!cleaverDictionary.ContainsKey(predictionId) || !cleaverProjectile.projectileController.isPrediction) { cleaverDictionary[predictionId] = cleaverProjectile; } } internal void RemoveLocalProjectileReference(ushort predictionId) { if (cleaverDictionary.ContainsKey(predictionId)) { cleaverDictionary.Remove(predictionId); } if (cleaverDictionary.Count < 1) { localCleaverFired = false; cleaverAway = false; recallCleaver = false; } } public void TransferSkillOverrides(SkillStateOverrideData skillOverrideData) { if (skillOverrides != null) { if (skillOverrides == skillOverrideData) { return; } skillOverrides.ClearOverrides(); } skillOverrides = skillOverrideData; } public void ClearSkillOverrides() { if (skillOverrides != null) { skillOverrides.ClearOverrides(); } skillOverrides = null; } [Server] public void DestroyCleavers() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void ChefController::DestroyCleavers()' called on client"); return; } foreach (CleaverProjectile value in cleaverDictionary.Values) { value.CallCmdDestroyAndCleanup(); } } private void UNetVersion() { } protected static void InvokeCmdCmdSetCleaverAway(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetCleaverAway called on client."); } else { ((ChefController)obj).CmdSetCleaverAway(reader.ReadBoolean()); } } protected static void InvokeCmdCmdSetRecallCleaver(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetRecallCleaver called on client."); } else { ((ChefController)obj).CmdSetRecallCleaver(reader.ReadBoolean()); } } public void CallCmdSetCleaverAway(bool b) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetCleaverAway called on server."); return; } if (base.isServer) { CmdSetCleaverAway(b); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetCleaverAway); networkWriter.Write(GetComponent().netId); networkWriter.Write(b); SendCommandInternal(networkWriter, 0, "CmdSetCleaverAway"); } public void CallCmdSetRecallCleaver(bool b) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetRecallCleaver called on server."); return; } if (base.isServer) { CmdSetRecallCleaver(b); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetRecallCleaver); networkWriter.Write(GetComponent().netId); networkWriter.Write(b); SendCommandInternal(networkWriter, 0, "CmdSetRecallCleaver"); } static ChefController() { kCmdCmdSetCleaverAway = -1756854004; NetworkBehaviour.RegisterCommandDelegate(typeof(ChefController), kCmdCmdSetCleaverAway, InvokeCmdCmdSetCleaverAway); kCmdCmdSetRecallCleaver = 535604397; NetworkBehaviour.RegisterCommandDelegate(typeof(ChefController), kCmdCmdSetRecallCleaver, InvokeCmdCmdSetRecallCleaver); NetworkCRC.RegisterBehaviour("ChefController", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(_cleaverAway); writer.Write(_recallCleaver); writer.Write(catchDirtied); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_cleaverAway); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_recallCleaver); } if ((base.syncVarDirtyBits & 4u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(catchDirtied); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { _cleaverAway = reader.ReadBoolean(); _recallCleaver = reader.ReadBoolean(); catchDirtied = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { _cleaverAway = reader.ReadBoolean(); } if (((uint)num & 2u) != 0) { _recallCleaver = reader.ReadBoolean(); } if (((uint)num & 4u) != 0) { catchDirtied = reader.ReadBoolean(); } } public override void PreStartClient() { } } public class ChefFoodPickController : MonoBehaviour { [SerializeField] public GameObject foodModel1; [SerializeField] public GameObject foodModel2; [SerializeField] public GameObject foodModel3; private void Start() { switch (UnityEngine.Random.Range(0, 2)) { case 0: foodModel1.SetActive(value: true); break; case 1: foodModel2.SetActive(value: true); break; case 2: foodModel3.SetActive(value: true); break; } } } public class RolyPolyBoostedProjectileTimer : MonoBehaviour { private ChefController chefController; private void OnEnable() { ProjectileController component = base.gameObject.GetComponent(); if ((bool)component) { component.onInitialized += GetChefController; } } private void GetChefController(ProjectileController projectileController) { chefController = projectileController.owner.GetComponent(); } private void Update() { if ((bool)chefController && !chefController.rolyPolyActive && Util.HasEffectiveAuthority(base.gameObject)) { UnityEngine.Object.Destroy(base.gameObject); } } } public class YesChefHeatProjectileTimer : MonoBehaviour { private ChefController chefController; private ProjectileController projectileController; private void OnEnable() { if (NetworkServer.active) { projectileController = base.gameObject.GetComponent(); if ((bool)projectileController) { projectileController.onInitialized += GetChefController; } } } private void GetChefController(ProjectileController projectileController) { chefController = projectileController.owner.GetComponent(); ChefController obj = chefController; obj.yesChefEndedDelegate = (ChefController.YesChefEnded)Delegate.Combine(obj.yesChefEndedDelegate, new ChefController.YesChefEnded(EndChefHeatProjectile)); } private void EndChefHeatProjectile() { if (NetworkServer.active) { UnityEngine.Object.Destroy(base.gameObject); } } private void OnDestroy() { if ((bool)projectileController) { projectileController.onInitialized -= GetChefController; } if ((bool)chefController) { ChefController obj = chefController; obj.yesChefEndedDelegate = (ChefController.YesChefEnded)Delegate.Remove(obj.yesChefEndedDelegate, new ChefController.YesChefEnded(EndChefHeatProjectile)); } } } public class PrimeDevastatorProjectileController : MonoBehaviour { public ProjectileOwnerOrbiter orbiter; public float expansionSpeed = 1f; private float orbitExpansionTimer; private void Start() { } private void Update() { ProjectileOwnerOrbiter projectileOwnerOrbiter = orbiter; projectileOwnerOrbiter.Networkradius = projectileOwnerOrbiter.radius + Time.deltaTime * expansionSpeed; } } public class HereticInitialStateHelper : MonoBehaviour { [SerializeField] private EntityStateMachine entityStateMachine; public void PrepareTransformation() { entityStateMachine.initialStateType = new SerializableEntityStateType(typeof(EntityStates.Heretic.SpawnState)); } } public class ScorchlingController : MonoBehaviour { public CharacterBody characterBody; public CharacterMotor characterMotor; private RigidbodyMotor rigidBodyMotor; public string burrowingSoundString; public Transform burrowFX; public float timeInAirToTele; public float timeInAirToShutOffDustTrail = 0.2f; private float inAirTimer; public GameObject breachEffectPrefab; public float breachEffectRadius = 5f; public float teleCooldown; private GameObject dustTrail; private GameObject baseDirt; private GameObject armatureObject; private GameObject meshObject; public bool isBurrowed = true; public bool isRecentlyBurrowed = true; public bool canTeleport = true; private bool dustTrailActive; private float teleportTimer; private float teleportCooldownDuration = 3f; private UnityEngine.Vector3 lastSafePosition; private GenericSkill breachSkill; private GenericSkill lavaBombSkill; private GenericSkill ensureBurrowSkill; private UnityEngine.Quaternion breachBaseDirtRotation; private int originalLayer; private float cachedYPosition; private void Start() { ChildLocator component = characterBody.modelLocator.modelTransform.GetComponent(); dustTrail = component.FindChild("BurrowLocation").gameObject; baseDirt = component.FindChild("BaseDirt").gameObject; armatureObject = component.FindChild("Armature").gameObject; meshObject = component.FindChild("Mesh").gameObject; dustTrailActive = dustTrail.activeInHierarchy; SkillLocator skillLocator = characterBody.skillLocator; breachSkill = skillLocator.GetSkill(SkillSlot.Primary); lavaBombSkill = skillLocator.GetSkill(SkillSlot.Secondary); ensureBurrowSkill = skillLocator.GetSkill(SkillSlot.Utility); rigidBodyMotor = GetComponent(); Burrow(); teleportTimer = teleportCooldownDuration; } private void Update() { if (!isBurrowed) { return; } float deltaTime = Time.deltaTime; teleportTimer += deltaTime; if (!characterMotor.isGrounded) { if (characterBody.footPosition.y > cachedYPosition) { cachedYPosition = characterBody.footPosition.y; return; } inAirTimer += deltaTime; cachedYPosition = characterBody.footPosition.y; if (dustTrailActive && inAirTimer > timeInAirToShutOffDustTrail) { dustTrailActive = false; dustTrail.SetActive(value: false); EffectManager.SpawnEffect(breachEffectPrefab, new EffectData { origin = characterBody.footPosition, scale = breachEffectRadius }, transmit: true); } if (!(teleportTimer < teleportCooldownDuration) && canTeleport && inAirTimer > timeInAirToTele && NetworkServer.active) { UnityEngine.Vector3 bestTeleportPosition = GetBestTeleportPosition(); TeleportHelper.TeleportBody(characterBody, bestTeleportPosition); inAirTimer = 0f; teleportTimer = 0f; } } else { inAirTimer = 0f; cachedYPosition = float.MaxValue; lastSafePosition = characterBody.footPosition; if (!dustTrailActive) { dustTrail.SetActive(value: true); dustTrailActive = true; EffectManager.SpawnEffect(breachEffectPrefab, new EffectData { origin = characterBody.footPosition, scale = breachEffectRadius }, transmit: true); } } } public void ResetTeleportTimer() { teleportTimer = 0f; inAirTimer = 0f; } public void SetTeleportPermission(bool b) { canTeleport = b; ResetTeleportTimer(); } private UnityEngine.Vector3 GetBestTeleportPosition() { NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); List list = nodeGraph.FindNodesInRange(characterBody.corePosition, 3f, 16f, HullMask.Human); if (list.Count < 1) { return lastSafePosition; } nodeGraph.GetNodePosition(list[0], out var position); return position; } public void Burrow() { isRecentlyBurrowed = true; isBurrowed = true; SetTeleportPermission(b: true); if (NetworkServer.active) { breachSkill.stock = 1; lavaBombSkill.stock = 0; ensureBurrowSkill.stock = 5; characterMotor.walkSpeedPenaltyCoefficient = 1f; if (characterBody.GetBuffCount(RoR2Content.Buffs.HiddenInvincibility.buffIndex) < 1) { characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); } } originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(characterBody.teamComponent.teamIndex).intVal; characterMotor.Motor.RebuildCollidableLayers(); if ((bool)baseDirt && (bool)dustTrail) { baseDirt.SetActive(value: false); dustTrail.SetActive(value: true); dustTrailActive = true; armatureObject.SetActive(value: false); meshObject.SetActive(value: false); } } public void LateUpdate() { if (!isBurrowed && (bool)baseDirt && NetworkServer.active && baseDirt.transform.rotation != breachBaseDirtRotation) { baseDirt.transform.rotation = breachBaseDirtRotation; } } public void Breach() { isBurrowed = false; SetTeleportPermission(b: false); if (NetworkServer.active) { characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); breachSkill.stock = 0; lavaBombSkill.stock = 1; ensureBurrowSkill.stock = 5; characterMotor.walkSpeedPenaltyCoefficient = 0f; if ((bool)characterBody) { characterBody.isSprinting = false; } if ((bool)rigidBodyMotor) { rigidBodyMotor.moveVector = UnityEngine.Vector3.zero; } breachBaseDirtRotation = baseDirt.transform.rotation; breachBaseDirtRotation.eulerAngles = new UnityEngine.Vector3(breachBaseDirtRotation.eulerAngles.x, Mathf.Floor(breachBaseDirtRotation.eulerAngles.y), breachBaseDirtRotation.eulerAngles.z); baseDirt.transform.localEulerAngles = UnityEngine.Vector3.zero; baseDirt.transform.rotation = breachBaseDirtRotation; } base.gameObject.layer = originalLayer; characterMotor.Motor.RebuildCollidableLayers(); if ((bool)baseDirt && (bool)dustTrail) { baseDirt.SetActive(value: true); dustTrail.SetActive(value: false); dustTrailActive = false; armatureObject.SetActive(value: true); meshObject.SetActive(value: true); } } } public class FirstSelectedObjectProvider : MonoBehaviour { public GameObject firstSelectedObject; public GameObject[] fallBackFirstSelectedObjects; private GameObject lastSelected; public GameObject[] enforceCurrentSelectionIsInList; public bool takeAbsolutePriority; public static FirstSelectedObjectProvider priorityHolder; private void OnEnable() { if (takeAbsolutePriority) { priorityHolder = this; } } private void OnDisable() { if (takeAbsolutePriority && priorityHolder == this) { priorityHolder = null; } } private GameObject getInteractableFirstSelectedObject() { if ((bool)firstSelectedObject && firstSelectedObject.GetComponent().interactable && firstSelectedObject.activeInHierarchy) { return firstSelectedObject; } if (fallBackFirstSelectedObjects == null) { return null; } for (int i = 0; i < fallBackFirstSelectedObjects.Length; i++) { if (fallBackFirstSelectedObjects[i].GetComponent().interactable && fallBackFirstSelectedObjects[i].activeInHierarchy) { return fallBackFirstSelectedObjects[i]; } } return null; } public void EnsureSelectedObject() { if (priorityHolder != null && priorityHolder != this) { return; } GameObject interactableFirstSelectedObject = getInteractableFirstSelectedObject(); if (!(interactableFirstSelectedObject != null)) { return; } MPEventSystemLocator component = interactableFirstSelectedObject.GetComponent(); if (!component) { return; } MPEventSystem eventSystem = component.eventSystem; if (!eventSystem) { return; } GameObject currentSelectedGameObject = eventSystem.currentSelectedGameObject; if (currentSelectedGameObject == null) { if (lastSelected != null && lastSelected.GetComponent().interactable) { eventSystem.SetSelectedGameObject(lastSelected); } else { if (eventSystem.firstSelectedGameObject == null) { eventSystem.firstSelectedGameObject = interactableFirstSelectedObject; } eventSystem.SetSelectedGameObject(interactableFirstSelectedObject); } } else { Selectable component2 = currentSelectedGameObject.GetComponent(); bool flag = true; if (enforceCurrentSelectionIsInList != null && enforceCurrentSelectionIsInList.Length != 0) { flag = false; GameObject[] array = enforceCurrentSelectionIsInList; for (int i = 0; i < array.Length; i++) { if (array[i] == currentSelectedGameObject) { flag = true; } } } if ((bool)component2 && (!component2.interactable || !component2.isActiveAndEnabled)) { flag = false; } if (!flag && (bool)component2 && (!component2.interactable || !component2.isActiveAndEnabled)) { eventSystem.SetSelectedGameObject(interactableFirstSelectedObject); } } if (component.eventSystem.currentSelectedGameObject != null) { lastSelected = component.eventSystem.currentSelectedGameObject; } } public void ForceSelectFirstInteractable() { GameObject interactableFirstSelectedObject = getInteractableFirstSelectedObject(); if (!(interactableFirstSelectedObject != null)) { return; } MPEventSystemLocator component = interactableFirstSelectedObject.GetComponent(); if (!component) { return; } MPEventSystem eventSystem = component.eventSystem; if ((bool)eventSystem) { if (eventSystem.firstSelectedGameObject == null) { eventSystem.firstSelectedGameObject = interactableFirstSelectedObject; } eventSystem.SetSelectedGameObject(interactableFirstSelectedObject); } if (component.eventSystem.currentSelectedGameObject != null) { lastSelected = component.eventSystem.currentSelectedGameObject; } } public void ResetLastSelected() { lastSelected = null; } public void AddObject(GameObject obj, bool enforceCurrentSelection = false) { if (firstSelectedObject == null) { firstSelectedObject = obj; } else if (fallBackFirstSelectedObjects == null) { fallBackFirstSelectedObjects = new GameObject[1]; fallBackFirstSelectedObjects[0] = obj; } else if (fallBackFirstSelectedObjects.Length >= 0) { List list = new List(fallBackFirstSelectedObjects); list.Add(obj); fallBackFirstSelectedObjects = list.ToArray(); } if (enforceCurrentSelection) { if (enforceCurrentSelectionIsInList == null) { enforceCurrentSelectionIsInList = new GameObject[1]; enforceCurrentSelectionIsInList[0] = obj; } else if (enforceCurrentSelectionIsInList.Length >= 0) { List list2 = new List(enforceCurrentSelectionIsInList); list2.Add(obj); enforceCurrentSelectionIsInList = list2.ToArray(); } } } } public static class FlashWindow { private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); private struct FLASHWINFO { public uint cbSize; public IntPtr hwnd; public uint dwFlags; public uint uCount; public uint dwTimeout; } private static IntPtr myWindow; private static readonly IntPtr myProcessId = GetCurrentProcessId(); public const uint FLASHW_STOP = 0u; public const uint FLASHW_CAPTION = 1u; public const uint FLASHW_TRAY = 2u; public const uint FLASHW_ALL = 3u; public const uint FLASHW_TIMER = 4u; public const uint FLASHW_TIMERNOFG = 12u; private static bool Win2000OrLater => Environment.OSVersion.Version.Major >= 5; [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool FlashWindowEx(ref FLASHWINFO pwfi); [DllImport("user32.dll")] private static extern IntPtr GetActiveWindow(); [DllImport("user32.dll")] private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam); [DllImport("user32.dll")] private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId); [DllImport("kernel32.dll")] private static extern IntPtr GetCurrentProcessId(); private static bool GetWindowEnum(IntPtr hWnd, IntPtr lParam) { GetWindowThreadProcessId(hWnd, out var lpdwProcessId); if (lpdwProcessId == myProcessId) { myWindow = hWnd; return false; } return true; } private static void UpdateCurrentWindow() { EnumWindows(GetWindowEnum, IntPtr.Zero); } private static bool IsCurrentWindowValid() { GetWindowThreadProcessId(myWindow, out var lpdwProcessId); if (lpdwProcessId != myProcessId) { myWindow = IntPtr.Zero; } return myWindow != IntPtr.Zero; } public static IntPtr GetWindowHandle() { if (!IsCurrentWindowValid()) { UpdateCurrentWindow(); } return myWindow; } public static bool Flash(IntPtr formHandle) { if (Win2000OrLater) { FLASHWINFO pwfi = Create_FLASHWINFO(formHandle, 15u, uint.MaxValue, 0u); return FlashWindowEx(ref pwfi); } return false; } private static FLASHWINFO Create_FLASHWINFO(IntPtr handle, uint flags, uint count, uint timeout) { FLASHWINFO fLASHWINFO = default(FLASHWINFO); fLASHWINFO.cbSize = System.Convert.ToUInt32(Marshal.SizeOf(fLASHWINFO)); fLASHWINFO.hwnd = handle; fLASHWINFO.dwFlags = flags; fLASHWINFO.uCount = count; fLASHWINFO.dwTimeout = timeout; return fLASHWINFO; } public static bool Flash(IntPtr formHandle, uint count) { if (Win2000OrLater) { FLASHWINFO pwfi = Create_FLASHWINFO(formHandle, 3u, count, 0u); return FlashWindowEx(ref pwfi); } return false; } public static bool Flash() { return Flash(GetWindowHandle()); } public static bool Start(IntPtr formHandle) { if (Win2000OrLater) { FLASHWINFO pwfi = Create_FLASHWINFO(formHandle, 3u, uint.MaxValue, 0u); return FlashWindowEx(ref pwfi); } return false; } public static bool Stop(IntPtr formHandle) { if (Win2000OrLater) { FLASHWINFO pwfi = Create_FLASHWINFO(formHandle, 0u, uint.MaxValue, 0u); return FlashWindowEx(ref pwfi); } return false; } [InitDuringStartup] private static void Init() { SceneManager.activeSceneChanged += delegate(Scene previousScene, Scene newScene) { if (newScene.name == "lobby") { Flash(); } }; NetworkManagerSystem.onClientConnectGlobal += delegate { Flash(); }; } } public class FPSQueue : MonoBehaviour { public static float fpsThrottlingCutoff = 28f; public static float currentFPS = 30f; public static int numSamples = 30; private static int sampleIndex = 0; private static float[] unitySamples; private static int waitTurn = 0; private static int waitIndex = 0; private static int maxWaitIndex = 5; private void Start() { RoR2Application.onUpdate += UpdateFPSLimitVars; unitySamples = new float[numSamples]; } public static int GetWaitIndex() { waitIndex++; if (waitIndex > maxWaitIndex) { waitIndex = 0; } return waitIndex; } public static bool CheckFPSQueue(ref int waitIndex) { if (waitIndex == 0) { waitIndex = GetWaitIndex(); } if (currentFPS < fpsThrottlingCutoff && waitIndex != waitTurn) { return false; } return true; } private static void UpdateFPSLimitVars() { waitTurn++; if (waitTurn > maxWaitIndex) { waitTurn = 0; } CalculateFramerate(); } private static void CalculateFramerate() { unitySamples[sampleIndex++] = 1f / Time.unscaledDeltaTime; if (sampleIndex == numSamples) { sampleIndex = 0; } float num = 0f; for (int i = 0; i < numSamples; i++) { num += unitySamples[i]; } currentFPS = num / (float)numSamples; } } [ExecuteAlways] public class BeamPointsFromTransforms : MonoBehaviour { [Tooltip("Line Renderer to set the positions of.")] public LineRenderer target; [Tooltip("Transforms to use as the points for the line renderer.")] [SerializeField] private Transform[] pointTransforms = Array.Empty(); private void Start() { UpdateBeamPositions(); } private void Update() { UpdateBeamPositions(); } private void UpdateBeamPositions() { if (!target) { return; } int num = pointTransforms.Length; target.positionCount = num; for (int i = 0; i < num; i++) { Transform transform = pointTransforms[i]; if ((bool)transform) { target.SetPosition(i, transform.position); } } } } public class BeginRapidlyActivatingAndDeactivating : MonoBehaviour { public float blinkFrequency = 10f; public float delayBeforeBeginningBlinking = 30f; public GameObject blinkingRootObject; private float fixedAge; private float blinkAge; private void FixedUpdate() { fixedAge += Time.fixedDeltaTime; if (fixedAge >= delayBeforeBeginningBlinking) { blinkAge += Time.fixedDeltaTime; if (blinkAge >= 1f / blinkFrequency) { blinkAge -= 1f / blinkFrequency; blinkingRootObject.SetActive(!blinkingRootObject.activeSelf); } } } } [RequireComponent(typeof(LineRenderer))] [ExecuteAlways] public class BezierCurveLine : MonoBehaviour { private UnityEngine.Vector3[] vertexList = Array.Empty(); private UnityEngine.Vector3 p0 = UnityEngine.Vector3.zero; public UnityEngine.Vector3 v0 = UnityEngine.Vector3.zero; public UnityEngine.Vector3 p1 = UnityEngine.Vector3.zero; public UnityEngine.Vector3 v1 = UnityEngine.Vector3.zero; public Transform endTransform; public bool animateBezierWind; public UnityEngine.Vector3 windMagnitude; public UnityEngine.Vector3 windFrequency; private UnityEngine.Vector3 windPhaseShift; private UnityEngine.Vector3 lastWind; private UnityEngine.Vector3 finalv0; private UnityEngine.Vector3 finalv1; private float windTime; public LineRenderer lineRenderer { get; private set; } private void Awake() { lineRenderer = GetComponent(); windPhaseShift = UnityEngine.Random.insideUnitSphere * 360f; Array.Resize(ref vertexList, lineRenderer.positionCount + 1); UpdateBezier(0f); } public void OnEnable() { Array.Resize(ref vertexList, lineRenderer.positionCount + 1); } private void LateUpdate() { UpdateBezier(Time.deltaTime); } public void UpdateBezier(float deltaTime) { windTime += deltaTime; p0 = base.transform.position; if ((bool)endTransform) { p1 = endTransform.position; } if (animateBezierWind) { finalv0 = v0 + new UnityEngine.Vector3(Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.x) * windFrequency.x) * windMagnitude.x, Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.y) * windFrequency.y) * windMagnitude.y, Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.z) * windFrequency.z) * windMagnitude.z); finalv1 = v1 + new UnityEngine.Vector3(Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.x + p1.x) * windFrequency.x) * windMagnitude.x, Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.y + p1.z) * windFrequency.y) * windMagnitude.y, Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.z + p1.y) * windFrequency.z) * windMagnitude.z); } else { finalv0 = v0; finalv1 = v1; } for (int i = 0; i < vertexList.Length; i++) { float t = (float)i / (float)(vertexList.Length - 2); vertexList[i] = EvaluateBezier(t); } lineRenderer.SetPositions(vertexList); } private UnityEngine.Vector3 EvaluateBezier(float t) { UnityEngine.Vector3 a = UnityEngine.Vector3.Lerp(p0, p0 + finalv0, t); UnityEngine.Vector3 b = UnityEngine.Vector3.Lerp(p1, p1 + finalv1, 1f - t); return UnityEngine.Vector3.Lerp(a, b, t); } } public class BlockObjectOnLoad : MonoBehaviour { private void Start() { if (!RoR2Application.loadFinished) { base.gameObject.SetActive(value: false); RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, (Action)delegate { base.gameObject.SetActive(value: true); }); } } } public class BobObject : MonoBehaviour { public float bobDelay; public UnityEngine.Vector3 bobDistance = UnityEngine.Vector3.zero; private UnityEngine.Vector3 initialPosition; private void Start() { if ((bool)base.transform.parent) { initialPosition = base.transform.localPosition; } else { initialPosition = base.transform.position; } } private void FixedUpdate() { if ((bool)Run.instance) { UnityEngine.Vector3 vector = initialPosition + bobDistance * Mathf.Sin(Run.instance.fixedTime - bobDelay); if ((bool)base.transform.parent) { base.transform.localPosition = vector; } else { base.transform.position = vector; } } } } [DisallowMultipleComponent] public class ChildLocator : MonoBehaviour { [Serializable] private struct NameTransformPair { public string name; public Transform transform; } [SerializeField] private NameTransformPair[] transformPairs = Array.Empty(); public int Count => transformPairs.Length; public int FindChildIndex(string childName) { for (int i = 0; i < transformPairs.Length; i++) { if (childName == transformPairs[i].name) { return i; } } return -1; } public int FindChildIndex(Transform childTransform) { for (int i = 0; i < transformPairs.Length; i++) { if ((object)childTransform == transformPairs[i].transform) { return i; } } return -1; } public string FindChildName(int childIndex) { if ((uint)childIndex < transformPairs.Length) { return transformPairs[childIndex].name; } return null; } public Transform FindChild(string childName) { return FindChild(FindChildIndex(childName)); } public GameObject FindChildGameObject(int childIndex) { Transform transform = FindChild(childIndex); if (!transform) { return null; } return transform.gameObject; } public GameObject FindChildGameObject(string childName) { return FindChildGameObject(FindChildIndex(childName)); } public Transform FindChild(int childIndex) { if ((uint)childIndex < transformPairs.Length) { return transformPairs[childIndex].transform; } return null; } public T FindChildComponent(string childName) { return FindChildComponent(FindChildIndex(childName)); } public T FindChildComponent(int childIndex) { Transform transform = FindChild(childIndex); if (!transform) { return default(T); } return transform.GetComponent(); } } public class DestroyOnKill : MonoBehaviour, IOnKilledServerReceiver { public GameObject effectPrefab; public void OnKilledServer(DamageReport damageReport) { UnityEngine.Object.Instantiate(effectPrefab, base.transform.position, base.transform.rotation); UnityEngine.Object.Destroy(base.gameObject); } } public class DestroyOnParticleEnd : MonoBehaviour { [SerializeField] [Tooltip("Set this if you want to specify which particle system is tracked. Otherwise it will automatically grab the first one it finds.")] private ParticleSystem trackedParticleSystem; private EffectManagerHelper efh; public void Start() { if (trackedParticleSystem == null) { trackedParticleSystem = GetComponentInChildren(); } if (!efh) { efh = GetComponent(); } } public void Update() { if ((bool)trackedParticleSystem && !trackedParticleSystem.IsAlive()) { if ((bool)efh && efh.OwningPool != null) { efh.OwningPool.ReturnObject(efh); } else { UnityEngine.Object.Destroy(base.gameObject); } } } } [RequireComponent(typeof(AudioSource))] public class DestroyOnSoundEnd : MonoBehaviour { private AudioSource audioSource; private void Awake() { audioSource = GetComponent(); } private void Update() { if (!audioSource.isPlaying) { UnityEngine.Object.Destroy(base.gameObject); } } } public class DisableOnStart : MonoBehaviour { private void Start() { base.gameObject.SetActive(value: false); } } [AddComponentMenu("Dynamic Bone/Dynamic Bone")] public class DynamicBone : MonoBehaviour { public enum UpdateMode { Normal, AnimatePhysics, UnscaledTime } public enum FreezeAxis { None, X, Y, Z } private class Particle { public Transform m_Transform; public int m_ParentIndex = -1; public float m_Damping; public float m_Elasticity; public float m_Stiffness; public float m_Inert; public float m_Radius; public float m_BoneLength; public UnityEngine.Vector3 m_Position = UnityEngine.Vector3.zero; public UnityEngine.Vector3 m_PrevPosition = UnityEngine.Vector3.zero; public UnityEngine.Vector3 m_EndOffset = UnityEngine.Vector3.zero; public UnityEngine.Vector3 m_InitLocalPosition = UnityEngine.Vector3.zero; public UnityEngine.Quaternion m_InitLocalRotation = UnityEngine.Quaternion.identity; } public Transform m_Root; public float m_UpdateRate = 60f; public UpdateMode m_UpdateMode; [Range(0f, 1f)] public float m_Damping = 0.1f; public AnimationCurve m_DampingDistrib; [Range(0f, 1f)] public float m_Elasticity = 0.1f; public AnimationCurve m_ElasticityDistrib; [Range(0f, 1f)] public float m_Stiffness = 0.1f; public AnimationCurve m_StiffnessDistrib; [Range(0f, 1f)] public float m_Inert; public AnimationCurve m_InertDistrib; public float m_Radius; public AnimationCurve m_RadiusDistrib; public float m_EndLength; public UnityEngine.Vector3 m_EndOffset = UnityEngine.Vector3.zero; public UnityEngine.Vector3 m_Gravity = UnityEngine.Vector3.zero; public UnityEngine.Vector3 m_Force = UnityEngine.Vector3.zero; public List m_Colliders; public List m_Exclusions; public FreezeAxis m_FreezeAxis; public bool m_DistantDisable; public Transform m_ReferenceObject; public float m_DistanceToObject = 20f; [Tooltip("Check this if you want the bone to be dynamic even on low performance HW")] public bool neverOptimize; private UnityEngine.Vector3 m_LocalGravity = UnityEngine.Vector3.zero; private UnityEngine.Vector3 m_ObjectMove = UnityEngine.Vector3.zero; private UnityEngine.Vector3 m_ObjectPrevPosition = UnityEngine.Vector3.zero; private float m_BoneTotalLength; private float m_ObjectScale = 1f; private float m_Time; private float m_Weight = 1f; private bool m_DistantDisabled; private List m_Particles = new List(); private void Start() { SetupParticles(); } private void FixedUpdate() { if (m_UpdateMode == UpdateMode.AnimatePhysics) { PreUpdate(); } } private void Update() { if (m_UpdateMode != UpdateMode.AnimatePhysics) { PreUpdate(); } } private void LateUpdate() { if (m_DistantDisable) { CheckDistance(); } if (m_Weight > 0f && (!m_DistantDisable || !m_DistantDisabled)) { float deltaTime = Time.deltaTime; UpdateDynamicBones(deltaTime); } } private void PreUpdate() { if (m_Weight > 0f && (!m_DistantDisable || !m_DistantDisabled)) { InitTransforms(); } } private void CheckDistance() { Transform referenceObject = m_ReferenceObject; if (referenceObject == null && (bool)Camera.main) { referenceObject = Camera.main.transform; } if (!referenceObject) { return; } bool flag = (referenceObject.position - base.transform.position).sqrMagnitude > m_DistanceToObject * m_DistanceToObject; if (flag != m_DistantDisabled) { if (!flag) { ResetParticlesPosition(); } m_DistantDisabled = flag; } } private void OnEnable() { ResetParticlesPosition(); } private void OnDisable() { InitTransforms(); } private void OnValidate() { m_UpdateRate = Mathf.Max(m_UpdateRate, 0f); m_Damping = Mathf.Clamp01(m_Damping); m_Elasticity = Mathf.Clamp01(m_Elasticity); m_Stiffness = Mathf.Clamp01(m_Stiffness); m_Inert = Mathf.Clamp01(m_Inert); m_Radius = Mathf.Max(m_Radius, 0f); if (Application.isEditor && Application.isPlaying) { InitTransforms(); SetupParticles(); } } private void OnDrawGizmosSelected() { if (!base.enabled || m_Root == null) { return; } if (Application.isEditor && !Application.isPlaying && base.transform.hasChanged) { InitTransforms(); SetupParticles(); } Gizmos.color = UnityEngine.Color.white; for (int i = 0; i < m_Particles.Count; i++) { Particle particle = m_Particles[i]; if (particle.m_ParentIndex >= 0) { Particle particle2 = m_Particles[particle.m_ParentIndex]; Gizmos.DrawLine(particle.m_Position, particle2.m_Position); } if (particle.m_Radius > 0f) { Gizmos.DrawWireSphere(particle.m_Position, particle.m_Radius * m_ObjectScale); } } } public void SetWeight(float w) { if (m_Weight != w) { if (w == 0f) { InitTransforms(); } else if (m_Weight == 0f) { ResetParticlesPosition(); } m_Weight = w; } } public float GetWeight() { return m_Weight; } private void UpdateDynamicBones(float t) { if (m_Root == null) { return; } m_ObjectScale = Mathf.Abs(base.transform.lossyScale.x); m_ObjectMove = base.transform.position - m_ObjectPrevPosition; m_ObjectPrevPosition = base.transform.position; int num = 1; if (m_UpdateRate > 0f) { float num2 = 1f / m_UpdateRate; m_Time += t; num = 0; while (m_Time >= num2) { m_Time -= num2; if (++num >= 3) { m_Time = 0f; break; } } } if (num > 0) { for (int i = 0; i < num; i++) { UpdateParticles1(); UpdateParticles2(); m_ObjectMove = UnityEngine.Vector3.zero; } } else { SkipUpdateParticles(); } ApplyParticlesToTransforms(); } private void SetupParticles() { m_Particles.Clear(); if (m_Root == null) { return; } m_LocalGravity = m_Root.InverseTransformDirection(m_Gravity); m_ObjectScale = Mathf.Abs(base.transform.lossyScale.x); m_ObjectPrevPosition = base.transform.position; m_ObjectMove = UnityEngine.Vector3.zero; m_BoneTotalLength = 0f; AppendParticles(m_Root, -1, 0f); for (int i = 0; i < m_Particles.Count; i++) { Particle particle = m_Particles[i]; particle.m_Damping = m_Damping; particle.m_Elasticity = m_Elasticity; particle.m_Stiffness = m_Stiffness; particle.m_Inert = m_Inert; particle.m_Radius = m_Radius; if (m_BoneTotalLength > 0f) { float time = particle.m_BoneLength / m_BoneTotalLength; if (m_DampingDistrib != null && m_DampingDistrib.keys.Length != 0) { particle.m_Damping *= m_DampingDistrib.Evaluate(time); } if (m_ElasticityDistrib != null && m_ElasticityDistrib.keys.Length != 0) { particle.m_Elasticity *= m_ElasticityDistrib.Evaluate(time); } if (m_StiffnessDistrib != null && m_StiffnessDistrib.keys.Length != 0) { particle.m_Stiffness *= m_StiffnessDistrib.Evaluate(time); } if (m_InertDistrib != null && m_InertDistrib.keys.Length != 0) { particle.m_Inert *= m_InertDistrib.Evaluate(time); } if (m_RadiusDistrib != null && m_RadiusDistrib.keys.Length != 0) { particle.m_Radius *= m_RadiusDistrib.Evaluate(time); } } particle.m_Damping = Mathf.Clamp01(particle.m_Damping); particle.m_Elasticity = Mathf.Clamp01(particle.m_Elasticity); particle.m_Stiffness = Mathf.Clamp01(particle.m_Stiffness); particle.m_Inert = Mathf.Clamp01(particle.m_Inert); particle.m_Radius = Mathf.Max(particle.m_Radius, 0f); } } private void AppendParticles(Transform b, int parentIndex, float boneLength) { Particle particle = new Particle(); particle.m_Transform = b; particle.m_ParentIndex = parentIndex; if ((bool)b) { particle.m_Position = (particle.m_PrevPosition = b.position); particle.m_InitLocalPosition = b.localPosition; particle.m_InitLocalRotation = b.localRotation; } else { Transform transform = m_Particles[parentIndex].m_Transform; if (m_EndLength > 0f) { Transform parent = transform.parent; if ((bool)parent) { particle.m_EndOffset = transform.InverseTransformPoint(transform.position * 2f - parent.position) * m_EndLength; } else { particle.m_EndOffset = new UnityEngine.Vector3(m_EndLength, 0f, 0f); } } else { particle.m_EndOffset = transform.InverseTransformPoint(base.transform.TransformDirection(m_EndOffset) + transform.position); } particle.m_Position = (particle.m_PrevPosition = transform.TransformPoint(particle.m_EndOffset)); } if (parentIndex >= 0) { boneLength += (m_Particles[parentIndex].m_Transform.position - particle.m_Position).magnitude; particle.m_BoneLength = boneLength; m_BoneTotalLength = Mathf.Max(m_BoneTotalLength, boneLength); } int count = m_Particles.Count; m_Particles.Add(particle); if (!b) { return; } for (int i = 0; i < b.childCount; i++) { bool flag = false; if (m_Exclusions != null) { for (int j = 0; j < m_Exclusions.Count; j++) { if (m_Exclusions[j] == b.GetChild(i)) { flag = true; break; } } } if (!flag) { AppendParticles(b.GetChild(i), count, boneLength); } } if (b.childCount == 0 && (m_EndLength > 0f || m_EndOffset != UnityEngine.Vector3.zero)) { AppendParticles(null, count, boneLength); } } private void InitTransforms() { for (int i = 0; i < m_Particles.Count; i++) { Particle particle = m_Particles[i]; if ((bool)particle.m_Transform) { particle.m_Transform.localPosition = particle.m_InitLocalPosition; particle.m_Transform.localRotation = particle.m_InitLocalRotation; } } } private void ResetParticlesPosition() { for (int i = 0; i < m_Particles.Count; i++) { Particle particle = m_Particles[i]; if ((bool)particle.m_Transform) { particle.m_Position = (particle.m_PrevPosition = particle.m_Transform.position); continue; } Transform transform = m_Particles[particle.m_ParentIndex].m_Transform; particle.m_Position = (particle.m_PrevPosition = transform.TransformPoint(particle.m_EndOffset)); } m_ObjectPrevPosition = base.transform.position; } private void UpdateParticles1() { UnityEngine.Vector3 gravity = m_Gravity; UnityEngine.Vector3 normalized = m_Gravity.normalized; UnityEngine.Vector3 lhs = m_Root.TransformDirection(m_LocalGravity); UnityEngine.Vector3 vector = normalized * Mathf.Max(UnityEngine.Vector3.Dot(lhs, normalized), 0f); gravity -= vector; gravity = (gravity + m_Force) * m_ObjectScale; for (int i = 0; i < m_Particles.Count; i++) { Particle particle = m_Particles[i]; if (particle.m_ParentIndex >= 0) { UnityEngine.Vector3 vector2 = particle.m_Position - particle.m_PrevPosition; UnityEngine.Vector3 vector3 = m_ObjectMove * particle.m_Inert; particle.m_PrevPosition = particle.m_Position + vector3; particle.m_Position += vector2 * (1f - particle.m_Damping) + gravity + vector3; } else { particle.m_PrevPosition = particle.m_Position; particle.m_Position = particle.m_Transform.position; } } } private void UpdateParticles2() { UnityEngine.Plane plane = default(UnityEngine.Plane); for (int i = 1; i < m_Particles.Count; i++) { Particle particle = m_Particles[i]; Particle particle2 = m_Particles[particle.m_ParentIndex]; if (!particle2.m_Transform) { continue; } float num = ((!particle.m_Transform) ? particle2.m_Transform.localToWorldMatrix.MultiplyVector(particle.m_EndOffset).magnitude : (particle2.m_Transform.position - particle.m_Transform.position).magnitude); float num2 = Mathf.Lerp(1f, particle.m_Stiffness, m_Weight); if (num2 > 0f || particle.m_Elasticity > 0f) { UnityEngine.Matrix4x4 localToWorldMatrix = particle2.m_Transform.localToWorldMatrix; localToWorldMatrix.SetColumn(3, particle2.m_Position); UnityEngine.Vector3 vector = ((!particle.m_Transform) ? localToWorldMatrix.MultiplyPoint3x4(particle.m_EndOffset) : localToWorldMatrix.MultiplyPoint3x4(particle.m_Transform.localPosition)); UnityEngine.Vector3 vector2 = vector - particle.m_Position; particle.m_Position += vector2 * particle.m_Elasticity; if (num2 > 0f) { vector2 = vector - particle.m_Position; float magnitude = vector2.magnitude; float num3 = num * (1f - num2) * 2f; if (magnitude > num3) { particle.m_Position += vector2 * ((magnitude - num3) / magnitude); } } } if (m_Colliders != null) { float particleRadius = particle.m_Radius * m_ObjectScale; for (int j = 0; j < m_Colliders.Count; j++) { DynamicBoneCollider dynamicBoneCollider = m_Colliders[j]; if ((bool)dynamicBoneCollider && dynamicBoneCollider.enabled) { dynamicBoneCollider.Collide(ref particle.m_Position, particleRadius); } } } if (m_FreezeAxis != 0) { switch (m_FreezeAxis) { case FreezeAxis.X: plane.SetNormalAndPosition(particle2.m_Transform.right, particle2.m_Position); break; case FreezeAxis.Y: plane.SetNormalAndPosition(particle2.m_Transform.up, particle2.m_Position); break; case FreezeAxis.Z: plane.SetNormalAndPosition(particle2.m_Transform.forward, particle2.m_Position); break; } particle.m_Position -= plane.normal * plane.GetDistanceToPoint(particle.m_Position); } UnityEngine.Vector3 vector3 = particle2.m_Position - particle.m_Position; float magnitude2 = vector3.magnitude; if (magnitude2 > 0f) { particle.m_Position += vector3 * ((magnitude2 - num) / magnitude2); } } } private void SkipUpdateParticles() { for (int i = 0; i < m_Particles.Count; i++) { Particle particle = m_Particles[i]; if (particle.m_ParentIndex >= 0) { particle.m_PrevPosition += m_ObjectMove; particle.m_Position += m_ObjectMove; Particle particle2 = m_Particles[particle.m_ParentIndex]; if (!particle2.m_Transform) { continue; } float num = ((!particle.m_Transform) ? particle2.m_Transform.localToWorldMatrix.MultiplyVector(particle.m_EndOffset).magnitude : (particle2.m_Transform.position - particle.m_Transform.position).magnitude); float num2 = Mathf.Lerp(1f, particle.m_Stiffness, m_Weight); if (num2 > 0f) { UnityEngine.Matrix4x4 localToWorldMatrix = particle2.m_Transform.localToWorldMatrix; localToWorldMatrix.SetColumn(3, particle2.m_Position); UnityEngine.Vector3 vector = ((!particle.m_Transform) ? localToWorldMatrix.MultiplyPoint3x4(particle.m_EndOffset) : localToWorldMatrix.MultiplyPoint3x4(particle.m_Transform.localPosition)); UnityEngine.Vector3 vector2 = vector - particle.m_Position; float magnitude = vector2.magnitude; float num3 = num * (1f - num2) * 2f; if (magnitude > num3) { particle.m_Position += vector2 * ((magnitude - num3) / magnitude); } } UnityEngine.Vector3 vector3 = particle2.m_Position - particle.m_Position; float magnitude2 = vector3.magnitude; if (magnitude2 > 0f) { particle.m_Position += vector3 * ((magnitude2 - num) / magnitude2); } } else if ((bool)particle.m_Transform) { particle.m_PrevPosition = particle.m_Position; particle.m_Position = particle.m_Transform.position; } } } private static UnityEngine.Vector3 MirrorVector(UnityEngine.Vector3 v, UnityEngine.Vector3 axis) { return v - axis * (UnityEngine.Vector3.Dot(v, axis) * 2f); } private void ApplyParticlesToTransforms() { for (int i = 1; i < m_Particles.Count; i++) { Particle particle = m_Particles[i]; Particle particle2 = m_Particles[particle.m_ParentIndex]; if (particle2.m_Transform.childCount <= 1) { UnityEngine.Vector3 direction = ((!particle.m_Transform) ? particle.m_EndOffset : particle.m_Transform.localPosition); UnityEngine.Vector3 toDirection = particle.m_Position - particle2.m_Position; UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.FromToRotation(particle2.m_Transform.TransformDirection(direction), toDirection); particle2.m_Transform.rotation = quaternion * particle2.m_Transform.rotation; } if ((bool)particle.m_Transform) { particle.m_Transform.position = particle.m_Position; } } } } [AddComponentMenu("Dynamic Bone/Dynamic Bone Collider")] public class DynamicBoneCollider : MonoBehaviour { public enum Direction { X, Y, Z } public enum Bound { Outside, Inside } public UnityEngine.Vector3 m_Center = UnityEngine.Vector3.zero; public float m_Radius = 0.5f; public float m_Height; public Direction m_Direction; public Bound m_Bound; private void OnValidate() { m_Radius = Mathf.Max(m_Radius, 0f); m_Height = Mathf.Max(m_Height, 0f); } public void Collide(ref UnityEngine.Vector3 particlePosition, float particleRadius) { float num = m_Radius * Mathf.Abs(base.transform.lossyScale.x); float num2 = m_Height * 0.5f - m_Radius; if (num2 <= 0f) { if (m_Bound == Bound.Outside) { OutsideSphere(ref particlePosition, particleRadius, base.transform.TransformPoint(m_Center), num); } else { InsideSphere(ref particlePosition, particleRadius, base.transform.TransformPoint(m_Center), num); } return; } UnityEngine.Vector3 center = m_Center; UnityEngine.Vector3 center2 = m_Center; switch (m_Direction) { case Direction.X: center.x -= num2; center2.x += num2; break; case Direction.Y: center.y -= num2; center2.y += num2; break; case Direction.Z: center.z -= num2; center2.z += num2; break; } if (m_Bound == Bound.Outside) { OutsideCapsule(ref particlePosition, particleRadius, base.transform.TransformPoint(center), base.transform.TransformPoint(center2), num); } else { InsideCapsule(ref particlePosition, particleRadius, base.transform.TransformPoint(center), base.transform.TransformPoint(center2), num); } } private static void OutsideSphere(ref UnityEngine.Vector3 particlePosition, float particleRadius, UnityEngine.Vector3 sphereCenter, float sphereRadius) { float num = sphereRadius + particleRadius; float num2 = num * num; UnityEngine.Vector3 vector = particlePosition - sphereCenter; float sqrMagnitude = vector.sqrMagnitude; if (sqrMagnitude > 0f && sqrMagnitude < num2) { float num3 = Mathf.Sqrt(sqrMagnitude); particlePosition = sphereCenter + vector * (num / num3); } } private static void InsideSphere(ref UnityEngine.Vector3 particlePosition, float particleRadius, UnityEngine.Vector3 sphereCenter, float sphereRadius) { float num = sphereRadius - particleRadius; float num2 = num * num; UnityEngine.Vector3 vector = particlePosition - sphereCenter; float sqrMagnitude = vector.sqrMagnitude; if (sqrMagnitude > num2) { float num3 = Mathf.Sqrt(sqrMagnitude); particlePosition = sphereCenter + vector * (num / num3); } } private static void OutsideCapsule(ref UnityEngine.Vector3 particlePosition, float particleRadius, UnityEngine.Vector3 capsuleP0, UnityEngine.Vector3 capsuleP1, float capsuleRadius) { float num = capsuleRadius + particleRadius; float num2 = num * num; UnityEngine.Vector3 vector = capsuleP1 - capsuleP0; UnityEngine.Vector3 vector2 = particlePosition - capsuleP0; float num3 = UnityEngine.Vector3.Dot(vector2, vector); if (num3 <= 0f) { float sqrMagnitude = vector2.sqrMagnitude; if (sqrMagnitude > 0f && sqrMagnitude < num2) { float num4 = Mathf.Sqrt(sqrMagnitude); particlePosition = capsuleP0 + vector2 * (num / num4); } return; } float sqrMagnitude2 = vector.sqrMagnitude; if (num3 >= sqrMagnitude2) { vector2 = particlePosition - capsuleP1; float sqrMagnitude3 = vector2.sqrMagnitude; if (sqrMagnitude3 > 0f && sqrMagnitude3 < num2) { float num5 = Mathf.Sqrt(sqrMagnitude3); particlePosition = capsuleP1 + vector2 * (num / num5); } } else if (sqrMagnitude2 > 0f) { num3 /= sqrMagnitude2; vector2 -= vector * num3; float sqrMagnitude4 = vector2.sqrMagnitude; if (sqrMagnitude4 > 0f && sqrMagnitude4 < num2) { float num6 = Mathf.Sqrt(sqrMagnitude4); particlePosition += vector2 * ((num - num6) / num6); } } } private static void InsideCapsule(ref UnityEngine.Vector3 particlePosition, float particleRadius, UnityEngine.Vector3 capsuleP0, UnityEngine.Vector3 capsuleP1, float capsuleRadius) { float num = capsuleRadius - particleRadius; float num2 = num * num; UnityEngine.Vector3 vector = capsuleP1 - capsuleP0; UnityEngine.Vector3 vector2 = particlePosition - capsuleP0; float num3 = UnityEngine.Vector3.Dot(vector2, vector); if (num3 <= 0f) { float sqrMagnitude = vector2.sqrMagnitude; if (sqrMagnitude > num2) { float num4 = Mathf.Sqrt(sqrMagnitude); particlePosition = capsuleP0 + vector2 * (num / num4); } return; } float sqrMagnitude2 = vector.sqrMagnitude; if (num3 >= sqrMagnitude2) { vector2 = particlePosition - capsuleP1; float sqrMagnitude3 = vector2.sqrMagnitude; if (sqrMagnitude3 > num2) { float num5 = Mathf.Sqrt(sqrMagnitude3); particlePosition = capsuleP1 + vector2 * (num / num5); } } else if (sqrMagnitude2 > 0f) { num3 /= sqrMagnitude2; vector2 -= vector * num3; float sqrMagnitude4 = vector2.sqrMagnitude; if (sqrMagnitude4 > num2) { float num6 = Mathf.Sqrt(sqrMagnitude4); particlePosition += vector2 * ((num - num6) / num6); } } } private void OnDrawGizmosSelected() { if (!base.enabled) { return; } if (m_Bound == Bound.Outside) { Gizmos.color = UnityEngine.Color.yellow; } else { Gizmos.color = UnityEngine.Color.magenta; } float radius = m_Radius * Mathf.Abs(base.transform.lossyScale.x); float num = m_Height * 0.5f - m_Radius; if (num <= 0f) { Gizmos.DrawWireSphere(base.transform.TransformPoint(m_Center), radius); return; } UnityEngine.Vector3 center = m_Center; UnityEngine.Vector3 center2 = m_Center; switch (m_Direction) { case Direction.X: center.x -= num; center2.x += num; break; case Direction.Y: center.y -= num; center2.y += num; break; case Direction.Z: center.z -= num; center2.z += num; break; } Gizmos.DrawWireSphere(base.transform.TransformPoint(center), radius); Gizmos.DrawWireSphere(base.transform.TransformPoint(center2), radius); } } public class FloatPID : MonoBehaviour { [Tooltip("PID Constants.")] public UnityEngine.Vector3 PID = new UnityEngine.Vector3(1f, 0f, 0f); public float gain = 1f; [Tooltip("The value we are currently at.")] [HideInInspector] public float inputFloat; [HideInInspector] [Tooltip("The value we want to be at.")] public float targetFloat; [Tooltip("Value output from PID controller; what we read.")] [HideInInspector] public float outputFloat; public float timeBetweenUpdates; private float timer; private float errorSum; private float deltaError; private float lastError; private float lastTimer; public bool automaticallyUpdate; private void Start() { } private void FixedUpdate() { timer += Time.fixedDeltaTime; if (automaticallyUpdate && timer > timeBetweenUpdates) { timer -= timeBetweenUpdates; outputFloat = UpdatePID(); } } public float UpdatePID() { float num = timer - lastTimer; lastTimer = timer; float num2 = targetFloat - inputFloat; errorSum += num2 * num; deltaError = (num2 - lastError) / num; lastError = num2; return (num2 * PID.x + errorSum * PID.y + deltaError * PID.z) * gain; } } [RequireComponent(typeof(Animator))] [ExecuteInEditMode] public class ForcePose : MonoBehaviour { [Tooltip("The animation clip to force.")] public AnimationClip clip; [Tooltip("The moment in the cycle to force.")] [Range(0f, 1f)] public float cycle; private void Start() { } private void Update() { if ((bool)clip) { clip.SampleAnimation(base.gameObject, cycle * clip.length); } } } [ExecuteInEditMode] public class GlobalShaderTextures : MonoBehaviour { public Texture warpRampTexture; public string warpRampShaderVariableName; public Texture eliteRampTexture; public string eliteRampShaderVariableName; public Texture snowMicrofacetTexture; public string snowMicrofacetNoiseVariableName; private void OnValidate() { Shader.SetGlobalTexture(warpRampShaderVariableName, warpRampTexture); Shader.SetGlobalTexture(eliteRampShaderVariableName, eliteRampTexture); Shader.SetGlobalTexture(snowMicrofacetNoiseVariableName, snowMicrofacetTexture); } private void Start() { Shader.SetGlobalTexture(warpRampShaderVariableName, warpRampTexture); Shader.SetGlobalTexture(eliteRampShaderVariableName, eliteRampTexture); Shader.SetGlobalTexture(snowMicrofacetNoiseVariableName, snowMicrofacetTexture); } } public class HoverOverHead : MonoBehaviour { private Transform parentTransform; private Collider bodyCollider; public UnityEngine.Vector3 bonusOffset; private void Start() { Reset(); } public void Reset() { if ((bool)base.transform) { parentTransform = base.transform.parent; bodyCollider = ((parentTransform == null) ? null : parentTransform.GetComponent()); } } private void Update() { if ((bool)parentTransform) { UnityEngine.Vector3 vector = parentTransform.position; if ((bool)bodyCollider) { vector = bodyCollider.bounds.center + new UnityEngine.Vector3(0f, bodyCollider.bounds.extents.y, 0f); } base.transform.position = vector + bonusOffset; } } } [RequireComponent(typeof(InterpolatedTransformUpdater))] public class InterpolatedTransform : MonoBehaviour, ITeleportHandler, IEventSystemHandler { private struct TransformData { public UnityEngine.Vector3 position; public UnityEngine.Quaternion rotation; public UnityEngine.Vector3 scale; public TransformData(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, UnityEngine.Vector3 scale) { this.position = position; this.rotation = rotation; this.scale = scale; } } private TransformData[] m_lastTransforms; private int m_newTransformIndex; private void OnEnable() { ForgetPreviousTransforms(); } public void ForgetPreviousTransforms() { m_lastTransforms = new TransformData[2]; TransformData transformData = new TransformData(base.transform.localPosition, base.transform.localRotation, base.transform.localScale); m_lastTransforms[0] = transformData; m_lastTransforms[1] = transformData; m_newTransformIndex = 0; } private void FixedUpdate() { TransformData transformData = m_lastTransforms[m_newTransformIndex]; base.transform.localPosition = transformData.position; base.transform.localRotation = transformData.rotation; base.transform.localScale = transformData.scale; } public void LateFixedUpdate() { m_newTransformIndex = OldTransformIndex(); m_lastTransforms[m_newTransformIndex] = new TransformData(base.transform.localPosition, base.transform.localRotation, base.transform.localScale); } private void Update() { TransformData transformData = m_lastTransforms[m_newTransformIndex]; TransformData transformData2 = m_lastTransforms[OldTransformIndex()]; base.transform.localPosition = UnityEngine.Vector3.Lerp(transformData2.position, transformData.position, InterpolationController.InterpolationFactor); base.transform.localRotation = UnityEngine.Quaternion.Slerp(transformData2.rotation, transformData.rotation, InterpolationController.InterpolationFactor); base.transform.localScale = UnityEngine.Vector3.Lerp(transformData2.scale, transformData.scale, InterpolationController.InterpolationFactor); } private int OldTransformIndex() { if (m_newTransformIndex != 0) { return 0; } return 1; } public void OnTeleport(UnityEngine.Vector3 oldPosition, UnityEngine.Vector3 newPosition) { ForgetPreviousTransforms(); } } public class InterpolatedTransformUpdater : MonoBehaviour { private InterpolatedTransform m_interpolatedTransform; private void Awake() { m_interpolatedTransform = GetComponent(); } private void FixedUpdate() { m_interpolatedTransform.LateFixedUpdate(); } } public class InterpolationController : MonoBehaviour { private float[] m_lastFixedUpdateTimes; private int m_newTimeIndex; private static float m_interpolationFactor; public static float InterpolationFactor => m_interpolationFactor; public void Start() { m_lastFixedUpdateTimes = new float[2]; m_newTimeIndex = 0; } public void FixedUpdate() { m_newTimeIndex = OldTimeIndex(); m_lastFixedUpdateTimes[m_newTimeIndex] = Time.fixedTime; } public void Update() { float num = m_lastFixedUpdateTimes[m_newTimeIndex]; float num2 = m_lastFixedUpdateTimes[OldTimeIndex()]; if (num != num2) { m_interpolationFactor = (Time.time - num) / (num - num2); } else { m_interpolationFactor = 1f; } } private int OldTimeIndex() { if (m_newTimeIndex != 0) { return 0; } return 1; } } public class LightIntensityCurve : MonoBehaviour { public AnimationCurve curve; public float timeMax = 5f; private float time; private Light light; private float maxIntensity; [Tooltip("Loops the animation curve.")] public bool loop; [Tooltip("Starts in a random point in the animation curve.")] public bool randomStart; [Tooltip("Causes the lights to be negative, casting shadows instead.")] public bool enableNegativeLights; private void Awake() { if ((bool)light || TryGetComponent(out light)) { maxIntensity = light.intensity; } } private void Start() { light.intensity = 0f; if (randomStart) { time = UnityEngine.Random.Range(0f, timeMax); } if (enableNegativeLights) { light.color = new UnityEngine.Color(0f - light.color.r, 0f - light.color.g, 0f - light.color.b); } } private void OnEnable() { time = 0f; if (!light) { light = GetComponent(); } light.intensity = 0f; if (randomStart) { time = UnityEngine.Random.Range(0f, timeMax); } if (enableNegativeLights) { light.color = new UnityEngine.Color(0f - light.color.r, 0f - light.color.g, 0f - light.color.b); } } private void OnDisable() { if ((bool)light) { light.intensity = maxIntensity; } } private void Update() { time += Time.deltaTime; light.intensity = curve.Evaluate(time / timeMax) * maxIntensity; if (time >= timeMax && loop) { time = 0f; } } } [RequireComponent(typeof(LineRenderer))] [ExecuteAlways] public class LineBetweenTransforms : MonoBehaviour { [SerializeField] [FormerlySerializedAs("transformNodes")] [Tooltip("The list of transforms whose positions will drive the vertex positions of the sibling LineRenderer component.")] private Transform[] _transformNodes = Array.Empty(); private LineRenderer lineRenderer; private UnityEngine.Vector3[] vertexList = Array.Empty(); public Transform[] transformNodes { get { return _transformNodes; } set { if (value == null) { throw new ArgumentNullException("value"); } _transformNodes = value; UpdateVertexBufferSize(); } } private void PushPositionsToLineRenderer() { UnityEngine.Vector3[] array = vertexList; Transform[] array2 = transformNodes; for (int i = 0; i < array.Length; i++) { Transform transform = array2[i]; if ((bool)transform) { array[i] = transform.position; } } lineRenderer.SetPositions(array); } private void UpdateVertexBufferSize() { Array.Resize(ref vertexList, transformNodes.Length); } private void Awake() { lineRenderer = GetComponent(); UpdateVertexBufferSize(); } private void LateUpdate() { PushPositionsToLineRenderer(); } } public class LoadingScreenCanvas : MonoBehaviour { public static LoadingScreenCanvas Instance; public SpriteAsNumberManager percentage; public GameObject background; public LoadingScreenCanvas() { Instance = this; } public void Awake() { UnityEngine.Object.DontDestroyOnLoad(base.gameObject); RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnLoadComplete)); SceneManager.sceneLoaded += OnSceneChange; } private void OnLoadComplete() { SceneManager.sceneLoaded -= OnSceneChange; Instance = null; UnityEngine.Object.Destroy(base.gameObject); } private void OnSceneChange(Scene a, LoadSceneMode b) { Instance.background.SetActive(a.name == "loadingbasic"); } } public class LunarWispFXController : MonoBehaviour { public List FXParticles = new List(); private void Start() { } private void FixedUpdate() { } public void TurnOffFX() { for (int i = 0; i < FXParticles.Count; i++) { ParticleSystem.EmissionModule emission = FXParticles[i].emission; emission.enabled = false; } } public void TurnOnFX() { for (int i = 0; i < FXParticles.Count; i++) { ParticleSystem.EmissionModule emission = FXParticles[i].emission; emission.enabled = true; } } } [ExecuteAlways] public class MaintainRotation : MonoBehaviour { public UnityEngine.Vector3 eulerAngles; private void Start() { } private void LateUpdate() { base.transform.eulerAngles = eulerAngles; } } public class PauseTintController : MonoBehaviour { private PostProcessVolume ppPauseVolume; private void Awake() { ppPauseVolume = GetComponent(); ppPauseVolume.enabled = false; } private void OnEnable() { PauseManager.onPauseStartGlobal = (Action)Delegate.Combine(PauseManager.onPauseStartGlobal, new Action(OnPauseStart)); PauseManager.onPauseEndGlobal = (Action)Delegate.Combine(PauseManager.onPauseEndGlobal, new Action(OnPauseEnd)); } private void OnDisable() { PauseManager.onPauseStartGlobal = (Action)Delegate.Remove(PauseManager.onPauseStartGlobal, new Action(OnPauseStart)); PauseManager.onPauseEndGlobal = (Action)Delegate.Remove(PauseManager.onPauseEndGlobal, new Action(OnPauseEnd)); } private void OnPauseStart() { ppPauseVolume.enabled = true; } private void OnPauseEnd() { ppPauseVolume.enabled = false; } } public class PhysicsController : MonoBehaviour { public UnityEngine.Vector3 centerOfMass = UnityEngine.Vector3.zero; private Rigidbody carRigidbody; public Transform cameraTransform; public UnityEngine.Vector3 PID = new UnityEngine.Vector3(1f, 0f, 0f); public bool turnOnInput; private UnityEngine.Vector3 errorSum = UnityEngine.Vector3.zero; private UnityEngine.Vector3 deltaError = UnityEngine.Vector3.zero; private UnityEngine.Vector3 lastError = UnityEngine.Vector3.zero; private UnityEngine.Vector3 desiredHeading; private void OnDrawGizmosSelected() { Gizmos.color = UnityEngine.Color.red; Gizmos.DrawSphere(base.transform.TransformPoint(centerOfMass), 0.5f); } private void Awake() { carRigidbody = GetComponent(); } private void Update() { } private void FixedUpdate() { if (!turnOnInput || Input.GetAxis("Vertical") > 0f || Input.GetAxis("Vertical") > 0f) { desiredHeading = cameraTransform.forward; desiredHeading = UnityEngine.Vector3.Project(desiredHeading, base.transform.forward); desiredHeading = cameraTransform.forward - desiredHeading; UnityEngine.Debug.DrawRay(base.transform.position, desiredHeading * 15f, UnityEngine.Color.magenta); } UnityEngine.Vector3 vector = -base.transform.up; UnityEngine.Debug.DrawRay(base.transform.position, vector * 15f, UnityEngine.Color.blue); UnityEngine.Vector3 vector2 = UnityEngine.Vector3.Cross(vector, desiredHeading); UnityEngine.Debug.DrawRay(base.transform.position, vector2 * 15f, UnityEngine.Color.red); vector2.x = 0f; vector2.z = 0f; errorSum += vector2 * Time.fixedDeltaTime; deltaError = (vector2 - lastError) / Time.fixedDeltaTime; lastError = vector2; carRigidbody.AddTorque(vector2 * PID.x + errorSum * PID.y + deltaError * PID.z, ForceMode.Acceleration); } } public class POISecretChest : MonoBehaviour { public float influence = 5f; private void OnDrawGizmos() { Gizmos.matrix = base.transform.localToWorldMatrix; Gizmos.color = new UnityEngine.Color(0f, 1f, 1f, 0.03f); Gizmos.DrawCube(UnityEngine.Vector3.zero, base.transform.localScale / 2f); Gizmos.color = new UnityEngine.Color(0f, 1f, 1f, 0.1f); Gizmos.DrawWireCube(UnityEngine.Vector3.zero, base.transform.localScale / 2f); } } public class PositionFromParentRaycast : MonoBehaviour { public float maxLength; public LayerMask mask; private void Update() { RaycastHit hitInfo = default(RaycastHit); if (Physics.Raycast(base.transform.parent.position, base.transform.parent.forward, out hitInfo, maxLength, mask)) { base.transform.position = hitInfo.point; } else { base.transform.position = base.transform.parent.position + base.transform.parent.forward * maxLength; } } } [RequireComponent(typeof(Rigidbody))] public class PhysicsImpactSpeedModifier : MonoBehaviour { public float normalSpeedModifier; public float perpendicularSpeedModifier; private Rigidbody rigid; private void Awake() { rigid = GetComponent(); } private void OnCollisionEnter(Collision collision) { UnityEngine.Vector3 normal = collision.contacts[0].normal; UnityEngine.Vector3 velocity = rigid.velocity; UnityEngine.Vector3 vector = UnityEngine.Vector3.Project(velocity, normal); UnityEngine.Vector3 vector2 = velocity - vector; vector *= normalSpeedModifier; vector2 *= perpendicularSpeedModifier; rigid.velocity = vector + vector2; } } public class ProjectileGhostTriggerOnStick : MonoBehaviour { private UnityEngine.Vector3 lastPosition; private UnityEngine.Quaternion lastRotation; private bool begunMoving; private bool finishedMoving; [SerializeField] [Tooltip("If the object is rotating, will we consider that movement?")] private bool trackRotationAsMovement; [SerializeField] private UnityEvent OnStick; private void OnEnable() { begunMoving = false; finishedMoving = false; lastPosition = base.transform.position; lastRotation = base.transform.rotation; } private void Update() { UnityEngine.Vector3 position = base.transform.position; UnityEngine.Quaternion rotation = base.transform.rotation; if (!begunMoving && position != lastPosition && (!trackRotationAsMovement || (trackRotationAsMovement && rotation != lastRotation))) { begunMoving = true; } else if (begunMoving && !finishedMoving && position == lastPosition && (!trackRotationAsMovement || (trackRotationAsMovement && rotation == lastRotation))) { RunStuckMethod(); finishedMoving = true; } lastPosition = position; lastRotation = rotation; } public void RunStuckMethod() { OnStick.Invoke(); } } public class ProximityHighlight : MonoBehaviour { public float highlightRadius = 50f; public float highlightScale = 0.6f; public float highlightUpdateInterval = 0.1f; private float _highlightUpdateTimer; private CharacterMaster _characterMaster; private CharacterBody _characterBody; private InteractionDriver _interactionDriver; private Collider[] _hitColliders = new Collider[64]; private int _hits; private void Awake() { _characterMaster = GetComponent(); base.enabled = TutorialManager.isTutorialEnabled; } private void OnEnable() { OutlineHighlight.onPreRenderOutlineHighlight = (Action)Delegate.Combine(OutlineHighlight.onPreRenderOutlineHighlight, new Action(OnPreRenderOutlineHighlight)); } private void OnDisable() { OutlineHighlight.onPreRenderOutlineHighlight = (Action)Delegate.Remove(OutlineHighlight.onPreRenderOutlineHighlight, new Action(OnPreRenderOutlineHighlight)); } private void FixedUpdate() { if (!_characterMaster) { return; } _highlightUpdateTimer -= Time.fixedDeltaTime; if (!(_highlightUpdateTimer < 0f)) { return; } _highlightUpdateTimer = highlightUpdateInterval; _characterBody = _characterMaster.GetBody(); if ((bool)_characterBody) { _interactionDriver = _characterBody.GetComponent(); if ((bool)_interactionDriver) { Array.Clear(_hitColliders, 0, _hitColliders.Length); _hits = Physics.OverlapSphereNonAlloc(_characterBody.transform.position, highlightRadius, _hitColliders, LayerIndex.CommonMasks.interactable, QueryTriggerInteraction.Collide); } } } private void OnPreRenderOutlineHighlight(OutlineHighlight outlineHighlight) { for (int i = 0; i < _hits; i++) { if (!_hitColliders[i] || !_hitColliders[i].gameObject || !EntityLocator.HasEntityLocator(_hitColliders[i].gameObject, out var foundLocator)) { continue; } GameObject entity = foundLocator.entity; if (_interactionDriver.currentInteractable == entity) { continue; } IInteractable component = entity.GetComponent(); if (component != null && ((MonoBehaviour)component).isActiveAndEnabled && (bool)_interactionDriver.interactor && component.GetInteractability(_interactionDriver.interactor) != 0 && component.ShouldProximityHighlight()) { Highlight component2 = entity.GetComponent(); if (!component2) { break; } UnityEngine.Color color = component2.GetColor() * component2.strength * highlightScale; outlineHighlight.highlightQueue.Enqueue(new OutlineHighlight.HighlightInfo { renderer = component2.targetRenderer, color = color }); } } } } public class QuaternionPID : MonoBehaviour { [Tooltip("Just a field for user naming. Doesn't do anything.")] [FormerlySerializedAs("name")] public string customName; [Tooltip("PID Constants.")] public UnityEngine.Vector3 PID = new UnityEngine.Vector3(1f, 0f, 0f); [Tooltip("The quaternion we are currently at.")] public UnityEngine.Quaternion inputQuat = UnityEngine.Quaternion.identity; [Tooltip("The quaternion we want to be at.")] public UnityEngine.Quaternion targetQuat = UnityEngine.Quaternion.identity; [Tooltip("Vector output from PID controller; what we read.")] [HideInInspector] public UnityEngine.Vector3 outputVector = UnityEngine.Vector3.zero; public float gain = 1f; private UnityEngine.Vector3 errorSum = UnityEngine.Vector3.zero; private UnityEngine.Vector3 deltaError = UnityEngine.Vector3.zero; private UnityEngine.Vector3 lastError = UnityEngine.Vector3.zero; private float lastUpdateTime; private void Start() { gain *= 60f * Time.fixedDeltaTime; lastUpdateTime = Time.time; } public UnityEngine.Vector3 UpdatePID() { float time = Time.time; float num = time - lastUpdateTime; lastUpdateTime = time; if (num != 0f) { UnityEngine.Quaternion quaternion = targetQuat * UnityEngine.Quaternion.Inverse(inputQuat); if (quaternion.w < 0f) { quaternion.x *= -1f; quaternion.y *= -1f; quaternion.z *= -1f; quaternion.w *= -1f; } UnityEngine.Vector3 vector = default(UnityEngine.Vector3); vector.x = quaternion.x; vector.y = quaternion.y; vector.z = quaternion.z; errorSum += vector * num; deltaError = (vector - lastError) / num; lastError = vector; outputVector = vector * PID.x + errorSum * PID.y + deltaError * PID.z; return outputVector * gain; } return UnityEngine.Vector3.zero; } } [ExecuteInEditMode] public class RenderDepth : MonoBehaviour { private void OnEnable() { GetComponent().depthTextureMode = DepthTextureMode.DepthNormals; } } public class RenderInFrontOfParticles : MonoBehaviour { public int renderOrder; private Renderer rend; private void Start() { rend = GetComponent(); rend.material.renderQueue = renderOrder; } private void Update() { } } [RequireComponent(typeof(Animator))] public class RootMotionAccumulator : MonoBehaviour { private Animator animator; [NonSerialized] public UnityEngine.Vector3 accumulatedRootMotion; public UnityEngine.Quaternion accumulatedRootRotation; public bool accumulateRotation; public UnityEngine.Vector3 ExtractRootMotion() { UnityEngine.Vector3 result = accumulatedRootMotion; accumulatedRootMotion = UnityEngine.Vector3.zero; return result; } public UnityEngine.Quaternion ExtractRootRotation() { UnityEngine.Quaternion result = accumulatedRootRotation; accumulatedRootRotation = UnityEngine.Quaternion.identity; return result; } private void Awake() { animator = GetComponent(); accumulatedRootRotation = UnityEngine.Quaternion.identity; } private void OnAnimatorMove() { accumulatedRootMotion += animator.deltaPosition; if (accumulateRotation) { accumulatedRootRotation *= animator.deltaRotation; } } } public class RotateItem : MonoBehaviour { public float spinSpeed = 30f; public float bobHeight = 0.3f; public UnityEngine.Vector3 offsetVector = UnityEngine.Vector3.zero; private float counter; private UnityEngine.Vector3 initialPosition; private void Start() { initialPosition = base.transform.position; } private void Update() { counter += Time.deltaTime; base.transform.Rotate(new UnityEngine.Vector3(0f, spinSpeed * Time.deltaTime, 0f), Space.World); if ((bool)base.transform.parent) { base.transform.localPosition = offsetVector + new UnityEngine.Vector3(0f, 0f, Mathf.Sin(counter) * bobHeight); } else { base.transform.position = initialPosition + new UnityEngine.Vector3(0f, Mathf.Sin(counter) * bobHeight, 0f); } } } public class RotateObject : MonoBehaviour { public UnityEngine.Vector3 rotationSpeed; private void Start() { } private void Update() { base.transform.Rotate(rotationSpeed * Time.deltaTime); } } public class ScaledCamera : MonoBehaviour { public float scale = 1f; private bool foundCamera; private UnityEngine.Vector3 offset; private void Start() { } private void LateUpdate() { Camera main = Camera.main; if (main != null) { if (!foundCamera) { foundCamera = true; offset = main.transform.position - base.transform.position; } base.transform.eulerAngles = main.transform.eulerAngles; base.transform.position = main.transform.position / scale - offset; } } } public class ScaleLineRenderer : MonoBehaviour { private LineRenderer line; public float scaleSize = 1f; public UnityEngine.Vector3[] positions; private void Start() { line = GetComponent(); SetScale(); } private void Update() { } private void SetScale() { line.SetPosition(0, positions[0]); line.SetPosition(1, positions[1]); line.material.SetTextureScale("_MainTex", new UnityEngine.Vector2(UnityEngine.Vector3.Distance(positions[0], positions[1]) * scaleSize, 1f)); } } public class ScaleProjector : MonoBehaviour { private Projector projector; private void Start() { projector = GetComponent(); } private void Update() { if ((bool)projector) { projector.orthographicSize = base.transform.lossyScale.x; } } } [RequireComponent(typeof(Rigidbody))] public class SetAngularVelocity : MonoBehaviour { public UnityEngine.Vector3 angularVelocity; private Rigidbody rigidBody; private void Start() { rigidBody = GetComponent(); } private void FixedUpdate() { rigidBody.maxAngularVelocity = angularVelocity.magnitude; rigidBody.angularVelocity = base.transform.TransformVector(angularVelocity); } } public class ShrinePlaceTotem : MonoBehaviour { public int totemCount = 5; public GameObject totem; [Tooltip("Distance from which to form totem ring")] public float totemRadius = 2f; [Tooltip("Height from which to calculate totem placements.")] public float height = 10f; [Tooltip("Distance to raycast for totems")] public float raycastDistance = 20f; [Tooltip("Random bending of totems")] public float bendAmount = 15f; [Tooltip("Allowed difference from straight up (1) to straight down (-1)")] public float dotLimit = 0.8f; private void Awake() { int num = 0; for (int i = 0; i < totemCount * 2; i++) { float num2 = ((i >= totemCount) ? ((float)i * 1f * (360f / (float)totemCount)) : (((float)i + 0.5f) * (360f / (float)totemCount))); Physics.Raycast(base.transform.position + new UnityEngine.Vector3(0f, height, 0f), new UnityEngine.Vector3(Mathf.Cos(num2 * (MathF.PI / 180f)) * totemRadius, 0f - height, Mathf.Sin(num2 * (MathF.PI / 180f)) * totemRadius), out var hitInfo, raycastDistance); if (hitInfo.collider != null && UnityEngine.Vector3.Dot(hitInfo.normal, UnityEngine.Vector3.up) > dotLimit) { GameObject gameObject = UnityEngine.Object.Instantiate(totem, hitInfo.point, UnityEngine.Quaternion.identity); gameObject.transform.parent = base.transform; gameObject.transform.rotation = UnityEngine.Quaternion.FromToRotation(gameObject.transform.up, hitInfo.normal); gameObject.transform.eulerAngles += new UnityEngine.Vector3(UnityEngine.Random.Range(0f - bendAmount, bendAmount), UnityEngine.Random.Range(0f - bendAmount, bendAmount), UnityEngine.Random.Range(0f - bendAmount, bendAmount)); gameObject.transform.position -= new UnityEngine.Vector3(0f, UnityEngine.Random.Range(0.1f, 0.2f), 0f); num++; } if (num == totemCount) { break; } } } private void Update() { } } public class SpeechBubbleController : MonoBehaviour { [Serializable] public struct SpeechCategory { public string refName; public float chanceToTrigger; public SpeechInfo[] speechInfos; public WeightedSelection speechSelection; } [Serializable] public struct SpeechInfo { public string nameToken; public float weight; } [Header("Cached Components")] public Transform idealBubbleTransform; public CharacterBody characterBody; public SfxLocator sfxLocator; [Header("Speech Info")] public string formatStringToken; public float minimumDurationBetweenSpeech; public bool removeRepeats; [SerializeField] public SpeechCategory[] speechCategories; [Header("Events")] public UnityEvent onBodyDamageDealt; public UnityEvent onStart; public UnityEvent onBodyKill; public UnityEvent onBodyDeath; private GameObject speechBubbleInstance; private float lastSpeechStopwatch; private void Start() { Initialize(); lastSpeechStopwatch = minimumDurationBetweenSpeech; onStart?.Invoke(); } private void OnEnable() { GlobalEventManager.onServerDamageDealt += OnServerDamageDealt; GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal; } private void OnDisable() { GlobalEventManager.onServerDamageDealt -= OnServerDamageDealt; GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal; } private void FixedUpdate() { lastSpeechStopwatch += Time.fixedDeltaTime; } private void OnCharacterDeathGlobal(DamageReport damageReport) { if ((object)damageReport.victimBody == characterBody) { onBodyDeath?.Invoke(); } else if ((object)damageReport.attackerBody == characterBody) { onBodyKill?.Invoke(); } } private void OnServerDamageDealt(DamageReport damageReport) { if ((object)damageReport.attackerBody == characterBody) { onBodyDamageDealt?.Invoke(); } } private void Initialize() { for (int i = 0; i < speechCategories.Length; i++) { WeightedSelection weightedSelection = new WeightedSelection(); for (int j = 0; j < speechCategories[i].speechInfos.Length; j++) { SpeechInfo value = speechCategories[i].speechInfos[j]; weightedSelection.AddChoice(value, value.weight); } speechCategories[i].speechSelection = weightedSelection; } } private void SubmitSpeech(string token) { lastSpeechStopwatch = 0f; Chat.SendBroadcastChat(new Chat.NpcChatMessage { baseToken = token, formatStringToken = formatStringToken, sender = base.gameObject, sound = sfxLocator.barkSound }); } public void TriggerSpeech(string refName) { if (lastSpeechStopwatch < minimumDurationBetweenSpeech) { return; } for (int i = 0; i < speechCategories.Length; i++) { if (speechCategories[i].refName == refName) { if (speechCategories[i].speechSelection.Count <= 0) { Initialize(); } int num = speechCategories[i].speechSelection.EvaluateToChoiceIndex(UnityEngine.Random.value); SpeechInfo value = speechCategories[i].speechSelection.GetChoice(num).value; if (removeRepeats) { SpeechCategory speechCategory = speechCategories[i]; speechCategory.speechSelection.RemoveChoice(num); speechCategories[i] = speechCategory; } if (UnityEngine.Random.value < speechCategories[i].chanceToTrigger) { SubmitSpeech(value.nameToken); } } } } } public class TracerBehavior : MonoBehaviour { public float speed = 1f; public UnityEngine.Vector3[] positions; private UnityEngine.Vector3 direction; private void Start() { direction = UnityEngine.Vector3.Normalize(positions[1] - positions[0]); } private void Update() { if (UnityEngine.Vector3.Distance(base.transform.position, positions[1]) > speed * Time.deltaTime) { base.transform.position += direction * speed * Time.deltaTime; } } } [RequireComponent(typeof(HGButton))] public class AlternateButtonEvents : MonoBehaviour { public UnityEvent onAlternateClick; public UnityEvent onTertiaryClick; public void InvokeAltClick() { if (onAlternateClick != null) { onAlternateClick.Invoke(); } } public void InvokeTertiaryClick() { if (onTertiaryClick != null) { onTertiaryClick.Invoke(); } } } public static class AutomatedBuildVersion { public const string buildVersionString = "290"; } [RequireComponent(typeof(MPEventSystemLocator))] public class DevCheatMenu : MonoBehaviour { public TextMeshProUGUI enemyName; public TextMeshProUGUI teamText; public TextMeshProUGUI affixText; public TextMeshProUGUI spawnEnemyText; public TextMeshProUGUI toggleSpawningText; public TextMeshProUGUI miscCommandLabel; public TMP_Dropdown masterNameDropdown; public TMP_Dropdown enemiesAmountDropdown; public TMP_Dropdown itemsNamesDropdown; public TMP_Dropdown itemsAmountDropdown; public TMP_Dropdown stageListDropdown; private string enemyMasterName; private string teamIndex; private string equipmentIndex; private string enemyMasterNameTeamIndexEquipmentIndex; private bool spawnEnemyArgsDirty; private readonly StringBuilder miscCommand = new StringBuilder(); private NetworkUser localUser; private MPEventSystem eventSystem; private bool isUpper; private void Awake() { Close(); } private void SetMonsterTabText() { spawnEnemyText.SetText(enemyMasterNameTeamIndexEquipmentIndex); enemyName.SetText(enemyMasterName); teamText.SetText(teamIndex); affixText.SetText(equipmentIndex); toggleSpawningText.SetText(CombatDirector.cvDirectorCombatDisable.value ? "Spawning DISABLED" : "Spawning ENABLED"); } private void InitializeMasterDropdown() { masterNameDropdown.options = MasterCatalog.allMasters.Select((CharacterMaster master) => new TMP_Dropdown.OptionData(master.gameObject.name)).ToList(); } private void InitializeStageListDropdown() { stageListDropdown.options = SceneCatalog.allSceneDefs.Select((SceneDef scene) => new TMP_Dropdown.OptionData(scene.baseSceneName)).ToList(); } public void EnableSpawning() { } public void DisableSpawning() { } public void SpawnEnemy() { if (!CombatDirector.cvDirectorCombatDisable.value && !string.IsNullOrEmpty(enemyMasterName)) { if (spawnEnemyArgsDirty) { enemyMasterNameTeamIndexEquipmentIndex = string.Join(" ", "create_master", enemyMasterName, teamIndex, equipmentIndex); spawnEnemyArgsDirty = false; } int num = int.Parse(enemiesAmountDropdown.options[Mathf.Min(enemiesAmountDropdown.options.Count - 1, enemiesAmountDropdown.value)].text); for (int i = 0; i < num; i++) { RoR2.Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], enemyMasterNameTeamIndexEquipmentIndex, recordSubmit: true); spawnEnemyText.SetText(enemyMasterNameTeamIndexEquipmentIndex); } } } public void SetEnemyMasterName() { string text = masterNameDropdown.options[Mathf.Min(masterNameDropdown.options.Count - 1, masterNameDropdown.value)].text; if (string.IsNullOrEmpty(text) || enemyMasterName == text || MasterCatalog.FindMasterIndex(text) == MasterCatalog.MasterIndex.none) { UnityEngine.Debug.LogWarning("Invalid newEnemyMaster: " + text); return; } enemyMasterName = text; spawnEnemyArgsDirty = true; enemyName.SetText(enemyMasterName); } public void SetSceneTravelName() { string text = stageListDropdown.options[Mathf.Min(stageListDropdown.options.Count - 1, stageListDropdown.value)].text; if (!string.IsNullOrEmpty(text)) { RoR2.Console.instance.SubmitCmd(null, "set_scene " + text); } } public void SetTeamIndex(string newTeamIndex) { if (string.IsNullOrEmpty(newTeamIndex) || teamIndex == newTeamIndex || !Enum.TryParse(newTeamIndex, ignoreCase: true, out var _)) { UnityEngine.Debug.LogWarning("Invalid newTeamIndex: " + newTeamIndex); return; } teamIndex = newTeamIndex; spawnEnemyArgsDirty = true; teamText.SetText(teamIndex); } public void SetCurrentEquipment(string newEquipment) { if (string.IsNullOrEmpty(newEquipment) || equipmentIndex == newEquipment || EquipmentCatalog.FindEquipmentIndex(newEquipment) == EquipmentIndex.None) { UnityEngine.Debug.LogWarning("Invalid newEquipment: " + newEquipment); return; } equipmentIndex = newEquipment; spawnEnemyArgsDirty = true; affixText.SetText(equipmentIndex); } public void SetUppercase() { isUpper = true; } public void SetLowercase() { isUpper = false; } public void BackspaceMiscCommand() { miscCommand.Remove(miscCommand.Length - 1, 1); miscCommandLabel.SetText(miscCommand); } public void AppendMiscCommand(string stringToAdd) { miscCommand.Append(isUpper ? stringToAdd.ToUpper() : stringToAdd.ToLower()); miscCommandLabel.SetText(miscCommand); } public void SubmitMiscCommand() { string text = miscCommand.ToString(); if (string.IsNullOrEmpty(text)) { string text2 = "Invalid command sequence: " + text + ". Enter a valid command sequence before submitting a command."; UnityEngine.Debug.LogWarning(text2); miscCommandLabel.SetText(text2); return; } if (localUser == null && NetworkUser.readOnlyLocalPlayersList != null && NetworkUser.readOnlyLocalPlayersList.Count > 0) { localUser = NetworkUser.readOnlyLocalPlayersList[0]; } RoR2.Console.instance.SubmitCmd(localUser, text, recordSubmit: true); } public void ClearMiscCommand() { miscCommand.Clear(); miscCommandLabel.SetText(miscCommand); } public void AttemptAlternateClick() { if ((bool)eventSystem.currentSelectedButton) { AlternateButtonEvents component = eventSystem.currentSelectedButton.GetComponent(); if ((bool)component) { component.InvokeAltClick(); } } } public void AttemptTertiaryClick() { if ((bool)eventSystem.currentSelectedButton) { AlternateButtonEvents component = eventSystem.currentSelectedButton.GetComponent(); if ((bool)component) { component.InvokeTertiaryClick(); } } } private void InitializeItemsDropdown() { itemsNamesDropdown.options = ContentManager._itemDefs.Select((ItemDef itemDef) => new TMP_Dropdown.OptionData(itemDef.name)).ToList(); } public void GiveItem() { string text = itemsNamesDropdown.options[Mathf.Min(itemsNamesDropdown.options.Count - 1, itemsNamesDropdown.value)].text; int num = int.Parse(itemsAmountDropdown.options[Mathf.Min(itemsAmountDropdown.options.Count - 1, itemsAmountDropdown.value)].text); RoR2.Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], $"give_item {text} {num}", recordSubmit: true); } [ConCommand(commandName = "enemies_are_gods", flags = ConVarFlags.None, helpText = "EnemiesAreGods")] private static void EnemiesAreGods(ConCommandArgs args) { foreach (TeamComponent teamMember in TeamComponent.GetTeamMembers(TeamIndex.Monster)) { HealthComponent component = teamMember.GetComponent(); component.godMode = !component.godMode; } } public void StartLog() { } public void StopLog() { } public void Close() { UnityEngine.Object.Destroy(base.gameObject); } } public class EclipseDifficultyMedalDisplay : MonoBehaviour { [SerializeField] private int eclipseLevel; [SerializeField] private UnityEngine.UI.Image iconImage; [SerializeField] private Sprite unearnedSprite; [SerializeField] private Sprite incompleteSprite; [SerializeField] private Sprite completeSprite; private void OnEnable() { UserProfile.onSurvivorPreferenceChangedGlobal += OnSurvivorPreferenceChangedGlobal; Refresh(); } private void OnDisable() { UserProfile.onSurvivorPreferenceChangedGlobal -= OnSurvivorPreferenceChangedGlobal; } private void OnSurvivorPreferenceChangedGlobal(UserProfile userProfile) { Refresh(); } private void Refresh() { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); SurvivorDef survivorDef = firstLocalUser?.userProfile.GetSurvivorPreference(); if (!survivorDef) { return; } int localUserSurvivorCompletedEclipseLevel = EclipseRun.GetLocalUserSurvivorCompletedEclipseLevel(firstLocalUser, survivorDef); if (eclipseLevel <= localUserSurvivorCompletedEclipseLevel) { bool flag = true; foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs) { if (ShouldDisplaySurvivor(orderedSurvivorDef, firstLocalUser)) { localUserSurvivorCompletedEclipseLevel = EclipseRun.GetLocalUserSurvivorCompletedEclipseLevel(firstLocalUser, orderedSurvivorDef); if (localUserSurvivorCompletedEclipseLevel < eclipseLevel) { flag = false; break; } } } if (flag) { iconImage.sprite = completeSprite; } else { iconImage.sprite = incompleteSprite; } } else { iconImage.sprite = unearnedSprite; } } private bool ShouldDisplaySurvivor(SurvivorDef survivorDef, LocalUser localUser) { if ((bool)survivorDef && !survivorDef.hidden) { return survivorDef.CheckUserHasRequiredEntitlement(localUser); } return false; } } public class FriendSessionBrowserController : MonoBehaviour { public SessionButtonController SessionButtonPrefab; public Transform SessionButtonContainer; public RectTransform InProgressSpinner; public TextMeshProUGUI SearchStateText; public MPButton RefreshButton; public MPButton BackButton; private List sessionButtons; } public class GenericInspectInfoProvider : MonoBehaviour, IInspectInfoProvider, IHasInspectHintOverride { public InspectDef InspectInfo; [Tooltip("Set this to a non-empty token to override the default Inspect hint on the HUD.")] public string inspectHintOverrideToken; public bool CanBeInspected() { return true; } public InspectInfo GetInfo() { return InspectInfo; } public bool GetInspectHintOverride(out string hintOverride) { if (inspectHintOverrideToken.Length > 0) { hintOverride = Language.GetString(inspectHintOverrideToken); return true; } hintOverride = null; return false; } } public class InviteButton : MonoBehaviour { public void OnInviteButtonPressed() { PlatformSystems.lobbyManager.OpenInviteOverlay(); } } public class SessionButtonController : MonoBehaviour { public HGButton Button; public HGTextMeshProUGUI Text; public void AddListener(UnityAction call) { Button.onClick.AddListener(call); } public void SetText(int currentParticipationNumber, int maxParticipationNumber, string hostName) { Text.text = currentParticipationNumber + "/" + maxParticipationNumber + " " + hostName; } } public class SocialUserIconBehavior { protected enum SourceType { Local, Network } protected RawImage rawImageComponent; protected Texture2D generatedTexture; protected RoR2.PlatformID userID; protected SourceType sourceType; protected GameObject gameObject; protected MonoBehaviour monoBehaviour; protected UserManager.AvatarSize avatarSize; protected Texture defaultTexture => LegacyResourcesAPI.Load("Textures/UI/texDefaultSocialUserIcon"); public void Awake(GameObject go, MonoBehaviour mb) { gameObject = go; monoBehaviour = mb; OnAwakeBehavior(); } public void OnEnable(GameObject go, MonoBehaviour mb) { gameObject = go; monoBehaviour = mb; OnEnableBehavior(); } public void OnDestroy() { OnDestroyBehavior(); gameObject = null; monoBehaviour = null; } protected virtual void OnAwakeBehavior() { rawImageComponent = gameObject.GetComponent(); rawImageComponent.texture = defaultTexture; if (!UserManager.P_UseSocialIcon.value) { gameObject.SetActive(value: false); } } protected virtual void OnEnableBehavior() { } protected virtual void OnDestroyBehavior() { } public virtual void Refresh(bool shouldForceRefresh = false) { if (PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon)) { PlatformSystems.userManager.GetAvatar(userID, gameObject, generatedTexture, avatarSize, HandleNewTexture); if (!generatedTexture && rawImageComponent != null) { rawImageComponent.texture = defaultTexture; } } } public virtual void SetFromMaster(CharacterMaster master) { if (!PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon)) { return; } if ((bool)master) { PlayerCharacterMasterController component = master.GetComponent(); if ((bool)component) { NetworkUser networkUser = component.networkUser; RefreshWithUser(new RoR2.PlatformID(networkUser.id.value)); return; } } userID = default(RoR2.PlatformID); sourceType = SourceType.Local; Refresh(); } public virtual void RefreshWithUser(RoR2.PlatformID newUserID) { if (PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon) && (sourceType != SourceType.Network || !newUserID.Equals(userID))) { sourceType = SourceType.Network; userID = newUserID; Refresh(); } } protected virtual void HandleNewTexture(Texture2D tex) { if ((bool)tex) { generatedTexture = tex; if (rawImageComponent != null) { rawImageComponent.texture = tex; } } } } public class SocialUserIconBehaviorConsoles : SocialUserIconBehavior { private bool UserIconIsLoad; private bool loadAvatarIsDone; private Texture2D pointerOfTexture; private HGButton button; private bool blockToClick; private WaitForSeconds waiteSecond = new WaitForSeconds(0.3f); private UnityEngine.UI.Image outline; public override void Refresh(bool shouldForceRefresh = false) { if (!(!PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon) | (UserIconIsLoad && !shouldForceRefresh))) { PlatformSystems.userManager.GetAvatar(userID, gameObject, generatedTexture, avatarSize, HandleNewTexture); UserIconIsLoad = true; loadAvatarIsDone = false; if ((bool)gameObject && gameObject.activeInHierarchy) { monoBehaviour.StartCoroutine(UserIconTextureChangeCoroutine()); } if (!generatedTexture && rawImageComponent != null) { rawImageComponent.texture = base.defaultTexture; } } } public override void RefreshWithUser(RoR2.PlatformID newUserID) { if (PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon) && (sourceType != SourceType.Network || !newUserID.Equals(userID))) { sourceType = SourceType.Network; UserIconIsLoad = false; userID = newUserID; InitButtonToClickeble(); Refresh(); } } protected override void HandleNewTexture(Texture2D tex) { if (tex == null || rawImageComponent == null) { UserIconIsLoad = false; if (this != null && (bool)gameObject) { monoBehaviour.StopCoroutine(UserIconTextureChangeCoroutine()); } } else { pointerOfTexture = tex; generatedTexture = pointerOfTexture; rawImageComponent.texture = pointerOfTexture; loadAvatarIsDone = true; } } protected override void OnAwakeBehavior() { rawImageComponent = gameObject.GetComponent(); rawImageComponent.texture = base.defaultTexture; rawImageComponent.rectTransform.sizeDelta = new UnityEngine.Vector2(32f, 32f); if (PreGameController.instance != null) { UserIconIsLoad = false; } if (!UserManager.P_UseSocialIcon.value) { gameObject.SetActive(value: false); } } protected override void OnEnableBehavior() { if (UserIconIsLoad) { monoBehaviour.StartCoroutine(UserIconTextureChangeCoroutine()); } if (userID != default(RoR2.PlatformID)) { InitButtonToClickeble(); } } private void InitButtonToClickeble() { if (!(button != null) && !(gameObject == null)) { button = gameObject.AddComponent(); button.onClick.RemoveAllListeners(); button.onClick.AddListener(OnClickToSocialUserIcon); outline = gameObject.transform.GetComponentInChildren(); if (outline != null) { outline.rectTransform.offsetMax = new UnityEngine.Vector2(2f, 2f); outline.rectTransform.offsetMin = new UnityEngine.Vector2(-2f, -2f); button.onSelect = new UnityEvent(); button.onSelect.AddListener(Selected); button.onDeselect = new UnityEvent(); button.onDeselect.AddListener(Deselected); } } } private void Selected() { outline.enabled = true; } private void Deselected() { outline.enabled = false; } private void OnClickToSocialUserIcon() { if (!blockToClick) { blockToClick = true; } } private void UnblockToCkick() { if (!monoBehaviour.isActiveAndEnabled) { blockToClick = false; } else { monoBehaviour.StartCoroutine(ButtonUpAcrivityCoroutine()); } } private IEnumerator ButtonUpAcrivityCoroutine() { yield return waiteSecond; blockToClick = false; } private IEnumerator UserIconTextureChangeCoroutine() { while (!loadAvatarIsDone) { yield return null; } generatedTexture = pointerOfTexture; rawImageComponent.texture = pointerOfTexture; } } public class VectorPID : MonoBehaviour { [Tooltip("Just a field for user naming. Doesn't do anything.")] [FormerlySerializedAs("name")] public string customName; [Tooltip("PID Constants.")] public UnityEngine.Vector3 PID = new UnityEngine.Vector3(1f, 0f, 0f); [Tooltip("The vector we are currently at.")] [HideInInspector] public UnityEngine.Vector3 inputVector = UnityEngine.Vector3.zero; [HideInInspector] [Tooltip("The vector we want to be at.")] public UnityEngine.Vector3 targetVector = UnityEngine.Vector3.zero; [Tooltip("Vector output from PID controller; what we read.")] [HideInInspector] public UnityEngine.Vector3 outputVector = UnityEngine.Vector3.zero; [Tooltip("This is an euler angle, so we need to wrap correctly")] public bool isAngle; public float gain = 1f; private UnityEngine.Vector3 errorSum = UnityEngine.Vector3.zero; private UnityEngine.Vector3 deltaError = UnityEngine.Vector3.zero; private UnityEngine.Vector3 lastError = UnityEngine.Vector3.zero; private float lastTimer; private float timer; private void Start() { } private void FixedUpdate() { timer += Time.fixedDeltaTime; } public UnityEngine.Vector3 UpdatePID() { float num = timer - lastTimer; lastTimer = timer; if (num != 0f) { UnityEngine.Vector3 vector; if (isAngle) { vector = UnityEngine.Vector3.zero; vector.x = Mathf.DeltaAngle(inputVector.x, targetVector.x); vector.y = Mathf.DeltaAngle(inputVector.y, targetVector.y); vector.z = Mathf.DeltaAngle(inputVector.z, targetVector.z); } else { vector = targetVector - inputVector; } errorSum += vector * num; deltaError = (vector - lastError) / num; lastError = vector; outputVector = vector * PID.x + errorSum * PID.y + deltaError * PID.z; return outputVector * gain; } return UnityEngine.Vector3.zero; } } public class Visualizer : MonoBehaviour { public float yscale; public GameObject particleObject; public float yvalue; private UnityEngine.Vector3 initialPos; private void Start() { initialPos = particleObject.transform.localPosition; } private void Update() { particleObject.transform.localPosition = initialPos + new UnityEngine.Vector3(0f, yvalue / yscale, 0f); } } public class Wind : MonoBehaviour { private Renderer rend; private MaterialPropertyBlock props; public UnityEngine.Vector4 windVector; public float MainWindAmplitude = 1f; public float MainWindSpeed = 3f; private float time; private void Start() { rend = GetComponent(); props = new MaterialPropertyBlock(); SetWind(props, windVector); } private void Update() { time += Time.deltaTime; windVector.x = (0.5f + 0.5f * Mathf.Sin(MainWindSpeed * time * (MathF.PI / 180f))) * MainWindAmplitude; SetWind(props, windVector); } private void SetWind(MaterialPropertyBlock block, UnityEngine.Vector4 input) { rend.GetPropertyBlock(block); block.Clear(); block.SetVector("_Wind", input); rend.SetPropertyBlock(block); } } [Obsolete("HGArrayUtilities is deprecated. Use HG.ArrayUtils instead.")] public static class HGArrayUtilities { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ArrayInsertNoResize(T[] array, int arraySize, int position, ref T value) { ArrayUtils.ArrayInsertNoResize(array, arraySize, position, in value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ArrayInsert(ref T[] array, ref int arraySize, int position, ref T value) { ArrayUtils.ArrayInsert(ref array, ref arraySize, position, in value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ArrayInsert(ref T[] array, int position, ref T value) { ArrayUtils.ArrayInsert(ref array, position, in value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ArrayAppend(ref T[] array, ref int arraySize, ref T value) { ArrayUtils.ArrayAppend(ref array, ref arraySize, in value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ArrayAppend(ref T[] array, ref T value) { ArrayUtils.ArrayAppend(ref array, in value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ArrayRemoveAt(ref T[] array, ref int arraySize, int position, int count = 1) { ArrayUtils.ArrayRemoveAt(array, ref arraySize, position, count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ArrayRemoveAtAndResize(ref T[] array, int position, int count = 1) { ArrayUtils.ArrayRemoveAtAndResize(ref array, position, count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T GetSafe([NotNull] T[] array, int index) { return ArrayUtils.GetSafe(array, index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T GetSafe([NotNull] T[] array, int index, T defaultValue) { return ArrayUtils.GetSafe(array, index, in defaultValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void SetAll(T[] array, in T value) { ArrayUtils.SetAll(array, in value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureCapacity(ref T[] array, int capacity) { ArrayUtils.EnsureCapacity(ref array, capacity); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Swap(T[] array, int a, int b) { ArrayUtils.Swap(array, a, b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Clear(T[] array, ref int count) { ArrayUtils.Clear(array, ref count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool SequenceEquals(T[] a, T[] b) where T : IEquatable { return ArrayUtils.SequenceEquals(a, b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] Clone(T[] src) { return ArrayUtils.Clone(src); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInBounds(T[] array, int index) { return ArrayUtils.IsInBounds(array, index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInBounds(T[] array, uint index) { return ArrayUtils.IsInBounds(array, index); } } public static class HGMath { [Obsolete("Use HG.Vector3Utils.AverageFast or .AveragePrecise instead.", false)] public static UnityEngine.Vector3 Average(T entries) where T : ICollection { int count = entries.Count; float num = 1f / (float)count; UnityEngine.Vector3 zero = UnityEngine.Vector3.zero; foreach (UnityEngine.Vector3 item in entries) { zero += num * item; } return zero; } [Obsolete("Use HG.Vector3Utils.Average instead.", false)] public static UnityEngine.Vector3 Average(in UnityEngine.Vector3 a, in UnityEngine.Vector3 b) { return Vector3Utils.Average(in a, in b); } [Obsolete("Use HG.Vector3Utils.Average instead.", false)] public static UnityEngine.Vector3 Average(in UnityEngine.Vector3 a, in UnityEngine.Vector3 b, in UnityEngine.Vector3 c) { return Vector3Utils.Average(in a, in b, in c); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int IntDivCeil(int a, int b) { return (a - 1) / b + 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UintSafeSubtract(uint a, uint b) { if (b <= a) { return a - b; } return 0u; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UintSafeAdd(uint a, uint b) { uint num = a + b; uint num2 = ((a > b) ? a : b); if (num >= num2) { return num; } return uint.MaxValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ByteSafeSubtract(byte a, byte b) { if (b <= a) { return (byte)(a - b); } return 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ByteSafeAdd(byte a, byte b) { byte b2 = (byte)(a + b); byte b3 = ((a > b) ? a : b); if (b2 >= b3) { return b2; } return byte.MaxValue; } public static UnityEngine.Vector3 Remap(UnityEngine.Vector3 value, UnityEngine.Vector3 inMin, UnityEngine.Vector3 inMax, UnityEngine.Vector3 outMin, UnityEngine.Vector3 outMax) { return new UnityEngine.Vector3(outMin.x + (value.x - inMin.x) / (inMax.x - inMin.x) * (outMax.x - outMin.x), outMin.y + (value.y - inMin.y) / (inMax.y - inMin.y) * (outMax.y - outMin.y), outMin.z + (value.z - inMin.z) / (inMax.z - inMin.z) * (outMax.z - outMin.z)); } public static UnityEngine.Vector3 Remap(UnityEngine.Vector3 value, float inMin, float inMax, float outMin, float outMax) { return new UnityEngine.Vector3(outMin + (value.x - inMin) / (inMax - inMin) * (outMax - outMin), outMin + (value.y - inMin) / (inMax - inMin) * (outMax - outMin), outMin + (value.z - inMin) / (inMax - inMin) * (outMax - outMin)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float Clamp(float value, float min, float max) { if (!(value > min)) { return min; } if (!(value < max)) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Clamp(int value, int min, int max) { if (value <= min) { return min; } if (value >= max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Clamp(uint value, uint min, uint max) { if (value <= min) { return min; } if (value >= max) { return max; } return value; } public static UnityEngine.Vector3 Clamp(UnityEngine.Vector3 value, UnityEngine.Vector3 min, UnityEngine.Vector3 max) { return new UnityEngine.Vector3(Clamp(value.x, min.x, max.x), Clamp(value.y, min.y, max.y), Clamp(value.z, min.z, max.z)); } public static UnityEngine.Vector3 Clamp(UnityEngine.Vector3 value, float min, float max) { return new UnityEngine.Vector3(Clamp(value.x, min, max), Clamp(value.y, min, max), Clamp(value.z, min, max)); } public static bool IsVectorNaN(UnityEngine.Vector3 value) { if (!float.IsNaN(value.x) && !float.IsNaN(value.y)) { return float.IsNaN(value.z); } return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsVectorValid(ref UnityEngine.Vector3 vector3) { float f = vector3.x + vector3.y + vector3.z; if (!float.IsInfinity(f)) { return !float.IsNaN(f); } return false; } public static bool Overshoots(UnityEngine.Vector3 startPosition, UnityEngine.Vector3 endPosition, UnityEngine.Vector3 targetPosition) { UnityEngine.Vector3 lhs = endPosition - startPosition; UnityEngine.Vector3 rhs = targetPosition - endPosition; return UnityEngine.Vector3.Dot(lhs, rhs) <= 0f; } public static float TriangleArea(in UnityEngine.Vector3 a, in UnityEngine.Vector3 b, in UnityEngine.Vector3 c) { return 0.5f * UnityEngine.Vector3.Cross(b - a, c - a).magnitude; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float CircleRadiusToArea(float radius) { return MathF.PI * (radius * radius); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float CircleAreaToRadius(float area) { return Mathf.Sqrt(area * (1f / MathF.PI)); } } public static class HGUnitConversions { public static readonly double milesToKilometers = 1.609344; public static readonly double kilometersToMeters = 1000.0; public static readonly double milesToMeters = milesToKilometers * kilometersToMeters; public static readonly double hoursToMinutes = 60.0; public static readonly double minutesToSeconds = 60.0; public static readonly double hoursToSeconds = hoursToMinutes * minutesToSeconds; } public static class HGXml { public delegate void Serializer(XElement element, T contents); public delegate bool Deserializer(XElement element, ref T contents); public class SerializationRules { public Serializer serializer; public Deserializer deserializer; public static SerializationRules defaultRules; static SerializationRules() { if (typeof(T).IsEnum) { RegisterEnum(); } } private static void RegisterEnum() { Type typeFromHandle = typeof(T); Dictionary nameToValue = new Dictionary(); string[] names = Enum.GetNames(typeFromHandle); for (int i = 0; i < names.Length; i++) { string text = names[i]; Enum.Parse(typeFromHandle, names[i]); nameToValue[text] = (T)Enum.Parse(typeFromHandle, text); } Dictionary valueToName = new Dictionary(); Array values = Enum.GetValues(typeFromHandle); for (int j = 0; j < values.Length; j++) { object value = values.GetValue(j); valueToName[(T)value] = Enum.GetName(typeFromHandle, value); } defaultRules = new SerializationRules { serializer = Serializer, deserializer = Deserializer }; bool Deserializer(XElement element, ref T contents) { if (nameToValue.TryGetValue(element.Value, out var value2)) { contents = value2; return true; } try { contents = (T)Enum.Parse(typeof(T), element.Value); return true; } catch (Exception) { } return false; } void Serializer(XElement element, T contents) { if (valueToName.TryGetValue(contents, out var value3)) { element.Value = value3; } else { element.Value = contents.ToString(); } } } } public static void Register(Serializer serializer, Deserializer deserializer) { SerializationRules.defaultRules = new SerializationRules { serializer = serializer, deserializer = deserializer }; } [NotNull] public static XElement ToXml(string name, T value) { return ToXml(name, value, SerializationRules.defaultRules); } [NotNull] public static XElement ToXml(string name, T value, SerializationRules rules) { XElement xElement = new XElement(name); rules.serializer(xElement, value); return xElement; } public static bool FromXml([NotNull] XElement element, ref T value) { return FromXml(element, ref value, SerializationRules.defaultRules); } public static bool FromXml([NotNull] XElement element, ref T value, SerializationRules rules) { if (rules == null) { UnityEngine.Debug.LogFormat("Serialization rules not defined for type <{0}>", typeof(T).Name); return false; } return rules.deserializer(element, ref value); } public static bool FromXml([NotNull] XElement element, [NotNull] Action setter) { return FromXml(element, setter, SerializationRules.defaultRules); } public static bool FromXml([NotNull] XElement element, [NotNull] Action setter, [NotNull] SerializationRules rules) { T value = default(T); if (FromXml(element, ref value, rules)) { setter(value); return true; } return false; } static HGXml() { Register(delegate(XElement element, int contents) { element.Value = TextSerialization.ToStringInvariant(contents); }, delegate(XElement element, ref int contents) { if (TextSerialization.TryParseInvariant(element.Value, out int result8)) { contents = result8; return true; } return false; }); Register(delegate(XElement element, uint contents) { element.Value = TextSerialization.ToStringInvariant(contents); }, delegate(XElement element, ref uint contents) { if (TextSerialization.TryParseInvariant(element.Value, out uint result7)) { contents = result7; return true; } return false; }); Register(delegate(XElement element, ulong contents) { element.Value = TextSerialization.ToStringInvariant(contents); }, delegate(XElement element, ref ulong contents) { if (TextSerialization.TryParseInvariant(element.Value, out ulong result6)) { contents = result6; return true; } return false; }); Register(delegate(XElement element, bool contents) { element.Value = (contents ? "1" : "0"); }, delegate(XElement element, ref bool contents) { if (TextSerialization.TryParseInvariant(element.Value, out int result5)) { contents = result5 != 0; return true; } return false; }); Register(delegate(XElement element, float contents) { element.Value = TextSerialization.ToStringInvariant(contents); }, delegate(XElement element, ref float contents) { if (TextSerialization.TryParseInvariant(element.Value, out float result4)) { contents = result4; return true; } return false; }); Register(delegate(XElement element, double contents) { element.Value = TextSerialization.ToStringInvariant(contents); }, delegate(XElement element, ref double contents) { if (TextSerialization.TryParseInvariant(element.Value, out double result3)) { contents = result3; return true; } return false; }); Register(delegate(XElement element, string contents) { element.Value = contents; }, delegate(XElement element, ref string contents) { contents = element.Value; return true; }); Register(delegate(XElement element, Guid contents) { element.Value = contents.ToString(); }, delegate(XElement element, ref Guid contents) { if (Guid.TryParse(element.Value, out var result2)) { contents = result2; return true; } return false; }); Register(delegate(XElement element, DateTime contents) { element.Value = TextSerialization.ToStringInvariant(contents.ToBinary()); }, delegate(XElement element, ref DateTime contents) { if (TextSerialization.TryParseInvariant(element.Value, out long result)) { try { contents = DateTime.FromBinary(result); return true; } catch (ArgumentException) { } } return false; }); } public static void Deserialize(this XElement element, ref T dest) { FromXml(element, ref dest); } public static void Deserialize(this XElement element, ref T dest, SerializationRules rules) { FromXml(element, ref dest, rules); } public static void UsedOnlyForAOTCodeGeneration() { throw new InvalidOperationException("This method is used for AOT code generation only. Do not call it at runtime."); } } public class HideIfSurvivorLocked : MonoBehaviour { [Tooltip("Survivor Def(s) that must be unlocked in order to show this component's gameObject. (ANY)")] public SurvivorDef[] requiredSurvivors; [Tooltip("Indicator to show that none of the designated survivors are unlocked.")] public GameObject lockedIndicator; private void Awake() { EntitlementManager.onEntitlementsUpdated += Reset; Reset(); } private void OnDestroy() { EntitlementManager.onEntitlementsUpdated -= Reset; } private void Reset() { if (requiredSurvivors.Length != 0) { if (requiredSurvivors.Any((SurvivorDef survivorDef) => SurvivorCatalog.SurvivorIsUnlockedOnThisClient(survivorDef.survivorIndex) && survivorDef.CheckLocalUserHasRequiredEntitlement())) { base.gameObject.SetActive(value: true); SetLockIndicator(value: false); } else { base.gameObject.SetActive(value: false); SetLockIndicator(value: true); } } else { UnityEngine.Debug.LogWarning("No designated requiredSurvivors or lockedIndicator on HideIfSurvivorLocked. Consider updating or removing this component on gameObject:" + base.gameObject.name + "."); } } private void SetLockIndicator(bool value) { if (lockedIndicator != null) { lockedIndicator.SetActive(value); } } } public class ItemIndexStorage : MonoBehaviour { public bool isEquipment; public ItemIndex itemIndex; public EquipmentIndex equipmentIndex; } public readonly struct KeyValueSplitter { private interface IStringWrapper { int Length { get; } string SubString(int startIndex, int length); } private struct StringWrapper : IStringWrapper { private readonly string src; public int Length => src.Length; public StringWrapper([NotNull] string str) { src = str; } public override string ToString() { return src; } public string SubString(int startIndex, int length) { return src.Substring(startIndex, length); } } private struct StringBuilderWrapper : IStringWrapper { private readonly StringBuilder src; public int Length => src.Length; public StringBuilderWrapper([NotNull] StringBuilder src) { this.src = src; } public override string ToString() { return src.ToString(); } public string SubString(int startIndex, int length) { return src.ToString(startIndex, length); } } public readonly string baseKey; private readonly int maxKeyLength; private readonly int maxValueLength; private readonly List currentSubKeys; private readonly Action keyValueSetter; public KeyValueSplitter([NotNull] string baseKey, int maxKeyLength, int maxValueLength, [NotNull] Action keyValueSetter) { this.baseKey = baseKey; this.maxKeyLength = maxKeyLength; this.maxValueLength = maxValueLength; this.keyValueSetter = keyValueSetter; currentSubKeys = new List(); } public void SetValue([NotNull] StringBuilder stringBuilder) { SetValueInternal(new StringBuilderWrapper(stringBuilder)); } public void SetValue([NotNull] string value) { SetValueInternal(new StringWrapper(value)); } private void SetValueInternal(T value) where T : IStringWrapper { int length = value.Length; List> list = CollectionPool, List>>.RentCollection(); if (length <= maxValueLength) { list.Add(new KeyValuePair(baseKey, value.ToString())); } else { int num = length; int num2 = 0; StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder(); do { int length2 = Math.Min(num, maxValueLength); string key = stringBuilder.Clear().Append(baseKey).Append("[") .AppendInt(num2++) .Append("]") .ToString(); string value2 = value.SubString(value.Length - num, length2); list.Add(new KeyValuePair(key, value2)); num -= maxValueLength; } while (num > 0); HG.StringBuilderPool.ReturnStringBuilder(stringBuilder); } for (int i = 0; i < currentSubKeys.Count; i++) { string text = currentSubKeys[i]; bool flag = false; for (int j = 0; j < list.Count; j++) { if (list[j].Key.Equals(text, StringComparison.Ordinal)) { flag = true; break; } } if (!flag) { keyValueSetter(text, null); } } currentSubKeys.Clear(); for (int k = 0; k < list.Count; k++) { currentSubKeys.Add(list[k].Key); } for (int l = 0; l < list.Count; l++) { KeyValuePair keyValuePair = list[l]; keyValueSetter(keyValuePair.Key, keyValuePair.Value); } CollectionPool, List>>.ReturnCollection(list); } } public struct KeyValueUnsplitter { public readonly string baseKey; public KeyValueUnsplitter(string baseKey) { this.baseKey = baseKey; } public string GetValue(IEnumerable> keyValues) { List> list = CollectionPool, List>>.RentCollection(); foreach (KeyValuePair keyValue in keyValues) { if (keyValue.Key.EndsWith("]", StringComparison.Ordinal)) { int num = keyValue.Key.LastIndexOf("[", StringComparison.Ordinal); string value = keyValue.Key.Substring(0, num); if (baseKey.Equals(value, StringComparison.Ordinal) && int.TryParse(keyValue.Key.Substring(num + 1), out var result)) { list.Add(new KeyValuePair(result, keyValue.Value)); } } else if (baseKey.Equals(keyValue.Key, StringComparison.Ordinal)) { return keyValue.Value; } } list.Sort((KeyValuePair a, KeyValuePair b) => a.Key.CompareTo(b.Key)); string result2 = string.Concat(list); CollectionPool, List>>.ReturnCollection(list); return result2; } } public static class LoadHelper { private static Dictionary> currentSceneLoads = new Dictionary>(); public static AsyncOperationHandle StartLoadSceneAdditiveAsync(string _sceneGuid) { AsyncOperationHandle asyncOperationHandle = Addressables.LoadSceneAsync(_sceneGuid, LoadSceneMode.Additive, activateOnLoad: false); if (!currentSceneLoads.ContainsKey(_sceneGuid)) { currentSceneLoads[_sceneGuid] = asyncOperationHandle; } return asyncOperationHandle; } public static IEnumerator LoadSceneAdditivelyAsync(string _sceneGuid) { AsyncOperationHandle handler; if (!currentSceneLoads.ContainsKey(_sceneGuid)) { handler = Addressables.LoadSceneAsync(_sceneGuid, LoadSceneMode.Additive, activateOnLoad: false); yield return handler; } else { handler = currentSceneLoads[_sceneGuid]; currentSceneLoads.Remove(_sceneGuid); yield return handler; } Scene oldScene = SceneManager.GetActiveScene(); SceneInstance newScene = handler.Result; yield return newScene.ActivateAsync(); SceneManager.SetActiveScene(newScene.Scene); SceneManager.UnloadSceneAsync(oldScene); } } public static class FastDebug { [Conditional("YEET")] public static void Log(object message, UnityEngine.Object context) { UnityEngine.Debug.Log(message, context); } [Conditional("YEET")] public static void Log(object message) { UnityEngine.Debug.Log(message); } [Conditional("YEET")] public static void LogFormat(string message, params object[] args) { UnityEngine.Debug.LogFormat(message, args); } [Conditional("YEET")] public static void LogFormat(UnityEngine.Object context, string message, params object[] args) { UnityEngine.Debug.LogFormat(context, message, args); } [Conditional("YEET")] public static void LogWarning(object message, UnityEngine.Object context) { UnityEngine.Debug.LogWarning(message, context); } [Conditional("YEET")] public static void LogWarning(object message) { UnityEngine.Debug.LogWarning(message); } [Conditional("YEET")] public static void LogWarningFormat(string message, params object[] args) { UnityEngine.Debug.LogWarningFormat(message, args); } [Conditional("YEET")] public static void LogWarningFormat(UnityEngine.Object context, string message, params object[] args) { UnityEngine.Debug.LogWarningFormat(context, message, args); } [Conditional("YEET")] public static void LogError(object message, UnityEngine.Object context) { UnityEngine.Debug.LogError(message, context); } [Conditional("YEET")] public static void LogError(object message) { UnityEngine.Debug.LogError(message); } [Conditional("YEET")] public static void LogErrorFormat(string message, params object[] args) { UnityEngine.Debug.LogErrorFormat(message, args); } [Conditional("YEET")] public static void LogErrorFormat(UnityEngine.Object context, string message, params object[] args) { UnityEngine.Debug.LogErrorFormat(context, message, args); } [Conditional("YEET")] public static void LogAssertion(object message, UnityEngine.Object context) { } [Conditional("YEET")] public static void LogAssertion(object message) { } [Conditional("YEET")] public static void LogAssertionFormat(string message, params object[] args) { } [Conditional("YEET")] public static void LogAssertion(UnityEngine.Object context, string message, params object[] args) { } [Conditional("YEET")] public static void LogException(Exception e, UnityEngine.Object context) { UnityEngine.Debug.LogException(e, context); } [Conditional("YEET")] public static void LogException(Exception e) { UnityEngine.Debug.LogException(e); } public static void LogChat(object message) { Chat.AddMessage(message.ToString()); } } public struct MemoizedToString where TInput : IEquatable where TToString : struct, IToStringImplementation { private TInput lastInput; private string lastOutput; private TToString implementation; private static readonly MemoizedToString defaultValue; public string GetString(in TInput input) { if (!input.Equals(lastInput)) { lastInput = input; lastOutput = implementation.DoToString(in lastInput); } return lastOutput; } public static MemoizedToString GetNew() { return defaultValue; } static MemoizedToString() { TInput input = default(TInput); TToString val = default(TToString); defaultValue = new MemoizedToString { lastInput = input, lastOutput = val.DoToString(in input), implementation = val }; } } public struct NetworkLerpedAngle { private const float interpDuration = 0.05f; private const float invInterpDuration = 20f; public float authoritativeValue; private float interpStartValue; private float interpStartTime; public float GetCurrentValue(bool hasAuthority) { if (hasAuthority) { return authoritativeValue; } float t = Mathf.Clamp01((Time.time - interpStartTime) * 20f); return Mathf.LerpAngle(interpStartValue, authoritativeValue, t); } public void SetAuthoritativeValue(float newValue, bool hasAuthority) { interpStartValue = GetCurrentValue(hasAuthority); interpStartTime = Time.time; authoritativeValue = newValue; } } public struct NetworkLerpedAngleNew { private struct InterpPoint { public float time; public float value; } private const float interpDelay = 0.1f; private InterpPoint lowInterpPoint; private InterpPoint highInterpPoint; private InterpPoint newestInterpPoint; private float inverseLowHighTimespan; public void SetValueImmediate(float value) { newestInterpPoint.time = Time.time; newestInterpPoint.value = value; highInterpPoint = newestInterpPoint; lowInterpPoint = newestInterpPoint; inverseLowHighTimespan = 0f; } public float GetCurrentValue(bool hasAuthority) { if (hasAuthority) { return newestInterpPoint.value; } float num = Time.time - 0.1f; if (num > highInterpPoint.time) { lowInterpPoint = highInterpPoint; highInterpPoint = newestInterpPoint; float num2 = highInterpPoint.time - lowInterpPoint.time; inverseLowHighTimespan = ((num2 == 0f) ? 0f : (1f / num2)); } float t = Mathf.Clamp01((num - lowInterpPoint.time) * inverseLowHighTimespan); return Mathf.LerpAngle(lowInterpPoint.value, highInterpPoint.value, t); } public float GetAuthoritativeValue() { return newestInterpPoint.value; } public void PushValue(float value) { if (newestInterpPoint.value != value) { newestInterpPoint.time = Time.time; newestInterpPoint.value = value; } } } public struct NetworkLerpedFloat { private struct InterpPoint { public float time; public float value; } private const float interpDelay = 0.1f; private InterpPoint lowInterpPoint; private InterpPoint highInterpPoint; private InterpPoint newestInterpPoint; private float inverseLowHighTimespan; public void SetValueImmediate(float value) { newestInterpPoint.time = Time.time; newestInterpPoint.value = value; highInterpPoint = newestInterpPoint; lowInterpPoint = newestInterpPoint; inverseLowHighTimespan = 0f; } public float GetCurrentValue(bool hasAuthority) { if (hasAuthority) { return newestInterpPoint.value; } float num = Time.time - 0.1f; if (num > highInterpPoint.time) { lowInterpPoint = highInterpPoint; highInterpPoint = newestInterpPoint; float num2 = highInterpPoint.time - lowInterpPoint.time; inverseLowHighTimespan = ((num2 == 0f) ? 0f : (1f / num2)); } float t = (num - lowInterpPoint.time) * inverseLowHighTimespan; return Mathf.Lerp(lowInterpPoint.value, highInterpPoint.value, t); } public float GetAuthoritativeValue() { return newestInterpPoint.value; } public void PushValue(float value) { if (newestInterpPoint.value != value) { newestInterpPoint.time = Time.time; newestInterpPoint.value = value; } } } public struct NetworkLerpedVector3 { private struct InterpPoint { public float time; public UnityEngine.Vector3 value; } public float interpDelay; private InterpPoint lowInterpPoint; private InterpPoint highInterpPoint; private InterpPoint newestInterpPoint; private float inverseLowHighTimespan; public void SetValueImmediate(UnityEngine.Vector3 value) { newestInterpPoint.time = Time.time; newestInterpPoint.value = value; highInterpPoint = newestInterpPoint; lowInterpPoint = newestInterpPoint; inverseLowHighTimespan = 0f; } public UnityEngine.Vector3 GetCurrentValue(bool hasAuthority) { if (hasAuthority) { return newestInterpPoint.value; } float num = Time.time - interpDelay; if (num > highInterpPoint.time) { lowInterpPoint = highInterpPoint; highInterpPoint = newestInterpPoint; float num2 = highInterpPoint.time - lowInterpPoint.time; inverseLowHighTimespan = ((num2 == 0f) ? 0f : (1f / num2)); } float t = (num - lowInterpPoint.time) * inverseLowHighTimespan; return UnityEngine.Vector3.Lerp(lowInterpPoint.value, highInterpPoint.value, t); } public UnityEngine.Vector3 GetAuthoritativeValue() { return newestInterpPoint.value; } public void PushValue(UnityEngine.Vector3 value) { if (newestInterpPoint.value != value) { newestInterpPoint.time = Time.time; newestInterpPoint.value = value; } } } public struct NetworkLerpedQuaternion { private struct InterpPoint { public float time; public UnityEngine.Quaternion value; } private const float interpDelay = 0.1f; private InterpPoint lowInterpPoint; private InterpPoint highInterpPoint; private InterpPoint newestInterpPoint; private float inverseLowHighTimespan; public void SetValueImmediate(UnityEngine.Quaternion value) { newestInterpPoint.time = Time.time; newestInterpPoint.value = value; highInterpPoint = newestInterpPoint; lowInterpPoint = newestInterpPoint; inverseLowHighTimespan = 0f; } public UnityEngine.Quaternion GetCurrentValue(bool hasAuthority) { if (hasAuthority) { return newestInterpPoint.value; } float num = Time.time - 0.1f; if (num > highInterpPoint.time) { lowInterpPoint = highInterpPoint; highInterpPoint = newestInterpPoint; float num2 = highInterpPoint.time - lowInterpPoint.time; inverseLowHighTimespan = ((num2 == 0f) ? 0f : (1f / num2)); } float t = (num - lowInterpPoint.time) * inverseLowHighTimespan; return UnityEngine.Quaternion.Slerp(lowInterpPoint.value, highInterpPoint.value, t); } public UnityEngine.Quaternion GetAuthoritativeValue() { return newestInterpPoint.value; } public void PushValue(UnityEngine.Quaternion value) { if (newestInterpPoint.value != value) { newestInterpPoint.time = Time.time; newestInterpPoint.value = value; } } } public class NetworkManagerConfiguration : MonoBehaviour { public new bool DontDestroyOnLoad = true; public bool RunInBackground = true; public LogFilter.FilterLevel LogLevel = LogFilter.FilterLevel.Info; public string OfflineScene; public string OnlineScene; public GameObject PlayerPrefab; public bool AutoCreatePlayer = true; public PlayerSpawnMethod PlayerSpawnMethod; public List SpawnPrefabs = new List(); public bool CustomConfig; public int MaxConnections = 4; public List QosChannels = new List(); } [RequireComponent(typeof(Light))] public class EnableCustomRenderTextureOnLight : MonoBehaviour { private Light targetLight; private bool targetLightHasCustomRenderTexture; private CustomRenderTexture targetLightCookie; private void Awake() { targetLight = GetComponent(); InitRenderTexture(); } private void Start() { SetUpdateMode(CustomRenderTextureUpdateMode.Realtime); } private void InitRenderTexture() { if (!(targetLight == null) && !(targetLight.cookie == null) && targetLight.cookie is CustomRenderTexture) { targetLightHasCustomRenderTexture = true; targetLightCookie = targetLight.cookie as CustomRenderTexture; } } private void SetUpdateMode(CustomRenderTextureUpdateMode mode) { if (targetLightHasCustomRenderTexture) { targetLightCookie.updateMode = mode; } } private void OnEnable() { SetUpdateMode(CustomRenderTextureUpdateMode.Realtime); } private void OnDisable() { SetUpdateMode(CustomRenderTextureUpdateMode.OnDemand); } private void OnDestroy() { SetUpdateMode(CustomRenderTextureUpdateMode.OnDemand); } } public static class GlobalPrefabFunctions { private static bool doSave = true; private static Transform FindRecursive(Transform t, string name) { if (t.name == name) { return t; } for (int i = 0; i < t.childCount; i++) { Transform child = t.GetChild(i); child = FindRecursive(child, name); if (child != null) { return child; } } return null; } } public class NearestPlayerCheckerSingleton : MonoBehaviour { public bool debugPrintInfo; public static NearestPlayerCheckerSingleton instance; } public class OnEnableRestartChildParticleSystems : MonoBehaviour { [SerializeField] private List particleSystemList = new List(); private void OnEnable() { if (particleSystemList == null || particleSystemList.Count <= 0) { return; } foreach (ParticleSystem particleSystem in particleSystemList) { if (!particleSystem.isPlaying) { particleSystem.Play(); } } } private void OnDisable() { if (particleSystemList == null || particleSystemList.Count <= 0) { return; } foreach (ParticleSystem particleSystem in particleSystemList) { particleSystem.Stop(); particleSystem.Clear(); } } } public class OrbEffectSingleton : MonoBehaviour { public static OrbEffectSingleton instance; public static OrbEffect[] orbEffectArray; public static int numPnts; private void Awake() { if (instance != null) { UnityEngine.Object.DestroyImmediate(this); return; } instance = this; orbEffectArray = new OrbEffect[50]; } public static void RegisterInstance(OrbEffect newOrbEffect) { if (orbEffectArray == null || orbEffectArray.Length == numPnts) { OrbEffect[] array = new OrbEffect[(int)((float)(numPnts + 1) * 1.5f)]; orbEffectArray.CopyTo(array, 0); orbEffectArray = array; } newOrbEffect.singletonArrayIndex = numPnts; orbEffectArray[numPnts] = newOrbEffect; numPnts++; } public static void UnregisterInstance(OrbEffect orbToDisable) { int singletonArrayIndex = orbToDisable.singletonArrayIndex; if (singletonArrayIndex != numPnts - 1) { orbEffectArray[singletonArrayIndex] = orbEffectArray[numPnts - 1]; orbEffectArray[singletonArrayIndex].singletonArrayIndex = singletonArrayIndex; } orbToDisable.singletonArrayIndex = -1; numPnts--; } public void Update() { for (int i = 0; i < numPnts; i++) { orbEffectArray[i].UpdateOrb(Time.deltaTime); } } } public class SceneReduction : MonoBehaviour { public enum ReductionSeverity { LOW, MEDIUM, HIGH } public static ReductionSeverity TargetReduction; public ReductionSeverity reductionSeverity; } public class Particle_SetMinSize : MonoBehaviour { public float minimumPixelCoverage = 2f; public float defaultMinimumParticleSize; [SerializeField] private bool _isEnabled = true; private void Start() { UpdateMinSize(); } public void SetEnabled(bool isEnabled) { _isEnabled = isEnabled; UpdateMinSize(); } private void UpdateMinSize() { GetComponent().minParticleSize = (_isEnabled ? (minimumPixelCoverage / (float)Screen.width) : defaultMinimumParticleSize); } } public class EOSTogglePopup : MonoBehaviour { public string titleText = "EOS_TOGGLE_POPUP_TITLE"; public string messageText = "EOS_TOGGLE_POPUP_MESSAGE"; public string closeNowButtonText = "EOS_TOGGLE_CLOSE_NOW"; public string closeLaterButtonText = "EOS_TOGGLE_CLOSE_LATER"; public void emitMessage() { SimpleDialogBox dialogBox = SimpleDialogBox.Create(); Action deactiveCrossplayAndRestartFunction = delegate { if ((bool)dialogBox) { RoR2.Console.instance.SubmitCmd(null, "quit"); } }; dialogBox.AddActionButton(delegate { deactiveCrossplayAndRestartFunction(); }, closeNowButtonText, true); dialogBox.AddCancelButton(closeLaterButtonText); dialogBox.headerToken = new SimpleDialogBox.TokenParamsPair { token = titleText, formatParams = Array.Empty() }; dialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair { token = messageText, formatParams = Array.Empty() }; } } public class GamecoreLeaderboards : MonoBehaviour { } public class GamecoreNameDisplay : MonoBehaviour { public HGTextMeshProUGUI Text; public GameObject Parent; private void Awake() { Parent.SetActive(value: false); } } public class GamecoreSwitchUser : MonoBehaviour { public void OnButtonClick() { } } public class PS4Timer { } public class SonyNpRanking { } public class PlatformVoiceChatManager { public static VoiceChatManager Get() { return null; } } public static class UDPHelper { public static UDPSender Sender; public static UDPReceive Receiver; public static UDPTest Test; private static UDPSenderUpdate uDPSender; static UDPHelper() { Sender = new UDPSender(); Receiver = new UDPReceive(); Test = new UDPTest(); GameObject gameObject = new GameObject("UDPHelperSender"); gameObject.AddComponent(); uDPSender = gameObject.GetComponent(); } } public class UDPSenderUpdate : MonoBehaviour { private void Awake() { UnityEngine.Object.DontDestroyOnLoad(base.gameObject); } private void Start() { } private void Update() { } private IEnumerator EndlessSending() { yield return new WaitForEndOfFrame(); } } public class UDPTest { private byte counter = 1; public void AddByte(ref byte[] bytes, ref int numBytes, ref bool shouldAddToQueue, int channelId) { if (numBytes == 1 && bytes[0] == 0) { return; } if (bytes.Length <= numBytes) { byte[] array = new byte[numBytes + 1]; for (int i = 0; i < bytes.Length; i++) { array[i] = bytes[i]; } bytes = array; } shouldAddToQueue = TryAdd(ref bytes, ref numBytes, channelId); } private bool TryAdd(ref byte[] data, ref int numbytes, int channelId) { if (true) { data[numbytes] = GetCounter(); } else { data[numbytes] = 0; } numbytes++; return true; } private byte GetCounter() { return 7; } } public class StadiaGameEventManager { } public class VoiceChatManagerStadia : MonoBehaviour { } public class PinnedKey { } [Serializable] internal class ApplicationDataStruct { public uint quickPlayCutoffTime; public string hostName = ""; public int Serialize(byte[] destinationBuf) { int offset = 0; EncodeUint(quickPlayCutoffTime, ref offset, ref destinationBuf); EncodeString(hostName, ref offset, ref destinationBuf); return offset; } private void EncodeUint(uint u, ref int offset, ref byte[] destinationBuf) { BitConverter.GetBytes(u).CopyTo(destinationBuf, offset); offset += 4; } private void EncodeString(string s, ref int offset, ref byte[] destinationBuf) { byte[] bytes = Encoding.ASCII.GetBytes(s); byte[] bytes2 = BitConverter.GetBytes(bytes.Length); bytes2.CopyTo(destinationBuf, offset); offset += bytes2.Length; bytes.CopyTo(destinationBuf, offset); offset += bytes.Length; } public void Deserialize(byte[] buffer, uint dataSize) { int offset = 0; quickPlayCutoffTime = DecodeUint(ref offset, buffer); hostName = DecodeString(ref offset, buffer); } private uint DecodeUint(ref int offset, byte[] buffer) { uint result = BitConverter.ToUInt32(buffer, offset); offset += 4; return result; } private string DecodeString(ref int offset, byte[] buffer) { string result = null; int num = BitConverter.ToInt32(buffer, offset); offset += 4; if (num > 0) { result = Encoding.ASCII.GetString(buffer, offset, num); offset += num; } return result; } } public class PiaMatchmaker : MonoBehaviour { } public class PiaNetworkTransport : INetworkTransport { public bool IsStarted => NetworkTransport.IsStarted; public int AddHost(HostTopology topology, int port, string ip) { UnityEngine.Debug.LogFormat($"PiaNetworkTransport::AddHost: topology: {0}, port: {1}, ip: {2}", topology.ToString(), port, ip); return NetworkTransport.AddHost(topology, 7777, "localhost"); } public int AddHostWithSimulator(HostTopology topology, int minTimeout, int maxTimeout, int port) { return NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout, port); } public int AddWebsocketHost(HostTopology topology, int port, string ip) { return NetworkTransport.AddWebsocketHost(topology, port, ip); } public int Connect(int hostId, string address, int port, int specialConnectionId, out byte error) { return NetworkTransport.Connect(hostId, address, port, specialConnectionId, out error); } public void ConnectAsNetworkHost(int hostId, string address, int port, NetworkID network, SourceID source, NodeID node, out byte error) { NetworkTransport.ConnectAsNetworkHost(hostId, address, port, network, source, node, out error); } public int ConnectEndPoint(int hostId, EndPoint endPoint, int specialConnectionId, out byte error) { return NetworkTransport.ConnectEndPoint(hostId, endPoint, specialConnectionId, out error); } public int ConnectToNetworkPeer(int hostId, string address, int port, int specialConnectionId, int relaySlotId, NetworkID network, SourceID source, NodeID node, out byte error) { return NetworkTransport.ConnectToNetworkPeer(hostId, address, port, specialConnectionId, relaySlotId, network, source, node, out error); } public int ConnectWithSimulator(int hostId, string address, int port, int specialConnectionId, out byte error, ConnectionSimulatorConfig conf) { return NetworkTransport.ConnectWithSimulator(hostId, address, port, specialConnectionId, out error, conf); } public bool Disconnect(int hostId, int connectionId, out byte error) { return NetworkTransport.Disconnect(hostId, connectionId, out error); } public bool DoesEndPointUsePlatformProtocols(EndPoint endPoint) { return true; } public void GetBroadcastConnectionInfo(int hostId, out string address, out int port, out byte error) { NetworkTransport.GetBroadcastConnectionInfo(hostId, out address, out port, out error); } public void GetBroadcastConnectionMessage(int hostId, byte[] buffer, int bufferSize, out int receivedSize, out byte error) { NetworkTransport.GetBroadcastConnectionMessage(hostId, buffer, bufferSize, out receivedSize, out error); } public void GetConnectionInfo(int hostId, int connectionId, out string address, out int port, out NetworkID network, out NodeID dstNode, out byte error) { NetworkTransport.GetConnectionInfo(hostId, connectionId, out address, out port, out network, out dstNode, out error); } public int GetCurrentRTT(int hostId, int connectionId, out byte error) { return NetworkTransport.GetCurrentRTT(hostId, connectionId, out error); } public void Init() { NetworkTransport.Init(); } public void Init(GlobalConfig config) { NetworkTransport.Init(config); } public NetworkEventType Receive(out int hostId, out int connectionId, out int channelId, byte[] buffer, int bufferSize, out int receivedSize, out byte error) { return NetworkTransport.Receive(out hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error); } public NetworkEventType ReceiveFromHost(int hostId, out int connectionId, out int channelId, byte[] buffer, int bufferSize, out int receivedSize, out byte error) { return NetworkTransport.ReceiveFromHost(hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error); } public NetworkEventType ReceiveRelayEventFromHost(int hostId, out byte error) { return NetworkTransport.ReceiveRelayEventFromHost(hostId, out error); } public bool RemoveHost(int hostId) { return NetworkTransport.RemoveHost(hostId); } public bool Send(int hostId, int connectionId, int channelId, byte[] buffer, int size, out byte error) { return NetworkTransport.Send(hostId, connectionId, channelId, buffer, size, out error); } public void SetBroadcastCredentials(int hostId, int key, int version, int subversion, out byte error) { NetworkTransport.SetBroadcastCredentials(hostId, key, version, subversion, out error); } public void SetPacketStat(int direction, int packetStatId, int numMsgs, int numBytes) { NetworkTransport.SetPacketStat(direction, packetStatId, numMsgs, numBytes); } public void Shutdown() { NetworkTransport.Shutdown(); } public bool StartBroadcastDiscovery(int hostId, int broadcastPort, int key, int version, int subversion, byte[] buffer, int size, int timeout, out byte error) { return NetworkTransport.StartBroadcastDiscovery(hostId, broadcastPort, key, version, subversion, buffer, size, timeout, out error); } public void StopBroadcastDiscovery() { NetworkTransport.StopBroadcastDiscovery(); } } public class RewiredControllerSupport : MonoBehaviour { } public static class ProcessorAffinity { } public static class RendererSetMaterialsExtension { private static Material[][] sharedMaterialArrays; private static void InitSharedMaterialsArrays(int maxMaterials) { sharedMaterialArrays = new Material[maxMaterials + 1][]; if (maxMaterials > 0) { sharedMaterialArrays[0] = Array.Empty(); for (int i = 1; i < sharedMaterialArrays.Length; i++) { sharedMaterialArrays[i] = new Material[i]; } } } static RendererSetMaterialsExtension() { InitSharedMaterialsArrays(16); } public static void SetSharedMaterials(this Renderer renderer, Material[] sharedMaterials, int count) { if (sharedMaterialArrays.Length < count) { InitSharedMaterialsArrays(count); } Material[] array = sharedMaterialArrays[count]; Array.Copy(sharedMaterials, array, count); renderer.sharedMaterials = array; Array.Clear(array, 0, count); } public static void SetSharedMaterials(this Renderer renderer, List sharedMaterials) { int count = sharedMaterials.Count; if (sharedMaterialArrays.Length < count) { InitSharedMaterialsArrays(count); } Material[] array = sharedMaterialArrays[count]; sharedMaterials.CopyTo(array, 0); renderer.sharedMaterials = array; Array.Clear(array, 0, count); } public static void SetMaterials(this Renderer renderer, Material[] materials, int count) { if (sharedMaterialArrays.Length < count) { InitSharedMaterialsArrays(count); } Material[] array = sharedMaterialArrays[count]; Array.Copy(materials, array, count); renderer.materials = array; Array.Clear(array, 0, count); } public static void SetMaterials(this Renderer renderer, List materials) { int count = materials.Count; if (sharedMaterialArrays.Length < count) { InitSharedMaterialsArrays(count); } Material[] array = sharedMaterialArrays[count]; materials.CopyTo(array, 0); renderer.materials = array; Array.Clear(array, 0, count); } } public class RendererVisiblity : MonoBehaviour { public enum DistanceClass { Near, Far, VeryFar } public CharacterModel parentModel; public DistanceClass approxDistance; public bool isVisible; [HideInInspector] public Animator animatorToUpdateOnceWhenVisible; private float visualUpdateTimer; public bool shouldUpdateVisuals = true; public void CalcDistanceClass(float distanceSq) { if (distanceSq < 2500f) { approxDistance = DistanceClass.Near; } else if (distanceSq < 10000f) { approxDistance = DistanceClass.Far; } else { approxDistance = DistanceClass.VeryFar; } if (!isVisible) { visualUpdateTimer -= Time.deltaTime; if (visualUpdateTimer < 0f) { visualUpdateTimer = 0.2f; shouldUpdateVisuals = true; } else { shouldUpdateVisuals = false; } return; } switch (approxDistance) { case DistanceClass.Near: shouldUpdateVisuals = true; break; case DistanceClass.Far: visualUpdateTimer -= Time.deltaTime; if (visualUpdateTimer < 0f) { visualUpdateTimer = 1f / 15f; shouldUpdateVisuals = true; } else { shouldUpdateVisuals = false; } break; case DistanceClass.VeryFar: visualUpdateTimer -= Time.deltaTime; if (visualUpdateTimer < 0f) { visualUpdateTimer = 2f / 15f; shouldUpdateVisuals = true; } else { shouldUpdateVisuals = false; } break; } } private void OnBecameVisible() { parentModel.SetVisible(visible: true); isVisible = true; if ((bool)animatorToUpdateOnceWhenVisible) { animatorToUpdateOnceWhenVisible.Update(0f); animatorToUpdateOnceWhenVisible = null; } } private void OnBecameInvisible() { parentModel.SetVisible(visible: false); isVisible = false; } } [Serializable] public struct RenderSettingsState { public float haloStrength; public int defaultReflectionResolution; public DefaultReflectionMode defaultReflectionMode; public int reflectionBounces; public float reflectionIntensity; public Texture customReflection; public SphericalHarmonicsL2 ambientProbe; public Light sun; public Material skybox; public UnityEngine.Color subtractiveShadowColor; public float flareStrength; [ColorUsage(false, true)] public UnityEngine.Color ambientLight; [ColorUsage(false, true)] public UnityEngine.Color ambientGroundColor; [ColorUsage(false, true)] public UnityEngine.Color ambientEquatorColor; [ColorUsage(false, true)] public UnityEngine.Color ambientSkyColor; public AmbientMode ambientMode; public float fogDensity; [ColorUsage(true, false)] public UnityEngine.Color fogColor; public FogMode fogMode; public float fogEndDistance; public float fogStartDistance; public bool fog; public float ambientIntensity; public float flareFadeSpeed; public static RenderSettingsState FromCurrent() { RenderSettingsState result = default(RenderSettingsState); result.haloStrength = RenderSettings.haloStrength; result.defaultReflectionResolution = RenderSettings.defaultReflectionResolution; result.defaultReflectionMode = RenderSettings.defaultReflectionMode; result.reflectionBounces = RenderSettings.reflectionBounces; result.reflectionIntensity = RenderSettings.reflectionIntensity; result.customReflection = RenderSettings.customReflection; result.ambientProbe = RenderSettings.ambientProbe; result.sun = RenderSettings.sun; result.skybox = RenderSettings.skybox; result.subtractiveShadowColor = RenderSettings.subtractiveShadowColor; result.flareStrength = RenderSettings.flareStrength; result.ambientLight = RenderSettings.ambientLight; result.ambientGroundColor = RenderSettings.ambientGroundColor; result.ambientEquatorColor = RenderSettings.ambientEquatorColor; result.ambientSkyColor = RenderSettings.ambientSkyColor; result.ambientMode = RenderSettings.ambientMode; result.fogDensity = RenderSettings.fogDensity; result.fogColor = RenderSettings.fogColor; result.fogMode = RenderSettings.fogMode; result.fogEndDistance = RenderSettings.fogEndDistance; result.fogStartDistance = RenderSettings.fogStartDistance; result.fog = RenderSettings.fog; result.ambientIntensity = RenderSettings.ambientIntensity; result.flareFadeSpeed = RenderSettings.flareFadeSpeed; return result; } public void Apply() { RenderSettings.haloStrength = haloStrength; RenderSettings.defaultReflectionResolution = defaultReflectionResolution; RenderSettings.defaultReflectionMode = defaultReflectionMode; RenderSettings.reflectionBounces = reflectionBounces; RenderSettings.reflectionIntensity = reflectionIntensity; RenderSettings.customReflection = customReflection; RenderSettings.ambientProbe = ambientProbe; RenderSettings.sun = sun; RenderSettings.skybox = skybox; RenderSettings.subtractiveShadowColor = subtractiveShadowColor; RenderSettings.flareStrength = flareStrength; RenderSettings.ambientLight = ambientLight; RenderSettings.ambientGroundColor = ambientGroundColor; RenderSettings.ambientEquatorColor = ambientEquatorColor; RenderSettings.ambientSkyColor = ambientSkyColor; RenderSettings.ambientMode = ambientMode; RenderSettings.fogDensity = fogDensity; RenderSettings.fogColor = fogColor; RenderSettings.fogMode = fogMode; RenderSettings.fogEndDistance = fogEndDistance; RenderSettings.fogStartDistance = fogStartDistance; RenderSettings.fog = fog; RenderSettings.ambientIntensity = ambientIntensity; RenderSettings.flareFadeSpeed = flareFadeSpeed; } } public struct ResourceAvailability { public bool available { get; private set; } private event Action onAvailable; public void MakeAvailable() { if (!available) { available = true; this.onAvailable?.Invoke(); this.onAvailable = null; } } public void CallWhenAvailable([NotNull] Action callback) { if (available) { callback(); } else { onAvailable += callback; } } } [Serializable] public class SceneField { [SerializeField] private UnityEngine.Object sceneAsset; [SerializeField] private string sceneName = ""; public string SceneName => sceneName; public SceneField(string sceneName) { this.sceneName = sceneName; } public static implicit operator string(SceneField sceneField) { return sceneField.sceneName; } public static implicit operator bool(SceneField sceneField) { return !string.IsNullOrEmpty(sceneField.sceneName); } } [Serializable] public class SerializableBitArray { [SerializeField] protected readonly byte[] bytes; [SerializeField] public readonly int length; private const int bitMask = 7; public int byteCount => bytes.Length; public bool this[int index] { get { int num = index >> 3; int num2 = index & 7; return (bytes[num] & (1 << num2)) != 0; } set { int num = index >> 3; int num2 = index & 7; int num3 = bytes[num]; bytes[num] = (byte)(value ? (num3 | (1 << num2)) : (num3 & ~(1 << num2))); } } public SerializableBitArray(int length) { bytes = new byte[length + 7 >> 3]; this.length = length; } public SerializableBitArray(SerializableBitArray src) { if (src.bytes != null) { bytes = new byte[src.bytes.Length]; src.bytes.CopyTo(bytes, 0); } length = src.length; } public byte[] GetBytes() { byte[] array = new byte[bytes.Length]; GetBytes(array); return array; } public void GetBytes([NotNull] byte[] dest) { Buffer.BlockCopy(bytes, 0, dest, 0, bytes.Length); } } public class SetAkGameObjToStaticAfterDelay : MonoBehaviour { [Tooltip("Delay until setting this AkGameObj script as 'static' (not updating")] [SerializeField] private float timeUntilSetToStatic = -1f; public static float defaultValueForDelayUntilSetToStatic = 10f; private void Awake() { if (timeUntilSetToStatic == -1f) { timeUntilSetToStatic = defaultValueForDelayUntilSetToStatic; } else { timeUntilSetToStatic = Mathf.Abs(timeUntilSetToStatic); } StartCoroutine(SetAkGameObjToStatic()); } private IEnumerator SetAkGameObjToStatic() { yield return new WaitForSeconds(timeUntilSetToStatic); AkGameObjUtil.SetAkGameObjectStatic(base.gameObject, this); UnityEngine.Object.Destroy(this); } } public class ShowThumbnailAttribute : PropertyAttribute { } public static class SingletonHelper { public static void Assign(ref T field, T instance) where T : UnityEngine.Object { if (!field) { field = instance; return; } UnityEngine.Debug.LogErrorFormat(instance, "Duplicate instance of singleton class {0}. Only one should exist at a time.", typeof(T).Name); } public static void Unassign(ref T field, T instance) where T : UnityEngine.Object { if (field == instance) { field = null; } } public static T Assign(T existingInstance, T instance) where T : UnityEngine.Object { if (!existingInstance) { return instance; } UnityEngine.Debug.LogErrorFormat(instance, "Duplicate instance of singleton class {0}. Only one should exist at a time.", typeof(T).Name); return existingInstance; } public static T Unassign(T existingInstance, T instance) where T : UnityEngine.Object { if (instance == existingInstance) { return null; } return existingInstance; } } public static class StringBuilderExtensions { private const uint maxDigitsInUint = 10u; private const uint maxDigitsInUlong = 20u; private static readonly char[] hexLookup = new char[16] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public static StringBuilder AppendInt(this StringBuilder stringBuilder, int value, uint minDigits = 1u, uint maxDigits = uint.MaxValue) { return AppendSignedInternal(stringBuilder, value, 10u, minDigits, maxDigits); } public static StringBuilder AppendUint(this StringBuilder stringBuilder, uint value, uint minDigits = 1u, uint maxDigits = uint.MaxValue) { return AppendUnsignedInternal(stringBuilder, value, 10u, minDigits, maxDigits); } public static StringBuilder AppendLong(this StringBuilder stringBuilder, long value, uint minDigits = 1u, uint maxDigits = uint.MaxValue) { return AppendSignedInternal(stringBuilder, value, 20u, minDigits, maxDigits); } public static StringBuilder AppendUlong(this StringBuilder stringBuilder, ulong value, uint minDigits = 1u, uint maxDigits = uint.MaxValue) { return AppendUnsignedInternal(stringBuilder, value, 20u, minDigits, maxDigits); } private static StringBuilder AppendUnsignedInternal(StringBuilder stringBuilder, ulong value, uint maxDigitsForType, uint minDigits = 1u, uint maxDigits = uint.MaxValue) { if (maxDigits < minDigits) { throw new ArgumentException("minDigits cannot be greater than maxDigits."); } uint num = 0u; uint num2 = ((maxDigitsForType < maxDigits) ? maxDigitsForType : maxDigits); ulong num3 = 1uL; while (num3 <= value && num < num2) { num3 *= 10; num++; } uint num4 = ((minDigits < num) ? num : minDigits); if (num4 != 0) { int length = stringBuilder.Length; stringBuilder.Append('0', (int)num4); ulong num5 = 0uL; ulong num6 = (uint)(length + (int)num4 - 1); ulong num7 = value; while (num5 < num) { ulong num8 = num7 / 10; byte b = (byte)(num7 - num8 * 10); char value2 = (char)(48 + b); stringBuilder[(int)num6] = value2; num7 = num8; num5++; num6--; } } return stringBuilder; } private static StringBuilder AppendSignedInternal(StringBuilder stringBuilder, long value, uint maxDigitsForType, uint minDigits = 1u, uint maxDigits = uint.MaxValue) { if (maxDigits < minDigits) { throw new ArgumentException("minDigits cannot be greater than maxDigits."); } if (value < 0) { stringBuilder.Append('-'); value = -value; } return AppendUnsignedInternal(stringBuilder, (uint)value, maxDigitsForType, minDigits, maxDigits); } private static void GetByteHexChars(byte byteValue, out char char1, out char char2) { char1 = hexLookup[(byteValue >> 4) & 0xF]; char2 = hexLookup[byteValue & 0xF]; } public static StringBuilder AppendByteHexValue(this StringBuilder stringBuilder, byte value) { GetByteHexChars(value, out var @char, out var char2); return stringBuilder.Append(@char).Append(char2); } public static StringBuilder AppendColor32RGBHexValues(this StringBuilder stringBuilder, Color32 color) { int num = stringBuilder.Length + 6; if (stringBuilder.Capacity < num) { stringBuilder.Capacity = num; } GetByteHexChars(color.r, out var @char, out var char2); GetByteHexChars(color.g, out var char3, out var char4); GetByteHexChars(color.b, out var char5, out var char6); return stringBuilder.Append(@char).Append(char2).Append(char3) .Append(char4) .Append(char5) .Append(char6); } public static StringBuilder JoinEnumerator(this StringBuilder stringBuilder, [NotNull] string separator, TEnumerator enumerator) where TEnumerator : IEnumerator { if (enumerator.MoveNext()) { stringBuilder.Append(enumerator.Current); while (enumerator.MoveNext()) { stringBuilder.Append(separator); stringBuilder.Append(enumerator.Current); } } return stringBuilder; } public static string Take(this StringBuilder stringBuilder) { string result = stringBuilder.ToString(); stringBuilder.Clear(); return result; } } [Obsolete("Use HG.StringBuilderPool instead.", false)] public static class StringBuilderPool { [MethodImpl(MethodImplOptions.AggressiveInlining)] [NotNull] [Obsolete("Use HG.StringBuilderPool instead.", false)] public static StringBuilder RentStringBuilder() { return HG.StringBuilderPool.RentStringBuilder(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Obsolete("Use HG.StringBuilderPool instead.", false)] [CanBeNull] public static StringBuilder ReturnStringBuilder([NotNull] StringBuilder stringBuilder) { return HG.StringBuilderPool.ReturnStringBuilder(stringBuilder); } } public static class TextSerialization { private static readonly CultureInfo invariantCulture = CultureInfo.InvariantCulture; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ParseIntInvariant(string s) { return int.Parse(s, NumberStyles.Integer, invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ParseUintInvariant(string s) { return uint.Parse(s, NumberStyles.Integer, invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ParseLongInvariant(string s) { return long.Parse(s, NumberStyles.Integer, invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong ParseUlongInvariant(string s) { return ulong.Parse(s, NumberStyles.Integer, invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short ParseShortInvariant(string s) { return short.Parse(s, NumberStyles.Integer, invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort ParseUshortInvariant(string s) { return ushort.Parse(s, NumberStyles.Integer, invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ParseFloatInvariant(string s) { return float.Parse(s, NumberStyles.Float, invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ParseDoubleInvariant(string s) { return double.Parse(s, NumberStyles.Float, invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal ParseDecimalInvariant(string s) { return decimal.Parse(s, NumberStyles.Float, invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseInvariant(string s, out int result) { return int.TryParse(s, NumberStyles.Integer, invariantCulture, out result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseInvariant(string s, out uint result) { return uint.TryParse(s, NumberStyles.Integer, invariantCulture, out result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseInvariant(string s, out long result) { return long.TryParse(s, NumberStyles.Integer, invariantCulture, out result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseInvariant(string s, out ulong result) { return ulong.TryParse(s, NumberStyles.Integer, invariantCulture, out result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseInvariant(string s, out short result) { return short.TryParse(s, NumberStyles.Integer, invariantCulture, out result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseInvariant(string s, out ushort result) { return ushort.TryParse(s, NumberStyles.Integer, invariantCulture, out result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseInvariant(string s, out float result) { return float.TryParse(s, NumberStyles.Float, invariantCulture, out result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseInvariant(string s, out double result) { return double.TryParse(s, NumberStyles.Float, invariantCulture, out result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseInvariant(string s, out decimal result) { return decimal.TryParse(s, NumberStyles.Float, invariantCulture, out result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringInvariant(int value) { return value.ToString(invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringInvariant(uint value) { return value.ToString(invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringInvariant(long value) { return value.ToString(invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringInvariant(ulong value) { return value.ToString(invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringInvariant(short value) { return value.ToString(invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringInvariant(ushort value) { return value.ToString(invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringInvariant(float value) { return value.ToString(invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringInvariant(double value) { return value.ToString(invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringInvariant(decimal value) { return value.ToString(invariantCulture); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringNumeric(int value) { return value.ToString("N0"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringNumeric(uint value) { return value.ToString("N0"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringNumeric(long value) { return value.ToString("N0"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringNumeric(ulong value) { return value.ToString("N0"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringNumeric(short value) { return value.ToString("N0"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringNumeric(ushort value) { return value.ToString("N0"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringNumeric(float value) { return value.ToString("N0"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringNumeric(double value) { return value.ToString("N0"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToStringNumeric(decimal value) { return value.ToString("N0"); } } public interface IToStringImplementation { string DoToString(in T input); } [StructLayout(LayoutKind.Sequential, Size = 1)] public struct ToStringDefault : IToStringImplementation { public string DoToString(in T input) { return input.ToString(); } string IToStringImplementation.DoToString(in T input) { return DoToString(in input); } } [StructLayout(LayoutKind.Sequential, Size = 1)] public struct ToStringImplementationInvariant : IToStringImplementation, IToStringImplementation, IToStringImplementation, IToStringImplementation, IToStringImplementation, IToStringImplementation, IToStringImplementation, IToStringImplementation { public string DoToString(in int input) { return TextSerialization.ToStringInvariant(input); } public string DoToString(in uint input) { return TextSerialization.ToStringInvariant(input); } public string DoToString(in long input) { return TextSerialization.ToStringInvariant(input); } public string DoToString(in ulong input) { return TextSerialization.ToStringInvariant(input); } public string DoToString(in short input) { return TextSerialization.ToStringInvariant(input); } public string DoToString(in ushort input) { return TextSerialization.ToStringInvariant(input); } public string DoToString(in float input) { return TextSerialization.ToStringInvariant(input); } public string DoToString(in double input) { return TextSerialization.ToStringInvariant(input); } public string DoToString(in decimal input) { return TextSerialization.ToStringInvariant(input); } string IToStringImplementation.DoToString(in int input) { return DoToString(in input); } string IToStringImplementation.DoToString(in uint input) { return DoToString(in input); } string IToStringImplementation.DoToString(in long input) { return DoToString(in input); } string IToStringImplementation.DoToString(in ulong input) { return DoToString(in input); } string IToStringImplementation.DoToString(in short input) { return DoToString(in input); } string IToStringImplementation.DoToString(in ushort input) { return DoToString(in input); } string IToStringImplementation.DoToString(in float input) { return DoToString(in input); } string IToStringImplementation.DoToString(in double input) { return DoToString(in input); } } public class ToggleAction : IDisposable { private readonly Action activationAction; private readonly Action deactivationAction; public bool active { get; private set; } public ToggleAction(Action activationAction, Action deactivationAction) { active = false; this.activationAction = activationAction; this.deactivationAction = deactivationAction; } public void SetActive(bool newActive) { if (active != newActive) { active = newActive; if (active) { activationAction?.Invoke(); } else { deactivationAction?.Invoke(); } } } public void Dispose() { SetActive(newActive: false); } } public static class QuickStopwatch { private static string m_name; private static Stopwatch m_stopwatch = new Stopwatch(); private static long m_lapTime = 0L; private static int m_lap = 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Begin(string name) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void End() { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Lap(string addText = "") { } } public class Utility_DebugScreamer : MonoBehaviour { [SerializeField] private bool screamOnFixedTime; [SerializeField] private bool screamOnUpdate; [SerializeField] private UnityEngine.Color _screamColor = new UnityEngine.Color(49f / 51f, 36f / 85f, 0.007843138f); private string colorHex; private float timeBorn; private float fixedTimeBorn; private float timeDisabled; private float fixedTimeDisabled; private string _goName; private void Awake() { timeBorn = Time.time; fixedTimeBorn = Time.fixedTime; _goName = base.gameObject.name; colorHex = "#" + ColorUtility.ToHtmlStringRGB(_screamColor); } private void FixedUpdate() { _ = screamOnFixedTime; } private void Update() { _ = screamOnUpdate; } private void OnDisable() { timeDisabled = Time.time; fixedTimeDisabled = Time.fixedTime; string text = _goName + " Screamer: DISABLED "; if (screamOnFixedTime) { text = text + " (FixedTime of Disable: " + fixedTimeDisabled + " / " + (fixedTimeDisabled - fixedTimeBorn) + "s alive)"; } if (screamOnUpdate) { text = text + " (Time of Disable: " + timeDisabled + " / " + (timeDisabled - timeBorn) + "s alive)"; } } private void OnDestroy() { float time = Time.time; float fixedTime = Time.fixedTime; string text = _goName + " Screamer: DISABLED "; if (screamOnFixedTime) { text = text + " (FixedTime of Destroy: " + fixedTime + " / " + (fixedTime - fixedTimeBorn) + "s alive)"; } if (screamOnUpdate) { text = text + " (Time of Destroy: " + time + " / " + (time - timeBorn) + "s alive)"; } } } public class Utility_Event_MemoryDebugging : MonoBehaviour { [Flags] public enum EventFlags { None = 0, FixedUpdate = 2, EarlyUpdate = 4, Update = 8, LateUpdate = 0x10, Render = 0x20 } public enum MemoryType { MonoUsed, TotalAllocated, FragmentationInfo } public const int arraySize = 10000; private static bool staticRecordData; private static EventFlags staticEventsToTrack; private static MemoryType staticMemoryTrackType; private static int index = 0; private static int lastRecordedRenderIndex = -1; private static long[] monoUsedEarlyUpdate = new long[10000]; private static long[] monoUsedUpdate = new long[10000]; private static long[] monoUsedLateUpdate = new long[10000]; private static long[] monoUsedFixedUpdate = new long[10000]; private static long[] monoUsedRender = new long[10000]; public EventFlags EventsToTrack; private EventFlags prevEventsToTrack; [Header("Should we record this info")] public bool RecordData; private bool prevRecordData; [Header("What type of memory should we be tracking?")] public MemoryType memoryTrackType; private MemoryType prevMemoryTrackType; [Header("In case you need to print it again")] public bool DumpDebugDataToConsole; [Header("The most memory gained so far")] public long mostMemoryIncrease = long.MinValue; public EventFlags mostMemoryIncreaseEvent; [Header("For viewing only - editing does nothing")] [Space(20f)] public string Index; public bool IncreasingBetweenUpdate; public bool IncreasingBetweenEarlyUpdate; public bool IncreasingBetweenLateUpdate; public bool IncreasingBetweenFixedUpdate; private long previousLong; private long temporaryLong; private long previousLongInThisArray; protected bool amIPreDefaultTime; private NativeArray fragmentationInfo; private void FixedUpdate() { if (DumpDebugDataToConsole && index > 0) { PrintAllDataRecorded(); DumpDebugDataToConsole = false; } if (ShouldWeRecordAnything() && AreWeTrackingThisEvent(EventFlags.FixedUpdate | EventFlags.Render)) { RecordCurrentMemory(ref monoUsedFixedUpdate, ref IncreasingBetweenFixedUpdate, EventFlags.FixedUpdate); } } private void EarlyUpdate() { if (ShouldWeRecordAnything() && AreWeTrackingThisEvent(EventFlags.EarlyUpdate)) { RecordCurrentMemory(ref monoUsedEarlyUpdate, ref IncreasingBetweenEarlyUpdate, EventFlags.EarlyUpdate); } } private void Update() { if (ShouldWeRecordAnything() && AreWeTrackingThisEvent(EventFlags.Update)) { RecordCurrentMemory(ref monoUsedUpdate, ref IncreasingBetweenUpdate, EventFlags.Update); } } private void LateUpdate() { if (ShouldWeRecordAnything() && (AreWeTrackingThisEvent(EventFlags.LateUpdate) || AreWeTrackingThisEvent(EventFlags.Render))) { RecordCurrentMemory(ref monoUsedLateUpdate, ref IncreasingBetweenLateUpdate, EventFlags.LateUpdate); TryIncrementIndex(); } } private bool AreWeTrackingThisEvent(EventFlags eventFlag) { if (EventsToTrack != prevEventsToTrack) { staticEventsToTrack = EventsToTrack; prevEventsToTrack = EventsToTrack; } if (EventsToTrack != staticEventsToTrack) { EventsToTrack = staticEventsToTrack; prevEventsToTrack = staticEventsToTrack; } return staticEventsToTrack.HasFlag(eventFlag); } private bool ShouldWeRecordAnything() { if (prevMemoryTrackType != memoryTrackType) { prevMemoryTrackType = memoryTrackType; staticMemoryTrackType = memoryTrackType; if (staticRecordData) { ResetAllData(); } } if (prevRecordData != RecordData) { prevRecordData = RecordData; staticRecordData = RecordData; if (!RecordData) { PrintAllDataRecorded(); } else { ResetAllData(); } } if (staticRecordData != RecordData) { RecordData = staticRecordData; prevRecordData = staticRecordData; } return staticRecordData; } private void TryIncrementIndex() { float num = index / 10000; Index = (float)(int)(num * 100f) / 100f + "% Complete"; if (!amIPreDefaultTime) { if (index < 9998) { index++; } else if (staticRecordData) { staticRecordData = false; PrintAllDataRecorded(); } } } private long GetMemoryValue() { return staticMemoryTrackType switch { MemoryType.TotalAllocated => Profiler.GetTotalAllocatedMemoryLong(), MemoryType.FragmentationInfo => Profiler.GetTotalFragmentationInfo(fragmentationInfo), _ => Profiler.GetMonoUsedSizeLong(), }; } private void RecordCurrentMemory(ref long[] _array, ref bool increasing, EventFlags _event) { temporaryLong = GetMemoryValue(); if (staticEventsToTrack.HasFlag(EventFlags.Render)) { if (!amIPreDefaultTime && _event == EventFlags.LateUpdate) { monoUsedRender[index] = temporaryLong; } else if (amIPreDefaultTime && _event == EventFlags.FixedUpdate && lastRecordedRenderIndex != index) { monoUsedRender[index] = temporaryLong - monoUsedRender[index]; lastRecordedRenderIndex = index; } } if (!amIPreDefaultTime) { temporaryLong -= _array[index]; RecordMostMemoryGain(temporaryLong - previousLong, _event); previousLong = temporaryLong; increasing = temporaryLong > 0; } _array[index] = temporaryLong; } private void TryRecordRenderMemoryGain() { if (amIPreDefaultTime && index >= 1 && index != lastRecordedRenderIndex) { lastRecordedRenderIndex = index; monoUsedRender[index] = monoUsedFixedUpdate[index] - monoUsedLateUpdate[index - 1]; } } private void RecordMostMemoryGain(long amount, EventFlags _event) { if (mostMemoryIncrease < amount) { mostMemoryIncrease = amount; mostMemoryIncreaseEvent = _event; } } private void ResetAllData() { index = 0; monoUsedEarlyUpdate = new long[10000]; monoUsedUpdate = new long[10000]; monoUsedLateUpdate = new long[10000]; monoUsedFixedUpdate = new long[10000]; monoUsedRender = new long[10000]; } private void PrintAllDataRecorded() { StringBuilder sb2 = new StringBuilder(); sb2.Append($"Memory Debugging Data results - Tracked Memory: {staticMemoryTrackType}"); sb2.Append($"\r\nMost Memory in a single step: {mostMemoryIncrease} ({mostMemoryIncreaseEvent})"); long averageMemoryChangePerStep; long totalMemoryChange; if (staticEventsToTrack.HasFlag(EventFlags.FixedUpdate)) { CalculateDataFromArray(ref sb2, EventFlags.FixedUpdate, ref monoUsedFixedUpdate); } if (staticEventsToTrack.HasFlag(EventFlags.EarlyUpdate)) { CalculateDataFromArray(ref sb2, EventFlags.EarlyUpdate, ref monoUsedEarlyUpdate); } if (staticEventsToTrack.HasFlag(EventFlags.Update)) { CalculateDataFromArray(ref sb2, EventFlags.Update, ref monoUsedUpdate); } if (staticEventsToTrack.HasFlag(EventFlags.LateUpdate)) { CalculateDataFromArray(ref sb2, EventFlags.LateUpdate, ref monoUsedLateUpdate); } if (staticEventsToTrack.HasFlag(EventFlags.Render)) { CalculateDataFromArray(ref sb2, EventFlags.Render, ref monoUsedRender); } totalMemoryChange = 0L; void CalculateDataFromArray(ref StringBuilder sb, EventFlags _event, ref long[] _array) { averageMemoryChangePerStep = 0L; totalMemoryChange = 0L; for (int i = 0; i < index; i++) { long num = _array[i]; if (i != 0) { totalMemoryChange += num; } } averageMemoryChangePerStep = totalMemoryChange / Mathf.Max(index, 1); sb.Append($"\r\n\r\n{_event}: Avg change per step {FormatLongAsText(averageMemoryChangePerStep)}. | Total Memory changed: {FormatLongAsText(totalMemoryChange)}"); } static string FormatLongAsText(long value) { if (value > 1000000000) { return $"{(float)value / 1E+09f}GB {value}"; } if (value > 1000000) { return $"{(float)value / 1000000f}MB {value}"; } return $"{(float)value / 1000f}KB ({value})"; } } } public class Utility_Event_MemoryDebugging_PostDefault : Utility_Event_MemoryDebugging { } public class Utility_Event_MemoryDebugging_PreDefault : Utility_Event_MemoryDebugging { private void Awake() { amIPreDefaultTime = true; } } public class Utility_ScreamPositionDiff : MonoBehaviour { private UnityEngine.Vector3 _prevPosition; private void OnEnable() { _prevPosition = base.transform.position; } private void FixedUpdate() { UnityEngine.Vector3 position = base.transform.position; if (!NetworkServer.active && _prevPosition != position) { _prevPosition = position; } } } [Serializable] public struct Wave { public float amplitude; public float frequency; [FormerlySerializedAs("phase")] public float cycleOffset; public float period { get { return 1f / frequency; } set { frequency = 1f / value; } } public float Evaluate(float t) { return Mathf.Sin(MathF.PI * 2f * (frequency * t + cycleOffset)) * amplitude; } } public class WeightedSelection { [Serializable] public struct ChoiceInfo { public T value; public float weight; } [SerializeField] [HideInInspector] public ChoiceInfo[] choices; [HideInInspector] [SerializeField] private int _count; [SerializeField] [HideInInspector] private float totalWeight; private const int minCapacity = 8; public int Count { get { return _count; } private set { _count = value; } } public int Capacity { get { return choices.Length; } set { if (value < 8 || value < Count) { throw new ArgumentOutOfRangeException("value"); } ChoiceInfo[] sourceArray = choices; choices = new ChoiceInfo[value]; Array.Copy(sourceArray, choices, Count); } } public WeightedSelection(int capacity = 8) { choices = new ChoiceInfo[capacity]; } public void AddChoice(T value, float weight) { AddChoice(new ChoiceInfo { value = value, weight = weight }); } public void AddChoice(ChoiceInfo choice) { if (Count == Capacity) { Capacity *= 2; } choices[Count++] = choice; totalWeight += choice.weight; } public void RemoveChoice(int choiceIndex) { if (choiceIndex < 0 || Count <= choiceIndex) { throw new ArgumentOutOfRangeException("choiceIndex"); } int i = choiceIndex; for (int num = Count - 1; i < num; i++) { choices[i] = choices[i + 1]; } choices[--Count] = default(ChoiceInfo); RecalculateTotalWeight(); } public void ModifyChoiceWeight(int choiceIndex, float newWeight) { choices[choiceIndex].weight = newWeight; RecalculateTotalWeight(); } public void Clear() { for (int i = 0; i < Count; i++) { choices[i] = default(ChoiceInfo); } Count = 0; totalWeight = 0f; } private void RecalculateTotalWeight() { totalWeight = 0f; for (int i = 0; i < Count; i++) { totalWeight += choices[i].weight; } } public T Evaluate(float normalizedIndex) { int num = EvaluateToChoiceIndex(normalizedIndex); return choices[num].value; } public int EvaluateToChoiceIndex(float normalizedIndex) { return EvaluateToChoiceIndex(normalizedIndex, null); } public int EvaluateToChoiceIndex(float normalizedIndex, int[] ignoreIndices) { if (Count == 0) { throw new InvalidOperationException("Cannot call Evaluate without available choices."); } float num = totalWeight; if (ignoreIndices != null) { foreach (int num2 in ignoreIndices) { num -= choices[num2].weight; } } float num3 = normalizedIndex * num; float num4 = 0f; for (int j = 0; j < Count; j++) { if (ignoreIndices == null || Array.IndexOf(ignoreIndices, j) == -1) { num4 += choices[j].weight; if (num3 < num4) { return j; } } } return Count - 1; } public ChoiceInfo GetChoice(int i) { return choices[i]; } } namespace SteamAPIValidator { internal static class WinCrypt { public struct BLOB { public int cbData; public IntPtr pbData; } public struct CRYPT_ALGORITHM_IDENTIFIER { public string pszObjId; private BLOB Parameters; } public struct CERT_ID { public int dwIdChoice; public BLOB IssuerSerialNumberOrKeyIdOrHashId; } public struct SIGNER_SUBJECT_INFO { public uint cbSize; public IntPtr pdwIndex; public uint dwSubjectChoice; public SubjectChoiceUnion Union1; } [StructLayout(LayoutKind.Explicit)] public struct SubjectChoiceUnion { [FieldOffset(0)] public IntPtr pSignerFileInfo; [FieldOffset(0)] public IntPtr pSignerBlobInfo; } public struct CERT_NAME_BLOB { public uint cbData; [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] public byte[] pbData; } public struct CRYPT_INTEGER_BLOB { public uint cbData; public IntPtr pbData; } public struct CRYPT_ATTR_BLOB { public uint cbData; [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] public byte[] pbData; } public struct CRYPT_ATTRIBUTE { [MarshalAs(UnmanagedType.LPStr)] public string pszObjId; public uint cValue; [MarshalAs(UnmanagedType.LPStruct)] public CRYPT_ATTR_BLOB rgValue; } public struct CMSG_SIGNER_INFO { public int dwVersion; private CERT_NAME_BLOB Issuer; private CRYPT_INTEGER_BLOB SerialNumber; private CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; private CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm; private BLOB EncryptedHash; private CRYPT_ATTRIBUTE[] AuthAttrs; private CRYPT_ATTRIBUTE[] UnauthAttrs; } public const int CRYPT_ASN_ENCODING = 1; public const int CRYPT_NDR_ENCODING = 2; public const int X509_ASN_ENCODING = 1; public const int X509_NDR_ENCODING = 2; public const int PKCS_7_ASN_ENCODING = 65536; public const int PKCS_7_NDR_ENCODING = 131072; public static UIntPtr PKCS7_SIGNER_INFO = new UIntPtr(500u); public static UIntPtr CMS_SIGNER_INFO = new UIntPtr(501u); public static string szOID_RSA_signingTime = "1.2.840.113549.1.9.5"; public static string szOID_RSA_counterSign = "1.2.840.113549.1.9.6"; public const int CMSG_TYPE_PARAM = 1; public const int CMSG_CONTENT_PARAM = 2; public const int CMSG_BARE_CONTENT_PARAM = 3; public const int CMSG_INNER_CONTENT_TYPE_PARAM = 4; public const int CMSG_SIGNER_COUNT_PARAM = 5; public const int CMSG_SIGNER_INFO_PARAM = 6; public const int CMSG_SIGNER_CERT_INFO_PARAM = 7; public const int CMSG_SIGNER_HASH_ALGORITHM_PARAM = 8; public const int CMSG_SIGNER_AUTH_ATTR_PARAM = 9; public const int CMSG_SIGNER_UNAUTH_ATTR_PARAM = 10; public const int CMSG_CERT_COUNT_PARAM = 11; public const int CMSG_CERT_PARAM = 12; public const int CMSG_CRL_COUNT_PARAM = 13; public const int CMSG_CRL_PARAM = 14; public const int CMSG_ENVELOPE_ALGORITHM_PARAM = 15; public const int CMSG_RECIPIENT_COUNT_PARAM = 17; public const int CMSG_RECIPIENT_INDEX_PARAM = 18; public const int CMSG_RECIPIENT_INFO_PARAM = 19; public const int CMSG_HASH_ALGORITHM_PARAM = 20; public const int CMSG_HASH_DATA_PARAM = 21; public const int CMSG_COMPUTED_HASH_PARAM = 22; public const int CMSG_ENCRYPT_PARAM = 26; public const int CMSG_ENCRYPTED_DIGEST = 27; public const int CMSG_ENCODED_SIGNER = 28; public const int CMSG_ENCODED_MESSAGE = 29; public const int CMSG_VERSION_PARAM = 30; public const int CMSG_ATTR_CERT_COUNT_PARAM = 31; public const int CMSG_ATTR_CERT_PARAM = 32; public const int CMSG_CMS_RECIPIENT_COUNT_PARAM = 33; public const int CMSG_CMS_RECIPIENT_INDEX_PARAM = 34; public const int CMSG_CMS_RECIPIENT_ENCRYPTED_KEY_INDEX_PARAM = 35; public const int CMSG_CMS_RECIPIENT_INFO_PARAM = 36; public const int CMSG_UNPROTECTED_ATTR_PARAM = 37; public const int CMSG_SIGNER_CERT_ID_PARAM = 38; public const int CMSG_CMS_SIGNER_INFO_PARAM = 39; public const int CERT_QUERY_OBJECT_FILE = 1; public const int CERT_QUERY_OBJECT_BLOB = 2; public const int CERT_QUERY_CONTENT_CERT = 1; public const int CERT_QUERY_CONTENT_CTL = 2; public const int CERT_QUERY_CONTENT_CRL = 3; public const int CERT_QUERY_CONTENT_SERIALIZED_STORE = 4; public const int CERT_QUERY_CONTENT_SERIALIZED_CERT = 5; public const int CERT_QUERY_CONTENT_SERIALIZED_CTL = 6; public const int CERT_QUERY_CONTENT_SERIALIZED_CRL = 7; public const int CERT_QUERY_CONTENT_PKCS7_SIGNED = 8; public const int CERT_QUERY_CONTENT_PKCS7_UNSIGNED = 9; public const int CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED = 10; public const int CERT_QUERY_CONTENT_PKCS10 = 11; public const int CERT_QUERY_CONTENT_PFX = 12; public const int CERT_QUERY_CONTENT_CERT_PAIR = 13; public const int CERT_QUERY_CONTENT_FLAG_CERT = 2; public const int CERT_QUERY_CONTENT_FLAG_CTL = 4; public const int CERT_QUERY_CONTENT_FLAG_CRL = 8; public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE = 16; public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT = 32; public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL = 64; public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL = 128; public const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED = 256; public const int CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED = 512; public const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = 1024; public const int CERT_QUERY_CONTENT_FLAG_PKCS10 = 2048; public const int CERT_QUERY_CONTENT_FLAG_PFX = 4096; public const int CERT_QUERY_CONTENT_FLAG_CERT_PAIR = 8192; public const int CERT_QUERY_CONTENT_FLAG_ALL = 16382; public const int CERT_QUERY_FORMAT_BINARY = 1; public const int CERT_QUERY_FORMAT_BASE64_ENCODED = 2; public const int CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED = 3; public const int CERT_QUERY_FORMAT_FLAG_BINARY = 2; public const int CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED = 4; public const int CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED = 8; public const int CERT_QUERY_FORMAT_FLAG_ALL = 14; [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CryptQueryObject(int dwObjectType, IntPtr pvObject, int dwExpectedContentTypeFlags, int dwExpectedFormatTypeFlags, int dwFlags, out int pdwMsgAndCertEncodingType, out int pdwContentType, out int pdwFormatType, ref IntPtr phCertStore, ref IntPtr phMsg, ref IntPtr ppvContext); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CryptMsgGetParam(IntPtr hCryptMsg, int dwParamType, int dwIndex, IntPtr pvData, ref int pcbData); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CryptMsgGetParam(IntPtr hCryptMsg, int dwParamType, int dwIndex, [In][Out] byte[] vData, ref int pcbData); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptDecodeObject(uint CertEncodingType, UIntPtr lpszStructType, byte[] pbEncoded, uint cbEncoded, uint flags, [In][Out] byte[] pvStructInfo, ref uint cbStructInfo); } public static class SteamApiValidator { private const int MAX_PATH_SIZE = 32767; [DllImport("kernel32.dll")] private static extern IntPtr LoadLibrary(string dllToLoad); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern IntPtr GetModuleHandle(string lpModuleName); [DllImport("kernel32.dll", SetLastError = true)] private static extern uint GetModuleFileName([In] IntPtr hModule, [Out] StringBuilder lpFilename, [In][MarshalAs(UnmanagedType.U4)] int nSize); public static bool IsValidSteamApiDll() { string text = (Environment.Is64BitProcess ? "steam_api64.dll" : "steam_api.dll"); IntPtr intPtr = GetModuleHandle(text); if (intPtr == IntPtr.Zero) { intPtr = LoadLibrary(text); } if (intPtr == IntPtr.Zero) { return false; } if (intPtr != IntPtr.Zero) { StringBuilder stringBuilder = new StringBuilder(32767); if (GetModuleFileName(intPtr, stringBuilder, 32767) != 0) { return CheckIfValveSigned(stringBuilder.ToString()); } } return false; } public static bool IsValidSteamClientDll() { IntPtr moduleHandle = GetModuleHandle(Environment.Is64BitProcess ? "steamclient64.dll" : "steamclient.dll"); if (moduleHandle != IntPtr.Zero) { StringBuilder stringBuilder = new StringBuilder(32767); if (GetModuleFileName(moduleHandle, stringBuilder, 32767) != 0) { return CheckIfValveSigned(stringBuilder.ToString()); } } return false; } private static bool CheckIfValveSigned(string filePath) { try { IntPtr phCertStore = IntPtr.Zero; IntPtr phMsg = IntPtr.Zero; IntPtr ppvContext = IntPtr.Zero; if (!WinCrypt.CryptQueryObject(1, Marshal.StringToHGlobalUni(filePath), 16382, 14, 0, out var _, out var pdwContentType, out var _, ref phCertStore, ref phMsg, ref ppvContext)) { return false; } return pdwContentType == 10; } catch { return false; } } } } namespace RewiredConsts { public static class Action { [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Move Horizontal")] public const int MoveHorizontal = 0; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Move Vertical")] public const int MoveVertical = 1; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Aim Horizontal Mouse")] public const int AimHorizontalMouse = 2; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Aim Vertical Mouse")] public const int AimVerticalMouse = 3; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Aim Horizontal Stick")] public const int AimHorizontalStick = 16; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Aim Vertical Stick")] public const int AimVerticalStick = 17; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Jump")] public const int Jump = 4; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Sprint")] public const int Sprint = 18; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Interact")] public const int Interact = 5; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Activate Equipment")] public const int Equipment = 6; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Primary Skill")] public const int PrimarySkill = 7; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Secondary Skill")] public const int SecondarySkill = 8; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Utility Skill")] public const int UtilitySkill = 9; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Special Skill")] public const int SpecialSkill = 10; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Start")] public const int Start = 11; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Info")] public const int Info = 19; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UIHorizontal")] public const int UIHorizontal = 12; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UIVertical")] public const int UIVertical = 13; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmit")] public const int UISubmit = 14; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UICancel")] public const int UICancel = 15; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UI Left Mouse Button")] public const int UILMB = 20; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UI Right Mouse Button")] public const int UIRMB = 21; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UI Middle Mouse Button")] public const int UIMMB = 22; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UICursorX")] public const int UICursorX = 23; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UICursorY")] public const int UICursorY = 24; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UIScrollWheel")] public const int UIScrollWheel = 26; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Pause")] public const int Pause = 25; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "Ping")] public const int Ping = 28; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UITabLeft")] public const int UITabLeft = 29; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UITabRight")] public const int UITabRight = 30; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmitAlt")] public const int UISubmitAlt = 31; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmenuLeft")] public const int UISubmenuLeft = 32; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmenuRight")] public const int UISubmenuRight = 33; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmenuUp")] public const int UISubmenuUp = 34; [ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmenuDown")] public const int UISubmenuDown = 35; } public static class Category { public const int Default = 0; public const int UI = 2; } public static class Layout { public static class Joystick { public const int Default = 0; public const int Default_JP = 1; } public static class Keyboard { public const int Default = 0; } public static class Mouse { public const int Default = 0; } public static class CustomController { public const int Default = 0; } } public static class Player { [PlayerIdFieldInfo(friendlyName = "System")] public const int System = 9999999; [PlayerIdFieldInfo(friendlyName = "PlayerMain")] public const int PlayerMain = 0; [PlayerIdFieldInfo(friendlyName = "Player1")] public const int Player1 = 1; [PlayerIdFieldInfo(friendlyName = "Player2")] public const int Player2 = 2; [PlayerIdFieldInfo(friendlyName = "Player3")] public const int Player3 = 3; [PlayerIdFieldInfo(friendlyName = "Player4")] public const int Player4 = 4; [PlayerIdFieldInfo(friendlyName = "Player5")] public const int Player5 = 5; } public static class CustomController { } } namespace UDPHelperSpace { public class UDPData { public byte packageNumber = 2; public byte[] data; public int numBytes; public int channelId; public byte error; public UDPData() { } public UDPData(byte packageNumber, byte[] data, int numBytes, int channelId, byte error) { this.packageNumber = packageNumber; this.packageNumber = data[0]; this.data = data; this.numBytes = numBytes; this.channelId = channelId; this.error = error; } } public class UDPReceive { public int packageNumber; public List data = new List(); public UDPReceiveWork Work = new UDPReceiveWork(); public byte[] Receive(byte[] bytes, int length) { if (bytes == null || bytes.Length < 1 || (bytes.Length == 1 && bytes[0] == 0)) { return bytes; } byte b = 0; byte ñonfirmationByte = 0; byte packetLoss = 0; byte temp = 0; byte[] array = Work.GetData(bytes, out b, out ñonfirmationByte, out packetLoss, out temp, length); string.Concat(string.Concat(string.Concat("_packageNumber: " + b + " ", "ñonfirmationByte: ", ñonfirmationByte.ToString(), " "), "packetLoss: ", packetLoss.ToString(), "\n"), "total bytes: ", bytes.Length.ToString(), "\n"); if (packageNumber == 0) { packageNumber = b; ConfirmPackage(b); return array; } if (length == 4) { UDPHelper.Sender.RemoveFromQueue(array[2]); return null; } if (packageNumber == b) { ConfirmPackage(b); return null; } if (b == packageNumber + 1 || (b == 1 && packageNumber == 100)) { packageNumber = b; ConfirmPackage(b); } return array; } public void ConfirmPackage(byte confirmPackageNumber) { byte[] arg = new byte[4] { 1, 0, 0, confirmPackageNumber }; UDPHelper.Sender.SendCall?.Invoke(arg, 4, 0, 0); } } public class UDPReceiveWork { public byte[] GetData(byte[] bytes, out byte packageNumber, out byte ñonfirmationByte, out byte packetLoss, out byte temp2, int length) { byte[] array = new byte[bytes.Length]; Array.Copy(bytes, array, bytes.Length); ñonfirmationByte = 0; packetLoss = 0; temp2 = 0; packageNumber = bytes[0]; return RemoveDataReceive(array); } private byte[] RemoveDataReceive(byte[] bytes) { return RemoveBytes(bytes); } private byte[] RemoveBytes(byte[] bytes, int countRemove = 1) { return bytes = bytes.Skip(1).ToArray(); } } public class UDPSender { public byte packageNumber = 1; public int maxListCount = 90; public List data = new List(); public UDPSenderWork Work = new UDPSenderWork(); public Action SendCall; public void Send(byte[] bytes, int numBytes, int channelId, byte error) { data.Add(new UDPData(packageNumber, bytes, numBytes, channelId, error)); } public byte[] Send(byte[] bytes, ref int numBytes) { if (bytes == null || bytes.Length < 1 || (bytes.Length == 1 && bytes[0] == 0)) { return bytes; } byte[] result = Work.AddDataSend(bytes, packageNumber); numBytes++; packageNumber++; if (packageNumber > 100) { packageNumber = 1; } return result; } public byte[] SendReturne(byte[] bytes, int numBytes, int channelId, byte error) { if (bytes == null || bytes.Length < 1 || (bytes.Length == 1 && bytes[0] == 0)) { return bytes; } return new UDPData(packageNumber, bytes, numBytes, channelId, error).data; } public void SendAction() { if (data.Count > 0) { UDPData uDPData = data[data.Count - 1]; byte[] arg = uDPData.data; UDPHelper.Sender.SendCall?.Invoke(arg, uDPData.numBytes, uDPData.channelId, uDPData.error); } } public void RemoveFromQueue(byte _packageNumber) { data = data.Where((UDPData x) => x.packageNumber != _packageNumber).ToList(); } } public class UDPSenderWork { public byte[] AddDataSend(byte[] bytes, int packageNumber) { if (bytes == null || bytes.Length < 4) { return bytes; } bytes = AddByteToArray(bytes, packageNumber); return bytes; } private byte[] AddByteToArray(byte[] bArray, int newByte) { return AddByteToArray(bArray, (byte)newByte); } public byte[] AddByteToArray(byte[] bArray, byte newByte) { byte[] array = new byte[bArray.Length + 1]; bArray.CopyTo(array, 1); array[0] = newByte; return array; } } } namespace Assets.RoR2.Scripts.Platform { [CreateAssetMenu(menuName = "RoR2/ActivityData")] public class ActivityData : ScriptableObject { [SerializeField] private List activities; public BaseActivity LookupActivityByID(string activityID) { foreach (BaseActivity activity in activities) { if (activity.ActivityID == activityID) { return activity; } } return null; } public List CompareActivityCriteria(BaseActivitySelector activitySelector) { List list = new List(); foreach (BaseActivity activity in activities) { if (activitySelector.IsCompatibleWith(activity)) { list.Add(activity); } } return list; } } public class BaseActivitySelector { public BaseActivity.ActivityGameType activityGameType = BaseActivity.ActivityGameType.Any; public BaseActivity.ActivityGameMode activityGameMode = BaseActivity.ActivityGameMode.Any; public BaseActivity.ActivitySurvivor activitySurvivor = BaseActivity.ActivitySurvivor.Any; public string activityAchievementID = ""; public bool IsCompatibleWith(BaseActivity activity) { if ((activity.GameType == BaseActivity.ActivityGameType.Any || activityGameType == BaseActivity.ActivityGameType.Any || activity.GameType == activityGameType) && (activity.GameMode == BaseActivity.ActivityGameMode.Any || activityGameMode == BaseActivity.ActivityGameMode.Any || activity.GameMode == activityGameMode) && (activity.Survivor == BaseActivity.ActivitySurvivor.Any || activitySurvivor == BaseActivity.ActivitySurvivor.Any || activity.Survivor == activitySurvivor)) { if (activity.AchievementID.Length != 0 && activityAchievementID.Length != 0) { return activity.AchievementID.CompareTo(activityAchievementID) == 0; } return true; } return false; } } public class ActivityManager { protected ActivityData LoadedActivityData; protected Dictionary InProgressActivities = new Dictionary(); protected Dictionary AvailableActivities = new Dictionary(); protected BaseActivity ActivityToProcess; public bool IsInitialized { get; private set; } public BaseActivity.ActivityGameMode CurrentGameMode { get { GameModeIndex gameModeIndex = GameModeIndex.Invalid; if (null != PreGameController.instance) { gameModeIndex = PreGameController.instance.gameModeIndex; } if (null != Run.instance) { gameModeIndex = Run.instance.gameModeIndex; } if (GameModeIndex.Invalid != gameModeIndex) { if (gameModeIndex == GameModeCatalog.FindGameModeIndex("ClassicRun")) { return BaseActivity.ActivityGameMode.ClassicRun; } if (gameModeIndex == GameModeCatalog.FindGameModeIndex("EclipseRun")) { return BaseActivity.ActivityGameMode.Eclipse; } if (gameModeIndex == GameModeCatalog.FindGameModeIndex("InfiniteTowerRun")) { return BaseActivity.ActivityGameMode.InfiniteTower; } if (gameModeIndex == GameModeCatalog.FindGameModeIndex("WeeklyRun")) { return BaseActivity.ActivityGameMode.WeeklyRun; } } UnityEngine.Debug.LogError("ActivityManager::CurrentGameMode property unable to determine GameMode."); return BaseActivity.ActivityGameMode.Any; } } public BaseActivity.ActivityGameType CurrentGameType { get { ReadOnlyCollection readOnlyLocalPlayersList = NetworkUser.readOnlyLocalPlayersList; if (readOnlyLocalPlayersList != null) { if (readOnlyLocalPlayersList.Count == 1) { return BaseActivity.ActivityGameType.SinglePlayer; } if (readOnlyLocalPlayersList.Count > 1) { return BaseActivity.ActivityGameType.MultiPlayer; } } UnityEngine.Debug.LogError("ActivityManager::CurrentGameType property unable to determine GameType."); return BaseActivity.ActivityGameType.Any; } } public BaseActivity.ActivitySurvivor CurrentSurvivor { get { UserProfile userProfile = LocalUserManager.GetFirstLocalUser()?.userProfile; if (userProfile != null) { SurvivorDef survivorDef = userProfile?.GetSurvivorPreference(); if (null != survivorDef) { BaseActivity.ActivitySurvivor result = BaseActivity.ActivitySurvivor.Any; if (Enum.TryParse(survivorDef.cachedName, out result)) { return result; } } } UnityEngine.Debug.LogError("ActivityManager::CurrentSurvivor property unable to determine survivor."); return BaseActivity.ActivitySurvivor.Any; } } private bool ValidCurrentSelectorExists { get { if ((null != PreGameController.instance || null != Run.instance) && LocalUserManager.GetFirstLocalUser()?.userProfile != null) { if (NetworkUser.readOnlyLocalPlayersList != null) { return NetworkUser.readOnlyLocalPlayersList.Count >= 0; } return false; } return false; } } public BaseActivitySelector CurrentActivitySelector { get { if (ValidCurrentSelectorExists) { return new BaseActivitySelector { activitySurvivor = CurrentSurvivor, activityGameMode = CurrentGameMode, activityGameType = CurrentGameType }; } return null; } } public virtual void Initialize() { MainMenuController.OnPreMainMenuInitialized -= OnPreMainMenuInitializedCallback; MainMenuController.OnPreMainMenuInitialized += OnPreMainMenuInitializedCallback; LocalUserManager.onUserSignIn -= OnLocalUserSignIn; LocalUserManager.onUserSignIn += OnLocalUserSignIn; BaseUserEntitlementTracker.OnAllUserEntitlementsUpdated = (Action)Delegate.Remove(BaseUserEntitlementTracker.OnAllUserEntitlementsUpdated, new Action(OnEntitlementsChangedCallback)); BaseUserEntitlementTracker.OnAllUserEntitlementsUpdated = (Action)Delegate.Combine(BaseUserEntitlementTracker.OnAllUserEntitlementsUpdated, new Action(OnEntitlementsChangedCallback)); Run.onRunStartGlobal += OnRunStartGlobal; Run.onClientGameOverGlobal += OnClientGameOverGlobal; } protected virtual void OnPreMainMenuReInitializedCallback() { AbandonInProgressActivities(); } protected virtual void OnLocalUserSignIn(LocalUser localUser) { if (localUser.userProfile != null && localUser.userProfile == LocalUserManager.GetFirstLocalUser().userProfile) { RebuildActivityAvailabilityForUser(localUser); IsInitialized = true; } } protected virtual void AbandonInProgressActivities() { BaseActivitySelector activitySelector = new BaseActivitySelector(); PlatformSystems.activityManager.TryToAbandonActivity(activitySelector); } protected virtual void OnClientGameOverGlobal(Run run, RunReport runReport) { if (runReport.gameEnding == RoR2Content.GameEndings.StandardLoss) { if (ValidCurrentSelectorExists) { PlatformSystems.activityManager.TryToFailActivity(PlatformSystems.activityManager.CurrentActivitySelector); } else { UnityEngine.Debug.LogError("ActivityManager::OnClientGameOverGlobal - missing context to fail activities activities on Game Over."); } } } protected virtual void OnRunStartGlobal(Run run) { if (ValidCurrentSelectorExists) { TryToStartActivity(CurrentActivitySelector); } else { UnityEngine.Debug.LogError("ActivityManager::OnRunStartGlobal - missing context to start activities on Run start."); } } protected virtual void OnPreMainMenuInitializedCallback() { MainMenuController.OnPreMainMenuInitialized -= OnPreMainMenuInitializedCallback; AsyncOperationHandle handle = Addressables.LoadAssetAsync("RoR2/Base/Common/ActivityData.asset"); ActivityData loadedActivityData = handle.WaitForCompletion(); LoadedActivityData = loadedActivityData; Addressables.Release(handle); if (GameIntentReceiver.GameIntentAdapter.hasPendingGameIntent) { CreateStartupActivity(); } GameIntentReceiver.GameIntentAdapter.OnGameIntentReceivedEvent -= GameIntentReceiverListener; GameIntentReceiver.GameIntentAdapter.OnGameIntentReceivedEvent += GameIntentReceiverListener; if (ActivityToProcess != null) { RoR2Application.instance.StartCoroutine(ProcessGameActivity()); GameIntentReceiver.GameIntentAdapter.ClearPendingGameIntent(); } MainMenuController.OnPreMainMenuInitialized += OnPreMainMenuReInitializedCallback; } protected virtual void CreateStartupActivity() { } public virtual void GameIntentReceiverListener(GameIntentAdapter.EventResponse eventResponseObject) { eventResponseObject.EventHasBeenHandled(eventHandled: false); } public virtual void TryToStartActivity(BaseActivitySelector activitySelector) { } public virtual void TryToCompleteActivity(BaseActivitySelector activitySelector, bool markUnavailableOnComplete = true, bool applyAsDelta = true) { } public virtual void TryToAbandonActivity(BaseActivitySelector activitySelector) { } public virtual void TryToFailActivity(BaseActivitySelector activitySelector) { } public virtual void TryToSetActivityAvailability(BaseActivitySelector activitySelector, bool newAvailability, bool applyAsDelta = true, bool sendImmediate = true) { } public virtual void FlushAvailabilityUpdates(bool applyAsDelta) { } public virtual bool ShouldSkipGameIntentHandler(BaseActivity activity) { return CurrentActivitySelector?.IsCompatibleWith(activity) ?? false; } public virtual bool IsActivityAvailable(BaseActivity baseActivity) { return AvailableActivities.ContainsKey(baseActivity.ActivityID); } protected IEnumerator ProcessGameActivity() { if (!IsInitialized) { yield return new WaitForEndOfFrame(); } BaseActivity gameActivity = LoadedActivityData.LookupActivityByID(ActivityToProcess.ActivityID); if (gameActivity == null) { UnityEngine.Debug.LogError("ActivityManager::ProcessGameActivity() was unable to find data for a Game Activity!"); yield break; } if (!IsActivityAvailable(gameActivity)) { UnityEngine.Debug.LogError("ActivityManager::ProcessGameActivity() user attempted to launch an unavailable activity!"); yield break; } if (!RoR2Application.IsMainScene) { if (ShouldSkipGameIntentHandler(gameActivity)) { yield break; } global::RoR2.Console.instance.SubmitCmd(null, "transition_command \"disconnect\";"); yield return new WaitForSeconds(1f); global::RoR2.Console.instance.SubmitCmd(null, "transition_command \"set_scene title\";"); while (!RoR2Application.IsMainScene) { yield return new WaitForEndOfFrame(); } } while (!RoR2Application.IsMainMenuInitialized) { yield return new WaitForEndOfFrame(); } string gameModeStr; if (gameActivity.GameMode == BaseActivity.ActivityGameMode.ClassicRun || gameActivity.GameMode == BaseActivity.ActivityGameMode.Any) { gameModeStr = "ClassicRun"; } else if (gameActivity.GameMode == BaseActivity.ActivityGameMode.WeeklyRun) { gameModeStr = "WeeklyRun"; } else if (gameActivity.GameMode == BaseActivity.ActivityGameMode.Eclipse) { gameModeStr = "EclipseRun"; } else if (gameActivity.GameMode == BaseActivity.ActivityGameMode.InfiniteTower) { gameModeStr = "InfiniteTowerRun"; } else { UnityEngine.Debug.LogError("ActivityManager::ProcessGameActivity() - Trying to transition to gamemode with unhandled BaseActivity.ActivityGameMode. Transitioning to Classic Run..."); gameModeStr = "ClassicRun"; } while (TransitionCommand.requestPending) { yield return new WaitForEndOfFrame(); } global::RoR2.Console.instance.SubmitCmd(null, "transition_command \"gamemode " + gameModeStr + "; host 0;\""); string text = gameActivity.Survivor.ToString(); if (string.Compare("Any", text) != 0) { SurvivorIndex survivorIndex = SurvivorCatalog.FindSurvivorIndex(text); UserProfile userProfile = LocalUserManager.GetFirstLocalUser()?.userProfile; if (userProfile.HasSurvivorUnlocked(survivorIndex)) { SurvivorDef survivorDef = SurvivorCatalog.GetSurvivorDef(survivorIndex); userProfile.SetSurvivorPreference(survivorDef); } } yield return new WaitForSeconds(2f); RoR2Application.SetMapsEnabled(enabled: true); } public void RebuildActivityAvailabilityForUser(LocalUser localUser) { if (LoadedActivityData == null) { return; } UserProfile userProfile = localUser.userProfile; BaseActivitySelector baseActivitySelector = new BaseActivitySelector(); List list = LoadedActivityData.CompareActivityCriteria(baseActivitySelector); foreach (BaseActivity item in list) { if (item.AchievementID.Length == 0) { continue; } baseActivitySelector.activityAchievementID = item.AchievementID; bool flag = userProfile.CanSeeAchievement(item.AchievementID); bool flag2 = userProfile.HasAchievement(item.AchievementID); if (item.RequiredEntitlementID.Length > 0) { if (EntitlementCatalog.FindEntitlementIndex(item.RequiredEntitlementID) == EntitlementIndex.None) { UnityEngine.Debug.LogError("ActivityManager::RebuildAvailabilityForUser - Activity requires entitlement (" + item.RequiredEntitlementID + ") that is not defined in the EntitlementCatalog. (probably a typo)"); } else { EntitlementDef entitlementDef = EntitlementCatalog.GetEntitlementDef(EntitlementCatalog.FindEntitlementIndex(item.RequiredEntitlementID)); if (!EntitlementManager.localUserEntitlementTracker.UserHasEntitlement(localUser, entitlementDef)) { flag = false; } } } TryToSetActivityAvailability(baseActivitySelector, flag && !flag2, applyAsDelta: false, sendImmediate: false); } if (list.Count > 0) { FlushAvailabilityUpdates(applyAsDelta: false); } } private void OnEntitlementsChangedCallback() { RebuildActivityAvailabilityForUser(LocalUserManager.GetFirstLocalUser()); } } [Serializable] public class BaseActivity { public enum ActivityGameType : uint { SinglePlayer, MultiPlayer, Any } public enum ActivityGameMode : uint { ClassicRun, Eclipse, InfiniteTower, WeeklyRun, Any } public enum ActivitySurvivor : uint { Bandit2, Captain, Commando, Croco, Engi, Heretic, Huntress, Loader, Mage, Merc, Toolbot, Treebot, Railgunner, Any } [SerializeField] protected ActivityGameType _gameType; [SerializeField] protected ActivityGameMode _gameMode; [SerializeField] protected ActivitySurvivor _survivor; [SerializeField] protected string _activityID; [SerializeField] protected string _achievementID; [SerializeField] protected string _requiredEntitlementID; public ActivityGameType GameType => _gameType; public ActivityGameMode GameMode => _gameMode; public ActivitySurvivor Survivor => _survivor; public string ActivityID => _activityID; public string AchievementID => _achievementID; public string RequiredEntitlementID => _requiredEntitlementID; public virtual void StartActivity() { UnityEngine.Debug.LogError("BaseActivity::StartActivity() invoked!"); } public virtual void CompleteActivity() { UnityEngine.Debug.LogError("BaseActivity::CompleteActivity() invoked!"); } public virtual void AbandonActivity() { UnityEngine.Debug.LogError("BaseActivity::AbandonActivity() invoked!"); } public virtual void FailActivity() { UnityEngine.Debug.LogError("BaseActivity::FailActivity() invoked!"); } } public class GameIntentAdapter { public class EventResponse : EventArgs { public bool wasEventHandledByAnySystem { get; private set; } public void EventHasBeenHandled(bool eventHandled) { wasEventHandledByAnySystem |= eventHandled; } } public virtual bool hasPendingGameIntent => false; public event Action OnGameIntentReceivedEvent; public virtual void Initialize() { } public virtual void ClearPendingGameIntent() { } protected void FireGameIntentReceived() { EventResponse eventResponse = new EventResponse(); this.OnGameIntentReceivedEvent?.Invoke(eventResponse); if (eventResponse.wasEventHandledByAnySystem) { ClearPendingGameIntent(); } } } public static class GameIntentReceiver { public static GameIntentAdapter GameIntentAdapter { get; private set; } = new GameIntentAdapter(); public static void Initialize() { GameIntentAdapter.Initialize(); } } } namespace Assets.RoR2.Scripts.Platform.PS5 { public class OnScreenLog : MonoBehaviour { } } namespace Optimization { public static class WanderCulling { public const float wanderTimeBeforeCull = 15f; public const float wanderResetTime = 7.5f; public const float minLifeTime = 20f; public const float wanderPlayerCheckRadius = 75f; public const int minEnemyCountBeforeCull = 10; public const int importanceThreshold = 3; } } namespace UnityEngine.Rendering.PostProcessing { [Serializable] [PostProcess(typeof(HopooSSRRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/Hopoo SSR", true)] public sealed class HopooSSR : PostProcessEffectSettings { [Tooltip("Choose a quality preset, or use \"Custom\" to fine tune it. Don't use a preset higher than \"Medium\" if you care about performances on consoles.")] public ScreenSpaceReflectionPresetParameter preset = new ScreenSpaceReflectionPresetParameter { value = ScreenSpaceReflectionPreset.Medium }; [Tooltip("Maximum iteration count.")] [Range(0f, 256f)] public IntParameter maximumIterationCount = new IntParameter { value = 16 }; [Tooltip("Changes the size of the SSR buffer. Downsample it to maximize performances or supersample it to get slow but higher quality results.")] public ScreenSpaceReflectionResolutionParameter resolution = new ScreenSpaceReflectionResolutionParameter { value = ScreenSpaceReflectionResolution.Downsampled }; [Tooltip("Ray thickness. Lower values are more expensive but allow the effect to detect smaller details.")] [Range(1f, 64f)] public FloatParameter thickness = new FloatParameter { value = 8f }; [Tooltip("Maximum distance to traverse after which it will stop drawing reflections.")] public FloatParameter maximumMarchDistance = new FloatParameter { value = 100f }; [Range(0f, 1f)] [Tooltip("Fades reflections close to the near planes.")] public FloatParameter distanceFade = new FloatParameter { value = 0.5f }; [Range(0f, 1f)] [Tooltip("Fades reflections close to the screen edges.")] public FloatParameter vignette = new FloatParameter { value = 0.5f }; public override bool IsEnabledAndSupported(PostProcessRenderContext context) { if ((bool)enabled && context.camera.actualRenderingPath == RenderingPath.DeferredShading && SystemInfo.supportsMotionVectors && SystemInfo.supportsComputeShaders && SystemInfo.copyTextureSupport > CopyTextureSupport.None && (bool)context.resources.shaders.screenSpaceReflections && context.resources.shaders.screenSpaceReflections.isSupported) { return context.resources.computeShaders.gaussianDownsample; } return false; } } public sealed class HopooSSRRenderer : PostProcessEffectRenderer { private class QualityPreset { public int maximumIterationCount; public float thickness; public ScreenSpaceReflectionResolution downsampling; } private enum Pass { Test, Resolve, Reproject, Composite } private RenderTexture m_Resolve; private RenderTexture m_History; private int[] m_MipIDs; private readonly QualityPreset[] m_Presets = new QualityPreset[7] { new QualityPreset { maximumIterationCount = 10, thickness = 32f, downsampling = ScreenSpaceReflectionResolution.Downsampled }, new QualityPreset { maximumIterationCount = 16, thickness = 32f, downsampling = ScreenSpaceReflectionResolution.Downsampled }, new QualityPreset { maximumIterationCount = 32, thickness = 16f, downsampling = ScreenSpaceReflectionResolution.Downsampled }, new QualityPreset { maximumIterationCount = 48, thickness = 8f, downsampling = ScreenSpaceReflectionResolution.Downsampled }, new QualityPreset { maximumIterationCount = 16, thickness = 32f, downsampling = ScreenSpaceReflectionResolution.FullSize }, new QualityPreset { maximumIterationCount = 48, thickness = 16f, downsampling = ScreenSpaceReflectionResolution.FullSize }, new QualityPreset { maximumIterationCount = 128, thickness = 12f, downsampling = ScreenSpaceReflectionResolution.Supersampled } }; public override DepthTextureMode GetCameraFlags() { return DepthTextureMode.Depth | DepthTextureMode.MotionVectors; } internal void CheckRT(ref RenderTexture rt, int width, int height, RenderTextureFormat format, FilterMode filterMode, bool useMipMap) { if (rt == null || !rt.IsCreated() || rt.width != width || rt.height != height || rt.format != format) { if (rt != null) { rt.Release(); } rt = new RenderTexture(width, height, 0, format) { filterMode = filterMode, useMipMap = useMipMap, autoGenerateMips = false, hideFlags = HideFlags.HideAndDontSave }; rt.Create(); } } public override void Render(PostProcessRenderContext context) { CommandBuffer command = context.command; command.BeginSample("Screen-space Reflections"); if (base.settings.preset.value != ScreenSpaceReflectionPreset.Custom) { int value = (int)base.settings.preset.value; base.settings.maximumIterationCount.value = m_Presets[value].maximumIterationCount; base.settings.thickness.value = m_Presets[value].thickness; base.settings.resolution.value = m_Presets[value].downsampling; } base.settings.maximumMarchDistance.value = Mathf.Max(0f, base.settings.maximumMarchDistance.value); int num = Mathf.ClosestPowerOfTwo(Mathf.Min(context.width, context.height)); if (base.settings.resolution.value == ScreenSpaceReflectionResolution.Downsampled) { num >>= 1; } else if (base.settings.resolution.value == ScreenSpaceReflectionResolution.Supersampled) { num <<= 1; } int a = Mathf.FloorToInt(Mathf.Log(num, 2f) - 3f); a = Mathf.Min(a, 12); CheckRT(ref m_Resolve, num, num, context.sourceFormat, FilterMode.Trilinear, useMipMap: true); Texture2D texture2D = context.resources.blueNoise256[0]; PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcessing/HopooSSR")); propertySheet.properties.SetTexture(Shader.PropertyToID("_Noise"), texture2D); Matrix4x4 value2 = default(Matrix4x4); value2.SetRow(0, new Vector4((float)num * 0.5f, 0f, 0f, (float)num * 0.5f)); value2.SetRow(1, new Vector4(0f, (float)num * 0.5f, 0f, (float)num * 0.5f)); value2.SetRow(2, new Vector4(0f, 0f, 1f, 0f)); value2.SetRow(3, new Vector4(0f, 0f, 0f, 1f)); Matrix4x4 gPUProjectionMatrix = GL.GetGPUProjectionMatrix(context.camera.projectionMatrix, renderIntoTexture: false); value2 *= gPUProjectionMatrix; propertySheet.properties.SetMatrix(Shader.PropertyToID("_ViewMatrix"), context.camera.worldToCameraMatrix); propertySheet.properties.SetMatrix(Shader.PropertyToID("_InverseViewMatrix"), context.camera.worldToCameraMatrix.inverse); propertySheet.properties.SetMatrix(Shader.PropertyToID("_InverseProjectionMatrix"), gPUProjectionMatrix.inverse); propertySheet.properties.SetMatrix(Shader.PropertyToID("_ScreenSpaceProjectionMatrix"), value2); propertySheet.properties.SetVector(Shader.PropertyToID("_Params"), new Vector4(base.settings.vignette.value, base.settings.distanceFade.value, base.settings.maximumMarchDistance.value, a)); propertySheet.properties.SetVector(Shader.PropertyToID("_Params2"), new Vector4((float)context.width / (float)context.height, (float)num / (float)texture2D.width, base.settings.thickness.value, base.settings.maximumIterationCount.value)); command.GetTemporaryRT(Shader.PropertyToID("_Test"), num, num, 0, FilterMode.Point, context.sourceFormat); command.BlitFullscreenTriangle(context.source, Shader.PropertyToID("_Test"), propertySheet, 0); if (context.isSceneView) { command.BlitFullscreenTriangle(context.source, m_Resolve, propertySheet, 1); } else { CheckRT(ref m_History, num, num, context.sourceFormat, FilterMode.Bilinear, useMipMap: false); if (m_ResetHistory) { context.command.BlitFullscreenTriangle(context.source, m_History); m_ResetHistory = false; } command.GetTemporaryRT(Shader.PropertyToID("_SSRResolveTemp"), num, num, 0, FilterMode.Bilinear, context.sourceFormat); command.BlitFullscreenTriangle(context.source, Shader.PropertyToID("_SSRResolveTemp"), propertySheet, 1); propertySheet.properties.SetTexture(Shader.PropertyToID("_History"), m_History); command.BlitFullscreenTriangle(Shader.PropertyToID("_SSRResolveTemp"), m_Resolve, propertySheet, 2); command.CopyTexture(m_Resolve, 0, 0, m_History, 0, 0); command.ReleaseTemporaryRT(Shader.PropertyToID("_SSRResolveTemp")); } command.ReleaseTemporaryRT(Shader.PropertyToID("_Test")); if (m_MipIDs == null || m_MipIDs.Length == 0) { m_MipIDs = new int[12]; for (int i = 0; i < 12; i++) { m_MipIDs[i] = Shader.PropertyToID("_SSRGaussianMip" + i); } } ComputeShader gaussianDownsample = context.resources.computeShaders.gaussianDownsample; int kernelIndex = gaussianDownsample.FindKernel("KMain"); RenderTargetIdentifier rt = new RenderTargetIdentifier(m_Resolve); for (int j = 0; j < a; j++) { num >>= 1; command.GetTemporaryRT(m_MipIDs[j], num, num, 0, FilterMode.Bilinear, context.sourceFormat, RenderTextureReadWrite.Default, 1, enableRandomWrite: true); command.SetComputeTextureParam(gaussianDownsample, kernelIndex, "_Source", rt); command.SetComputeTextureParam(gaussianDownsample, kernelIndex, "_Result", m_MipIDs[j]); command.SetComputeVectorParam(gaussianDownsample, "_Size", new Vector4(num, num, 1f / (float)num, 1f / (float)num)); command.DispatchCompute(gaussianDownsample, kernelIndex, num / 8, num / 8, 1); command.CopyTexture(m_MipIDs[j], 0, 0, m_Resolve, 0, j + 1); rt = m_MipIDs[j]; } for (int k = 0; k < a; k++) { command.ReleaseTemporaryRT(m_MipIDs[k]); } propertySheet.properties.SetTexture(Shader.PropertyToID("_Resolve"), m_Resolve); command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 3); command.EndSample("Screen-space Reflections"); } public override void Release() { RuntimeUtilities.Destroy(m_Resolve); RuntimeUtilities.Destroy(m_History); m_Resolve = null; m_History = null; } } } namespace EntityStates { public abstract class AimThrowableBase : BaseSkillState { private struct CalculateArcPointsJob : IJobParallelFor, IDisposable { [ReadOnly] private UnityEngine.Vector3 origin; [ReadOnly] private UnityEngine.Vector3 velocity; [ReadOnly] private float indexMultiplier; [ReadOnly] private float gravity; [WriteOnly] public NativeArray outputPositions; public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 velocity, float totalTravelTime, int positionCount, float gravity) { this.origin = origin; this.velocity = velocity; if (outputPositions.Length != positionCount) { if (outputPositions.IsCreated) { outputPositions.Dispose(); } outputPositions = new NativeArray(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); } indexMultiplier = totalTravelTime / (float)(positionCount - 1); this.gravity = gravity; } public void Dispose() { if (outputPositions.IsCreated) { outputPositions.Dispose(); } } public void Execute(int index) { float t = (float)index * indexMultiplier; outputPositions[index] = Trajectory.CalculatePositionAtTime(origin, velocity, t, gravity); } } protected struct TrajectoryInfo { public Ray finalRay; public UnityEngine.Vector3 hitPoint; public UnityEngine.Vector3 hitNormal; public float travelTime; public float speedOverride; } [SerializeField] public float maxDistance; [SerializeField] public float rayRadius; [SerializeField] public GameObject arcVisualizerPrefab; [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject endpointVisualizerPrefab; [SerializeField] public float endpointVisualizerRadiusScale; [SerializeField] public bool setFuse; [SerializeField] public float damageCoefficient; [SerializeField] public float baseMinimumDuration; protected LineRenderer arcVisualizerLineRenderer; protected Transform endpointVisualizerTransform; protected float projectileBaseSpeed; protected float detonationRadius; protected float minimumDuration; protected bool useGravity; private CalculateArcPointsJob calculateArcPointsJob; private JobHandle calculateArcPointsJobHandle; private UnityEngine.Vector3[] pointsBuffer = Array.Empty(); private Action completeArcPointsVisualizerJobMethod; protected TrajectoryInfo currentTrajectoryInfo; public override void OnEnter() { base.OnEnter(); if ((bool)arcVisualizerPrefab) { arcVisualizerLineRenderer = UnityEngine.Object.Instantiate(arcVisualizerPrefab, base.transform.position, UnityEngine.Quaternion.identity).GetComponent(); calculateArcPointsJob = default(CalculateArcPointsJob); completeArcPointsVisualizerJobMethod = CompleteArcVisualizerJob; RoR2Application.onLateUpdate += completeArcPointsVisualizerJobMethod; } if ((bool)endpointVisualizerPrefab) { endpointVisualizerTransform = UnityEngine.Object.Instantiate(endpointVisualizerPrefab, base.transform.position, UnityEngine.Quaternion.identity).transform; } if ((bool)base.characterBody) { base.characterBody.hideCrosshair = true; } ProjectileSimple component = projectilePrefab.GetComponent(); if ((bool)component) { projectileBaseSpeed = component.velocity; } Rigidbody component2 = projectilePrefab.GetComponent(); if ((bool)component2) { useGravity = component2.useGravity; } minimumDuration = baseMinimumDuration / attackSpeedStat; ProjectileImpactExplosion component3 = projectilePrefab.GetComponent(); if ((bool)component3) { detonationRadius = component3.blastRadius; if ((bool)endpointVisualizerTransform) { endpointVisualizerTransform.localScale = new UnityEngine.Vector3(detonationRadius, detonationRadius, detonationRadius); } } UpdateVisualizers(currentTrajectoryInfo); SceneCamera.onSceneCameraPreRender += OnPreRenderSceneCam; } public override void OnExit() { SceneCamera.onSceneCameraPreRender -= OnPreRenderSceneCam; if (!outer.destroying) { if (base.isAuthority) { FireProjectile(); } OnProjectileFiredLocal(); } if ((bool)base.characterBody) { base.characterBody.hideCrosshair = false; } calculateArcPointsJobHandle.Complete(); if ((bool)arcVisualizerLineRenderer) { EntityState.Destroy(arcVisualizerLineRenderer.gameObject); arcVisualizerLineRenderer = null; } if (completeArcPointsVisualizerJobMethod != null) { RoR2Application.onLateUpdate -= completeArcPointsVisualizerJobMethod; completeArcPointsVisualizerJobMethod = null; } calculateArcPointsJob.Dispose(); pointsBuffer = Array.Empty(); if ((bool)endpointVisualizerTransform) { EntityState.Destroy(endpointVisualizerTransform.gameObject); endpointVisualizerTransform = null; } base.OnExit(); } protected virtual bool KeyIsDown() { return IsKeyDownAuthority(); } protected virtual void OnProjectileFiredLocal() { } protected virtual void FireProjectile() { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.crit = RollCrit(); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.position = currentTrajectoryInfo.finalRay.origin; fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(currentTrajectoryInfo.finalRay.direction, UnityEngine.Vector3.up); fireProjectileInfo.speedOverride = currentTrajectoryInfo.speedOverride; fireProjectileInfo.damage = damageCoefficient * damageStat; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; if (setFuse) { fireProjectileInfo2.fuseOverride = currentTrajectoryInfo.travelTime; } ModifyProjectile(ref fireProjectileInfo2); ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } protected virtual void ModifyProjectile(ref FireProjectileInfo fireProjectileInfo) { } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && !KeyIsDown() && base.fixedAge >= minimumDuration) { UpdateTrajectoryInfo(out currentTrajectoryInfo); EntityState entityState = PickNextState(); if (entityState != null) { outer.SetNextState(entityState); } else { outer.SetNextStateToMain(); } } } protected virtual EntityState PickNextState() { return null; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } public override void Update() { base.Update(); UpdateTrajectoryInfo(out currentTrajectoryInfo); UpdateVisualizers(currentTrajectoryInfo); } protected virtual void UpdateTrajectoryInfo(out TrajectoryInfo dest) { dest = default(TrajectoryInfo); Ray aimRay = GetAimRay(); RaycastHit hitInfo = default(RaycastHit); bool flag = false; if (rayRadius > 0f && Util.CharacterSpherecast(base.gameObject, aimRay, rayRadius, out hitInfo, maxDistance, LayerIndex.CommonMasks.bullet, QueryTriggerInteraction.UseGlobal) && (bool)hitInfo.collider.GetComponent()) { flag = true; } if (!flag) { flag = Util.CharacterRaycast(base.gameObject, aimRay, out hitInfo, maxDistance, LayerIndex.CommonMasks.bullet, QueryTriggerInteraction.UseGlobal); } if (flag) { dest.hitPoint = hitInfo.point; dest.hitNormal = hitInfo.normal; } else { dest.hitPoint = aimRay.GetPoint(maxDistance); dest.hitNormal = -aimRay.direction; } UnityEngine.Vector3 vector = dest.hitPoint - aimRay.origin; if (useGravity) { float num = projectileBaseSpeed; UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z); float magnitude = vector2.magnitude; float y = Trajectory.CalculateInitialYSpeed(magnitude / num, vector.y); UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(vector2.x / magnitude * num, y, vector2.y / magnitude * num); dest.speedOverride = vector3.magnitude; dest.finalRay = new Ray(aimRay.origin, vector3 / dest.speedOverride); dest.travelTime = Trajectory.CalculateGroundTravelTime(num, magnitude); } else { dest.speedOverride = projectileBaseSpeed; dest.finalRay = aimRay; dest.travelTime = projectileBaseSpeed / vector.magnitude; } } private void CompleteArcVisualizerJob() { calculateArcPointsJobHandle.Complete(); if ((bool)arcVisualizerLineRenderer) { Array.Resize(ref pointsBuffer, calculateArcPointsJob.outputPositions.Length); calculateArcPointsJob.outputPositions.CopyTo(pointsBuffer); arcVisualizerLineRenderer.SetPositions(pointsBuffer); } } private void UpdateVisualizers(TrajectoryInfo trajectoryInfo) { if ((bool)arcVisualizerLineRenderer && calculateArcPointsJobHandle.IsCompleted) { calculateArcPointsJob.SetParameters(trajectoryInfo.finalRay.origin, trajectoryInfo.finalRay.direction * trajectoryInfo.speedOverride, trajectoryInfo.travelTime, arcVisualizerLineRenderer.positionCount, useGravity ? Physics.gravity.y : 0f); calculateArcPointsJobHandle = calculateArcPointsJob.Schedule(calculateArcPointsJob.outputPositions.Length, 32); } if ((bool)endpointVisualizerTransform) { endpointVisualizerTransform.SetPositionAndRotation(trajectoryInfo.hitPoint, Util.QuaternionSafeLookRotation(trajectoryInfo.hitNormal)); if (!endpointVisualizerRadiusScale.Equals(0f)) { endpointVisualizerTransform.localScale = new UnityEngine.Vector3(endpointVisualizerRadiusScale, endpointVisualizerRadiusScale, endpointVisualizerRadiusScale); } } } private void OnPreRenderSceneCam(SceneCamera sceneCam) { if ((bool)arcVisualizerLineRenderer) { arcVisualizerLineRenderer.renderingLayerMask = ((sceneCam.cameraRigController.target == base.gameObject) ? 1u : 0u); } if ((bool)endpointVisualizerTransform) { endpointVisualizerTransform.gameObject.layer = ((sceneCam.cameraRigController.target == base.gameObject) ? LayerIndex.defaultLayer.intVal : LayerIndex.noDraw.intVal); } } } public class BaseBodyAttachmentState : EntityState { protected NetworkedBodyAttachment bodyAttachment { get; private set; } protected CharacterBody attachedBody { get; private set; } public override void OnEnter() { base.OnEnter(); bodyAttachment = GetComponent(); attachedBody = (bodyAttachment ? bodyAttachment.attachedBody : null); } } public class BaseCharacterMain : BaseState { private RootMotionAccumulator rootMotionAccumulator; private UnityEngine.Vector3 previousPosition; protected CharacterAnimParamAvailability characterAnimParamAvailability; private CharacterAnimatorWalkParamCalculator animatorWalkParamCalculator; protected BodyAnimatorSmoothingParameters.SmoothingParameters smoothingParameters; protected bool useRootMotion; private bool wasGrounded; private float lastYSpeed; protected bool hasCharacterMotor; protected bool hasCharacterDirection; protected bool hasCharacterBody; protected bool hasRailMotor; protected bool hasCameraTargetParams; protected bool hasSkillLocator; protected bool hasModelAnimator; protected bool hasInputBank; protected bool hasRootMotionAccumulator; protected Animator modelAnimator { get; private set; } protected UnityEngine.Vector3 estimatedVelocity { get; private set; } public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); rootMotionAccumulator = GetModelRootMotionAccumulator(); if ((bool)rootMotionAccumulator) { rootMotionAccumulator.ExtractRootMotion(); } GetBodyAnimatorSmoothingParameters(out smoothingParameters); previousPosition = base.transform.position; hasCharacterMotor = base.characterMotor; hasCharacterDirection = base.characterDirection; hasCharacterBody = base.characterBody; hasRailMotor = base.railMotor; hasCameraTargetParams = base.cameraTargetParams; hasSkillLocator = base.skillLocator; hasModelAnimator = modelAnimator; hasInputBank = base.inputBank; hasRootMotionAccumulator = rootMotionAccumulator; if ((bool)modelAnimator) { characterAnimParamAvailability = CharacterAnimParamAvailability.FromAnimator(modelAnimator); int layerIndex = modelAnimator.GetLayerIndex("Body"); if (characterAnimParamAvailability.isGrounded) { wasGrounded = base.isGrounded; modelAnimator.SetBool(AnimationParameters.isGrounded, wasGrounded); } if (base.isGrounded || !hasCharacterMotor) { modelAnimator.CrossFadeInFixedTime("Idle", 0.1f, layerIndex); } else { modelAnimator.CrossFadeInFixedTime("AscendDescend", 0.1f, layerIndex); } modelAnimator.Update(0f); } } public override void OnExit() { if ((bool)rootMotionAccumulator) { rootMotionAccumulator.ExtractRootMotion(); } if ((bool)modelAnimator) { if (characterAnimParamAvailability.isMoving) { modelAnimator.SetBool(AnimationParameters.isMoving, value: false); } if (characterAnimParamAvailability.turnAngle) { modelAnimator.SetFloat(AnimationParameters.turnAngle, 0f); } } base.OnExit(); } public override void Update() { base.Update(); if (!(Time.deltaTime <= 0f)) { UpdateEstimatedVelocity(); useRootMotion = ((bool)base.characterBody && base.characterBody.rootMotionInMainState && base.isGrounded) || (bool)base.railMotor; UpdateAnimationParameters(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void UpdateEstimatedVelocity() { UnityEngine.Vector3 vector; if (hasCharacterMotor) { vector = base.characterMotor.velocity; } else if (base.rigidbodyMotor != null && base.rigidbody != null) { vector = base.rigidbody.velocity; } else { UnityEngine.Vector3 position = base.transform.position; vector = (position - previousPosition) / Time.deltaTime; previousPosition = position; } estimatedVelocity = (estimatedVelocity + vector + vector) * (1f / 3f); } public override void FixedUpdate() { base.FixedUpdate(); if (hasCharacterMotor) { float num = estimatedVelocity.y - lastYSpeed; if (base.isGrounded && !wasGrounded && hasModelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Impact"); if (layerIndex >= 0) { modelAnimator.SetLayerWeight(layerIndex, Mathf.Clamp01(Mathf.Max(0.3f, num / 5f, modelAnimator.GetLayerWeight(layerIndex)))); modelAnimator.PlayInFixedTime("LightImpact", layerIndex, 0f); } } wasGrounded = base.isGrounded; lastYSpeed = estimatedVelocity.y; } if (!hasRootMotionAccumulator) { return; } UnityEngine.Vector3 vector = rootMotionAccumulator.ExtractRootMotion(); if (useRootMotion && vector != UnityEngine.Vector3.zero && base.isAuthority) { if ((bool)base.characterMotor) { base.characterMotor.rootMotion += vector; } if ((bool)base.railMotor) { base.railMotor.rootMotion += vector; } } } protected virtual void UpdateAnimationParameters() { if (hasRailMotor || !hasModelAnimator) { return; } float deltaTime = GetDeltaTime(); UnityEngine.Vector3 vector = (base.inputBank ? base.inputBank.moveVector : UnityEngine.Vector3.zero); bool value = vector != UnityEngine.Vector3.zero && base.characterBody.moveSpeed > Mathf.Epsilon; animatorWalkParamCalculator.Update(vector, base.characterDirection ? base.characterDirection.animatorForward : base.transform.forward, in smoothingParameters, deltaTime); if (useRootMotion) { if (characterAnimParamAvailability.mainRootPlaybackRate) { float num = 1f; if ((bool)base.modelLocator && (bool)base.modelLocator.modelTransform) { num = base.modelLocator.modelTransform.localScale.x; } float value2 = base.characterBody.moveSpeed / (base.characterBody.mainRootSpeed * num); modelAnimator.SetFloat(AnimationParameters.mainRootPlaybackRate, value2); } } else if (characterAnimParamAvailability.walkSpeed) { modelAnimator.SetFloat(AnimationParameters.walkSpeed, base.characterBody.moveSpeed); } if (characterAnimParamAvailability.isGrounded) { modelAnimator.SetBool(AnimationParameters.isGrounded, base.isGrounded); } if (characterAnimParamAvailability.isMoving) { modelAnimator.SetBool(AnimationParameters.isMoving, value); } if (characterAnimParamAvailability.turnAngle) { modelAnimator.SetFloat(AnimationParameters.turnAngle, animatorWalkParamCalculator.remainingTurnAngle, smoothingParameters.turnAngleSmoothDamp, deltaTime); } if (characterAnimParamAvailability.isSprinting) { modelAnimator.SetBool(AnimationParameters.isSprinting, base.characterBody.isSprinting); } if (characterAnimParamAvailability.forwardSpeed) { modelAnimator.SetFloat(AnimationParameters.forwardSpeed, animatorWalkParamCalculator.animatorWalkSpeed.x, smoothingParameters.forwardSpeedSmoothDamp, Time.deltaTime); } if (characterAnimParamAvailability.rightSpeed) { modelAnimator.SetFloat(AnimationParameters.rightSpeed, animatorWalkParamCalculator.animatorWalkSpeed.y, smoothingParameters.rightSpeedSmoothDamp, Time.deltaTime); } if (characterAnimParamAvailability.upSpeed) { modelAnimator.SetFloat(AnimationParameters.upSpeed, estimatedVelocity.y, 0.1f, Time.deltaTime); } } } public class BaseSkillState : BaseState, ISkillState { public GenericSkill activatorSkillSlot { get; set; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); this.Serialize(base.skillLocator, writer); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); this.Deserialize(base.skillLocator, reader); } public bool IsKeyDownAuthority() { return this.IsKeyDownAuthority(base.skillLocator, base.inputBank); } } public class BaseState : EntityState { protected struct HitStopCachedState { public UnityEngine.Vector3 characterVelocity; public string playbackName; public float playbackRate; } protected float attackSpeedStat = 1f; protected float damageStat; protected float critStat; protected float moveSpeedStat; private const float defaultAimDuration = 2f; protected bool isGrounded { get { if ((bool)base.characterMotor) { return base.characterMotor.isGrounded; } return false; } } public override void Reset() { base.Reset(); attackSpeedStat = 1f; damageStat = 0f; critStat = 0f; moveSpeedStat = 0f; } public override void OnEnter() { base.OnEnter(); if ((bool)base.characterBody) { attackSpeedStat = base.characterBody.attackSpeed; damageStat = base.characterBody.damage; critStat = base.characterBody.crit; moveSpeedStat = base.characterBody.moveSpeed; } } protected Ray GetAimRay() { if ((bool)base.inputBank) { return new Ray(base.inputBank.aimOrigin, base.inputBank.aimDirection); } return new Ray(base.transform.position, base.transform.forward); } protected void AddRecoil(float verticalMin, float verticalMax, float horizontalMin, float horizontalMax) { base.cameraTargetParams.AddRecoil(verticalMin, verticalMax, horizontalMin, horizontalMax); } public OverlapAttack InitMeleeOverlap(float damageCoefficient, GameObject hitEffectPrefab, Transform modelTransform, string hitboxGroupName) { OverlapAttack overlapAttack = new OverlapAttack(); overlapAttack.attacker = base.gameObject; overlapAttack.inflictor = base.gameObject; overlapAttack.teamIndex = TeamComponent.GetObjectTeam(overlapAttack.attacker); overlapAttack.damage = damageCoefficient * damageStat; overlapAttack.hitEffectPrefab = hitEffectPrefab; overlapAttack.isCrit = RollCrit(); if ((bool)modelTransform) { overlapAttack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == hitboxGroupName); } return overlapAttack; } public bool FireMeleeOverlap(OverlapAttack attack, Animator animator, string mecanimHitboxActiveParameter, float forceMagnitude, bool calculateForceVector = true) { bool result = false; if ((bool)animator && animator.GetFloat(mecanimHitboxActiveParameter) > 0.1f) { if (calculateForceVector) { attack.forceVector = base.transform.forward * forceMagnitude; } result = attack.Fire(); } return result; } public bool FireMeleeOverlap(OverlapAttack attack, Animator animator, int mecanimHitboxActiveParameterHash, float forceMagnitude, bool calculateForceVector = true) { bool result = false; if ((bool)animator && animator.GetFloat(mecanimHitboxActiveParameterHash) > 0.1f) { if (calculateForceVector) { attack.forceVector = base.transform.forward * forceMagnitude; } result = attack.Fire(); } return result; } public void SmallHop(CharacterMotor characterMotor, float smallHopVelocity) { if ((bool)characterMotor) { characterMotor.Motor.ForceUnground(); characterMotor.velocity = new UnityEngine.Vector3(characterMotor.velocity.x, Mathf.Max(characterMotor.velocity.y, smallHopVelocity), characterMotor.velocity.z); } } protected HitStopCachedState CreateHitStopCachedState(CharacterMotor characterMotor, Animator animator, string playbackRateAnimationParameter) { HitStopCachedState result = default(HitStopCachedState); result.characterVelocity = new UnityEngine.Vector3(characterMotor.velocity.x, Mathf.Max(0f, characterMotor.velocity.y), characterMotor.velocity.z); result.playbackName = playbackRateAnimationParameter; result.playbackRate = animator.GetFloat(result.playbackName); return result; } protected void ConsumeHitStopCachedState(HitStopCachedState hitStopCachedState, CharacterMotor characterMotor, Animator animator) { characterMotor.velocity = hitStopCachedState.characterVelocity; animator.SetFloat(hitStopCachedState.playbackName, hitStopCachedState.playbackRate); } protected void StartAimMode(float duration = 2f, bool snap = false) { StartAimMode(GetAimRay(), duration, snap); } protected void StartAimMode(Ray aimRay, float duration = 2f, bool snap = false) { if ((bool)base.characterDirection && aimRay.direction != UnityEngine.Vector3.zero) { if (snap) { base.characterDirection.forward = aimRay.direction; } else { base.characterDirection.moveVector = aimRay.direction; } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } if (!base.modelLocator) { return; } Transform modelTransform = base.modelLocator.modelTransform; if ((bool)modelTransform) { AimAnimator component = modelTransform.GetComponent(); if ((bool)component && snap) { component.AimImmediate(); } } } protected bool RollCrit() { if ((bool)base.characterBody && (bool)base.characterBody.master) { return Util.CheckRoll(critStat, base.characterBody.master); } return false; } protected Transform FindModelChild(string childName) { ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { return modelChildLocator.FindChild(childName); } return null; } protected T FindModelChildComponent(string childName) { ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { return modelChildLocator.FindChildComponent(childName); } return default(T); } protected GameObject FindModelChildGameObject(string childName) { ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { return modelChildLocator.FindChildGameObject(childName); } return null; } public TeamIndex GetTeam() { return TeamComponent.GetObjectTeam(base.gameObject); } public bool HasBuff(BuffIndex buffType) { if ((bool)base.characterBody) { return base.characterBody.HasBuff(buffType); } return false; } public bool HasBuff(BuffDef buffType) { if ((bool)base.characterBody) { return base.characterBody.HasBuff(buffType); } return false; } public int GetBuffCount(BuffIndex buffType) { if (!base.characterBody) { return 0; } return base.characterBody.GetBuffCount(buffType); } public int GetBuffCount(BuffDef buffType) { if (!base.characterBody) { return 0; } return base.characterBody.GetBuffCount(buffType); } protected void AttemptToStartSprint() { if ((bool)base.inputBank) { base.inputBank.sprint.down = true; } } protected HitBoxGroup FindHitBoxGroup(string groupName) { Transform modelTransform = GetModelTransform(); if (!modelTransform) { return null; } HitBoxGroup result = null; List gameObjectComponents = GetComponentsCache.GetGameObjectComponents(modelTransform.gameObject); int i = 0; for (int count = gameObjectComponents.Count; i < count; i++) { if (gameObjectComponents[i].groupName == groupName) { result = gameObjectComponents[i]; break; } } GetComponentsCache.ReturnBuffer(gameObjectComponents); return result; } } public class BasicMeleeAttack : BaseState { [SerializeField] public float baseDuration; [SerializeField] public float damageCoefficient; [SerializeField] public string hitBoxGroupName; [SerializeField] public GameObject hitEffectPrefab; [SerializeField] public float procCoefficient; [SerializeField] public float pushAwayForce; [SerializeField] public UnityEngine.Vector3 forceVector; [SerializeField] public float hitPauseDuration; [SerializeField] public GameObject swingEffectPrefab; [SerializeField] public string swingEffectMuzzleString; [SerializeField] public string mecanimHitboxActiveParameter; [SerializeField] public float shorthopVelocityFromHit; [SerializeField] public string beginStateSoundString; [SerializeField] public string beginSwingSoundString; [SerializeField] public NetworkSoundEventDef impactSound; [SerializeField] public bool forceForwardVelocity; [SerializeField] public AnimationCurve forwardVelocityCurve; [SerializeField] public bool scaleHitPauseDurationAndVelocityWithAttackSpeed; [SerializeField] public bool ignoreAttackSpeed; protected float duration; protected HitBoxGroup hitBoxGroup; protected Animator animator; private OverlapAttack overlapAttack; protected bool authorityHitThisFixedUpdate; protected float hitPauseTimer; protected UnityEngine.Vector3 storedHitPauseVelocity; private Run.FixedTimeStamp meleeAttackStartTime = Run.FixedTimeStamp.positiveInfinity; private GameObject swingEffectInstance; private int meleeAttackTicks; protected List hitResults = new List(); private bool forceFire; protected EffectManagerHelper _emh_swingEffectInstance; protected bool authorityInHitPause => hitPauseTimer > 0f; private bool meleeAttackHasBegun => meleeAttackStartTime.hasPassed; protected bool authorityHasFiredAtAll => meleeAttackTicks > 0; protected bool isCritAuthority { get; private set; } protected virtual bool allowExitFire => true; public virtual string GetHitBoxGroupName() { return hitBoxGroupName; } public override void Reset() { base.Reset(); duration = 0f; hitBoxGroup = null; animator = null; if (overlapAttack != null) { overlapAttack.Reset(); } authorityHitThisFixedUpdate = false; hitPauseTimer = 0f; storedHitPauseVelocity = UnityEngine.Vector3.zero; meleeAttackStartTime = Run.FixedTimeStamp.positiveInfinity; swingEffectInstance = null; meleeAttackTicks = 0; forceFire = false; _emh_swingEffectInstance = null; } public override void OnEnter() { base.OnEnter(); duration = CalcDuration(); if (duration <= Time.fixedDeltaTime * 2f) { forceFire = true; } StartAimMode(); Util.PlaySound(beginStateSoundString, base.gameObject); animator = GetModelAnimator(); if (base.isAuthority) { isCritAuthority = RollCrit(); hitBoxGroup = FindHitBoxGroup(GetHitBoxGroupName()); if ((bool)hitBoxGroup) { overlapAttack = new OverlapAttack { attacker = base.gameObject, damage = damageCoefficient * damageStat, damageColorIndex = DamageColorIndex.Default, damageType = DamageType.Generic, forceVector = forceVector, hitBoxGroup = hitBoxGroup, hitEffectPrefab = hitEffectPrefab, impactSound = (impactSound?.index ?? NetworkSoundEventIndex.Invalid), inflictor = base.gameObject, isCrit = isCritAuthority, procChainMask = default(ProcChainMask), pushAwayForce = pushAwayForce, procCoefficient = procCoefficient, teamIndex = GetTeam() }; } } PlayAnimation(); } protected virtual float CalcDuration() { if (ignoreAttackSpeed) { return baseDuration; } return baseDuration / attackSpeedStat; } protected virtual void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { } public override void FixedUpdate() { base.FixedUpdate(); if (string.IsNullOrEmpty(mecanimHitboxActiveParameter)) { BeginMeleeAttackEffect(); } else if (animator.GetFloat(mecanimHitboxActiveParameter) > 0.5f) { BeginMeleeAttackEffect(); } if (base.isAuthority) { AuthorityFixedUpdate(); } } protected void AuthorityTriggerHitPause() { if ((bool)base.characterMotor) { storedHitPauseVelocity += base.characterMotor.velocity; base.characterMotor.velocity = UnityEngine.Vector3.zero; } if ((bool)animator) { animator.speed = 0f; } if ((bool)swingEffectInstance) { ScaleParticleSystemDuration component = swingEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = 20f; } } hitPauseTimer = (scaleHitPauseDurationAndVelocityWithAttackSpeed ? (hitPauseDuration / attackSpeedStat) : hitPauseDuration); } protected virtual void BeginMeleeAttackEffect() { if (meleeAttackStartTime != Run.FixedTimeStamp.positiveInfinity) { return; } meleeAttackStartTime = Run.FixedTimeStamp.now; Util.PlaySound(beginSwingSoundString, base.gameObject); if (!swingEffectPrefab) { return; } Transform transform = FindModelChild(swingEffectMuzzleString); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(swingEffectPrefab)) { swingEffectInstance = UnityEngine.Object.Instantiate(swingEffectPrefab, transform); } else { _emh_swingEffectInstance = EffectManager.GetAndActivatePooledEffect(swingEffectPrefab, transform, inResetLocal: true); swingEffectInstance = _emh_swingEffectInstance.gameObject; } ScaleParticleSystemDuration component = swingEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = component.initialDuration; } } } protected virtual void AuthorityExitHitPause() { hitPauseTimer = 0f; storedHitPauseVelocity.y = Mathf.Max(storedHitPauseVelocity.y, scaleHitPauseDurationAndVelocityWithAttackSpeed ? (shorthopVelocityFromHit / Mathf.Sqrt(attackSpeedStat)) : shorthopVelocityFromHit); if ((bool)base.characterMotor) { base.characterMotor.velocity = storedHitPauseVelocity; } storedHitPauseVelocity = UnityEngine.Vector3.zero; if ((bool)animator) { animator.speed = 1f; } if ((bool)swingEffectInstance) { ScaleParticleSystemDuration component = swingEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = component.initialDuration; } } } protected virtual void PlayAnimation() { } protected virtual void OnMeleeHitAuthority() { } private void AuthorityFireAttack() { AuthorityModifyOverlapAttack(overlapAttack); hitResults.Clear(); authorityHitThisFixedUpdate = overlapAttack.Fire(hitResults); meleeAttackTicks++; if (authorityHitThisFixedUpdate) { AuthorityTriggerHitPause(); OnMeleeHitAuthority(); } } protected virtual void AuthorityFixedUpdate() { if (authorityInHitPause) { hitPauseTimer -= GetDeltaTime(); if ((bool)base.characterMotor) { base.characterMotor.velocity = UnityEngine.Vector3.zero; } base.fixedAge -= GetDeltaTime(); if (!authorityInHitPause) { AuthorityExitHitPause(); } } else if (forceForwardVelocity && (bool)base.characterMotor && (bool)base.characterDirection) { UnityEngine.Vector3 vector = base.characterDirection.forward * forwardVelocityCurve.Evaluate(base.fixedAge / duration); _ = base.characterMotor.velocity; base.characterMotor.AddDisplacement(new UnityEngine.Vector3(vector.x, 0f, vector.z)); } authorityHitThisFixedUpdate = false; if (overlapAttack != null && (string.IsNullOrEmpty(mecanimHitboxActiveParameter) || animator.GetFloat(mecanimHitboxActiveParameter) > 0.5f || forceFire)) { AuthorityFireAttack(); } if (duration <= base.fixedAge) { AuthorityOnFinish(); } } public override void OnExit() { if (base.isAuthority) { if (!outer.destroying && !authorityHasFiredAtAll && allowExitFire) { BeginMeleeAttackEffect(); AuthorityFireAttack(); } if (authorityInHitPause) { AuthorityExitHitPause(); } } if (_emh_swingEffectInstance != null && _emh_swingEffectInstance.OwningPool != null) { _emh_swingEffectInstance.OwningPool.ReturnObject(_emh_swingEffectInstance); } else if ((bool)swingEffectInstance) { EntityState.Destroy(swingEffectInstance); } swingEffectInstance = null; _emh_swingEffectInstance = null; if ((bool)animator) { animator.speed = 1f; } base.OnExit(); } protected virtual void AuthorityOnFinish() { outer.SetNextStateToMain(); } } public class BigCharacterMain : GenericCharacterMain { public override void ProcessJump() { if (base.characterMotor.jumpCount > base.characterBody.baseJumpCount) { base.ProcessJump(); } else if (jumpInputReceived && base.characterMotor.isGrounded) { outer.SetNextState(new AnimatedJump()); } } } public class AnimatedJump : BaseState { private float duration; private bool hasInputJump; public override void OnEnter() { base.OnEnter(); Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Body"); modelAnimator.CrossFadeInFixedTime("AnimatedJump", 0.25f); modelAnimator.Update(0f); duration = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length; AimAnimator component = modelAnimator.GetComponent(); if ((bool)component) { component.enabled = true; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration / 2f && base.isAuthority && !hasInputJump) { hasInputJump = true; base.characterMotor.moveDirection = base.inputBank.moveVector; GenericCharacterMain.ApplyJumpVelocity(base.characterMotor, base.characterBody, 1f, 1f); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class CloakTest : BaseState { private float duration = 3f; public override void OnEnter() { base.OnEnter(); if ((bool)base.characterBody && NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.Cloak); base.characterBody.AddBuff(RoR2Content.Buffs.CloakSpeed); } } public override void OnExit() { if ((bool)base.characterBody && NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak); base.characterBody.RemoveBuff(RoR2Content.Buffs.CloakSpeed); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class EmotePoint : BaseState { public static float duration = 0.5f; private static int EmotePointStateHash = Animator.StringToHash("EmotePoint"); private static int EmotePointplaybackRateParamHash = Animator.StringToHash("EmotePoint.playbackRate"); public override void OnEnter() { base.OnEnter(); Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Gesture"); modelAnimator.SetFloat(EmotePointplaybackRateParamHash, 1f); modelAnimator.PlayInFixedTime(EmotePointStateHash, layerIndex, 0f); modelAnimator.Update(0f); modelAnimator.SetFloat(EmotePointplaybackRateParamHash, attackSpeedStat); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public enum InterruptPriority { Any, Skill, PrioritySkill, Pain, Stun, Frozen, Vehicle, Death } public class EntityState { public EntityStateMachine outer; protected float age { get; set; } protected float fixedAge { get; set; } protected GameObject gameObject => outer.gameObject; protected bool isLocalPlayer { get { if ((bool)outer.networker) { return outer.networker.isLocalPlayer; } return false; } } protected bool localPlayerAuthority { get { if ((bool)outer.networker) { return outer.networker.localPlayerAuthority; } return false; } } protected bool isAuthority => Util.HasEffectiveAuthority(outer.networkIdentity); protected Transform transform => outer.commonComponents.transform; protected CharacterBody characterBody => outer.commonComponents.characterBody; protected CharacterMotor characterMotor => outer.commonComponents.characterMotor; protected CharacterDirection characterDirection => outer.commonComponents.characterDirection; protected Rigidbody rigidbody => outer.commonComponents.rigidbody; protected RigidbodyMotor rigidbodyMotor => outer.commonComponents.rigidbodyMotor; protected RigidbodyDirection rigidbodyDirection => outer.commonComponents.rigidbodyDirection; protected RailMotor railMotor => outer.commonComponents.railMotor; protected ModelLocator modelLocator => outer.commonComponents.modelLocator; protected InputBankTest inputBank => outer.commonComponents.inputBank; protected TeamComponent teamComponent => outer.commonComponents.teamComponent; protected HealthComponent healthComponent => outer.commonComponents.healthComponent; protected SkillLocator skillLocator => outer.commonComponents.skillLocator; protected CharacterEmoteDefinitions characterEmoteDefinitions => outer.commonComponents.characterEmoteDefinitions; protected CameraTargetParams cameraTargetParams => outer.commonComponents.cameraTargetParams; protected SfxLocator sfxLocator => outer.commonComponents.sfxLocator; protected BodyAnimatorSmoothingParameters bodyAnimatorSmoothingParameters => outer.commonComponents.bodyAnimatorSmoothingParameters; protected ProjectileController projectileController => outer.commonComponents.projectileController; public void ClearEntityStateMachine() { outer = null; } public EntityState() { EntityStateCatalog.InitializeStateFields(this); } public virtual void OnEnter() { } public virtual void OnExit() { } public virtual void ModifyNextState(EntityState nextState) { } public virtual void Update() { age += Time.deltaTime; } public virtual void FixedUpdate() { fixedAge += GetDeltaTime(); } protected float GetDeltaTime() { return Time.fixedDeltaTime; } public virtual void OnSerialize(NetworkWriter writer) { } public virtual void OnDeserialize(NetworkReader reader) { } public virtual InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } public virtual void Reset() { ClearEntityStateMachine(); age = 0f; fixedAge = 0f; } public void SetAIUpdateFrequency(bool alwaysUpdate) { if ((bool)characterBody && (bool)characterBody.master) { characterBody.master.SetAIUpdateFrequency(alwaysUpdate); } } protected static void Destroy(UnityEngine.Object obj) { UnityEngine.Object.Destroy(obj); } protected T GetComponent() where T : Component { return outer.GetComponent(); } protected Component GetComponent(Type type) { return outer.GetComponent(type); } protected Component GetComponent(string type) { return outer.GetComponent(type); } protected Transform GetModelBaseTransform() { if (!modelLocator) { return null; } return modelLocator.modelBaseTransform; } protected Transform GetModelTransform() { if (!modelLocator) { return null; } return modelLocator.modelTransform; } protected AimAnimator GetAimAnimator() { if ((bool)modelLocator && (bool)modelLocator.modelTransform) { return modelLocator.modelTransform.GetComponent(); } return null; } protected Animator GetModelAnimator() { if ((bool)modelLocator && (bool)modelLocator.modelTransform) { return modelLocator.modelTransform.GetComponent(); } return null; } protected ChildLocator GetModelChildLocator() { if ((bool)modelLocator && (bool)modelLocator.modelTransform) { return modelLocator.modelTransform.GetComponent(); } return null; } protected RootMotionAccumulator GetModelRootMotionAccumulator() { if ((bool)modelLocator && (bool)modelLocator.modelTransform) { return modelLocator.modelTransform.GetComponent(); } return null; } protected void PlayAnimation(string layerName, string animationStateName, string playbackRateParam, float duration, float transition = 0f) { if (duration <= 0f) { UnityEngine.Debug.LogWarningFormat("EntityState.PlayAnimation: Zero duration is not allowed. type={0}", GetType().Name); return; } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayAnimationOnAnimator(modelAnimator, layerName, animationStateName, playbackRateParam, duration, transition); } } protected void PlayAnimation(string layerName, int animationStateHash, int playbackRateParamHash, float duration) { if (duration <= 0f) { UnityEngine.Debug.LogWarningFormat("EntityState.PlayAnimation: Zero duration is not allowed. type={0}", GetType().Name); return; } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex(layerName); if (layerIndex >= 0) { PlayAnimationOnAnimator(modelAnimator, layerIndex, animationStateHash, playbackRateParamHash, duration); } } } protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, string animationStateName, string playbackRateParam, float duration, float transition = 0f) { modelAnimator.speed = 1f; modelAnimator.Update(0f); int layerIndex = modelAnimator.GetLayerIndex(layerName); if (layerIndex >= 0) { if (!string.IsNullOrEmpty(playbackRateParam)) { modelAnimator.SetFloat(playbackRateParam, 1f); } if (transition > 0f) { modelAnimator.CrossFadeInFixedTime(animationStateName, transition, layerIndex); } else { modelAnimator.PlayInFixedTime(animationStateName, layerIndex, 0f); } modelAnimator.Update(0f); float length = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length; if (!string.IsNullOrEmpty(playbackRateParam)) { modelAnimator.SetFloat(playbackRateParam, length / duration); } } } protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, int animationStateHash, int playbackRateParamHash, float duration) { int layerIndex = modelAnimator.GetLayerIndex(layerName); if (layerIndex >= 0) { PlayAnimationOnAnimator(modelAnimator, layerIndex, animationStateHash, playbackRateParamHash, duration); } } protected static void PlayAnimationOnAnimator(Animator modelAnimator, int layerIndex, int animationStateHash, int playbackRateParamHash, float duration) { modelAnimator.speed = 1f; modelAnimator.Update(0f); if (layerIndex >= 0) { modelAnimator.SetFloat(playbackRateParamHash, 1f); modelAnimator.PlayInFixedTime(animationStateHash, layerIndex, 0f); modelAnimator.Update(0f); float length = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length; modelAnimator.SetFloat(playbackRateParamHash, length / duration); } } protected void PlayCrossfade(string layerName, string animationStateName, string playbackRateParam, float duration, float crossfadeDuration) { if (duration <= 0f) { UnityEngine.Debug.LogWarningFormat("EntityState.PlayCrossfade: Zero duration is not allowed. type={0}", GetType().Name); return; } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.speed = 1f; modelAnimator.Update(0f); int layerIndex = modelAnimator.GetLayerIndex(layerName); modelAnimator.SetFloat(playbackRateParam, 1f); modelAnimator.CrossFadeInFixedTime(animationStateName, crossfadeDuration, layerIndex); modelAnimator.Update(0f); float length = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length; modelAnimator.SetFloat(playbackRateParam, length / duration); } } protected void PlayCrossfade(string layerName, int animationStateNameHash, int playbackRateParamHash, float duration, float crossfadeDuration) { if (duration <= 0f) { UnityEngine.Debug.LogWarningFormat("EntityState.PlayCrossfade: Zero duration is not allowed. type={0}", GetType().Name); return; } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.speed = 1f; modelAnimator.Update(0f); int layerIndex = modelAnimator.GetLayerIndex(layerName); modelAnimator.SetFloat(playbackRateParamHash, 1f); modelAnimator.CrossFadeInFixedTime(animationStateNameHash, crossfadeDuration, layerIndex); modelAnimator.Update(0f); float length = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length; modelAnimator.SetFloat(playbackRateParamHash, length / duration); } } protected void PlayCrossfade(string layerName, string animationStateName, float crossfadeDuration) { Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.speed = 1f; modelAnimator.Update(0f); int layerIndex = modelAnimator.GetLayerIndex(layerName); modelAnimator.CrossFadeInFixedTime(animationStateName, crossfadeDuration, layerIndex); } } protected void PlayCrossfade(string layerName, int animationStateHash, float crossfadeDuration) { Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.speed = 1f; modelAnimator.Update(0f); int layerIndex = modelAnimator.GetLayerIndex(layerName); modelAnimator.CrossFadeInFixedTime(animationStateHash, crossfadeDuration, layerIndex); } } public virtual void PlayAnimation(string layerName, string animationStateName) { Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayAnimationOnAnimator(modelAnimator, layerName, animationStateName); } } public virtual void PlayAnimation(string layerName, int animationStateHash) { Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayAnimationOnAnimator(modelAnimator, layerName, animationStateHash); } } public virtual void SetPingable(bool value) { if ((bool)outer && (bool)outer.networkIdentity) { outer.networkIdentity.isPingable = value; } } protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, string animationStateName) { int layerIndex = modelAnimator.GetLayerIndex(layerName); modelAnimator.speed = 1f; modelAnimator.Update(0f); modelAnimator.PlayInFixedTime(animationStateName, layerIndex, 0f); } protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, int animationStateHash) { int layerIndex = modelAnimator.GetLayerIndex(layerName); modelAnimator.speed = 1f; modelAnimator.Update(0f); modelAnimator.PlayInFixedTime(animationStateHash, layerIndex, 0f); } protected void GetBodyAnimatorSmoothingParameters(out BodyAnimatorSmoothingParameters.SmoothingParameters smoothingParameters) { if ((bool)bodyAnimatorSmoothingParameters) { smoothingParameters = bodyAnimatorSmoothingParameters.smoothingParameters; } else { smoothingParameters = BodyAnimatorSmoothingParameters.defaultParameters; } } } [Serializable] public struct SerializableEntityStateType { private Type _stateType; [SerializeField] private string _typeName; public string typeName { get { return _typeName; } private set { stateType = Type.GetType(value); } } public Type stateType { get { if (_stateType == null) { CacheStateType(); return _stateType; } return _stateType; } set { _typeName = ((value != null && value.IsSubclassOf(typeof(EntityState))) ? value.AssemblyQualifiedName : ""); } } public SerializableEntityStateType(string typeName) { _typeName = ""; _stateType = null; this.typeName = typeName; } public SerializableEntityStateType(Type stateType) { _typeName = ""; _stateType = null; this.stateType = stateType; } private void CacheStateType() { if (_typeName != null) { Type type = Type.GetType(_typeName); _stateType = ((type != null && type.IsSubclassOf(typeof(EntityState))) ? type : null); } } } public interface ISkillOverrideHandoff { void TransferSkillOverride(SkillStateOverrideData skillOverrideData); } public class SkillStateOverrideData { private object source; public bool duplicateStock; public bool overrideFullReloadOnAssign; public bool simulateRestockForOverridenSkills = true; private static GenericSkill.SkillOverridePriority priority = GenericSkill.SkillOverridePriority.Contextual; private float overrideTimestamp; public SkillDef primarySkillOverride; public SkillDef secondarySkillOverride; public SkillDef utilitySkillOverride; public SkillDef specialSkillOverride; private GenericSkill primarySkillOriginal; private GenericSkill secondarySkillOriginal; private GenericSkill utilitySkillOriginal; private GenericSkill specialSkillOriginal; public int previousPrimaryStock = -1; public int previousSecondaryStock = -1; public int previousUtilityStock = -1; public int previousSpecialStock = -1; public bool hasAuthority { get; private set; } public SkillStateOverrideData(CharacterBody sourceBody) { source = sourceBody; hasAuthority = Util.HasEffectiveAuthority(sourceBody.gameObject); duplicateStock = false; } public SkillStateOverrideData(CharacterBody sourceBody, bool _duplicateStock) { source = sourceBody; hasAuthority = Util.HasEffectiveAuthority(sourceBody.gameObject); duplicateStock = _duplicateStock; } public void OverrideSkills(SkillLocator skillLocator) { if (hasAuthority && !(skillLocator == null)) { overrideTimestamp = Time.time; InternalOverride(skillLocator.primary, ref primarySkillOverride, ref primarySkillOriginal, ref previousPrimaryStock); InternalOverride(skillLocator.secondary, ref secondarySkillOverride, ref secondarySkillOriginal, ref previousSecondaryStock); InternalOverride(skillLocator.utility, ref utilitySkillOverride, ref utilitySkillOriginal, ref previousUtilityStock); InternalOverride(skillLocator.special, ref specialSkillOverride, ref specialSkillOriginal, ref previousSpecialStock); } } private void InternalOverride(GenericSkill existingSkillToOverride, ref SkillDef overridingSkill, ref GenericSkill originalSkill, ref int previousStockAmount) { if (!(overridingSkill == null) && !(existingSkillToOverride == null) && !(existingSkillToOverride == originalSkill) && !existingSkillToOverride.HasSkillOverrideOfPriority(priority)) { int stock = existingSkillToOverride.stock; previousStockAmount = -1; originalSkill = existingSkillToOverride; originalSkill.SetSkillOverride(source, overridingSkill, priority); if (duplicateStock) { originalSkill.stock = stock; } } } public void ClearOverrides() { if (hasAuthority && source != null) { InternalClearOverride(ref primarySkillOriginal, ref primarySkillOverride, ref previousPrimaryStock); InternalClearOverride(ref secondarySkillOriginal, ref secondarySkillOverride, ref previousSecondaryStock); InternalClearOverride(ref utilitySkillOriginal, ref utilitySkillOverride, ref previousUtilityStock); InternalClearOverride(ref specialSkillOriginal, ref specialSkillOverride, ref previousSpecialStock); } void InternalClearOverride(ref GenericSkill overriddenSkill, ref SkillDef skillDef, ref int previousStockAmount) { if (!(overriddenSkill == null) && !(skillDef == null) && overriddenSkill.HasSkillOverrideOfPriority(priority)) { int baseStock = overriddenSkill.GetBaseStock(); int stock = overriddenSkill.stock; float rechargeStopwatch = overriddenSkill.rechargeStopwatch; overriddenSkill.UnsetSkillOverride(source, skillDef, priority); if (overrideFullReloadOnAssign && overriddenSkill.skillDef.fullRestockOnAssign) { overriddenSkill.stock = baseStock; } if (simulateRestockForOverridenSkills) { overriddenSkill.RechargeBaseSkill(Time.time - overrideTimestamp); } previousStockAmount = -1; if (duplicateStock) { overriddenSkill.baseStock = stock; overriddenSkill.baseRechargeStopwatch = rechargeStopwatch; } } } } public void StepRestock() { float time2 = Time.time; if (!(time2 <= overrideTimestamp)) { InternalRestock(time2, ref primarySkillOriginal); InternalRestock(time2, ref secondarySkillOriginal); InternalRestock(time2, ref utilitySkillOriginal); InternalRestock(time2, ref specialSkillOriginal); overrideTimestamp = time2; } void InternalRestock(float time, ref GenericSkill overridenSkill) { if (!(overridenSkill == null)) { overridenSkill.RechargeBaseSkill(time - overrideTimestamp); } } } } public class FlyState : BaseState { private Animator modelAnimator; private bool skill1InputReceived; private bool skill2InputReceived; private bool skill3InputReceived; private bool skill4InputReceived; private static int IdleStateHash = Animator.StringToHash("Idle"); private bool hasPivotPitchLayer; private bool hasPivotYawLayer; private bool hasPivotRollLayer; private static readonly int pivotPitchCycle = Animator.StringToHash("pivotPitchCycle"); private static readonly int pivotYawCycle = Animator.StringToHash("pivotYawCycle"); private static readonly int pivotRollCycle = Animator.StringToHash("pivotRollCycle"); private static readonly int flyRate = Animator.StringToHash("fly.rate"); public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); PlayAnimation("Body", IdleStateHash); if ((bool)modelAnimator) { hasPivotPitchLayer = modelAnimator.GetLayerIndex("PivotPitch") != -1; hasPivotYawLayer = modelAnimator.GetLayerIndex("PivotYaw") != -1; hasPivotRollLayer = modelAnimator.GetLayerIndex("PivotRoll") != -1; } } public override void Update() { base.Update(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.rigidbodyDirection) { UnityEngine.Quaternion rotation = base.transform.rotation; UnityEngine.Quaternion quaternion = Util.QuaternionSafeLookRotation(base.rigidbodyDirection.aimDirection); UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.Inverse(rotation) * quaternion; if ((bool)modelAnimator) { float deltaTime = GetDeltaTime(); if (hasPivotPitchLayer) { modelAnimator.SetFloat(pivotPitchCycle, Mathf.Clamp01(Util.Remap(quaternion2.x * Mathf.Sign(quaternion2.w), -1f, 1f, 0f, 1f)), 1f, deltaTime); } if (hasPivotYawLayer) { modelAnimator.SetFloat(pivotYawCycle, Mathf.Clamp01(Util.Remap(quaternion2.y * Mathf.Sign(quaternion2.w), -1f, 1f, 0f, 1f)), 1f, deltaTime); } if (hasPivotRollLayer) { modelAnimator.SetFloat(pivotRollCycle, Mathf.Clamp01(Util.Remap(quaternion2.z * Mathf.Sign(quaternion2.w), -1f, 1f, 0f, 1f)), 1f, deltaTime); } } } PerformInputs(); } protected virtual bool CanExecuteSkill(GenericSkill skillSlot) { return true; } protected virtual void PerformInputs() { if (!base.isAuthority) { return; } if ((bool)base.inputBank) { if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = base.inputBank.moveVector * base.characterBody.moveSpeed; if ((bool)modelAnimator) { modelAnimator.SetFloat(flyRate, UnityEngine.Vector3.Magnitude(base.rigidbodyMotor.rigid.velocity)); } } if ((bool)base.rigidbodyDirection) { base.rigidbodyDirection.aimDirection = GetAimRay().direction; } skill1InputReceived = base.inputBank.skill1.down; skill2InputReceived = base.inputBank.skill2.down; skill3InputReceived = base.inputBank.skill3.down; skill4InputReceived = base.inputBank.skill4.down; } if ((bool)base.skillLocator) { if (skill1InputReceived && (bool)base.skillLocator.primary && CanExecuteSkill(base.skillLocator.primary)) { base.skillLocator.primary.ExecuteIfReady(); } if (skill2InputReceived && (bool)base.skillLocator.secondary && CanExecuteSkill(base.skillLocator.secondary)) { base.skillLocator.secondary.ExecuteIfReady(); } if (skill3InputReceived && (bool)base.skillLocator.utility && CanExecuteSkill(base.skillLocator.utility)) { base.skillLocator.utility.ExecuteIfReady(); } if (skill4InputReceived && (bool)base.skillLocator.special && CanExecuteSkill(base.skillLocator.special)) { base.skillLocator.special.ExecuteIfReady(); } } } } public class FrozenState : BaseState { private float duration; private Animator modelAnimator; private TemporaryOverlayInstance temporaryOverlay; public float freezeDuration = 0.35f; public static GameObject frozenEffectPrefab; public static GameObject executeEffectPrefab; public override void OnEnter() { base.OnEnter(); if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "") { Util.PlaySound(base.sfxLocator.barkSound, base.gameObject); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { CharacterModel component = modelTransform.GetComponent(); if ((bool)component) { temporaryOverlay = TemporaryOverlayManager.AddOverlay(base.gameObject); temporaryOverlay.duration = freezeDuration; temporaryOverlay.originalMaterial = LegacyResourcesAPI.Load("Materials/matIsFrozen"); temporaryOverlay.AddToCharacterModel(component); } } modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.enabled = false; duration = freezeDuration; EffectManager.SpawnEffect(frozenEffectPrefab, new EffectData { origin = base.characterBody.corePosition, scale = (base.characterBody ? base.characterBody.radius : 1f) }, transmit: false); } if ((bool)base.rigidbody && !base.rigidbody.isKinematic) { base.rigidbody.velocity = UnityEngine.Vector3.zero; if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } } base.healthComponent.isInFrozenState = true; if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } } public override void OnExit() { if ((bool)modelAnimator) { modelAnimator.enabled = true; } if (temporaryOverlay != null) { temporaryOverlay.Destroy(); temporaryOverlay = null; } EffectManager.SpawnEffect(frozenEffectPrefab, new EffectData { origin = base.characterBody.corePosition, scale = (base.characterBody ? base.characterBody.radius : 1f) }, transmit: false); base.healthComponent.isInFrozenState = false; base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public abstract class GenericBulletBaseState : BaseState { [SerializeField] public float baseDuration = 0.1f; [SerializeField] public int bulletCount = 1; [SerializeField] public float maxDistance = 50f; [SerializeField] public float bulletRadius; [SerializeField] public bool useSmartCollision; [SerializeField] public float damageCoefficient = 0.1f; [SerializeField] public float procCoefficient = 1f; [SerializeField] public float force = 100f; [SerializeField] public float minSpread; [SerializeField] public float maxSpread; [SerializeField] public float spreadPitchScale = 0.5f; [SerializeField] public float spreadYawScale = 1f; [SerializeField] public float spreadBloomValue = 0.2f; [SerializeField] public float recoilAmplitudeY; [SerializeField] public float recoilAmplitudeX; [SerializeField] public string muzzleName; [SerializeField] public string fireSoundString; [SerializeField] public GameObject muzzleFlashPrefab; [SerializeField] public GameObject tracerEffectPrefab; [SerializeField] public GameObject hitEffectPrefab; protected float duration; protected Transform muzzleTransform; protected BulletAttack GenerateBulletAttack(Ray aimRay) { float num = 0f; if ((bool)base.characterBody) { num = base.characterBody.spreadBloomAngle; } return new BulletAttack { aimVector = aimRay.direction, origin = aimRay.origin, owner = base.gameObject, weapon = null, bulletCount = (uint)bulletCount, damage = damageStat * damageCoefficient, damageColorIndex = DamageColorIndex.Default, damageType = DamageType.Generic, falloffModel = BulletAttack.FalloffModel.Buckshot, force = force, HitEffectNormal = false, procChainMask = default(ProcChainMask), procCoefficient = procCoefficient, maxDistance = maxDistance, radius = bulletRadius, isCrit = RollCrit(), muzzleName = muzzleName, minSpread = minSpread, maxSpread = maxSpread + num, hitEffectPrefab = hitEffectPrefab, smartCollision = useSmartCollision, sniper = false, spreadPitchScale = spreadPitchScale, spreadYawScale = spreadYawScale, tracerEffectPrefab = tracerEffectPrefab }; } protected virtual void PlayFireAnimation() { } protected virtual void DoFireEffects() { Util.PlaySound(fireSoundString, base.gameObject); if ((bool)muzzleTransform) { EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); } } protected virtual void ModifyBullet(BulletAttack bulletAttack) { } protected virtual void FireBullet(Ray aimRay) { StartAimMode(aimRay, 3f); DoFireEffects(); PlayFireAnimation(); AddRecoil(-1f * recoilAmplitudeY, -1.5f * recoilAmplitudeY, -1f * recoilAmplitudeX, 1f * recoilAmplitudeX); if (base.isAuthority) { BulletAttack bulletAttack = GenerateBulletAttack(aimRay); ModifyBullet(bulletAttack); bulletAttack.Fire(); OnFireBulletAuthority(aimRay); } } protected virtual void OnFireBulletAuthority(Ray aimRay) { } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; muzzleTransform = FindModelChild(muzzleName); FireBullet(GetAimRay()); base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(InstantiateNextState()); } } protected virtual EntityState InstantiateNextState() { return EntityStateCatalog.InstantiateState(ref outer.mainStateType); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class GenericCharacterDeath : BaseState { private static readonly float bodyPreservationDuration = 1f; private static readonly float hardCutoffDuration = 10f; private static readonly float maxFallDuration = 4f; private static readonly float minTimeToKeepBodyForNetworkMessages = 0.5f; public static GameObject voidDeathEffect; private float restStopwatch; private float fallingStopwatch; private bool bodyMarkedForDestructionServer; private CameraTargetParams.AimRequest aimRequest; protected Transform cachedModelTransform { get; private set; } protected bool isBrittle { get; private set; } protected bool isVoidDeath { get; private set; } protected bool isPlayerDeath { get; private set; } protected virtual bool shouldAutoDestroy => true; protected virtual float GetDeathAnimationCrossFadeDuration() { return 0.1f; } public override void OnEnter() { base.OnEnter(); bodyMarkedForDestructionServer = false; cachedModelTransform = (base.modelLocator ? base.modelLocator.modelTransform : null); isBrittle = (bool)base.characterBody && base.characterBody.isGlass; isVoidDeath = (bool)base.healthComponent && (ulong)(base.healthComponent.killingDamageType & DamageType.VoidDeath) != 0; isPlayerDeath = (bool)base.characterBody.master && base.characterBody.master.GetComponent() != null; if (isVoidDeath) { if ((bool)base.characterBody && base.isAuthority) { EffectManager.SpawnEffect(voidDeathEffect, new EffectData { origin = base.characterBody.corePosition, scale = base.characterBody.bestFitRadius }, transmit: true); } if ((bool)cachedModelTransform) { EntityState.Destroy(cachedModelTransform.gameObject); cachedModelTransform = null; } } if (isPlayerDeath && (bool)base.characterBody) { UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/TemporaryVisualEffects/PlayerDeathEffect"), base.characterBody.corePosition, UnityEngine.Quaternion.identity).GetComponent().targetCharacter = base.characterBody.gameObject; } if ((bool)cachedModelTransform) { if (isBrittle) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(cachedModelTransform.gameObject); temporaryOverlayInstance.duration = 0.5f; temporaryOverlayInstance.destroyObjectOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matShatteredGlass"); temporaryOverlayInstance.destroyEffectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/BrittleDeath"); temporaryOverlayInstance.destroyEffectChildString = "Chest"; temporaryOverlayInstance.inspectorCharacterModel = cachedModelTransform.gameObject.GetComponent(); temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.transmit = false; } if ((bool)base.cameraTargetParams) { ChildLocator component = cachedModelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("Chest"); if ((bool)transform) { base.cameraTargetParams.cameraPivotTransform = transform; aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); base.cameraTargetParams.dontRaycastToPivot = true; } } } } if (!isVoidDeath) { PlayDeathSound(); PlayDeathAnimation(); CreateDeathEffects(); } } protected virtual void PlayDeathSound() { if ((bool)base.sfxLocator && base.sfxLocator.deathSound != "") { Util.PlaySound(base.sfxLocator.deathSound, base.gameObject); } } protected virtual void PlayDeathAnimation(float crossfadeDuration = 0.1f) { Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.CrossFadeInFixedTime("Death", crossfadeDuration); } } protected virtual void CreateDeathEffects() { } public override void FixedUpdate() { base.FixedUpdate(); if (!NetworkServer.active) { return; } bool flag = false; bool flag2 = true; if ((bool)base.characterMotor) { flag = base.characterMotor.isGrounded; flag2 = base.characterMotor.atRest; } else if ((bool)base.rigidbodyMotor) { flag = false; flag2 = false; } float deltaTime = GetDeltaTime(); fallingStopwatch = (flag ? 0f : (fallingStopwatch + deltaTime)); restStopwatch = ((!flag2) ? 0f : (restStopwatch + deltaTime)); if (!(base.fixedAge >= minTimeToKeepBodyForNetworkMessages)) { return; } if (!bodyMarkedForDestructionServer) { if ((restStopwatch >= bodyPreservationDuration || fallingStopwatch >= maxFallDuration || base.fixedAge > hardCutoffDuration) && shouldAutoDestroy) { DestroyBodyAsapServer(); } } else { OnPreDestroyBodyServer(); EntityState.Destroy(base.gameObject); } } protected void DestroyBodyAsapServer() { bodyMarkedForDestructionServer = true; } protected virtual void OnPreDestroyBodyServer() { } protected void DestroyModel() { if ((bool)cachedModelTransform) { EntityState.Destroy(cachedModelTransform.gameObject); cachedModelTransform = null; } } public override void OnExit() { aimRequest?.Dispose(); if (shouldAutoDestroy && fallingStopwatch >= maxFallDuration) { DestroyModel(); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class GenericCharacterMain : BaseCharacterMain { public delegate void MovementHitDelegate(ref CharacterMotor.MovementHitInfo movementHitInfo); private AimAnimator aimAnimator; protected bool jumpInputReceived; protected bool sprintInputReceived; private UnityEngine.Vector3 moveVector = UnityEngine.Vector3.zero; private UnityEngine.Vector3 aimDirection = UnityEngine.Vector3.forward; private int emoteRequest = -1; private bool hasAimAnimator; public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { aimAnimator = modelTransform.GetComponent(); if ((bool)aimAnimator) { aimAnimator.enabled = true; } } hasAimAnimator = aimAnimator; } public override void OnExit() { Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { AimAnimator component = modelTransform.GetComponent(); if ((bool)component) { component.enabled = false; } } if (base.isAuthority) { if ((bool)base.characterMotor) { base.characterMotor.moveDirection = UnityEngine.Vector3.zero; } if ((bool)base.railMotor) { base.railMotor.inputMoveVector = UnityEngine.Vector3.zero; } } base.OnExit(); } public override void Update() { base.Update(); } public override void FixedUpdate() { base.FixedUpdate(); GatherInputs(); HandleMovements(); PerformInputs(); } public virtual void HandleMovements() { if (useRootMotion) { if (hasCharacterMotor) { base.characterMotor.moveDirection = UnityEngine.Vector3.zero; } if (hasRailMotor) { base.railMotor.inputMoveVector = moveVector; } } else { if (hasCharacterMotor) { base.characterMotor.moveDirection = moveVector; } if (hasRailMotor) { base.railMotor.inputMoveVector = moveVector; } } _ = base.isGrounded; if (!hasRailMotor && hasCharacterDirection && hasCharacterBody) { if (hasAimAnimator && aimAnimator.aimType == AimAnimator.AimType.Smart) { UnityEngine.Vector3 vector = ((moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : moveVector); float num = UnityEngine.Vector3.Angle(aimDirection, vector); float num2 = Mathf.Max(aimAnimator.pitchRangeMax + aimAnimator.pitchGiveupRange, aimAnimator.yawRangeMax + aimAnimator.yawGiveupRange); base.characterDirection.moveVector = (((bool)base.characterBody && base.characterBody.shouldAim && num > num2) ? aimDirection : vector); } else { base.characterDirection.moveVector = (((bool)base.characterBody && base.characterBody.shouldAim) ? aimDirection : moveVector); } } if (!base.isAuthority) { return; } ProcessJump(); if (hasCharacterBody) { bool isSprinting = sprintInputReceived; if (moveVector.magnitude <= 0.5f) { isSprinting = false; } base.characterBody.isSprinting = isSprinting; } } public static void ApplyJumpVelocity(CharacterMotor characterMotor, CharacterBody characterBody, float horizontalBonus, float verticalBonus, bool vault = false) { UnityEngine.Vector3 moveDirection = characterMotor.moveDirection; if (vault) { characterMotor.velocity = moveDirection; } else { moveDirection.y = 0f; float magnitude = moveDirection.magnitude; if (magnitude > 0f) { moveDirection /= magnitude; } UnityEngine.Vector3 velocity = moveDirection * characterBody.moveSpeed * horizontalBonus; velocity.y = characterBody.jumpPower * verticalBonus; characterMotor.velocity = velocity; } characterMotor.Motor.ForceUnground(); } public virtual void ProcessJump() { if (!hasCharacterMotor) { return; } bool flag = false; bool flag2 = false; if (!jumpInputReceived || !base.characterBody || base.characterMotor.jumpCount >= base.characterBody.maxJumpCount) { return; } int itemCount = base.characterBody.inventory.GetItemCount(RoR2Content.Items.JumpBoost); float horizontalBonus = 1f; float verticalBonus = 1f; if (base.characterMotor.jumpCount >= base.characterBody.baseJumpCount) { flag = true; horizontalBonus = 1.5f; verticalBonus = 1.5f; } else if ((float)itemCount > 0f && base.characterBody.isSprinting) { float num = base.characterBody.acceleration * base.characterMotor.airControl; if (base.characterBody.moveSpeed > 0f && num > 0f) { flag2 = true; float num2 = Mathf.Sqrt(10f * (float)itemCount / num); float num3 = base.characterBody.moveSpeed / num; horizontalBonus = (num2 + num3) / num3; } } ApplyJumpVelocity(base.characterMotor, base.characterBody, horizontalBonus, verticalBonus); if (hasModelAnimator) { int layerIndex = base.modelAnimator.GetLayerIndex("Body"); if (layerIndex >= 0) { if (base.characterMotor.jumpCount == 0 || base.characterBody.baseJumpCount == 1) { base.modelAnimator.CrossFadeInFixedTime("Jump", smoothingParameters.intoJumpTransitionTime, layerIndex); } else { base.modelAnimator.CrossFadeInFixedTime("BonusJump", smoothingParameters.intoJumpTransitionTime, layerIndex); } } } if (flag) { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/FeatherEffect"), new EffectData { origin = base.characterBody.footPosition }, transmit: true); } else if (base.characterMotor.jumpCount > 0) { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/CharacterLandImpact"), new EffectData { origin = base.characterBody.footPosition, scale = base.characterBody.radius }, transmit: true); } if (flag2) { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/BoostJumpEffect"), new EffectData { origin = base.characterBody.footPosition, rotation = Util.QuaternionSafeLookRotation(base.characterMotor.velocity) }, transmit: true); } base.characterMotor.jumpCount++; base.characterBody.onJump?.Invoke(); } protected virtual bool CanExecuteSkill(GenericSkill skillSlot) { return true; } protected void PerformInputs() { if (base.isAuthority) { if (hasSkillLocator) { HandleSkill(base.skillLocator.primary, ref base.inputBank.skill1); HandleSkill(base.skillLocator.secondary, ref base.inputBank.skill2); HandleSkill(base.skillLocator.utility, ref base.inputBank.skill3); HandleSkill(base.skillLocator.special, ref base.inputBank.skill4); } jumpInputReceived = false; sprintInputReceived = false; } void HandleSkill(GenericSkill skillSlot, ref InputBankTest.ButtonState buttonState) { if (buttonState.down && (bool)skillSlot && (!skillSlot.mustKeyPress || !buttonState.hasPressBeenClaimed) && CanExecuteSkill(skillSlot) && skillSlot.ExecuteIfReady()) { buttonState.hasPressBeenClaimed = true; } } } protected void GatherInputs() { if (hasInputBank) { moveVector = base.inputBank.moveVector; aimDirection = base.inputBank.aimDirection; emoteRequest = base.inputBank.emoteRequest; base.inputBank.emoteRequest = -1; jumpInputReceived |= base.inputBank.jump.justPressed; jumpInputReceived &= !base.inputBank.jump.hasPressBeenClaimed; sprintInputReceived |= base.inputBank.sprint.down; } } } public class GenericCharacterPod : BaseState { public override void OnEnter() { base.OnEnter(); if ((bool)base.characterMotor) { base.characterMotor.enabled = false; } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.enabled = false; } } public override void OnExit() { if ((bool)base.characterMotor) { base.characterMotor.enabled = true; } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.enabled = true; } base.OnExit(); } } public abstract class GenericCharacterSpawnState : BaseState { [SerializeField] public float duration = 2f; [SerializeField] public string spawnSoundString; private static int Spawn1StateHash = Animator.StringToHash("Spawn1"); private static int Spawn1ParamHash = Animator.StringToHash("Spawn1.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", Spawn1StateHash, Spawn1ParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class GenericCharacterVehicleSeated : BaseState { public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Vehicle; } } public class GenericProjectileBaseState : BaseState { [SerializeField] public GameObject effectPrefab; [SerializeField] public GameObject projectilePrefab; [SerializeField] public float damageCoefficient; [SerializeField] public float force; [SerializeField] public float minSpread; [SerializeField] public float maxSpread; [SerializeField] public float baseDuration = 2f; [SerializeField] public float recoilAmplitude = 1f; [SerializeField] public string attackSoundString; [SerializeField] public float projectilePitchBonus; [SerializeField] public float baseDelayBeforeFiringProjectile; [SerializeField] public string targetMuzzle; [SerializeField] public float bloom; protected float stopwatch; protected float duration; protected float delayBeforeFiringProjectile; protected bool firedProjectile; public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; delayBeforeFiringProjectile = baseDelayBeforeFiringProjectile / attackSpeedStat; if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } PlayAnimation(duration); } public override void OnExit() { base.OnExit(); } protected virtual void PlayAnimation(float duration) { } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= delayBeforeFiringProjectile && !firedProjectile) { firedProjectile = true; FireProjectile(); DoFireEffects(); } if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } protected virtual void FireProjectile() { if (base.isAuthority) { Ray aimRay = GetAimRay(); aimRay = ModifyProjectileAimRay(aimRay); aimRay.direction = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, 0f, projectilePitchBonus); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } protected virtual Ray ModifyProjectileAimRay(Ray aimRay) { return aimRay; } protected virtual void DoFireEffects() { Util.PlaySound(attackSoundString, base.gameObject); AddRecoil(-2f * recoilAmplitude, -3f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } base.characterBody.AddSpreadBloom(bloom); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class GenericReload : BaseState { [SerializeField] public string enterSoundString; protected float duration; public override void OnEnter() { base.OnEnter(); if ((bool)base.skillLocator && (bool)base.skillLocator.primary) { duration = base.skillLocator.primary.CalculateFinalRechargeInterval(); } Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } public override void OnExit() { base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } } public class GhostUtilitySkillState : GenericCharacterMain { public static float baseDuration; public static GameObject coreVfxPrefab; public static GameObject footVfxPrefab; public static GameObject entryEffectPrefab; public static GameObject exitEffectPrefab; public static float moveSpeedCoefficient; public static float healFractionPerTick; public static float healFrequency; private HurtBoxGroup hurtBoxGroup; private CharacterModel characterModel; private GameObject coreVfxInstance; private GameObject footVfxInstance; private float healTimer; private float duration; private ICharacterGravityParameterProvider characterGravityParameterProvider; private ICharacterFlightParameterProvider characterFlightParameterProvider; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string playbackRateParam; private EffectManagerHelper _emh_coreVfxInstance; private EffectManagerHelper _emh_footVfxInstance; public override void Reset() { base.Reset(); hurtBoxGroup = null; characterModel = null; coreVfxInstance = null; footVfxInstance = null; healTimer = 0f; duration = 0f; _emh_coreVfxInstance = null; _emh_footVfxInstance = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration; characterGravityParameterProvider = base.gameObject.GetComponent(); characterFlightParameterProvider = base.gameObject.GetComponent(); if ((bool)base.characterBody) { if ((bool)base.characterBody.inventory) { duration *= base.characterBody.inventory.GetItemCount(RoR2Content.Items.LunarUtilityReplacement); } hurtBoxGroup = base.characterBody.hurtBoxGroup; if ((bool)hurtBoxGroup) { HurtBoxGroup obj = hurtBoxGroup; int hurtBoxesDeactivatorCounter = obj.hurtBoxesDeactivatorCounter + 1; obj.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)coreVfxPrefab) { if (!EffectManager.ShouldUsePooledEffect(coreVfxPrefab)) { coreVfxInstance = UnityEngine.Object.Instantiate(coreVfxPrefab); } else { _emh_coreVfxInstance = EffectManager.GetAndActivatePooledEffect(coreVfxPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity); coreVfxInstance = _emh_coreVfxInstance.gameObject; } } if ((bool)footVfxPrefab) { if (!EffectManager.ShouldUsePooledEffect(footVfxPrefab)) { footVfxInstance = UnityEngine.Object.Instantiate(footVfxPrefab); } else { _emh_footVfxInstance = EffectManager.GetAndActivatePooledEffect(footVfxPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity); footVfxInstance = _emh_footVfxInstance.gameObject; } } UpdateVfxPositions(); if ((bool)entryEffectPrefab) { Ray aimRay = GetAimRay(); EffectManager.SimpleEffect(entryEffectPrefab, aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction), transmit: false); } } characterModel = GetModelTransform()?.GetComponent(); if ((bool)base.modelAnimator) { base.modelAnimator.enabled = false; } if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = moveSpeedCoefficient; } if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount++; characterGravityParameterProvider.gravityParameters = gravityParameters; } if (characterFlightParameterProvider != null) { CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters; flightParameters.channeledFlightGranterCount++; characterFlightParameterProvider.flightParameters = flightParameters; } if ((bool)characterModel) { characterModel.invisibilityCount++; } EntityStateMachine[] components = base.gameObject.GetComponents(); foreach (EntityStateMachine entityStateMachine in components) { if (entityStateMachine.customName == "Weapon") { entityStateMachine.SetNextStateToMain(); } } } private void UpdateVfxPositions() { if ((bool)base.characterBody) { if ((bool)coreVfxInstance) { coreVfxInstance.transform.position = base.characterBody.corePosition; } if ((bool)footVfxInstance) { footVfxInstance.transform.position = base.characterBody.footPosition; } } } protected override bool CanExecuteSkill(GenericSkill skillSlot) { return false; } public override void Update() { base.Update(); UpdateVfxPositions(); } public override void FixedUpdate() { base.FixedUpdate(); healTimer -= GetDeltaTime(); if (healTimer <= 0f) { if (NetworkServer.active) { base.healthComponent.HealFraction(healFractionPerTick, default(ProcChainMask)); } healTimer = 1f / healFrequency; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if ((bool)exitEffectPrefab && !outer.destroying) { Ray aimRay = GetAimRay(); EffectManager.SimpleEffect(exitEffectPrefab, aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction), transmit: false); } if (_emh_coreVfxInstance != null && _emh_coreVfxInstance.OwningPool != null) { _emh_coreVfxInstance.OwningPool.ReturnObject(_emh_coreVfxInstance); } else if (coreVfxInstance != null) { EntityState.Destroy(coreVfxInstance); } coreVfxInstance = null; _emh_coreVfxInstance = null; if (_emh_footVfxInstance != null && _emh_footVfxInstance.OwningPool != null) { _emh_footVfxInstance.OwningPool.ReturnObject(_emh_footVfxInstance); } else if (footVfxInstance != null) { EntityState.Destroy(footVfxInstance); } footVfxInstance = null; _emh_footVfxInstance = null; if ((bool)characterModel) { characterModel.invisibilityCount--; } if ((bool)hurtBoxGroup) { HurtBoxGroup obj = hurtBoxGroup; int hurtBoxesDeactivatorCounter = obj.hurtBoxesDeactivatorCounter - 1; obj.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)base.modelAnimator) { base.modelAnimator.enabled = true; } if (characterFlightParameterProvider != null) { CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters; flightParameters.channeledFlightGranterCount--; characterFlightParameterProvider.flightParameters = flightParameters; } if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount--; characterGravityParameterProvider.gravityParameters = gravityParameters; } if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = 1f; } base.OnExit(); } } public class HoverState : BaseState { private Animator modelAnimator; private bool skill1InputReceived; private bool skill2InputReceived; private bool skill3InputReceived; private bool skill4InputReceived; private static int IdleStateHash = Animator.StringToHash("Idle"); private static int flyrateParamHash = Animator.StringToHash("fly.rate"); public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); PlayAnimation("Body", IdleStateHash); } public override void Update() { base.Update(); if ((bool)base.inputBank) { skill1InputReceived = base.inputBank.skill1.down; skill2InputReceived = base.inputBank.skill2.down; skill3InputReceived = base.inputBank.skill3.down; skill4InputReceived = base.inputBank.skill4.down; } } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } if ((bool)base.inputBank) { if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = base.inputBank.moveVector * base.characterBody.moveSpeed; if ((bool)modelAnimator) { modelAnimator.SetFloat(flyrateParamHash, UnityEngine.Vector3.Magnitude(base.rigidbodyMotor.rigid.velocity)); } } if ((bool)base.rigidbodyDirection) { base.rigidbodyDirection.aimDirection = GetAimRay().direction; } } if ((bool)base.skillLocator) { if ((bool)base.skillLocator.primary && skill1InputReceived) { base.skillLocator.primary.ExecuteIfReady(); } if ((bool)base.skillLocator.secondary && skill2InputReceived) { base.skillLocator.secondary.ExecuteIfReady(); } if ((bool)base.skillLocator.utility && skill3InputReceived) { base.skillLocator.utility.ExecuteIfReady(); } if ((bool)base.skillLocator.special && skill4InputReceived) { base.skillLocator.special.ExecuteIfReady(); } } } } public class HurtState : BaseState { private float stopwatch; private float duration = 0.35f; public override void OnEnter() { base.OnEnter(); if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "") { Util.PlaySound(base.sfxLocator.barkSound, base.gameObject); } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Body"); modelAnimator.CrossFadeInFixedTime((UnityEngine.Random.Range(0, 2) == 0) ? "Hurt1" : "Hurt2", 0.1f); modelAnimator.Update(0f); duration = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length; } if ((bool)base.characterBody) { base.characterBody.isSprinting = false; } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class HurtStateFlyer : BaseState { private float stopwatch; private float duration = 0.35f; public override void OnEnter() { base.OnEnter(); if ((bool)base.sfxLocator && base.sfxLocator.deathSound != "") { Util.PlaySound(base.sfxLocator.barkSound, base.gameObject); } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Body"); modelAnimator.CrossFadeInFixedTime((UnityEngine.Random.Range(0, 2) == 0) ? "Hurt1" : "Hurt2", 0.1f); modelAnimator.Update(0f); duration = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length; } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class Idle : EntityState { } public class IdleSkillOverrideHandoff : EntityState, ISkillOverrideHandoff { public static float skillOverrideTimeout = 0.05f; private bool shouldProcess; private SkillStateOverrideData skillOverrideData; public void TransferSkillOverride(SkillStateOverrideData skillOverrideData) { this.skillOverrideData = skillOverrideData; shouldProcess = this.skillOverrideData != null; } public override void Update() { if (shouldProcess) { base.Update(); skillOverrideData.StepRestock(); if (base.age > skillOverrideTimeout) { skillOverrideData.ClearOverrides(); skillOverrideData = null; shouldProcess = false; } } } public override void ModifyNextState(EntityState nextState) { base.ModifyNextState(nextState); if (skillOverrideData != null && nextState is ISkillOverrideHandoff skillOverrideHandoff) { skillOverrideHandoff.TransferSkillOverride(skillOverrideData); skillOverrideData = null; shouldProcess = false; } } public override void OnExit() { base.OnExit(); if (shouldProcess) { skillOverrideData?.ClearOverrides(); } } } public interface ISkillState { GenericSkill activatorSkillSlot { get; set; } } public static class SkillStateMethods { public static void Serialize(this ISkillState skillState, SkillLocator skillLocator, NetworkWriter writer) { int num = -1; if ((object)skillLocator != null) { num = skillLocator.GetSkillSlotIndex(skillState.activatorSkillSlot); } writer.Write((sbyte)num); } public static void Deserialize(this ISkillState skillState, SkillLocator skillLocator, NetworkReader reader) { int index = reader.ReadSByte(); if ((object)skillLocator != null) { skillState.activatorSkillSlot = skillLocator.GetSkillAtIndex(index); } } public static bool IsKeyDownAuthority(this ISkillState skillState, SkillLocator skillLocator, InputBankTest inputBank) { GenericSkill activatorSkillSlot = skillState.activatorSkillSlot; if ((object)skillLocator == null || (object)activatorSkillSlot == null || (object)inputBank == null) { return false; } return skillLocator.FindSkillSlot(activatorSkillSlot) switch { SkillSlot.None => false, SkillSlot.Primary => inputBank.skill1.down, SkillSlot.Secondary => inputBank.skill2.down, SkillSlot.Utility => inputBank.skill3.down, SkillSlot.Special => inputBank.skill4.down, _ => throw new ArgumentOutOfRangeException(), }; } } public class LockSkill : BaseState { public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class MageCalibrate : BaseState { public MageElement element; public MageCalibrationController calibrationController; private bool shouldApply; public override void OnEnter() { calibrationController = GetComponent(); shouldApply = NetworkServer.active; base.OnEnter(); } public override void OnExit() { ApplyElement(); base.OnExit(); } public override void FixedUpdate() { outer.SetNextStateToMain(); } private void ApplyElement() { if (shouldApply && (bool)calibrationController) { shouldApply = false; calibrationController.SetElement(element); } } public override void OnSerialize(NetworkWriter writer) { writer.Write((byte)element); } public override void OnDeserialize(NetworkReader reader) { element = (MageElement)reader.ReadByte(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class BaseMelee : BaseState { protected RootMotionAccumulator rootMotionAccumulator; public RootMotionAccumulator InitMeleeRootMotion() { rootMotionAccumulator = GetModelRootMotionAccumulator(); if ((bool)rootMotionAccumulator) { rootMotionAccumulator.ExtractRootMotion(); } if ((bool)base.characterDirection) { base.characterDirection.forward = base.inputBank.aimDirection; } if ((bool)base.characterMotor) { base.characterMotor.moveDirection = UnityEngine.Vector3.zero; } return rootMotionAccumulator; } public void UpdateMeleeRootMotion(float scale) { if ((bool)rootMotionAccumulator) { UnityEngine.Vector3 vector = rootMotionAccumulator.ExtractRootMotion(); if ((bool)base.characterMotor) { base.characterMotor.rootMotion = vector * scale; } } } } public class SleepState : EntityState { public override void OnEnter() { base.OnEnter(); Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Body"); modelAnimator.Play("Sleep", layerIndex, 0f); } } public override void FixedUpdate() { base.FixedUpdate(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } } public class SpawnTeleporterState : BaseState { private float duration = 4f; public static string soundString; public static float initialDelay; private bool hasTeleported; private Animator modelAnimator; private PrintController printController; private CharacterModel characterModel; private CameraTargetParams.AimRequest aimRequest; public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } if ((bool)modelAnimator) { GameObject gameObject = modelAnimator.gameObject; characterModel = gameObject.GetComponent(); characterModel.invisibilityCount++; } if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } } public override void OnExit() { base.OnExit(); if (!hasTeleported) { characterModel.invisibilityCount--; } aimRequest?.Dispose(); if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 3f); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= initialDelay && !hasTeleported) { hasTeleported = true; characterModel.invisibilityCount--; duration = initialDelay; TeleportOutController.AddTPOutEffect(characterModel, 1f, 0f, duration); GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(base.gameObject); if ((bool)teleportEffectPrefab) { EffectManager.SimpleEffect(teleportEffectPrefab, base.transform.position, UnityEngine.Quaternion.identity, transmit: false); } Util.PlaySound(soundString, base.gameObject); } if (base.fixedAge >= duration && hasTeleported && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class StunState : BaseState { private float duration; private GameObject stunVfxInstance; public float stunDuration = 0.35f; public static GameObject stunVfxPrefab; protected EffectManagerHelper _efhStunEffect; public float timeRemaining => Math.Max(duration - base.fixedAge, 0f); public override void Reset() { base.Reset(); duration = 0f; stunVfxInstance = null; stunDuration = 0.35f; _efhStunEffect = null; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Stun; } public void ExtendStun(float durationDelta) { duration += durationDelta; PlayStunAnimation(); } public override void OnEnter() { base.OnEnter(); if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "") { Util.PlaySound(base.sfxLocator.barkSound, base.gameObject); } PlayStunAnimation(); if ((bool)base.characterBody) { base.characterBody.isSprinting = false; } if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } } private void PlayStunAnimation() { Animator modelAnimator = GetModelAnimator(); if (!modelAnimator) { return; } int layerIndex = modelAnimator.GetLayerIndex("Body"); modelAnimator.CrossFadeInFixedTime((UnityEngine.Random.Range(0, 2) == 0) ? "Hurt1" : "Hurt2", 0.1f); modelAnimator.Update(0f); AnimatorStateInfo nextAnimatorStateInfo = modelAnimator.GetNextAnimatorStateInfo(layerIndex); duration = Mathf.Max(duration, Mathf.Max(stunDuration, nextAnimatorStateInfo.length)); if (stunDuration >= 0f) { if ((bool)stunVfxInstance) { ReleaseStunVFX(); } if (!EffectManager.ShouldUsePooledEffect(stunVfxPrefab)) { stunVfxInstance = UnityEngine.Object.Instantiate(stunVfxPrefab, base.transform); } else { _efhStunEffect = EffectManager.GetAndActivatePooledEffect(stunVfxPrefab, base.transform); stunVfxInstance = _efhStunEffect.gameObject; } ScaleParticleSystemDuration component = stunVfxInstance.GetComponent(); component.newDuration = duration; component.UpdateDuration(); } } public override void OnExit() { ReleaseStunVFX(); base.OnExit(); } private void ReleaseStunVFX() { if (!stunVfxInstance) { return; } if (!EffectManager.UsePools) { EntityState.Destroy(stunVfxInstance); } else if (_efhStunEffect != null && _efhStunEffect.OwningPool != null) { if (!_efhStunEffect.OwningPool.IsObjectInPool(_efhStunEffect)) { _efhStunEffect.OwningPool.ReturnObject(_efhStunEffect); } } else { if (_efhStunEffect != null) { UnityEngine.Debug.LogFormat("StunEffect has no owning pool {0} {1}", base.gameObject.name, base.gameObject.GetInstanceID()); } EntityState.Destroy(stunVfxInstance); } _efhStunEffect = null; stunVfxInstance = null; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class ShockState : BaseState { public static GameObject stunVfxPrefab; public float shockDuration = 1f; public static float shockInterval = 0.1f; public static float shockStrength = 1f; public static float healthFractionToForceExit = 0.1f; public static string enterSoundString; public static string exitSoundString; private float shockTimer; private Animator animator; private TemporaryOverlayInstance temporaryOverlay; private float healthFraction; private GameObject stunVfxInstance; private static int Hurt1StateHash = Animator.StringToHash("Hurt1"); private static int Hurt2StateHash = Animator.StringToHash("Hurt2"); public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "") { Util.PlaySound(base.sfxLocator.barkSound, base.gameObject); } Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation("Body", (UnityEngine.Random.Range(0, 2) == 0) ? Hurt1StateHash : Hurt2StateHash); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { CharacterModel component = modelTransform.GetComponent(); if ((bool)component) { temporaryOverlay = TemporaryOverlayManager.AddOverlay(base.gameObject); temporaryOverlay.duration = shockDuration; temporaryOverlay.originalMaterial = LegacyResourcesAPI.Load("Materials/matIsShocked"); temporaryOverlay.AddToCharacterModel(component); } } stunVfxInstance = UnityEngine.Object.Instantiate(stunVfxPrefab, base.transform); stunVfxInstance.GetComponent().newDuration = shockDuration; if ((bool)base.characterBody.healthComponent) { healthFraction = base.characterBody.healthComponent.combinedHealthFraction; } if ((bool)base.characterBody) { base.characterBody.isSprinting = false; } if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } } public override void FixedUpdate() { base.FixedUpdate(); shockTimer -= GetDeltaTime(); float combinedHealthFraction = base.characterBody.healthComponent.combinedHealthFraction; if (shockTimer <= 0f) { shockTimer += shockInterval; PlayShockAnimation(); } if (base.fixedAge > shockDuration || healthFraction - combinedHealthFraction > healthFractionToForceExit) { outer.SetNextStateToMain(); } } public override void OnExit() { if (temporaryOverlay != null) { temporaryOverlay.Destroy(); } if ((bool)stunVfxInstance) { EntityState.Destroy(stunVfxInstance); } Util.PlaySound(exitSoundString, base.gameObject); base.OnExit(); } private void PlayShockAnimation() { string layerName = "Flinch"; int layerIndex = animator.GetLayerIndex(layerName); if (layerIndex >= 0) { animator.SetLayerWeight(layerIndex, shockStrength); animator.Play("FlinchStart", layerIndex); } } } public class TestState1 : EntityState { public override void OnEnter() { UnityEngine.Debug.LogFormat("{0} Entering TestState1.", base.gameObject); } public override void OnExit() { UnityEngine.Debug.LogFormat("{0} Exiting TestState1.", base.gameObject); } public override void FixedUpdate() { if (base.isAuthority && Input.GetButton("Fire1")) { outer.SetNextState(new TestState2()); } } } public class TestState2 : EntityState { public override void OnEnter() { UnityEngine.Debug.LogFormat("{0} Entering TestState2.", base.gameObject); } public override void OnExit() { UnityEngine.Debug.LogFormat("{0} Exiting TestState2.", base.gameObject); } public override void FixedUpdate() { if (base.isAuthority && Input.GetButton("Fire2")) { outer.SetNextState(new TestState1()); } } } public class PrepFlower2 : BaseState { public static float baseDuration; public static string enterSoundString; private float duration; private static int PrepFlowerStateHash = Animator.StringToHash("PrepFlower"); private static int PrepFlowerParamHash = Animator.StringToHash("PrepFlower.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation("Gesture, Additive", PrepFlowerStateHash, PrepFlowerParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new FireFlower2()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireFlower2 : BaseState { public static GameObject projectilePrefab; public static float baseDuration; public static float damageCoefficient; public static float healthCostFraction; public static string enterSoundString; public static string muzzleName; public static GameObject muzzleFlashPrefab; private float duration; private static int FireFlowerStateHash = Animator.StringToHash("FireFlower"); private static int FireFlowerParamHash = Animator.StringToHash("FireFlower.playbackRate"); public override void OnEnter() { base.OnEnter(); EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); duration = baseDuration / attackSpeedStat; Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation("Gesture, Additive", FireFlowerStateHash, FireFlowerParamHash, duration); if (base.isAuthority) { Ray aimRay = GetAimRay(); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.crit = RollCrit(); fireProjectileInfo.damage = damageCoefficient * damageStat; fireProjectileInfo.damageColorIndex = DamageColorIndex.Default; fireProjectileInfo.force = 0f; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.position = aimRay.origin; fireProjectileInfo.procChainMask = default(ProcChainMask); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction); fireProjectileInfo.useSpeedOverride = false; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } if (NetworkServer.active && (bool)base.healthComponent) { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction; damageInfo.position = base.characterBody.corePosition; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.damageColorIndex = DamageColorIndex.Default; damageInfo.crit = false; damageInfo.attacker = null; damageInfo.inflictor = null; damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor; damageInfo.procCoefficient = 0f; damageInfo.procChainMask = default(ProcChainMask); base.healthComponent.TakeDamage(damageInfo); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class Uninitialized : EntityState { } } namespace EntityStates.Wisp1Monster { public class ChargeEmbers : BaseState { public static float baseDuration = 3f; public static GameObject chargeEffectPrefab; public static GameObject laserEffectPrefab; public static string attackString; private float duration; private float stopwatch; private uint soundID; private GameObject chargeEffectInstance; private GameObject laserEffectInstance; private LineRenderer laserEffectInstanceLineRenderer; private bool lineRendererNull; protected EffectManagerHelper _emh_chargeEffect; protected EffectManagerHelper _emh_laserEffect; private UnityEngine.Color startColor = UnityEngine.Color.white; private static int ChargeAttack1StateHash = Animator.StringToHash("ChargeAttack1"); private static int ChargeAttack1ParamHash = Animator.StringToHash("ChargeAttack1.playbackRate"); public override void Reset() { base.Reset(); duration = 0f; chargeEffectInstance = null; laserEffectInstance = null; laserEffectInstanceLineRenderer = null; lineRendererNull = true; _emh_chargeEffect = null; _emh_laserEffect = null; startColor = UnityEngine.Color.white; } public override void OnEnter() { base.OnEnter(); SetAIUpdateFrequency(alwaysUpdate: true); stopwatch = 0f; duration = baseDuration / attackSpeedStat; soundID = Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("Muzzle"); if ((bool)transform) { if ((bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance = _emh_chargeEffect.gameObject; } chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffectInstance.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } if ((bool)laserEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(laserEffectPrefab)) { laserEffectInstance = UnityEngine.Object.Instantiate(laserEffectPrefab, transform.position, transform.rotation); } else { _emh_laserEffect = EffectManager.GetAndActivatePooledEffect(laserEffectPrefab, transform.position, transform.rotation); laserEffectInstance = _emh_laserEffect.gameObject; } laserEffectInstance.transform.parent = transform; laserEffectInstanceLineRenderer = laserEffectInstance.GetComponent(); lineRendererNull = false; } } } } PlayAnimation("Body", ChargeAttack1StateHash, ChargeAttack1ParamHash, duration); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void OnExit() { base.OnExit(); SetAIUpdateFrequency(alwaysUpdate: false); AkSoundEngine.StopPlayingID(soundID); if ((bool)chargeEffectInstance) { if (!EffectManager.UsePools) { EntityState.Destroy(chargeEffectInstance); } else if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null) { _emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect); } else { EntityState.Destroy(chargeEffectInstance); } chargeEffectInstance = null; _emh_chargeEffect = null; } if ((bool)laserEffectInstance) { if (!EffectManager.UsePools) { EntityState.Destroy(laserEffectInstance); } else if (_emh_laserEffect != null && _emh_laserEffect.OwningPool != null) { _emh_laserEffect.OwningPool.ReturnObject(_emh_laserEffect); } else { EntityState.Destroy(laserEffectInstance); } laserEffectInstance = null; _emh_laserEffect = null; lineRendererNull = true; } } public override void Update() { base.Update(); if (!lineRendererNull) { if (!laserEffectInstanceLineRenderer) { lineRendererNull = true; return; } Ray aimRay = GetAimRay(); float distance = 50f; UnityEngine.Vector3 origin = aimRay.origin; UnityEngine.Vector3 point = aimRay.GetPoint(distance); laserEffectInstanceLineRenderer.SetPosition(0, origin); laserEffectInstanceLineRenderer.SetPosition(1, point); startColor.a = stopwatch / duration; laserEffectInstanceLineRenderer.startColor = startColor; laserEffectInstanceLineRenderer.endColor = UnityEngine.Color.clear; } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextState(new FireEmbers()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class DeathState : GenericCharacterDeath { public static GameObject initialExplosion; public override void OnEnter() { base.OnEnter(); if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if (!EffectManager.ShouldUsePooledEffect(initialExplosion)) { UnityEngine.Object.Instantiate(initialExplosion, base.transform.position, base.transform.rotation); } else { EffectManager.SpawnEffect(initialExplosion, new EffectData { origin = base.transform.position, rotation = base.transform.rotation }, transmit: false); } if (NetworkServer.active) { EntityState.Destroy(base.gameObject); } } } public class FireEmbers : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float baseDuration = 2f; public static string attackString; private float duration; private static int FireAttack1StateHash = Animator.StringToHash("FireAttack1"); private static int FireAttack1ParamHash = Animator.StringToHash("FireAttack1.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat); Ray aimRay = GetAimRay(); StartAimMode(aimRay); PlayAnimation("Body", FireAttack1StateHash, FireAttack1ParamHash, duration); string muzzleName = ""; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u); bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleName; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet; bulletAttack.HitEffectNormal = false; bulletAttack.radius = 0.5f; bulletAttack.procCoefficient = 1f / (float)bulletCount; bulletAttack.Fire(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class SpawnState : BaseState { public static float duration = 4f; public static string spawnSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Vulture { public class FallingDeath : GenericCharacterDeath { private Animator animator; private static int isGroundedParamHash = Animator.StringToHash("isGrounded"); public override void OnEnter() { base.OnEnter(); if ((bool)base.characterMotor) { base.characterMotor.velocity.y = 0f; } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)animator) { animator.SetBool(isGroundedParamHash, base.characterMotor.isGrounded); return; } animator = GetModelAnimator(); if ((bool)animator) { int layerIndex = animator.GetLayerIndex("FlyOverride"); animator.SetLayerWeight(layerIndex, 0f); } } } public class VultureModeState : BaseSkillState { [SerializeField] public float mecanimTransitionDuration; [SerializeField] public float flyOverrideMecanimLayerWeight; [SerializeField] public float movementSpeedMultiplier; [SerializeField] public string enterSoundString; protected Animator animator; protected int flyOverrideLayer; protected ICharacterGravityParameterProvider characterGravityParameterProvider; protected ICharacterFlightParameterProvider characterFlightParameterProvider; public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); characterGravityParameterProvider = base.gameObject.GetComponent(); characterFlightParameterProvider = base.gameObject.GetComponent(); if ((bool)animator) { flyOverrideLayer = animator.GetLayerIndex("FlyOverride"); } if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = movementSpeedMultiplier; } if ((bool)base.modelLocator) { base.modelLocator.normalizeToFloor = false; } Util.PlaySound(enterSoundString, base.gameObject); } public override void Update() { base.Update(); if ((bool)animator) { animator.SetLayerWeight(flyOverrideLayer, Util.Remap(Mathf.Clamp01(base.age / mecanimTransitionDuration), 0f, 1f, 1f - flyOverrideMecanimLayerWeight, flyOverrideMecanimLayerWeight)); } } public override void OnExit() { if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = 1f; } base.OnExit(); } } public class Land : VultureModeState { public override void OnEnter() { base.OnEnter(); } } public class Fly : VultureModeState { public static SkillDef landingSkill; public static float launchSpeed; public static GameObject jumpEffectPrefab; public static string jumpEffectMuzzleString; private static int JumpStateHash = Animator.StringToHash("Jump"); public override void OnEnter() { base.OnEnter(); if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount++; characterGravityParameterProvider.gravityParameters = gravityParameters; } if (characterFlightParameterProvider != null) { CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters; flightParameters.channeledFlightGranterCount++; characterFlightParameterProvider.flightParameters = flightParameters; } if ((bool)base.characterMotor) { base.characterMotor.velocity.y = launchSpeed; base.characterMotor.Motor.ForceUnground(); } PlayAnimation("Body", JumpStateHash); if ((bool)base.activatorSkillSlot) { base.activatorSkillSlot.SetSkillOverride(this, landingSkill, GenericSkill.SkillOverridePriority.Contextual); } if ((bool)jumpEffectPrefab) { EffectManager.SimpleMuzzleFlash(jumpEffectPrefab, base.gameObject, jumpEffectMuzzleString, transmit: false); } } public override void OnExit() { if ((bool)base.activatorSkillSlot) { base.activatorSkillSlot.UnsetSkillOverride(this, landingSkill, GenericSkill.SkillOverridePriority.Contextual); } if (characterFlightParameterProvider != null) { CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters; flightParameters.channeledFlightGranterCount--; characterFlightParameterProvider.flightParameters = flightParameters; } if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount--; characterGravityParameterProvider.gravityParameters = gravityParameters; } if ((bool)base.modelLocator) { base.modelLocator.normalizeToFloor = true; } base.OnExit(); } } public class FlyToLand : BaseSkillState { private float duration; private UnityEngine.Vector3 targetPosition; public static float speedMultiplier; private ICharacterGravityParameterProvider characterGravityParameterProvider; private ICharacterFlightParameterProvider characterFlightParameterProvider; public override void OnEnter() { base.OnEnter(); characterGravityParameterProvider = base.gameObject.GetComponent(); characterFlightParameterProvider = base.gameObject.GetComponent(); UnityEngine.Vector3 footPosition = GetFootPosition(); if (base.isAuthority) { bool flag = false; NodeGraph groundNodes = SceneInfo.instance.groundNodes; if ((bool)groundNodes) { NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNodeWithFlagConditions(base.transform.position, base.characterBody.hullClassification, NodeFlags.None, NodeFlags.None, preventOverhead: false); flag = nodeIndex != NodeGraph.NodeIndex.invalid && groundNodes.GetNodePosition(nodeIndex, out targetPosition); } if (!flag) { outer.SetNextState(new Fly { activatorSkillSlot = base.activatorSkillSlot }); duration = 0f; targetPosition = footPosition; return; } } UnityEngine.Vector3 vector = targetPosition - footPosition; float num = moveSpeedStat * speedMultiplier; duration = vector.magnitude / num; if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount++; characterGravityParameterProvider.gravityParameters = gravityParameters; } if (characterFlightParameterProvider != null) { CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters; flightParameters.channeledFlightGranterCount++; characterFlightParameterProvider.flightParameters = flightParameters; } } private UnityEngine.Vector3 GetFootPosition() { if ((bool)base.characterBody) { return base.characterBody.footPosition; } return base.transform.position; } public override void FixedUpdate() { base.FixedUpdate(); UnityEngine.Vector3 footPosition = GetFootPosition(); base.characterMotor.moveDirection = (targetPosition - footPosition).normalized * speedMultiplier; if (base.isAuthority && (base.characterMotor.isGrounded || duration <= base.fixedAge)) { outer.SetNextStateToMain(); } } public override void OnExit() { if (characterFlightParameterProvider != null) { CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters; flightParameters.channeledFlightGranterCount--; characterFlightParameterProvider.flightParameters = flightParameters; } if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount--; characterGravityParameterProvider.gravityParameters = gravityParameters; } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetFloat("Flying", 0f); } base.OnExit(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(targetPosition); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); targetPosition = reader.ReadVector3(); } } public class SpawnState : BaseState { public static float duration = 4f; public static string spawnSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Vulture.Weapon { public class ChargeWindblade : BaseSkillState { public static float baseDuration; public static string muzzleString; public static GameObject chargeEffectPrefab; public static string soundString; private float duration; private GameObject chargeEffectInstance; protected EffectManagerHelper _emh_chargeEffectInstance; private static int ChargeWindbladeStateHash = Animator.StringToHash("ChargeWindblade"); private static int ChargeWindbladeParamHash = Animator.StringToHash("ChargeWindblade.playbackRate"); public override void Reset() { base.Reset(); duration = 0f; chargeEffectInstance = null; _emh_chargeEffectInstance = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", ChargeWindbladeStateHash, ChargeWindbladeParamHash, duration); Util.PlaySound(soundString, base.gameObject); base.characterBody.SetAimTimer(3f); Transform transform = FindModelChild(muzzleString); if ((bool)transform && (bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance = _emh_chargeEffectInstance.gameObject; } chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new FireWindblade()); } } public override void OnExit() { if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null) { _emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance); } else if (chargeEffectInstance != null) { EntityState.Destroy(chargeEffectInstance); } chargeEffectInstance = null; _emh_chargeEffectInstance = null; base.OnExit(); } } public class FireWindblade : BaseSkillState { public static float baseDuration; public static string muzzleString; public static GameObject muzzleEffectPrefab; public static GameObject projectilePrefab; public static float damageCoefficient = 1.2f; public static float force = 20f; public static string soundString; private float duration; private static int FireWindbladeStateHash = Animator.StringToHash("FireWindblade"); private static int FireWindbladeParamHash = Animator.StringToHash("FireWindblade.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", FireWindbladeStateHash, FireWindbladeParamHash, duration); Util.PlaySound(soundString, base.gameObject); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleString, transmit: false); } Ray aimRay = GetAimRay(); if (base.isAuthority) { UnityEngine.Quaternion quaternion = Util.QuaternionSafeLookRotation(aimRay.direction); UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 360f), aimRay.direction); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, quaternion2 * quaternion, base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } } namespace EntityStates.VoidSurvivorPod { public class Descent : SurvivorPodBaseState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && duration < base.fixedAge) { TransitionIntoNextState(); } } protected virtual void TransitionIntoNextState() { outer.SetNextState(new Landed()); } } public class Landed : SurvivorPodBaseState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; [SerializeField] public string effectMuzzle; [SerializeField] public GameObject openEffect; [SerializeField] public string particleChildName; private ParticleSystem[] particles; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); base.vehicleSeat.handleVehicleExitRequestServer.AddCallback(HandleVehicleExitRequest); ModelLocator component = GetComponent(); if (!component || !component.modelTransform) { return; } ChildLocator component2 = component.modelTransform.GetComponent(); if ((bool)component2) { Transform transform = component2.FindChild(particleChildName); if ((bool)transform) { particles = transform.GetComponentsInChildren(); transform.gameObject.SetActive(value: true); } } } public override void FixedUpdate() { if (base.fixedAge > 0f) { base.survivorPodController.exitAllowed = true; } base.FixedUpdate(); } private void HandleVehicleExitRequest(GameObject gameObject, ref bool? result) { base.survivorPodController.exitAllowed = false; outer.SetNextState(new Release()); result = true; } public override void OnExit() { base.vehicleSeat.handleVehicleExitRequestServer.RemoveCallback(HandleVehicleExitRequest); base.survivorPodController.exitAllowed = false; EffectManager.SimpleMuzzleFlash(openEffect, base.gameObject, effectMuzzle, transmit: false); ParticleSystem[] array = particles; for (int i = 0; i < array.Length; i++) { array[i].Stop(); } } } public class Release : SurvivorPodBaseState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; [SerializeField] public float exitForceAmount; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)base.survivorPodController && NetworkServer.active && (bool)base.vehicleSeat && (bool)base.vehicleSeat.currentPassengerBody) { CharacterBody currentPassengerBody = base.vehicleSeat.currentPassengerBody; base.vehicleSeat.EjectPassenger(currentPassengerBody.gameObject); HealthComponent component = currentPassengerBody.GetComponent(); if ((bool)component) { DamageInfo damageInfo = new DamageInfo(); damageInfo.attacker = base.gameObject; damageInfo.force = UnityEngine.Vector3.up * exitForceAmount; damageInfo.position = currentPassengerBody.corePosition; component.TakeDamageForce(damageInfo, alwaysApply: true); } } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (!base.vehicleSeat || !base.vehicleSeat.currentPassengerBody)) { outer.SetNextStateToMain(); } } } } namespace EntityStates.VoidSurvivor { public class CorruptionTransitionBase : BaseState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationGroundStateName; [SerializeField] public string animationAirStateName; [SerializeField] public string animationPlaybackParameterName; [SerializeField] public float animationCrossfadeDuration; [SerializeField] public string entrySound; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public GameObject completionEffectPrefab; [SerializeField] public string effectmuzzle; [SerializeField] public CharacterCameraParams cameraParams; [SerializeField] public float dampingCoefficient; protected VoidSurvivorController voidSurvivorController; private GameObject chargeEffectInstance; private CameraTargetParams.CameraParamsOverrideHandle cameraParamsOverrideHandle; public override void OnEnter() { base.OnEnter(); voidSurvivorController = GetComponent(); PlayCrossfade(animationLayerName, base.characterMotor.isGrounded ? animationGroundStateName : animationAirStateName, animationPlaybackParameterName, duration, animationCrossfadeDuration); Util.PlaySound(entrySound, base.gameObject); if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } StartCameraParamsOverride(duration); Transform transform = FindModelChild(effectmuzzle); if ((bool)transform && (bool)chargeEffectPrefab) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } if (base.isAuthority && (bool)voidSurvivorController) { voidSurvivorController.weaponStateMachine.SetNextStateToMain(); } } public override void OnExit() { EndCameraParamsOverride(0f); if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); } if ((bool)chargeEffectInstance) { EntityState.Destroy(chargeEffectInstance); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { base.characterMotor.velocity -= base.characterMotor.velocity * dampingCoefficient; } if (base.fixedAge >= duration && base.isAuthority) { OnFinishAuthority(); outer.SetNextStateToMain(); } } public virtual void OnFinishAuthority() { EffectManager.SimpleMuzzleFlash(completionEffectPrefab, base.gameObject, effectmuzzle, transmit: true); } protected void StartCameraParamsOverride(float transitionDuration) { if (!cameraParamsOverrideHandle.isValid) { cameraParamsOverrideHandle = base.cameraTargetParams.AddParamsOverride(new CameraTargetParams.CameraParamsOverrideRequest { cameraParamsData = cameraParams.data }, transitionDuration); } } protected void EndCameraParamsOverride(float transitionDuration) { if (cameraParamsOverrideHandle.isValid) { base.cameraTargetParams.RemoveParamsOverride(cameraParamsOverrideHandle, transitionDuration); cameraParamsOverrideHandle = default(CameraTargetParams.CameraParamsOverrideHandle); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class EnterCorruptionTransition : CorruptionTransitionBase { [SerializeField] public float lingeringInvincibilityDuration; public override void FixedUpdate() { base.FixedUpdate(); if ((bool)voidSurvivorController && NetworkServer.active) { voidSurvivorController.AddCorruption(100f); } } public override void OnFinishAuthority() { base.OnFinishAuthority(); if ((bool)voidSurvivorController) { voidSurvivorController.corruptionModeStateMachine.SetNextState(new EntityStates.VoidSurvivor.CorruptMode.CorruptMode()); } } public override void OnExit() { base.OnExit(); if (NetworkServer.active) { base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, lingeringInvincibilityDuration); } } } public class ExitCorruptionTransition : CorruptionTransitionBase { public override void FixedUpdate() { base.FixedUpdate(); if ((bool)voidSurvivorController && NetworkServer.active) { voidSurvivorController.AddCorruption(-100f); } } public override void OnFinishAuthority() { base.OnFinishAuthority(); if ((bool)voidSurvivorController) { voidSurvivorController.corruptionModeStateMachine.SetNextState(new UncorruptedMode()); } } } public class VoidBlinkBase : BaseState { public class VoidBlinkUp : VoidBlinkBase { } public class VoidBlinkDown : VoidBlinkBase { } private Transform modelTransform; [SerializeField] public GameObject blinkEffectPrefab; [SerializeField] public float duration = 0.3f; [SerializeField] public float speedCoefficient = 25f; [SerializeField] public string beginSoundString; [SerializeField] public string endSoundString; [SerializeField] public AnimationCurve forwardSpeed; [SerializeField] public AnimationCurve upSpeed; [SerializeField] public GameObject blinkVfxPrefab; [SerializeField] public float overlayDuration; [SerializeField] public Material overlayMaterial; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private UnityEngine.Vector3 forwardVector; private GameObject blinkVfxInstance; private uint soundID; public override void OnEnter() { base.OnEnter(); base.characterBody.bodyFlags |= CharacterBody.BodyFlags.OverheatImmune; soundID = Util.PlaySound(beginSoundString, base.gameObject); forwardVector = ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized; modelTransform = GetModelTransform(); if ((bool)modelTransform) { characterModel = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); } if ((bool)characterModel) { characterModel.invisibilityCount++; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if (NetworkServer.active) { Util.CleanseBody(base.characterBody, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: false, removeDots: true, removeStun: true, removeNearbyProjectiles: false); } blinkVfxInstance = UnityEngine.Object.Instantiate(blinkVfxPrefab); blinkVfxInstance.transform.SetParent(base.transform, worldPositionStays: false); CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); } protected virtual UnityEngine.Vector3 GetBlinkVector() { return base.inputBank.aimDirection; } private void CreateBlinkEffect(UnityEngine.Vector3 origin) { EffectData effectData = new EffectData(); effectData.rotation = Util.QuaternionSafeLookRotation(GetVelocity()); effectData.origin = origin; EffectManager.SpawnEffect(blinkEffectPrefab, effectData, transmit: false); } private UnityEngine.Vector3 GetVelocity() { float time = base.fixedAge / duration; UnityEngine.Vector3 vector = forwardSpeed.Evaluate(time) * forwardVector; UnityEngine.Vector3 vector2 = upSpeed.Evaluate(time) * UnityEngine.Vector3.up; return (vector + vector2) * speedCoefficient * moveSpeedStat; } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.characterMotor && (bool)base.characterDirection) { if ((bool)base.characterMotor) { base.characterMotor.Motor.ForceUnground(); } UnityEngine.Vector3 velocity = GetVelocity(); base.characterMotor.velocity = velocity; if ((bool)blinkVfxInstance) { blinkVfxInstance.transform.forward = velocity; } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { AkSoundEngine.StopPlayingID(soundID); if (!outer.destroying) { Util.PlaySound(endSoundString, base.gameObject); CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); } if ((bool)blinkVfxInstance) { VfxKillBehavior.KillVfxObject(blinkVfxInstance); } if ((bool)characterModel) { characterModel.invisibilityCount--; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } base.characterBody.bodyFlags &= ~CharacterBody.BodyFlags.OverheatImmune; modelTransform = GetModelTransform(); if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = overlayDuration; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = overlayMaterial; temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent()); } base.OnExit(); } } } namespace EntityStates.VoidSurvivor.Weapon { public class ChargeMegaBlaster : BaseSkillState { [SerializeField] public float minimumDuration = 0.1f; [SerializeField] public float baseDuration = 2f; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string muzzle; [SerializeField] public string chargeSoundString; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; private float duration; private uint soundID; private GameObject chargeEffectInstance; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; soundID = Util.PlayAttackSpeedSound(chargeSoundString, base.gameObject, attackSpeedStat); PlayAnimation(animationLayerName, animationStateName); base.characterBody.SetAimTimer(duration + 1f); Transform transform = FindModelChild(muzzle); if ((bool)transform && (bool)chargeEffectPrefab) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); ObjectScaleCurve component2 = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } if ((bool)component2) { component2.timeMax = duration; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { if (base.fixedAge >= duration) { outer.SetNextState(new ReadyMegaBlaster { activatorSkillSlot = base.activatorSkillSlot }); } else if (!IsKeyDownAuthority() && base.fixedAge > minimumDuration) { outer.SetNextState(new FireMegaBlasterSmall()); } } } public override void OnExit() { if ((bool)chargeEffectInstance) { EntityState.Destroy(chargeEffectInstance); } AkSoundEngine.StopPlayingID(soundID); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ReadyMegaBlaster : BaseSkillState { [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string muzzle; [SerializeField] public string enterSoundString; [SerializeField] public string exitSoundString; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; private GameObject chargeEffectInstance; public override void OnEnter() { base.OnEnter(); Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation(animationLayerName, animationStateName); Transform transform = FindModelChild(muzzle); if ((bool)transform && (bool)chargeEffectPrefab) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; } } public override void FixedUpdate() { base.FixedUpdate(); base.characterBody.SetAimTimer(3f); if (base.isAuthority && !IsKeyDownAuthority()) { outer.SetNextState(new FireMegaBlasterBig()); } } public override void OnExit() { Util.PlaySound(exitSoundString, base.gameObject); if ((bool)chargeEffectInstance) { EntityState.Destroy(chargeEffectInstance); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireMegaBlasterSmall : FireMegaBlasterBase { } public class FireMegaBlasterBig : FireMegaBlasterBase { } public class FireMegaBlasterBase : BaseState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float baseDuration = 2f; [SerializeField] public float damageCoefficient = 1.2f; [SerializeField] public float force = 20f; [SerializeField] public string attackSoundString; [SerializeField] public float recoilAmplitude; [SerializeField] public float bloom; [SerializeField] public string muzzle; [SerializeField] public float spread; [SerializeField] public float yawPerProjectile; [SerializeField] public float selfKnockbackForce; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private float duration; public override void OnEnter() { base.OnEnter(); Ray aimRay = GetAimRay(); duration = baseDuration / attackSpeedStat; StartAimMode(duration + 2f); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(attackSoundString, base.gameObject); AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude); base.characterBody.AddSpreadBloom(bloom); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } if (base.isAuthority) { FireProjectiles(); } base.characterBody.characterMotor.ApplyForce((0f - selfKnockbackForce) * aimRay.direction); } private void FireProjectiles() { Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); ray.direction = Util.ApplySpread(ray.direction, 0f, spread, 1f, 1f); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = ray.origin; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = force; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ChargeCorruptHandBeam : BaseSkillState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public float baseDuration = 2f; [SerializeField] public string muzzle; [SerializeField] public string enterSoundString; [SerializeField] public GameObject muzzleflashEffectPrefab; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; GetAimRay(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); base.characterBody.SetAimTimer(3f); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { outer.SetNextState(new FireCorruptHandBeam { activatorSkillSlot = base.activatorSkillSlot }); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireCorruptHandBeam : BaseSkillState { [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public GameObject hitEffectPrefab; [SerializeField] public GameObject beamVfxPrefab; [SerializeField] public string enterSoundString; [SerializeField] public string exitSoundString; [SerializeField] public float tickRate; [SerializeField] public float damageCoefficientPerSecond; [SerializeField] public float procCoefficientPerSecond; [SerializeField] public float forcePerSecond; [SerializeField] public float maxDistance; [SerializeField] public float minDistance; [SerializeField] public float bulletRadius; [SerializeField] public float baseMinimumDuration = 2f; [SerializeField] public float recoilAmplitude; [SerializeField] public float spreadBloomValue = 0.3f; [SerializeField] public float maxSpread; [SerializeField] public string muzzle; [SerializeField] public string animationLayerName; [SerializeField] public string animationEnterStateName; [SerializeField] public string animationExitStateName; private GameObject blinkVfxInstance; private float minimumDuration; private float fireCountdown; public override void OnEnter() { base.OnEnter(); minimumDuration = baseMinimumDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationEnterStateName); Util.PlaySound(enterSoundString, base.gameObject); blinkVfxInstance = UnityEngine.Object.Instantiate(beamVfxPrefab); blinkVfxInstance.transform.SetParent(base.characterBody.aimOriginTransform, worldPositionStays: false); if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.Slow50); } } public override void FixedUpdate() { base.FixedUpdate(); fireCountdown -= GetDeltaTime(); if (fireCountdown <= 0f) { fireCountdown = 1f / tickRate / attackSpeedStat; FireBullet(); } base.characterBody.SetAimTimer(3f); if ((bool)blinkVfxInstance) { UnityEngine.Vector3 point = GetAimRay().GetPoint(maxDistance); if (Util.CharacterRaycast(base.gameObject, GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.UseGlobal)) { point = hitInfo.point; } blinkVfxInstance.transform.forward = point - blinkVfxInstance.transform.position; } if (((base.fixedAge >= minimumDuration && !IsKeyDownAuthority()) || base.characterBody.isSprinting) && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if ((bool)blinkVfxInstance) { VfxKillBehavior.KillVfxObject(blinkVfxInstance); } if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.Slow50); } PlayAnimation(animationLayerName, animationExitStateName); Util.PlaySound(exitSoundString, base.gameObject); base.OnExit(); } private void FireBullet() { Ray aimRay = GetAimRay(); AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.muzzleName = muzzle; bulletAttack.maxDistance = Mathf.Lerp(minDistance, maxDistance, UnityEngine.Random.value); bulletAttack.minSpread = 0f; bulletAttack.maxSpread = maxSpread; bulletAttack.radius = bulletRadius; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.smartCollision = false; bulletAttack.stopperMask = default(LayerMask); bulletAttack.hitMask = LayerIndex.entityPrecise.mask; bulletAttack.allowTrajectoryAimAssist = false; bulletAttack.damage = damageCoefficientPerSecond * damageStat / tickRate; bulletAttack.procCoefficient = procCoefficientPerSecond / tickRate; bulletAttack.force = forcePerSecond / tickRate; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.Fire(); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ChargeCrabCannon : BaseSkillState { [SerializeField] public float baseDurationPerGrenade; [SerializeField] public float minimumDuration; [SerializeField] public string muzzle; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string chargeStockSoundString; [SerializeField] public string chargeLoopStartSoundString; [SerializeField] public string chargeLoopStopSoundString; [SerializeField] public float bloomPerGrenade; [SerializeField] public float corruptionPerGrenade; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; private VoidSurvivorController voidSurvivorController; private GameObject chargeEffectInstance; private int grenadeCount; private int lastGrenadeCount; private float durationPerGrenade; private float nextGrenadeStopwatch; private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty"); public override void OnEnter() { base.OnEnter(); voidSurvivorController = GetComponent(); PlayAnimation(animationLayerName, animationStateName); durationPerGrenade = baseDurationPerGrenade / attackSpeedStat; Util.PlaySound(chargeLoopStartSoundString, base.gameObject); AddGrenade(); Transform modelTransform = GetModelTransform(); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild(muzzle); if ((bool)transform && (bool)chargeEffectPrefab) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffectInstance.GetComponent(); if ((bool)component2) { component2.newDuration = durationPerGrenade; } } } public override void OnExit() { base.OnExit(); Util.PlaySound(chargeLoopStopSoundString, base.gameObject); PlayAnimation(animationLayerName, BufferEmptyStateHash); EntityState.Destroy(chargeEffectInstance); } private void AddGrenade() { grenadeCount++; if ((bool)voidSurvivorController && NetworkServer.active) { voidSurvivorController.AddCorruption(corruptionPerGrenade); } } public override void FixedUpdate() { base.FixedUpdate(); base.characterBody.SetAimTimer(3f); nextGrenadeStopwatch += GetDeltaTime(); if (nextGrenadeStopwatch > durationPerGrenade && base.activatorSkillSlot.stock > 0) { AddGrenade(); nextGrenadeStopwatch -= durationPerGrenade; base.activatorSkillSlot.DeductStock(1); } float value = bloomPerGrenade * (float)lastGrenadeCount; base.characterBody.SetSpreadBloom(value); if (lastGrenadeCount < grenadeCount) { Util.PlaySound(chargeStockSoundString, base.gameObject); } if (!IsKeyDownAuthority() && base.fixedAge > minimumDuration / attackSpeedStat && base.isAuthority) { FireCrabCannon fireCrabCannon = new FireCrabCannon(); fireCrabCannon.grenadeCountMax = grenadeCount; outer.SetNextState(fireCrabCannon); } else { lastGrenadeCount = grenadeCount; } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireCrabCannon : BaseState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public GameObject projectilePrefab; [SerializeField] public string muzzle; [SerializeField] public int grenadeCountMax = 3; [SerializeField] public float damageCoefficient; [SerializeField] public float maxSpread; [SerializeField] public float fireDuration = 1f; [SerializeField] public float baseDuration = 2f; [SerializeField] private static float recoilAmplitude = 1f; [SerializeField] public string enterSoundString; [SerializeField] public string perGrenadeSoundString; [SerializeField] public float spreadBloomValue = 0.3f; private Transform modelTransform; private float duration; private float fireTimer; private int grenadeCount; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelTransform = GetModelTransform(); StartAimMode(); } public override void OnExit() { base.OnExit(); } private void FireProjectile() { PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(perGrenadeSoundString, base.gameObject); AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); base.characterBody.AddSpreadBloom(spreadBloomValue); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } if (base.isAuthority) { Ray aimRay = GetAimRay(); aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, maxSpread, 1f, 1f); UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere; UnityEngine.Vector3.ProjectOnPlane(onUnitSphere, aimRay.direction); UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(aimRay.direction, onUnitSphere); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, rotation, base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void FixedUpdate() { base.FixedUpdate(); fireTimer -= GetDeltaTime(); float num = fireDuration / attackSpeedStat / (float)grenadeCountMax; if (fireTimer <= 0f && grenadeCount < grenadeCountMax) { FireProjectile(); fireTimer += num; grenadeCount++; } if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ChargeCrushBase : BaseSkillState { [SerializeField] public float baseDuration = 2f; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string muzzle; [SerializeField] public string chargeSoundString; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackParameterName; protected float duration; private uint soundID; private GameObject chargeEffectInstance; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; soundID = Util.PlayAttackSpeedSound(chargeSoundString, base.gameObject, attackSpeedStat); PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, duration); base.characterBody.SetAimTimer(duration + 1f); Transform transform = FindModelChild(muzzle); if ((bool)transform && (bool)chargeEffectPrefab) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); ObjectScaleCurve component2 = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } if ((bool)component2) { component2.timeMax = duration; } } } public override void OnExit() { if ((bool)chargeEffectInstance) { EntityState.Destroy(chargeEffectInstance); } AkSoundEngine.StopPlayingID(soundID); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class CrushBase : BaseState { [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float baseDuration = 2f; [SerializeField] public string enterSoundString; [SerializeField] public float recoilAmplitude; [SerializeField] public float bloom; [SerializeField] public string muzzle; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public float selfHealFraction; [SerializeField] public float corruptionChange; private float duration; public override void OnEnter() { base.OnEnter(); GetAimRay(); duration = baseDuration / attackSpeedStat; StartAimMode(duration + 2f); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude); base.characterBody.AddSpreadBloom(bloom); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } if (NetworkServer.active) { ProcChainMask procChainMask = default(ProcChainMask); procChainMask.AddProc(ProcType.VoidSurvivorCrush); if (selfHealFraction > 0f) { base.healthComponent.HealFraction(selfHealFraction, procChainMask); } else { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = (0f - base.healthComponent.fullCombinedHealth) * selfHealFraction; damageInfo.position = base.characterBody.corePosition; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.damageColorIndex = DamageColorIndex.Default; damageInfo.crit = false; damageInfo.attacker = null; damageInfo.inflictor = null; damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor; damageInfo.procCoefficient = 0f; damageInfo.procChainMask = procChainMask; base.healthComponent.TakeDamage(damageInfo); } VoidSurvivorController component = GetComponent(); if ((bool)component) { component.AddCorruption(corruptionChange); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ChargeCrushCorruption : ChargeCrushBase { public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new CrushCorruption()); } } } public class ChargeCrushHealth : ChargeCrushBase { public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new CrushHealth()); } } } public class CrushCorruption : CrushBase { } public class CrushHealth : CrushBase { } public class FireBlasterBase : BaseSkillState, SteppedSkillDef.IStepSetter { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float baseDuration = 2f; [SerializeField] public float damageCoefficient = 1.2f; [SerializeField] public float force = 20f; [SerializeField] public string attackSoundString; [SerializeField] public float attackSoundPitchPerStep; [SerializeField] public float recoilAmplitude; [SerializeField] public float bloom; [SerializeField] public string muzzle; [SerializeField] public float spread; [SerializeField] public int projectileCount; [SerializeField] public float yawPerProjectile; [SerializeField] public float offsetPerProjectile; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public int burstCount; [SerializeField] public bool canCharge; private float duration; private float interruptDuration; public int step; void SteppedSkillDef.IStepSetter.SetStep(int i) { step = i; } public override void OnEnter() { base.OnEnter(); base.activatorSkillSlot = base.skillLocator.primary; GetAimRay(); duration = baseDuration / attackSpeedStat; StartAimMode(duration + 2f); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, 1f + (float)step * attackSoundPitchPerStep); AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude); base.characterBody.AddSpreadBloom(bloom); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } if (base.isAuthority) { FireProjectiles(); } } private void FireProjectiles() { for (int i = 0; i < projectileCount; i++) { float num = (float)i - (float)(projectileCount - 1) / 2f; float bonusYaw = num * yawPerProjectile; float num2 = num * offsetPerProjectile; Ray aimRay = GetAimRay(); aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, base.characterBody.spreadBloomAngle + spread, 1f, 1f, bonusYaw); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = aimRay.origin + UnityEngine.Vector3.Cross(aimRay.direction, UnityEngine.Vector3.up) * num2; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(aimRay.direction); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = force; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { if (step >= burstCount && IsKeyDownAuthority() && canCharge) { outer.SetNextState(new ChargeMegaBlaster()); } else { outer.SetNextState(new Idle()); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)step); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); step = reader.ReadByte(); } } public class FireBlaster1 : FireBlasterBase { } public class FireBlaster2 : FireBlasterBase { } public class FireBlaster3 : FireBlasterBase { } public class FireBlaster4 : FireBlasterBase { } public class FireCorruptDisks : BaseSkillState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float baseDuration = 2f; [SerializeField] public float damageCoefficient = 1.2f; [SerializeField] public float force = 20f; [SerializeField] public string attackSoundString; [SerializeField] public float recoilAmplitude; [SerializeField] public float bloom; [SerializeField] public string muzzle; [SerializeField] public float spread; [SerializeField] public int projectileCount; [SerializeField] public float yawPerProjectile; [SerializeField] public float offsetPerProjectile; [SerializeField] public float selfKnockbackForce; [SerializeField] public float bonusPitch; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private float duration; public override void OnEnter() { base.OnEnter(); Ray aimRay = GetAimRay(); duration = baseDuration / attackSpeedStat; StartAimMode(duration + 2f); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(attackSoundString, base.gameObject); AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude); base.characterBody.AddSpreadBloom(bloom); base.characterBody.characterMotor.ApplyForce((0f - selfKnockbackForce) * aimRay.direction); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } if (base.isAuthority) { FireProjectiles(); } } private void FireProjectiles() { for (int i = 0; i < projectileCount; i++) { float num = (float)i - (float)(projectileCount - 1) / 2f; float bonusYaw = num * yawPerProjectile; float num2 = num * offsetPerProjectile; Ray aimRay = GetAimRay(); aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, base.characterBody.spreadBloomAngle + spread, 1f, 1f, bonusYaw, bonusPitch); UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere; UnityEngine.Vector3.ProjectOnPlane(onUnitSphere, aimRay.direction); UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(aimRay.direction, onUnitSphere); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = aimRay.origin + UnityEngine.Vector3.Cross(aimRay.direction, UnityEngine.Vector3.up) * num2; fireProjectileInfo.rotation = rotation; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = force; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new Idle()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireRepulsion : BaseState { [SerializeField] public string sound; [SerializeField] public string muzzle; [SerializeField] public GameObject fireEffectPrefab; [SerializeField] public float baseDuration; [SerializeField] public float fieldOfView; [SerializeField] public float backupDistance; [SerializeField] public float maxKnockbackDistance; [SerializeField] public float idealDistanceToPlaceTargets; [SerializeField] public float liftVelocity; [SerializeField] public float animationCrossfadeDuration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackParameterName; [SerializeField] public float damageMultiplier; [SerializeField] public float maxProjectileReflectDistance; [SerializeField] public GameObject tracerEffectPrefab; [SerializeField] public float corruption; [SerializeField] public BuffDef buffDef; [SerializeField] public float buffDuration; public static AnimationCurve shoveSuitabilityCurve; private float duration; private Ray aimRay; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; aimRay = GetAimRay(); PlayCrossfade(animationLayerName, animationStateName, animationPlaybackParameterName, duration, animationCrossfadeDuration); Util.PlaySound(sound, base.gameObject); UnityEngine.Vector3 origin = aimRay.origin; Transform transform = FindModelChild(muzzle); if ((bool)transform) { origin = transform.position; } EffectManager.SpawnEffect(fireEffectPrefab, new EffectData { origin = origin, rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction) }, transmit: false); aimRay.origin -= aimRay.direction * backupDistance; if (NetworkServer.active) { PushEnemies(); ReflectProjectiles(); VoidSurvivorController component = GetComponent(); if ((bool)component) { component.AddCorruption(corruption); } } } private void ReflectProjectiles() { UnityEngine.Vector3 vector = (base.characterBody ? base.characterBody.corePosition : UnityEngine.Vector3.zero); TeamIndex teamIndex = (base.characterBody ? base.characterBody.teamComponent.teamIndex : TeamIndex.None); float num = maxProjectileReflectDistance * maxProjectileReflectDistance; List instancesList = InstanceTracker.GetInstancesList(); List list = new List(); int i = 0; for (int count = instancesList.Count; i < count; i++) { ProjectileController projectileController = instancesList[i]; if (projectileController.teamFilter.teamIndex != teamIndex && (projectileController.transform.position - vector).sqrMagnitude < num) { list.Add(projectileController); } } int j = 0; for (int count2 = list.Count; j < count2; j++) { ProjectileController projectileController2 = list[j]; if (!projectileController2) { continue; } UnityEngine.Vector3 position = projectileController2.transform.position; UnityEngine.Vector3 start = vector; if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = position, start = start }; EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } _ = projectileController2.owner; CharacterBody component = projectileController2.owner.GetComponent(); projectileController2.IgnoreCollisionsWithOwner(shouldIgnore: false); projectileController2.Networkowner = base.gameObject; projectileController2.teamFilter.teamIndex = base.characterBody.teamComponent.teamIndex; ProjectileDamage component2 = projectileController2.GetComponent(); if ((bool)component2) { component2.damage *= damageMultiplier; } Rigidbody component3 = projectileController2.GetComponent(); if ((bool)component3) { UnityEngine.Vector3 vector2 = component3.velocity * -1f; if ((bool)component) { vector2 = component.corePosition - component3.transform.position; } component3.transform.forward = vector2; component3.velocity = UnityEngine.Vector3.RotateTowards(component3.velocity, vector2, float.PositiveInfinity, 0f); } } } private void PushEnemies() { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.all; bullseyeSearch.maxAngleFilter = fieldOfView * 0.5f; bullseyeSearch.maxDistanceFilter = maxKnockbackDistance; bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.filterByLoS = false; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); IEnumerable enumerable = bullseyeSearch.GetResults().Where(Util.IsValid).Distinct(default(HurtBox.EntityEqualityComparer)); TeamIndex team = GetTeam(); foreach (HurtBox item in enumerable) { if (FriendlyFireManager.ShouldSplashHitProceed(item.healthComponent, team)) { CharacterBody body = item.healthComponent.body; AddDebuff(body); body.RecalculateStats(); _ = body.acceleration; } } } protected virtual void AddDebuff(CharacterBody body) { body.AddTimedBuff(buffDef, buffDuration); body.healthComponent.GetComponent()?.SetStun(-1f); } protected virtual float CalculateDamage() { return 0f; } protected virtual float CalculateProcCoefficient() { return 0f; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireTwinBlaster : BaseSkillState { [SerializeField] public GameObject projectile1Prefab; [SerializeField] public GameObject projectile2Prefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float baseDuration = 2f; [SerializeField] public float damageCoefficient = 1.2f; [SerializeField] public float force = 20f; [SerializeField] public string attackSoundString; [SerializeField] public float attackSoundPitchPerStep; [SerializeField] public float recoilAmplitude; [SerializeField] public float bloom; [SerializeField] public string muzzle; [SerializeField] public float spread; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private float duration; private float interruptDuration; public int step; public override void OnEnter() { base.OnEnter(); base.activatorSkillSlot = base.skillLocator.primary; GetAimRay(); duration = baseDuration / attackSpeedStat; StartAimMode(duration + 2f); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, 1f + (float)step * attackSoundPitchPerStep); AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude); base.characterBody.AddSpreadBloom(bloom); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } if (base.isAuthority) { FireProjectiles(); } } private void FireProjectiles() { Ray aimRay = GetAimRay(); aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, base.characterBody.spreadBloomAngle * spread, 1f, 1f); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.position = aimRay.origin; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(aimRay.direction); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = force; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); fireProjectileInfo.projectilePrefab = projectile1Prefab; ProjectileManager.instance.FireProjectile(fireProjectileInfo); fireProjectileInfo.projectilePrefab = projectile2Prefab; ProjectileManager.instance.FireProjectile(fireProjectileInfo); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ChargeHandBeam : BaseState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public float baseDuration = 2f; [SerializeField] public string muzzle; [SerializeField] public string enterSoundString; [SerializeField] public GameObject muzzleflashEffectPrefab; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; GetAimRay(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); base.characterBody.SetAimTimer(3f); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { outer.SetNextState(new FireHandBeam()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireHandBeam : BaseState { [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public GameObject hitEffectPrefab; [SerializeField] public GameObject tracerEffectPrefab; [SerializeField] public float damageCoefficient; [SerializeField] public float maxDistance; [SerializeField] public float force; [SerializeField] public int bulletCount; [SerializeField] public float bulletRadius; [SerializeField] public float baseDuration = 2f; [SerializeField] public string attackSoundString; [SerializeField] public float recoilAmplitude; [SerializeField] public float spreadBloomValue = 0.3f; [SerializeField] public float maxSpread; [SerializeField] public string muzzle; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public float trajectoryAimAssistMultiplier = 0.75f; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Ray aimRay = GetAimRay(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude); StartAimMode(aimRay); Util.PlaySound(attackSoundString, base.gameObject); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.muzzleName = muzzle; bulletAttack.maxDistance = maxDistance; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = base.characterBody.spreadBloomAngle; bulletAttack.radius = bulletRadius; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.smartCollision = true; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.procCoefficient = 1f / (float)bulletCount; bulletAttack.force = force; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.damageType = DamageType.SlowOnHit; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.trajectoryAimAssistMultiplier = trajectoryAimAssistMultiplier; bulletAttack.Fire(); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Suppress : BaseSkillState { [SerializeField] public float minimumDuration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public float maxSearchAngleFilter; [SerializeField] public float maxSearchDistance; [SerializeField] public float idealDistance; [SerializeField] public float springConstant; [SerializeField] public float springMaxLength; [SerializeField] public float damperConstant; [SerializeField] public float suppressedTargetForceRadius; [SerializeField] public GameObject suppressEffectPrefab; [SerializeField] public string muzzle; [SerializeField] public AnimationCurve forceSuitabilityCurve; [SerializeField] public float damageCoefficientPerSecond; [SerializeField] public float procCoefficientPerSecond; [SerializeField] public float corruptionPerSecond; [SerializeField] public float maxBreakDistance; [SerializeField] public float tickRate; [SerializeField] public bool applyForces; private GameObject suppressEffectInstance; private Transform idealFXTransform; private Transform targetFXTransform; private Transform muzzleTransform; private VoidSurvivorController voidSurvivorController; private CharacterBody targetBody; private float damageTickCountdown; public override void OnEnter() { base.OnEnter(); targetBody = null; voidSurvivorController = GetComponent(); PlayAnimation(animationLayerName, animationStateName); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { muzzleTransform = component.FindChild(muzzle); if ((bool)muzzleTransform && (bool)suppressEffectPrefab) { suppressEffectInstance = UnityEngine.Object.Instantiate(suppressEffectPrefab, muzzleTransform.position, muzzleTransform.rotation); suppressEffectInstance.transform.parent = base.characterBody.transform; ChildLocator component2 = suppressEffectInstance.GetComponent(); if ((bool)component2) { idealFXTransform = component2.FindChild("IdealFX"); targetFXTransform = component2.FindChild("TargetFX"); } } } } Ray aimRay = GetAimRay(); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam()); bullseyeSearch.maxAngleFilter = maxSearchAngleFilter; bullseyeSearch.maxDistanceFilter = maxSearchDistance; bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.filterByLoS = true; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); if ((bool)hurtBox) { UnityEngine.Debug.LogFormat("Found target {0}", targetBody); targetBody = hurtBox.healthComponent.body; } } public override void OnExit() { if ((bool)suppressEffectInstance) { EntityState.Destroy(suppressEffectInstance); } base.OnExit(); } public override void Update() { base.Update(); if ((bool)targetBody) { if ((bool)muzzleTransform) { suppressEffectInstance.transform.position = muzzleTransform.position; } if ((bool)idealFXTransform) { Ray aimRay = GetAimRay(); _ = targetBody.corePosition; UnityEngine.Vector3 position = aimRay.origin + aimRay.direction * idealDistance; idealFXTransform.position = position; } if ((bool)targetFXTransform) { targetFXTransform.position = targetBody.corePosition; } } } public override void FixedUpdate() { base.FixedUpdate(); base.characterBody.SetAimTimer(3f); float deltaTime = GetDeltaTime(); if (NetworkServer.active && (bool)targetBody) { Ray aimRay = GetAimRay(); UnityEngine.Vector3 corePosition = targetBody.corePosition; UnityEngine.Vector3 vector = aimRay.origin + aimRay.direction * idealDistance; if (applyForces) { UnityEngine.Vector3 vector2 = vector - corePosition; float magnitude = vector2.magnitude; Mathf.Clamp01(magnitude / suppressedTargetForceRadius); UnityEngine.Vector3 velocity; float mass; bool flag; if ((bool)targetBody.characterMotor) { velocity = targetBody.characterMotor.velocity; mass = targetBody.characterMotor.mass; flag = !targetBody.characterMotor.isFlying; } else { Rigidbody obj = targetBody.rigidbody; velocity = obj.velocity; mass = obj.mass; flag = obj.useGravity; } UnityEngine.Vector3 vector3 = vector2.normalized * Mathf.Min(springMaxLength, magnitude) * springConstant * deltaTime; UnityEngine.Vector3 vector4 = -velocity * damperConstant * deltaTime; UnityEngine.Vector3 vector5 = (flag ? (Physics.gravity * deltaTime * mass) : UnityEngine.Vector3.zero); float num = forceSuitabilityCurve.Evaluate(mass); targetBody.healthComponent.TakeDamageForce((vector3 + vector4) * num - vector5, alwaysApply: true, disableAirControlUntilCollision: true); } damageTickCountdown -= deltaTime; if (damageTickCountdown <= 0f) { damageTickCountdown = 1f / tickRate; DamageInfo damageInfo = new DamageInfo(); damageInfo.attacker = base.gameObject; damageInfo.procCoefficient = procCoefficientPerSecond / tickRate; damageInfo.damage = damageCoefficientPerSecond * damageStat / tickRate; damageInfo.crit = RollCrit(); targetBody.healthComponent.TakeDamage(damageInfo); voidSurvivorController.AddCorruption(corruptionPerSecond / tickRate); } } if (base.isAuthority && (!targetBody || !targetBody.healthComponent.alive)) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class EnterSwingMelee : BaseState, SteppedSkillDef.IStepSetter { public int step; void SteppedSkillDef.IStepSetter.SetStep(int i) { step = i; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)step); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); step = reader.ReadByte(); } public override void OnEnter() { base.OnEnter(); switch (step) { case 0: outer.SetNextState(new SwingMelee1()); break; case 1: outer.SetNextState(new SwingMelee2()); break; case 2: outer.SetNextState(new SwingMelee3()); break; default: outer.SetNextState(new SwingMelee1()); break; } } } public class SwingMeleeBase : BasicMeleeAttack { [SerializeField] public float recoilAmplitude; [SerializeField] public float bloom; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParameter; protected override bool allowExitFire { get { if ((bool)base.characterBody) { return !base.characterBody.isSprinting; } return false; } } public override void OnEnter() { base.OnEnter(); base.characterDirection.forward = GetAimRay().direction; } public override void OnExit() { base.OnExit(); } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); } protected override void PlayAnimation() { PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParameter, duration); } protected override void OnMeleeHitAuthority() { base.OnMeleeHitAuthority(); base.characterBody.AddSpreadBloom(bloom); } protected override void BeginMeleeAttackEffect() { AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); base.BeginMeleeAttackEffect(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class SwingMelee1 : SwingMeleeBase { } public class SwingMelee2 : SwingMeleeBase { } public class SwingMelee3 : SwingMeleeBase { } } namespace EntityStates.VoidSurvivor.Vent { public class VentCorruption : GenericCharacterMain { [SerializeField] public float minimumDuration; [SerializeField] public float maximumDuration; [SerializeField] public string leftVentEffectChildLocatorEntry; [SerializeField] public string rightVentEffectChildLocatorEntry; [SerializeField] public string miniVentEffectChildLocatorEntry; [SerializeField] public string enterSoundString; [SerializeField] public string exitSoundString; [SerializeField] public float animationCrossfadeDuration; [SerializeField] public string animationLayerName; [SerializeField] public string enterAnimationStateName; [SerializeField] public string exitAnimationStateName; [SerializeField] public float hoverVelocity; [SerializeField] public float hoverAcceleration; [SerializeField] public float healingPercentagePerSecond; [SerializeField] public float healingTickRate; [SerializeField] public float corruptionReductionPerSecond; [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public float turnSpeed; private float healPerTick; private float healTickStopwatch; private float corruptionReductionPerTick; private UnityEngine.Vector3 liftVector = UnityEngine.Vector3.up; private VoidSurvivorController voidSurvivorController; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private float previousTurnSpeed; public override void OnEnter() { base.OnEnter(); voidSurvivorController = GetComponent(); voidSurvivorController = GetComponent(); Util.PlaySound(enterSoundString, base.gameObject); PlayCrossfade(animationLayerName, enterAnimationStateName, animationCrossfadeDuration); healPerTick = base.healthComponent.fullHealth * healingPercentagePerSecond / healingTickRate; corruptionReductionPerTick = corruptionReductionPerSecond / healingTickRate; FindModelChild(leftVentEffectChildLocatorEntry)?.gameObject.SetActive(value: true); FindModelChild(rightVentEffectChildLocatorEntry)?.gameObject.SetActive(value: true); FindModelChild(miniVentEffectChildLocatorEntry)?.gameObject.SetActive(value: true); if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } if ((bool)base.characterDirection) { previousTurnSpeed = base.characterDirection.turnSpeed; base.characterDirection.turnSpeed = turnSpeed; } } public override void FixedUpdate() { base.FixedUpdate(); base.characterBody.SetAimTimer(1f); if (NetworkServer.active) { healTickStopwatch += GetDeltaTime(); if (healTickStopwatch > 1f / healingTickRate) { healTickStopwatch -= 1f / healingTickRate; base.healthComponent.Heal(healPerTick, default(ProcChainMask)); if ((bool)voidSurvivorController) { voidSurvivorController.AddCorruption(0f - corruptionReductionPerTick); } } } if (!base.isAuthority) { return; } if ((bool)base.characterMotor) { float y = base.characterMotor.velocity.y; if (y < hoverVelocity) { y = Mathf.MoveTowards(y, hoverVelocity, hoverAcceleration * GetDeltaTime()); base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, y, base.characterMotor.velocity.z); } } if (base.fixedAge >= maximumDuration || (base.fixedAge >= minimumDuration && (bool)voidSurvivorController && voidSurvivorController.corruption <= voidSurvivorController.minimumCorruption)) { outer.SetNextStateToMain(); } } protected override bool CanExecuteSkill(GenericSkill skillSlot) { return false; } public override void OnExit() { if ((bool)base.characterDirection) { base.characterDirection.turnSpeed = previousTurnSpeed; } crosshairOverrideRequest?.Dispose(); FindModelChild(leftVentEffectChildLocatorEntry)?.gameObject.SetActive(value: false); FindModelChild(rightVentEffectChildLocatorEntry)?.gameObject.SetActive(value: false); FindModelChild(miniVentEffectChildLocatorEntry)?.gameObject.SetActive(value: false); PlayCrossfade(animationLayerName, exitAnimationStateName, animationCrossfadeDuration); Util.PlaySound(exitSoundString, base.gameObject); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.VoidSurvivor.CorruptMode { public class CorruptModeBase : BaseState { protected VoidSurvivorController voidSurvivorController; public override void OnEnter() { base.OnEnter(); voidSurvivorController = GetComponent(); } } public class CorruptMode : CorruptModeBase { [SerializeField] public SkillDef primaryOverrideSkillDef; [SerializeField] public SkillDef secondaryOverrideSkillDef; [SerializeField] public SkillDef utilityOverrideSkillDef; [SerializeField] public SkillDef specialOverrideSkillDef; public override void OnEnter() { base.OnEnter(); if (base.isAuthority && (bool)base.skillLocator) { base.skillLocator.primary.SetSkillOverride(this, primaryOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade); base.skillLocator.secondary.SetSkillOverride(this, secondaryOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade); base.skillLocator.utility.SetSkillOverride(this, utilityOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade); base.skillLocator.special.SetSkillOverride(this, specialOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade); } if ((bool)voidSurvivorController && NetworkServer.active) { base.characterBody.AddBuff(voidSurvivorController.corruptedBuffDef); } } public override void OnExit() { if (base.isAuthority && (bool)base.skillLocator) { base.skillLocator.primary.UnsetSkillOverride(this, primaryOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade); base.skillLocator.secondary.UnsetSkillOverride(this, secondaryOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade); base.skillLocator.utility.UnsetSkillOverride(this, utilityOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade); base.skillLocator.special.UnsetSkillOverride(this, specialOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade); } if ((bool)voidSurvivorController && NetworkServer.active) { base.characterBody.RemoveBuff(voidSurvivorController.corruptedBuffDef); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && (bool)voidSurvivorController && voidSurvivorController.corruption <= voidSurvivorController.minimumCorruption && !voidSurvivorController.isPermanentlyCorrupted && (bool)voidSurvivorController.bodyStateMachine) { voidSurvivorController.bodyStateMachine.SetInterruptState(new ExitCorruptionTransition(), InterruptPriority.Skill); } } } public class UncorruptedMode : CorruptModeBase { public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && (bool)voidSurvivorController && voidSurvivorController.corruption >= voidSurvivorController.maxCorruption && (bool)voidSurvivorController.bodyStateMachine) { voidSurvivorController.bodyStateMachine.SetInterruptState(new EnterCorruptionTransition(), InterruptPriority.Skill); } } } } namespace EntityStates.VoidRaidCrab { public class BaseWardWipeState : BaseState { [SerializeField] public GameObject safeWardDisappearEffectPrefab; protected List safeWards = new List(); protected FogDamageController fogDamageController; public override void ModifyNextState(EntityState nextState) { base.ModifyNextState(nextState); if (nextState is BaseWardWipeState baseWardWipeState) { baseWardWipeState.fogDamageController = fogDamageController; baseWardWipeState.safeWards = safeWards; return; } if ((bool)fogDamageController) { fogDamageController.enabled = false; } if (safeWards == null || !NetworkServer.active) { return; } foreach (GameObject safeWard in safeWards) { if ((bool)fogDamageController) { IZone component = safeWard.GetComponent(); fogDamageController.RemoveSafeZone(component); } if ((bool)safeWardDisappearEffectPrefab) { EffectData effectData = new EffectData(); effectData.origin = safeWard.transform.position; EffectManager.SpawnEffect(safeWardDisappearEffectPrefab, effectData, transmit: true); } EntityState.Destroy(safeWard); } } } public class ChannelGauntlet : BaseState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; [SerializeField] public GameObject overlayPrefab; [SerializeField] public string overlayChildLocatorEntryName; [SerializeField] public string fillImageChildLocatorEntryName; private List overlayControllers; private HashSet overlayFillImages; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Player); overlayControllers = new List(); overlayFillImages = new HashSet(); foreach (TeamComponent item in teamMembers) { OverlayController overlayController = HudOverlayManager.AddOverlay(item.gameObject, new OverlayCreationParams { prefab = overlayPrefab, childLocatorEntry = overlayChildLocatorEntryName }); overlayController.onInstanceAdded += OnOverlayInstanceAdded; overlayController.onInstanceRemove += OnOverlayInstanceRemoved; overlayControllers.Add(overlayController); } } private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance) { if (!instance) { return; } ChildLocator component = instance.GetComponent(); if ((bool)component) { UnityEngine.UI.Image image = component.FindChildComponent(fillImageChildLocatorEntryName); if (image != null) { overlayFillImages.Add(image); } } } private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance) { if (!instance) { return; } ChildLocator component = instance.GetComponent(); if ((bool)component) { UnityEngine.UI.Image image = component.FindChildComponent(overlayChildLocatorEntryName); if (image != null) { overlayFillImages.Remove(image); } } } public override void OnExit() { overlayFillImages.Clear(); foreach (OverlayController overlayController in overlayControllers) { HudOverlayManager.RemoveOverlay(overlayController); overlayController.onInstanceAdded -= OnOverlayInstanceAdded; overlayController.onInstanceRemove -= OnOverlayInstanceRemoved; } overlayControllers.Clear(); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (duration > 0f) { float fillAmount = base.fixedAge / duration; foreach (UnityEngine.UI.Image overlayFillImage in overlayFillImages) { overlayFillImage.fillAmount = fillAmount; } } if (base.isAuthority && base.fixedAge >= duration) { _ = (bool)VoidRaidGauntletController.instance; outer.SetNextState(new CloseGauntlet()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class ChargeFinalStand : BaseWardWipeState { [SerializeField] public float duration; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string muzzleName; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; private GameObject chargeEffectInstance; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator && (bool)chargeEffectPrefab) { Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform; if ((bool)transform) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } fogDamageController = GetComponent(); fogDamageController.enabled = true; safeWards = new List(); PhasedInventorySetter component2 = GetComponent(); if ((bool)component2 && NetworkServer.active) { component2.AdvancePhase(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { FireFinalStand nextState = new FireFinalStand(); outer.SetNextState(nextState); } } public override void OnExit() { EntityState.Destroy(chargeEffectInstance); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class ChargeGauntlet : BaseState { [SerializeField] public float duration; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string muzzleName; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; [SerializeField] public SkillDef skillDefToReplaceAtStocksEmpty; [SerializeField] public SkillDef nextSkillDef; private GameObject chargeEffectInstance; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator && (bool)chargeEffectPrefab) { Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform; if ((bool)transform) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } PhasedInventorySetter component2 = GetComponent(); if ((bool)component2 && NetworkServer.active) { component2.AdvancePhase(); } if ((bool)nextSkillDef) { GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty); if ((bool)genericSkill && genericSkill.stock == 0) { genericSkill.SetBaseSkill(nextSkillDef); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { _ = (bool)VoidRaidGauntletController.instance; outer.SetNextState(new ChannelGauntlet()); } } public override void OnExit() { EntityState.Destroy(chargeEffectInstance); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class ChargeWardWipe : BaseWardWipeState { [SerializeField] public float duration; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string muzzleName; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; [SerializeField] public InteractableSpawnCard safeWardSpawnCard; [SerializeField] public AnimationCurve safeWardSpawnCurve; [SerializeField] public float minDistanceBetweenConsecutiveWards; [SerializeField] public float maxDistanceBetweenConsecutiveWards; [SerializeField] public float maxDistanceToInitialWard; private GameObject chargeEffectInstance; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator && (bool)chargeEffectPrefab) { Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform; if ((bool)transform) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } fogDamageController = GetComponent(); fogDamageController.enabled = true; safeWards = new List(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)safeWardSpawnCard) { float time = base.fixedAge / duration; float f = safeWardSpawnCurve.Evaluate(time); DirectorPlacementRule directorPlacementRule = null; while ((float)safeWards.Count < Mathf.Floor(f)) { if (directorPlacementRule == null) { directorPlacementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, maxDistance = maxDistanceToInitialWard, minDistance = 0f, spawnOnTarget = base.gameObject.transform, preventOverhead = true }; } if (safeWards.Count > 0) { directorPlacementRule.maxDistance = maxDistanceBetweenConsecutiveWards; directorPlacementRule.minDistance = minDistanceBetweenConsecutiveWards; directorPlacementRule.spawnOnTarget = safeWards[safeWards.Count - 1].transform; directorPlacementRule.placementMode = DirectorPlacementRule.PlacementMode.Approximate; } GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(safeWardSpawnCard, directorPlacementRule, Run.instance.stageRng)); if ((bool)gameObject) { NetworkServer.Spawn(gameObject); if ((bool)fogDamageController) { IZone component = gameObject.GetComponent(); fogDamageController.AddSafeZone(component); } safeWards.Add(gameObject); } else { UnityEngine.Debug.LogError("Unable to spawn safe ward instance. Are there any ground nodes?"); } } } if (base.isAuthority && base.fixedAge >= duration) { FireWardWipe nextState = new FireWardWipe(); outer.SetNextState(nextState); } } public override void OnExit() { EntityState.Destroy(chargeEffectInstance); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class CloseGauntlet : BaseState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class Collapse : BaseState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new ReEmerge()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class DeathState : GenericCharacterDeath { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public GameObject initialEffectPrefab; [SerializeField] public string initialEffectMuzzle; [SerializeField] public GameObject explosionEffectPrefab; [SerializeField] public string explosionEffectMuzzle; [SerializeField] public UnityEngine.Vector3 ragdollForce; [SerializeField] public float explosionForce; [SerializeField] public bool addPrintController; [SerializeField] public float printDuration; [SerializeField] public float startingPrintBias; [SerializeField] public float maxPrintBias; private Transform modelTransform; protected override bool shouldAutoDestroy => false; protected override void PlayDeathAnimation(float crossfadeDuration) { PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateParam, duration, crossfadeDuration); } public override void OnEnter() { base.OnEnter(); if ((bool)VoidRaidGauntletController.instance) { VoidRaidGauntletController.instance.SetCurrentDonutCombatDirectorEnabled(isEnabled: false); } modelTransform = GetModelTransform(); Transform transform = FindModelChild("StandableSurface"); if ((bool)transform) { transform.gameObject.SetActive(value: false); } if ((bool)explosionEffectPrefab) { EffectManager.SimpleMuzzleFlash(initialEffectPrefab, base.gameObject, initialEffectMuzzle, transmit: false); } if (addPrintController) { PrintController printController = modelTransform.gameObject.AddComponent(); printController.printTime = printDuration; printController.enabled = true; printController.startingPrintHeight = 99f; printController.maxPrintHeight = 99f; printController.startingPrintBias = startingPrintBias; printController.maxPrintBias = maxPrintBias; printController.disableWhenFinished = false; printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { if ((bool)explosionEffectPrefab) { EffectManager.SimpleMuzzleFlash(explosionEffectPrefab, base.gameObject, explosionEffectMuzzle, transmit: true); } DestroyBodyAsapServer(); } } public override void OnExit() { if ((bool)modelTransform) { RagdollController component = modelTransform.GetComponent(); Rigidbody component2 = GetComponent(); if ((bool)component && (bool)component2) { component.BeginRagdoll(ragdollForce); } ExplodeRigidbodiesOnStart component3 = modelTransform.GetComponent(); if ((bool)component3) { component3.force = explosionForce; component3.enabled = true; } } } } public class EscapeDeath : GenericCharacterDeath { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public bool addPrintController; [SerializeField] public float printDuration; [SerializeField] public float startingPrintHeight; [SerializeField] public float maxPrintHeight; [SerializeField] public string gauntletEntranceChildName; [SerializeField] public string enterSoundString; private UnityEngine.Vector3 gauntletEntrancePosition; private Transform gauntletEntranceTransform; private NetworkInstanceId netId; protected override bool shouldAutoDestroy => false; protected override void PlayDeathAnimation(float crossfadeDuration) { PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateParam, duration, crossfadeDuration); } public override void OnEnter() { base.OnEnter(); netId = NetworkInstanceId.Invalid; if ((bool)base.characterBody && (bool)base.characterBody.master) { netId = base.characterBody.master.netId; } Util.PlaySound(enterSoundString, base.gameObject); if (addPrintController) { Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { PrintController printController = modelTransform.gameObject.AddComponent(); printController.printTime = printDuration; printController.enabled = true; printController.startingPrintHeight = startingPrintHeight; printController.maxPrintHeight = maxPrintHeight; printController.startingPrintBias = 0f; printController.maxPrintBias = 0f; printController.disableWhenFinished = false; printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); } } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { gauntletEntranceTransform = modelChildLocator.FindChild(gauntletEntranceChildName); RefreshGauntletEntrancePosition(); } } public override void OnExit() { if (NetworkServer.active) { RefreshGauntletEntrancePosition(); VoidRaidGauntletController.instance.TryOpenGauntlet(gauntletEntrancePosition, netId); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { RefreshGauntletEntrancePosition(); } if (base.isAuthority && base.fixedAge >= duration) { EntityState.Destroy(base.gameObject); } } private void RefreshGauntletEntrancePosition() { if ((bool)gauntletEntranceTransform) { gauntletEntrancePosition = gauntletEntranceTransform.position; } } } public class FireFinalStand : BaseWardWipeState { [SerializeField] public float duration; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleFlashPrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; [SerializeField] public BuffDef requiredBuffToKill; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)muzzleFlashPrefab) { EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); } if (!fogDamageController) { return; } if (NetworkServer.active) { foreach (CharacterBody affectedBody in fogDamageController.GetAffectedBodies()) { if (!requiredBuffToKill || affectedBody.HasBuff(requiredBuffToKill)) { affectedBody.healthComponent.Suicide(base.gameObject, base.gameObject, DamageType.VoidDeath); } } } fogDamageController.enabled = false; } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class FireWardWipe : BaseWardWipeState { [SerializeField] public float duration; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleFlashPrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; [SerializeField] public SkillDef skillDefToReplaceAtStocksEmpty; [SerializeField] public SkillDef nextSkillDef; [SerializeField] public BuffDef requiredBuffToKill; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)muzzleFlashPrefab) { EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); } if ((bool)nextSkillDef) { GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty); if ((bool)genericSkill && genericSkill.stock == 0) { genericSkill.SetBaseSkill(nextSkillDef); } } if (!fogDamageController) { return; } if (NetworkServer.active) { foreach (CharacterBody affectedBody in fogDamageController.GetAffectedBodies()) { if (!requiredBuffToKill || affectedBody.HasBuff(requiredBuffToKill)) { affectedBody.healthComponent.Suicide(base.gameObject, base.gameObject, DamageType.VoidDeath); } } } fogDamageController.enabled = false; } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class LegBreakStunState : BaseState { public static string animLayerName; public static string animStateName; public static string animPlaybackRateParamName; public static float baseDuration; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration; PlayAnimation(animLayerName, animStateName, animPlaybackRateParamName, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class ReEmerge : BaseState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); if (NetworkServer.active) { CentralLegController component = GetComponent(); if ((bool)component) { component.RegenerateAllBrokenServer(); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class SpawnState : BaseState { [SerializeField] public float duration = 4f; [SerializeField] public string spawnSoundString; [SerializeField] public GameObject spawnEffectPrefab; [SerializeField] public string spawnMuzzleName; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public bool doLegs; [SerializeField] public CharacterSpawnCard jointSpawnCard; [SerializeField] public string leg1Name; [SerializeField] public string leg2Name; [SerializeField] public string leg3Name; [SerializeField] public string leg4Name; [SerializeField] public string leg5Name; [SerializeField] public string leg6Name; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(spawnSoundString, base.gameObject); if ((bool)spawnEffectPrefab) { EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnMuzzleName, transmit: false); } if (doLegs && NetworkServer.active) { ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)jointSpawnCard && (bool)modelChildLocator) { DirectorPlacementRule placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Direct, spawnOnTarget = base.transform }; SpawnJointBodyForLegServer(leg1Name, modelChildLocator, placementRule); SpawnJointBodyForLegServer(leg2Name, modelChildLocator, placementRule); SpawnJointBodyForLegServer(leg3Name, modelChildLocator, placementRule); SpawnJointBodyForLegServer(leg4Name, modelChildLocator, placementRule); SpawnJointBodyForLegServer(leg5Name, modelChildLocator, placementRule); SpawnJointBodyForLegServer(leg6Name, modelChildLocator, placementRule); } } } private void SpawnJointBodyForLegServer(string legName, ChildLocator childLocator, DirectorPlacementRule placementRule) { DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(jointSpawnCard, placementRule, Run.instance.stageRng); directorSpawnRequest.summonerBodyObject = base.gameObject; GameObject gameObject = DirectorCore.instance?.TrySpawnObject(directorSpawnRequest); Transform transform = childLocator.FindChild(legName); if (!gameObject || !transform) { return; } CharacterMaster component = gameObject.GetComponent(); if ((bool)component) { LegController component2 = transform.GetComponent(); if ((bool)component2) { component2.SetJointMaster(component, transform.GetComponent()); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class BaseSpinBeamAttackState : BaseState { [SerializeField] public string animLayerName; [SerializeField] public string animStateName; [SerializeField] public string animPlaybackRateParamName; [SerializeField] public float baseDuration; public static string headTransformNameInChildLocator; public static string muzzleTransformNameInChildLocator; public static string headYawParamName; [SerializeField] public AnimationCurve headForwardYCurve; private Transform headTransform; private Transform muzzleTransform; private bool hasHeadSpinOwnership; protected float duration { get; private set; } protected Animator modelAnimator { get; private set; } protected GameObject beamVfxInstance { get; private set; } protected float normalizedFixedAge => Mathf.Clamp01(base.fixedAge / duration); public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); headTransform = FindModelChild(headTransformNameInChildLocator); muzzleTransform = FindModelChild(muzzleTransformNameInChildLocator); duration = baseDuration; if (!string.IsNullOrEmpty(animLayerName) && !string.IsNullOrEmpty(animStateName)) { if (!string.IsNullOrEmpty(animPlaybackRateParamName)) { PlayAnimation(animLayerName, animStateName, animPlaybackRateParamName, duration); } else { PlayAnimation(animLayerName, animStateName); } } if ((bool)modelAnimator) { modelAnimator.GetComponent().enabled = true; } hasHeadSpinOwnership = true; } public override void ModifyNextState(EntityState nextState) { base.ModifyNextState(nextState); if (nextState is BaseSpinBeamAttackState baseSpinBeamAttackState) { baseSpinBeamAttackState.hasHeadSpinOwnership |= hasHeadSpinOwnership; hasHeadSpinOwnership = false; } } public override void OnExit() { if (hasHeadSpinOwnership) { SetHeadYawRevolutions(0f); hasHeadSpinOwnership = true; } DestroyBeamVFXInstance(); base.OnExit(); } protected void SetHeadYawRevolutions(float newRevolutions) { if ((bool)modelAnimator) { modelAnimator.SetFloat(headYawParamName, (0.5f + newRevolutions) % 1f); } } protected Ray GetBeamRay() { _ = muzzleTransform.forward; UnityEngine.Vector3 forward = headTransform.forward; forward.y = headForwardYCurve.Evaluate(base.fixedAge / duration); forward.Normalize(); return new Ray(muzzleTransform.position, forward); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } protected void CreateBeamVFXInstance(GameObject beamVfxPrefab) { if ((object)beamVfxInstance != null) { throw new InvalidOperationException(); } beamVfxInstance = UnityEngine.Object.Instantiate(beamVfxPrefab); beamVfxInstance.transform.SetParent(headTransform, worldPositionStays: true); UpdateBeamTransforms(); RoR2Application.onLateUpdate += UpdateBeamTransformsInLateUpdate; } protected void DestroyBeamVFXInstance() { if ((object)beamVfxInstance != null) { RoR2Application.onLateUpdate -= UpdateBeamTransformsInLateUpdate; VfxKillBehavior.KillVfxObject(beamVfxInstance); beamVfxInstance = null; } } private void UpdateBeamTransformsInLateUpdate() { try { UpdateBeamTransforms(); } catch (Exception exception) { UnityEngine.Debug.LogException(exception); } } private void UpdateBeamTransforms() { Ray beamRay = GetBeamRay(); beamVfxInstance.transform.SetPositionAndRotation(beamRay.origin, UnityEngine.Quaternion.LookRotation(beamRay.direction)); } } public class SpinBeamEnter : BaseSpinBeamAttackState { public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= base.duration && base.isAuthority) { outer.SetNextState(new SpinBeamWindUp()); } } } public class SpinBeamWindUp : BaseSpinBeamAttackState { public static AnimationCurve revolutionsCurve; public static GameObject warningLaserPrefab; public static string enterSoundString; public override void OnEnter() { base.OnEnter(); CreateBeamVFXInstance(warningLaserPrefab); Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= base.duration && base.isAuthority) { outer.SetNextState(new SpinBeamAttack()); } SetHeadYawRevolutions(revolutionsCurve.Evaluate(base.normalizedFixedAge)); } } public class SpinBeamWindDown : BaseSpinBeamAttackState { public static AnimationCurve revolutionsCurve; public static string enterSoundString; public override void OnEnter() { base.OnEnter(); Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= base.duration && base.isAuthority) { outer.SetNextState(new SpinBeamExit()); } SetHeadYawRevolutions(revolutionsCurve.Evaluate(base.normalizedFixedAge)); } } public class SpinBeamExit : BaseSpinBeamAttackState { [SerializeField] public SkillDef skillDefToReplaceAtStocksEmpty; [SerializeField] public SkillDef nextSkillDef; public override void OnEnter() { base.OnEnter(); if ((bool)nextSkillDef) { GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty); if ((bool)genericSkill && genericSkill.stock == 0) { genericSkill.SetBaseSkill(nextSkillDef); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= base.duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class SpinBeamAttack : BaseSpinBeamAttackState { public static AnimationCurve revolutionsCurve; public static GameObject beamVfxPrefab; public static float beamRadius = 16f; public static float beamMaxDistance = 400f; public static float beamDpsCoefficient = 1f; public static float beamTickFrequency = 4f; public static GameObject beamImpactEffectPrefab; public static LoopSoundDef loopSound; public static string enterSoundString; private float beamTickTimer; private LoopSoundManager.SoundLoopPtr loopPtr; public override void OnEnter() { base.OnEnter(); CreateBeamVFXInstance(beamVfxPrefab); loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSound); Util.PlaySound(enterSoundString, base.gameObject); } public override void OnExit() { LoopSoundManager.StopSoundLoopLocal(loopPtr); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= base.duration && base.isAuthority) { outer.SetNextState(new SpinBeamWindDown()); } if (base.isAuthority) { if (beamTickTimer <= 0f) { beamTickTimer += 1f / beamTickFrequency; FireBeamBulletAuthority(); } beamTickTimer -= GetDeltaTime(); } SetHeadYawRevolutions(revolutionsCurve.Evaluate(base.normalizedFixedAge)); } private void FireBeamBulletAuthority() { Ray beamRay = GetBeamRay(); BulletAttack bulletAttack = new BulletAttack(); bulletAttack.muzzleName = BaseSpinBeamAttackState.muzzleTransformNameInChildLocator; bulletAttack.origin = beamRay.origin; bulletAttack.aimVector = beamRay.direction; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = 0f; bulletAttack.maxDistance = 400f; bulletAttack.hitMask = LayerIndex.CommonMasks.bullet; bulletAttack.stopperMask = 0; bulletAttack.bulletCount = 1u; bulletAttack.radius = beamRadius; bulletAttack.smartCollision = false; bulletAttack.queryTriggerInteraction = QueryTriggerInteraction.Ignore; bulletAttack.procCoefficient = 1f; bulletAttack.procChainMask = default(ProcChainMask); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.damage = beamDpsCoefficient * damageStat / beamTickFrequency; bulletAttack.damageColorIndex = DamageColorIndex.Default; bulletAttack.damageType = DamageType.Generic; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.force = 0f; bulletAttack.hitEffectPrefab = beamImpactEffectPrefab; bulletAttack.tracerEffectPrefab = null; bulletAttack.isCrit = false; bulletAttack.HitEffectNormal = false; bulletAttack.Fire(); } } public class TurnState : GenericCharacterMain { [SerializeField] public float duration = 1f; [SerializeField] public float turnDegrees = 22.5f; [SerializeField] public int maxNumConsecutiveTurns; [SerializeField] public string animationLayerName; [SerializeField] public string clockwiseAnimationStateName; [SerializeField] public string counterClockwiseAnimationStateName; [SerializeField] public string animationPlaybackRateParam; private CentralLegController centralLegController; private CentralLegController.SuppressBreaksRequest suppressBreaksRequest; private int turnCount = 1; private bool isClockwiseTurn; private bool canTurn; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { centralLegController = GetComponent(); if ((bool)centralLegController) { suppressBreaksRequest = centralLegController.SuppressBreaks(); } float dirToAimDegrees = GetDirToAimDegrees(); if (dirToAimDegrees >= turnDegrees) { isClockwiseTurn = true; canTurn = true; } else if (dirToAimDegrees <= 0f - turnDegrees) { isClockwiseTurn = false; canTurn = true; } } if (canTurn) { if (isClockwiseTurn) { PlayAnimation(animationLayerName, clockwiseAnimationStateName, animationPlaybackRateParam, duration); } else { PlayAnimation(animationLayerName, counterClockwiseAnimationStateName, animationPlaybackRateParam, duration); } } else if (base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { base.OnExit(); suppressBreaksRequest?.Dispose(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { if (Mathf.Abs(GetDirToAimDegrees()) >= turnDegrees && (bool)centralLegController && !centralLegController.AreAnyBreaksPending() && turnCount < maxNumConsecutiveTurns) { TurnState turnState = new TurnState(); turnState.turnCount = turnCount + 1; outer.SetNextState(turnState); } else { outer.SetNextStateToMain(); } } } public float GetDirToAimDegrees() { float num = 0f; if ((bool)base.inputBank && (bool)base.characterDirection) { UnityEngine.Vector3 rhs = base.inputBank.aimDirection; rhs.y = 0f; rhs.Normalize(); UnityEngine.Vector3 forward = base.characterDirection.forward; forward.y = 0f; forward.Normalize(); num = Mathf.Acos(UnityEngine.Vector3.Dot(forward, rhs)) * 57.29578f; if (UnityEngine.Vector3.Dot(UnityEngine.Vector3.Cross(forward, rhs), UnityEngine.Vector3.up) < 0f) { num *= -1f; } } return num; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(isClockwiseTurn); writer.Write(canTurn); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); isClockwiseTurn = reader.ReadBoolean(); canTurn = reader.ReadBoolean(); } } public abstract class BaseVacuumAttackState : BaseState { [SerializeField] public float baseDuration; [SerializeField] public string animLayerName; [SerializeField] public string animStateName; [SerializeField] public string animPlaybackRateParamName; public static string vacuumOriginChildLocatorName; protected float duration { get; private set; } protected Transform vacuumOrigin { get; private set; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; if (!string.IsNullOrEmpty(animLayerName) && !string.IsNullOrEmpty(animStateName) && !string.IsNullOrEmpty(animPlaybackRateParamName)) { PlayAnimation(animLayerName, animStateName, animPlaybackRateParamName, duration); } if (!string.IsNullOrEmpty(vacuumOriginChildLocatorName)) { vacuumOrigin = FindModelChild(vacuumOriginChildLocatorName); } else { vacuumOrigin = base.transform; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { OnLifetimeExpiredAuthority(); } } protected abstract void OnLifetimeExpiredAuthority(); public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class VacuumEnter : BaseVacuumAttackState { protected override void OnLifetimeExpiredAuthority() { outer.SetNextState(new VacuumWindUp()); } } public class VacuumWindUp : BaseVacuumAttackState { protected override void OnLifetimeExpiredAuthority() { outer.SetNextState(new VacuumAttack()); } } public class VacuumAttack : BaseVacuumAttackState { public static AnimationCurve killRadiusCurve; public static AnimationCurve pullMagnitudeCurve; public static float losObstructionFactor = 0.5f; public static GameObject killSphereVfxPrefab; public static GameObject environmentVfxPrefab; public static LoopSoundDef loopSound; private CharacterLosTracker losTracker; private VFXHelper killSphereVfxHelper; private VFXHelper environmentVfxHelper; private SphereSearch killSearch; private float killRadius = 1f; private BodyIndex jointBodyIndex = BodyIndex.None; private LoopSoundManager.SoundLoopPtr loopPtr; public override void OnEnter() { base.OnEnter(); losTracker = new CharacterLosTracker(); losTracker.enabled = true; killSphereVfxHelper = VFXHelper.Rent(); killSphereVfxHelper.vfxPrefabReference = killSphereVfxPrefab; killSphereVfxHelper.followedTransform = base.vacuumOrigin; killSphereVfxHelper.useFollowedTransformScale = false; killSphereVfxHelper.enabled = true; UpdateKillSphereVfx(); environmentVfxHelper = VFXHelper.Rent(); environmentVfxHelper.vfxPrefabReference = environmentVfxPrefab; environmentVfxHelper.followedTransform = base.vacuumOrigin; environmentVfxHelper.useFollowedTransformScale = false; environmentVfxHelper.enabled = true; loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSound); if (NetworkServer.active) { killSearch = new SphereSearch(); } jointBodyIndex = BodyCatalog.FindBodyIndex("VoidRaidCrabJointBody"); } public override void OnExit() { killSphereVfxHelper = VFXHelper.Return(killSphereVfxHelper); environmentVfxHelper = VFXHelper.Return(environmentVfxHelper); losTracker.enabled = false; losTracker.Dispose(); losTracker = null; LoopSoundManager.StopSoundLoopLocal(loopPtr); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); float time = Mathf.Clamp01(base.fixedAge / base.duration); killRadius = killRadiusCurve.Evaluate(time); UpdateKillSphereVfx(); UnityEngine.Vector3 position = base.vacuumOrigin.position; losTracker.origin = position; losTracker.Step(); ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; float num = pullMagnitudeCurve.Evaluate(time); for (int i = 0; i < readOnlyInstancesList.Count; i++) { CharacterBody characterBody = readOnlyInstancesList[i]; if ((object)characterBody == base.characterBody) { continue; } bool flag = losTracker.CheckBodyHasLos(characterBody); if (characterBody.hasEffectiveAuthority) { IDisplacementReceiver component = characterBody.GetComponent(); if (component != null) { float num2 = (flag ? 1f : losObstructionFactor); component.AddDisplacement((position - characterBody.transform.position).normalized * (num * num2 * GetDeltaTime())); } } } if (!NetworkServer.active) { return; } List list = CollectionPool>.RentCollection(); List list2 = CollectionPool>.RentCollection(); try { killSearch.radius = killRadius; killSearch.origin = position; killSearch.mask = LayerIndex.entityPrecise.mask; killSearch.RefreshCandidates(); killSearch.OrderCandidatesByDistance(); killSearch.FilterCandidatesByDistinctHurtBoxEntities(); killSearch.GetHurtBoxes(list); for (int j = 0; j < list.Count; j++) { HurtBox hurtBox = list[j]; if ((bool)hurtBox.healthComponent) { list2.Add(hurtBox.healthComponent); } } for (int k = 0; k < list2.Count; k++) { HealthComponent healthComponent = list2[k]; if ((object)base.healthComponent != healthComponent && healthComponent.body.bodyIndex != jointBodyIndex) { healthComponent.Suicide(base.gameObject, base.gameObject, DamageType.VoidDeath); } } } finally { list2 = CollectionPool>.ReturnCollection(list2); list = CollectionPool>.ReturnCollection(list); } } private void UpdateKillSphereVfx() { if ((bool)killSphereVfxHelper.vfxInstanceTransform) { killSphereVfxHelper.vfxInstanceTransform.localScale = UnityEngine.Vector3.one * killRadius; } } protected override void OnLifetimeExpiredAuthority() { outer.SetNextState(new VacuumWindDown()); } } public class VacuumWindDown : BaseVacuumAttackState { protected override void OnLifetimeExpiredAuthority() { outer.SetNextState(new VacuumExit()); } } public class VacuumExit : BaseVacuumAttackState { [SerializeField] public SkillDef skillDefToReplaceAtStocksEmpty; [SerializeField] public SkillDef nextSkillDef; public override void OnEnter() { base.OnEnter(); if ((bool)nextSkillDef) { GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty); if ((bool)genericSkill && genericSkill.stock == 0) { genericSkill.SetBaseSkill(nextSkillDef); } } } protected override void OnLifetimeExpiredAuthority() { outer.SetNextStateToMain(); } } public class WaitForLegsAvailable : BaseState { public EntityState nextState; private CentralLegController centralLegController; public override void OnEnter() { base.OnEnter(); centralLegController = GetComponent(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && !centralLegController.AreLegsBlockingBodyAnimation()) { outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return nextState.GetMinimumInterruptPriority(); } } } namespace EntityStates.VoidRaidCrab.Weapon { public abstract class BaseFireMultiBeam : BaseMultiBeamState { [SerializeField] public float baseDuration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public GameObject tracerEffectPrefab; [SerializeField] public GameObject explosionEffectPrefab; [SerializeField] public float blastDamageCoefficient; [SerializeField] public float blastForceMagnitude; [SerializeField] public float blastRadius; [SerializeField] public UnityEngine.Vector3 blastBonusForce; [SerializeField] public string enterSoundString; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, BaseMultiBeamState.muzzleName, transmit: false); } Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); if (!base.isAuthority) { return; } CalcBeamPath(out var beamRay, out var beamEndPos); BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * blastDamageCoefficient; blastAttack.baseForce = blastForceMagnitude; blastAttack.position = beamEndPos; blastAttack.radius = blastRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot; blastAttack.bonusForce = blastBonusForce; blastAttack.damageType = DamageType.Generic; blastAttack.Fire(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { int childIndex = component.FindChildIndex(BaseMultiBeamState.muzzleName); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = beamEndPos, start = beamRay.origin, scale = blastRadius }; effectData.SetChildLocatorTransformReference(base.gameObject, childIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); EffectManager.SpawnEffect(explosionEffectPrefab, effectData, transmit: true); } } } OnFireBeam(beamRay.origin, beamEndPos); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { EntityState nextState = InstantiateNextState(); outer.SetNextState(nextState); } } protected abstract EntityState InstantiateNextState(); protected virtual void OnFireBeam(UnityEngine.Vector3 beamStart, UnityEngine.Vector3 beamEnd) { } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public abstract class BaseGravityBumpState : BaseState { [SerializeField] public float maxDistance; protected UnityEngine.Vector3 airborneForce; protected UnityEngine.Vector3 groundedForce; protected bool isLeft; public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(isLeft); writer.Write(groundedForce); writer.Write(airborneForce); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); isLeft = reader.ReadBoolean(); groundedForce = reader.ReadVector3(); airborneForce = reader.ReadVector3(); } public override void ModifyNextState(EntityState nextState) { base.ModifyNextState(nextState); if (nextState is BaseGravityBumpState baseGravityBumpState) { baseGravityBumpState.groundedForce = groundedForce; baseGravityBumpState.airborneForce = airborneForce; baseGravityBumpState.isLeft = isLeft; } } protected IEnumerable GetTargets() { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.viewer = base.characterBody; bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(base.characterBody.teamComponent.teamIndex); bullseyeSearch.minDistanceFilter = 0f; bullseyeSearch.maxDistanceFilter = maxDistance; bullseyeSearch.searchOrigin = base.inputBank.aimOrigin; bullseyeSearch.searchDirection = base.inputBank.aimDirection; bullseyeSearch.maxAngleFilter = 360f; bullseyeSearch.filterByLoS = false; bullseyeSearch.filterByDistinctEntity = true; bullseyeSearch.RefreshCandidates(); return bullseyeSearch.GetResults(); } } public abstract class BaseMultiBeamState : BaseState { public static float beamMaxDistance = 1000f; public static string muzzleName; protected Transform muzzleTransform { get; private set; } public override void OnEnter() { base.OnEnter(); muzzleTransform = FindModelChild(muzzleName); } protected void CalcBeamPath(out Ray beamRay, out UnityEngine.Vector3 beamEndPos) { Ray aimRay = GetAimRay(); float num = float.PositiveInfinity; RaycastHit[] array = Physics.RaycastAll(aimRay, beamMaxDistance, LayerIndex.CommonMasks.bullet, QueryTriggerInteraction.Ignore); Transform root = GetModelTransform().root; for (int i = 0; i < array.Length; i++) { ref RaycastHit reference = ref array[i]; float distance = reference.distance; if (distance < num && (object)reference.collider.transform.root != root) { num = distance; } } num = Mathf.Min(num, beamMaxDistance); beamEndPos = aimRay.GetPoint(num); UnityEngine.Vector3 position = muzzleTransform.position; beamRay = new Ray(position, beamEndPos - position); } } public class ChargeGravityBump : BaseGravityBumpState { [SerializeField] public float baseDuration; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string muzzleName; [SerializeField] public string enterSoundString; [SerializeField] public bool isSoundScaledByAttackSpeed; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public float horizontalAirborneForce; [SerializeField] public float verticalAirborneForce; [SerializeField] public float horizontalGroundedForce; [SerializeField] public float verticalGroundedForce; [SerializeField] public GameObject forceIndicatorPrefab; private float duration; private GameObject chargeEffectInstance; private Dictionary characterMotorsToIndicatorTransforms; private UnityEngine.Quaternion airborneForceOrientation; private UnityEngine.Quaternion groundedForceOrientation; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { isLeft = UnityEngine.Random.value > 0.5f; CharacterDirection component = GetComponent(); if ((bool)component) { UnityEngine.Vector3 vector = UnityEngine.Vector3.Cross(component.forward, UnityEngine.Vector3.up); if (!isLeft) { vector *= -1f; } airborneForce = UnityEngine.Vector3.up * -1f * verticalAirborneForce + vector * horizontalAirborneForce; groundedForce = UnityEngine.Vector3.up * verticalGroundedForce + vector * horizontalGroundedForce; } } airborneForceOrientation = Util.QuaternionSafeLookRotation(airborneForce); groundedForceOrientation = Util.QuaternionSafeLookRotation(groundedForce); duration = baseDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator && (bool)chargeEffectPrefab) { Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform; if ((bool)transform) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffectInstance.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } } if (!string.IsNullOrEmpty(enterSoundString)) { if (isSoundScaledByAttackSpeed) { Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); } else { Util.PlaySound(enterSoundString, base.gameObject); } } characterMotorsToIndicatorTransforms = new Dictionary(); AssignIndicators(); } public override void OnExit() { CleanUpIndicators(); EntityState.Destroy(chargeEffectInstance); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); foreach (KeyValuePair characterMotorsToIndicatorTransform in characterMotorsToIndicatorTransforms) { if (characterMotorsToIndicatorTransform.Key.isGrounded) { characterMotorsToIndicatorTransform.Value.rotation = groundedForceOrientation; } else { characterMotorsToIndicatorTransform.Value.rotation = airborneForceOrientation; } } if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new FireGravityBump()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } private void AssignIndicators() { foreach (HurtBox target in GetTargets()) { GameObject gameObject = target.healthComponent.gameObject; if ((bool)gameObject) { CharacterMotor component = gameObject.GetComponent(); if ((bool)component && !characterMotorsToIndicatorTransforms.ContainsKey(component)) { GameObject gameObject2 = UnityEngine.Object.Instantiate(forceIndicatorPrefab, gameObject.transform); characterMotorsToIndicatorTransforms.Add(component, gameObject2.transform); } } } } private void CleanUpIndicators() { foreach (KeyValuePair characterMotorsToIndicatorTransform in characterMotorsToIndicatorTransforms) { Transform value = characterMotorsToIndicatorTransform.Value; if ((bool)value) { EntityState.Destroy(value.gameObject); } } characterMotorsToIndicatorTransforms.Clear(); } } public class ChargeMissiles : BaseState { [SerializeField] public float baseDuration; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string muzzleName; [SerializeField] public string enterSoundString; [SerializeField] public bool isSoundScaledByAttackSpeed; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private float duration; private GameObject chargeEffectInstance; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator && (bool)chargeEffectPrefab) { Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform; if ((bool)transform) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; } } if (!string.IsNullOrEmpty(enterSoundString)) { if (isSoundScaledByAttackSpeed) { Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); } else { Util.PlaySound(enterSoundString, base.gameObject); } } } public override void OnExit() { EntityState.Destroy(chargeEffectInstance); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new FireMissiles()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ChargeMultiBeam : BaseMultiBeamState { [SerializeField] public float baseDuration; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public GameObject warningLaserVfxPrefab; [SerializeField] public new string muzzleName; [SerializeField] public string enterSoundString; [SerializeField] public bool isSoundScaledByAttackSpeed; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private float duration; private GameObject chargeEffectInstance; private GameObject warningLaserVfxInstance; private RayAttackIndicator warningLaserVfxInstanceRayAttackIndicator; private bool warningLaserEnabled { get { return warningLaserVfxInstance; } set { if (value == warningLaserEnabled) { return; } if (value) { if ((bool)warningLaserVfxPrefab) { warningLaserVfxInstance = UnityEngine.Object.Instantiate(warningLaserVfxPrefab); warningLaserVfxInstanceRayAttackIndicator = warningLaserVfxInstance.GetComponent(); UpdateWarningLaser(); } } else { EntityState.Destroy(warningLaserVfxInstance); warningLaserVfxInstance = null; warningLaserVfxInstanceRayAttackIndicator = null; } } } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator && (bool)chargeEffectPrefab) { Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform; if ((bool)transform) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } if (!string.IsNullOrEmpty(enterSoundString)) { if (isSoundScaledByAttackSpeed) { Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); } else { Util.PlaySound(enterSoundString, base.gameObject); } } warningLaserEnabled = true; } public override void OnExit() { warningLaserEnabled = false; EntityState.Destroy(chargeEffectInstance); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new FireMultiBeamSmall()); } } public override void Update() { base.Update(); UpdateWarningLaser(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } private void UpdateWarningLaser() { if ((bool)warningLaserVfxInstanceRayAttackIndicator) { warningLaserVfxInstanceRayAttackIndicator.attackRange = BaseMultiBeamState.beamMaxDistance; CalcBeamPath(out var beamRay, out var _); warningLaserVfxInstanceRayAttackIndicator.attackRay = beamRay; } } } public class FireGravityBump : BaseGravityBumpState { [SerializeField] public float baseDuration; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleFlashPrefab; [SerializeField] public bool disableAirControlUntilCollision; [SerializeField] public GameObject airborneEffectPrefab; [SerializeField] public GameObject groundedEffectPrefab; [SerializeField] public string enterSoundString; [SerializeField] public bool isSoundScaledByAttackSpeed; [SerializeField] public string leftAnimationLayerName; [SerializeField] public string leftAnimationStateName; [SerializeField] public string leftAnimationPlaybackRateParam; [SerializeField] public string rightAnimationLayerName; [SerializeField] public string rightAnimationStateName; [SerializeField] public string rightAnimationPlaybackRateParam; [SerializeField] public SkillDef skillDefToReplaceAtStocksEmpty; [SerializeField] public SkillDef nextSkillDef; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; if ((bool)nextSkillDef) { GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty); if ((bool)genericSkill && genericSkill.stock == 0) { genericSkill.SetBaseSkill(nextSkillDef); } } if (isLeft) { PlayAnimation(leftAnimationLayerName, leftAnimationStateName, leftAnimationPlaybackRateParam, duration); } else { PlayAnimation(rightAnimationLayerName, rightAnimationStateName, rightAnimationPlaybackRateParam, duration); } if ((bool)muzzleFlashPrefab) { EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); } if (!NetworkServer.active) { return; } BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.viewer = base.characterBody; bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(base.characterBody.teamComponent.teamIndex); bullseyeSearch.minDistanceFilter = 0f; bullseyeSearch.maxDistanceFilter = maxDistance; bullseyeSearch.searchOrigin = base.inputBank.aimOrigin; bullseyeSearch.searchDirection = base.inputBank.aimDirection; bullseyeSearch.maxAngleFilter = 360f; bullseyeSearch.filterByLoS = false; bullseyeSearch.filterByDistinctEntity = true; bullseyeSearch.RefreshCandidates(); foreach (HurtBox result in bullseyeSearch.GetResults()) { GameObject gameObject = result.healthComponent.gameObject; if (!gameObject) { continue; } CharacterMotor component = gameObject.GetComponent(); if ((bool)component) { EffectData effectData = new EffectData { origin = gameObject.transform.position }; GameObject effectPrefab; if (component.isGrounded) { component.ApplyForce(groundedForce, alwaysApply: true, disableAirControlUntilCollision); effectPrefab = groundedEffectPrefab; effectData.rotation = Util.QuaternionSafeLookRotation(groundedForce); } else { component.ApplyForce(airborneForce, alwaysApply: true, disableAirControlUntilCollision); effectPrefab = airborneEffectPrefab; effectData.rotation = Util.QuaternionSafeLookRotation(airborneForce); } EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireMissiles : BaseState { [SerializeField] public float baseInitialDelay; [SerializeField] public float baseDelayBetweenWaves; [SerializeField] public float baseEndDelay; [SerializeField] public int numWaves; [SerializeField] public int numMissilesPerWave; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleFlashPrefab; [SerializeField] public GameObject projectilePrefab; [SerializeField] public float damageCoefficient; [SerializeField] public float force; [SerializeField] public float minSpreadDegrees; [SerializeField] public float rangeSpreadDegrees; [SerializeField] public string fireWaveSoundString; [SerializeField] public bool isSoundScaledByAttackSpeed; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public SkillDef skillDefToReplaceAtStocksEmpty; [SerializeField] public SkillDef nextSkillDef; private float delayBetweenWaves; private float duration; private int numWavesFired; private float timeUntilNextWave; private Transform muzzleTransform; public override void OnEnter() { base.OnEnter(); if ((bool)nextSkillDef) { GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty); if ((bool)genericSkill && genericSkill.stock == 0) { genericSkill.SetBaseSkill(nextSkillDef); } } float num = baseInitialDelay + Mathf.Max(0f, baseDelayBetweenWaves * (float)(numWaves - 1)) + baseEndDelay; duration = num / attackSpeedStat; timeUntilNextWave = baseInitialDelay / attackSpeedStat; delayBetweenWaves = baseDelayBetweenWaves / attackSpeedStat; muzzleTransform = FindModelChild(muzzleName); } public override void FixedUpdate() { base.FixedUpdate(); timeUntilNextWave -= GetDeltaTime(); while (timeUntilNextWave < 0f && numWavesFired < numWaves) { PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); timeUntilNextWave += delayBetweenWaves; numWavesFired++; EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); if (base.isAuthority) { UnityEngine.Quaternion quaternion = Util.QuaternionSafeLookRotation(GetAimRay().direction); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = muzzleTransform.position; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = force; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; for (int i = 0; i < numMissilesPerWave; i++) { fireProjectileInfo2.rotation = quaternion * GetRandomRollPitch(); fireProjectileInfo2.crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } } } if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } protected UnityEngine.Quaternion GetRandomRollPitch() { UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.forward); UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(minSpreadDegrees + UnityEngine.Random.Range(0f, rangeSpreadDegrees), UnityEngine.Vector3.left); return quaternion * quaternion2; } } public class FireMultiBeamFinale : BaseFireMultiBeam { [SerializeField] public GameObject projectilePrefab; [SerializeField] public float projectileVerticalSpawnOffset; [SerializeField] public float projectileDamageCoefficient; [SerializeField] public SkillDef skillDefToReplaceAtStocksEmpty; [SerializeField] public SkillDef nextSkillDef; protected override void OnFireBeam(UnityEngine.Vector3 beamStart, UnityEngine.Vector3 beamEnd) { if ((bool)nextSkillDef) { GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty); if ((bool)genericSkill && genericSkill.stock == 0) { genericSkill.SetBaseSkill(nextSkillDef); } } FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = beamEnd + UnityEngine.Vector3.up * projectileVerticalSpawnOffset; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * projectileDamageCoefficient; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } protected override EntityState InstantiateNextState() { return EntityStateCatalog.InstantiateState(ref outer.mainStateType); } } public class FireMultiBeamSmall : BaseFireMultiBeam { [SerializeField] public int numFireBeforeFinale; private int fireIndex; protected override EntityState InstantiateNextState() { if (fireIndex < numFireBeforeFinale - 1) { return new FireMultiBeamSmall { fireIndex = fireIndex + 1 }; } return new FireMultiBeamFinale(); } } } namespace EntityStates.VoidRaidCrab.Leg { public class BaseLegState : EntityState { protected LegController legController { get; private set; } public override void OnEnter() { base.OnEnter(); legController = legController ?? GetComponent(); } public override void ModifyNextState(EntityState nextState) { base.ModifyNextState(nextState); if (nextState is BaseLegState baseLegState) { baseLegState.legController = legController; } } } public class Idle : BaseLegState { public override void FixedUpdate() { base.FixedUpdate(); if (base.legController.mainBodyHasEffectiveAuthority && !base.legController.DoesJointExist()) { outer.SetNextState(new JointBroken()); } } } public abstract class BaseStompState : BaseLegState { [SerializeField] public float baseDuration; [SerializeField] public string animName; public static GameObject warningIndicatorPrefab; public GameObject target; protected float duration; private bool lifetimeExpiredAuthority; private RayAttackIndicator warningIndicatorInstance; protected virtual bool shouldUseWarningIndicator => false; protected virtual bool shouldUpdateLegStompTargetPosition => false; public override void OnEnter() { base.OnEnter(); duration = baseDuration; string stompPlaybackRateParam = base.legController.stompPlaybackRateParam; if (!string.IsNullOrEmpty(stompPlaybackRateParam)) { EntityState.PlayAnimationOnAnimator(base.legController.animator, base.legController.primaryLayerName, animName, stompPlaybackRateParam, duration); } else { EntityState.PlayAnimationOnAnimator(base.legController.animator, base.legController.primaryLayerName, animName); int layerIndex = base.legController.animator.GetLayerIndex(base.legController.primaryLayerName); duration = base.legController.animator.GetCurrentAnimatorStateInfo(layerIndex).length; } SetWarningIndicatorActive(shouldUseWarningIndicator); } public override void OnExit() { SetWarningIndicatorActive(newWarningIndicatorActive: false); base.OnExit(); } public override void ModifyNextState(EntityState nextState) { base.ModifyNextState(nextState); if (nextState is BaseStompState baseStompState) { baseStompState.warningIndicatorInstance = warningIndicatorInstance; warningIndicatorInstance = null; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.legController.mainBody.hasEffectiveAuthority && base.fixedAge >= duration && !lifetimeExpiredAuthority) { lifetimeExpiredAuthority = true; OnLifetimeExpiredAuthority(); } if (shouldUpdateLegStompTargetPosition && (bool)target) { base.legController.SetStompTargetWorldPosition(target.transform.position); } UpdateWarningIndicatorInstance(); } protected abstract void OnLifetimeExpiredAuthority(); protected void SetWarningIndicatorActive(bool newWarningIndicatorActive) { if ((bool)warningIndicatorInstance == newWarningIndicatorActive) { return; } if (newWarningIndicatorActive) { GameObject gameObject = UnityEngine.Object.Instantiate(warningIndicatorPrefab); warningIndicatorInstance = gameObject.GetComponent(); UpdateWarningIndicatorInstance(); return; } if ((bool)warningIndicatorInstance) { EntityState.Destroy(warningIndicatorInstance.gameObject); } warningIndicatorInstance = null; } private void UpdateWarningIndicatorInstance() { if ((bool)warningIndicatorInstance) { UnityEngine.Vector3 position = base.legController.toeTipTransform.position; UnityEngine.Vector3 vector = (base.legController.mainBody ? base.legController.mainBody.transform.position : position); warningIndicatorInstance.attackRay = new Ray(position, UnityEngine.Vector3.down); warningIndicatorInstance.attackRange = position.y - vector.y; warningIndicatorInstance.attackRadius = Stomp.blastRadius; warningIndicatorInstance.layerMask = LayerIndex.world.mask; } } } public class PreStompLegRaise : BaseStompState { protected override bool shouldUseWarningIndicator => true; protected override bool shouldUpdateLegStompTargetPosition => true; protected override void OnLifetimeExpiredAuthority() { outer.SetNextState(new PreStompFollowTarget { target = target }); } } public class PreStompFollowTarget : BaseStompState { protected override bool shouldUseWarningIndicator => true; protected override bool shouldUpdateLegStompTargetPosition => true; protected override void OnLifetimeExpiredAuthority() { outer.SetNextState(new PreStompPauseBeforeStomp { target = target }); } } public class PreStompPauseBeforeStomp : BaseStompState { protected override void OnLifetimeExpiredAuthority() { outer.SetNextState(new Stomp { target = target }); } } public class Stomp : BaseStompState { public static float blastDamageCoefficient; public static float blastRadius; public static float blastForce; public static GameObject blastEffectPrefab; private UnityEngine.Vector3? previousToePosition; private bool hasDoneBlast; protected override void OnLifetimeExpiredAuthority() { outer.SetNextState(new PostStompReturnToBase { target = target }); } public override void FixedUpdate() { base.FixedUpdate(); if (!hasDoneBlast && (bool)base.legController.mainBody && base.legController.mainBody.hasEffectiveAuthority) { TryStompCollisionAuthority(); } } private void TryStompCollisionAuthority() { UnityEngine.Vector3 currentToePosition = base.legController.toeTipTransform.position; TryAttack(); previousToePosition = currentToePosition; void TryAttack() { if (previousToePosition.HasValue) { UnityEngine.Vector3 value = previousToePosition.Value; if (!((currentToePosition - value).sqrMagnitude < 0.0025000002f) && Physics.Linecast(previousToePosition.Value, currentToePosition, out var hitInfo, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { DoBlastAuthority(hitInfo.point); base.legController.DoToeConcussionBlastAuthority(hitInfo.point, useEffect: false); hasDoneBlast = true; } } } } private void DoBlastAuthority(UnityEngine.Vector3 blastOrigin) { CharacterBody mainBody = base.legController.mainBody; EffectData effectData = new EffectData(); effectData.origin = blastOrigin; effectData.scale = blastRadius; effectData.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.up); EffectManager.SpawnEffect(blastEffectPrefab, effectData, transmit: true); BlastAttack obj = new BlastAttack { attacker = mainBody.gameObject }; obj.inflictor = obj.attacker; obj.baseDamage = blastDamageCoefficient * mainBody.damage; obj.baseForce = blastForce; obj.position = blastOrigin; obj.radius = blastRadius; obj.falloffModel = BlastAttack.FalloffModel.SweetSpot; obj.teamIndex = mainBody.teamComponent.teamIndex; obj.attackerFiltering = AttackerFiltering.NeverHitSelf; obj.damageType = DamageType.Generic; obj.crit = mainBody.RollCrit(); obj.damageColorIndex = DamageColorIndex.Default; obj.impactEffect = EffectIndex.Invalid; obj.losType = BlastAttack.LoSType.None; obj.procChainMask = default(ProcChainMask); obj.procCoefficient = 1f; obj.Fire(); } private void DoStompAttackAuthority(UnityEngine.Vector3 hitPosition) { CharacterBody mainBody = base.legController.mainBody; if ((bool)mainBody) { UnityEngine.Vector3 position = base.legController.footTranform.position; UnityEngine.Vector3 position2 = base.legController.toeTipTransform.position; RaycastHit hitInfo; UnityEngine.Vector3 vector = (Physics.Linecast(position, position2, out hitInfo, LayerIndex.world.mask, QueryTriggerInteraction.Ignore) ? hitInfo.point : position2); EffectData effectData = new EffectData(); effectData.origin = vector; effectData.scale = blastRadius; effectData.rotation = UnityEngine.Quaternion.LookRotation(-hitInfo.normal); EffectManager.SpawnEffect(blastEffectPrefab, effectData, transmit: true); BlastAttack obj = new BlastAttack { attacker = mainBody.gameObject }; obj.inflictor = obj.attacker; obj.baseDamage = blastDamageCoefficient * mainBody.damage; obj.baseForce = blastForce; obj.position = vector; obj.radius = blastRadius; obj.falloffModel = BlastAttack.FalloffModel.Linear; obj.teamIndex = mainBody.teamComponent.teamIndex; obj.attackerFiltering = AttackerFiltering.NeverHitSelf; obj.damageType = DamageType.Generic; obj.crit = mainBody.RollCrit(); obj.damageColorIndex = DamageColorIndex.Default; obj.impactEffect = EffectIndex.Invalid; obj.losType = BlastAttack.LoSType.None; obj.procChainMask = default(ProcChainMask); obj.procCoefficient = 1f; obj.Fire(); } } } public class PostStompReturnToBase : BaseStompState { protected override void OnLifetimeExpiredAuthority() { outer.SetNextStateToMain(); } } public class JointBroken : BaseLegState { public override void OnEnter() { base.OnEnter(); base.legController.shouldRetract = true; } public override void OnExit() { base.OnExit(); base.legController.shouldRetract = false; } public override void FixedUpdate() { base.FixedUpdate(); if (base.legController.mainBodyHasEffectiveAuthority && base.legController.DoesJointExist()) { outer.SetNextState(new Idle()); } } } public class Retract : BaseLegState { } public class Retracted : BaseLegState { } public class Restore : BaseLegState { } } namespace EntityStates.VoidRaidCrab.Joint { public class DeathState : GenericCharacterDeath { [SerializeField] public string joint1Name; [SerializeField] public string joint2Name; [SerializeField] public string joint3Name; [SerializeField] public GameObject joint1EffectPrefab; [SerializeField] public GameObject joint2EffectPrefab; [SerializeField] public GameObject joint3EffectPrefab; private CharacterModel characterModel; public override void OnEnter() { base.OnEnter(); EffectManager.SimpleMuzzleFlash(joint1EffectPrefab, base.gameObject, joint1Name, transmit: false); EffectManager.SimpleMuzzleFlash(joint2EffectPrefab, base.gameObject, joint2Name, transmit: false); EffectManager.SimpleMuzzleFlash(joint3EffectPrefab, base.gameObject, joint3Name, transmit: false); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { characterModel = modelTransform.GetComponent(); } if ((bool)characterModel) { characterModel.invisibilityCount++; } } public override void OnExit() { if ((bool)characterModel) { characterModel.invisibilityCount--; } base.OnExit(); } } public class PreDeathState : BaseState { [SerializeField] public float minDuration; [SerializeField] public string joint1Name; [SerializeField] public string joint2Name; [SerializeField] public string joint3Name; [SerializeField] public GameObject jointEffectPrefab; public bool canProceed; private List jointEffects = new List(); public override void OnEnter() { base.OnEnter(); canProceed = false; jointEffects.Clear(); ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { SpawnJointEffect(joint1Name, modelChildLocator); SpawnJointEffect(joint2Name, modelChildLocator); SpawnJointEffect(joint3Name, modelChildLocator); } } public override void OnExit() { base.OnExit(); foreach (GameObject jointEffect in jointEffects) { UnityEngine.Object.Destroy(jointEffect); } jointEffects.Clear(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > minDuration && canProceed) { outer.SetNextState(new DeathState()); } } private void SpawnJointEffect(string jointName, ChildLocator childLocator) { Transform transform = childLocator.FindChild(jointName); if ((bool)transform) { GameObject item = UnityEngine.Object.Instantiate(jointEffectPrefab, transform); jointEffects.Add(item); } } } } namespace EntityStates.VoidMegaCrab { public class DeathState : GenericCharacterDeath { public static GameObject deathBombProjectile; public static float duration; public static string muzzleName; private Transform muzzleTransform; private static int EmptyStateHash = Animator.StringToHash("Empty"); private static int DeathStateHash = Animator.StringToHash("Death"); private static int DeathParamHash = Animator.StringToHash("Death.playbackRate"); protected override bool shouldAutoDestroy => false; protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayCrossfade("Body", DeathStateHash, DeathParamHash, duration, 0.1f); PlayAnimation("Left Gun Override (Arm)", EmptyStateHash); PlayAnimation("Right Gun Override (Arm)", EmptyStateHash); } public override void OnEnter() { base.OnEnter(); muzzleTransform = FindModelChild(muzzleName); if ((bool)muzzleTransform && base.isAuthority) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = deathBombProjectile; fireProjectileInfo.position = muzzleTransform.position; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat; fireProjectileInfo.crit = base.characterBody.RollCrit(); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { DestroyModel(); if (NetworkServer.active) { DestroyBodyAsapServer(); } } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class SpawnState : BaseState { [SerializeField] public float duration = 4f; [SerializeField] public string spawnSoundString; [SerializeField] public GameObject spawnEffectPrefab; [SerializeField] public string spawnMuzzleName; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(spawnSoundString, base.gameObject); if ((bool)spawnEffectPrefab) { EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnMuzzleName, transmit: false); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { modelTransform.GetComponent().enabled = true; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.VoidMegaCrab.Weapon { public class FireCrabCannonBase : BaseState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public int projectileCount = 3; [SerializeField] public float spread; [SerializeField] public float bonusPitch; [SerializeField] public float totalYawSpread = 5f; [SerializeField] public float baseDuration = 2f; [SerializeField] public float baseFireDuration = 0.2f; [SerializeField] public float damageCoefficient = 1.2f; [SerializeField] public float force = 20f; [SerializeField] public string attackSound; [SerializeField] public string muzzleName; [SerializeField] public string animationLayerName = "Gesture, Additive"; [SerializeField] public string animationStateName = "FireCrabCannon"; [SerializeField] public string animationPlaybackRateParam = "FireCrabCannon.playbackRate"; private float duration; private float fireDuration; private int projectilesFired; private Transform muzzleTransform; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; fireDuration = baseFireDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); muzzleTransform = FindModelChild(muzzleName); if (!muzzleTransform) { muzzleTransform = base.characterBody.aimOriginTransform; } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); int num = Mathf.FloorToInt(base.fixedAge / fireDuration * (float)projectileCount); if (projectilesFired <= num && projectilesFired < projectileCount) { FireProjectile(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireProjectile() { Util.PlaySound(attackSound, base.gameObject); base.characterBody.SetAimTimer(3f); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { Ray aimRay = GetAimRay(); int num = Mathf.FloorToInt((float)projectilesFired - (float)(projectileCount - 1) / 2f); float bonusYaw = 0f; if (projectileCount > 1) { bonusYaw = (float)num / (float)(projectileCount - 1) * totalYawSpread; } UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, spread, 1f, 1f, bonusYaw, bonusPitch); UnityEngine.Vector3 position = muzzleTransform.position; ProjectileManager.instance.FireProjectile(projectilePrefab, position, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } projectilesFired++; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireCrabBlackCannon : FireCrabCannonBase { } public class FireCrabWhiteCannon : FireCrabCannonBase { } public abstract class ChargeCrabCannonBase : BaseState { [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public float baseDuration = 2f; [SerializeField] public string soundName; [SerializeField] public string chargeMuzzleName; [SerializeField] public string animationLayerName = "Gesture, Additive"; [SerializeField] public string animationStateName = "FireCrabCannon"; [SerializeField] public string animationStateNamePreCharged = "FireCrabCannon"; [SerializeField] public string animationPlaybackRateParam = "FireCrabCannon.playbackRate"; [SerializeField] public float animationCrossfadeDuration = 0.2f; private GameObject chargeInstance; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex(animationLayerName); if (modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("Empty")) { PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateParam, duration, animationCrossfadeDuration); } else { PlayCrossfade(animationLayerName, animationStateNamePreCharged, animationPlaybackRateParam, duration, animationCrossfadeDuration); } } Util.PlaySound(soundName, base.gameObject); Transform transform = FindModelChild(chargeMuzzleName); if ((bool)chargeEffectPrefab && (bool)transform) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } base.characterBody.SetAimTimer(duration + 2f); } public override void OnExit() { base.OnExit(); if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(GetNextState()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } protected abstract FireCrabCannonBase GetNextState(); } public class ChargeCrabBlackCannon : ChargeCrabCannonBase { protected override FireCrabCannonBase GetNextState() { return new FireCrabBlackCannon(); } } public class ChargeCrabWhiteCannon : ChargeCrabCannonBase { protected override FireCrabCannonBase GetNextState() { return new FireCrabWhiteCannon(); } } } namespace EntityStates.VoidMegaCrab.BackWeapon { public class FireVoidMissiles : BaseSkillState { public static float baseDuration; public static string leftMuzzleString; public static string rightMuzzleString; public static GameObject muzzleEffectPrefab; public static GameObject projectilePrefab; public static int totalMissileWaveCount; public static float baseDurationBetweenMissiles; public static float damageCoefficient = 1.2f; public static float force = 20f; public static string enterSoundString; public static string animationLayerName = "Gesture, Additive"; public static string animationStateName = "FireCrabCannon"; public static string animationPlaybackRateParam = "FireCrabCannon.playbackRate"; private float duration; private float durationBetweenMissiles; private float missileTimer; private int missileWaveCount; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; durationBetweenMissiles = baseDurationBetweenMissiles / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); } private void FireMissile() { if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, leftMuzzleString, transmit: false); EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, rightMuzzleString, transmit: false); } if (base.isAuthority) { Transform transform = FindModelChild(leftMuzzleString); Transform transform2 = FindModelChild(rightMuzzleString); Ray ray = GetAimRay(); if (transform != null) { ray = new Ray(transform.position, transform.forward); } ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); if (transform2 != null) { ray = new Ray(transform2.position, transform2.forward); } ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void FixedUpdate() { base.FixedUpdate(); missileTimer -= GetDeltaTime(); if (missileWaveCount < totalMissileWaveCount && missileTimer <= 0f) { missileWaveCount++; missileTimer += durationBetweenMissiles; FireMissile(); } if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } } namespace EntityStates.VoidJailer { public class DeathState : GenericCharacterDeath { public static GameObject deathBombProjectile; public static float duration; public static string muzzleName; private Transform muzzleTransform; protected override bool shouldAutoDestroy => false; protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayCrossfade("Body", "Death", "Death.playbackRate", duration, 0.1f); } public override void OnEnter() { base.OnEnter(); muzzleTransform = FindModelChild(muzzleName); if ((bool)muzzleTransform && base.isAuthority) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = deathBombProjectile; fireProjectileInfo.position = muzzleTransform.position; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(base.characterDirection.forward, UnityEngine.Vector3.up); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat; fireProjectileInfo.crit = base.characterBody.RollCrit(); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { DestroyModel(); if (NetworkServer.active) { DestroyBodyAsapServer(); } } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class SpawnState : GenericCharacterSpawnState { public static GameObject spawnFXPrefab; public static string spawnFXTransformName; public override void OnEnter() { base.OnEnter(); PlaySpawnFX(); } private void PlaySpawnFX() { if (spawnFXPrefab != null && !string.IsNullOrEmpty(spawnFXTransformName)) { EffectManager.SimpleMuzzleFlash(spawnFXPrefab, base.gameObject, spawnFXTransformName, transmit: false); } } } public class Capture : BaseState { public static string animationLayerName; public static string animationStateName; public static string animationPlaybackRateName; public static GameObject chargeVfxPrefab; [SerializeField] public float duration; public static GameObject tetherPrefab; public static GameObject captureRangeEffect; public static float effectScaleCoefficient; public static float effectScaleAddition; public static string muzzleName; public static string tetherOriginName; public static float maxTetherDistance; public static float tetherReelSpeed; public static float damagePerSecond; public static float damageTickFrequency; public static BuffDef tetherDebuff; public static float innerRange; public static BuffDef innerRangeDebuff; public static float innerRangeDebuffDuration; public static GameObject innerRangeDebuffEffect; public static bool singleDurationReset; public static string captureLoopSoundString; private Transform muzzleTransform; private List tetherControllers = new List(); private uint soundID; private bool initialized; private bool shouldModifyTetherDuration = true; private GameObject rangeEffect; private GameObject _chargeVfxInstance; public override void OnEnter() { muzzleTransform = FindModelChild(muzzleName); if (NetworkServer.active) { InitializeTethers(); } if (NetworkServer.active && base.isAuthority && tetherControllers.Count == 0) { outer.SetNextState(new ExitCapture()); return; } base.OnEnter(); duration /= attackSpeedStat; FireTethers(); } private void InitializeTethers() { UnityEngine.Vector3 position = muzzleTransform.position; float breakDistanceSqr = maxTetherDistance * maxTetherDistance; tetherControllers = new List(); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = position; bullseyeSearch.maxDistanceFilter = maxTetherDistance; bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(base.teamComponent.teamIndex); bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.filterByLoS = true; bullseyeSearch.searchDirection = UnityEngine.Vector3.up; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); List list = bullseyeSearch.GetResults().ToList(); for (int i = 0; i < list.Count; i++) { GameObject gameObject = list[i].healthComponent.gameObject; if ((bool)gameObject && !TargetIsTethered(gameObject.GetComponent())) { GameObject obj = UnityEngine.Object.Instantiate(tetherPrefab, position, UnityEngine.Quaternion.identity, muzzleTransform); JailerTetherController component = obj.GetComponent(); component.NetworkownerRoot = base.gameObject; component.Networkorigin = muzzleTransform.gameObject; component.NetworktargetRoot = gameObject; component.breakDistanceSqr = breakDistanceSqr; component.damageCoefficientPerTick = damagePerSecond / damageTickFrequency; component.tickInterval = 1f / damageTickFrequency; component.tickTimer = (float)i * 0.1f; component.NetworkreelSpeed = tetherReelSpeed; component.SetTetheredBuff(tetherDebuff); tetherControllers.Add(component); NetworkServer.Spawn(obj); } } initialized = true; } private static bool TargetIsTethered(CharacterBody characterBody) { if (characterBody != null) { return characterBody.HasBuff(tetherDebuff); } return false; } private void FireTethers() { PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration); soundID = Util.PlayAttackSpeedSound(captureLoopSoundString, base.gameObject, attackSpeedStat); if (!muzzleTransform) { return; } if ((bool)captureRangeEffect) { rangeEffect = UnityEngine.Object.Instantiate(captureRangeEffect, base.characterBody.transform); rangeEffect.transform.localScale = effectScaleCoefficient * (maxTetherDistance + effectScaleAddition) * UnityEngine.Vector3.one; ScaleParticleSystemDuration component = rangeEffect.GetComponent(); if ((bool)component) { component.newDuration = duration; } } if ((bool)chargeVfxPrefab) { _chargeVfxInstance = UnityEngine.Object.Instantiate(chargeVfxPrefab, muzzleTransform.position, muzzleTransform.rotation, muzzleTransform); ScaleParticleSystemDuration component2 = _chargeVfxInstance.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } } public override void FixedUpdate() { base.FixedUpdate(); if (initialized) { UpdateTethers(base.gameObject.transform.position); if (tetherControllers.Count == 0 || base.fixedAge >= duration) { outer.SetNextState(new ExitCapture()); } } } private void UpdateTethers(UnityEngine.Vector3 origin) { for (int num = tetherControllers.Count - 1; num >= 0; num--) { JailerTetherController jailerTetherController = tetherControllers[num]; if (!jailerTetherController) { tetherControllers.RemoveAt(num); } else { CharacterBody targetBody = jailerTetherController.GetTargetBody(); if (!(targetBody == null) && !targetBody.HasBuff(innerRangeDebuff) && UnityEngine.Vector3.Distance(origin, targetBody.transform.position) < innerRange) { float num2 = duration - base.fixedAge; targetBody.AddTimedBuff(innerRangeDebuff, innerRangeDebuffDuration); if (shouldModifyTetherDuration) { duration = ((num2 > innerRangeDebuffDuration) ? innerRangeDebuffDuration : (innerRangeDebuffDuration + base.fixedAge)); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, innerRangeDebuffDuration); shouldModifyTetherDuration = !singleDurationReset; if ((bool)_chargeVfxInstance) { ScaleParticleSystemDuration component = _chargeVfxInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } jailerTetherController.NetworkreelSpeed = 0f; } } } } public override void OnExit() { DestroyTethers(); if ((bool)rangeEffect) { EntityState.Destroy(rangeEffect); } if ((bool)_chargeVfxInstance) { EntityState.Destroy(_chargeVfxInstance); } AkSoundEngine.StopPlayingID(soundID); base.OnExit(); } private void DestroyTethers() { if (tetherControllers == null) { return; } for (int num = tetherControllers.Count - 1; num >= 0; num--) { if ((bool)tetherControllers[num]) { EntityState.Destroy(tetherControllers[num].gameObject); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class CaptureFire : BaseState { public static string animationLayerName; public static string animationStateName; public static string animationPlaybackRateName; public static float duration; public static string enterSoundString; public static float exitCrossfadeDuration; public static string crossfadeStateName; public override void OnEnter() { base.OnEnter(); duration /= attackSpeedStat; Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { Capture nextState = new Capture(); outer.SetNextState(nextState); } } public override void OnExit() { PlayCrossfade(animationLayerName, crossfadeStateName, animationPlaybackRateName, exitCrossfadeDuration, exitCrossfadeDuration); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.VoidJailer.Weapon { public class Capture2 : BaseState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateName; [SerializeField] public float baseDuration; [SerializeField] public string enterSoundString; [SerializeField] public float pullFieldOfView; [SerializeField] public float pullMinDistance; [SerializeField] public float pullMaxDistance; [SerializeField] public AnimationCurve pullSuitabilityCurve; [SerializeField] public GameObject pullTracerPrefab; [SerializeField] public float pullLiftVelocity; [SerializeField] public BuffDef debuffDef; [SerializeField] public float debuffDuration; [SerializeField] public float damageCoefficient; [SerializeField] public float procCoefficient; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public string muzzleString; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); } Ray aimRay = GetAimRay(); if (!NetworkServer.active) { return; } BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.all; bullseyeSearch.maxAngleFilter = pullFieldOfView * 0.5f; bullseyeSearch.maxDistanceFilter = pullMaxDistance; bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.filterByLoS = true; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); GetTeam(); if (!hurtBox) { return; } UnityEngine.Vector3 vector = hurtBox.transform.position - aimRay.origin; float magnitude = vector.magnitude; UnityEngine.Vector3 vector2 = vector / magnitude; float num = 1f; CharacterBody body = hurtBox.healthComponent.body; if ((bool)body.characterMotor) { num = body.characterMotor.mass; } else if ((bool)hurtBox.healthComponent.GetComponent()) { num = base.rigidbody.mass; } if ((bool)debuffDef) { body.AddTimedBuff(debuffDef, debuffDuration); } float num2 = pullSuitabilityCurve.Evaluate(num); UnityEngine.Vector3 vector3 = vector2; float num3 = Trajectory.CalculateInitialYSpeedForHeight(Mathf.Abs(pullMinDistance - magnitude)) * Mathf.Sign(pullMinDistance - magnitude); vector3 *= num3; vector3.y = pullLiftVelocity; DamageInfo damageInfo = new DamageInfo { attacker = base.gameObject, damage = damageStat * damageCoefficient, position = hurtBox.transform.position, procCoefficient = procCoefficient }; hurtBox.healthComponent.TakeDamageForce(vector3 * (num * num2), alwaysApply: true, disableAirControlUntilCollision: true); hurtBox.healthComponent.TakeDamage(damageInfo); GlobalEventManager.instance.OnHitEnemy(damageInfo, hurtBox.healthComponent.gameObject); if ((bool)pullTracerPrefab) { UnityEngine.Vector3 position = hurtBox.transform.position; UnityEngine.Vector3 start = base.characterBody.corePosition; Transform transform = FindModelChild(muzzleString); if ((bool)transform) { start = transform.position; } EffectData effectData = new EffectData { origin = position, start = start }; EffectManager.SpawnEffect(pullTracerPrefab, effectData, transmit: true); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new ExitCapture()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ChargeCapture : BaseState { public static string animationLayerName; public static string animationStateName; public static string animationPlaybackRateName; public static float duration; public static string enterSoundString; public static GameObject chargeEffectPrefab; public static GameObject attackIndicatorPrefab; public static string muzzleString; private float _crossFadeDuration; private uint soundID; private GameObject attackIndicatorInstance; public override void OnEnter() { base.OnEnter(); duration /= attackSpeedStat; _crossFadeDuration = duration * 0.25f; PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateName, duration, _crossFadeDuration); soundID = Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); if ((bool)chargeEffectPrefab) { EffectManager.SimpleMuzzleFlash(chargeEffectPrefab, base.gameObject, muzzleString, transmit: false); } if ((bool)attackIndicatorPrefab) { Transform coreTransform = base.characterBody.coreTransform; if ((bool)coreTransform) { attackIndicatorInstance = UnityEngine.Object.Instantiate(attackIndicatorPrefab, coreTransform); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new Capture2()); } } public override void Update() { if ((bool)attackIndicatorInstance) { attackIndicatorInstance.transform.forward = GetAimRay().direction; } base.Update(); } public override void OnExit() { AkSoundEngine.StopPlayingID(soundID); if ((bool)attackIndicatorInstance) { EntityState.Destroy(attackIndicatorInstance); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ChargeFire : BaseState { public static string attackSoundEffect; public static string animationLayerName; public static string animationStateName; public static string animationPlaybackRateName; public static float baseDuration; public static GameObject chargeVfxPrefab; private float _totalDuration; private float _crossFadeDuration; private float _chargingDuration; private GameObject _chargeVfxInstance; public override void OnEnter() { base.OnEnter(); _totalDuration = baseDuration / attackSpeedStat; _crossFadeDuration = _totalDuration * 0.25f; _chargingDuration = _totalDuration - _crossFadeDuration; Transform modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(attackSoundEffect, base.gameObject, attackSpeedStat); if (modelTransform != null) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("ClawMuzzle"); if ((bool)transform && (bool)chargeVfxPrefab) { _chargeVfxInstance = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform.position, transform.rotation, transform); ScaleParticleSystemDuration component2 = _chargeVfxInstance.GetComponent(); if ((bool)component2) { component2.newDuration = _totalDuration; } } } } PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateName, _chargingDuration, _crossFadeDuration); base.characterBody.SetAimTimer(_totalDuration + 3f); } public override void Update() { base.Update(); if ((bool)_chargeVfxInstance) { Ray aimRay = GetAimRay(); _chargeVfxInstance.transform.forward = aimRay.direction; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= _totalDuration && base.isAuthority) { Fire nextState = new Fire(); outer.SetNextState(nextState); } } public override void OnExit() { base.OnExit(); if ((bool)_chargeVfxInstance) { EntityState.Destroy(_chargeVfxInstance); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ExitCapture : BaseState { public static string animationLayerName; public static string animationStateName; public static string animationPlaybackRateName; public static float duration; public static string enterSoundString; public override void OnEnter() { base.OnEnter(); duration /= attackSpeedStat; Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class Fire : GenericProjectileBaseState { public static string animationLayerName; public static string animationStateName; public static string animationPlaybackRateName; public static int totalProjectileCount; public static float maxRandomDistance; public static float basePriorityReductionDuration; private float priorityReductionDuration; private Transform muzzleTransform; public override void OnEnter() { muzzleTransform = FindModelChild("ClawMuzzle"); base.OnEnter(); base.characterBody.SetAimTimer(duration + 3f); for (int i = 1; i < totalProjectileCount; i++) { FireProjectile(); } priorityReductionDuration = basePriorityReductionDuration / attackSpeedStat; } protected override Ray ModifyProjectileAimRay(Ray aimRay) { aimRay.origin += UnityEngine.Random.insideUnitSphere * maxRandomDistance; return aimRay; } protected override void PlayAnimation(float duration) { PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration); } public override InterruptPriority GetMinimumInterruptPriority() { if (!(base.fixedAge > priorityReductionDuration)) { return InterruptPriority.PrioritySkill; } return InterruptPriority.Skill; } } } namespace EntityStates.VoidInfestor { public class Death : GenericCharacterDeath { public static float deathDelay; public static GameObject deathEffectPrefab; private bool hasDied; public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > deathDelay && NetworkServer.active && !hasDied) { hasDied = true; EffectManager.SimpleImpactEffect(deathEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: true); DestroyBodyAsapServer(); EntityState.Destroy(base.gameObject); } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class Infest : BaseState { public static GameObject enterEffectPrefab; public static GameObject successfulInfestEffectPrefab; public static GameObject infestVfxPrefab; public static string enterSoundString; public static float searchMaxDistance; public static float searchMaxAngle; public static float velocityInitialSpeed; public static float velocityTurnRate; public static float infestDamageCoefficient; private Transform targetTransform; private GameObject infestVfxInstance; private OverlapAttack attack; private List victimsStruck = new List(); private static int InfestStateHash = Animator.StringToHash("Infest"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", InfestStateHash); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)enterEffectPrefab) { EffectManager.SimpleImpactEffect(enterEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: false); } if ((bool)infestVfxPrefab) { infestVfxInstance = UnityEngine.Object.Instantiate(infestVfxPrefab, base.transform.position, UnityEngine.Quaternion.identity); infestVfxInstance.transform.parent = base.transform; } HitBoxGroup hitBoxGroup = null; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Infest"); } attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = GetTeam(); attack.damage = infestDamageCoefficient * damageStat; attack.hitEffectPrefab = null; attack.hitBoxGroup = hitBoxGroup; attack.isCrit = RollCrit(); attack.damageType = DamageType.Stun1s; attack.damageColorIndex = DamageColorIndex.Void; BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.viewer = base.characterBody; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; bullseyeSearch.teamMaskFilter.RemoveTeam(base.characterBody.teamComponent.teamIndex); bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.minDistanceFilter = 0f; bullseyeSearch.maxDistanceFilter = searchMaxDistance; bullseyeSearch.searchOrigin = base.inputBank.aimOrigin; bullseyeSearch.searchDirection = base.inputBank.aimDirection; bullseyeSearch.maxAngleFilter = searchMaxAngle; bullseyeSearch.filterByLoS = true; bullseyeSearch.RefreshCandidates(); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); if ((bool)hurtBox) { targetTransform = hurtBox.transform; if ((bool)base.characterMotor) { UnityEngine.Vector3 position = targetTransform.position; float num = velocityInitialSpeed; UnityEngine.Vector3 vector = position - base.transform.position; UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z); float magnitude = vector2.magnitude; float y = Trajectory.CalculateInitialYSpeed(magnitude / num, vector.y); UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(vector2.x / magnitude * num, y, vector2.y / magnitude * num); base.characterMotor.velocity = vector3; base.characterMotor.disableAirControlUntilCollision = true; base.characterMotor.Motor.ForceUnground(); base.characterDirection.forward = vector3; } } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)targetTransform && (bool)base.characterMotor) { UnityEngine.Vector3 target = targetTransform.position - base.transform.position; UnityEngine.Vector3 velocity = base.characterMotor.velocity; velocity = UnityEngine.Vector3.RotateTowards(velocity, target, velocityTurnRate * GetDeltaTime() * (MathF.PI / 180f), 0f); base.characterMotor.velocity = velocity; if (NetworkServer.active && attack.Fire(victimsStruck)) { for (int i = 0; i < victimsStruck.Count; i++) { HealthComponent obj = victimsStruck[i].healthComponent; CharacterBody body = obj.body; CharacterMaster master = body.master; if (obj.alive && master != null && !body.isPlayerControlled && !body.bodyFlags.HasFlag(CharacterBody.BodyFlags.Mechanical)) { master.teamIndex = TeamIndex.Void; body.teamComponent.teamIndex = TeamIndex.Void; body.inventory.SetEquipmentIndex(DLC1Content.Elites.Void.eliteEquipmentDef.equipmentIndex); BaseAI component = master.GetComponent(); if ((bool)component) { component.enemyAttention = 0f; component.ForceAcquireNearestEnemyIfNoCurrentEnemy(); } base.healthComponent.Suicide(); if ((bool)successfulInfestEffectPrefab) { EffectManager.SimpleImpactEffect(successfulInfestEffectPrefab, base.transform.position, UnityEngine.Vector3.up, transmit: false); } break; } } } } if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterMotor.velocity; } if (base.isAuthority && (bool)base.characterMotor && base.characterMotor.isGrounded && base.fixedAge > 0.1f) { outer.SetNextStateToMain(); } } public override void OnExit() { if ((bool)infestVfxInstance) { EntityState.Destroy(infestVfxInstance); } base.OnExit(); } } public class Spawn : BaseState { public static GameObject spawnEffectPrefab; public static float velocityStrength; public static float spread; private static int SpawnStateHash = Animator.StringToHash("Spawn"); public override void OnEnter() { base.OnEnter(); if ((bool)spawnEffectPrefab) { EffectManager.SimpleImpactEffect(spawnEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: false); } if ((bool)base.characterMotor) { UnityEngine.Vector3 vector = (UnityEngine.Vector3.up + UnityEngine.Random.onUnitSphere * spread) * velocityStrength; base.characterMotor.ApplyForce(vector, alwaysApply: true, disableAirControlUntilCollision: true); base.characterDirection.forward = vector; } PlayAnimation("Base", SpawnStateHash); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && (bool)base.characterMotor && base.characterMotor.isGrounded && base.fixedAge > 0.1f) { outer.SetNextStateToMain(); } } } } namespace EntityStates.VoidCamp { public class Deactivate : EntityState { [SerializeField] public float duration; [SerializeField] public string onEnterSoundString; [SerializeField] public string baseAnimationLayerName; [SerializeField] public string baseAnimationStateName; [SerializeField] public string deactivateChildName; [SerializeField] public string additiveAnimationLayerName; [SerializeField] public string additiveAnimationStateName; [SerializeField] public string completeObjectiveChatMessageToken; [SerializeField] public PickupDropTable rewardDropTable; [SerializeField] public GameObject rewardPickupPrefab; [SerializeField] public bool dropItem; public override void OnEnter() { base.OnEnter(); PlayAnimation(additiveAnimationLayerName, additiveAnimationStateName); FogDamageController componentInChildren = outer.GetComponentInChildren(); if ((bool)componentInChildren) { componentInChildren.enabled = false; } Util.PlaySound(onEnterSoundString, base.gameObject); ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { modelChildLocator.FindChild("ActiveFX").gameObject.SetActive(value: false); modelChildLocator.FindChild("RangeFX").GetComponent().enabled = true; } Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = completeObjectiveChatMessageToken }); if (!NetworkServer.active || !dropItem) { return; } Transform transform = modelChildLocator.FindChild("RewardSpawnTarget"); int participatingPlayerCount = Run.instance.participatingPlayerCount; if (participatingPlayerCount > 0 && (bool)transform && (bool)rewardDropTable) { int num = participatingPlayerCount; float angle = 360f / (float)num; UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); UnityEngine.Vector3 position = transform.transform.position; PickupPickerController.Option[] pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(3, rewardDropTable, Run.instance.treasureRng); int num2 = 0; while (num2 < num) { GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo); pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(ItemTier.VoidTier2); pickupInfo.pickerOptions = pickerOptions; pickupInfo.rotation = UnityEngine.Quaternion.identity; pickupInfo.prefabOverride = rewardPickupPrefab; pickupInfo.position = position; PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector); num2++; vector = quaternion * vector; } } } public override void OnExit() { PlayAnimation(baseAnimationLayerName, baseAnimationStateName); ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { modelChildLocator.FindChildGameObject(deactivateChildName).gameObject.SetActive(value: false); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new EntityStates.Idle()); } } } public class Idle : EntityState { private class VoidCampObjectiveTracker : ObjectivePanelController.ObjectiveTracker { protected override string GenerateString() { int count = TeamComponent.GetTeamMembers(TeamIndex.Void).Count; return string.Format(Language.GetString("OBJECTIVE_VOIDCAMP"), count); } protected override bool IsDirty() { return true; } } [SerializeField] public string baseAnimationLayerName; [SerializeField] public string baseAnimationStateName; [SerializeField] public string additiveAnimationLayerName; [SerializeField] public string additiveAnimationStateName; [SerializeField] public float clearCheckRate; [SerializeField] public float initialClearCheckDelay; [SerializeField] public LoopSoundDef loopSoundDef; [SerializeField] public int indicatorMaxTeamCountThreshold; [SerializeField] public GameObject indicatorPrefab; private LoopSoundManager.SoundLoopPtr loopPtr; private bool hasEnabledIndicators; private HashSet indicatedNetIds; private float countdown; public override void OnEnter() { base.OnEnter(); PlayAnimation(baseAnimationLayerName, baseAnimationStateName); PlayAnimation(additiveAnimationLayerName, additiveAnimationStateName); loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSoundDef); countdown = initialClearCheckDelay; indicatedNetIds = new HashSet(); GetComponent().enabled = true; ObjectivePanelController.collectObjectiveSources += OnCollectObjectiveSources; } private void OnCollectObjectiveSources(CharacterMaster master, List objectiveSourcesList) { objectiveSourcesList.Add(new ObjectivePanelController.ObjectiveSourceDescriptor { master = master, objectiveType = typeof(VoidCampObjectiveTracker), source = base.gameObject }); } public override void FixedUpdate() { base.FixedUpdate(); countdown -= GetDeltaTime(); if (!(countdown < 0f)) { return; } countdown = clearCheckRate; ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Void); int count = teamMembers.Count; if (count <= 0) { outer.SetNextState(new Deactivate()); } else { if (!hasEnabledIndicators && count > indicatorMaxTeamCountThreshold) { return; } hasEnabledIndicators = true; foreach (TeamComponent item in teamMembers) { if ((bool)item && (bool)item.body && (bool)item.body.master) { RequestIndicatorForMaster(item.body.master); } } } } public override void OnExit() { LoopSoundManager.StopSoundLoopLocal(loopPtr); GetComponent().enabled = false; ObjectivePanelController.collectObjectiveSources -= OnCollectObjectiveSources; base.OnExit(); } protected void RequestIndicatorForMaster(CharacterMaster master) { if (indicatedNetIds.Contains(master.netId)) { return; } GameObject bodyObject = master.GetBodyObject(); if ((bool)bodyObject) { TeamComponent component = bodyObject.GetComponent(); if ((bool)component) { indicatedNetIds.Add(master.netId); component.RequestDefaultIndicator(indicatorPrefab); } } } } } namespace EntityStates.VoidBarnacle { public class DeathState : GenericCharacterDeath { public static string animationLayerName; public static string animationStateName; public static string animationPlaybackRateName; public static float duration; public static GameObject deathFXPrefab; public override void OnEnter() { base.OnEnter(); if (deathFXPrefab != null) { EffectManager.SimpleEffect(deathFXPrefab, base.transform.position, base.transform.rotation, transmit: true); } PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && NetworkServer.active) { EntityState.Destroy(base.gameObject); } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class FindSurface : NoCastSpawn { public static int raycastCount; public static float maxRaycastLength; public static float raycastSphereYOffset; public static float raycastMinimumAngle; public static float raycastMaximumAngle; private const float _cRadianConversionCoeficcient = MathF.PI / 180f; public override void OnEnter() { base.OnEnter(); RaycastHit hitInfo = default(RaycastHit); UnityEngine.Vector3 origin = new UnityEngine.Vector3(base.characterBody.corePosition.x, base.characterBody.corePosition.y + raycastSphereYOffset, base.characterBody.corePosition.z); if (!base.isAuthority) { return; } raycastMinimumAngle = Mathf.Clamp(raycastMinimumAngle, 0f, raycastMaximumAngle); raycastMaximumAngle = Mathf.Clamp(raycastMaximumAngle, raycastMinimumAngle, 90f); raycastCount = Mathf.Abs(raycastCount); float num = 360f / (float)raycastCount; for (int i = 0; i < raycastCount; i++) { float minInclusive = num * (float)i; float maxInclusive = num * (float)(i + 1) - 1f; float f = UnityEngine.Random.Range(minInclusive, maxInclusive) * (MathF.PI / 180f); float f2 = UnityEngine.Random.Range(raycastMinimumAngle, raycastMaximumAngle) * (MathF.PI / 180f); float x = Mathf.Cos(f); float y = Mathf.Sin(f2); float z = Mathf.Sin(f); UnityEngine.Vector3 direction = new UnityEngine.Vector3(x, y, z); if (Physics.Raycast(origin, direction, out hitInfo, maxRaycastLength, LayerIndex.world.mask)) { base.transform.position = hitInfo.point; base.transform.up = hitInfo.normal; break; } } } } public class NoCastSpawn : BaseState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateName; [SerializeField] public float duration; [SerializeField] public string enterSoundString; [SerializeField] public GameObject spawnFXPrefab; [SerializeField] public string spawnFXTransformName; public override void OnEnter() { base.OnEnter(); if (spawnFXPrefab != null) { EffectManager.SimpleMuzzleFlash(spawnFXPrefab, base.gameObject, spawnFXTransformName, transmit: false); } PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration); Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } } namespace EntityStates.VoidBarnacle.Weapon { public class ChargeFire : BaseState { [SerializeField] public float baseDuration; [SerializeField] public GameObject chargeVfxPrefab; [SerializeField] public string attackSoundEffect; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateName; private float _chargingDuration; private float _totalDuration; private float _crossFadeDuration; private GameObject _chargeVfxInstance; public override void OnEnter() { base.OnEnter(); _totalDuration = baseDuration / attackSpeedStat; _crossFadeDuration = _totalDuration * 0.25f; _chargingDuration = _totalDuration - _crossFadeDuration; Transform modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(attackSoundEffect, base.gameObject, attackSpeedStat); if (modelTransform != null) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleMouth"); if ((bool)transform && (bool)chargeVfxPrefab) { _chargeVfxInstance = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform.position, transform.rotation, transform); ScaleParticleSystemDuration component2 = _chargeVfxInstance.GetComponent(); if ((bool)component2) { component2.newDuration = _totalDuration; } } } } PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateName, _chargingDuration, _crossFadeDuration); } public override void Update() { base.Update(); if ((bool)_chargeVfxInstance) { Ray aimRay = GetAimRay(); _chargeVfxInstance.transform.forward = aimRay.direction; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= _totalDuration && base.isAuthority) { Fire nextState = new Fire(); outer.SetNextState(nextState); } } public override void OnExit() { base.OnExit(); if ((bool)_chargeVfxInstance) { EntityState.Destroy(_chargeVfxInstance); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Fire : GenericProjectileBaseState { [SerializeField] public int numberOfFireballs; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateName; private float _interFireballDuration; private float _animationDuration; private Transform muzzleTransform; public override void OnEnter() { duration = baseDuration / attackSpeedStat; _interFireballDuration = duration / (float)numberOfFireballs; _animationDuration = _interFireballDuration; muzzleTransform = FindModelChild(targetMuzzle); base.OnEnter(); } public override void FixedUpdate() { base.FixedUpdate(); if (stopwatch >= _animationDuration && numberOfFireballs > 0) { _animationDuration += _animationDuration; PlayAnimation(_animationDuration); } } protected override void PlayAnimation(float duration) { PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, _interFireballDuration); } protected override void FireProjectile() { base.FireProjectile(); if (numberOfFireballs > 1) { firedProjectile = false; delayBeforeFiringProjectile += _interFireballDuration; } numberOfFireballs--; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.Vermin { public class SpawnState : GenericCharacterSpawnState { } } namespace EntityStates.Vermin.Weapon { public class TongueLash : BasicMeleeAttack { protected override void PlayAnimation() { PlayCrossfade("Gesture, Additive", "TongueLash", "TongueLash.playbackRate", duration, 0.1f); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); } } } namespace EntityStates.VagrantNovaItem { public class BaseVagrantNovaItemState : BaseBodyAttachmentState { protected ParticleSystem chargeSparks; protected int GetItemStack() { if (!base.attachedBody || !base.attachedBody.inventory) { return 1; } return base.attachedBody.inventory.GetItemCount(RoR2Content.Items.NovaOnLowHealth); } public override void OnEnter() { base.OnEnter(); ChildLocator component = GetComponent(); if (!component) { return; } chargeSparks = component.FindChild("ChargeSparks")?.GetComponent(); if ((bool)chargeSparks) { ParticleSystem.ShapeModule shape = chargeSparks.shape; SkinnedMeshRenderer skinnedMeshRenderer = FindAttachedBodyMainRenderer(); if ((bool)skinnedMeshRenderer) { shape.skinnedMeshRenderer = FindAttachedBodyMainRenderer(); ParticleSystem.MainModule main = chargeSparks.main; float x = skinnedMeshRenderer.transform.lossyScale.x; main.startSize = 0.5f / x; } } } protected void SetChargeSparkEmissionRateMultiplier(float multiplier) { if ((bool)chargeSparks) { ParticleSystem.EmissionModule emission = chargeSparks.emission; emission.rateOverTimeMultiplier = multiplier * 20f; } } private SkinnedMeshRenderer FindAttachedBodyMainRenderer() { if (!base.attachedBody) { return null; } CharacterModel.RendererInfo[] array = base.attachedBody.modelLocator?.modelTransform.GetComponent()?.baseRendererInfos; if (array == null) { return null; } for (int i = 0; i < array.Length; i++) { if (array[i].renderer is SkinnedMeshRenderer result) { return result; } } return null; } } public class RechargeState : BaseVagrantNovaItemState { public static float baseDuration = 30f; public static AnimationCurve particleEmissionCurve; private float rechargeDuration; public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { int itemStack = GetItemStack(); float num = baseDuration / (float)(itemStack + 1); float num2 = base.fixedAge / num; if (num2 >= 1f) { num2 = 1f; outer.SetNextState(new ReadyState()); } SetChargeSparkEmissionRateMultiplier(particleEmissionCurve.Evaluate(num2)); } } } public class ReadyState : BaseVagrantNovaItemState { private HealthComponent attachedHealthComponent; public override void OnEnter() { base.OnEnter(); attachedHealthComponent = base.attachedBody?.healthComponent; SetChargeSparkEmissionRateMultiplier(1f); GlobalEventManager.onServerDamageDealt += OnDamaged; } public override void OnExit() { base.OnExit(); GlobalEventManager.onServerDamageDealt -= OnDamaged; } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && attachedHealthComponent.isHealthLow) { outer.SetNextState(new ChargeState()); } } private void OnDamaged(DamageReport report) { if (report.hitLowHealth && (object)report?.victim?.body == base.attachedBody) { outer.SetNextState(new ChargeState()); } } } public class ChargeState : BaseVagrantNovaItemState { public static float baseDuration = 3f; public static string chargeSound; private float duration; private GameObject chargeVfxInstance; private GameObject areaIndicatorVfxInstance; public override void OnEnter() { base.OnEnter(); duration = baseDuration / (base.attachedBody ? base.attachedBody.attackSpeed : 1f); SetChargeSparkEmissionRateMultiplier(1f); if ((bool)base.attachedBody) { UnityEngine.Vector3 position = base.transform.position; UnityEngine.Quaternion rotation = base.transform.rotation; chargeVfxInstance = UnityEngine.Object.Instantiate(ChargeMegaNova.chargingEffectPrefab, position, rotation); chargeVfxInstance.transform.localScale = UnityEngine.Vector3.one * 0.25f; Util.PlaySound(chargeSound, base.gameObject); areaIndicatorVfxInstance = UnityEngine.Object.Instantiate(ChargeMegaNova.areaIndicatorPrefab, position, rotation); ObjectScaleCurve component = areaIndicatorVfxInstance.GetComponent(); component.timeMax = duration; component.baseScale = UnityEngine.Vector3.one * DetonateState.blastRadius * 2f; areaIndicatorVfxInstance.GetComponent().timeMax = duration; } RoR2Application.onLateUpdate += OnLateUpdate; } public override void OnExit() { RoR2Application.onLateUpdate -= OnLateUpdate; if ((object)chargeVfxInstance != null) { EntityState.Destroy(chargeVfxInstance); chargeVfxInstance = null; } if ((object)areaIndicatorVfxInstance != null) { EntityState.Destroy(areaIndicatorVfxInstance); areaIndicatorVfxInstance = null; } base.OnExit(); } private void OnLateUpdate() { if ((bool)chargeVfxInstance) { chargeVfxInstance.transform.position = base.transform.position; } if ((bool)areaIndicatorVfxInstance) { areaIndicatorVfxInstance.transform.position = base.transform.position; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new DetonateState()); } } } public class DetonateState : BaseVagrantNovaItemState { public static float blastRadius; public static float blastDamageCoefficient; public static float blastProcCoefficient; public static float blastForce; public static float baseDuration; public static string explosionSound; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration; if (NetworkServer.active && (bool)base.attachedBody) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.attachedBody.gameObject; blastAttack.baseDamage = base.attachedBody.damage * blastDamageCoefficient; blastAttack.baseForce = blastForce; blastAttack.bonusForce = UnityEngine.Vector3.zero; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = base.attachedBody.RollCrit(); blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.damageType = DamageType.Generic; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.inflictor = base.gameObject; blastAttack.position = base.attachedBody.corePosition; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = blastProcCoefficient; blastAttack.radius = blastRadius; blastAttack.losType = BlastAttack.LoSType.NearestHit; blastAttack.teamIndex = base.attachedBody.teamComponent.teamIndex; blastAttack.Fire(); EffectData effectData = new EffectData(); effectData.origin = base.attachedBody.corePosition; effectData.SetHurtBoxReference(base.attachedBody.mainHurtBox); EffectManager.SpawnEffect(FireMegaNova.novaEffectPrefab, effectData, transmit: true); } SetChargeSparkEmissionRateMultiplier(0f); Util.PlaySound(explosionSound, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new RechargeState()); } } } } namespace EntityStates.UrchinTurret { public class DeathState : BaseState { public static GameObject initialExplosion; public static float effectScale; public static string deathString; public override void OnEnter() { base.OnEnter(); Util.PlaySound(deathString, base.gameObject); Transform transform = FindModelChild("Muzzle"); if (base.isAuthority) { if ((bool)initialExplosion) { EffectManager.SpawnEffect(initialExplosion, new EffectData { origin = transform.position, scale = effectScale }, transmit: true); } EntityState.Destroy(base.gameObject); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class SpawnState : GenericCharacterSpawnState { } } namespace EntityStates.UrchinTurret.Weapon { public class MinigunState : BaseState { public static string muzzleName; protected Transform muzzleTransform; protected ref InputBankTest.ButtonState skillButtonState => ref base.inputBank.skill1; public override void OnEnter() { base.OnEnter(); muzzleTransform = FindModelChild(muzzleName); } public override void FixedUpdate() { base.FixedUpdate(); StartAimMode(); } public override void OnExit() { base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class MinigunSpinUp : MinigunState { public static float baseDuration; public static string sound; public static GameObject chargeEffectPrefab; private GameObject chargeInstance; private float duration; private EffectManagerHelper _emh_chargeInstance; public override void Reset() { base.Reset(); duration = 0f; chargeInstance = null; _emh_chargeInstance = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(sound, base.gameObject); PlayCrossfade("Gesture, Additive", "EnterShootLoop", 0.2f); if ((bool)muzzleTransform && (bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation); } else { _emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation); chargeInstance = _emh_chargeInstance.gameObject; } chargeInstance.transform.parent = muzzleTransform; ScaleParticleSystemDuration component = chargeInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new MinigunFire()); } } public override void OnExit() { base.OnExit(); if ((bool)chargeInstance) { if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null) { _emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance); } else { EntityState.Destroy(chargeInstance); } _emh_chargeInstance = null; chargeInstance = null; } } } public class MinigunSpinDown : MinigunState { public static float baseDuration; public static string sound; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(sound, base.gameObject, attackSpeedStat); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class MinigunFire : MinigunState { public static GameObject muzzleVfxPrefab; public static GameObject projectilePrefab; public static float baseFireInterval; public static float baseDamagePerSecondCoefficient; public static float bulletMinSpread; public static float bulletMaxSpread; public static string fireSound; public static string startSound; public static string endSound; private float fireTimer; private Transform muzzleVfxTransform; private float baseFireRate; private float baseBulletsPerSecond; private Run.FixedTimeStamp critEndTime; private Run.FixedTimeStamp lastCritCheck; public override void OnEnter() { base.OnEnter(); if ((bool)muzzleTransform && (bool)muzzleVfxPrefab) { muzzleVfxTransform = UnityEngine.Object.Instantiate(muzzleVfxPrefab, muzzleTransform).transform; } baseFireRate = 1f / baseFireInterval; baseBulletsPerSecond = baseFireRate; critEndTime = Run.FixedTimeStamp.negativeInfinity; lastCritCheck = Run.FixedTimeStamp.negativeInfinity; Util.PlaySound(startSound, base.gameObject); PlayCrossfade("Gesture, Additive", "ShootLoop", 0.2f); } private void UpdateCrits() { if (lastCritCheck.timeSince >= 1f) { lastCritCheck = Run.FixedTimeStamp.now; if (RollCrit()) { critEndTime = Run.FixedTimeStamp.now + 2f; } } } public override void OnExit() { Util.PlaySound(endSound, base.gameObject); if ((bool)muzzleVfxTransform) { EntityState.Destroy(muzzleVfxTransform.gameObject); muzzleVfxTransform = null; } PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.2f); base.OnExit(); } private void OnFireShared() { Util.PlaySound(fireSound, base.gameObject); if (base.isAuthority) { OnFireAuthority(); } } private void OnFireAuthority() { UpdateCrits(); bool crit = !critEndTime.hasPassed; float damage = baseDamagePerSecondCoefficient / baseBulletsPerSecond * damageStat; Ray aimRay = GetAimRay(); UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, bulletMinSpread, bulletMaxSpread, 1f, 1f); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damage, 0f, crit); } public override void FixedUpdate() { base.FixedUpdate(); fireTimer -= GetDeltaTime(); if (fireTimer <= 0f) { float num = baseFireInterval / attackSpeedStat; fireTimer += num; OnFireShared(); } if (base.isAuthority && !base.skillButtonState.down) { outer.SetNextState(new MinigunSpinDown()); } } } } namespace EntityStates.Pounder { public class Spawn : BaseState { public static GameObject spawnPrefab; public static float baseDuration; public static string spawnSoundString; private float duration; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(spawnSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(spawnPrefab, base.gameObject, "Feet", transmit: false); PlayAnimation("Base", SpawnStateHash, SpawnParamHash, duration); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Pound : BaseState { public static float blastRadius; public static float blastProcCoefficient; public static float blastForce; public static float blastFrequency; public static float duration; public static GameObject blastEffectPrefab; private ProjectileDamage projectileDamage; private float poundTimer; private static int PoundStateHash = Animator.StringToHash("Pound"); public override void OnEnter() { base.OnEnter(); projectileDamage = GetComponent(); } public override void FixedUpdate() { base.FixedUpdate(); poundTimer -= GetDeltaTime(); if (poundTimer <= 0f && (bool)base.projectileController.owner) { poundTimer += 1f / blastFrequency; if (NetworkServer.active) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.projectileController.owner; blastAttack.baseDamage = projectileDamage.damage; blastAttack.baseForce = blastForce; blastAttack.crit = projectileDamage.crit; blastAttack.damageType = projectileDamage.damageType; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.position = base.transform.position; blastAttack.radius = blastRadius; blastAttack.teamIndex = base.projectileController.teamFilter.teamIndex; blastAttack.Fire(); EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = base.transform.position, scale = blastRadius }, transmit: true); } PlayAnimation("Base", PoundStateHash); } if (NetworkServer.active && base.fixedAge > duration) { EntityState.Destroy(base.gameObject); } } } } namespace EntityStates.Treebot { public class BurrowDash : BaseCharacterMain { [SerializeField] public float baseDuration; [SerializeField] public static AnimationCurve speedMultiplier; public static float chargeDamageCoefficient; public static GameObject impactEffectPrefab; public static GameObject burrowLoopEffectPrefab; public static float hitPauseDuration; public static float timeBeforeExitToPlayExitAnimation; public static string impactSoundString; public static string startSoundString; public static string endSoundString; public static float healPercent; public static bool resetDurationOnImpact; [SerializeField] public GameObject startEffectPrefab; [SerializeField] public GameObject endEffectPrefab; private float duration; private float hitPauseTimer; private UnityEngine.Vector3 idealDirection; private OverlapAttack attack; private ChildLocator childLocator; private bool inHitPause; private bool beginPlayingExitAnimation; private Transform modelTransform; private GameObject burrowLoopEffectInstance; private int originalLayer; public override void OnEnter() { base.OnEnter(); duration = baseDuration; if (base.isAuthority) { if ((bool)base.inputBank) { idealDirection = base.inputBank.aimDirection; idealDirection.y = 0f; } UpdateDirection(); } if ((bool)base.modelLocator) { base.modelLocator.normalizeToFloor = true; } if ((bool)startEffectPrefab && (bool)base.characterBody) { EffectManager.SpawnEffect(startEffectPrefab, new EffectData { origin = base.characterBody.corePosition }, transmit: false); } if ((bool)base.characterDirection) { base.characterDirection.forward = idealDirection; } Util.PlaySound(startSoundString, base.gameObject); PlayCrossfade("Body", "BurrowEnter", 0.1f); HitBoxGroup hitBoxGroup = null; modelTransform = GetModelTransform(); if ((bool)modelTransform) { hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "BurrowCharge"); childLocator = modelTransform.GetComponent(); } attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = chargeDamageCoefficient * damageStat; attack.hitEffectPrefab = impactEffectPrefab; attack.hitBoxGroup = hitBoxGroup; attack.damage = damageStat * chargeDamageCoefficient; attack.damageType = DamageType.Freeze2s; attack.procCoefficient = 1f; originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.debris.intVal; base.characterMotor.Motor.RebuildCollidableLayers(); modelTransform.GetComponent().hurtBoxesDeactivatorCounter++; base.characterBody.hideCrosshair = true; base.characterBody.isSprinting = true; if ((bool)childLocator) { Transform transform = childLocator.FindChild("BurrowCenter"); if ((bool)transform && (bool)burrowLoopEffectPrefab) { burrowLoopEffectInstance = UnityEngine.Object.Instantiate(burrowLoopEffectPrefab, transform.position, transform.rotation); burrowLoopEffectInstance.transform.parent = transform; } } } public override void OnExit() { if ((bool)base.characterBody && !outer.destroying && (bool)endEffectPrefab) { EffectManager.SpawnEffect(endEffectPrefab, new EffectData { origin = base.characterBody.corePosition }, transmit: false); } Util.PlaySound(endSoundString, base.gameObject); base.gameObject.layer = originalLayer; base.characterMotor.Motor.RebuildCollidableLayers(); modelTransform.GetComponent().hurtBoxesDeactivatorCounter--; base.characterBody.hideCrosshair = false; if ((bool)burrowLoopEffectInstance) { EntityState.Destroy(burrowLoopEffectInstance); } Animator animator = GetModelAnimator(); int layerIndex = animator.GetLayerIndex("Impact"); if (layerIndex >= 0) { animator.SetLayerWeight(layerIndex, 2f); animator.PlayInFixedTime("LightImpact", layerIndex, 0f); } base.OnExit(); } private void UpdateDirection() { if ((bool)base.inputBank) { UnityEngine.Vector2 vector = Util.Vector3XZToVector2XY(base.inputBank.moveVector); if (vector != UnityEngine.Vector2.zero) { vector.Normalize(); idealDirection = new UnityEngine.Vector3(vector.x, 0f, vector.y).normalized; } } } protected override void UpdateAnimationParameters() { } private UnityEngine.Vector3 GetIdealVelocity() { return base.characterDirection.forward * base.characterBody.moveSpeed * speedMultiplier.Evaluate(base.fixedAge / duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); return; } if (base.fixedAge >= duration - timeBeforeExitToPlayExitAnimation && !beginPlayingExitAnimation) { beginPlayingExitAnimation = true; PlayCrossfade("Body", "BurrowExit", 0.1f); } if (!base.isAuthority) { return; } UpdateDirection(); if (!inHitPause) { if ((bool)base.characterDirection) { base.characterDirection.moveVector = idealDirection; if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision) { base.characterMotor.rootMotion += GetIdealVelocity() * GetDeltaTime(); } } if (attack.Fire()) { Util.PlaySound(impactSoundString, base.gameObject); inHitPause = true; hitPauseTimer = hitPauseDuration; if (healPercent > 0f) { base.healthComponent.HealFraction(healPercent, default(ProcChainMask)); Util.PlaySound("Play_item_use_fruit", base.gameObject); EffectData effectData = new EffectData(); effectData.origin = base.transform.position; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/FruitHealEffect"), effectData, transmit: true); } if (resetDurationOnImpact) { base.fixedAge = 0f; } else { base.fixedAge -= hitPauseDuration; } } } else { base.characterMotor.velocity = UnityEngine.Vector3.zero; hitPauseTimer -= GetDeltaTime(); if (hitPauseTimer < 0f) { inHitPause = false; } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class Burrowed : GenericCharacterMain { public static float mortarCooldown; public static string primarySkillName; public static string altPrimarySkillName; public static string utilitySkillName; public static string altUtilitySkillName; public float duration; private ChildLocator childLocator; private CameraTargetParams.AimRequest aimRequest; public override void OnEnter() { base.OnEnter(); PlayCrossfade("Body", "Burrowed", 0.1f); base.skillLocator.primary = base.skillLocator.FindSkill(altPrimarySkillName); base.skillLocator.utility = base.skillLocator.FindSkill(altUtilitySkillName); base.skillLocator.primary.stateMachine.mainStateType = new SerializableEntityStateType(typeof(AimMortar)); base.skillLocator.primary.stateMachine.SetNextStateToMain(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); } if ((bool)childLocator) { base.characterBody.aimOriginTransform = childLocator.FindChild("AimOriginMortar"); } if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } } public override void OnExit() { aimRequest?.Dispose(); base.skillLocator.primary = base.skillLocator.FindSkill(primarySkillName); base.skillLocator.utility = base.skillLocator.FindSkill(utilitySkillName); base.skillLocator.primary.stateMachine.mainStateType = new SerializableEntityStateType(typeof(Idle)); base.skillLocator.primary.stateMachine.SetNextStateToMain(); if ((bool)childLocator) { base.characterBody.aimOriginTransform = childLocator.FindChild("AimOriginSyringe"); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class BurrowIn : BaseState { public static GameObject burrowPrefab; public static float baseDuration; public static string burrowInSoundString; private float stopwatch; private float duration; private Transform modelTransform; private ChildLocator childLocator; private CameraTargetParams.AimRequest aimRequest; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayCrossfade("Body", "BurrowIn", "BurrowIn.playbackRate", duration, 0.1f); modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); Util.PlaySound(burrowInSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false); if ((bool)base.characterBody) { base.characterBody.hideCrosshair = true; } if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } } public override void OnExit() { aimRequest?.Dispose(); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { Burrowed nextState = new Burrowed(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class BurrowOut : GenericCharacterMain { public static GameObject burrowPrefab; public static float baseDuration; public static string burrowOutSoundString; public static float jumpVelocity; private float stopwatch; private Transform modelTransform; private ChildLocator childLocator; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); Util.PlaySound(burrowOutSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false); base.characterMotor.velocity = new UnityEngine.Vector3(0f, jumpVelocity, 0f); base.characterMotor.Motor.ForceUnground(); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class TreebotFireFruitSeed : BaseState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public float baseDuration; [SerializeField] public float damageCoefficient; [SerializeField] public string enterSoundString; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleFlashPrefab; [SerializeField] public string animationLayerName = "Gesture, Additive"; [SerializeField] public string animationStateName = "FireFlower"; [SerializeField] public string playbackRateParam = "FireFlower.playbackRate"; private float duration; public override void OnEnter() { base.OnEnter(); EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); duration = baseDuration / attackSpeedStat; Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration); if (base.isAuthority) { Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.crit = RollCrit(); fireProjectileInfo.damage = damageCoefficient * damageStat; fireProjectileInfo.damageColorIndex = DamageColorIndex.Default; fireProjectileInfo.force = 0f; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.position = ray.origin; fireProjectileInfo.procChainMask = default(ProcChainMask); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(ray.direction); fireProjectileInfo.useSpeedOverride = false; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FlowerProjectileHover : DroneProjectileHover { public static float yankSpeed; public static AnimationCurve yankSuitabilityCurve; public static float healthFractionYieldPerHit; private GameObject owner; private ProcChainMask procChainMask; private float procCoefficient; private float damage; private DamageTypeCombo damageType; private bool crit; private TeamIndex teamIndex = TeamIndex.None; private float healPulseHealthFractionValue; public override void OnEnter() { base.OnEnter(); ProjectileController component = GetComponent(); if ((bool)component) { owner = component.owner; procChainMask = component.procChainMask; procCoefficient = component.procCoefficient; teamIndex = component.teamFilter.teamIndex; } ProjectileDamage component2 = GetComponent(); if ((bool)component2) { damage = component2.damage; damageType = component2.damageType; crit = component2.crit; } } private void FirstPulse() { UnityEngine.Vector3 position = base.transform.position; BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = position; bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(teamIndex); bullseyeSearch.maxDistanceFilter = pulseRadius; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.filterByLoS = true; bullseyeSearch.filterByDistinctEntity = true; bullseyeSearch.RefreshCandidates(); IEnumerable results = bullseyeSearch.GetResults(); int num = 0; foreach (HurtBox item in results) { num++; UnityEngine.Vector3 vector = item.transform.position - position; float magnitude = vector.magnitude; UnityEngine.Vector3 vector2 = vector / magnitude; Rigidbody component = item.healthComponent.GetComponent(); float num2 = (component ? component.mass : 1f); float num3 = yankSuitabilityCurve.Evaluate(num2); UnityEngine.Vector3 force = vector2 * (num2 * num3 * (0f - yankSpeed)); DamageInfo damageInfo = new DamageInfo { attacker = owner, inflictor = base.gameObject, crit = crit, damage = damage, damageColorIndex = DamageColorIndex.Default, damageType = damageType, force = force, position = item.transform.position, procChainMask = procChainMask, procCoefficient = procCoefficient }; item.healthComponent.TakeDamage(damageInfo); } healPulseHealthFractionValue = (float)num * healthFractionYieldPerHit / (float)(pulseCount - 1); } private void HealPulse() { if ((bool)owner) { HealthComponent component = owner.GetComponent(); if ((bool)component) { component.HealFraction(healPulseHealthFractionValue, procChainMask); } } } protected override void Pulse() { if (pulses == 1) { FirstPulse(); } else { HealPulse(); } } } public class TreebotPrepFruitSeed : BaseState { [SerializeField] public float baseDuration; [SerializeField] public string enterSoundString; [SerializeField] public string animationLayerName = "Gesture, Additive"; [SerializeField] public string animationStateName = "PrepFlower"; [SerializeField] public string playbackRateParam = "PrepFlower.playbackRate"; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new TreebotFireFruitSeed()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.Treebot.Weapon { public class AimFlower : AimThrowableBase { public static float healthCostFraction; private bool keyDown = true; public override void Update() { base.Update(); keyDown &= !base.inputBank.skill1.down; } protected override bool KeyIsDown() { return keyDown; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } protected override void FireProjectile() { if ((bool)base.healthComponent) { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction; damageInfo.position = base.characterBody.corePosition; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.damageColorIndex = DamageColorIndex.Default; damageInfo.crit = false; damageInfo.attacker = null; damageInfo.inflictor = null; damageInfo.damageType = DamageType.NonLethal; damageInfo.procCoefficient = 0f; damageInfo.procChainMask = default(ProcChainMask); base.healthComponent.TakeDamage(damageInfo); } base.FireProjectile(); } } public class AimMortar : AimThrowableBase { public static string enterSoundString; public static string exitSoundString; private static int StateHash = Animator.StringToHash(""); private static int ParamHash = Animator.StringToHash(".playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation("Gesture, Additive", StateHash, ParamHash, minimumDuration); } public override void OnExit() { base.OnExit(); outer.SetNextState(new FireMortar()); if (!outer.destroying) { Util.PlaySound(exitSoundString, base.gameObject); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class AimMortar2 : AimThrowableBase { [SerializeField] public float healthCostFraction; public static string muzzleName; [SerializeField] public GameObject muzzleFlashPrefab; [SerializeField] public string fireSound; [SerializeField] public string enterSound; public override void OnEnter() { base.OnEnter(); PlayCrossfade("Gesture, Additive", "PrepBomb", 0.1f); Util.PlaySound(enterSound, base.gameObject); } protected override void OnProjectileFiredLocal() { if (NetworkServer.active && (bool)base.healthComponent && healthCostFraction >= Mathf.Epsilon) { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction; damageInfo.position = base.characterBody.corePosition; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.damageColorIndex = DamageColorIndex.Default; damageInfo.crit = false; damageInfo.attacker = null; damageInfo.inflictor = null; damageInfo.damageType = DamageType.NonLethal; damageInfo.procCoefficient = 0f; damageInfo.procChainMask = default(ProcChainMask); base.healthComponent.TakeDamage(damageInfo); } EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); Util.PlaySound(fireSound, base.gameObject); PlayCrossfade("Gesture, Additive", "FireBomb", 0.1f); } protected override bool KeyIsDown() { return base.inputBank.skill2.down; } protected override void ModifyProjectile(ref FireProjectileInfo fireProjectileInfo) { base.ModifyProjectile(ref fireProjectileInfo); fireProjectileInfo.position = currentTrajectoryInfo.hitPoint; fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; fireProjectileInfo.speedOverride = 0f; } } public class AimMortarRain : AimMortar2 { } public class ChargeSonicBoom : BaseState { [SerializeField] public string sound; [SerializeField] public GameObject chargeEffectPrefab; public static string muzzleName; public static float baseDuration; private float duration; private GameObject chargeEffect; private EffectManagerHelper _emh_chargeEffect; public override void Reset() { base.Reset(); duration = 0f; chargeEffect = null; _emh_chargeEffect = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(sound, base.gameObject); base.characterBody.SetAimTimer(3f); if (!chargeEffectPrefab) { return; } Transform transform = FindModelChild(muzzleName); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeEffect = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform); } else { _emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform, inResetLocal: true); chargeEffect = _emh_chargeEffect.gameObject; } chargeEffect.transform.localPosition = UnityEngine.Vector3.zero; chargeEffect.transform.localRotation = UnityEngine.Quaternion.identity; } } public override void OnExit() { if ((bool)chargeEffect) { if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null) { _emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect); } else { EntityState.Destroy(chargeEffect); } chargeEffect = null; _emh_chargeEffect = null; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(GetNextState()); } } protected virtual EntityState GetNextState() { return new FireSonicBoom(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ChargePlantSonicBoom : ChargeSonicBoom { protected override EntityState GetNextState() { return new FirePlantSonicBoom(); } } public class CreatePounder : BaseState { public static float baseDuration; public static GameObject areaIndicatorPrefab; public static GameObject projectilePrefab; public static float damageCoefficient; public static GameObject muzzleflashEffect; public static GameObject goodCrosshairPrefab; public static GameObject badCrosshairPrefab; public static string prepSoundString; public static float maxDistance; public static string fireSoundString; public static float maxSlopeAngle; private float duration; private float stopwatch; private bool goodPlacement; private GameObject areaIndicatorInstance; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private EffectManagerHelper _emh_areaIndicatorInstance; private static int PrepWallStateHash = Animator.StringToHash("PrepWall"); private static int PrepWallParamHash = Animator.StringToHash("PrepWall.playbackRate"); public override void Reset() { base.Reset(); duration = 0f; stopwatch = 0f; goodPlacement = false; areaIndicatorInstance = null; _emh_areaIndicatorInstance = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", PrepWallStateHash, PrepWallParamHash, duration); Util.PlaySound(prepSoundString, base.gameObject); if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab)) { areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab); } else { _emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity); areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject; } UpdateAreaIndicator(); } private void UpdateAreaIndicator() { bool flag = goodPlacement; goodPlacement = false; areaIndicatorInstance.SetActive(value: true); if ((bool)areaIndicatorInstance) { float num = maxDistance; float extraRaycastDistance = 0f; if (Physics.Raycast(CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance), out var hitInfo, num + extraRaycastDistance, LayerIndex.world.mask)) { areaIndicatorInstance.transform.position = hitInfo.point; areaIndicatorInstance.transform.up = hitInfo.normal; goodPlacement = UnityEngine.Vector3.Angle(UnityEngine.Vector3.up, hitInfo.normal) < maxSlopeAngle; } if (flag != goodPlacement || crosshairOverrideRequest == null) { crosshairOverrideRequest?.Dispose(); GameObject crosshairPrefab = (goodPlacement ? goodCrosshairPrefab : badCrosshairPrefab); crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill); } } areaIndicatorInstance.SetActive(goodPlacement); } public override void Update() { base.Update(); UpdateAreaIndicator(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && !base.inputBank.skill4.down && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if (goodPlacement) { Util.PlaySound(fireSoundString, base.gameObject); if ((bool)areaIndicatorInstance && base.isAuthority) { bool crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(projectilePrefab, areaIndicatorInstance.transform.position, UnityEngine.Quaternion.identity, base.gameObject, damageStat * damageCoefficient, 0f, crit); } } else { base.skillLocator.special.AddOneStock(); } if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null) { _emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance); } else { EntityState.Destroy(areaIndicatorInstance.gameObject); } areaIndicatorInstance = null; _emh_areaIndicatorInstance = null; crosshairOverrideRequest?.Dispose(); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class FireMortar : BaseState { public static GameObject muzzleEffectPrefab; public static string fireSoundString; public static float baseDuration; private float duration; private static int FireBombStateHash = Animator.StringToHash("FireBomb"); private static int FireBombParamHash = Animator.StringToHash("FireBomb.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", FireBombStateHash, FireBombParamHash, duration); Util.PlaySound(fireSoundString, base.gameObject); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "MuzzleNailgun", transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireMortar2 : BaseState { public static float baseDuration; public static GameObject projectilePrefab; public static string fireSound; public static float maxDistance; public static float damageCoefficient; public static float force; public static string muzzleName; public static GameObject muzzleEffect; public static float healthCostFraction; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; EffectManager.SimpleMuzzleFlash(muzzleEffect, base.gameObject, muzzleName, transmit: false); Util.PlaySound(fireSound, base.gameObject); PlayCrossfade("Gesture, Additive", "FireBomb", 0.1f); if (base.isAuthority) { Fire(); } if (NetworkServer.active && (bool)base.healthComponent) { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction; damageInfo.position = base.characterBody.corePosition; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.damageColorIndex = DamageColorIndex.Default; damageInfo.crit = false; damageInfo.attacker = null; damageInfo.inflictor = null; damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor; damageInfo.procCoefficient = 0f; damageInfo.procChainMask = default(ProcChainMask); base.healthComponent.TakeDamage(damageInfo); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } private void Fire() { RaycastHit hitInfo; UnityEngine.Vector3 position = ((!base.inputBank.GetAimRaycast(maxDistance, out hitInfo)) ? base.inputBank.GetAimRay().GetPoint(maxDistance) : hitInfo.point); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = position; fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageCoefficient * damageStat; fireProjectileInfo.force = force; fireProjectileInfo.crit = RollCrit(); fireProjectileInfo.damageColorIndex = DamageColorIndex.Default; fireProjectileInfo.target = null; fireProjectileInfo.speedOverride = 0f; fireProjectileInfo.fuseOverride = -1f; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireSonicBoom : BaseState { [SerializeField] public string sound; [SerializeField] public string muzzle; [SerializeField] public GameObject fireEffectPrefab; [SerializeField] public float baseDuration; [SerializeField] public float fieldOfView; [SerializeField] public float backupDistance; [SerializeField] public float maxDistance; [SerializeField] public float idealDistanceToPlaceTargets; [SerializeField] public float liftVelocity; [SerializeField] public float slowDuration; [SerializeField] public float groundKnockbackDistance; [SerializeField] public float airKnockbackDistance; public static AnimationCurve shoveSuitabilityCurve; private float duration; private static int FireSonicBoomStateHash = Animator.StringToHash("FireSonicBoom"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", FireSonicBoomStateHash); Util.PlaySound(sound, base.gameObject); Ray aimRay = GetAimRay(); if (!string.IsNullOrEmpty(muzzle)) { EffectManager.SimpleMuzzleFlash(fireEffectPrefab, base.gameObject, muzzle, transmit: false); } else { EffectManager.SpawnEffect(fireEffectPrefab, new EffectData { origin = aimRay.origin, rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction) }, transmit: false); } aimRay.origin -= aimRay.direction * backupDistance; if (NetworkServer.active) { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.all; bullseyeSearch.maxAngleFilter = fieldOfView * 0.5f; bullseyeSearch.maxDistanceFilter = maxDistance; bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.filterByLoS = false; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); IEnumerable enumerable = bullseyeSearch.GetResults().Where(Util.IsValid).Distinct(default(HurtBox.EntityEqualityComparer)); TeamIndex team = GetTeam(); foreach (HurtBox item in enumerable) { if (FriendlyFireManager.ShouldSplashHitProceed(item.healthComponent, team)) { UnityEngine.Vector3 vector = item.transform.position - aimRay.origin; float magnitude = vector.magnitude; _ = new UnityEngine.Vector2(vector.x, vector.z).magnitude; UnityEngine.Vector3 vector2 = vector / magnitude; float num = 1f; CharacterBody body = item.healthComponent.body; if ((bool)body.characterMotor) { num = body.characterMotor.mass; } else if ((bool)item.healthComponent.GetComponent()) { num = base.rigidbody.mass; } float num2 = shoveSuitabilityCurve.Evaluate(num); AddDebuff(body); body.RecalculateStats(); float acceleration = body.acceleration; UnityEngine.Vector3 vector3 = vector2; float num3 = Trajectory.CalculateInitialYSpeedForHeight(Mathf.Abs(idealDistanceToPlaceTargets - magnitude), 0f - acceleration) * Mathf.Sign(idealDistanceToPlaceTargets - magnitude); vector3 *= num3; vector3.y = liftVelocity; DamageInfo damageInfo = new DamageInfo { attacker = base.gameObject, damage = CalculateDamage(), position = item.transform.position, procCoefficient = CalculateProcCoefficient() }; item.healthComponent.TakeDamageForce(vector3 * (num * num2), alwaysApply: true, disableAirControlUntilCollision: true); item.healthComponent.TakeDamage(new DamageInfo { attacker = base.gameObject, damage = CalculateDamage(), position = item.transform.position, procCoefficient = CalculateProcCoefficient() }); GlobalEventManager.instance.OnHitEnemy(damageInfo, item.healthComponent.gameObject); } } } if (base.isAuthority && (bool)base.characterBody && (bool)base.characterBody.characterMotor) { float height = (base.characterBody.characterMotor.isGrounded ? groundKnockbackDistance : airKnockbackDistance); float num4 = (base.characterBody.characterMotor ? base.characterBody.characterMotor.mass : 1f); float acceleration2 = base.characterBody.acceleration; float num5 = Trajectory.CalculateInitialYSpeedForHeight(height, 0f - acceleration2); base.characterBody.characterMotor.ApplyForce((0f - num5) * num4 * aimRay.direction); } } protected virtual void AddDebuff(CharacterBody body) { body.AddTimedBuff(RoR2Content.Buffs.Weak, slowDuration); body.healthComponent.GetComponent()?.SetStun(-1f); } protected virtual float CalculateDamage() { return 0f; } protected virtual float CalculateProcCoefficient() { return 0f; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FirePlantSonicBoom : FireSonicBoom { public static float damageCoefficient; public static float procCoefficient; public static GameObject hitEffectPrefab; public static float healthFractionPerHit; public static float healthCostFraction; public static string impactSoundString; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active && (bool)base.healthComponent && healthCostFraction >= Mathf.Epsilon) { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction; damageInfo.position = base.characterBody.corePosition; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.damageColorIndex = DamageColorIndex.Default; damageInfo.crit = false; damageInfo.attacker = null; damageInfo.inflictor = null; damageInfo.damageType = DamageType.NonLethal; damageInfo.procCoefficient = 0f; damageInfo.procChainMask = default(ProcChainMask); base.healthComponent.TakeDamage(damageInfo); } } protected override void AddDebuff(CharacterBody body) { body.healthComponent.GetComponent()?.SetStun(-1f); if ((bool)hitEffectPrefab) { EffectManager.SpawnEffect(hitEffectPrefab, new EffectData { origin = body.corePosition }, transmit: true); } if ((bool)base.healthComponent) { HealOrb healOrb = new HealOrb(); healOrb.origin = body.corePosition; healOrb.target = base.healthComponent.body.mainHurtBox; healOrb.healValue = healthFractionPerHit * base.healthComponent.fullHealth; healOrb.overrideDuration = UnityEngine.Random.Range(0.3f, 0.6f); OrbManager.instance.AddOrb(healOrb); } Util.PlaySound(impactSoundString, base.gameObject); } protected override float CalculateDamage() { return damageCoefficient * damageStat; } protected override float CalculateProcCoefficient() { return procCoefficient; } } public class FireSonicPull : FireSonicBoom { } public class FireSyringe : BaseState { public static GameObject projectilePrefab; public static GameObject finalProjectilePrefab; public static GameObject muzzleflashEffectPrefab; public static int projectileCount = 3; public static float totalYawSpread = 5f; public static float baseDuration = 2f; public static float baseFireDuration = 0.2f; public static float damageCoefficient = 1.2f; public static float force = 20f; public static string attackSound; public static string finalAttackSound; public static string muzzleName; private float duration; private float fireDuration; private int projectilesFired; private static int FireSyringeStateHash = Animator.StringToHash("FireSyringe"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; fireDuration = baseFireDuration / attackSpeedStat; } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); int num = Mathf.FloorToInt(base.fixedAge / fireDuration * (float)projectileCount); if (projectilesFired <= num && projectilesFired < projectileCount) { GameObject prefab = projectilePrefab; string soundString = attackSound; if (projectilesFired == projectileCount - 1) { prefab = finalProjectilePrefab; soundString = finalAttackSound; } PlayAnimation("Gesture, Additive", FireSyringeStateHash); Util.PlaySound(soundString, base.gameObject); base.characterBody.SetAimTimer(3f); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); float bonusYaw = (float)Mathf.FloorToInt((float)projectilesFired - (float)(projectileCount - 1) / 2f) / (float)(projectileCount - 1) * totalYawSpread; UnityEngine.Vector3 forward = Util.ApplySpread(ray.direction, 0f, 0f, 1f, 1f, bonusYaw); ProjectileManager.instance.FireProjectile(prefab, ray.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } projectilesFired++; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.Treebot.UnlockInteractable { public class Unlock : BaseState { private static int ReviveParamHash = Animator.StringToHash("Revive"); public static event Action onActivated; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { Unlock.onActivated?.Invoke(GetComponent().lastActivator); } GetModelAnimator().SetBool(ReviveParamHash, value: true); GetModelTransform().GetComponent().enabled = true; } } } namespace EntityStates.Treebot.TreebotFlower { public class SpawnState : BaseState { public static float duration; public static string enterSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation("Base", SpawnStateHash, SpawnParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new TreebotFlower2Projectile()); } } } public class TreebotFlower2Projectile : BaseState { public static float yankIdealDistance; public static AnimationCurve yankSuitabilityCurve; public static float healthFractionYieldPerHit; public static float radius; public static float healPulseCount; public static float duration; public static float rootPulseCount; public static string enterSoundString; public static string exitSoundString; public static GameObject enterEffectPrefab; public static GameObject exitEffectPrefab; private List rootedBodies; private float healTimer; private float rootPulseTimer; private GameObject owner; private ProcChainMask procChainMask; private float procCoefficient; private TeamIndex teamIndex = TeamIndex.None; private float damage; private DamageTypeCombo damageType; private bool crit; private float healPulseHealthFractionValue; private static int SpawnToIdleStateHash = Animator.StringToHash("SpawnToIdle"); public override void OnEnter() { base.OnEnter(); ProjectileController component = GetComponent(); if ((bool)component) { owner = component.owner; procChainMask = component.procChainMask; procCoefficient = component.procCoefficient; teamIndex = component.teamFilter.teamIndex; } ProjectileDamage component2 = GetComponent(); if ((bool)component2) { damage = component2.damage; damageType = component2.damageType; crit = component2.crit; } if (NetworkServer.active) { rootedBodies = new List(); } PlayAnimation("Base", SpawnToIdleStateHash); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)enterEffectPrefab) { EffectManager.SimpleEffect(enterEffectPrefab, base.transform.position, base.transform.rotation, transmit: false); } ChildLocator component3 = GetModelTransform().GetComponent(); if ((bool)component3) { Transform obj = component3.FindChild("AreaIndicator"); obj.localScale = new UnityEngine.Vector3(radius, radius, radius); obj.gameObject.SetActive(value: true); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { float deltaTime = GetDeltaTime(); rootPulseTimer -= deltaTime; healTimer -= deltaTime; if (rootPulseTimer <= 0f) { rootPulseTimer += duration / rootPulseCount; RootPulse(); } if (healTimer <= 0f) { healTimer += duration / healPulseCount; HealPulse(); } if (base.fixedAge >= duration) { EntityState.Destroy(base.gameObject); } } } private void RootPulse() { UnityEngine.Vector3 position = base.transform.position; HurtBox[] hurtBoxes = new SphereSearch { origin = position, radius = radius, mask = LayerIndex.entityPrecise.mask }.RefreshCandidates().FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(teamIndex)).OrderCandidatesByDistance() .FilterCandidatesByDistinctHurtBoxEntities() .GetHurtBoxes(); foreach (HurtBox hurtBox in hurtBoxes) { CharacterBody body = hurtBox.healthComponent.body; if (!rootedBodies.Contains(body)) { rootedBodies.Add(body); body.AddBuff(RoR2Content.Buffs.Entangle); body.RecalculateStats(); UnityEngine.Vector3 vector = hurtBox.transform.position - position; float magnitude = vector.magnitude; UnityEngine.Vector3 vector2 = vector / magnitude; Rigidbody component = hurtBox.healthComponent.GetComponent(); float num = (component ? component.mass : 1f); float num2 = magnitude - yankIdealDistance; float num3 = yankSuitabilityCurve.Evaluate(num); UnityEngine.Vector3 vector3 = (component ? component.velocity : UnityEngine.Vector3.zero); if (HGMath.IsVectorNaN(vector3)) { vector3 = UnityEngine.Vector3.zero; } UnityEngine.Vector3 vector4 = -vector3; if (num2 > 0f) { vector4 = vector2 * (0f - Trajectory.CalculateInitialYSpeedForHeight(num2, 0f - body.acceleration)); } UnityEngine.Vector3 force = vector4 * (num * num3); DamageInfo damageInfo = new DamageInfo { attacker = owner, inflictor = base.gameObject, crit = crit, damage = damage, damageColorIndex = DamageColorIndex.Default, damageType = damageType, force = force, position = hurtBox.transform.position, procChainMask = procChainMask, procCoefficient = procCoefficient }; hurtBox.healthComponent.TakeDamage(damageInfo); HurtBox hurtBoxReference = hurtBox; HurtBoxGroup hurtBoxGroup = hurtBox.hurtBoxGroup; for (int j = 0; (float)j < Mathf.Min(4f, body.radius * 2f); j++) { EffectData effectData = new EffectData { scale = 1f, origin = position, genericFloat = Mathf.Max(0.2f, duration - base.fixedAge) }; effectData.SetHurtBoxReference(hurtBoxReference); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/OrbEffects/EntangleOrbEffect"), effectData, transmit: true); hurtBoxReference = hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, hurtBoxGroup.hurtBoxes.Length)]; } } } } public override void OnExit() { if (rootedBodies != null) { foreach (CharacterBody rootedBody in rootedBodies) { rootedBody.RemoveBuff(RoR2Content.Buffs.Entangle); } rootedBodies = null; } Util.PlaySound(exitSoundString, base.gameObject); if ((bool)exitEffectPrefab) { EffectManager.SimpleEffect(exitEffectPrefab, base.transform.position, base.transform.rotation, transmit: false); } base.OnExit(); } private void HealPulse() { HealthComponent healthComponent = (owner ? owner.GetComponent() : null); if ((bool)healthComponent && rootedBodies.Count > 0) { float num = 1f / healPulseCount; HealOrb healOrb = new HealOrb(); healOrb.origin = base.transform.position; healOrb.target = healthComponent.body.mainHurtBox; healOrb.healValue = num * healthFractionYieldPerHit * healthComponent.fullHealth * (float)rootedBodies.Count; healOrb.overrideDuration = 0.3f; OrbManager.instance.AddOrb(healOrb); } } } } namespace EntityStates.Toolbot { public abstract class AimGrenade : AimThrowableBase { public override void OnEnter() { base.OnEnter(); detonationRadius = 7f; } } public class AimStunDrone : AimGrenade { public static string enterSoundString; public static string exitSoundString; private static int PrepBombStateHash = Animator.StringToHash("PrepBomb"); private static int PutAwayGunStateHash = Animator.StringToHash("PutAwayGun"); private static int PrepBombParamHash = Animator.StringToHash("PrepBomb.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation("Gesture, Additive", PrepBombStateHash, PrepBombParamHash, minimumDuration); PlayAnimation("Stance, Override", PutAwayGunStateHash); } public override void OnExit() { base.OnExit(); outer.SetNextState(new RecoverAimStunDrone()); Util.PlaySound(exitSoundString, base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class RecoverAimStunDrone : BaseState { public static GameObject muzzleEffectPrefab; public static string fireSoundString; public static float baseDuration; private float duration; private static int FireBombStateHash = Animator.StringToHash("FireBomb"); private static int FireBombParamHash = Animator.StringToHash("FireBomb.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", FireBombStateHash, FireBombParamHash, duration); Util.PlaySound(fireSoundString, base.gameObject); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "MuzzleNailgun", transmit: false); } } public override void OnExit() { base.OnExit(); PlayCrossfade("Stance, Override", "Empty", 0.1f); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class AimHealDrone : AimGrenade { } public abstract class BaseToolbotPrimarySkillState : BaseSkillState, IToolbotPrimarySkillState, ISkillState { public Transform muzzleTransform { get; set; } public virtual string baseMuzzleName => "Muzzle"; public bool isInDualWield { get; set; } public int currentHand { get; set; } public string muzzleName { get; set; } public SkillDef skillDef { get; set; } public override void OnEnter() { base.OnEnter(); BaseToolbotPrimarySkillStateMethods.OnEnter(this, base.gameObject, base.skillLocator, GetModelChildLocator()); } public override void OnExit() { base.OnExit(); } } public static class BaseToolbotPrimarySkillStateMethods { private static int DualWieldFireLStateHash = Animator.StringToHash("DualWieldFire, Left"); private static int DualWieldFireRStateHash = Animator.StringToHash("DualWieldFire, Right"); public static void OnEnter(T state, GameObject gameObject, SkillLocator skillLocator, ChildLocator modelChildLocator) where T : BaseState, IToolbotPrimarySkillState { state.currentHand = 0; state.isInDualWield = EntityStateMachine.FindByCustomName(gameObject, "Body").state is ToolbotDualWield; state.muzzleName = state.baseMuzzleName; state.skillDef = state.activatorSkillSlot.skillDef; if (state.isInDualWield) { if ((object)state.activatorSkillSlot == skillLocator.primary) { state.currentHand = -1; state.muzzleName = "DualWieldMuzzleL"; } else if ((object)state.activatorSkillSlot == skillLocator.secondary) { state.currentHand = 1; state.muzzleName = "DualWieldMuzzleR"; } } if (state.muzzleName != null) { state.muzzleTransform = modelChildLocator.FindChild(state.muzzleName); } } public static void PlayGenericFireAnim(T state, GameObject gameObject, SkillLocator skillLocator, float duration) where T : BaseState, IToolbotPrimarySkillState { state.currentHand = 0; if ((object)state.activatorSkillSlot == skillLocator.primary) { state.currentHand = -1; } else if ((object)state.activatorSkillSlot == skillLocator.secondary) { state.currentHand = 1; } switch (state.currentHand) { case -1: state.PlayAnimation("Gesture, Additive", DualWieldFireLStateHash); break; case 1: state.PlayAnimation("Gesture, Additive Bonus", DualWieldFireRStateHash); break; } } } public interface IToolbotPrimarySkillState : ISkillState { Transform muzzleTransform { get; set; } string muzzleName { get; set; } string baseMuzzleName { get; } bool isInDualWield { get; set; } int currentHand { get; set; } SkillDef skillDef { get; set; } } public class ChargeSpear : BaseToolbotPrimarySkillState { public static float baseMinChargeDuration; public static float baseChargeDuration; public static float perfectChargeWindow; public static GameObject chargeupVfxPrefab; public static GameObject holdChargeVfxPrefab; private float minChargeDuration; private float chargeDuration; private bool released; private GameObject chargeupVfxGameObject; private GameObject holdChargeVfxGameObject; private EffectManagerHelper _emh_chargeupVfx; private EffectManagerHelper _emh_holdChargeVfx; private static int ChargeSpearStateHash = Animator.StringToHash("ChargeSpear"); private static int ChargeSpearParamHash = Animator.StringToHash("ChargeSpear.playbackRate"); public override void Reset() { base.Reset(); minChargeDuration = 0f; chargeDuration = 0f; released = false; chargeupVfxGameObject = null; holdChargeVfxGameObject = null; _emh_chargeupVfx = null; _emh_holdChargeVfx = null; released = false; } public override void OnEnter() { base.OnEnter(); minChargeDuration = baseMinChargeDuration / attackSpeedStat; chargeDuration = baseChargeDuration / attackSpeedStat; if (!base.isInDualWield) { PlayAnimation("Gesture, Additive", ChargeSpearStateHash, ChargeSpearParamHash, chargeDuration); } if ((bool)base.muzzleTransform) { if (!EffectManager.ShouldUsePooledEffect(chargeupVfxPrefab)) { chargeupVfxGameObject = UnityEngine.Object.Instantiate(chargeupVfxPrefab, base.muzzleTransform); } else { _emh_chargeupVfx = EffectManager.GetAndActivatePooledEffect(chargeupVfxPrefab, base.muzzleTransform, inResetLocal: true); chargeupVfxGameObject = _emh_chargeupVfx.gameObject; } chargeupVfxGameObject.GetComponent().newDuration = chargeDuration; } } protected void KillChargeEffect() { if (!chargeupVfxGameObject) { return; } if (!EffectManager.UsePools) { EntityState.Destroy(chargeupVfxGameObject); } else { if (_emh_chargeupVfx != null && _emh_chargeupVfx.OwningPool != null) { _emh_chargeupVfx.OwningPool.ReturnObject(_emh_chargeupVfx); } else { EntityState.Destroy(chargeupVfxGameObject); } _emh_chargeupVfx = null; } chargeupVfxGameObject = null; } public override void OnExit() { KillChargeEffect(); if ((bool)holdChargeVfxGameObject) { if (!EffectManager.UsePools) { EntityState.Destroy(holdChargeVfxGameObject); } else { if (_emh_holdChargeVfx != null && _emh_holdChargeVfx.OwningPool != null) { _emh_holdChargeVfx.OwningPool.ReturnObject(_emh_holdChargeVfx); } else { EntityState.Destroy(holdChargeVfxGameObject); } _emh_holdChargeVfx = null; } holdChargeVfxGameObject = null; } base.OnExit(); } public override void Update() { base.Update(); base.characterBody.SetSpreadBloom(base.age / chargeDuration); } public override void FixedUpdate() { base.FixedUpdate(); float num = base.fixedAge - chargeDuration; if (num >= 0f) { _ = perfectChargeWindow; } float charge = Mathf.Clamp01(base.fixedAge / chargeDuration); if (base.fixedAge >= chargeDuration) { KillChargeEffect(); if (!holdChargeVfxGameObject && (bool)base.muzzleTransform) { if (!EffectManager.ShouldUsePooledEffect(holdChargeVfxPrefab)) { holdChargeVfxGameObject = UnityEngine.Object.Instantiate(holdChargeVfxPrefab, base.muzzleTransform); } else { _emh_holdChargeVfx = EffectManager.GetAndActivatePooledEffect(holdChargeVfxPrefab, base.muzzleTransform, inResetLocal: true); holdChargeVfxGameObject = _emh_holdChargeVfx.gameObject; } } } if (base.isAuthority) { if (!released && !IsKeyDownAuthority()) { released = true; } if (released && base.fixedAge >= minChargeDuration) { outer.SetNextState(new FireSpear { charge = charge, activatorSkillSlot = base.activatorSkillSlot }); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class CooldownSpear : BaseToolbotPrimarySkillState { public static float baseDuration; public static string enterSoundString; private float duration; private uint soundID; private static int CooldownSpearStateHash = Animator.StringToHash("CooldownSpear"); private static int CooldownSpearParamHash = Animator.StringToHash("CooldownSpear.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; if (!base.isInDualWield) { PlayAnimation("Gesture, Additive", CooldownSpearStateHash, CooldownSpearParamHash, duration); } soundID = Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override void OnExit() { AkSoundEngine.StopPlayingID(soundID); base.OnExit(); } public override void Update() { base.Update(); base.characterBody.SetSpreadBloom(1f - base.age / duration, canOnlyIncreaseBloom: false); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireBuzzsaw : BaseToolbotPrimarySkillState { public static float damageCoefficientPerSecond; public static float procCoefficientPerSecond = 1f; public static string fireSoundString; public static string impactSoundString; public static string spinUpSoundString; public static string spinDownSoundString; public static float spreadBloomValue = 0.2f; public static float baseFireFrequency; public static GameObject spinEffectPrefab; public static GameObject spinImpactEffectPrefab; public static GameObject impactEffectPrefab; public static float selfForceMagnitude; private OverlapAttack attack; private float fireFrequency; private float fireAge; private GameObject spinEffectInstance; private GameObject spinImpactEffectInstance; private bool hitOverlapLastTick; protected EffectManagerHelper _emh_spinEffectInstance; protected EffectManagerHelper _emh_spinImpactEffectInstance; private static int SpinBuzzsawStateHash = Animator.StringToHash("SpinBuzzsaw"); private static int EnterBuzzsawStateHash = Animator.StringToHash("EnterBuzzsaw"); private static int EmptyStateHash = Animator.StringToHash("Empty"); private static int ExitBuzzsawStateHash = Animator.StringToHash("ExitBuzzsaw"); private static int ImpactBuzzsawStateHash = Animator.StringToHash("ImpactBuzzsaw"); public override string baseMuzzleName => "MuzzleBuzzsaw"; public override void Reset() { base.Reset(); if (attack != null) { attack.Reset(); } fireFrequency = 0f; fireAge = 0f; spinEffectInstance = null; spinImpactEffectInstance = null; base.muzzleTransform = null; hitOverlapLastTick = false; _emh_spinEffectInstance = null; _emh_spinImpactEffectInstance = null; } public override void OnEnter() { base.OnEnter(); fireFrequency = baseFireFrequency * attackSpeedStat; Transform modelTransform = GetModelTransform(); Util.PlaySound(spinUpSoundString, base.gameObject); Util.PlaySound(fireSoundString, base.gameObject); if (!base.isInDualWield) { PlayAnimation("Gesture, Additive Gun", SpinBuzzsawStateHash); PlayAnimation("Gesture, Additive", EnterBuzzsawStateHash); } attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficientPerSecond * damageStat / baseFireFrequency; attack.procCoefficient = procCoefficientPerSecond / baseFireFrequency; if ((bool)impactEffectPrefab) { attack.hitEffectPrefab = impactEffectPrefab; } if ((bool)modelTransform) { string groupName = "Buzzsaw"; if (base.isInDualWield) { if (base.currentHand == -1) { groupName = "BuzzsawL"; } else if (base.currentHand == 1) { groupName = "BuzzsawR"; } } attack.hitBoxGroup = HitBoxGroup.FindByGroupName(modelTransform.gameObject, groupName); } if ((bool)base.muzzleTransform) { if ((bool)spinEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(spinEffectPrefab)) { spinEffectInstance = UnityEngine.Object.Instantiate(spinEffectPrefab, base.muzzleTransform.position, base.muzzleTransform.rotation); } else { _emh_spinEffectInstance = EffectManager.GetAndActivatePooledEffect(spinEffectPrefab, base.muzzleTransform.position, base.muzzleTransform.rotation); spinEffectInstance = _emh_spinEffectInstance.gameObject; } spinEffectInstance.transform.parent = base.muzzleTransform; spinEffectInstance.transform.localScale = UnityEngine.Vector3.one; } if ((bool)spinImpactEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(spinImpactEffectPrefab)) { spinImpactEffectInstance = UnityEngine.Object.Instantiate(spinImpactEffectPrefab, base.muzzleTransform.position, base.muzzleTransform.rotation); } else { _emh_spinImpactEffectInstance = EffectManager.GetAndActivatePooledEffect(spinImpactEffectPrefab, base.muzzleTransform.position, base.muzzleTransform.rotation); spinImpactEffectInstance = _emh_spinImpactEffectInstance.gameObject; } spinImpactEffectInstance.transform.parent = base.muzzleTransform; spinImpactEffectInstance.transform.localScale = UnityEngine.Vector3.one; spinImpactEffectInstance.gameObject.SetActive(value: false); } } attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); } public override void OnExit() { base.OnExit(); Util.PlaySound(spinDownSoundString, base.gameObject); if (!base.isInDualWield) { PlayAnimation("Gesture, Additive Gun", EmptyStateHash); PlayAnimation("Gesture, Additive", ExitBuzzsawStateHash); } if ((bool)spinEffectInstance) { if (!EffectManager.UsePools) { EntityState.Destroy(spinEffectInstance); } else { if (_emh_spinEffectInstance != null && _emh_spinEffectInstance.OwningPool != null) { _emh_spinEffectInstance.OwningPool.ReturnObject(_emh_spinEffectInstance); } else { EntityState.Destroy(spinEffectInstance); } _emh_spinEffectInstance = null; } } if ((bool)spinImpactEffectInstance) { EntityState.Destroy(spinImpactEffectInstance); } } public override void FixedUpdate() { base.FixedUpdate(); fireAge += GetDeltaTime(); base.characterBody.SetAimTimer(2f); attackSpeedStat = base.characterBody.attackSpeed; fireFrequency = baseFireFrequency * attackSpeedStat; if (fireAge >= 1f / fireFrequency && base.isAuthority) { fireAge = 0f; attack.ResetIgnoredHealthComponents(); attack.isCrit = base.characterBody.RollCrit(); hitOverlapLastTick = attack.Fire(); if (hitOverlapLastTick) { UnityEngine.Vector3 normalized = (attack.lastFireAverageHitPosition - GetAimRay().origin).normalized; if ((bool)base.characterMotor) { base.characterMotor.ApplyForce(normalized * selfForceMagnitude); } Util.PlaySound(impactSoundString, base.gameObject); if (!base.isInDualWield) { PlayAnimation("Gesture, Additive", ImpactBuzzsawStateHash); } } base.characterBody.AddSpreadBloom(spreadBloomValue); if (!IsKeyDownAuthority() || (object)base.skillDef != base.activatorSkillSlot.skillDef) { outer.SetNextStateToMain(); } } spinImpactEffectInstance.gameObject.SetActive(hitOverlapLastTick); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireGrenadeLauncher : GenericProjectileBaseState, IToolbotPrimarySkillState, ISkillState { private static int FireGrenadeLauncherStateHash = Animator.StringToHash("FireGrenadeLauncher"); private static int FireGrenadeLauncherParamHash = Animator.StringToHash("FireGrenadeLauncher.playbackRate"); Transform IToolbotPrimarySkillState.muzzleTransform { get; set; } string IToolbotPrimarySkillState.baseMuzzleName => targetMuzzle; bool IToolbotPrimarySkillState.isInDualWield { get; set; } int IToolbotPrimarySkillState.currentHand { get; set; } string IToolbotPrimarySkillState.muzzleName { get; set; } public SkillDef skillDef { get; set; } public GenericSkill activatorSkillSlot { get; set; } public override void OnEnter() { BaseToolbotPrimarySkillStateMethods.OnEnter(this, base.gameObject, base.skillLocator, GetModelChildLocator()); base.OnEnter(); } protected override void PlayAnimation(float duration) { if (!((IToolbotPrimarySkillState)this).isInDualWield) { PlayAnimation("Gesture, Additive", FireGrenadeLauncherStateHash, FireGrenadeLauncherParamHash, duration); } else { BaseToolbotPrimarySkillStateMethods.PlayGenericFireAnim(this, base.gameObject, base.skillLocator, duration); } } protected override Ray ModifyProjectileAimRay(Ray projectileRay) { if (((IToolbotPrimarySkillState)this).isInDualWield) { Transform muzzleTransform = ((IToolbotPrimarySkillState)this).muzzleTransform; if ((bool)muzzleTransform) { projectileRay.origin = muzzleTransform.position; } } return projectileRay; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); this.Serialize(base.skillLocator, writer); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); this.Deserialize(base.skillLocator, reader); } } public class BaseNailgunState : BaseToolbotPrimarySkillState { public static float damageCoefficient = 0.1f; public static float procCoefficient = 1f; public static float force = 100f; public static float maxDistance = 50f; public new static string muzzleName; public static GameObject hitEffectPrefab; public static float spreadPitchScale = 0.5f; public static float spreadYawScale = 1f; public static GameObject tracerEffectPrefab; public static string fireSoundString; public static GameObject muzzleFlashPrefab; public static float spreadBloomValue = 0.2f; protected float duration; protected int fireNumber; private static int FireNailgunStateHash = Animator.StringToHash("FireNailgun"); private static int isFiringNailgunStateHash = Animator.StringToHash("isFiringNailgun"); private bool _animateNailgunFiring; public override string baseMuzzleName => muzzleName; protected bool animateNailgunFiring { get { return _animateNailgunFiring; } set { if (_animateNailgunFiring != value) { _animateNailgunFiring = value; GetModelAnimator().SetBool(isFiringNailgunStateHash, value); } } } protected virtual float GetBaseDuration() { return 0f; } public override void OnEnter() { base.OnEnter(); PullCurrentStats(); } protected void PullCurrentStats() { attackSpeedStat = base.characterBody.attackSpeed; critStat = base.characterBody.crit; duration = GetBaseDuration() / attackSpeedStat; } protected void FireBullet(Ray aimRay, int bulletCount, float spreadPitchScale, float spreadYawScale) { fireNumber++; StartAimMode(aimRay, 3f); if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.aimVector = aimRay.direction; bulletAttack.origin = aimRay.origin; bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.bulletCount = (uint)bulletCount; bulletAttack.damage = damageStat * damageCoefficient; bulletAttack.damageColorIndex = DamageColorIndex.Default; bulletAttack.damageType = DamageType.Generic; bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet; bulletAttack.force = force; bulletAttack.HitEffectNormal = false; bulletAttack.procChainMask = default(ProcChainMask); bulletAttack.procCoefficient = procCoefficient; bulletAttack.maxDistance = maxDistance; bulletAttack.radius = 0f; bulletAttack.isCrit = RollCrit(); bulletAttack.muzzleName = ((IToolbotPrimarySkillState)this).muzzleName; bulletAttack.minSpread = 0f; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.maxSpread = base.characterBody.spreadBloomAngle; bulletAttack.smartCollision = false; bulletAttack.sniper = false; bulletAttack.spreadPitchScale = spreadPitchScale * spreadPitchScale; bulletAttack.spreadYawScale = spreadYawScale * spreadYawScale; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.allowTrajectoryAimAssist = false; bulletAttack.Fire(); } if ((bool)base.characterBody) { base.characterBody.AddSpreadBloom(spreadBloomValue); } Util.PlaySound(fireSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); if (!base.isInDualWield) { PlayAnimation("Gesture, Additive", FireNailgunStateHash); } else { BaseToolbotPrimarySkillStateMethods.PlayGenericFireAnim(this, base.gameObject, base.skillLocator, 0.2f); } } } public class FireNailgun : BaseNailgunState { public static float baseRefireInterval; public static string spinUpSound; private float refireStopwatch; private uint loopSoundID; private BuffIndex skillsDisabledBuffIndex; protected override float GetBaseDuration() { return baseRefireInterval; } public override void OnEnter() { base.OnEnter(); loopSoundID = Util.PlaySound(spinUpSound, base.gameObject); base.animateNailgunFiring = true; refireStopwatch = duration; skillsDisabledBuffIndex = DLC2Content.Buffs.DisableAllSkills.buffIndex; } public override void FixedUpdate() { base.FixedUpdate(); refireStopwatch += GetDeltaTime(); if (refireStopwatch >= duration) { PullCurrentStats(); refireStopwatch -= duration; Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, BaseNailgunState.maxDistance, base.gameObject); UnityEngine.Vector3 direction = ray.direction; UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, direction); float num = Mathf.Sin((float)fireNumber * 0.5f); UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(base.characterBody.spreadBloomAngle * num, axis) * direction; vector = UnityEngine.Quaternion.AngleAxis((float)fireNumber * -65.454544f, direction) * vector; ray.direction = vector; FireBullet(ray, 1, 0f, 0f); } if (base.isAuthority && (!IsKeyDownAuthority() || base.characterBody.isSprinting || base.characterBody.HasBuff(skillsDisabledBuffIndex))) { outer.SetNextState(new NailgunSpinDown { activatorSkillSlot = base.activatorSkillSlot }); } } public override void OnExit() { base.animateNailgunFiring = false; AkSoundEngine.StopPlayingID(loopSoundID); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class NailgunSpinDown : BaseNailgunState { public static string spinDownSound; public static float baseDuration; protected override float GetBaseDuration() { return baseDuration; } public override void OnEnter() { base.OnEnter(); Util.PlayAttackSpeedSound(spinDownSound, base.gameObject, attackSpeedStat); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new NailgunFinalBurst { activatorSkillSlot = base.activatorSkillSlot }); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class NailgunFinalBurst : BaseNailgunState { public static int finalBurstBulletCount = 8; public static float burstTimeCostCoefficient = 1.2f; public static string burstSound; public static float selfForce = 1000f; private static int FireGrenadeLauncherStateHash = Animator.StringToHash("FireGrenadeLauncher"); private static int FireGrenadeLauncherParamHash = Animator.StringToHash("FireGrenadeLauncher.playbackRate"); protected override float GetBaseDuration() { return (float)finalBurstBulletCount * FireNailgun.baseRefireInterval * burstTimeCostCoefficient; } public override void OnEnter() { base.OnEnter(); if ((bool)base.characterBody) { base.characterBody.SetSpreadBloom(1f, canOnlyIncreaseBloom: false); } if (!base.characterBody.HasBuff(DLC2Content.Buffs.DisableAllSkills.buffIndex)) { Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, BaseNailgunState.maxDistance, base.gameObject); FireBullet(GetAimRay(), finalBurstBulletCount, BaseNailgunState.spreadPitchScale, BaseNailgunState.spreadYawScale); if (!base.isInDualWield) { PlayAnimation("Gesture, Additive", FireGrenadeLauncherStateHash, FireGrenadeLauncherParamHash, 0.45f / attackSpeedStat); } else { BaseToolbotPrimarySkillStateMethods.PlayGenericFireAnim(this, base.gameObject, base.skillLocator, 0.45f / attackSpeedStat); } Util.PlaySound(burstSound, base.gameObject); if (base.isAuthority) { float num = selfForce * (base.characterMotor.isGrounded ? 0.5f : 1f) * base.characterMotor.mass; base.characterMotor.ApplyForce(ray.direction * (0f - num)); } Util.PlaySound(BaseNailgunState.fireSoundString, base.gameObject); Util.PlaySound(BaseNailgunState.fireSoundString, base.gameObject); Util.PlaySound(BaseNailgunState.fireSoundString, base.gameObject); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireSpear : GenericBulletBaseState, IToolbotPrimarySkillState, ISkillState { public float charge; public static float recoilAmplitude; private static int FireSpearStateHash = Animator.StringToHash("FireSpear"); private static int FireSpearParamHash = Animator.StringToHash("FireSpear.playbackRate"); Transform IToolbotPrimarySkillState.muzzleTransform { get; set; } string IToolbotPrimarySkillState.baseMuzzleName => muzzleName; bool IToolbotPrimarySkillState.isInDualWield { get; set; } int IToolbotPrimarySkillState.currentHand { get; set; } string IToolbotPrimarySkillState.muzzleName { get; set; } public SkillDef skillDef { get; set; } public GenericSkill activatorSkillSlot { get; set; } public override void OnEnter() { BaseToolbotPrimarySkillStateMethods.OnEnter(this, base.gameObject, base.skillLocator, GetModelChildLocator()); base.OnEnter(); } protected override void ModifyBullet(BulletAttack bulletAttack) { base.ModifyBullet(bulletAttack); bulletAttack.stopperMask = LayerIndex.world.mask; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.muzzleName = ((IToolbotPrimarySkillState)this).muzzleName; } protected override void FireBullet(Ray aimRay) { base.FireBullet(aimRay); base.characterBody.SetSpreadBloom(1f, canOnlyIncreaseBloom: false); AddRecoil(-0.6f * recoilAmplitude, -0.8f * recoilAmplitude, -0.1f * recoilAmplitude, 0.1f * recoilAmplitude); if (!((IToolbotPrimarySkillState)this).isInDualWield) { PlayAnimation("Gesture, Additive", FireSpearStateHash, FireSpearParamHash, duration); } else { BaseToolbotPrimarySkillStateMethods.PlayGenericFireAnim(this, base.gameObject, base.skillLocator, duration); } } public override void Update() { base.Update(); base.characterBody.SetSpreadBloom(0.9f + base.age / duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new CooldownSpear { activatorSkillSlot = activatorSkillSlot }); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); this.Serialize(base.skillLocator, writer); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); this.Deserialize(base.skillLocator, reader); } } public class ToolbotDash : BaseCharacterMain { [SerializeField] public float baseDuration; [SerializeField] public float speedMultiplier; public static float chargeDamageCoefficient; public static float awayForceMagnitude; public static float upwardForceMagnitude; public static GameObject impactEffectPrefab; public static float hitPauseDuration; public static string impactSoundString; public static float recoilAmplitude; public static string startSoundString; public static string endSoundString; public static GameObject knockbackEffectPrefab; public static float knockbackDamageCoefficient; public static float massThresholdForKnockback; public static float knockbackForce; [SerializeField] public GameObject startEffectPrefab; [SerializeField] public GameObject endEffectPrefab; private uint soundID; private float duration; private float hitPauseTimer; private UnityEngine.Vector3 idealDirection; private OverlapAttack attack; private bool inHitPause; private List victimsStruck = new List(); private static int BoxModeExitStateHash = Animator.StringToHash("BoxModeExit"); private static int EmptyStateHash = Animator.StringToHash("Empty"); private static int aimWeightStateHash = Animator.StringToHash("aimWeight"); private static int BoxModeImpactStateHash = Animator.StringToHash("BoxModeImpact"); private static int BoxModeImpactParamHash = Animator.StringToHash("BoxModeImpact.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration; if (base.isAuthority) { if ((bool)base.inputBank) { idealDirection = base.inputBank.aimDirection; idealDirection.y = 0f; } UpdateDirection(); } if ((bool)base.modelLocator) { base.modelLocator.normalizeToFloor = true; } if ((bool)startEffectPrefab && (bool)base.characterBody) { EffectManager.SpawnEffect(startEffectPrefab, new EffectData { origin = base.characterBody.corePosition }, transmit: false); } if ((bool)base.characterDirection) { base.characterDirection.forward = idealDirection; } soundID = Util.PlaySound(startSoundString, base.gameObject); PlayCrossfade("Body", "BoxModeEnter", 0.1f); PlayCrossfade("Stance, Override", "PutAwayGun", 0.1f); base.modelAnimator.SetFloat("aimWeight", 0f); if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.ArmorBoost); } HitBoxGroup hitBoxGroup = null; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Charge"); } attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = GetTeam(); attack.damage = chargeDamageCoefficient * damageStat; attack.hitEffectPrefab = impactEffectPrefab; attack.forceVector = UnityEngine.Vector3.up * upwardForceMagnitude; attack.pushAwayForce = awayForceMagnitude; attack.hitBoxGroup = hitBoxGroup; attack.isCrit = RollCrit(); } public override void OnExit() { AkSoundEngine.StopPlayingID(soundID); Util.PlaySound(endSoundString, base.gameObject); if (!outer.destroying && (bool)base.characterBody) { if ((bool)endEffectPrefab) { EffectManager.SpawnEffect(endEffectPrefab, new EffectData { origin = base.characterBody.corePosition }, transmit: false); } PlayAnimation("Body", BoxModeExitStateHash); PlayCrossfade("Stance, Override", EmptyStateHash, 0.1f); base.characterBody.isSprinting = false; if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost); } } if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision) { base.characterMotor.velocity += GetIdealVelocity(); } if ((bool)base.modelLocator) { base.modelLocator.normalizeToFloor = false; } base.modelAnimator.SetFloat(aimWeightStateHash, 1f); base.OnExit(); } private float GetDamageBoostFromSpeed() { return Mathf.Max(1f, base.characterBody.moveSpeed / base.characterBody.baseMoveSpeed); } private void UpdateDirection() { if ((bool)base.inputBank) { UnityEngine.Vector2 vector = Util.Vector3XZToVector2XY(base.inputBank.moveVector); if (vector != UnityEngine.Vector2.zero) { vector.Normalize(); idealDirection = new UnityEngine.Vector3(vector.x, 0f, vector.y).normalized; } } } private UnityEngine.Vector3 GetIdealVelocity() { return base.characterDirection.forward * base.characterBody.moveSpeed * speedMultiplier; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } else { if (!base.isAuthority) { return; } if ((bool)base.characterBody) { base.characterBody.isSprinting = true; } if ((bool)base.skillLocator.special && base.inputBank.skill4.down) { base.skillLocator.special.ExecuteIfReady(); } UpdateDirection(); if (!inHitPause) { if ((bool)base.characterDirection) { base.characterDirection.moveVector = idealDirection; if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision) { base.characterMotor.rootMotion += GetIdealVelocity() * GetDeltaTime(); } } attack.damage = damageStat * (chargeDamageCoefficient * GetDamageBoostFromSpeed()); if (!attack.Fire(victimsStruck)) { return; } Util.PlaySound(impactSoundString, base.gameObject); inHitPause = true; hitPauseTimer = hitPauseDuration; AddRecoil(-0.5f * recoilAmplitude, -0.5f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude); PlayAnimation("Gesture, Additive", BoxModeImpactStateHash, BoxModeImpactParamHash, hitPauseDuration); for (int i = 0; i < victimsStruck.Count; i++) { float num = 0f; HurtBox hurtBox = victimsStruck[i]; if (!hurtBox.healthComponent) { continue; } CharacterMotor component = hurtBox.healthComponent.GetComponent(); if ((bool)component) { num = component.mass; } else { Rigidbody component2 = hurtBox.healthComponent.GetComponent(); if ((bool)component2) { num = component2.mass; } } if (num >= massThresholdForKnockback) { outer.SetNextState(new ToolbotDashImpact { victimHealthComponent = hurtBox.healthComponent, idealDirection = idealDirection, damageBoostFromSpeed = GetDamageBoostFromSpeed(), isCrit = attack.isCrit }); break; } } } else { base.characterMotor.velocity = UnityEngine.Vector3.zero; hitPauseTimer -= GetDeltaTime(); if (hitPauseTimer < 0f) { inHitPause = false; } } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class ToolbotDashImpact : BaseState { public HealthComponent victimHealthComponent; public UnityEngine.Vector3 idealDirection; public float damageBoostFromSpeed; public bool isCrit; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { if ((bool)victimHealthComponent) { DamageInfo damageInfo = new DamageInfo { attacker = base.gameObject, damage = damageStat * ToolbotDash.knockbackDamageCoefficient * damageBoostFromSpeed, crit = isCrit, procCoefficient = 1f, damageColorIndex = DamageColorIndex.Item, damageType = DamageType.Stun1s, position = base.characterBody.corePosition }; victimHealthComponent.TakeDamage(damageInfo); GlobalEventManager.instance.OnHitEnemy(damageInfo, victimHealthComponent.gameObject); GlobalEventManager.instance.OnHitAll(damageInfo, victimHealthComponent.gameObject); } base.healthComponent.TakeDamageForce(idealDirection * (0f - ToolbotDash.knockbackForce), alwaysApply: true); } if (base.isAuthority) { AddRecoil(-0.5f * ToolbotDash.recoilAmplitude * 3f, -0.5f * ToolbotDash.recoilAmplitude * 3f, -0.5f * ToolbotDash.recoilAmplitude * 8f, 0.5f * ToolbotDash.recoilAmplitude * 3f); EffectManager.SimpleImpactEffect(ToolbotDash.knockbackEffectPrefab, base.characterBody.corePosition, base.characterDirection.forward, transmit: true); outer.SetNextStateToMain(); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(victimHealthComponent ? victimHealthComponent.gameObject : null); writer.Write(idealDirection); writer.Write(damageBoostFromSpeed); writer.Write(isCrit); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); GameObject gameObject = reader.ReadGameObject(); victimHealthComponent = (gameObject ? gameObject.GetComponent() : null); idealDirection = reader.ReadVector3(); damageBoostFromSpeed = reader.ReadSingle(); isCrit = reader.ReadBoolean(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class DroneProjectileInFlight : BaseState { private ProjectileImpactEventCaller impactEventCaller; private ProjectileSimple projectileSimple; private ProjectileFuse projectileFuse; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { impactEventCaller = GetComponent(); if ((bool)impactEventCaller) { impactEventCaller.impactEvent.AddListener(OnImpact); } projectileSimple = GetComponent(); projectileFuse = GetComponent(); if ((bool)projectileFuse) { projectileFuse.onFuse.AddListener(OnFuse); } } } public override void OnExit() { if ((bool)impactEventCaller) { impactEventCaller.impactEvent.RemoveListener(OnImpact); } if ((bool)projectileFuse) { projectileFuse.onFuse.RemoveListener(OnFuse); } base.OnEnter(); } private void OnImpact(ProjectileImpactInfo projectileImpactInfo) { Advance(); } private void OnFuse() { Advance(); } private void Advance() { if (NetworkServer.active) { if ((bool)projectileSimple) { projectileSimple.velocity = 0f; projectileSimple.enabled = false; } if ((bool)base.rigidbody) { base.rigidbody.velocity = new UnityEngine.Vector3(0f, Trajectory.CalculateInitialYSpeedForFlightDuration(DroneProjectilePrepHover.duration), 0f); } } if (base.isAuthority) { outer.SetNextState(new DroneProjectilePrepHover()); } } } public class DroneProjectilePrepHover : BaseState { public static float duration; public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.age >= duration) { outer.SetNextStateToMain(); } } } public class DroneProjectileHover : BaseState { [SerializeField] public float duration; [SerializeField] public int pulseCount = 3; [SerializeField] public float pulseRadius = 7f; protected TeamFilter teamFilter; protected float interval; protected int pulses; public override void OnEnter() { base.OnEnter(); if ((bool)base.rigidbody) { base.rigidbody.velocity = UnityEngine.Vector3.zero; base.rigidbody.useGravity = false; } if (NetworkServer.active && (bool)base.projectileController) { teamFilter = base.projectileController.teamFilter; } interval = duration / (float)(pulseCount + 1); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { if (base.age >= duration) { EntityState.Destroy(base.gameObject); } else if (base.age >= interval * (float)(pulses + 1)) { pulses++; Pulse(); } } } protected virtual void Pulse() { } } public class DroneProjectileHoverStun : DroneProjectileHover { protected override void Pulse() { BlastAttack blastAttack = new BlastAttack { baseDamage = 0f, baseForce = 0f, attacker = (base.projectileController ? base.projectileController.owner : null), inflictor = base.gameObject, bonusForce = UnityEngine.Vector3.zero, attackerFiltering = AttackerFiltering.NeverHitSelf, crit = false, damageColorIndex = DamageColorIndex.Default, damageType = DamageType.Stun1s, falloffModel = BlastAttack.FalloffModel.None, procChainMask = default(ProcChainMask), position = base.transform.position, procCoefficient = 0f, teamIndex = (base.projectileController ? base.projectileController.teamFilter.teamIndex : TeamIndex.None), radius = pulseRadius }; blastAttack.Fire(); EffectData effectData = new EffectData(); effectData.origin = blastAttack.position; effectData.scale = blastAttack.radius; EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/ExplosionVFX"), effectData, transmit: true); } } public class DroneProjectileHoverHeal : DroneProjectileHover { public static float healPointsCoefficient; public static float healFraction; protected override void Pulse() { float num = 1f; ProjectileDamage component = GetComponent(); if ((bool)component) { num = component.damage; } HealOccupants(pulseRadius, healPointsCoefficient * num, healFraction); EffectData effectData = new EffectData(); effectData.origin = base.transform.position; effectData.scale = pulseRadius; EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/ExplosionVFX"), effectData, transmit: true); } private static HealthComponent SelectHealthComponent(Collider collider) { HurtBox component = collider.GetComponent(); if ((bool)component && (bool)component.healthComponent) { return component.healthComponent; } return null; } private void HealOccupants(float radius, float healPoints, float healFraction) { Collider[] colliders; int num = HGPhysics.OverlapSphere(out colliders, base.transform.position, radius, LayerIndex.entityPrecise.mask); TeamIndex teamIndex = (teamFilter ? teamFilter.teamIndex : TeamIndex.None); for (int i = 0; i < num; i++) { HurtBox component = colliders[i].GetComponent(); if (!component || !component.healthComponent) { continue; } HealthComponent healthComponent = component.healthComponent; if (healthComponent.body.teamComponent.teamIndex == teamIndex) { float num2 = healPoints + healthComponent.fullHealth * healFraction; if (num2 > 0f) { healthComponent.Heal(num2, default(ProcChainMask)); } } } HGPhysics.ReturnResults(colliders); } } public abstract class ToolbotDualWieldBase : GenericCharacterMain, ISkillState { public static BuffDef penaltyBuff; public static BuffDef bonusBuff; public static SkillDef inertSkillDef; public static SkillDef cancelSkillDef; public static CharacterCameraParams cameraParams; [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public bool applyPenaltyBuff = true; [SerializeField] public bool applyBonusBuff = true; [SerializeField] public bool applyCameraAimMode = true; private GenericSkill specialSlot; private bool allowPrimarySkills; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private CameraTargetParams.CameraParamsOverrideHandle cameraParamsOverrideHandle; private static int isDualWieldingParamHash = Animator.StringToHash("isDualWielding"); private static int EmptyStateHash = Animator.StringToHash("Empty"); private static GenericSkill.StateMachineResolver offhandStateMachineResolverDelegate = OffhandStateMachineResolver; public GenericSkill activatorSkillSlot { get; set; } protected GenericSkill primary1Slot { get; private set; } protected GenericSkill primary2Slot { get; private set; } protected virtual bool shouldAllowPrimarySkills => false; public override void OnEnter() { base.OnEnter(); allowPrimarySkills = shouldAllowPrimarySkills; if (NetworkServer.active && (bool)base.characterBody) { if ((bool)penaltyBuff && applyPenaltyBuff) { base.characterBody.AddBuff(penaltyBuff); } if ((bool)bonusBuff && applyBonusBuff) { base.characterBody.AddBuff(bonusBuff); } } if ((bool)base.skillLocator) { primary1Slot = base.skillLocator.FindSkillByFamilyName("ToolbotBodyPrimary1"); primary2Slot = base.skillLocator.FindSkillByFamilyName("ToolbotBodyPrimary2"); specialSlot = base.skillLocator.FindSkillByFamilyName("ToolbotBodySpecialFamily"); if (!allowPrimarySkills) { if ((object)inertSkillDef != null) { if ((bool)base.skillLocator.primary) { base.skillLocator.primary.SetSkillOverride(this, inertSkillDef, GenericSkill.SkillOverridePriority.Contextual); } if ((bool)base.skillLocator.secondary) { base.skillLocator.secondary.SetSkillOverride(this, inertSkillDef, GenericSkill.SkillOverridePriority.Contextual); } } } else if ((bool)base.skillLocator.secondary && (bool)primary2Slot) { base.skillLocator.secondary.SetSkillOverride(this, primary2Slot.skillDef, GenericSkill.SkillOverridePriority.Contextual); base.skillLocator.secondary.customStateMachineResolver += offhandStateMachineResolverDelegate; } if ((bool)specialSlot && (object)cancelSkillDef != null) { specialSlot.SetSkillOverride(this, cancelSkillDef, GenericSkill.SkillOverridePriority.Contextual); } } if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } if ((bool)base.modelAnimator) { base.modelAnimator.SetBool(isDualWieldingParamHash, value: true); } if ((bool)base.cameraTargetParams && applyCameraAimMode) { cameraParamsOverrideHandle = base.cameraTargetParams.AddParamsOverride(new CameraTargetParams.CameraParamsOverrideRequest { cameraParamsData = cameraParams.data, priority = 1f }); } StopSkills(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(1f); if (base.isAuthority && (base.characterBody.isSprinting || base.characterBody.HasBuff(DLC2Content.Buffs.DisableAllSkills.buffIndex))) { outer.SetNextStateToMain(); } } } public override void OnExit() { if ((bool)specialSlot && (object)cancelSkillDef != null) { specialSlot.UnsetSkillOverride(this, cancelSkillDef, GenericSkill.SkillOverridePriority.Contextual); } if (!allowPrimarySkills) { if ((object)inertSkillDef != null) { if ((bool)base.skillLocator.secondary) { base.skillLocator.secondary.UnsetSkillOverride(this, inertSkillDef, GenericSkill.SkillOverridePriority.Contextual); } if ((bool)base.skillLocator.primary) { base.skillLocator.primary.UnsetSkillOverride(this, inertSkillDef, GenericSkill.SkillOverridePriority.Contextual); } } } else if ((bool)base.skillLocator.secondary && (bool)primary2Slot) { base.skillLocator.secondary.UnsetSkillOverride(this, primary2Slot.skillDef, GenericSkill.SkillOverridePriority.Contextual); base.skillLocator.secondary.customStateMachineResolver -= offhandStateMachineResolverDelegate; } if (NetworkServer.active && (bool)base.characterBody) { if ((bool)bonusBuff && applyBonusBuff) { base.characterBody.RemoveBuff(bonusBuff); } if ((bool)penaltyBuff && applyPenaltyBuff) { base.characterBody.RemoveBuff(penaltyBuff); } } crosshairOverrideRequest?.Dispose(); if ((bool)base.modelAnimator) { base.modelAnimator.SetBool(isDualWieldingParamHash, value: false); } PlayAnimation("DualWield, Additive", EmptyStateHash); if ((bool)base.cameraTargetParams && cameraParamsOverrideHandle.isValid) { cameraParamsOverrideHandle = base.cameraTargetParams.RemoveParamsOverride(cameraParamsOverrideHandle); } base.OnExit(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); this.Serialize(base.skillLocator, writer); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); this.Deserialize(base.skillLocator, reader); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } private static void OffhandStateMachineResolver(GenericSkill genericSkill, SkillDef skillDef, ref EntityStateMachine targetStateMachine) { if (string.Equals(skillDef.activationStateMachineName, "Weapon", StringComparison.Ordinal)) { targetStateMachine = EntityStateMachine.FindByCustomName(genericSkill.gameObject, "Weapon2"); } } protected void StopSkills() { if (base.isAuthority) { EntityStateMachine.FindByCustomName(base.gameObject, "Weapon")?.SetNextStateToMain(); EntityStateMachine.FindByCustomName(base.gameObject, "Weapon2")?.SetNextStateToMain(); } } } public class ToolbotDualWield : ToolbotDualWieldBase { public static string animLayer; public static string animStateName; public static GameObject coverPrefab; public static GameObject coverEjectEffect; public static string enterSoundString; public static string exitSoundString; public static string startLoopSoundString; public static string stopLoopSoundString; private bool keyReleased; private GameObject coverLeftInstance; private GameObject coverRightInstance; private uint loopSoundID; protected override bool shouldAllowPrimarySkills => true; public override void OnEnter() { base.OnEnter(); PlayAnimation(animLayer, animStateName); Util.PlaySound(enterSoundString, base.gameObject); loopSoundID = Util.PlaySound(startLoopSoundString, base.gameObject); if ((bool)coverPrefab) { Transform transform = FindModelChild("LowerArmL"); Transform transform2 = FindModelChild("LowerArmR"); if ((bool)transform) { coverLeftInstance = UnityEngine.Object.Instantiate(coverPrefab, transform.position, transform.rotation, transform); } if ((bool)transform2) { coverRightInstance = UnityEngine.Object.Instantiate(coverPrefab, transform2.position, transform2.rotation, transform2); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { bool flag = this.IsKeyDownAuthority(base.skillLocator, base.inputBank); keyReleased |= !flag; if (keyReleased && flag) { outer.SetNextState(new ToolbotDualWieldEnd { activatorSkillSlot = base.activatorSkillSlot }); } } } public override void OnExit() { Util.PlaySound(exitSoundString, base.gameObject); Util.PlaySound(stopLoopSoundString, base.gameObject); AkSoundEngine.StopPlayingID(loopSoundID); if ((bool)coverLeftInstance) { EffectManager.SimpleMuzzleFlash(coverEjectEffect, base.gameObject, "LowerArmL", transmit: false); EntityState.Destroy(coverLeftInstance); } if ((bool)coverRightInstance) { EffectManager.SimpleMuzzleFlash(coverEjectEffect, base.gameObject, "LowerArmR", transmit: false); EntityState.Destroy(coverRightInstance); } base.OnExit(); } } public class ToolbotDualWieldStart : ToolbotDualWieldBase { public static float baseDuration; public static string animLayer; public static string animStateName; public static string animPlaybackRateParam; public static string enterSfx; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animLayer, animStateName, animPlaybackRateParam, duration); Util.PlaySound(enterSfx, base.gameObject); if (base.isAuthority && (bool)base.characterMotor && !base.characterMotor.isGrounded) { base.characterMotor.disableAirControlUntilCollision = true; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new ToolbotDualWield { activatorSkillSlot = base.activatorSkillSlot }); } } } public class ToolbotDualWieldEnd : ToolbotDualWieldBase { public static float baseDuration; public static string animLayer; public static string animStateName; public static string animPlaybackRateParam; public static string enterSfx; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animLayer, animStateName, animPlaybackRateParam, duration); Util.PlaySound(enterSfx, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } } public class ToolbotStanceBase : BaseState { protected enum WeaponStance { None = -1, Nailgun, Spear, Grenade, Buzzsaw } private CrosshairUtils.OverrideRequest crosshairOverrideRequest; public static GameObject emptyCrosshairPrefab; public static AnimationCurve emptyCrosshairSpreadCurve; protected RoR2.Inventory inventory; public Type swapStateType; protected void SetPrimarySkill() { base.skillLocator.primary = GetCurrentPrimarySkill(); } protected void SetSecondarySkill(string skillName) { if ((bool)base.skillLocator) { base.skillLocator.secondary = base.skillLocator.FindSkill(skillName); } } protected string GetSkillSlotStance(GenericSkill skillSlot) { return (skillSlot.skillDef as ToolbotWeaponSkillDef)?.stanceName ?? string.Empty; } protected GenericSkill GetPrimarySkill1() { return base.skillLocator.FindSkillByFamilyName("ToolbotBodyPrimary1"); } protected GenericSkill GetPrimarySkill2() { return base.skillLocator.FindSkillByFamilyName("ToolbotBodyPrimary2"); } protected virtual GenericSkill GetCurrentPrimarySkill() { return null; } protected void UpdateCrosshairParameters(ToolbotWeaponSkillDef weaponSkillDef) { GameObject crosshairPrefab = emptyCrosshairPrefab; AnimationCurve crosshairSpreadCurve = emptyCrosshairSpreadCurve; if ((bool)weaponSkillDef) { crosshairPrefab = weaponSkillDef.crosshairPrefab; crosshairSpreadCurve = weaponSkillDef.crosshairSpreadCurve; } crosshairOverrideRequest?.Dispose(); crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill); base.characterBody.spreadBloomCurve = crosshairSpreadCurve; } protected void SetEquipmentSlot(byte i) { if ((bool)inventory) { inventory.SetActiveEquipmentSlot(i); } } public override void OnEnter() { base.OnEnter(); inventory = (base.characterBody ? base.characterBody.inventory : null); SetPrimarySkill(); ToolbotWeaponSkillDef toolbotWeaponSkillDef = GetCurrentPrimarySkill()?.skillDef as ToolbotWeaponSkillDef; if ((bool)toolbotWeaponSkillDef) { SendWeaponStanceToAnimator(toolbotWeaponSkillDef); PlayCrossfade("Gesture, Additive", toolbotWeaponSkillDef.enterGestureAnimState, 0.2f); } UpdateCrosshairParameters(toolbotWeaponSkillDef); } public override void OnExit() { crosshairOverrideRequest?.Dispose(); base.OnExit(); } protected void SendWeaponStanceToAnimator(ToolbotWeaponSkillDef weaponSkillDef) { if ((bool)weaponSkillDef) { GetModelAnimator().SetInteger("weaponStance", weaponSkillDef.animatorWeaponIndex); } } protected static WeaponStance GetSkillStance(GenericSkill skillSlot) { return (skillSlot?.skillDef as ToolbotWeaponSkillDef)?.stanceName switch { "Nailgun" => WeaponStance.Nailgun, "Spear" => WeaponStance.Spear, "Grenade" => WeaponStance.Grenade, "Buzzsaw" => WeaponStance.Buzzsaw, _ => WeaponStance.None, }; } } public class ToolbotStanceA : ToolbotStanceBase { public override void OnEnter() { base.OnEnter(); swapStateType = typeof(ToolbotStanceB); if (NetworkServer.active) { SetEquipmentSlot(0); } } protected override GenericSkill GetCurrentPrimarySkill() { return GetPrimarySkill1(); } } public class ToolbotStanceB : ToolbotStanceBase { public override void OnEnter() { base.OnEnter(); swapStateType = typeof(ToolbotStanceA); if (NetworkServer.active) { SetEquipmentSlot(1); } } protected override GenericSkill GetCurrentPrimarySkill() { return GetPrimarySkill2(); } } public class ToolbotStanceSwap : ToolbotStanceBase { [SerializeField] private float baseDuration = 0.5f; private Run.FixedTimeStamp endTime; public Type nextStanceState; public Type previousStanceState; public override void OnEnter() { base.OnEnter(); float num = baseDuration / attackSpeedStat; endTime = Run.FixedTimeStamp.now + num; GenericSkill a = GetPrimarySkill1(); GenericSkill b = GetPrimarySkill2(); if (previousStanceState != typeof(ToolbotStanceA)) { Util.Swap(ref a, ref b); } if ((bool)b && b.skillDef is ToolbotWeaponSkillDef toolbotWeaponSkillDef) { SendWeaponStanceToAnimator(toolbotWeaponSkillDef); Util.PlaySound(toolbotWeaponSkillDef.entrySound, base.gameObject); } if ((bool)a && a.skillDef is ToolbotWeaponSkillDef toolbotWeaponSkillDef2) { PlayAnimation("Stance, Additive", toolbotWeaponSkillDef2.exitAnimState, "StanceSwap.playbackRate", num * 0.5f); PlayAnimation("Gesture, Additive", toolbotWeaponSkillDef2.exitGestureAnimState); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && endTime.hasPassed) { outer.SetNextState(EntityStateCatalog.InstantiateState(nextStanceState)); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); EntityStateIndex stateIndex = EntityStateCatalog.GetStateIndex(previousStanceState); EntityStateIndex stateIndex2 = EntityStateCatalog.GetStateIndex(nextStanceState); writer.Write(stateIndex); writer.Write(stateIndex2); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); EntityStateIndex entityStateIndex = reader.ReadEntityStateIndex(); EntityStateIndex entityStateIndex2 = reader.ReadEntityStateIndex(); previousStanceState = EntityStateCatalog.GetStateType(entityStateIndex); nextStanceState = EntityStateCatalog.GetStateType(entityStateIndex2); } } public class StartToolbotStanceSwap : BaseState { private EntityStateMachine stanceStateMachine; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { stanceStateMachine = base.gameObject.GetComponents().FirstOrDefault((EntityStateMachine c) => c.customName == "Stance"); if (stanceStateMachine?.state is ToolbotStanceBase toolbotStanceBase && toolbotStanceBase.swapStateType != null) { stanceStateMachine.SetNextState(new ToolbotStanceSwap { previousStanceState = toolbotStanceBase.GetType(), nextStanceState = toolbotStanceBase.swapStateType }); } } } public override void FixedUpdate() { base.FixedUpdate(); outer.SetNextStateToMain(); } } } namespace EntityStates.TimedChest { public class Opening : BaseState { public static float delayUntilUnlockAchievement; private bool hasGrantedAchievement; private static int OpeningStateHash = Animator.StringToHash("Opening"); public static event Action onOpened; public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", OpeningStateHash); TimedChestController component = GetComponent(); if ((bool)component) { component.purchased = true; } if ((bool)base.sfxLocator) { Util.PlaySound(base.sfxLocator.openSound, base.gameObject); } SetPingable(value: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= delayUntilUnlockAchievement && !hasGrantedAchievement) { Opening.onOpened?.Invoke(); hasGrantedAchievement = true; GenericPickupController componentInChildren = base.gameObject.GetComponentInChildren(); if ((bool)componentInChildren) { componentInChildren.enabled = true; } } } } } namespace EntityStates.TeleporterHealNovaController { public class TeleporterHealNovaWindup : BaseState { public static GameObject chargeEffectPrefab; public static float duration; public override void OnEnter() { base.OnEnter(); EffectManager.SimpleEffect(chargeEffectPrefab, base.transform.position, UnityEngine.Quaternion.identity, transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && duration <= base.fixedAge) { outer.SetNextState(new TeleporterHealNovaPulse()); } } } public class TeleporterHealNovaPulse : BaseState { private class HealPulse { private readonly List healedTargets = new List(); private readonly SphereSearch sphereSearch; private float rate; private float t; private float finalRadius; private float healFractionValue; private TeamMask teamMask; private readonly List hurtBoxesList = new List(); public bool isFinished => t >= 1f; public HealPulse(UnityEngine.Vector3 origin, float finalRadius, float healFractionValue, float duration, TeamIndex teamIndex) { sphereSearch = new SphereSearch { mask = LayerIndex.entityPrecise.mask, origin = origin, queryTriggerInteraction = QueryTriggerInteraction.Collide, radius = 0f }; this.finalRadius = finalRadius; this.healFractionValue = healFractionValue; rate = 1f / duration; teamMask = default(TeamMask); teamMask.AddTeam(teamIndex); } public void Update(float deltaTime) { t += rate * deltaTime; t = ((t > 1f) ? 1f : t); sphereSearch.radius = finalRadius * novaRadiusCurve.Evaluate(t); sphereSearch.RefreshCandidates().FilterCandidatesByHurtBoxTeam(teamMask).FilterCandidatesByDistinctHurtBoxEntities() .GetHurtBoxes(hurtBoxesList); int i = 0; for (int count = hurtBoxesList.Count; i < count; i++) { HealthComponent healthComponent = hurtBoxesList[i].healthComponent; if (!healedTargets.Contains(healthComponent)) { healedTargets.Add(healthComponent); HealTarget(healthComponent); } } hurtBoxesList.Clear(); } private void HealTarget(HealthComponent target) { target.HealFraction(healFractionValue, default(ProcChainMask)); Util.PlaySound("Play_item_proc_TPhealingNova_hitPlayer", target.gameObject); } } public static AnimationCurve novaRadiusCurve; public static float duration; private Transform effectTransform; private HealPulse healPulse; private float radius; public override void OnEnter() { base.OnEnter(); if ((bool)base.transform.parent) { HoldoutZoneController componentInParent = base.gameObject.GetComponentInParent(); if ((bool)componentInParent) { radius = componentInParent.currentRadius; } } TeamFilter component = GetComponent(); TeamIndex teamIndex = (component ? component.teamIndex : TeamIndex.None); if (NetworkServer.active) { healPulse = new HealPulse(base.transform.position, radius, 0.5f, duration, teamIndex); } effectTransform = base.transform.Find("PulseEffect"); if ((bool)effectTransform) { effectTransform.gameObject.SetActive(value: true); } } public override void OnExit() { if ((bool)effectTransform) { effectTransform.gameObject.SetActive(value: false); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { healPulse.Update(GetDeltaTime()); if (duration < base.fixedAge) { EntityState.Destroy(outer.gameObject); } } } public override void Update() { if ((bool)effectTransform) { float num = radius * novaRadiusCurve.Evaluate(base.fixedAge / duration); effectTransform.localScale = new UnityEngine.Vector3(num, num, num); } } } public class TeleporterHealNovaGeneratorMain : BaseState { public static GameObject pulsePrefab; [SerializeField] public float minSecondsBetweenPulses; private HoldoutZoneController holdoutZone; private TeamIndex teamIndex; private float previousPulseFraction; private int pulseCount; private float secondsUntilPulseAvailable; public override void OnEnter() { base.OnEnter(); Transform parent = base.transform.parent; if ((bool)parent) { holdoutZone = parent.GetComponentInParent(); previousPulseFraction = GetCurrentTeleporterChargeFraction(); } TeamFilter component = GetComponent(); teamIndex = (component ? component.teamIndex : TeamIndex.None); } private float GetCurrentTeleporterChargeFraction() { return holdoutZone.charge; } public override void FixedUpdate() { if (!NetworkServer.active || !(GetDeltaTime() > 0f)) { return; } if (!holdoutZone || holdoutZone.charge >= 1f) { EntityState.Destroy(outer.gameObject); return; } if (secondsUntilPulseAvailable > 0f) { secondsUntilPulseAvailable -= GetDeltaTime(); return; } pulseCount = CalculatePulseCount(teamIndex); float num = CalculateNextPulseFraction(pulseCount, previousPulseFraction); float currentTeleporterChargeFraction = GetCurrentTeleporterChargeFraction(); if (num < currentTeleporterChargeFraction) { Pulse(); previousPulseFraction = num; secondsUntilPulseAvailable = minSecondsBetweenPulses; } } private static int CalculatePulseCount(TeamIndex teamIndex) { int num = 0; ReadOnlyCollection readOnlyInstancesList = CharacterMaster.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { CharacterMaster characterMaster = readOnlyInstancesList[i]; if (characterMaster.teamIndex == teamIndex) { num += characterMaster.inventory.GetItemCount(RoR2Content.Items.TPHealingNova); } } return num; } private static float CalculateNextPulseFraction(int pulseCount, float previousPulseFraction) { float num = 1f / (float)(pulseCount + 1); for (int i = 1; i <= pulseCount; i++) { float num2 = (float)i * num; if (!(num2 <= previousPulseFraction)) { return num2; } } return 1f; } protected void Pulse() { GameObject obj = UnityEngine.Object.Instantiate(pulsePrefab, base.transform.position, base.transform.rotation, base.transform.parent); obj.GetComponent().teamIndex = teamIndex; NetworkServer.Spawn(obj); } } } namespace EntityStates.FalseSonMeteorPod { public class Descent : EntityStates.SurvivorPod.Descent { public static GameObject effectPrefab; protected override void TransitionIntoNextState() { base.TransitionIntoNextState(); } public override void OnExit() { VehicleSeat component = GetComponent(); if ((bool)component) { component.EjectPassenger(); EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, "Base", transmit: true); } if (NetworkServer.active) { EntityState.Destroy(base.gameObject); } base.OnExit(); } } } namespace EntityStates.RoboCratePod { public class Descent : EntityStates.SurvivorPod.Descent { public static GameObject effectPrefab; protected override void TransitionIntoNextState() { base.TransitionIntoNextState(); EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, "Base", transmit: true); } public override void OnExit() { VehicleSeat component = GetComponent(); if ((bool)component) { component.EjectPassenger(); } if (NetworkServer.active) { EntityState.Destroy(base.gameObject); } base.OnExit(); } } } namespace EntityStates.SurvivorPod { public class Descent : SurvivorPodBaseState { public static float failsafeTimer = 30f; private ShakeEmitter shakeEmitter; private static int InitialSpawnStateHash = Animator.StringToHash("InitialSpawn"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", InitialSpawnStateHash); Transform modelTransform = GetModelTransform(); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("Travel"); if ((bool)transform) { shakeEmitter = transform.gameObject.AddComponent(); shakeEmitter.wave = new Wave { amplitude = 1f, frequency = 180f, cycleOffset = 0f }; shakeEmitter.duration = 10000f; shakeEmitter.radius = 400f; shakeEmitter.amplitudeTimeDecay = false; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { AuthorityFixedUpdate(); } } protected void AuthorityFixedUpdate() { if (base.fixedAge > failsafeTimer) { UnityEngine.Debug.LogError($"Descent timeout {failsafeTimer}..."); TransitionIntoNextState(); return; } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Base"); if (layerIndex != -1 && modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("Idle")) { TransitionIntoNextState(); } } } protected virtual void TransitionIntoNextState() { outer.SetNextState(new Landed()); } public override void OnExit() { EntityState.Destroy(shakeEmitter); base.OnExit(); } } public class Landed : SurvivorPodBaseState { private static int IdleStateHash = Animator.StringToHash("Idle"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", IdleStateHash); Util.PlaySound("Play_UI_podSteamLoop", base.gameObject); base.vehicleSeat.handleVehicleExitRequestServer.AddCallback(HandleVehicleExitRequest); } public override void FixedUpdate() { if (base.fixedAge > 0f) { base.survivorPodController.exitAllowed = true; } base.FixedUpdate(); } private void HandleVehicleExitRequest(GameObject gameObject, ref bool? result) { base.survivorPodController.exitAllowed = false; outer.SetNextState(new PreRelease()); result = true; } public override void OnExit() { base.vehicleSeat.handleVehicleExitRequestServer.RemoveCallback(HandleVehicleExitRequest); base.survivorPodController.exitAllowed = false; Util.PlaySound("Stop_UI_podSteamLoop", base.gameObject); } } public class PreRelease : SurvivorPodBaseState { private static int IdleToReleaseStateHash = Animator.StringToHash("IdleToRelease"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", IdleToReleaseStateHash); Util.PlaySound("Play_UI_podBlastDoorOpen", base.gameObject); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { modelTransform.GetComponent().FindChild("InitialExhaustFX").gameObject.SetActive(value: true); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Base"); if (layerIndex != -1 && modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("IdleToReleaseFinished")) { outer.SetNextState(new Release()); } } } } public class Release : SurvivorPodBaseState { public static float ejectionSpeed = 20f; private static int ReleaseStateHash = Animator.StringToHash("Release"); public static event Action onEnter; public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", ReleaseStateHash); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); component.FindChild("Door").gameObject.SetActive(value: false); component.FindChild("ReleaseExhaustFX").gameObject.SetActive(value: true); } Release.onEnter?.Invoke(this, base.vehicleSeat?.currentPassengerBody); if ((bool)base.survivorPodController && NetworkServer.active && (bool)base.vehicleSeat && (bool)base.vehicleSeat.currentPassengerBody) { base.vehicleSeat.EjectPassenger(base.vehicleSeat.currentPassengerBody.gameObject); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (!base.vehicleSeat || !base.vehicleSeat.currentPassengerBody)) { outer.SetNextState(new ReleaseFinished()); } } } public class ReleaseFinished : SurvivorPodBaseState { private static int ReleaseStateHash = Animator.StringToHash("Release"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", ReleaseStateHash); } } public abstract class SurvivorPodBaseState : EntityState { protected SurvivorPodController survivorPodController { get; private set; } protected VehicleSeat vehicleSeat { get; private set; } public override void OnEnter() { base.OnEnter(); survivorPodController = GetComponent(); vehicleSeat = survivorPodController?.vehicleSeat; if (!survivorPodController && base.isAuthority) { outer.SetNextStateToMain(); } } } } namespace EntityStates.SurvivorPod.BatteryPanel { public class BaseBatteryPanelState : BaseState { protected struct PodInfo { public GameObject podObject; public Animator podAnimator; } protected PodInfo podInfo; public override void OnEnter() { base.OnEnter(); SetPodObject(base.gameObject.GetComponentInParent()?.gameObject); } private void SetPodObject(GameObject podObject) { podInfo = default(PodInfo); if (!podObject) { return; } podInfo.podObject = podObject; ModelLocator component = podObject.GetComponent(); if ((bool)component) { Transform modelTransform = component.modelTransform; if ((bool)modelTransform) { podInfo.podAnimator = modelTransform.GetComponent(); } } } protected void PlayPodAnimation(string layerName, string animationStateName, string playbackRateParam, float duration) { if ((bool)podInfo.podAnimator) { EntityState.PlayAnimationOnAnimator(podInfo.podAnimator, layerName, animationStateName, playbackRateParam, duration); } } protected void PlayPodAnimation(string layerName, string animationStateName) { if ((bool)podInfo.podAnimator) { EntityState.PlayAnimationOnAnimator(podInfo.podAnimator, layerName, animationStateName); } } protected void EnablePickup() { ChildLocator component = podInfo.podAnimator.GetComponent(); if (!component) { return; } Transform transform = component.FindChild("BatteryAttachmentPoint"); if (!transform) { return; } Transform transform2 = transform.Find("QuestVolatileBatteryWorldPickup(Clone)"); if ((bool)transform2) { GenericPickupController component2 = transform2.GetComponent(); if ((bool)component2) { component2.enabled = true; } } } } public class Opening : BaseBatteryPanelState { public static float duration; public static string openSoundString; public override void OnEnter() { base.OnEnter(); PlayPodAnimation("Additive", "OpenPanel", "OpenPanel.playbackRate", duration); Util.PlaySound(openSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new Opened()); } } public override void OnExit() { base.OnExit(); } } public class Opened : BaseBatteryPanelState { public override void OnEnter() { base.OnEnter(); PlayPodAnimation("Additive", "OpenPanelFinished"); EnablePickup(); } } } namespace EntityStates.Emote { public class SurpriseState : EntityState { private float duration; public override void OnEnter() { base.OnEnter(); Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Body"); modelAnimator.Play("EmoteSurprise", layerIndex, 0f); modelAnimator.Update(0f); duration = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Squid { public class SquidDeathState : GenericCharacterDeath { private static int DeathStateHash = Animator.StringToHash("Death"); public static float duration = 0f; public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", DeathStateHash); } } } namespace EntityStates.Squid.SquidWeapon { public class FireSpine : BaseState { public static GameObject hitEffectPrefab; public static GameObject muzzleflashEffectPrefab; public static float damageCoefficient; public static float baseDuration = 2f; public static float procCoefficient = 1f; public static float forceScalar = 1f; private bool hasFiredArrow; private ChildLocator childLocator; private BullseyeSearch enemyFinder; private const float maxVisionDistance = float.PositiveInfinity; public bool fullVision = true; private float duration; private static int FireGooStateHash = Animator.StringToHash("FireGoo"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; GetAimRay(); PlayAnimation("Gesture", FireGooStateHash); if (base.isAuthority) { FireOrbArrow(); } } private void FireOrbArrow() { if (hasFiredArrow || !NetworkServer.active) { return; } Ray aimRay = GetAimRay(); enemyFinder = new BullseyeSearch(); enemyFinder.viewer = base.characterBody; enemyFinder.maxDistanceFilter = float.PositiveInfinity; enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.sortMode = BullseyeSearch.SortMode.Distance; enemyFinder.teamMaskFilter = TeamMask.allButNeutral; enemyFinder.minDistanceFilter = 0f; enemyFinder.maxAngleFilter = (fullVision ? 180f : 90f); enemyFinder.filterByLoS = true; if ((bool)base.teamComponent) { enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } enemyFinder.RefreshCandidates(); HurtBox hurtBox = enemyFinder.GetResults().FirstOrDefault(); if ((bool)hurtBox) { UnityEngine.Vector3 vector = hurtBox.transform.position - GetAimRay().origin; aimRay.origin = GetAimRay().origin; aimRay.direction = vector; base.inputBank.aimDirection = vector; StartAimMode(aimRay); hasFiredArrow = true; SquidOrb squidOrb = new SquidOrb(); squidOrb.forceScalar = forceScalar; squidOrb.damageValue = base.characterBody.damage * damageCoefficient; squidOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master); squidOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); squidOrb.attacker = base.gameObject; squidOrb.procCoefficient = procCoefficient; HurtBox hurtBox2 = hurtBox; if ((bool)hurtBox2) { Transform transform = base.characterBody.modelLocator.modelTransform.GetComponent().FindChild("Muzzle"); EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "Muzzle", transmit: true); squidOrb.origin = transform.position; squidOrb.target = hurtBox2; OrbManager.instance.AddOrb(squidOrb); } } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.Squid.DeathState { public class DeathState : BaseState { public static float baseDuration; private float duration; private static int DeathStateHash = Animator.StringToHash("Death"); public override void OnEnter() { duration = baseDuration; base.OnEnter(); PlayAnimation("Body", DeathStateHash); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { EntityState.Destroy(base.gameObject); } } public override void OnExit() { if (!outer.destroying && (bool)base.gameObject) { EntityState.Destroy(base.gameObject); } base.OnExit(); } } } namespace EntityStates.SpectatorSkills { public class LockOn : BaseSkillState { private UnityEngine.Vector3 targetPoint; public override void OnEnter() { base.OnEnter(); if (base.inputBank.GetAimRaycast(float.PositiveInfinity, out var hitInfo)) { targetPoint = hitInfo.point; } else { outer.SetNextStateToMain(); } RoR2Application.onUpdate += LookAtTarget; RoR2Application.onLateUpdate += LookAtTarget; } public override void OnExit() { RoR2Application.onLateUpdate -= LookAtTarget; RoR2Application.onUpdate -= LookAtTarget; base.OnExit(); } public override void Update() { base.Update(); if (base.isAuthority && !IsKeyDownAuthority()) { outer.SetNextStateToMain(); } } private void LookAtTarget() { ReadOnlyCollection readOnlyInstancesList = CameraRigController.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { _ = readOnlyInstancesList[i].target == base.gameObject; } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.Sniper.SniperWeapon { public class FireRifle : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float minChargeDamageCoefficient; public static float maxChargeDamageCoefficient; public static float minChargeForce; public static float maxChargeForce; public static int bulletCount; public static float baseDuration = 2f; public static string attackSoundString; public static float recoilAmplitude; public static float spreadBloomValue = 0.3f; public static float interruptInterval = 0.2f; private float duration; private bool inputReleased; private static int FireShotgunStateHash = Animator.StringToHash("FireShotgun"); private static int FireShotgunParamHash = Animator.StringToHash("FireShotgun.playbackRate"); public override void OnEnter() { base.OnEnter(); float num = 0f; if ((bool)base.skillLocator) { GenericSkill secondary = base.skillLocator.secondary; if ((bool)secondary) { EntityStateMachine stateMachine = secondary.stateMachine; if ((bool)stateMachine && stateMachine.state is ScopeSniper scopeSniper) { num = scopeSniper.charge; scopeSniper.charge = 0f; } } } AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude); duration = baseDuration / attackSpeedStat; Ray aimRay = GetAimRay(); StartAimMode(aimRay); Util.PlaySound(attackSoundString, base.gameObject); PlayAnimation("Gesture", FireShotgunStateHash, FireShotgunParamHash, duration * 1.1f); string muzzleName = "MuzzleShotgun"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = base.characterBody.spreadBloomAngle; bulletAttack.bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u); bulletAttack.procCoefficient = 1f / (float)bulletCount; bulletAttack.damage = Mathf.LerpUnclamped(minChargeDamageCoefficient, maxChargeDamageCoefficient, num) * damageStat / (float)bulletCount; bulletAttack.force = Mathf.LerpUnclamped(minChargeForce, maxChargeForce, num); bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleName; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); if (num == 1f) { bulletAttack.stopperMask = LayerIndex.world.mask; } bulletAttack.HitEffectNormal = false; bulletAttack.radius = 0f; bulletAttack.sniper = true; bulletAttack.Fire(); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.inputBank) { inputReleased |= !base.inputBank.skill1.down; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { if (inputReleased && base.fixedAge >= interruptInterval / attackSpeedStat) { return InterruptPriority.Any; } return InterruptPriority.Skill; } } public class Reload : BaseState { public static float baseDuration = 1f; public static float reloadTimeFraction = 0.75f; public static string soundString = ""; private float duration; private float reloadTime; private Animator modelAnimator; private bool reloaded; private EntityStateMachine scopeStateMachine; private static int PrepBarrageStateHash = Animator.StringToHash("PrepBarrage"); private static int PrepBarrageParamHash = Animator.StringToHash("PrepBarrage.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; reloadTime = duration * reloadTimeFraction; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayAnimation("Gesture", PrepBarrageStateHash, PrepBarrageParamHash, duration); } if ((bool)base.skillLocator) { GenericSkill secondary = base.skillLocator.secondary; if ((bool)secondary) { scopeStateMachine = secondary.stateMachine; } } if (base.isAuthority && (bool)scopeStateMachine) { scopeStateMachine.SetNextState(new LockSkill()); } } public override void FixedUpdate() { base.FixedUpdate(); if (!reloaded && base.fixedAge >= reloadTime) { if ((bool)base.skillLocator) { GenericSkill primary = base.skillLocator.primary; if ((bool)primary) { primary.Reset(); Util.PlaySound(soundString, base.gameObject); } } reloaded = true; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if (base.isAuthority && (bool)scopeStateMachine) { scopeStateMachine.SetNextStateToMain(); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.Sniper.Scope { public class ScopeSniper : BaseState { public static float baseChargeDuration = 4f; public static GameObject crosshairPrefab; public float charge; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private GameObject laserPointerObject; private CameraTargetParams.AimRequest aimRequest; public override void OnEnter() { base.OnEnter(); charge = 0f; if (NetworkServer.active && (bool)base.characterBody) { base.characterBody.AddBuff(RoR2Content.Buffs.Slow50); } if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.FirstPerson); base.cameraTargetParams.fovOverride = 20f; } if ((bool)crosshairPrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill); } laserPointerObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/LaserPointerBeamEnd")); laserPointerObject.GetComponent().source = base.inputBank; } public override void OnExit() { EntityState.Destroy(laserPointerObject); if (NetworkServer.active && (bool)base.characterBody) { base.characterBody.RemoveBuff(RoR2Content.Buffs.Slow50); } aimRequest?.Dispose(); if ((bool)base.cameraTargetParams) { base.cameraTargetParams.fovOverride = -1f; } crosshairOverrideRequest?.Dispose(); base.OnExit(); } public override void FixedUpdate() { charge = Mathf.Min(charge + attackSpeedStat / baseChargeDuration * GetDeltaTime(), 1f); if (base.isAuthority && (!base.inputBank || !base.inputBank.skill2.down)) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.SiphonItem { public class BaseSiphonItemState : BaseBodyAttachmentState { private List FXParticles = new List(); protected int GetItemStack() { if (!base.attachedBody || !base.attachedBody.inventory) { return 1; } return base.attachedBody.inventory.GetItemCount(RoR2Content.Items.SiphonOnLowHealth); } public override void OnEnter() { base.OnEnter(); FXParticles = base.gameObject.GetComponentsInChildren().ToList(); } public void TurnOffHealingFX() { for (int i = 0; i < FXParticles.Count; i++) { ParticleSystem.EmissionModule emission = FXParticles[i].emission; emission.enabled = false; } } public void TurnOnHealingFX() { for (int i = 0; i < FXParticles.Count; i++) { ParticleSystem.EmissionModule emission = FXParticles[i].emission; emission.enabled = true; } } } public class RechargeState : BaseSiphonItemState { public static float baseDuration = 30f; public static AnimationCurve particleEmissionCurve; private float rechargeDuration; public override void OnEnter() { base.OnEnter(); TurnOffHealingFX(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { int itemStack = GetItemStack(); float num = baseDuration / (float)(itemStack + 1); if (base.fixedAge / num >= 1f) { outer.SetNextState(new ReadyState()); } } } } public class ReadyState : BaseSiphonItemState { public static float healthFractionThreshold = 0.5f; private HealthComponent attachedHealthComponent; public override void OnEnter() { base.OnEnter(); attachedHealthComponent = base.attachedBody?.healthComponent; TurnOffHealingFX(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && attachedHealthComponent.combinedHealthFraction <= healthFractionThreshold) { outer.SetNextState(new ChargeState()); } } } public class ChargeState : BaseSiphonItemState { public static float baseDuration = 3f; public static string chargeSound; private float duration; private GameObject chargeVfxInstance; private GameObject areaIndicatorVfxInstance; public override void OnEnter() { base.OnEnter(); duration = baseDuration / (base.attachedBody ? base.attachedBody.attackSpeed : 1f); TurnOffHealingFX(); if ((bool)base.attachedBody) { UnityEngine.Vector3 position = base.transform.position; UnityEngine.Quaternion rotation = base.transform.rotation; chargeVfxInstance = UnityEngine.Object.Instantiate(ChargeMegaNova.chargingEffectPrefab, position, rotation); chargeVfxInstance.transform.localScale = UnityEngine.Vector3.one * 0.25f; Util.PlaySound(chargeSound, base.gameObject); areaIndicatorVfxInstance = UnityEngine.Object.Instantiate(ChargeMegaNova.areaIndicatorPrefab, position, rotation); ObjectScaleCurve component = areaIndicatorVfxInstance.GetComponent(); component.timeMax = duration; component.baseScale = UnityEngine.Vector3.one * DetonateState.baseSiphonRange * 2f; areaIndicatorVfxInstance.GetComponent().timeMax = duration; } RoR2Application.onLateUpdate += OnLateUpdate; } public override void OnExit() { RoR2Application.onLateUpdate -= OnLateUpdate; if ((object)chargeVfxInstance != null) { EntityState.Destroy(chargeVfxInstance); chargeVfxInstance = null; } if ((object)areaIndicatorVfxInstance != null) { EntityState.Destroy(areaIndicatorVfxInstance); areaIndicatorVfxInstance = null; } base.OnExit(); } private void OnLateUpdate() { if ((bool)chargeVfxInstance) { chargeVfxInstance.transform.position = base.transform.position; } if ((bool)areaIndicatorVfxInstance) { areaIndicatorVfxInstance.transform.position = base.transform.position; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new DetonateState()); } } } public class DetonateState : BaseSiphonItemState { public static float baseSiphonRange = 50f; public static float baseDuration; public static float healPulseFraction = 0.5f; public static float healMultiplier = 2f; public static float damageFraction = 0.1f; public static GameObject burstEffectPrefab; public static string explosionSound; public static string siphonLoopSound; public static string retractSound; private float duration; private float gainedHealth; private float gainedHealthFraction; private float healTimer; private bool burstPlayed; public override void OnEnter() { base.OnEnter(); duration = baseDuration; GetItemStack(); UnityEngine.Vector3 position = base.attachedBody.transform.position; SphereSearch obj = new SphereSearch { origin = position, radius = baseSiphonRange, mask = LayerIndex.entityPrecise.mask }; float num = base.attachedBody.healthComponent.fullCombinedHealth * damageFraction; TeamMask mask = default(TeamMask); mask.AddTeam(base.attachedBody.teamComponent.teamIndex); HurtBox[] hurtBoxes = obj.RefreshCandidates().FilterCandidatesByHurtBoxTeam(mask).OrderCandidatesByDistance() .FilterCandidatesByDistinctHurtBoxEntities() .GetHurtBoxes(); foreach (HurtBox hurtBox in hurtBoxes) { if (hurtBox.healthComponent != base.attachedBody.healthComponent) { if (!burstPlayed) { burstPlayed = true; Util.PlaySound(explosionSound, base.gameObject); Util.PlaySound(siphonLoopSound, base.gameObject); EffectData effectData = new EffectData { scale = 1f, origin = position }; effectData.SetHurtBoxReference(base.attachedBody.modelLocator.modelTransform.GetComponent().FindChild("Base").gameObject); EffectManager.SpawnEffect(burstEffectPrefab, effectData, transmit: false); } DamageInfo damageInfo = new DamageInfo { attacker = base.attachedBody.gameObject, inflictor = base.attachedBody.gameObject, crit = false, damage = num, damageColorIndex = DamageColorIndex.Default, damageType = DamageType.Generic, force = UnityEngine.Vector3.zero, position = hurtBox.transform.position }; hurtBox.healthComponent.TakeDamage(damageInfo); HurtBox hurtBoxReference = hurtBox; HurtBoxGroup hurtBoxGroup = hurtBox.hurtBoxGroup; for (int j = 0; (float)j < Mathf.Min(4f, base.attachedBody.radius * 2f); j++) { EffectData effectData2 = new EffectData { scale = 1f, origin = position, genericFloat = 3f }; effectData2.SetHurtBoxReference(hurtBoxReference); GameObject obj2 = LegacyResourcesAPI.Load("Prefabs/Effects/OrbEffects/SiphonOrbEffect"); obj2.GetComponent().parentObjectTransform = base.attachedBody.mainHurtBox.transform; EffectManager.SpawnEffect(obj2, effectData2, transmit: true); hurtBoxReference = hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, hurtBoxGroup.hurtBoxes.Length)]; } gainedHealth += num; } } gainedHealthFraction = gainedHealth * healPulseFraction; } public override void FixedUpdate() { base.FixedUpdate(); healTimer += GetDeltaTime(); if (base.isAuthority && healTimer > duration * healPulseFraction && gainedHealth > 0f) { base.attachedBody.healthComponent.Heal(gainedHealthFraction, default(ProcChainMask)); TurnOnHealingFX(); healTimer = 0f; if (base.fixedAge >= duration) { Util.PlaySound(retractSound, base.gameObject); TurnOffHealingFX(); outer.SetNextState(new RechargeState()); } } } } } namespace EntityStates.ShrineRebirth { public class ShrineRebirthEntityStates : EntityState { protected ShrineRebirthController _shrineController; protected PickupPickerController _pickupPickerController; protected PurchaseInteraction _pi; protected NetworkUIPromptController _netUIPromptController; public override void OnEnter() { base.OnEnter(); _shrineController = base.gameObject.GetComponent(); if (_shrineController.isForTesting) { outer.SetNextStateToMain(); } } public override void OnExit() { base.OnExit(); } } public class RevealRebirthShriine : ShrineRebirthEntityStates { [SyncVar] private GameObject shrineModel; public override void OnEnter() { base.OnEnter(); if (Run.instance.selectedDifficulty < DifficultyIndex.Eclipse1) { _shrineController.purchaseInteraction.SetAvailable(newAvailable: true); _shrineController.onShrineRevealObjectiveTextObject.SetActive(value: true); Transform transform = _shrineController.childLocator.FindChild("ShrineModel"); if ((bool)transform) { shrineModel = transform.gameObject; if (!shrineModel.activeInHierarchy) { shrineModel.SetActive(value: true); } } return; } Transform transform2 = _shrineController.childLocator.FindChild("ShrineModel"); shrineModel = transform2.gameObject; shrineModel.SetActive(value: false); GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(_shrineController.helminthPortalISC, new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Direct, position = _shrineController.portalObject.transform.position, spawnOnTarget = _shrineController.portalObject.transform }, Run.instance.stageRng)); if ((bool)gameObject) { gameObject.transform.rotation = _shrineController.portalObject.transform.rotation; } } public override void OnExit() { _shrineController.onShrineRevealObjectiveTextObject.SetActive(value: false); base.OnExit(); } } public class RebirthOrPortalChoice : ShrineRebirthEntityStates { public override void OnEnter() { base.OnEnter(); _shrineController.onRebirthOrContinueTextObject.SetActive(value: true); _shrineController.CallRpcChangeInteractScript(); GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(_shrineController.helminthPortalISC, new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Direct, position = _shrineController.portalObject.transform.position, spawnOnTarget = _shrineController.portalObject.transform }, Run.instance.stageRng)); if ((bool)gameObject) { gameObject.transform.rotation = _shrineController.portalObject.transform.rotation; } } public override void OnExit() { base.OnExit(); _shrineController.onRebirthOrContinueTextObject.SetActive(value: true); } } public class RebirthChoice : ShrineRebirthEntityStates { public float rebirthGameEndingTransition = 15f; public override void OnEnter() { base.OnEnter(); Util.PlaySound("Play_obj_shrineColossus_locked_loop", base.gameObject); Transform transform = _shrineController.childLocator.FindChild("TriggeredVFXSpawnPoint"); GameObject effectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/RebirthOnRebirthVFX"); EffectData effectData = new EffectData { origin = transform.position, genericFloat = 1.5f }; effectData.SetNetworkedObjectReference(base.gameObject); int childIndex = _shrineController.childLocator.FindChildIndex("TriggeredVFXSpawnPoint"); effectData.SetChildLocatorTransformReference(base.gameObject, childIndex); if (NetworkServer.active) { EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true); } } public override void FixedUpdate() { base.FixedUpdate(); _ = base.fixedAge; _ = rebirthGameEndingTransition; } } public class RebirthStormEnding : ShrineRebirthEntityStates { public override void OnEnter() { base.OnEnter(); } } } namespace EntityStates.ShrineHalcyonite { public class ShrineHalcyoniteBaseState : BaseState { protected HalcyoniteShrineInteractable parentShrineReference; protected GameObject crystalObject; protected ParticleSystem ps; protected GameObject shrineHalcyoniteBubble; protected GameObject shrineBase; private Xoroshiro128Plus rng; private GameObject modelBase; protected bool visualsDone; protected float timer; private int sliceHeightNameId; private Renderer shrineBaseRenderer; public override void OnEnter() { base.OnEnter(); parentShrineReference = GetComponent(); if ((bool)parentShrineReference) { shrineHalcyoniteBubble = parentShrineReference.shrineHalcyoniteBubble; crystalObject = parentShrineReference.crystalObject; crystalObject.GetComponent(); shrineBase = parentShrineReference.shrineBaseObject; } shrineBaseRenderer = parentShrineReference.shrineGoldTop.GetComponent(); shrineBaseRenderer.material.EnableKeyword("_SLICEHEIGHT"); int propertyIndex = shrineBaseRenderer.material.shader.FindPropertyIndex("_SliceHeight"); sliceHeightNameId = shrineBaseRenderer.material.shader.GetPropertyNameId(propertyIndex); } public override void OnExit() { base.OnExit(); } protected void TierChange(float tierChangeVFXModifier) { Transform transform = parentShrineReference.modelChildLocator.FindChild("ModelBase"); if ((bool)transform) { modelBase = transform.gameObject; } UnityEngine.Vector3 origin = modelBase.gameObject.transform.position + new UnityEngine.Vector3(0f, tierChangeVFXModifier, 0f); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/HalcyonShrineTierReachVFX"), new EffectData { origin = origin }, transmit: false); Util.PlaySound("Play_obj_shrineHalcyonite_tierChange", base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); parentShrineReference.shrineGoldTop.GetComponent().material.SetFloat(sliceHeightNameId, parentShrineReference.goldMaterialModifier); } protected void ModifyVisuals() { if (!NetworkServer.active || visualsDone || !parentShrineReference.isDraining) { return; } float num = 4.1f; float num2 = 3.5f; float num3 = 4f; float num4 = (float)parentShrineReference.goldDrainValue * num / (float)parentShrineReference.lowGoldCost; if (parentShrineReference.goldDrained < parentShrineReference.lowGoldCost || parentShrineReference.goldMaterialModifier < 1.9f) { HalcyoniteShrineInteractable halcyoniteShrineInteractable = parentShrineReference; halcyoniteShrineInteractable.NetworkgoldMaterialModifier = halcyoniteShrineInteractable.goldMaterialModifier + num4; } if ((parentShrineReference.goldDrained > parentShrineReference.lowGoldCost && parentShrineReference.goldDrained < parentShrineReference.midGoldCost) || (parentShrineReference.goldMaterialModifier < 6f && parentShrineReference.goldMaterialModifier >= 1.9f)) { num4 = (float)parentShrineReference.goldDrainValue * num2 / (float)(parentShrineReference.midGoldCost - parentShrineReference.lowGoldCost); if (parentShrineReference.goldMaterialModifier >= 5f) { num4 = (float)parentShrineReference.goldDrainValue * num3 / (float)(parentShrineReference.maxGoldCost - parentShrineReference.midGoldCost); } HalcyoniteShrineInteractable halcyoniteShrineInteractable2 = parentShrineReference; halcyoniteShrineInteractable2.NetworkgoldMaterialModifier = halcyoniteShrineInteractable2.goldMaterialModifier + num4; } if ((parentShrineReference.goldDrained > parentShrineReference.midGoldCost && parentShrineReference.goldDrained < parentShrineReference.maxGoldCost) || parentShrineReference.goldMaterialModifier >= 6f) { num4 = (float)parentShrineReference.goldDrainValue * num3 / (float)(parentShrineReference.maxGoldCost - parentShrineReference.midGoldCost); HalcyoniteShrineInteractable halcyoniteShrineInteractable3 = parentShrineReference; halcyoniteShrineInteractable3.NetworkgoldMaterialModifier = halcyoniteShrineInteractable3.goldMaterialModifier + num4; } if (parentShrineReference.goldDrained >= parentShrineReference.maxGoldCost) { visualsDone = true; } } } public class ShrineHalcyoniteActivatedState : ShrineHalcyoniteBaseState { public float shrineAnimationDuration = 1f; public float shrineDelayAge; public UnityEngine.Vector3 shrineEndLocation = new UnityEngine.Vector3(0f, 0f, 0f); private float shrineMovementTimer; private GameObject modelBase; public override void OnEnter() { base.OnEnter(); Transform transform = parentShrineReference.modelChildLocator.FindChild("ModelBase"); if ((bool)transform) { modelBase = transform.gameObject; } EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/HalcyonResurfaceVFX"), new EffectData { origin = base.gameObject.transform.position }, transmit: true); Util.PlaySound("Play_obj_shrineHalcyonite_activate", base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); shrineMovementTimer -= Time.deltaTime; if (!(shrineMovementTimer <= 0f)) { return; } if (modelBase.transform.localPosition != shrineEndLocation) { shrineMovementTimer += 0.05f; modelBase.transform.localPosition += new UnityEngine.Vector3(0f, 0.1f, 0f); if (modelBase.transform.localPosition == shrineEndLocation) { Util.PlaySound("Play_obj_shrineHalcyonite_activate_finish", base.gameObject); } } else { shrineDelayAge += Time.deltaTime; if (shrineDelayAge >= shrineAnimationDuration) { outer.SetNextState(new ShrineHalcyoniteNoQuality()); } } } } public class ShrineHalcyoniteNoQuality : ShrineHalcyoniteBaseState { [SerializeField] public float tierChangeMonsterCreditReduction; public override void OnEnter() { base.OnEnter(); parentShrineReference.TrackInteractions(); shrineHalcyoniteBubble.SetActive(value: true); parentShrineReference.activationDirector.monsterCredit += parentShrineReference.monsterCredit - tierChangeMonsterCreditReduction; parentShrineReference.activationDirector.SpendAllCreditsOnMapSpawns(parentShrineReference.gameObject.transform); GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain += base.ModifyVisuals; Util.PlaySound("Play_obj_shrineHalcyonite_idle_loop", base.gameObject); } public override void OnExit() { base.OnExit(); GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain -= base.ModifyVisuals; } } public class ShrineHalcyoniteLowQuality : ShrineHalcyoniteBaseState { [SerializeField] public float tierChangeMonsterCreditReduction; public override void OnEnter() { base.OnEnter(); GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain += base.ModifyVisuals; TierChange(5f); parentShrineReference.activationDirector.monsterCredit += parentShrineReference.monsterCredit - tierChangeMonsterCreditReduction; parentShrineReference.activationDirector.SpendAllCreditsOnMapSpawns(parentShrineReference.gameObject.transform); } public override void OnExit() { base.OnExit(); GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain -= base.ModifyVisuals; } } public class ShrineHalcyoniteMidQuality : ShrineHalcyoniteBaseState { [SerializeField] public float tierChangeMonsterCreditReduction; public override void OnEnter() { base.OnEnter(); TierChange(8f); GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain += base.ModifyVisuals; parentShrineReference.activationDirector.monsterCredit += parentShrineReference.monsterCredit - tierChangeMonsterCreditReduction; parentShrineReference.activationDirector.SpendAllCreditsOnMapSpawns(parentShrineReference.gameObject.transform); } public override void OnExit() { base.OnExit(); GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain -= base.ModifyVisuals; } } public class ShrineHalcyoniteMaxQuality : ShrineHalcyoniteBaseState { public override void OnEnter() { base.OnEnter(); parentShrineReference.shrineGoldTop.SetActive(value: true); parentShrineReference.DrainConditionMet(); } } public class ShrineHalcyoniteFinished : ShrineHalcyoniteBaseState { public override void OnEnter() { base.OnEnter(); if (shrineHalcyoniteBubble.activeInHierarchy) { Util.PlaySound("Stop_obj_shrineHalcyonite_idle_loop", base.gameObject); shrineHalcyoniteBubble.SetActive(value: false); } } } } namespace EntityStates.Seeker { public class InnerStrength : BaseState { public override void OnEnter() { } } public class Meditate : BaseWindUp { [SerializeField] public new GameObject scopeOverlayPrefab; private OverlayController overlayController; public override void OnEnter() { base.OnEnter(); overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams { prefab = scopeOverlayPrefab, childLocatorEntry = "ScopeContainer" }); } } public class BaseScopeState : BaseSkillState { [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public GameObject scopeOverlayPrefab; [SerializeField] public CharacterCameraParams cameraParams; [SerializeField] public float cameraOverridePriority; public static string mecanimBoolName; private OverlayController overlayController; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private CameraTargetParams.CameraParamsOverrideHandle cameraParamsOverrideHandle; public static bool inScope; public override void OnEnter() { base.OnEnter(); overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams { prefab = scopeOverlayPrefab, childLocatorEntry = "ScopeContainer" }); Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetBool(mecanimBoolName, value: true); } if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } inScope = true; } public override void OnExit() { inScope = false; Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetBool(mecanimBoolName, value: false); } RemoveOverlay(0f); crosshairOverrideRequest?.Dispose(); base.OnExit(); } protected void SetScopeAlpha(float alpha) { if (overlayController != null) { overlayController.alpha = alpha; } } protected void RemoveOverlay(float transitionDuration) { if (overlayController != null) { HudOverlayManager.RemoveOverlay(overlayController); overlayController = null; } } protected void StartScopeParamsOverride(float transitionDuration) { if (!cameraParamsOverrideHandle.isValid) { cameraParamsOverrideHandle = base.cameraTargetParams.AddParamsOverride(new CameraTargetParams.CameraParamsOverrideRequest { cameraParamsData = cameraParams.data, priority = cameraOverridePriority }, transitionDuration); } } protected void EndScopeParamsOverride(float transitionDuration) { if (cameraParamsOverrideHandle.isValid) { base.cameraTargetParams.RemoveParamsOverride(cameraParamsOverrideHandle, transitionDuration); cameraParamsOverrideHandle = default(CameraTargetParams.CameraParamsOverrideHandle); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } protected virtual CharacterCameraParams GetCameraParams() { return cameraParams; } protected virtual float GetScopeEntryDuration() { return 0f; } } public class BaseWindUp : BaseScopeState { [SerializeField] public float baseDuration; [SerializeField] public string enterSoundString; private float duration; public override void OnEnter() { duration = baseDuration; base.OnEnter(); SetScopeAlpha(0f); StartScopeParamsOverride(duration); Util.PlaySound(enterSoundString, base.gameObject); } public override void OnExit() { EndScopeParamsOverride(0f); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { BaseActive nextState = GetNextState(); nextState.activatorSkillSlot = base.activatorSkillSlot; outer.SetNextState(nextState); } } public override void Update() { base.Update(); SetScopeAlpha(Mathf.Clamp01(base.age / duration)); } protected virtual BaseActive GetNextState() { return new BaseActive(); } protected override float GetScopeEntryDuration() { return duration; } public override void ModifyNextState(EntityState nextState) { } } public class BaseWindDown : BaseScopeState { [SerializeField] public float baseDuration; [SerializeField] public string enterSoundString; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration; SetScopeAlpha(1f); RemoveOverlay(duration); StartScopeParamsOverride(0f); EndScopeParamsOverride(duration); Util.PlaySound(enterSoundString, base.gameObject); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override void Update() { base.Update(); SetScopeAlpha(1f - Mathf.Clamp01(base.age / duration)); } protected override CharacterCameraParams GetCameraParams() { return null; } } public class BaseActive : BaseScopeState { [SerializeField] public SkillDef primaryOverride; [SerializeField] public LoopSoundDef loopSound; private GenericSkill overriddenSkill; private LoopSoundManager.SoundLoopPtr loopPtr; public override void OnEnter() { base.OnEnter(); SetScopeAlpha(1f); StartScopeParamsOverride(0f); GenericSkill genericSkill = base.skillLocator?.primary; if ((bool)genericSkill) { TryOverrideSkill(genericSkill); genericSkill.onSkillChanged += TryOverrideSkill; } if (base.isAuthority) { loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSound); } } public override void OnExit() { if (loopPtr.isValid) { LoopSoundManager.StopSoundLoopLocal(loopPtr); } GenericSkill genericSkill = base.skillLocator?.primary; if ((bool)genericSkill) { genericSkill.onSkillChanged -= TryOverrideSkill; } if ((bool)overriddenSkill) { overriddenSkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); } EndScopeParamsOverride(0f); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && (!IsKeyDownAuthority() || base.characterBody.isSprinting)) { outer.SetNextState(GetNextState()); } } private void TryOverrideSkill(GenericSkill skill) { if ((bool)skill && !overriddenSkill && !skill.HasSkillOverrideOfPriority(GenericSkill.SkillOverridePriority.Contextual)) { overriddenSkill = skill; overriddenSkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); overriddenSkill.stock = base.skillLocator.secondary.stock; } } protected virtual BaseWindDown GetNextState() { return new BaseWindDown(); } } public class MeditationUI : BaseSkillState { [SerializeField] [Header("UI")] public GameObject scopeOverlayPrefab; [SerializeField] public float duration = 5f; [SerializeField] public float timePenalty = 1f; [SerializeField] public float failureCooldownPenalty = 5f; [SerializeField] public float animDuration; [SerializeField] public float smallHopVelocity; [SerializeField] public Sprite primaryIcon; [SerializeField] public Sprite secondaryIcon; [SerializeField] public Sprite utilityIcon; [SerializeField] public Sprite specialIcon; [SerializeField] public SeekerController seekerController; [SerializeField] public GameObject lotusPrefab; [SerializeField] public float wrapUpDuration; [SerializeField] public GameObject successEffectPrefab; [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public string startSoundString; [SerializeField] public string stopSoundString; [SerializeField] public string timeoutSoundString; [SerializeField] public string successSoundString; [SerializeField] public string inputCorrectSoundString; [SerializeField] public string inputFailSoundString; [SerializeField] [Header("Healing Explosion")] public float healingExplosionAmount = 10f; [SerializeField] public float healingOverShield = 5f; [SerializeField] public float blastRadius = 5f; [SerializeField] public float damageCoefficient = 5f; [SerializeField] public float blastForce = 5f; [SerializeField] public UnityEngine.Vector3 blastBonusForce; [SerializeField] public float blastProcCoefficient = 5f; [SerializeField] public float percentPerGate = 0.75f; [SerializeField] public float overShieldPercent = 0.25f; [SerializeField] public float startingOverShieldPercentage = 0.33f; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private GameObject lotus; private OverlayController overlayController; private bool meditationSuccess; private ICharacterGravityParameterProvider characterGravityParameterProvider; private ChildLocator overlayInstanceChildLocator; private ChildLocator lotusChildLocator; private List fillUiList = new List(); private CameraTargetParams.AimRequest aimRequest; private bool spawnedLotus; private bool failed; private bool meditationWrapUp; private bool wrapUpAnimationPlayed; private float wrapUpTimer; private float startingYaw; private EntityStateMachine bodyStateMachine; private float explosionHealingMod; private bool upReady = true; private bool downReady = true; private bool rightReady = true; private bool leftReady = true; private static string[] c = new string[5] { "ArrowInput1", "ArrowInput2", "ArrowInput3", "ArrowInput4", "ArrowInput5" }; public override void OnEnter() { base.OnEnter(); EntityStateMachine[] components = base.characterBody.gameObject.GetComponents(); foreach (EntityStateMachine entityStateMachine in components) { if (entityStateMachine.customName == "Body") { bodyStateMachine = entityStateMachine; } } bodyStateMachine.SetNextState(new Idle()); explosionHealingMod = base.characterBody.maxHealth; if (explosionHealingMod < base.characterBody.baseMaxHealth) { explosionHealingMod = base.characterBody.baseMaxHealth; } base.healthComponent.AddBarrierAuthority(explosionHealingMod * startingOverShieldPercentage); seekerController = base.characterBody.transform.GetComponent(); if (base.isAuthority) { seekerController.RandomizeMeditationInputs(); } SmallHop(base.characterMotor, smallHopVelocity); if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = 0f; } if ((bool)base.characterBody) { base.characterBody.isSprinting = false; } if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } PlayAnimation("FullBody, Override", "MeditationStart", "Meditation.playbackRate", animDuration); characterGravityParameterProvider = base.gameObject.GetComponent(); if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount++; characterGravityParameterProvider.gravityParameters = gravityParameters; } overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams { prefab = scopeOverlayPrefab, childLocatorEntry = "CrosshairExtras" }); overlayController.onInstanceAdded += OnOverlayInstanceAdded; overlayController.onInstanceRemove += OnOverlayInstanceRemoved; crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); CameraTargetParams component = base.gameObject.GetComponent(); if ((bool)component) { aimRequest = component.RequestAimType(CameraTargetParams.AimType.ZoomedOut); } startingYaw = base.characterDirection.yaw; Util.PlaySound(startSoundString, base.gameObject); } public override void Update() { if (seekerController.meditationUIDirty) { seekerController.meditationUIDirty = false; UpdateUIInputSequence(); } base.characterDirection.yaw = startingYaw; base.characterDirection.moveVector = base.characterDirection.forward; base.Update(); if (meditationWrapUp) { wrapUpTimer += Time.deltaTime; if (wrapUpTimer > wrapUpDuration) { outer.SetNextStateToMain(); } if (!wrapUpAnimationPlayed) { wrapUpAnimationPlayed = true; if (meditationSuccess) { PlayAnimation("FullBody, Override", "MeditationSuccess", "Meditation.playbackRate", animDuration); Util.PlaySound(successSoundString, base.gameObject); lotus.GetComponentInChildren().Play("MeditationSuccess"); EffectManager.SpawnEffect(successEffectPrefab, new EffectData { origin = base.characterBody.corePosition }, transmit: true); if (base.isAuthority) { float num = 0f; float num2 = 0f; seekerController.IncrementChakraGate(); if (base.characterBody.HasBuff(DLC2Content.Buffs.ChakraBuff)) { num2 = base.characterBody.GetBuffCount(DLC2Content.Buffs.ChakraBuff); num = num2 * percentPerGate; } seekerController.CallCmdTriggerHealPulse((healingExplosionAmount * num2 + 0.04f) * explosionHealingMod, base.characterBody.corePosition, blastRadius); BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.characterBody.gameObject; blastAttack.baseDamage = (damageCoefficient + num) * base.characterBody.damage; blastAttack.baseForce = blastForce; blastAttack.bonusForce = blastBonusForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = base.characterBody.RollCrit(); blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.inflictor = base.gameObject; blastAttack.position = base.characterBody.corePosition; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = blastProcCoefficient; blastAttack.radius = blastRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.teamIndex = base.teamComponent.teamIndex; blastAttack.Fire(); } } else { PlayAnimation("FullBody, Override", "MeditationFail", "Meditation.playbackRate", animDuration); Util.PlaySound(timeoutSoundString, base.gameObject); lotus.GetComponentInChildren().Play("MeditationFail"); outer.SetNextStateToMain(); } } } int num3 = -1; if (base.inputBank.rawMoveUp.justPressed) { num3 = 0; } if (base.inputBank.rawMoveDown.justPressed) { num3 = 1; } if (base.inputBank.rawMoveRight.justPressed) { num3 = 2; } if (base.inputBank.rawMoveLeft.justPressed) { num3 = 3; } if (seekerController.meditationInputStep > 4) { meditationSuccess = true; meditationWrapUp = true; } if (num3 == seekerController.GetNextMeditationStep()) { if (!wrapUpAnimationPlayed && seekerController.meditationInputStep < 5) { Util.PlaySound(inputCorrectSoundString, base.gameObject); seekerController.meditationInputStep++; } } else if (num3 != -1) { Util.PlaySound(inputFailSoundString, base.gameObject); base.fixedAge += timePenalty; } if (base.fixedAge > 0.4f) { base.characterMotor.velocity = new UnityEngine.Vector3(0f, 0f, 0f); if (base.inputBank.skill4.justPressed) { meditationWrapUp = true; } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform && !spawnedLotus) { spawnedLotus = true; lotusChildLocator = modelTransform.GetComponent(); lotus = UnityEngine.Object.Instantiate(lotusPrefab, lotusChildLocator.FindChild("Lotus"), worldPositionStays: false); } } if (base.fixedAge > duration) { failed = true; meditationWrapUp = true; } else { UpdateUI(); } } private void SetupInputUIIcons() { for (int i = 0; i < 5; i++) { switch (seekerController.meditationStepAndSequence[i + 1]) { case 0: overlayInstanceChildLocator.FindChild(c[i]).GetComponent().rotation = UnityEngine.Quaternion.Euler(0f, 0f, 0f); break; case 1: overlayInstanceChildLocator.FindChild(c[i]).GetComponent().rotation = UnityEngine.Quaternion.Euler(0f, 0f, -180f); break; case 2: overlayInstanceChildLocator.FindChild(c[i]).GetComponent().rotation = UnityEngine.Quaternion.Euler(0f, 0f, -90f); break; case 3: overlayInstanceChildLocator.FindChild(c[i]).GetComponent().rotation = UnityEngine.Quaternion.Euler(0f, 0f, -270f); break; } } UpdateUIInputSequence(); } private void UpdateUIInputSequence() { if (base.isAuthority) { Color32 color = new Color32(byte.MaxValue, 233, 124, byte.MaxValue); for (int i = 0; i < seekerController.meditationInputStep; i++) { overlayInstanceChildLocator.FindChild(c[i]).GetComponent().color = color; } } } private void UpdateUI() { foreach (ImageFillController fillUi in fillUiList) { fillUi.SetTValue(base.fixedAge / duration); } } public override void OnExit() { PlayAnimation("FullBody, Override", "Empty"); Util.PlaySound(stopSoundString, base.gameObject); if (overlayController != null) { HudOverlayManager.RemoveOverlay(overlayController); overlayController = null; } aimRequest?.Dispose(); crosshairOverrideRequest?.Dispose(); if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount--; characterGravityParameterProvider.gravityParameters = gravityParameters; } if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = 1f; } if ((bool)lotus) { lotus.GetComponent().duration = 0.01f; } if (failed) { base.skillLocator.special.temporaryCooldownPenalty += failureCooldownPenalty; } bodyStateMachine.SetNextStateToMain(); base.OnExit(); } private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance) { fillUiList.Add(instance.GetComponent()); overlayInstanceChildLocator = instance.GetComponent(); SetupInputUIIcons(); } private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance) { fillUiList.Remove(instance.GetComponent()); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SeekerInitialWeaponState : BaseState { public override void OnEnter() { base.OnEnter(); GenericSkill genericSkill = base.skillLocator.FindSkillByFamilyName("SeekerBodyPrimaryFamily"); if (genericSkill == null) { outer.SetNextStateToMain(); return; } SeekerWeaponSkillDef seekerWeaponSkillDef = genericSkill.skillDef as SeekerWeaponSkillDef; if (seekerWeaponSkillDef == null) { outer.SetNextStateToMain(); return; } HandleCrosshair(seekerWeaponSkillDef); HandleTargetTracking(seekerWeaponSkillDef); outer.SetNextStateToMain(); } private void HandleTargetTracking(SeekerWeaponSkillDef seekerWeapon) { HuntressTracker component = GetComponent(); if (!(component == null)) { component.enabled = seekerWeapon.targetTrackingIndicator; } } private void HandleCrosshair(SeekerWeaponSkillDef seekerWeapon) { CrosshairUtils.RequestOverrideForBody(base.characterBody, seekerWeapon.crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } } public class Sojourn : BaseState { [SerializeField] public GameObject vehiclePrefab; public static float smallHopVelocity; public static UnityEngine.Color screenDamageColor; public static bool combineTintAdditively; public static float minimumDamageStrength; public static float maximumDamageStrength; public static float pulseDuration; private SeekerController seekerController; public float duration = 0.3f; private bool animFinished; private ScreenDamageCalculatorSojourn screenDamageCalculator; public override void OnEnter() { if (NetworkServer.active) { base.characterBody.AddBuff(DLC2Content.Buffs.SojournVehicle); } screenDamageCalculator = new ScreenDamageCalculatorSojourn(); screenDamageCalculator.minimumDamage = minimumDamageStrength; screenDamageCalculator.maximumDamage = maximumDamageStrength; screenDamageCalculator.duration = pulseDuration; ScreenDamageData screenDamageData = screenDamageCalculator.screenDamageData; screenDamageData.IntendedTintColor = screenDamageColor; screenDamageData.combineAdditively = combineTintAdditively; base.characterBody.healthComponent.screenDamageCalculator = screenDamageCalculator; seekerController = base.characterBody.transform.GetComponent(); seekerController.doesExitVehicle = false; SmallHop(base.characterMotor, smallHopVelocity); PlayAnimation("Gesture, Override", "SojournEnterTransform"); base.fixedAge = 0f; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration && !animFinished) { if (NetworkServer.active) { Ray aimRay = GetAimRay(); GameObject gameObject = UnityEngine.Object.Instantiate(vehiclePrefab, aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction)); gameObject.GetComponent().sojournState = this; gameObject.GetComponent().AssignPassenger(base.gameObject); NetworkUser networkUser = base.characterBody?.master?.playerCharacterMasterController?.networkUser; if ((bool)networkUser) { NetworkServer.SpawnWithClientAuthority(gameObject, networkUser.gameObject); } else { NetworkServer.Spawn(gameObject); } } animFinished = true; } if (seekerController.doesExitVehicle) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Vehicle; } public override void OnExit() { PlayAnimation("Gesture, Override", "SojournExitTransformation"); if (screenDamageCalculator != null) { screenDamageCalculator.End(); } base.characterBody.healthComponent.screenDamageCalculator = null; if (!NetworkServer.active) { return; } base.characterBody.RemoveBuff(DLC2Content.Buffs.SojournVehicle); if (base.characterBody.HasBuff(DLC2Content.Buffs.SojournHealing)) { float num = base.characterBody.GetBuffCount(DLC2Content.Buffs.SojournHealing); for (int i = 0; (float)i < num; i++) { base.characterBody.RemoveBuff(DLC2Content.Buffs.SojournHealing); } } } } public class SoulSearch : BaseState, SteppedSkillDef.IStepSetter { public enum Gauntlet { Left, Right } [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float procCoefficient; [SerializeField] public float damageCoefficient; [SerializeField] public float force = 20f; public static float attackSpeedAltAnimationThreshold; [SerializeField] public float baseDuration; [SerializeField] public string attackSoundString; [SerializeField] public float attackSoundPitch; public static float bloom; [SerializeField] public GameObject blastEffectPrefab; [SerializeField] public GameObject blastImpactEffectPrefab; [SerializeField] public float blastRadius; [SerializeField] public float blastDamageCoefficient; [SerializeField] public float blastForce; [SerializeField] public UnityEngine.Vector3 blastBonusForce; [SerializeField] public float blastProcCoefficient; private float duration; private bool hasFiredGauntlet; private string muzzleString; private Transform muzzleTransform; private Animator animator; private ChildLocator childLocator; private Gauntlet gauntlet; private HuntressTracker huntressTracker; public void SetStep(int i) { gauntlet = (Gauntlet)i; } public override void OnEnter() { base.OnEnter(); huntressTracker = base.characterBody.GetComponent(); if (!huntressTracker.GetTrackingTarget()) { outer.SetNextStateToMain(); return; } duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch); base.characterBody.SetAimTimer(2f); animator = GetModelAnimator(); if ((bool)animator) { childLocator = animator.GetComponent(); } switch (gauntlet) { case Gauntlet.Left: muzzleString = "MuzzleLeft"; PlayCrossfade("Gesture, Additive", "Cast1Left", "FireGauntlet.playbackRate", duration, 0.1f); PlayCrossfade("Gesture, Override", "Cast1Left", "FireGauntlet.playbackRate", duration, 0.1f); break; case Gauntlet.Right: muzzleString = "MuzzleRight"; PlayCrossfade("Gesture, Additive", "Cast1Right", "FireGauntlet.playbackRate", duration, 0.1f); PlayCrossfade("Gesture, Override", "Cast1Right", "FireGauntlet.playbackRate", duration, 0.1f); break; } } public override void OnExit() { base.OnExit(); } private void FireGauntlet() { if (!hasFiredGauntlet) { base.characterBody.AddSpreadBloom(bloom); Ray aimRay = GetAimRay(); if ((bool)childLocator) { muzzleTransform = childLocator.FindChild(muzzleString); } if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (projectilePrefab != null && base.isAuthority) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = muzzleTransform.position; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(aimRay.direction); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration || hasFiredGauntlet) { if (!hasFiredGauntlet && (bool)huntressTracker.GetTrackingTarget()) { FireGauntlet(); hasFiredGauntlet = true; } if (base.isAuthority) { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)gauntlet); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); gauntlet = (Gauntlet)reader.ReadByte(); } } public class SoulSpiral : BaseState { public static string prepOrbSoundString; public static float duration; public static float dmgCoefficient; public static GameObject projectilePrefab; public static GameObject muzzleFXPrefab; public static string muzzleChildName; public static float projectileForce; public static float smallHopVelocity; public bool firedOrb; private EffectData effectData; public override void OnEnter() { base.OnEnter(); if ((bool)base.modelLocator) { ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if ((bool)component) { int childIndex = component.FindChildIndex(muzzleChildName); effectData = new EffectData(); effectData.SetChildLocatorTransformReference(base.characterBody.gameObject, childIndex); } } PlayAnimation("Gesture, Additive", "SoulSpiralStart", "PrepUnseenHand.playbackRate", duration); PlayAnimation("Gesture, Override", "SoulSpiralStart", "PrepUnseenHand.playbackRate", duration); } public override void FixedUpdate() { base.FixedUpdate(); if (!firedOrb && base.fixedAge > duration && base.isAuthority) { FireSpiral(); outer.SetNextStateToMain(); } } private void FireSpiral() { firedOrb = true; Util.PlaySound(prepOrbSoundString, base.gameObject); effectData.origin = base.characterBody.corePosition; effectData.rotation = UnityEngine.Quaternion.identity; EffectManager.SpawnEffect(muzzleFXPrefab, effectData, transmit: false); if (base.isAuthority) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * dmgCoefficient; fireProjectileInfo.force = projectileForce; fireProjectileInfo.position = base.characterBody.corePosition; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); FireProjectileInfo projectileInfo = fireProjectileInfo; base.characterBody.GetComponent().FireSoulSpiral(projectileInfo); } } public override void OnExit() { base.OnExit(); if (!firedOrb && !ObjectIsBeingDestroyed()) { FireSpiral(); } if ((bool)base.characterMotor && !base.isGrounded) { base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, Mathf.Max(base.characterMotor.velocity.y, smallHopVelocity), base.characterMotor.velocity.z); } } private bool ObjectIsBeingDestroyed() { GameObject gameObject = base.characterBody.gameObject; if (!(gameObject == null)) { if (!gameObject.activeSelf) { return gameObject.activeInHierarchy; } return false; } return true; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } } public class SpiritPunch : BaseState, SteppedSkillDef.IStepSetter { public enum Gauntlet { Left, Right, Explode } [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject projectileFinisherPrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float procCoefficient; [SerializeField] public float damageCoefficient; [SerializeField] public float dmgBuffIncrease = 0.2f; [SerializeField] public float comboDamageCoefficient; [SerializeField] public float force = 20f; public static float attackSpeedAltAnimationThreshold; [SerializeField] public float baseDuration; [SerializeField] public float paddingBetweenAttacks = 0.2f; [SerializeField] public string attackSoundString; [SerializeField] public string attackSoundStringAlt; [SerializeField] public float attackSoundPitch; [SerializeField] public float bloom; private float duration; private bool hasFiredGauntlet; private string muzzleString; private Transform muzzleTransform; private Animator animator; private ChildLocator childLocator; private Gauntlet gauntlet; private float extraDmgFromBuff; public static float recoilAmplitude; private string animationStateName; public static event Action onSpiritOrbFired; public void SetStep(int i) { gauntlet = (Gauntlet)i; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; base.characterBody.SetAimTimer(2f); animator = GetModelAnimator(); if ((bool)animator) { childLocator = animator.GetComponent(); } switch (gauntlet) { case Gauntlet.Left: muzzleString = "MuzzleLeft"; animationStateName = "Cast1Left"; break; case Gauntlet.Right: muzzleString = "MuzzleRight"; animationStateName = "Cast1Right"; break; case Gauntlet.Explode: muzzleString = "MuzzleEnergyBomb"; animationStateName = "SpiritPunchFinisher"; extraDmgFromBuff = dmgBuffIncrease * (float)base.characterBody.GetBuffCount(DLC2Content.Buffs.ChakraBuff); break; } bool @bool = animator.GetBool("isMoving"); bool bool2 = animator.GetBool("isGrounded"); if (!@bool && bool2) { PlayCrossfade("FullBody, Override", animationStateName, "FireGauntlet.playbackRate", duration, 0.025f); return; } PlayCrossfade("Gesture, Additive", animationStateName, "FireGauntlet.playbackRate", duration, 0.025f); PlayCrossfade("Gesture, Override", animationStateName, "FireGauntlet.playbackRate", duration, 0.025f); } public override void OnExit() { base.OnExit(); } private void FireGauntlet() { if (!hasFiredGauntlet) { base.characterBody.AddSpreadBloom(bloom); Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); if ((bool)childLocator) { muzzleTransform = childLocator.FindChild(muzzleString); } if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (base.isAuthority) { float damage = damageStat * (damageCoefficient + extraDmgFromBuff); ProjectileManager.instance.FireProjectile(projectilePrefab, muzzleTransform.position, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damage, force, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, 70f + attackSpeedStat * 2f); } AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration - duration * 0.25f || hasFiredGauntlet) { if (gauntlet == Gauntlet.Explode && !hasFiredGauntlet) { Util.PlayAttackSpeedSound(attackSoundStringAlt, base.gameObject, attackSoundPitch); projectilePrefab = projectileFinisherPrefab; damageCoefficient = comboDamageCoefficient; FireGauntlet(); SpiritPunch.onSpiritOrbFired?.Invoke(obj: true); _ = base.characterMotor.isGrounded; hasFiredGauntlet = true; } else if (!hasFiredGauntlet) { Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch); FireGauntlet(); hasFiredGauntlet = true; SpiritPunch.onSpiritOrbFired?.Invoke(obj: false); } if (base.isAuthority && base.fixedAge >= duration + duration * paddingBetweenAttacks) { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)gauntlet); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); gauntlet = (Gauntlet)reader.ReadByte(); } } public class UnseenHand : BaseState { public static float baseDuration; public static GameObject areaIndicatorPrefab; public static GameObject projectilePrefab; public static GameObject muzzleflashEffect; public static GameObject goodCrosshairPrefab; public static GameObject badCrosshairPrefab; public static string prepFistSoundString; public static string endFistSoundString; public static string startTargetingLoopSoundString; public static string stopTargetingLoopSoundString; public static float maxDistance; public static string fireSoundString; public static float maxSlopeAngle; public static GameObject initialEffect; public static GameObject muzzleFlashEffect; public static GameObject fistProjectilePrefab; public static float fistDamageCoefficient; public static float fistForce; public static float fuseOverride; public static int abilityAimType; public static float cameraTransitionOutTime; public static float smallHopVelocity; private float duration; private float stopwatch; private bool goodPlacement; private GameObject areaIndicatorInstance; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; protected CameraTargetParams.AimRequest aimRequest; private bool cameraStarted; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; base.characterBody.SetAimTimer(duration + 2f); PlayAnimation("Gesture, Additive", "UnseenHandPrep", "PrepUnseenHand.playbackRate", duration); PlayAnimation("Gesture, Override", "UnseenHandPrep", "PrepUnseenHand.playbackRate", duration); Util.PlaySound(prepFistSoundString, base.gameObject); Util.PlaySound(startTargetingLoopSoundString, base.gameObject); areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab); UpdateAreaIndicator(); } private void UpdateAreaIndicator() { bool flag = goodPlacement; goodPlacement = false; areaIndicatorInstance.SetActive(value: true); if ((bool)areaIndicatorInstance) { float num = maxDistance; float extraRaycastDistance = 0f; if (Physics.Raycast(CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance), out var hitInfo, num + extraRaycastDistance, LayerIndex.world.mask)) { areaIndicatorInstance.transform.position = hitInfo.point; goodPlacement = UnityEngine.Vector3.Angle(UnityEngine.Vector3.up, hitInfo.normal) < maxSlopeAngle; } if (flag != goodPlacement || crosshairOverrideRequest == null) { crosshairOverrideRequest?.Dispose(); GameObject crosshairPrefab = (goodPlacement ? goodCrosshairPrefab : badCrosshairPrefab); crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill); } } areaIndicatorInstance.SetActive(goodPlacement); } public override void Update() { base.Update(); UpdateAreaIndicator(); } public override void FixedUpdate() { base.FixedUpdate(); if (!cameraStarted && base.fixedAge > 0.1f) { if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType((CameraTargetParams.AimType)abilityAimType); } cameraStarted = true; } if (base.inputBank.skill2.down || !base.isAuthority) { return; } if (goodPlacement) { PlayAnimation("Gesture, Additive", "UnseenHandFinish"); PlayAnimation("Gesture, Override", "UnseenHandFinish"); Util.PlaySound(fireSoundString, base.gameObject); if ((bool)areaIndicatorInstance) { EffectManager.SpawnEffect(muzzleFlashEffect, new EffectData { origin = areaIndicatorInstance.transform.position }, transmit: true); if (base.isAuthority) { EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleLeft", transmit: true); EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleRight", transmit: true); UnityEngine.Vector3 forward = areaIndicatorInstance.transform.forward; forward.y = 0f; forward.Normalize(); UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, forward); Util.CheckRoll(critStat, base.characterBody.master); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = fistProjectilePrefab; fireProjectileInfo.position = areaIndicatorInstance.transform.position; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * fistDamageCoefficient; fireProjectileInfo.damageTypeOverride = DamageType.Stun1s; fireProjectileInfo.force = fistForce; fireProjectileInfo.crit = base.characterBody.RollCrit(); fireProjectileInfo.fuseOverride = fuseOverride; ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } } else { base.skillLocator.secondary.AddOneStock(); PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.2f); PlayCrossfade("Gesture, Override", "BufferEmpty", 0.2f); } outer.SetNextStateToMain(); } public override void OnExit() { if (goodPlacement) { if (!base.isGrounded) { base.characterMotor.velocity.y = Mathf.Max(base.characterMotor.velocity.y, smallHopVelocity); } if (base.characterBody.isServer) { CharacterBody obj = base.characterBody; if ((object)obj != null && obj.inventory.GetItemCount(DLC2Content.Items.IncreasePrimaryDamage) > 0) { base.characterBody.AddIncreasePrimaryDamageStack(); } } } Util.PlaySound(endFistSoundString, base.gameObject); Util.PlaySound(stopTargetingLoopSoundString, base.gameObject); EntityState.Destroy(areaIndicatorInstance.gameObject); crosshairOverrideRequest?.Dispose(); aimRequest?.Dispose(); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } } namespace EntityStates.Scrapper { public class ScrapperBaseState : BaseState { protected PickupPickerController pickupPickerController; protected ScrapperController scrapperController; protected virtual bool enableInteraction => true; public override void OnEnter() { base.OnEnter(); pickupPickerController = GetComponent(); scrapperController = GetComponent(); pickupPickerController.SetAvailable(enableInteraction); } } public class WaitToBeginScrapping : ScrapperBaseState { public static float duration; protected override bool enableInteraction => false; public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new Scrapping()); } } } public class Scrapping : ScrapperBaseState { public static string enterSoundString; public static string exitSoundString; public static float duration; private static int ScrappingStateHash = Animator.StringToHash("Scrapping"); private static int ScrappingParamHash = Animator.StringToHash("Scrapping.playbackRate"); protected override bool enableInteraction => false; public override void OnEnter() { base.OnEnter(); FindModelChild("ScrappingEffect").gameObject.SetActive(value: true); Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation("Base", ScrappingStateHash, ScrappingParamHash, duration); } public override void OnExit() { FindModelChild("ScrappingEffect").gameObject.SetActive(value: false); Util.PlaySound(exitSoundString, base.gameObject); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new ScrappingToIdle()); } } } public class ScrappingToIdle : ScrapperBaseState { public static string enterSoundString; public static string exitSoundString; public static float duration; public static float dropUpVelocityStrength; public static float dropForwardVelocityStrength; public static GameObject muzzleflashEffectPrefab; public static string muzzleString; private bool foundValidScrap; private static int ScrappingToIdleStateHash = Animator.StringToHash("ScrappingToIdle"); private static int ScrappingParamHash = Animator.StringToHash("Scrapping.playbackRate"); protected override bool enableInteraction => false; public override void OnEnter() { base.OnEnter(); Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation("Base", ScrappingToIdleStateHash, ScrappingParamHash, duration); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (NetworkServer.active) { foundValidScrap = false; PickupIndex none = PickupIndex.none; none = PickupCatalog.FindScrapIndexForItemTier(ItemCatalog.GetItemDef(scrapperController.lastScrappedItemIndex).tier); if (none != PickupIndex.none) { foundValidScrap = true; Transform transform = FindModelChild(muzzleString); PickupDropletController.CreatePickupDroplet(none, transform.position, UnityEngine.Vector3.up * dropUpVelocityStrength + transform.forward * dropForwardVelocityStrength); scrapperController.itemsEaten--; } } } public override void OnExit() { Util.PlaySound(exitSoundString, base.gameObject); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (foundValidScrap && scrapperController.itemsEaten > 0 && base.fixedAge > duration / 2f) { outer.SetNextState(new ScrappingToIdle()); } else if (base.fixedAge > duration) { outer.SetNextState(new Idle()); } } } public class Idle : ScrapperBaseState { protected override bool enableInteraction => true; } } namespace EntityStates.Scorchling { public class DeathState : GenericCharacterDeath { public static GameObject deathExplosion; public static string deathSoundString; public static string stopBurrowLoopString; public static float animDuration = 1f; public static float cleanUpDuration = 0.3f; public static float printDuration; private bool burrowed; protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayAnimation("FullBody, Override", "Burrow", "Burrow.playbackRate", animDuration); } public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { PrintController printController = modelTransform.gameObject.AddComponent(); printController.printTime = printDuration; printController.enabled = true; printController.startingPrintHeight = 99999f; printController.maxPrintHeight = 99999f; printController.startingPrintBias = 1f; printController.maxPrintBias = 3.5f; printController.animateFlowmapPower = true; printController.startingFlowmapPower = 1.14f; printController.maxFlowmapPower = 30f; printController.disableWhenFinished = false; printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); } cleanUpDuration += animDuration; Util.PlaySound(deathSoundString, base.gameObject); Util.PlaySound(stopBurrowLoopString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (!burrowed && base.fixedAge >= animDuration) { EffectManager.SpawnEffect(deathExplosion, new EffectData { origin = base.characterBody.corePosition, scale = 4f }, transmit: true); burrowed = true; } if (base.fixedAge >= cleanUpDuration) { DestroyModel(); if (NetworkServer.active) { DestroyBodyAsapServer(); } } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class ScorchlingBreach : BaseState { [SerializeField] [Header("Timing")] public float crackToBreachTime = 1f; [SerializeField] public float breachToBurrow = 5f; [SerializeField] public float burrowToEndOfTime = 1f; [SerializeField] public float animDuration = 1f; [Header("Explosion Attr")] [SerializeField] public float blastProcCoefficient; [SerializeField] public float blastDamageCoefficient; [SerializeField] public float blastForce; [SerializeField] public UnityEngine.Vector3 blastBonusForce; [SerializeField] public float knockbackForce; [Header("FX Objects")] [SerializeField] public GameObject crackEffectPrefab; [SerializeField] public float crackRadius = 1f; [SerializeField] public GameObject blastEffectPrefab; [SerializeField] public GameObject blastImpactEffectPrefab; [SerializeField] public float blastRadius = 1f; [SerializeField] public GameObject burrowEffectPrefab; [SerializeField] public float burrowRadius = 1f; [Header("Sound Strings")] [SerializeField] public string preBreachSoundString; [SerializeField] public string breachSoundString; [SerializeField] public string burrowSoundString; [SerializeField] public string burrowLoopSoundString; [SerializeField] public string burrowStopLoopSoundString; public bool proceedImmediatelyToLavaBomb; private bool breached; private bool burrowed; private bool amServer; private UnityEngine.Vector3 breachPosition; private ScorchlingController scorchlingController; private CharacterBody enemyCBody; public override void OnEnter() { base.OnEnter(); amServer = NetworkServer.active; scorchlingController = base.characterBody.GetComponent(); Util.PlaySound(preBreachSoundString, base.gameObject); if (amServer) { enemyCBody = base.characterBody.master.GetComponent().currentEnemy?.characterBody; if (proceedImmediatelyToLavaBomb) { breachToBurrow = 1f; } breachToBurrow += crackToBreachTime; burrowToEndOfTime += breachToBurrow; breachPosition = base.characterBody.footPosition; if (!proceedImmediatelyToLavaBomb && (bool)enemyCBody) { breachPosition = enemyCBody.footPosition; } if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = 0f; } base.characterBody.SetAimTimer(breachToBurrow); TeleportHelper.TeleportBody(base.characterBody, breachPosition); EffectManager.SpawnEffect(crackEffectPrefab, new EffectData { origin = breachPosition, scale = crackRadius }, transmit: true); scorchlingController.SetTeleportPermission(b: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (amServer && base.fixedAge < crackToBreachTime && enemyCBody != null) { UnityEngine.Vector3 normalized = (enemyCBody.corePosition - base.characterBody.corePosition).normalized; base.characterBody.characterDirection.forward = normalized; } if (!breached && base.fixedAge > crackToBreachTime) { breached = true; scorchlingController.Breach(); PlayAnimation("FullBody, Override", "Breach", "Breach.playbackRate", animDuration); Util.PlaySound(breachSoundString, base.gameObject); Util.PlaySound(burrowStopLoopSoundString, base.gameObject); if (amServer) { DetonateAuthority(); } } if (base.fixedAge > burrowToEndOfTime) { DoExit(); } } private void DoExit() { if (proceedImmediatelyToLavaBomb) { outer.SetNextState(new ScorchlingLavaBomb()); } else { outer.SetNextStateToMain(); } } protected BlastAttack.Result DetonateAuthority() { EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = breachPosition, scale = blastRadius }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * blastDamageCoefficient, baseForce = blastForce, bonusForce = blastBonusForce, crit = RollCrit(), damageType = DamageType.Stun1s, falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius, position = breachPosition, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } public override void OnExit() { base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { if (proceedImmediatelyToLavaBomb) { return InterruptPriority.Frozen; } return InterruptPriority.PrioritySkill; } } public class ScorchlingEnsureBurrow : BaseState { [SerializeField] public string burrowSoundString; [SerializeField] public string burrowLoopSoundString; [SerializeField] public string burrowStopLoopSoundString; [SerializeField] public GameObject burrowEffectPrefab; [SerializeField] public float burrowRadius = 1f; [SerializeField] public float animDurationBurrow = 1f; [SerializeField] public float burrowAnimationDuration = 1f; private ScorchlingController sController; private bool waitingForBurrow; public override void OnEnter() { base.OnEnter(); sController = base.characterBody.GetComponent(); if (!sController.isBurrowed) { Util.PlaySound(burrowSoundString, base.gameObject); Util.PlaySound(burrowLoopSoundString, base.gameObject); EffectManager.SpawnEffect(burrowEffectPrefab, new EffectData { origin = base.characterBody.footPosition, scale = burrowRadius }, transmit: true); PlayAnimation("FullBody, Override", "Burrow", "Burrow.playbackRate", animDurationBurrow); if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = 0f; } if ((bool)base.characterBody) { base.characterBody.isSprinting = false; } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } waitingForBurrow = true; } } public override void Update() { base.Update(); HandleWaitForBurrow(); } public override void OnExit() { base.OnExit(); HandleWaitForBurrow(); } private void HandleWaitForBurrow() { if (waitingForBurrow && base.age > burrowAnimationDuration) { sController.Burrow(); waitingForBurrow = false; } } public override InterruptPriority GetMinimumInterruptPriority() { if (waitingForBurrow) { return InterruptPriority.Frozen; } return InterruptPriority.Skill; } } public class ScorchlingLavaBomb : BaseState { [SerializeField] [Header("Timing")] public float breachToSpitTime = 1f; [SerializeField] public float spitToLaunchTime = 0.3f; [SerializeField] public float spitToBurrowTime = 5f; [SerializeField] public float burrowToEndOfTime = 1f; [SerializeField] public float animDurationBreach = 1f; [SerializeField] public float animDurationSpit = 1f; [SerializeField] public float animDurationBurrow = 1f; [SerializeField] public float animDurationPostSpit = 0.75f; [SerializeField] public float percentageToFireProjectile = 0.75f; [SerializeField] [Header("FX Objects")] public GameObject burrowEffectPrefab; [SerializeField] public float burrowRadius = 1f; [Header("Sound Strings")] [SerializeField] public string breachSoundString; [SerializeField] public string spitSoundString; [SerializeField] public string burrowSoundString; [SerializeField] public string burrowLoopSoundString; [SerializeField] public string burrowStopLoopSoundString; [Header("Lava Bomb Projectile")] public static GameObject mortarProjectilePrefab; public static GameObject mortarMuzzleflashEffect; public static int mortarCount; public static string mortarMuzzleName; public static string mortarSoundString; public static float mortarDamageCoefficient; public static float timeToTarget = 3f; public static float projectileVelocity = 55f; public static float minimumDistance; private bool spitStarted; private bool firedProjectile; private bool earlyExit; private ScorchlingController sController; public override void OnEnter() { base.OnEnter(); sController = base.characterBody.GetComponent(); animDurationBreach = (sController.isBurrowed ? animDurationBreach : 0f); spitToBurrowTime += animDurationBreach + animDurationSpit; burrowToEndOfTime += spitToBurrowTime; if (sController.isBurrowed) { earlyExit = true; if (Util.HasEffectiveAuthority(base.characterBody.networkIdentity)) { outer.SetNextState(new ScorchlingBreach { proceedImmediatelyToLavaBomb = true, breachToBurrow = breachToSpitTime }); } } else { base.characterBody.SetAimTimer(burrowToEndOfTime); } } public override void FixedUpdate() { if (earlyExit) { return; } base.FixedUpdate(); if (!spitStarted && base.fixedAge > animDurationBreach) { spitStarted = true; PlayAnimation("FullBody, Override", "Spit", "Spit.playbackRate", animDurationSpit); } if (spitStarted && !firedProjectile && base.fixedAge > animDurationSpit * percentageToFireProjectile + animDurationBreach) { firedProjectile = true; Util.PlaySound(spitSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(mortarMuzzleflashEffect, base.gameObject, mortarMuzzleName, transmit: false); if (base.isAuthority) { Spit(); } } if (firedProjectile && base.fixedAge > animDurationBreach + animDurationSpit + animDurationPostSpit) { outer.SetNextStateToMain(); } } public void Spit() { Transform transform = base.characterBody.modelLocator.modelTransform.GetComponent().FindChild("MuzzleFire"); Ray ray = new Ray(transform.position, transform.forward); Ray ray2 = new Ray(ray.origin, UnityEngine.Vector3.up); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = ray.origin; bullseyeSearch.searchDirection = ray.direction; bullseyeSearch.filterByLoS = false; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.RefreshCandidates(); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); bool flag = false; UnityEngine.Vector3 vector = UnityEngine.Vector3.zero; RaycastHit hitInfo; if ((bool)hurtBox) { vector = hurtBox.transform.position; flag = true; } else if (Physics.Raycast(ray, out hitInfo, 1000f, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) { vector = hitInfo.point; flag = true; } float magnitude = projectileVelocity; if (flag) { UnityEngine.Vector3 vector2 = vector - ray2.origin; UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z); float magnitude2 = vector3.magnitude; UnityEngine.Vector2 vector4 = vector3 / magnitude2; if (magnitude2 < minimumDistance) { magnitude2 = minimumDistance; } float y = Trajectory.CalculateInitialYSpeed(timeToTarget, vector2.y); float num = magnitude2 / timeToTarget; UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector4.x * num, y, vector4.y * num); magnitude = direction.magnitude; ray2.direction = direction; } UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(ray2.direction); ProjectileManager.instance.FireProjectile(mortarProjectilePrefab, ray2.origin, rotation, base.gameObject, damageStat * mortarDamageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude); } public override void OnExit() { base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : EntityState { public static float duration = 0.5f; public static string spawnSoundString; public static string burrowLoopSoundString; public override void OnEnter() { base.OnEnter(); Util.PlaySound(spawnSoundString, base.gameObject); Util.PlaySound(burrowLoopSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.ScavBackpack { public class Opening : EntityState { public static float duration = 1f; public static int maxItemDropCount; private ChestBehavior chestBehavior; private float itemDropCount; private float timeBetweenDrops; private float itemDropAge; private static int OpeningStateHash = Animator.StringToHash("Opening"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", OpeningStateHash); timeBetweenDrops = duration / (float)maxItemDropCount; chestBehavior = GetComponent(); if ((bool)base.sfxLocator) { Util.PlaySound(base.sfxLocator.openSound, base.gameObject); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { itemDropAge += GetDeltaTime(); if (itemDropCount < (float)maxItemDropCount && itemDropAge > timeBetweenDrops) { itemDropCount += 1f; itemDropAge -= timeBetweenDrops; chestBehavior.RollItem(); chestBehavior.ItemDrop(); } if (base.fixedAge >= duration) { outer.SetNextState(new Opened()); } } } } } namespace EntityStates.ScavMonster { public class Death : GenericCharacterDeath { [SerializeField] public SpawnCard spawnCard; public static float duration; private bool shouldDropPack; protected override bool shouldAutoDestroy => false; public override void OnEnter() { base.OnEnter(); if (!NetworkServer.active) { return; } CharacterMaster characterMaster = (base.characterBody ? base.characterBody.master : null); if ((bool)characterMaster) { bool flag = characterMaster.IsExtraLifePendingServer(); bool flag2 = characterMaster.inventory.GetItemCount(RoR2Content.Items.Ghost) > 0; bool flag3 = !Stage.instance || Stage.instance.scavPackDroppedServer; shouldDropPack = !flag && !flag2 && !flag3; if (shouldDropPack) { Stage.instance.scavPackDroppedServer = true; } } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { DestroyBodyAsapServer(); } } public override void OnExit() { DestroyModel(); base.OnExit(); } protected override void OnPreDestroyBodyServer() { base.OnPreDestroyBodyServer(); if (shouldDropPack) { AttemptDropPack(); } } private void AttemptDropPack() { DirectorCore instance = DirectorCore.instance; if ((bool)instance) { Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint); DirectorPlacementRule placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.NearestNode, position = base.characterBody.footPosition, minDistance = 0f, maxDistance = float.PositiveInfinity }; _ = (bool)instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, placementRule, rng)); } } } public class DeathLunar : Death { } public class EnergyCannonState : BaseState { public static string muzzleName; protected Transform muzzleTransform; public override void OnEnter() { base.OnEnter(); muzzleTransform = FindModelChild(muzzleName); } public override void FixedUpdate() { base.FixedUpdate(); } public override void OnExit() { base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class PrepEnergyCannon : EnergyCannonState { public static float baseDuration; public static string sound; public static GameObject chargeEffectPrefab; private GameObject chargeInstance; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayCrossfade("Body", "PrepEnergyCannon", "PrepEnergyCannon.playbackRate", duration, 0.1f); Util.PlaySound(sound, base.gameObject); if ((bool)muzzleTransform && (bool)chargeEffectPrefab) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation); chargeInstance.transform.parent = muzzleTransform; ScaleParticleSystemDuration component = chargeInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } public override void FixedUpdate() { base.FixedUpdate(); StartAimMode(0.5f); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new FireEnergyCannon()); } } public override void OnExit() { base.OnExit(); if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } } } public class FireEnergyCannon : EnergyCannonState { public static float baseDuration; public static float baseRefireDuration; public static string sound; public static GameObject effectPrefab; public static GameObject projectilePrefab; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static float recoilAmplitude = 1f; public static float projectilePitchBonus; public static float projectileYawBonusPerRefire; public static int projectileCount; public static int maxRefireCount; public int currentRefire; private float duration; private float refireDuration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; refireDuration = baseRefireDuration / attackSpeedStat; Util.PlayAttackSpeedSound(sound, base.gameObject, attackSpeedStat); PlayCrossfade("Body", "FireEnergyCannon", "FireEnergyCannon.playbackRate", duration, 0.1f); AddRecoil(-2f * recoilAmplitude, -3f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, EnergyCannonState.muzzleName, transmit: false); } if (base.isAuthority) { float num = ((currentRefire % 2 == 0) ? 1 : (-1)); float num2 = Mathf.Ceil((float)currentRefire / 2f) * projectileYawBonusPerRefire; for (int i = 0; i < projectileCount; i++) { Ray aimRay = GetAimRay(); aimRay.direction = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, num * num2, projectilePitchBonus); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= refireDuration && currentRefire + 1 < maxRefireCount && base.isAuthority) { FireEnergyCannon fireEnergyCannon = new FireEnergyCannon(); fireEnergyCannon.currentRefire = currentRefire + 1; outer.SetNextState(fireEnergyCannon); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class FindItem : BaseState { public static float baseDuration; public static float tier1Chance; public static int tier1Count; public static float tier2Chance; public static int tier2Count; public static float tier3Chance; public static int tier3Count; public static string sound; private float duration; private PickupIndex dropPickup; private int itemsToGrant; private PickupDisplay pickupDisplay; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayCrossfade("Body", "SitRummage", "Sit.playbackRate", duration, 0.1f); Util.PlaySound(sound, base.gameObject); if (base.isAuthority) { WeightedSelection> weightedSelection = new WeightedSelection>(); weightedSelection.AddChoice(Run.instance.availableTier1DropList.Where(PickupIsNonBlacklistedItem).ToList(), tier1Chance); weightedSelection.AddChoice(Run.instance.availableTier2DropList.Where(PickupIsNonBlacklistedItem).ToList(), tier2Chance); weightedSelection.AddChoice(Run.instance.availableTier3DropList.Where(PickupIsNonBlacklistedItem).ToList(), tier3Chance); List list = weightedSelection.Evaluate(UnityEngine.Random.value); dropPickup = list[UnityEngine.Random.Range(0, list.Count)]; PickupDef pickupDef = PickupCatalog.GetPickupDef(dropPickup); if (pickupDef != null) { ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex); if (itemDef != null) { itemsToGrant = 0; switch (itemDef.tier) { case ItemTier.Tier1: itemsToGrant = tier1Count; break; case ItemTier.Tier2: itemsToGrant = tier2Count; break; case ItemTier.Tier3: itemsToGrant = tier3Count; break; default: itemsToGrant = 1; break; } } } } Transform transform = FindModelChild("PickupDisplay"); pickupDisplay = transform.GetComponent(); pickupDisplay.SetPickupIndex(dropPickup); } public override void OnExit() { pickupDisplay.SetPickupIndex(PickupIndex.none); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new GrantItem { dropPickup = dropPickup, itemsToGrant = itemsToGrant }); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(dropPickup); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); dropPickup = reader.ReadPickupIndex(); } private bool PickupIsNonBlacklistedItem(PickupIndex pickupIndex) { PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef == null) { return false; } ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex); if (itemDef == null) { return false; } return itemDef.DoesNotContainTag(ItemTag.AIBlacklist); } } public class GrantItem : BaseState { public PickupIndex dropPickup; public int itemsToGrant; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { GrantPickupServer(dropPickup, itemsToGrant); } if (base.isAuthority) { outer.SetNextState(new ExitSit()); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(dropPickup); writer.WritePackedUInt32((uint)itemsToGrant); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); dropPickup = reader.ReadPickupIndex(); itemsToGrant = (int)reader.ReadPackedUInt32(); } private void GrantPickupServer(PickupIndex pickupIndex, int countToGrant) { PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef != null) { ItemIndex itemIndex = pickupDef.itemIndex; if (!(ItemCatalog.GetItemDef(itemIndex) == null)) { base.characterBody.inventory.GiveItem(itemIndex, countToGrant); Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage { subjectAsCharacterBody = base.characterBody, baseToken = "MONSTER_PICKUP", pickupToken = pickupDef.nameToken, pickupColor = pickupDef.baseColor, pickupQuantity = (uint)itemsToGrant }); } } } } public class BaseSitState : BaseState { public override void OnEnter() { base.OnEnter(); if (NetworkServer.active && (bool)base.characterBody) { base.characterBody.AddBuff(RoR2Content.Buffs.ArmorBoost); } } public override void OnExit() { if (NetworkServer.active && (bool)base.characterBody) { base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost); } base.OnExit(); } } public class EnterSit : BaseSitState { public static float baseDuration; public static string soundString; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(soundString, base.gameObject); PlayCrossfade("Body", "EnterSit", "Sit.playbackRate", duration, 0.1f); base.modelLocator.normalizeToFloor = true; base.modelLocator.modelTransform.GetComponent().enabled = true; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new FindItem()); } } } public class Sit : BaseSitState { public static string soundString; public static float minimumDuration; public override void OnEnter() { base.OnEnter(); PlayCrossfade("Body", "SitLoop", 0.1f); } public override void FixedUpdate() { base.FixedUpdate(); if (base.inputBank.moveVector.sqrMagnitude >= Mathf.Epsilon && base.fixedAge >= minimumDuration) { outer.SetNextState(new ExitSit()); } } } public class ExitSit : BaseSitState { public static float baseDuration; public static string soundString; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(soundString, base.gameObject); PlayCrossfade("Body", "ExitSit", "Sit.playbackRate", duration, 0.1f); base.modelLocator.normalizeToFloor = false; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } public class SackBaseState : BaseState { public static string muzzleName; protected Transform muzzleTransform; public override void OnEnter() { base.OnEnter(); muzzleTransform = FindModelChild(muzzleName); } public override void FixedUpdate() { base.FixedUpdate(); } public override void OnExit() { base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class PrepSack : SackBaseState { public static float baseDuration; public static string sound; public static GameObject chargeEffectPrefab; private GameObject chargeInstance; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayCrossfade("Body", "PrepSack", "PrepSack.playbackRate", duration, 0.1f); Util.PlaySound(sound, base.gameObject); StartAimMode(duration); if ((bool)muzzleTransform && (bool)chargeEffectPrefab) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation); chargeInstance.transform.parent = muzzleTransform; ScaleParticleSystemDuration component = chargeInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new ThrowSack()); } } public override void OnExit() { base.OnExit(); if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } } } public class ThrowSack : SackBaseState { public static float baseDuration; public static string sound; public static GameObject effectPrefab; public static GameObject projectilePrefab; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static string attackSoundString; public static float projectileVelocity; public static float minimumDistance; public static float timeToTarget = 3f; public static int projectileCount; private float duration; private static int ThrowSackStateHash = Animator.StringToHash("ThrowSack"); private static int ThrowSackParamHash = Animator.StringToHash("ThrowSack.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(sound, base.gameObject, attackSpeedStat); PlayAnimation("Body", ThrowSackStateHash, ThrowSackParamHash, duration); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, SackBaseState.muzzleName, transmit: false); } Fire(); } private void Fire() { Ray aimRay = GetAimRay(); Ray ray = aimRay; Ray ray2 = aimRay; UnityEngine.Vector3 point = aimRay.GetPoint(minimumDistance); bool flag = false; if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo, 500f, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) { point = hitInfo.point; flag = true; } float magnitude = projectileVelocity; if (flag) { UnityEngine.Vector3 vector = point - ray2.origin; UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z); float magnitude2 = vector2.magnitude; UnityEngine.Vector2 vector3 = vector2 / magnitude2; if (magnitude2 < minimumDistance) { magnitude2 = minimumDistance; } float y = Trajectory.CalculateInitialYSpeed(timeToTarget, vector.y); float num = magnitude2 / timeToTarget; UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector3.x * num, y, vector3.y * num); magnitude = direction.magnitude; ray2.direction = direction; } for (int i = 0; i < projectileCount; i++) { UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(Util.ApplySpread(ray2.direction, minSpread, maxSpread, 1f, 1f)); ProjectileManager.instance.FireProjectile(projectilePrefab, ray2.origin, rotation, base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } } namespace EntityStates.RoboBallBoss { public class DeathState : GenericCharacterDeath { public static GameObject initialEffect; public static GameObject deathEffect; public static float duration = 2f; private float stopwatch; private Transform modelBaseTransform; private Transform centerTransform; private bool attemptedDeathBehavior; public override void OnEnter() { base.OnEnter(); if (!base.modelLocator) { return; } ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if ((bool)component) { centerTransform = component.FindChild("Center"); if ((bool)initialEffect) { GameObject obj = UnityEngine.Object.Instantiate(initialEffect, centerTransform.position, centerTransform.rotation); obj.GetComponent().newDuration = duration; obj.transform.parent = centerTransform; } } modelBaseTransform = base.modelLocator.modelBaseTransform; } private void AttemptDeathBehavior() { if (!attemptedDeathBehavior) { attemptedDeathBehavior = true; if ((bool)deathEffect && NetworkServer.active && (bool)centerTransform) { EffectManager.SpawnEffect(deathEffect, new EffectData { origin = centerTransform.position }, transmit: true); } if ((bool)modelBaseTransform) { EntityState.Destroy(modelBaseTransform.gameObject); modelBaseTransform = null; } if (NetworkServer.active) { EntityState.Destroy(base.gameObject); } } } public override void FixedUpdate() { stopwatch += GetDeltaTime(); if (stopwatch >= duration) { AttemptDeathBehavior(); } } public override void OnExit() { if (!outer.destroying) { AttemptDeathBehavior(); } base.OnExit(); } } public class SpawnState : GenericCharacterSpawnState { public static GameObject spawnEffectPrefab; public static float spawnEffectRadius; public override void OnEnter() { base.OnEnter(); if ((bool)spawnEffectPrefab) { EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData { origin = base.characterBody.corePosition, scale = spawnEffectRadius }, transmit: false); } } } } namespace EntityStates.RoboBallBoss.Weapon { public class DeployMinions : BaseState { public static float baseDuration = 3.5f; public static string attackSoundString; public static string summonSoundString; public static int maxSummonCount = 5; public static float summonDuration = 3.26f; public static string summonMuzzleString; public static string spawnCard; private Animator animator; private Transform modelTransform; private ChildLocator childLocator; private float duration; private float summonInterval; private float summonTimer; private int summonCount; private bool isSummoning; public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); duration = baseDuration; PlayCrossfade("Gesture, Additive", "DeployMinions", "DeployMinions.playbackRate", duration, 0.1f); Util.PlaySound(attackSoundString, base.gameObject); summonInterval = summonDuration / (float)maxSummonCount; } private Transform FindTargetClosest(UnityEngine.Vector3 point, TeamIndex enemyTeam) { ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(enemyTeam); float num = 99999f; Transform result = null; for (int i = 0; i < teamMembers.Count; i++) { float num2 = UnityEngine.Vector3.SqrMagnitude(teamMembers[i].transform.position - point); if (num2 < num) { num = num2; result = teamMembers[i].transform; } } return result; } private void SummonMinion() { if (!base.characterBody || !base.characterBody.master || base.characterBody.master.GetDeployableCount(DeployableSlot.RoboBallMini) >= base.characterBody.master.GetDeployableSameSlotLimit(DeployableSlot.RoboBallMini)) { return; } Util.PlaySound(summonSoundString, base.gameObject); if (!NetworkServer.active) { return; } UnityEngine.Vector3 position = FindModelChild(summonMuzzleString).position; DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load($"SpawnCards/CharacterSpawnCards/{spawnCard}"), new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Direct, minDistance = 0f, maxDistance = 0f, position = position }, RoR2Application.rng); directorSpawnRequest.summonerBodyObject = base.gameObject; GameObject gameObject = DirectorCore.instance.TrySpawnObject(directorSpawnRequest); if ((bool)gameObject) { CharacterMaster component = gameObject.GetComponent(); RoR2.Inventory component2 = gameObject.GetComponent(); component2.SetEquipmentIndex(base.characterBody.inventory.currentEquipmentIndex); if (base.characterBody.inventory.GetItemCount(RoR2Content.Items.Ghost) > 0) { component2.GiveItem(RoR2Content.Items.Ghost); component2.GiveItem(RoR2Content.Items.HealthDecay, 30); component2.GiveItem(RoR2Content.Items.BoostDamage, 150); } Deployable deployable = gameObject.AddComponent(); deployable.onUndeploy = new UnityEvent(); deployable.onUndeploy.AddListener(component.TrueKill); base.characterBody.master.AddDeployable(deployable, DeployableSlot.RoboBallMini); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)animator) { bool flag = animator.GetFloat("DeployMinions.active") > 0.9f; if (isSummoning) { summonTimer += GetDeltaTime(); if (NetworkServer.active && summonTimer > 0f && summonCount < maxSummonCount) { summonCount++; summonTimer -= summonInterval; SummonMinion(); } } isSummoning = flag; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class EnableEyebeams : BaseState { public static float baseDuration; public static string soundString; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(soundString, base.gameObject); EntityStateMachine[] components = base.gameObject.GetComponents(); foreach (EntityStateMachine entityStateMachine in components) { if (entityStateMachine.customName.Contains("EyeBeam")) { entityStateMachine.SetNextState(new FireSpinningEyeBeam()); } } } } public class ChargeEyeblast : BaseState { public static float baseDuration = 1f; public static GameObject chargeEffectPrefab; public static string attackString; public static string muzzleString; private float duration; private GameObject chargeInstance; protected EffectManagerHelper _emh_chargeInstance; public override void Reset() { base.Reset(); chargeInstance = null; _emh_chargeInstance = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Animator modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(muzzleString); if ((bool)transform && (bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation); chargeInstance = _emh_chargeInstance.gameObject; } chargeInstance.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeInstance.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } } } if ((bool)modelAnimator) { PlayCrossfade("Gesture, Additive", "ChargeEyeBlast", "ChargeEyeBlast.playbackRate", duration, 0.1f); } } public override void OnExit() { base.OnExit(); if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null) { _emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance); } else { EntityState.Destroy(chargeInstance); } chargeInstance = null; _emh_chargeInstance = null; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(GetNextState()); } } public virtual EntityState GetNextState() { return new FireEyeBlast(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireEyeBlast : BaseState { [SerializeField] public GameObject projectilePrefab; public static GameObject muzzleflashEffectPrefab; [SerializeField] public int projectileCount = 3; [SerializeField] public float totalYawSpread = 5f; [SerializeField] public float baseDuration = 2f; [SerializeField] public float baseFireDuration = 0.2f; [SerializeField] public float damageCoefficient = 1.2f; [SerializeField] public float projectileSpeed; public static float force = 20f; public static float selfForce; public static string attackString; public static string muzzleString; private float duration; private float fireDuration; private int projectilesFired; private bool projectileSpreadIsYaw; private static int FireEyeBlastStateHash = Animator.StringToHash("FireEyeBlast"); private static int FireEyeBlastParamHash = Animator.StringToHash("FireEyeBlast.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; fireDuration = baseFireDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", FireEyeBlastStateHash, FireEyeBlastParamHash, duration); Util.PlaySound(attackString, base.gameObject); if (base.isAuthority) { base.healthComponent.TakeDamageForce(GetAimRay().direction * selfForce); } if (UnityEngine.Random.value <= 0.5f) { projectileSpreadIsYaw = true; } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { int num = Mathf.FloorToInt(base.fixedAge / fireDuration * (float)projectileCount); if (projectilesFired <= num && projectilesFired < projectileCount) { if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); } Ray aimRay = GetAimRay(); float speedOverride = projectileSpeed; int num2 = Mathf.FloorToInt((float)projectilesFired - (float)(projectileCount - 1) / 2f); float bonusYaw = 0f; float bonusPitch = 0f; if (projectileSpreadIsYaw) { bonusYaw = (float)num2 / (float)(projectileCount - 1) * totalYawSpread; } else { bonusPitch = (float)num2 / (float)(projectileCount - 1) * totalYawSpread; } UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw, bonusPitch); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speedOverride); projectilesFired++; } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ChargeSuperEyeblast : ChargeEyeblast { public override EntityState GetNextState() { return new FireSuperEyeblast(); } } public class FireSuperEyeblast : FireEyeBlast { } public class FireDelayKnockup : BaseState { [SerializeField] public int knockupCount; [SerializeField] public float randomPositionRadius; public static float baseDuration; public static GameObject projectilePrefab; public static GameObject muzzleEffectPrefab; public static float maxDistance; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayCrossfade("Gesture, Additive", "FireDelayKnockup", 0.1f); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "EyeballMuzzle1", transmit: false); EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "EyeballMuzzle2", transmit: false); EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "EyeballMuzzle3", transmit: false); } if (!NetworkServer.active) { return; } BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } bullseyeSearch.maxDistanceFilter = maxDistance; bullseyeSearch.maxAngleFilter = 360f; Ray aimRay = GetAimRay(); bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.filterByLoS = false; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.RefreshCandidates(); List list = bullseyeSearch.GetResults().ToList(); int num = 0; for (int i = 0; i < knockupCount; i++) { if (num >= list.Count) { num = 0; } HurtBox hurtBox = list[num]; if ((bool)hurtBox) { UnityEngine.Vector2 vector = UnityEngine.Random.insideUnitCircle * randomPositionRadius; UnityEngine.Vector3 vector2 = hurtBox.transform.position + new UnityEngine.Vector3(vector.x, 0f, vector.y); if (Physics.Raycast(new Ray(vector2 + UnityEngine.Vector3.up * 1f, UnityEngine.Vector3.down), out var hitInfo, 200f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { vector2 = hitInfo.point; } ProjectileManager.instance.FireProjectile(projectilePrefab, vector2, UnityEngine.Quaternion.identity, base.gameObject, damageStat, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } num++; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } public class FireSuperDelayKnockup : FireDelayKnockup { public static float shieldDuration; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { base.characterBody.AddTimedBuff(RoR2Content.Buffs.EngiShield, shieldDuration); } } } public class FireSpinningEyeBeam : FireEyeBeam { private Transform eyeBeamOriginTransform; public override void OnEnter() { string customName = outer.customName; eyeBeamOriginTransform = FindModelChild(customName); muzzleString = customName; base.OnEnter(); } public override Ray GetLaserRay() { Ray result = default(Ray); if ((bool)eyeBeamOriginTransform) { result.origin = eyeBeamOriginTransform.position; result.direction = eyeBeamOriginTransform.forward; } return result; } public override bool ShouldFireLaser() { return true; } } } namespace EntityStates.RoboBallMini { public class DeathState : EntityStates.Drone.DeathState { public override void OnImpactServer(UnityEngine.Vector3 contactPoint) { } } } namespace EntityStates.RoboBallMini.Weapon { public class FireEyeBeam : FireBeam { public override void ModifyBullet(BulletAttack bulletAttack) { } } } namespace EntityStates.Railgunner.Weapon { public class ActiveReload : BaseState { private const string reloadStateMachineName = "Reload"; [SerializeField] public float baseDuration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration; Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Reload"); if ((bool)entityStateMachine && entityStateMachine.state is Reloading reloading) { reloading.AttemptBoost(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } public abstract class BaseChargeSnipe : BaseState, IBaseWeaponState { private const string backpackStateMachineName = "Backpack"; [SerializeField] public float baseDuration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Backpack"); if ((bool)entityStateMachine) { entityStateMachine.SetNextState(InstantiateBackpackState()); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public bool CanScope() { return false; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } protected abstract EntityState InstantiateBackpackState(); } public class BaseFireMine : BaseState { [SerializeField] public float baseDuration; [SerializeField] public float baseCrossfadeDuration; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public GameObject projectilePrefab; [SerializeField] public string muzzleName; [SerializeField] public float damageCoefficient; [SerializeField] public float force; [SerializeField] public string enterSoundString; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; float crossfadeDuration = baseCrossfadeDuration / attackSpeedStat; Util.PlaySound(enterSoundString, base.gameObject); Ray aimRay = GetAimRay(); StartAimMode(aimRay); if ((bool)GetModelAnimator()) { PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateParam, duration, crossfadeDuration); } if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public abstract class BaseFireSnipe : GenericBulletBaseState, IBaseWeaponState { private const string reloadStateMachineName = "Reload"; private const string backpackStateMachineName = "Backpack"; [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public bool useSecondaryStocks; [SerializeField] public bool queueReload; [SerializeField] [Header("Projectile")] public float critDamageMultiplier; [SerializeField] public float selfKnockbackForce; [SerializeField] public bool isPiercing; [SerializeField] public float piercingDamageCoefficientPerTarget; [SerializeField] public float trajectoryAimAssistMultiplier = 0.3f; [Header("Animation")] [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private bool wasMiss; private bool wasAtLeastOneWeakpoint; public static event Action onWeakPointHit; public static event Action onWeakPointMissed; public static event Action onFireSnipe; public override void OnEnter() { wasMiss = true; BaseFireSnipe.onFireSnipe?.Invoke(this); base.OnEnter(); if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } if (base.isAuthority && useSecondaryStocks && (bool)base.skillLocator && (bool)base.skillLocator.secondary) { base.skillLocator.secondary.DeductStock(1); } } public override void OnExit() { if (base.isAuthority && (wasMiss || (!wasAtLeastOneWeakpoint && !wasMiss))) { BaseFireSnipe.onWeakPointMissed?.Invoke(); } crosshairOverrideRequest?.Dispose(); base.OnExit(); } protected override void ModifyBullet(BulletAttack bulletAttack) { bulletAttack.sniper = true; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Reload"); if ((bool)entityStateMachine) { if (entityStateMachine.state is Boosted boosted) { bulletAttack.damage += boosted.GetBonusDamage(); boosted.ConsumeBoost(queueReload); } else if (queueReload && entityStateMachine.state is Waiting waiting) { waiting.QueueReload(); } } if (isPiercing) { bulletAttack.stopperMask = LayerIndex.world.mask; } bulletAttack.modifyOutgoingDamageCallback = delegate(BulletAttack _bulletAttack, ref BulletAttack.BulletHit hitInfo, DamageInfo damageInfo) { _bulletAttack.damage *= piercingDamageCoefficientPerTarget; wasMiss = false; if (damageInfo.crit) { damageInfo.damage *= critDamageMultiplier; if ((bool)hitInfo.hitHurtBox && (bool)hitInfo.hitHurtBox.healthComponent && (bool)hitInfo.hitHurtBox.healthComponent.body && hitInfo.hitHurtBox.healthComponent.body.teamComponent.teamIndex != base.characterBody.teamComponent.teamIndex) { BaseFireSnipe.onWeakPointHit?.Invoke(damageInfo); wasAtLeastOneWeakpoint = true; } } }; EntityStateMachine entityStateMachine2 = EntityStateMachine.FindByCustomName(base.gameObject, "Backpack"); EntityState entityState = InstantiateBackpackState(); if ((bool)entityStateMachine2 && entityState != null) { entityStateMachine2.SetNextState(entityState); } bulletAttack.trajectoryAimAssistMultiplier = trajectoryAimAssistMultiplier; } protected override void OnFireBulletAuthority(Ray aimRay) { base.characterBody.characterMotor.ApplyForce((0f - selfKnockbackForce) * aimRay.direction); } protected override void PlayFireAnimation() { PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); } public bool CanScope() { return true; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } protected virtual EntityState InstantiateBackpackState() { return null; } } public abstract class BaseWindupSnipe : BaseState, IBaseWeaponState { [SerializeField] public float duration; [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; [SerializeField] public GameObject windupEffectPrefab; [SerializeField] public string windupEffectMuzzle; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private GameObject windupEffectInstance; public override void OnEnter() { base.OnEnter(); Util.PlaySound(enterSoundString, base.gameObject); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } if ((bool)windupEffectPrefab) { Transform transform = FindModelChild(windupEffectMuzzle); if ((bool)transform) { windupEffectInstance = UnityEngine.Object.Instantiate(windupEffectPrefab, transform.position, transform.rotation); windupEffectInstance.transform.parent = transform; } } } public override void Update() { base.Update(); base.characterBody.SetSpreadBloom(base.age / duration, canOnlyIncreaseBloom: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(InstantiateNextState()); } } public override void OnExit() { crosshairOverrideRequest?.Dispose(); if ((bool)windupEffectInstance) { EntityState.Destroy(windupEffectInstance); } base.OnExit(); } protected abstract EntityState InstantiateNextState(); public bool CanScope() { return true; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class ChargeSnipeCryo : BaseChargeSnipe { protected override EntityState InstantiateBackpackState() { return new ChargingCryo(); } } public class ChargeSnipeSuper : BaseChargeSnipe { protected override EntityState InstantiateBackpackState() { return new ChargingSuper(); } } public class FireMineBlinding : BaseFireMine { } public class FireMineConcussive : BaseFireMine { } public class FirePistol : BaseState, IBaseWeaponState { [SerializeField] public float baseDuration; [Header("Projectile")] [SerializeField] public float damageCoefficient; [SerializeField] public float force; [SerializeField] public float spreadBloomValue; [SerializeField] public float recoilYMin; [SerializeField] public float recoilXMin; [SerializeField] public float recoilYMax; [SerializeField] public float recoilXMax; [SerializeField] public GameObject projectilePrefab; [SerializeField] public float selfKnockbackForce; [SerializeField] public float baseInaccuracyDegrees; [Header("Effects")] [SerializeField] public string muzzleName; [SerializeField] public string fireSoundString; [SerializeField] public GameObject muzzleFlashPrefab; [Header("Animation")] [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; protected float duration; protected virtual void FireBullet(Ray aimRay) { StartAimMode(aimRay); Util.PlaySound(fireSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); AddRecoil(recoilYMin, recoilYMax, recoilXMin, recoilXMax); if (base.isAuthority) { float num = 0f; if ((bool)base.characterBody) { num = base.characterBody.spreadBloomAngle; } UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.forward); UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, baseInaccuracyDegrees + num), UnityEngine.Vector3.left); UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(aimRay.direction, UnityEngine.Vector3.up) * quaternion * quaternion2; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = aimRay.origin; fireProjectileInfo.rotation = rotation; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.crit = RollCrit(); fireProjectileInfo.force = force; fireProjectileInfo.procChainMask = default(ProcChainMask); fireProjectileInfo.damageColorIndex = DamageColorIndex.Default; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); base.characterBody.characterMotor.ApplyForce((0f - selfKnockbackForce) * aimRay.direction); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; FireBullet(GetAimRay()); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } public bool CanScope() { return true; } } public class FireSnipeCryo : BaseFireSnipe { protected override void ModifyBullet(BulletAttack bulletAttack) { base.ModifyBullet(bulletAttack); bulletAttack.damageType |= (DamageTypeCombo)DamageType.Freeze2s; } protected override EntityState InstantiateBackpackState() { return new UseCryo(); } } public class FireSnipeHeavy : BaseFireSnipe { } public class FireSnipeLight : BaseFireSnipe { } public class FireSnipeSuper : BaseFireSnipe { protected override EntityState InstantiateBackpackState() { return new Offline(); } } public interface IBaseWeaponState { bool CanScope(); } public class WindupSnipeCryo : BaseWindupSnipe { protected override EntityState InstantiateNextState() { return new FireSnipeCryo(); } } public class WindupSnipeSuper : BaseWindupSnipe { protected override EntityState InstantiateNextState() { return new FireSnipeSuper(); } } } namespace EntityStates.Railgunner.Scope { public class ActiveScopeHeavy : BaseActive { protected override BaseWindDown GetNextState() { return new WindDownScopeHeavy(); } } public class ActiveScopeLight : BaseActive { protected override BaseWindDown GetNextState() { return new WindDownScopeLight(); } } public class BaseScopeState : BaseSkillState { [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public GameObject scopeOverlayPrefab; [SerializeField] public CharacterCameraParams cameraParams; [SerializeField] public float cameraOverridePriority; public static string mecanimBoolName; private OverlayController overlayController; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private CameraTargetParams.CameraParamsOverrideHandle cameraParamsOverrideHandle; public static bool inScope; public override void OnEnter() { base.OnEnter(); overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams { prefab = scopeOverlayPrefab, childLocatorEntry = "ScopeContainer" }); Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetBool(mecanimBoolName, value: true); } if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } inScope = true; } public override void OnExit() { inScope = false; Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetBool(mecanimBoolName, value: false); } RemoveOverlay(0f); crosshairOverrideRequest?.Dispose(); base.OnExit(); } protected void SetScopeAlpha(float alpha) { if (overlayController != null) { overlayController.alpha = alpha; } } protected void RemoveOverlay(float transitionDuration) { if (overlayController != null) { HudOverlayManager.RemoveOverlay(overlayController); overlayController = null; } } protected void StartScopeParamsOverride(float transitionDuration) { if (!cameraParamsOverrideHandle.isValid) { cameraParamsOverrideHandle = base.cameraTargetParams.AddParamsOverride(new CameraTargetParams.CameraParamsOverrideRequest { cameraParamsData = cameraParams.data, priority = cameraOverridePriority }, transitionDuration); } } protected void EndScopeParamsOverride(float transitionDuration) { if (cameraParamsOverrideHandle.isValid) { base.cameraTargetParams.RemoveParamsOverride(cameraParamsOverrideHandle, transitionDuration); cameraParamsOverrideHandle = default(CameraTargetParams.CameraParamsOverrideHandle); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } protected virtual CharacterCameraParams GetCameraParams() { return cameraParams; } protected virtual float GetScopeEntryDuration() { return 0f; } } public class BaseWindUp : BaseScopeState { [SerializeField] public float baseDuration; [SerializeField] public string enterSoundString; private float duration; public override void OnEnter() { duration = baseDuration; base.OnEnter(); SetScopeAlpha(0f); StartScopeParamsOverride(duration); Util.PlaySound(enterSoundString, base.gameObject); } public override void OnExit() { EndScopeParamsOverride(0f); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { BaseActive nextState = GetNextState(); nextState.activatorSkillSlot = base.activatorSkillSlot; outer.SetNextState(nextState); } } public override void Update() { base.Update(); SetScopeAlpha(Mathf.Clamp01(base.age / duration)); } protected virtual BaseActive GetNextState() { return new BaseActive(); } protected override float GetScopeEntryDuration() { return duration; } public override void ModifyNextState(EntityState nextState) { } } public class BaseWindDown : BaseScopeState { [SerializeField] public float baseDuration; [SerializeField] public string enterSoundString; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration; SetScopeAlpha(1f); RemoveOverlay(duration); StartScopeParamsOverride(0f); EndScopeParamsOverride(duration); Util.PlaySound(enterSoundString, base.gameObject); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override void Update() { base.Update(); SetScopeAlpha(1f - Mathf.Clamp01(base.age / duration)); } protected override CharacterCameraParams GetCameraParams() { return null; } } public class BaseActive : BaseScopeState { [SerializeField] public SkillDef primaryOverride; [SerializeField] public LoopSoundDef loopSound; private GenericSkill overriddenSkill; private LoopSoundManager.SoundLoopPtr loopPtr; public override void OnEnter() { base.OnEnter(); SetScopeAlpha(1f); StartScopeParamsOverride(0f); GenericSkill genericSkill = base.skillLocator?.primary; if ((bool)genericSkill) { TryOverrideSkill(genericSkill); genericSkill.onSkillChanged += TryOverrideSkill; } if (base.isAuthority) { loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSound); } } public override void OnExit() { if (loopPtr.isValid) { LoopSoundManager.StopSoundLoopLocal(loopPtr); } GenericSkill genericSkill = base.skillLocator?.primary; if ((bool)genericSkill) { genericSkill.onSkillChanged -= TryOverrideSkill; } if ((bool)overriddenSkill) { overriddenSkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); } EndScopeParamsOverride(0f); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && (!IsKeyDownAuthority() || base.characterBody.isSprinting)) { outer.SetNextState(GetNextState()); } } private void TryOverrideSkill(GenericSkill skill) { if ((bool)skill && !overriddenSkill && !skill.HasSkillOverrideOfPriority(GenericSkill.SkillOverridePriority.Contextual)) { overriddenSkill = skill; overriddenSkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); overriddenSkill.stock = base.skillLocator.secondary.stock; } } protected virtual BaseWindDown GetNextState() { return new BaseWindDown(); } } public class WindDownScopeHeavy : BaseWindDown { } public class WindDownScopeLight : BaseWindDown { } public class WindUpScopeHeavy : BaseWindUp { protected override BaseActive GetNextState() { return new ActiveScopeHeavy(); } } public class WindUpScopeLight : BaseWindUp { protected override BaseActive GetNextState() { return new ActiveScopeLight(); } } } namespace EntityStates.Railgunner.Reload { public class BoostConfirm : EntityState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; public OverlayController overlayController; private GenericSkill primarySkill; public SkillDef primaryOverride; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); if (overlayController == null) { return; } foreach (GameObject instances in overlayController.instancesList) { ActiveReloadBarController component = instances.GetComponent(); if ((bool)component) { component.SetWasWindowHit(wasWindowHit: true); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new Boosted()); } } public override void OnExit() { if (overlayController != null) { HudOverlayManager.RemoveOverlay(overlayController); } if ((bool)primarySkill) { primarySkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); } base.OnExit(); } public void OverridePrimary(GenericSkill skill, SkillDef overrideDef) { primarySkill = skill; primaryOverride = overrideDef; primarySkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); } } public class Boosted : BaseState { [SerializeField] public float bonusDamageCoefficient; [SerializeField] public string boostConsumeSoundString; [SerializeField] public GameObject overlayPrefab; [SerializeField] public string overlayChildLocatorEntry; private OverlayController overlayController; public float GetBonusDamage() { return bonusDamageCoefficient * damageStat; } public void ConsumeBoost(bool queueReload) { Util.PlaySound(boostConsumeSoundString, base.gameObject); outer.SetNextState(new Waiting(queueReload)); } public override void OnEnter() { base.OnEnter(); OverlayCreationParams overlayCreationParams = default(OverlayCreationParams); overlayCreationParams.prefab = overlayPrefab; overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry; OverlayCreationParams overlayCreationParams2 = overlayCreationParams; overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2); } public override void OnExit() { HudOverlayManager.RemoveOverlay(overlayController); base.OnExit(); } } public class Reloading : BaseState { [SerializeField] public float baseDuration; [SerializeField] public float boostWindowDelay; [SerializeField] public float boostWindowDuration; [SerializeField] public float boostGracePeriod; [SerializeField] public SkillDef primaryOverride; [SerializeField] public GameObject overlayPrefab; [SerializeField] public string overlayChildLocatorEntry; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public LoopSoundDef loopSoundDef; [SerializeField] public string endNoBoostSoundString; [SerializeField] public string failSoundString; private float duration; private float adjustedBoostWindowDelay; private float adjustedBoostWindowDuration; private GenericSkill primarySkill; private OverlayController overlayController; private List reloadUiList = new List(); private bool hasAttempted; private LoopSoundManager.SoundLoopPtr loopPtr; public bool AttemptBoost() { if (IsInBoostWindow()) { outer.SetNextState(new BoostConfirm()); return true; } foreach (ActiveReloadBarController reloadUi in reloadUiList) { reloadUi.SetWasFailure(wasFailure: true); } return false; } public override void OnEnter() { base.OnEnter(); float num = boostWindowDelay + boostWindowDuration; float num2 = baseDuration - num; duration = num + num2 / attackSpeedStat; adjustedBoostWindowDelay = Mathf.Min(boostWindowDelay / baseDuration * duration, boostWindowDelay); adjustedBoostWindowDuration = Mathf.Max((boostWindowDelay + boostWindowDuration) / baseDuration * duration, num) - adjustedBoostWindowDelay; if ((bool)loopSoundDef) { loopPtr = LoopSoundManager.PlaySoundLoopLocalRtpc(base.gameObject, loopSoundDef, "attackSpeed", Util.CalculateAttackSpeedRtpcValue(attackSpeedStat)); } PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); SkillLocator component = base.gameObject.GetComponent(); if ((bool)component && (bool)component.primary) { primarySkill = component.primary; primarySkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); } OverlayCreationParams overlayCreationParams = default(OverlayCreationParams); overlayCreationParams.prefab = overlayPrefab; overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry; OverlayCreationParams overlayCreationParams2 = overlayCreationParams; overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2); overlayController.onInstanceAdded += OnOverlayInstanceAdded; overlayController.onInstanceRemove += OnOverlayInstanceRemoved; } public override void FixedUpdate() { base.FixedUpdate(); float num = ((duration > 0f) ? (base.fixedAge / duration) : 0f); foreach (ActiveReloadBarController reloadUi in reloadUiList) { reloadUi.SetTValue(num); reloadUi.SetIsWindowActive(IsInBoostWindow()); } if (duration <= 0f || num >= 1f) { Util.PlaySound(endNoBoostSoundString, base.gameObject); outer.SetNextState(new Waiting()); } if ((bool)base.inputBank && base.inputBank.skill1.justPressed && !hasAttempted) { hasAttempted = true; if (!AttemptBoost()) { Util.PlaySound(failSoundString, base.gameObject); } } } public override void OnExit() { if (overlayController != null) { overlayController.onInstanceAdded -= OnOverlayInstanceAdded; overlayController.onInstanceRemove -= OnOverlayInstanceRemoved; reloadUiList.Clear(); } if ((bool)base.skillLocator) { primarySkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); } for (int i = 0; i < base.skillLocator.skillSlotCount; i++) { GenericSkill skillAtIndex = base.skillLocator.GetSkillAtIndex(i); if ((bool)skillAtIndex) { RailgunSkillDef railgunSkillDef = skillAtIndex.skillDef as RailgunSkillDef; if ((bool)railgunSkillDef && railgunSkillDef.restockOnReload) { skillAtIndex.stock = skillAtIndex.maxStock; } } } if (loopPtr.isValid) { LoopSoundManager.StopSoundLoopLocal(loopPtr); } base.OnExit(); } public bool IsInBoostWindow() { if (adjustedBoostWindowDelay - base.fixedAge < boostGracePeriod) { return base.fixedAge - (adjustedBoostWindowDelay + adjustedBoostWindowDuration) < boostGracePeriod; } return false; } public override void ModifyNextState(EntityState nextState) { if (nextState is BoostConfirm boostConfirm) { boostConfirm.overlayController = overlayController; if ((bool)primarySkill) { boostConfirm.OverridePrimary(primarySkill, primaryOverride); } } else if (overlayController != null) { HudOverlayManager.RemoveOverlay(overlayController); } } private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance) { ActiveReloadBarController component = instance.GetComponent(); float num = ((duration > 0f) ? (1f / duration) : 0f); component.SetWindowRange(num * adjustedBoostWindowDelay, num * (adjustedBoostWindowDelay + adjustedBoostWindowDuration)); reloadUiList.Add(component); } private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance) { ActiveReloadBarController component = instance.GetComponent(); reloadUiList.Remove(component); } } public class Waiting : EntityState { private const string backpackStateMachineName = "Backpack"; private const string scopeStateMachineName = "Scope"; private List restockOnReloadList = new List(); private EntityStateMachine backpackStateMachine; private EntityStateMachine scopeStateMachine; private bool isReloadQueued; public Waiting() { isReloadQueued = false; } public Waiting(bool queueReload) { isReloadQueued = queueReload; } public override void OnEnter() { base.OnEnter(); if ((bool)base.skillLocator) { for (int i = 0; i < base.skillLocator.skillSlotCount; i++) { GenericSkill skillAtIndex = base.skillLocator.GetSkillAtIndex(i); if ((bool)skillAtIndex) { skillAtIndex.onSkillChanged += OnSkillChanged; } } ReevaluateSkills(); } backpackStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Backpack"); scopeStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Scope"); } public override void FixedUpdate() { base.FixedUpdate(); if (!isReloadQueued) { foreach (GenericSkill restockOnReload in restockOnReloadList) { if (restockOnReload.stock == 0) { isReloadQueued = true; break; } } } if (isReloadQueued && CanReload()) { outer.SetNextState(new Reloading()); } } public override void OnExit() { if ((bool)base.skillLocator) { for (int i = 0; i < base.skillLocator.skillSlotCount; i++) { GenericSkill skillAtIndex = base.skillLocator.GetSkillAtIndex(i); if ((bool)skillAtIndex) { skillAtIndex.onSkillChanged -= OnSkillChanged; } } } base.OnExit(); } public bool CanReload() { if (!(backpackStateMachine.state is Offline)) { return scopeStateMachine.IsInMainState(); } return false; } public void QueueReload() { isReloadQueued = true; } private void OnSkillChanged(GenericSkill skill) { ReevaluateSkills(); } private void ReevaluateSkills() { restockOnReloadList.Clear(); for (int i = 0; i < base.skillLocator.skillSlotCount; i++) { GenericSkill skillAtIndex = base.skillLocator.GetSkillAtIndex(i); if ((bool)skillAtIndex) { RailgunSkillDef railgunSkillDef = skillAtIndex.skillDef as RailgunSkillDef; if ((bool)railgunSkillDef && railgunSkillDef.restockOnReload) { restockOnReloadList.Add(skillAtIndex); } } } } } } namespace EntityStates.Railgunner.Backpack { public abstract class BaseBackpack : BaseState { [SerializeField] public LoopSoundDef loopSoundDef; [SerializeField] public string enterSoundString; [SerializeField] public string mecanimBoolName; private LoopSoundManager.SoundLoopPtr loopPtr; protected bool isSoundScaledByAttackSpeed; public override void OnEnter() { base.OnEnter(); if ((bool)loopSoundDef) { if (isSoundScaledByAttackSpeed) { loopPtr = LoopSoundManager.PlaySoundLoopLocalRtpc(base.gameObject, loopSoundDef, "attackSpeed", Util.CalculateAttackSpeedRtpcValue(attackSpeedStat)); } else { loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSoundDef); } } if (!string.IsNullOrEmpty(enterSoundString)) { if (isSoundScaledByAttackSpeed) { Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); } else { Util.PlaySound(enterSoundString, base.gameObject); } } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator && !string.IsNullOrEmpty(mecanimBoolName)) { modelAnimator.SetBool(mecanimBoolName, value: true); } } public override void OnExit() { if (loopPtr.isValid) { LoopSoundManager.StopSoundLoopLocal(loopPtr); } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator && !string.IsNullOrEmpty(mecanimBoolName)) { modelAnimator.SetBool(mecanimBoolName, value: false); } base.OnExit(); } } public abstract class BaseCharged : BaseBackpack { [SerializeField] public float duration; [SerializeField] public SkillDef primaryOverride; [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public GameObject overlayPrefab; [SerializeField] public string overlayChildLocatorEntry; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private OverlayController overlayController; private GenericSkill primarySkill; private List fillUiList = new List(); private CrosshairUtils.OverrideRequest crosshairOverrideRequest; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); SkillLocator component = base.gameObject.GetComponent(); if ((bool)component && (bool)component.primary) { primarySkill = component.primary; primarySkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); } OverlayCreationParams overlayCreationParams = default(OverlayCreationParams); overlayCreationParams.prefab = overlayPrefab; overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry; OverlayCreationParams overlayCreationParams2 = overlayCreationParams; overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2); overlayController.onInstanceAdded += OnOverlayInstanceAdded; overlayController.onInstanceRemove += OnOverlayInstanceRemoved; if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.PrioritySkill); } } public override void FixedUpdate() { base.FixedUpdate(); if (duration > 0f) { foreach (ImageFillController fillUi in fillUiList) { fillUi.SetTValue(1f - base.fixedAge / duration); } } if (base.fixedAge >= duration) { outer.SetNextState(InstantiateExpiredState()); } base.characterBody.SetAimTimer(3f); } public override void OnExit() { crosshairOverrideRequest?.Dispose(); if (overlayController != null) { overlayController.onInstanceAdded -= OnOverlayInstanceAdded; overlayController.onInstanceRemove -= OnOverlayInstanceRemoved; fillUiList.Clear(); HudOverlayManager.RemoveOverlay(overlayController); } if ((bool)base.skillLocator) { primarySkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } protected abstract EntityState InstantiateExpiredState(); private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance) { fillUiList.Add(instance.GetComponent()); } private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance) { fillUiList.Remove(instance.GetComponent()); } } public abstract class BaseCharging : BaseBackpack { [SerializeField] public float baseDuration; [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public GameObject overlayPrefab; [SerializeField] public string overlayChildLocatorEntry; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private OverlayController overlayController; private List fillUiList = new List(); private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private float duration; public override void OnEnter() { isSoundScaledByAttackSpeed = true; base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); OverlayCreationParams overlayCreationParams = default(OverlayCreationParams); overlayCreationParams.prefab = overlayPrefab; overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry; OverlayCreationParams overlayCreationParams2 = overlayCreationParams; overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2); overlayController.onInstanceAdded += OnOverlayInstanceAdded; overlayController.onInstanceRemove += OnOverlayInstanceRemoved; if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.PrioritySkill); } } public override void OnExit() { crosshairOverrideRequest?.Dispose(); if (overlayController != null) { overlayController.onInstanceAdded -= OnOverlayInstanceAdded; overlayController.onInstanceRemove -= OnOverlayInstanceRemoved; fillUiList.Clear(); HudOverlayManager.RemoveOverlay(overlayController); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (duration > 0f) { foreach (ImageFillController fillUi in fillUiList) { fillUi.SetTValue(base.fixedAge / duration); } } if (base.fixedAge >= duration) { outer.SetNextState(InstantiateChargedState()); } } protected abstract EntityState InstantiateChargedState(); private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance) { fillUiList.Add(instance.GetComponent()); } private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance) { fillUiList.Remove(instance.GetComponent()); } } public abstract class BaseExpired : BaseBackpack { [SerializeField] public float duration; [SerializeField] public bool forceShieldRegen; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); if (forceShieldRegen) { base.characterBody?.healthComponent?.ForceShieldRegen(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(InstantiateNextState()); } } protected abstract EntityState InstantiateNextState(); public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public abstract class BaseOnline : BaseBackpack { [SerializeField] public SkillDef requiredSkillDef; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string cooldownParamName; private int animationStateHash; private int cooldownParamHash; private Animator animator; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); animator = GetModelAnimator(); cooldownParamHash = Animator.StringToHash(cooldownParamName); animationStateHash = Animator.StringToHash(animationStateName); } public override void FixedUpdate() { base.FixedUpdate(); if ((object)base.skillLocator.special.skillDef != requiredSkillDef) { outer.SetNextState(new Disconnected()); } else if ((bool)animator) { float num = base.skillLocator.special.CalculateFinalRechargeInterval(); float value = 0f; if (num > 0f) { value = base.skillLocator.special.cooldownRemaining / num; } animator.SetFloat(cooldownParamHash, value); } } public override void OnExit() { if ((bool)animator) { animator.SetFloat(cooldownParamHash, 0f); } base.OnExit(); } } public class ChargedCryo : BaseCharged { protected override EntityState InstantiateExpiredState() { return new ExpiredCryo(); } } public class ChargedSuper : BaseCharged { protected override EntityState InstantiateExpiredState() { return new ExpiredSuper(); } } public class ChargingCryo : BaseCharging { protected override EntityState InstantiateChargedState() { return new ChargedCryo(); } } public class ChargingSuper : BaseCharging { protected override EntityState InstantiateChargedState() { return new ChargedSuper(); } } public class Disconnected : BaseBackpack { [SerializeField] public SkillDef superSkillDef; [SerializeField] public SkillDef cryoSkillDef; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); } public override void FixedUpdate() { base.FixedUpdate(); if ((object)base.skillLocator.special.skillDef == superSkillDef) { outer.SetNextState(new OnlineSuper()); } else if ((object)base.skillLocator.special.skillDef == cryoSkillDef) { outer.SetNextState(new OnlineCryo()); } } } public class ExpiredCryo : BaseExpired { protected override EntityState InstantiateNextState() { return new OnlineCryo(); } } public class ExpiredSuper : BaseExpired { protected override EntityState InstantiateNextState() { return new OnlineSuper(); } } public class Offline : BaseBackpack { [SerializeField] public float baseDuration; [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public GameObject overlayPrefab; [SerializeField] public string overlayChildLocatorEntry; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private OverlayController overlayController; private List fillUiList = new List(); private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } OverlayCreationParams overlayCreationParams = default(OverlayCreationParams); overlayCreationParams.prefab = overlayPrefab; overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry; OverlayCreationParams overlayCreationParams2 = overlayCreationParams; overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2); overlayController.onInstanceAdded += OnOverlayInstanceAdded; overlayController.onInstanceRemove += OnOverlayInstanceRemoved; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new Reboot()); } if (!(duration > 0f)) { return; } foreach (ImageFillController fillUi in fillUiList) { fillUi.SetTValue(base.fixedAge / duration); } } public override void OnExit() { crosshairOverrideRequest?.Dispose(); if (overlayController != null) { overlayController.onInstanceAdded -= OnOverlayInstanceAdded; overlayController.onInstanceRemove -= OnOverlayInstanceRemoved; fillUiList.Clear(); HudOverlayManager.RemoveOverlay(overlayController); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance) { fillUiList.Add(instance.GetComponent()); } private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance) { fillUiList.Remove(instance.GetComponent()); } } public class OnlineCryo : BaseOnline { } public class OnlineSuper : BaseOnline { } public class Reboot : BaseBackpack { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new OnlineSuper()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class UseCryo : BaseBackpack { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new OnlineCryo()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.QuestVolatileBattery { public class QuestVolatileBatteryBaseState : BaseState { protected NetworkedBodyAttachment networkedBodyAttachment { get; private set; } protected HealthComponent attachedHealthComponent { get; private set; } protected CharacterModel attachedCharacterModel { get; private set; } protected Transform[] displays { get; private set; } = Array.Empty(); public override void OnEnter() { base.OnEnter(); networkedBodyAttachment = GetComponent(); if (!networkedBodyAttachment || !networkedBodyAttachment.attachedBody) { return; } attachedHealthComponent = networkedBodyAttachment.attachedBody.healthComponent; ModelLocator modelLocator = networkedBodyAttachment.attachedBody.modelLocator; if ((bool)modelLocator) { Transform modelTransform = modelLocator.modelTransform; if ((bool)modelTransform) { attachedCharacterModel = modelTransform.GetComponent(); } } } } public class Monitor : QuestVolatileBatteryBaseState { private float previousHealthFraction; private static readonly float healthFractionDetonationThreshold = 0.5f; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { FixedUpdateServer(); } } private void FixedUpdateServer() { if ((bool)base.attachedHealthComponent) { float combinedHealthFraction = base.attachedHealthComponent.combinedHealthFraction; if (combinedHealthFraction <= healthFractionDetonationThreshold && healthFractionDetonationThreshold < previousHealthFraction) { outer.SetNextState(new CountDown()); } previousHealthFraction = combinedHealthFraction; } } } public class CountDown : QuestVolatileBatteryBaseState { public static float duration; public static GameObject vfxPrefab; public static float explosionRadius; public static GameObject explosionEffectPrefab; private GameObject[] vfxInstances = Array.Empty(); private bool detonated; public override void OnEnter() { base.OnEnter(); if (!vfxPrefab || !base.attachedCharacterModel) { return; } List equipmentDisplayObjects = base.attachedCharacterModel.GetEquipmentDisplayObjects(RoR2Content.Equipment.QuestVolatileBattery.equipmentIndex); if (equipmentDisplayObjects.Count > 0) { vfxInstances = new GameObject[equipmentDisplayObjects.Count]; for (int i = 0; i < vfxInstances.Length; i++) { GameObject gameObject = UnityEngine.Object.Instantiate(vfxPrefab, equipmentDisplayObjects[i].transform); gameObject.transform.localPosition = UnityEngine.Vector3.zero; gameObject.transform.localRotation = UnityEngine.Quaternion.identity; vfxInstances[i] = gameObject; } } } public override void OnExit() { GameObject[] array = vfxInstances; for (int i = 0; i < array.Length; i++) { EntityState.Destroy(array[i]); } vfxInstances = Array.Empty(); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { FixedUpdateServer(); } } private void FixedUpdateServer() { if (base.fixedAge >= duration && !detonated) { detonated = true; Detonate(); } } public void Detonate() { if ((bool)base.networkedBodyAttachment.attachedBody) { UnityEngine.Vector3 corePosition = base.networkedBodyAttachment.attachedBody.corePosition; float baseDamage = 0f; if ((bool)base.attachedHealthComponent) { baseDamage = base.attachedHealthComponent.fullCombinedHealth * 3f; } EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = corePosition, scale = explosionRadius }, transmit: true); BlastAttack blastAttack = new BlastAttack(); blastAttack.position = corePosition + UnityEngine.Random.onUnitSphere; blastAttack.radius = explosionRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.attacker = base.networkedBodyAttachment.attachedBodyObject; blastAttack.inflictor = base.networkedBodyAttachment.gameObject; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.baseDamage = baseDamage; blastAttack.baseForce = 5000f; blastAttack.bonusForce = UnityEngine.Vector3.zero; blastAttack.attackerFiltering = AttackerFiltering.AlwaysHit; blastAttack.crit = false; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = 0f; blastAttack.teamIndex = base.networkedBodyAttachment.attachedBody.teamComponent.teamIndex; blastAttack.Fire(); base.networkedBodyAttachment.attachedBody.inventory.SetEquipmentIndex(EquipmentIndex.None); outer.SetNextState(new Idle()); } } } } namespace EntityStates.Pot.PotWeapon { public class FireCannon : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject projectilePrefab; public static float selfForce = 1000f; public static int grenadeCountMax = 3; public static float damageCoefficient; public static float fireDuration = 1f; public static float baseDuration = 2f; public static float minSpread = 0f; public static float maxSpread = 5f; public static float arcAngle = 5f; private Ray aimRay; private Transform modelTransform; private float duration; private float fireTimer; private int grenadeCount; private void FireBullet(string targetMuzzle) { aimRay = GetAimRay(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { base.rigidbody.AddForceAtPosition(transform.forward * selfForce, transform.position, ForceMode.Impulse); } } } if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { float x = UnityEngine.Random.Range(minSpread, maxSpread); float z = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 up = UnityEngine.Vector3.up; UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction); UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward); float y = vector.y; vector.y = 0f; float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle; UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelTransform = GetModelTransform(); aimRay = GetAimRay(); StartAimMode(aimRay); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } fireTimer -= GetDeltaTime(); float num = fireDuration / attackSpeedStat / (float)grenadeCountMax; if (fireTimer <= 0f && grenadeCount < grenadeCountMax) { fireTimer += num; if (grenadeCount % 2 == 0) { FireBullet("MuzzleLeft"); PlayCrossfade("Gesture, Left Cannon", "FireGrenadeLeft", 0.1f); } else { FireBullet("MuzzleRight"); PlayCrossfade("Gesture, Right Cannon", "FireGrenadeRight", 0.1f); } grenadeCount++; } if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.ParentPod { public class DeathState : GenericCharacterDeath { public static float deathAnimTimer; private float mDeathAnimTimer; public static GameObject deathEffect; private bool printingStarted; public override void OnEnter() { base.OnEnter(); mDeathAnimTimer = deathAnimTimer; EffectManager.SimpleEffect(deathEffect, base.gameObject.transform.position, base.transform.rotation, transmit: false); } public override void FixedUpdate() { mDeathAnimTimer -= Time.deltaTime; if (mDeathAnimTimer <= 0f && !printingStarted) { printingStarted = true; PrintController printController = GetComponent().modelTransform.gameObject.AddComponent(); printController.enabled = false; printController.printTime = 1f; printController.startingPrintHeight = 99999f; printController.maxPrintHeight = 99999f; printController.startingPrintBias = 0.95f; printController.maxPrintBias = 1.95f; printController.animateFlowmapPower = true; printController.startingFlowmapPower = 1.14f; printController.maxFlowmapPower = 30f; printController.disableWhenFinished = false; printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); printController.enabled = true; } if (printingStarted) { base.FixedUpdate(); } } } } namespace EntityStates.ParentEgg { public class BaseEggState : BaseState { protected SpawnerPodsController controller { get; private set; } public override void OnEnter() { base.OnEnter(); controller = GetComponent(); } } public class Death : GenericCharacterDeath { private float duration; public override void OnEnter() { base.OnEnter(); GetComponent().Dissolve(); } } public class Hatch : GenericCharacterDeath { private SpawnerPodsController controller; private static int HatchStateHash = Animator.StringToHash("Hatch"); public override void OnEnter() { controller = GetComponent(); base.OnEnter(); if (NetworkServer.active) { DoHatch(); } } protected override void PlayDeathAnimation(float crossfadeDuration) { PlayAnimation("Body", HatchStateHash); EffectManager.SimpleEffect(controller.hatchEffect, base.gameObject.transform.position, base.transform.rotation, transmit: false); } protected override void PlayDeathSound() { Util.PlaySound(controller.podHatchSound, base.gameObject); } private void DoHatch() { DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load("SpawnCards/CharacterSpawnCards/cscParent"), new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Direct, minDistance = 0f, maxDistance = 1f, spawnOnTarget = base.transform }, RoR2Application.rng); directorSpawnRequest.summonerBodyObject = base.gameObject; directorSpawnRequest.onSpawnedServer = (Action)Delegate.Combine(directorSpawnRequest.onSpawnedServer, new Action(OnHatchlingSpawned)); DirectorCore.instance.TrySpawnObject(directorSpawnRequest); } private void OnHatchlingSpawned(SpawnCard.SpawnResult spawnResult) { CharacterMaster component = spawnResult.spawnedInstance.GetComponent(); component.teamIndex = base.characterBody.teamComponent.teamIndex; CharacterMaster master = base.characterBody.master; CharacterMaster characterMaster = (master ? master.minionOwnership.ownerMaster : null); if ((bool)component) { RoR2.Inventory inventory = base.characterBody.master.inventory; RoR2.Inventory inventory2 = component.inventory; inventory2.CopyItemsFrom(inventory); inventory2.CopyEquipmentFrom(inventory); GameObject bodyObject = component.GetBodyObject(); if ((bool)bodyObject && (bool)characterMaster) { Deployable component2 = bodyObject.GetComponent(); characterMaster.AddDeployable(component2, DeployableSlot.ParentAlly); } } } } public class IncubateState : BaseEggState { private float duration; private static int SpawnStateHash = Animator.StringToHash("Spawn"); public override void OnEnter() { base.OnEnter(); duration = base.controller.incubationDuration; PlayAnimation("Body", SpawnStateHash); Util.PlaySound(base.controller.podSpawnSound, base.gameObject); EffectManager.SimpleEffect(base.controller.spawnEffect, base.gameObject.transform.position, base.transform.rotation, transmit: true); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new PreHatch()); } } } public class PreHatch : BaseEggState { public override void OnEnter() { base.OnEnter(); GetComponent().deathState = new SerializableEntityStateType(typeof(Hatch)); if (NetworkServer.active) { base.healthComponent.Suicide(); } } } } namespace EntityStates.ParentMonster { public class DeathState : GenericCharacterDeath { [SerializeField] public float timeBeforeDestealth = 2.5f; [SerializeField] public float destealthDuration; [SerializeField] public Material destealthMaterial; [SerializeField] public GameObject effectPrefab; [SerializeField] public string effectMuzzleString; private bool destealth; protected override bool shouldAutoDestroy { get { if (destealth) { return base.fixedAge > timeBeforeDestealth + destealthDuration; } return false; } } public override void OnEnter() { base.OnEnter(); } public override void OnExit() { DestroyModel(); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > timeBeforeDestealth && !destealth) { DoDestealth(); } if (destealth && base.fixedAge > timeBeforeDestealth + destealthDuration) { DestroyModel(); } } private void DoDestealth() { destealth = true; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, effectMuzzleString, transmit: false); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { CharacterModel component = modelTransform.gameObject.GetComponent(); if ((bool)destealthMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = destealthDuration; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = destealthMaterial; temporaryOverlayInstance.inspectorCharacterModel = component; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; PrintController component2 = base.modelLocator.modelTransform.gameObject.GetComponent(); component2.enabled = false; component2.printTime = destealthDuration; component2.startingPrintHeight = 0f; component2.maxPrintHeight = 20f; component2.startingPrintBias = 0f; component2.maxPrintBias = 2f; component2.disableWhenFinished = false; component2.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); component2.enabled = true; } Transform transform = FindModelChild("CoreLight"); if ((bool)transform) { transform.gameObject.SetActive(value: false); } } } } public class GroundSlam : BaseState { public static float duration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float radius = 3f; private BlastAttack attack; public static string attackSoundString; public static GameObject slamImpactEffect; public static GameObject meleeTrailEffectL; public static GameObject meleeTrailEffectR; private Animator modelAnimator; private Transform modelTransform; private bool hasAttacked; public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); PlayCrossfade("Body", "Slam", "Slam.playbackRate", duration, 0.1f); if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)modelAnimator && modelAnimator.GetFloat("Slam.hitBoxActive") > 0.5f && !hasAttacked) { if (base.isAuthority) { if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if ((bool)modelTransform) { Transform transform = FindModelChild("SlamZone"); if ((bool)transform) { attack = new BlastAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); attack.baseDamage = damageStat * damageCoefficient; attack.baseForce = forceMagnitude; attack.position = transform.position; attack.radius = radius; attack.Fire(); } } } hasAttacked = true; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class LoomingPresence : BaseState { private Transform modelTransform; public static GameObject blinkPrefab; public static Material destealthMaterial; private float stopwatch; private UnityEngine.Vector3 blinkDestination = UnityEngine.Vector3.zero; private UnityEngine.Vector3 blinkStart = UnityEngine.Vector3.zero; public static float duration = 0.3f; public static float blinkDistance = 25f; public static string beginSoundString; public static string endSoundString; public static float destealthDuration; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); if ((bool)modelTransform) { characterModel = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); } if ((bool)characterModel) { characterModel.invisibilityCount++; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)base.characterMotor) { base.characterMotor.enabled = false; } if (base.isAuthority) { UnityEngine.Vector3 vector = base.inputBank.aimDirection * blinkDistance; blinkDestination = base.transform.position; blinkStart = base.transform.position; NodeGraph groundNodes = SceneInfo.instance.groundNodes; NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(base.transform.position + vector, base.characterBody.hullClassification); groundNodes.GetNodePosition(nodeIndex, out blinkDestination); blinkDestination += base.transform.position - base.characterBody.footPosition; vector = blinkDestination - blinkStart; CreateBlinkEffect(Util.GetCorePosition(base.gameObject), vector); } } private void CreateBlinkEffect(UnityEngine.Vector3 origin, UnityEngine.Vector3 direction) { EffectData effectData = new EffectData(); effectData.rotation = Util.QuaternionSafeLookRotation(direction); effectData.origin = origin; EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: true); } private void SetPosition(UnityEngine.Vector3 newPosition) { if ((bool)base.characterMotor) { base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if ((bool)base.characterMotor && (bool)base.characterDirection) { base.characterMotor.velocity = UnityEngine.Vector3.zero; } SetPosition(UnityEngine.Vector3.Lerp(blinkStart, blinkDestination, stopwatch / duration)); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { Util.PlaySound(endSoundString, base.gameObject); modelTransform = GetModelTransform(); if ((bool)base.characterDirection) { base.characterDirection.forward = GetAimRay().direction; } if ((bool)modelTransform && (bool)destealthMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = destealthDuration; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = destealthMaterial; temporaryOverlayInstance.inspectorCharacterModel = modelTransform.gameObject.GetComponent(); temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } if ((bool)characterModel) { characterModel.invisibilityCount--; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)base.characterMotor) { base.characterMotor.enabled = true; } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : EntityState { public static float duration = 2f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private ParentEnergyFXController FXController; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); GetModelAnimator(); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); if ((bool)spawnEffectPrefab) { EffectData effectData = new EffectData { origin = base.modelLocator.modelTransform.GetComponent().FindChild("SpawnEffectOrigin").position }; EffectManager.SpawnEffect(spawnEffectPrefab, effectData, transmit: true); } PrintController component = base.modelLocator.modelTransform.gameObject.GetComponent(); component.enabled = false; component.printTime = duration; component.startingPrintHeight = 4f; component.maxPrintHeight = -1f; component.startingPrintBias = 2f; component.maxPrintBias = 0.95f; component.disableWhenFinished = true; component.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); component.enabled = true; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Paladin { public class DashSlam : BaseState { private float stopwatch; public static float damageCoefficient = 4f; public static float baseForceMagnitude = 16f; public static float bonusImpactForce; public static string initialAttackSoundString; public static GameObject chargeEffectPrefab; public static GameObject slamEffectPrefab; public static GameObject hitEffectPrefab; public static float initialSpeedCoefficient; public static float finalSpeedCoefficient; public static float duration; public static float overlapSphereRadius; public static float blastAttackRadius; private BlastAttack attack; private Transform modelTransform; private GameObject leftHandChargeEffect; private GameObject rightHandChargeEffect; private ChildLocator modelChildLocator; private UnityEngine.Vector3 initialAimVector; private void EnableIndicator(string childLocatorName, ChildLocator childLocator = null) { if (!childLocator) { childLocator = GetModelTransform().GetComponent(); } Transform transform = childLocator.FindChild(childLocatorName); if ((bool)transform) { transform.gameObject.SetActive(value: true); ObjectScaleCurve component = transform.gameObject.GetComponent(); if ((bool)component) { component.time = 0f; } } } private void DisableIndicator(string childLocatorName, ChildLocator childLocator = null) { if (!childLocator) { childLocator = GetModelTransform().GetComponent(); } Transform transform = childLocator.FindChild(childLocatorName); if ((bool)transform) { transform.gameObject.SetActive(value: false); } } public override void OnEnter() { base.OnEnter(); modelTransform = GetModelTransform(); Util.PlaySound(initialAttackSoundString, base.gameObject); initialAimVector = UnityEngine.Vector3.ProjectOnPlane(GetAimRay().direction, UnityEngine.Vector3.up); base.characterMotor.velocity.y = 0f; base.characterDirection.forward = initialAimVector; attack = new BlastAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.baseDamage = damageCoefficient * damageStat; attack.damageType = DamageType.Stun1s; attack.baseForce = baseForceMagnitude; attack.radius = blastAttackRadius + base.characterBody.radius; attack.falloffModel = BlastAttack.FalloffModel.None; attack.attackerFiltering = AttackerFiltering.NeverHitSelf; if (!modelTransform) { return; } modelChildLocator = modelTransform.GetComponent(); if ((bool)modelChildLocator) { GameObject original = chargeEffectPrefab; Transform transform = modelChildLocator.FindChild("HandL"); Transform transform2 = modelChildLocator.FindChild("HandR"); if ((bool)transform) { leftHandChargeEffect = UnityEngine.Object.Instantiate(original, transform); } if ((bool)transform2) { rightHandChargeEffect = UnityEngine.Object.Instantiate(original, transform2); } EnableIndicator("GroundSlamIndicator", modelChildLocator); } } public override void OnExit() { if (NetworkServer.active) { attack.position = base.transform.position; attack.bonusForce = (initialAimVector + UnityEngine.Vector3.up * 0.3f) * bonusImpactForce; attack.Fire(); } if (base.isAuthority && (bool)modelTransform) { EffectManager.SimpleMuzzleFlash(slamEffectPrefab, base.gameObject, "SlamZone", transmit: true); } EntityState.Destroy(leftHandChargeEffect); EntityState.Destroy(rightHandChargeEffect); DisableIndicator("GroundSlamIndicator", modelChildLocator); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (base.isAuthority) { Collider[] colliders; int num = HGPhysics.OverlapSphere(out colliders, base.transform.position, base.characterBody.radius + overlapSphereRadius, LayerIndex.entityPrecise.mask); for (int i = 0; i < num; i++) { HurtBox component = colliders[i].GetComponent(); if ((bool)component && component.healthComponent != base.healthComponent) { HGPhysics.ReturnResults(colliders); outer.SetNextStateToMain(); return; } } } if ((bool)base.characterMotor) { float num2 = Mathf.Lerp(initialSpeedCoefficient, finalSpeedCoefficient, stopwatch / duration) * base.characterBody.moveSpeed; UnityEngine.Vector3 velocity = new UnityEngine.Vector3(initialAimVector.x * num2, 0f, initialAimVector.z * num2); base.characterMotor.velocity = velocity; base.characterMotor.moveDirection = initialAimVector; } if (stopwatch > duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class LeapSlam : BaseState { private float stopwatch; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float yBias; public static string initialAttackSoundString; public static GameObject chargeEffectPrefab; public static GameObject slamEffectPrefab; public static GameObject hitEffectPrefab; public static float leapVelocityCoefficient; public static float verticalLeapBonusCoefficient; public static float minimumDuration; private float leapVelocity; private OverlapAttack attack; private Transform modelTransform; private GameObject leftHandChargeEffect; private GameObject rightHandChargeEffect; private ChildLocator modelChildLocator; private UnityEngine.Vector3 initialAimVector; private void EnableIndicator(string childLocatorName, ChildLocator childLocator = null) { if (!childLocator) { childLocator = GetModelTransform().GetComponent(); } Transform transform = childLocator.FindChild(childLocatorName); if ((bool)transform) { transform.gameObject.SetActive(value: true); ObjectScaleCurve component = transform.gameObject.GetComponent(); if ((bool)component) { component.time = 0f; } } } private void DisableIndicator(string childLocatorName, ChildLocator childLocator = null) { if (!childLocator) { childLocator = GetModelTransform().GetComponent(); } Transform transform = childLocator.FindChild(childLocatorName); if ((bool)transform) { transform.gameObject.SetActive(value: false); } } public override void OnEnter() { base.OnEnter(); leapVelocity = base.characterBody.moveSpeed * leapVelocityCoefficient; modelTransform = GetModelTransform(); Util.PlaySound(initialAttackSoundString, base.gameObject); initialAimVector = GetAimRay().direction; initialAimVector.y = Mathf.Max(initialAimVector.y, 0f); initialAimVector.y += yBias; initialAimVector = initialAimVector.normalized; base.characterMotor.velocity.y = leapVelocity * initialAimVector.y * verticalLeapBonusCoefficient; attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.damageType = DamageType.Stun1s; attack.forceVector = UnityEngine.Vector3.up * forceMagnitude; if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "GroundSlam"); } if (!modelTransform) { return; } modelChildLocator = modelTransform.GetComponent(); if ((bool)modelChildLocator) { GameObject original = chargeEffectPrefab; Transform transform = modelChildLocator.FindChild("HandL"); Transform transform2 = modelChildLocator.FindChild("HandR"); if ((bool)transform) { leftHandChargeEffect = UnityEngine.Object.Instantiate(original, transform); } if ((bool)transform2) { rightHandChargeEffect = UnityEngine.Object.Instantiate(original, transform2); } EnableIndicator("GroundSlamIndicator", modelChildLocator); } } public override void OnExit() { if (NetworkServer.active) { attack.Fire(); } if (base.isAuthority && (bool)modelTransform) { EffectManager.SimpleMuzzleFlash(slamEffectPrefab, base.gameObject, "SlamZone", transmit: true); } EntityState.Destroy(leftHandChargeEffect); EntityState.Destroy(rightHandChargeEffect); DisableIndicator("GroundSlamIndicator", modelChildLocator); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if ((bool)base.characterMotor) { UnityEngine.Vector3 velocity = base.characterMotor.velocity; UnityEngine.Vector3 velocity2 = new UnityEngine.Vector3(initialAimVector.x * leapVelocity, velocity.y, initialAimVector.z * leapVelocity); base.characterMotor.velocity = velocity2; base.characterMotor.moveDirection = initialAimVector; } if (base.characterMotor.isGrounded && stopwatch > minimumDuration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.Paladin.PaladinWeapon { public class BarrierUp : BaseState { public static float duration = 5f; public static string soundEffectString; private float stopwatch; private PaladinBarrierController paladinBarrierController; public override void OnEnter() { base.OnEnter(); Util.PlaySound(soundEffectString, base.gameObject); stopwatch = 0f; paladinBarrierController = GetComponent(); if ((bool)paladinBarrierController) { paladinBarrierController.EnableBarrier(); } } public override void OnExit() { base.OnExit(); if ((bool)paladinBarrierController) { paladinBarrierController.DisableBarrier(); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= 0.1f && !base.inputBank.skill2.down && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireBigRocket : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static string soundEffectString; public static float damageCoefficient; public static float force; public static float baseDuration = 2f; private float duration; public override void OnEnter() { base.OnEnter(); Util.PlaySound(soundEffectString, base.gameObject); duration = baseDuration / attackSpeedStat; base.characterBody.AddSpreadBloom(1f); Ray aimRay = GetAimRay(); StartAimMode(aimRay); string muzzleName = "MuzzleCenter"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireRocket : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static string soundEffectString; public static float damageCoefficient; public static float force; public static float baseDuration = 2f; private float duration; public int bulletCountCurrent = 1; public override void OnEnter() { base.OnEnter(); Util.PlaySound(soundEffectString, base.gameObject); duration = baseDuration / attackSpeedStat; base.characterBody.AddSpreadBloom(0.3f); Ray aimRay = GetAimRay(); StartAimMode(aimRay); string muzzleName = "MuzzleCenter"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.NullifierMonster { public class DeathState : GenericCharacterDeath { public static GameObject deathBombProjectile; public static float duration; public static string muzzleName; private Transform muzzleTransform; protected override bool shouldAutoDestroy => false; protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayCrossfade("Body", "Death", "Death.playbackRate", duration, 0.1f); } public override void OnEnter() { base.OnEnter(); muzzleTransform = FindModelChild(muzzleName); if ((bool)muzzleTransform && base.isAuthority) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = deathBombProjectile; fireProjectileInfo.position = muzzleTransform.position; fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat; fireProjectileInfo.crit = base.characterBody.RollCrit(); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { DestroyModel(); if (NetworkServer.active) { DestroyBodyAsapServer(); } } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class SpawnState : BaseState { public static float duration = 4f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); if ((bool)spawnEffectPrefab) { EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "PortalEffect", transmit: false); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { modelTransform.GetComponent().enabled = true; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class AimPortalBomb : BaseState { private HurtBox target; public static float baseDuration; public static float arcMultiplier; private float duration; private UnityEngine.Vector3? pointA; private UnityEngine.Vector3? pointB; public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.viewer = base.characterBody; bullseyeSearch.searchOrigin = base.characterBody.corePosition; bullseyeSearch.searchDirection = base.characterBody.corePosition; bullseyeSearch.maxDistanceFilter = FirePortalBomb.maxDistance; bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam()); bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle; bullseyeSearch.RefreshCandidates(); target = bullseyeSearch.GetResults().FirstOrDefault(); if ((bool)target) { pointA = RaycastToFloor(target.transform.position); } } duration = baseDuration; } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority || !(base.fixedAge >= duration)) { return; } EntityState entityState = null; if ((bool)target) { pointB = RaycastToFloor(target.transform.position); if (pointA.HasValue && pointB.HasValue) { Ray aimRay = GetAimRay(); UnityEngine.Vector3 forward = pointA.Value - aimRay.origin; UnityEngine.Vector3 forward2 = pointB.Value - aimRay.origin; UnityEngine.Quaternion a = UnityEngine.Quaternion.LookRotation(forward); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.LookRotation(forward2); UnityEngine.Quaternion value = quaternion; UnityEngine.Quaternion value2 = UnityEngine.Quaternion.SlerpUnclamped(a, quaternion, 1f + arcMultiplier); entityState = new FirePortalBomb { startRotation = value, endRotation = value2 }; } } if (entityState != null) { outer.SetNextState(entityState); } else { outer.SetNextStateToMain(); } } private UnityEngine.Vector3? RaycastToFloor(UnityEngine.Vector3 position) { if (Physics.Raycast(new Ray(position, UnityEngine.Vector3.down), out var hitInfo, 10f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { return hitInfo.point; } return null; } } public class FirePortalBomb : BaseState { public static GameObject portalBombProjectileEffect; public static GameObject muzzleflashEffectPrefab; public static string muzzleString; public static int portalBombCount; public static float baseDuration; public static float maxDistance; public static float damageCoefficient; public static float procCoefficient; public static float randomRadius; public static float force; public static float minimumDistanceBetweenBombs; public UnityEngine.Quaternion? startRotation; public UnityEngine.Quaternion? endRotation; private float duration; private int bombsFired; private float fireTimer; private float fireInterval; private UnityEngine.Vector3 lastBombPosition; public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; StartAimMode(4f); if (base.isAuthority) { fireInterval = duration / (float)portalBombCount; fireTimer = 0f; } } private void FireBomb(Ray fireRay) { if (Physics.Raycast(fireRay, out var hitInfo, maxDistance, LayerIndex.world.mask)) { UnityEngine.Vector3 point = hitInfo.point; UnityEngine.Vector3 vector = point - lastBombPosition; if (bombsFired > 0 && vector.sqrMagnitude < minimumDistanceBetweenBombs * minimumDistanceBetweenBombs) { point += vector.normalized * minimumDistanceBetweenBombs; } FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = portalBombProjectileEffect; fireProjectileInfo.position = point; fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = force; fireProjectileInfo.crit = base.characterBody.RollCrit(); ProjectileManager.instance.FireProjectile(fireProjectileInfo); lastBombPosition = point; } } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } fireTimer -= GetDeltaTime(); if (fireTimer <= 0f) { fireTimer += fireInterval; if (startRotation.HasValue && endRotation.HasValue) { float num = 1f / ((float)portalBombCount - 1f); float t = (float)bombsFired * num; Ray aimRay = GetAimRay(); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Slerp(startRotation.Value, endRotation.Value, t); aimRay.direction = quaternion * UnityEngine.Vector3.forward; FireBomb(aimRay); EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true); } bombsFired++; } if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } } namespace EntityStates.NewtMonster { public class KickFromShop : BaseState { public static float duration = 3.5f; public static string attackSoundString; public static string stompSoundString; public static GameObject chargeEffectPrefab; public static GameObject stompEffectPrefab; private Animator modelAnimator; private Transform modelTransform; private bool hasAttacked; private GameObject chargeEffectInstance; private EffectManagerHelper _emh_chargeEffectInstance; public override void Reset() { base.Reset(); modelAnimator = null; modelTransform = null; hasAttacked = false; chargeEffectInstance = null; _emh_chargeEffectInstance = null; } public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); PlayCrossfade("Body", "Stomp", "Stomp.playbackRate", duration, 0.1f); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild("StompMuzzle"); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform); return; } _emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform, inResetLocal: true); chargeEffectInstance = _emh_chargeEffectInstance.gameObject; } } protected void DestroyChargeEffect() { if (chargeEffectInstance != null) { if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null) { _emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance); } else { EntityState.Destroy(chargeEffectInstance); } chargeEffectInstance = null; _emh_chargeEffectInstance = null; } } public override void OnExit() { DestroyChargeEffect(); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)modelAnimator && modelAnimator.GetFloat("Stomp.hitBoxActive") > 0.5f && !hasAttacked) { Util.PlayAttackSpeedSound(stompSoundString, base.gameObject, attackSpeedStat); EffectManager.SimpleMuzzleFlash(stompEffectPrefab, base.gameObject, "HealthBarOrigin", transmit: false); if ((bool)SceneInfo.instance) { GameObject gameObject = SceneInfo.instance.transform.Find("KickOutOfShop").gameObject; if ((bool)gameObject) { gameObject.gameObject.SetActive(value: true); } } if (base.isAuthority) { HurtBoxGroup component = modelTransform.GetComponent(); if ((bool)component) { int hurtBoxesDeactivatorCounter = component.hurtBoxesDeactivatorCounter + 1; component.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } } hasAttacked = true; DestroyChargeEffect(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : EntityState { public static float duration = 2f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); GetModelAnimator(); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); if ((bool)spawnEffectPrefab) { EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "SpawnEffectOrigin", transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.MoonElevator { public abstract class MoonElevatorBaseState : BaseState { [SerializeField] public float duration; [SerializeField] public string enterSfxString; protected GenericInteraction genericInteraction; public virtual EntityState nextState => new Uninitialized(); public virtual Interactability interactability => Interactability.Disabled; public virtual bool goToNextStateAutomatically => false; public virtual bool showBaseEffects => false; public override void OnEnter() { base.OnEnter(); genericInteraction = GetComponent(); Util.PlaySound(enterSfxString, base.gameObject); if (NetworkServer.active) { genericInteraction.Networkinteractability = interactability; if (interactability == Interactability.Available) { genericInteraction.onActivation?.AddListener(OnInteractionBegin); } } FindModelChild("EffectBase").gameObject.SetActive(showBaseEffects); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration && base.isAuthority && goToNextStateAutomatically) { outer.SetNextState(nextState); } } protected virtual void OnInteractionBegin(Interactor activator) { } } public class Inactive : MoonElevatorBaseState { private static int InactiveStateHash = Animator.StringToHash("Inactive"); public override Interactability interactability => Interactability.ConditionsNotMet; public override bool goToNextStateAutomatically => false; public override bool showBaseEffects => false; public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", InactiveStateHash); } } public class InactiveToReady : MoonElevatorBaseState { private static int InactiveToActiveStateHash = Animator.StringToHash("InactiveToActive"); private static int playbackRateParamHash = Animator.StringToHash("playbackRate"); public override Interactability interactability => Interactability.Disabled; public override bool goToNextStateAutomatically => true; public override EntityState nextState => new Ready(); public override bool showBaseEffects => true; public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", InactiveToActiveStateHash, playbackRateParamHash, duration); } } public class Ready : MoonElevatorBaseState { private static int ReadyStateHash = Animator.StringToHash("Ready"); public override Interactability interactability => Interactability.Available; public override bool goToNextStateAutomatically => false; public override bool showBaseEffects => true; public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", ReadyStateHash); } protected override void OnInteractionBegin(Interactor activator) { base.OnInteractionBegin(activator); _ = base.isAuthority; } } } namespace EntityStates.BrotherHaunt { public class FireRandomProjectiles : BaseState { public static GameObject projectilePrefab; public static float damageCoefficient; public static int initialCharges; public static int maximumCharges; public static float chargeRechargeDuration; public static float chanceToFirePerSecond; public static float projectileVerticalOffset; private int charges; private float chargeTimer; public override void OnEnter() { base.OnEnter(); charges = initialCharges; } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { chargeTimer -= GetDeltaTime(); if (chargeTimer <= 0f) { chargeTimer = chargeRechargeDuration; charges = Mathf.Min(charges + 1, maximumCharges); } if (UnityEngine.Random.value < chanceToFirePerSecond && charges > 0) { FireProjectile(); } } } private void FireProjectile() { NodeGraph groundNodes = SceneInfo.instance.groundNodes; if ((bool)groundNodes) { List activeNodesForHullMaskWithFlagConditions = groundNodes.GetActiveNodesForHullMaskWithFlagConditions(HullMask.Golem, NodeFlags.None, NodeFlags.NoCharacterSpawn); NodeGraph.NodeIndex nodeIndex = activeNodesForHullMaskWithFlagConditions[UnityEngine.Random.Range(0, activeNodesForHullMaskWithFlagConditions.Count)]; charges--; groundNodes.GetNodePosition(nodeIndex, out var position); ProjectileManager.instance.FireProjectile(new FireProjectileInfo { projectilePrefab = projectilePrefab, owner = base.gameObject, damage = damageStat * damageCoefficient, position = position + UnityEngine.Vector3.up * projectileVerticalOffset, rotation = UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f) }); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Missions.SuperRoboBallEncounter { public class Listening : EntityState { public static float delayBeforeBeginningEncounter; public static int eggsDestroyedToTriggerEncounter; private ScriptedCombatEncounter scriptedCombatEncounter; private List eggList = new List(); private const float delayBeforeRegisteringEggs = 2f; private bool hasRegisteredEggs; private int previousDestroyedEggCount; private bool beginEncounterCountdown; private float encounterCountdown; public override void OnEnter() { base.OnEnter(); scriptedCombatEncounter = GetComponent(); } public override void FixedUpdate() { base.FixedUpdate(); if (!NetworkServer.active) { return; } if (base.fixedAge >= 2f) { RegisterEggs(); } if (!hasRegisteredEggs) { return; } int num = 0; for (int i = 0; i < eggList.Count; i++) { if (eggList[i] == null) { num++; } } int num2 = eggsDestroyedToTriggerEncounter - 1; if (previousDestroyedEggCount < num2 && num >= num2) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "VULTURE_EGG_WARNING" }); } if (num >= eggsDestroyedToTriggerEncounter && !beginEncounterCountdown) { encounterCountdown = delayBeforeBeginningEncounter; beginEncounterCountdown = true; Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "VULTURE_EGG_BEGIN" }); } if (beginEncounterCountdown) { encounterCountdown -= GetDeltaTime(); if (encounterCountdown <= 0f) { scriptedCombatEncounter.BeginEncounter(); outer.SetNextState(new Idle()); } } previousDestroyedEggCount = num; } private void RegisterEggs() { if (hasRegisteredEggs) { return; } ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { if (readOnlyInstancesList[i].name.Contains("VultureEgg")) { eggList.Add(readOnlyInstancesList[i].gameObject); } } hasRegisteredEggs = true; } } } namespace EntityStates.Missions.RaidGauntletEncounterSlowDeath { public class Listening : EntityState { public static float delayBeforeBeginningEncounter; public static int shardsDestroyedToTriggerEncounter; private List shardList = new List(); private const float delayBeforeRegisteringShards = 2f; private bool hasRegisteredShards; private int previousDestroyedShardCount; private bool beginEncounterCountdown; private bool beginGauntletCountdown; private bool gauntletTwentySecondWarning; private bool gauntletTenSecondWarning; private bool gauntletFiveSecondWarning; private bool beginGauntletFinalCountdown; private const float delayBeforeBeginningGauntletCountdown = 15f; private float gauntletFinalCountdown; private int secondsRemaining = 4; private bool gauntletEnd; private int totalSeconds; private GameObject slowDeathEffect; private bool slowDeathEffectActive; private GauntletMissionController gauntletMissionController; private GameObject gMC; private float degenTickFrequency; private float percentDegenPerSecond; private bool hasGauntletMissionController; private bool theEnd; public override void OnEnter() { base.OnEnter(); } public override void FixedUpdate() { base.FixedUpdate(); if (!NetworkServer.active) { return; } if (base.fixedAge >= 2f) { RegisterShards(); RegisterGauntletMissionController(); } if (base.fixedAge >= 15f && !beginGauntletCountdown) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_START" }); beginGauntletCountdown = true; } if (base.fixedAge >= 25f && !gauntletTwentySecondWarning) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_TWENTY_SECONDS_WARNING" }); gauntletTwentySecondWarning = true; } if (base.fixedAge >= 35f && !gauntletTenSecondWarning) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_TEN_SECONDS_WARNING" }); gauntletTenSecondWarning = true; } if (base.fixedAge >= 40f && !gauntletFiveSecondWarning) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_FIVE_SECONDS_WARNING" }); gauntletFiveSecondWarning = true; beginGauntletFinalCountdown = true; } if (!hasRegisteredShards) { return; } int num = 0; for (int i = 0; i < shardList.Count; i++) { if (shardList[i] == null) { num++; } } if (previousDestroyedShardCount != num) { _ = shardsDestroyedToTriggerEncounter; } int num2 = shardsDestroyedToTriggerEncounter - 1; if (previousDestroyedShardCount < num2 && num >= num2) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_ONE_SHARD_REMAINING" }); } if (num >= shardsDestroyedToTriggerEncounter && !beginEncounterCountdown) { beginEncounterCountdown = true; Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_ALL_SHARDS_DESTROYED" }); } if (beginGauntletFinalCountdown && !gauntletEnd) { gauntletFinalCountdown += GetDeltaTime(); if (gauntletFinalCountdown >= 1f) { secondsRemaining--; totalSeconds++; if (totalSeconds == 1) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_FOUR_SECONDS_REMAINING" }); } else if (totalSeconds == 2) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_THREE_SECONDS_REMAINING" }); } else if (totalSeconds == 3) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_TWO_SECONDS_REMAINING" }); } else if (totalSeconds == 4) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_ONE_SECOND_REMAINING" }); } gauntletFinalCountdown = 0f; } if (secondsRemaining == 0) { gauntletEnd = true; Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_SLOWDEATH_END" }); } } if (gauntletEnd && !theEnd) { gauntletMissionController.GauntletMissionTimesUp(); theEnd = true; } previousDestroyedShardCount = num; } private void RegisterShards() { if (hasRegisteredShards) { return; } ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { if (readOnlyInstancesList[i].name.Contains("GauntletShard")) { shardList.Add(readOnlyInstancesList[i].gameObject); } } shardsDestroyedToTriggerEncounter = shardList.Count; hasRegisteredShards = true; } private void RegisterGauntletMissionController() { if (!hasGauntletMissionController) { gMC = GameObject.Find("GauntletMissionController"); gauntletMissionController = gMC.GetComponent(); if ((bool)gauntletMissionController) { slowDeathEffect = gauntletMissionController.clearedEffect; degenTickFrequency = gauntletMissionController.degenTickFrequency; percentDegenPerSecond = gauntletMissionController.percentDegenPerSecond; hasGauntletMissionController = true; } } } } } namespace EntityStates.Missions.RaidGauntletEncounter { public class Listening : EntityState { public static float delayBeforeBeginningEncounter; public static int shardsDestroyedToTriggerEncounter = 5; private GameObject exitPortal; private List shardList = new List(); private const float delayBeforeRegisteringShards = 2f; private bool hasRegisteredShards; private int previousDestroyedShardCount; private bool beginEncounterCountdown; private bool beginGauntletCountdown; private bool gauntletTwentySecondWarning; private bool gauntletTenSecondWarning; private bool gauntletFiveSecondWarning; private bool beginGauntletFinalCountdown; private const float delayBeforeBeginningGauntletCountdown = 15f; private float gauntletFinalCountdown; private int secondsRemaining = 4; private bool gauntletEnd; private bool hasExitPortal; private int totalSeconds; public override void OnEnter() { base.OnEnter(); } public override void FixedUpdate() { base.FixedUpdate(); if (!NetworkServer.active) { return; } if (base.fixedAge >= 2f) { RegisterShards(); RegisterExitPortal(); } if (base.fixedAge >= 15f && !beginGauntletCountdown) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_START" }); Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_FIVE_SHARDS_REMAINING" }); beginGauntletCountdown = true; } if (base.fixedAge >= 25f && !gauntletTwentySecondWarning) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_TWENTY_SECONDS_WARNING" }); gauntletTwentySecondWarning = true; } if (base.fixedAge >= 35f && !gauntletTenSecondWarning) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_TEN_SECONDS_WARNING" }); gauntletTenSecondWarning = true; } if (base.fixedAge >= 40f && !gauntletFiveSecondWarning) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_FIVE_SECONDS_WARNING" }); gauntletFiveSecondWarning = true; beginGauntletFinalCountdown = true; } if (!hasRegisteredShards) { return; } int num = 0; for (int i = 0; i < shardList.Count; i++) { if (shardList[i] == null) { num++; } } if (previousDestroyedShardCount != num) { switch (shardsDestroyedToTriggerEncounter - num) { case 4: Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_FOUR_SHARDS_REMAINING" }); break; case 3: Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_THREE_SHARDS_REMAINING" }); break; case 2: Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_TWO_SHARDS_REMAINING" }); break; } } int num2 = shardsDestroyedToTriggerEncounter - 1; if (previousDestroyedShardCount < num2 && num >= num2) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_ONE_SHARD_REMAINING" }); } if (num >= shardsDestroyedToTriggerEncounter && !beginEncounterCountdown) { beginEncounterCountdown = true; Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_ALL_SHARDS_DESTROYED" }); } if (beginGauntletFinalCountdown && !gauntletEnd) { gauntletFinalCountdown += GetDeltaTime(); if (gauntletFinalCountdown >= 1f) { secondsRemaining--; totalSeconds++; if (totalSeconds == 1) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_FOUR_SECONDS_REMAINING" }); } else if (totalSeconds == 2) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_THREE_SECONDS_REMAINING" }); } else if (totalSeconds == 3) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_TWO_SECONDS_REMAINING" }); } else if (totalSeconds == 4) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_ONE_SECOND_REMAINING" }); } gauntletFinalCountdown = 0f; } if (secondsRemaining == 0) { gauntletEnd = true; exitPortal.SetActive(value: false); Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "GAUNTLET_END" }); } } previousDestroyedShardCount = num; } private void RegisterShards() { if (hasRegisteredShards) { return; } ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { if (readOnlyInstancesList[i].name.Contains("GauntletShard")) { shardList.Add(readOnlyInstancesList[i].gameObject); } } hasRegisteredShards = true; } private void RegisterExitPortal() { if (!hasExitPortal) { exitPortal = GameObject.Find("PortalArena"); if ((bool)exitPortal) { hasExitPortal = true; } } } } } namespace EntityStates.Missions.Moon { public abstract class MoonBatteryBaseState : BaseState { protected PurchaseInteraction purchaseInteraction; protected Animator[] animators; public override void OnEnter() { base.OnEnter(); purchaseInteraction = GetComponent(); animators = outer.GetComponentsInChildren(); } } public class MoonBatteryInactive : MoonBatteryBaseState { public override void OnEnter() { base.OnEnter(); purchaseInteraction.SetAvailable(newAvailable: true); FindModelChild("InactiveFX").gameObject.SetActive(value: true); } public override void OnExit() { FindModelChild("InactiveFX").gameObject.SetActive(value: false); purchaseInteraction.SetAvailable(newAvailable: false); base.OnExit(); } } public class MoonBatteryActive : MoonBatteryBaseState { public static string soundEntryEvent; public static string soundLoopStartEvent; public static string soundLoopEndEvent; public static string soundExitEvent; public static string activeTriggerName; public static string completeTriggerName; private HoldoutZoneController holdoutZoneController; private ChargeIndicatorController chargeIndicatorController; private static int ActivecycleOffsetParamHash = Animator.StringToHash("Active.cycleOffset"); public override void OnEnter() { base.OnEnter(); holdoutZoneController = GetComponent(); holdoutZoneController.enabled = true; if (NetworkServer.active) { GetComponent().enabled = true; } Animator[] array = animators; for (int i = 0; i < array.Length; i++) { array[i].SetTrigger(activeTriggerName); } Util.PlaySound(soundEntryEvent, base.gameObject); Util.PlaySound(soundLoopStartEvent, base.gameObject); FindModelChild("ChargingFX").gameObject.SetActive(value: true); Transform targetTransform = FindModelChild("PositionIndicatorPosition").transform; PositionIndicator component = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/PositionIndicators/PillarChargingPositionIndicator"), base.transform.position, UnityEngine.Quaternion.identity).GetComponent(); component.targetTransform = targetTransform; chargeIndicatorController = component.GetComponent(); chargeIndicatorController.holdoutZoneController = holdoutZoneController; } public override void Update() { base.Update(); if ((bool)holdoutZoneController) { Animator[] array = animators; for (int i = 0; i < array.Length; i++) { array[i].SetFloat(ActivecycleOffsetParamHash, holdoutZoneController.charge * 0.99f); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && holdoutZoneController.charge >= 1f) { outer.SetNextState(new MoonBatteryComplete()); } } public override void OnExit() { FindModelChild("ChargingFX").gameObject.SetActive(value: false); if ((bool)holdoutZoneController) { holdoutZoneController.enabled = false; } Animator[] array = animators; for (int i = 0; i < array.Length; i++) { array[i].SetTrigger(completeTriggerName); } Util.PlaySound(soundLoopEndEvent, base.gameObject); Util.PlaySound(soundExitEvent, base.gameObject); if ((bool)chargeIndicatorController) { EntityState.Destroy(chargeIndicatorController.gameObject); } base.OnExit(); } } public class MoonBatteryComplete : MoonBatteryBaseState { public override void OnEnter() { base.OnEnter(); FindModelChild("ChargedFX").gameObject.SetActive(value: true); } } public class MoonBatteryDisabled : MoonBatteryBaseState { } public class MoonBatteryDesignActive : MoonBatteryActive { private TeamFilter teamFilter; public static GameObject pulsePrefab; public static float pulseInterval; public static BuffDef buffDef; public static float buffDuration; public static float baseForce; private float pulseTimer; public override void OnEnter() { base.OnEnter(); teamFilter = GetComponent(); pulseTimer = 0f; } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { pulseTimer -= GetDeltaTime(); if (pulseTimer < 0f) { pulseTimer = pulseInterval; CreatePulseServer(); } } } private void CreatePulseServer() { if (!FindModelChild("PulseOrigin")) { _ = base.transform; } GameObject obj = UnityEngine.Object.Instantiate(pulsePrefab, base.transform.position, base.transform.rotation); SphereSearch sphereSearch = new SphereSearch(); PulseController component = obj.GetComponent(); component.performSearch += PerformPulseSearch; component.onPulseHit += OnPulseHit; component.StartPulseServer(); NetworkServer.Spawn(obj); static void OnPulseHit(PulseController _, PulseController.PulseHit hitInfo) { HealthComponent healthComponent = hitInfo.hitObject as HealthComponent; if ((bool)healthComponent) { CharacterBody body = healthComponent.body; if ((bool)body.characterMotor && body.characterMotor.isGrounded) { UnityEngine.Vector3 normalized = (hitInfo.hitPos - hitInfo.pulseOrigin).normalized; body.characterMotor.ApplyForce(normalized * (baseForce * hitInfo.hitSeverity)); body.AddTimedBuff(buffDef, buffDuration); } } } void PerformPulseSearch(PulseController _, UnityEngine.Vector3 origin, float radius, List dest) { TeamMask none = TeamMask.none; none.AddTeam(teamFilter.teamIndex); sphereSearch.origin = origin; sphereSearch.radius = radius; sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.Ignore; sphereSearch.mask = LayerIndex.entityPrecise.mask; sphereSearch.RefreshCandidates(); sphereSearch.FilterCandidatesByHurtBoxTeam(none); sphereSearch.OrderCandidatesByDistance(); sphereSearch.FilterCandidatesByDistinctHurtBoxEntities(); List list = CollectionPool>.RentCollection(); sphereSearch.GetHurtBoxes(list); for (int i = 0; i < list.Count; i++) { HurtBox hurtBox = list[i]; if ((bool)hurtBox) { _ = hurtBox.healthComponent; if ((bool)hurtBox.healthComponent) { UnityEngine.Vector3 vector = hurtBox.collider.ClosestPoint(origin); UnityEngine.Vector3.Distance(origin, vector); PulseController.PulseSearchResult pulseSearchResult = default(PulseController.PulseSearchResult); pulseSearchResult.hitObject = hurtBox.healthComponent; pulseSearchResult.hitPos = vector; PulseController.PulseSearchResult item = pulseSearchResult; dest.Add(item); } } } list = CollectionPool>.ReturnCollection(list); } } } public class MoonBatteryBloodActive : MoonBatteryActive { [SerializeField] public GameObject siphonPrefab; [SerializeField] public string siphonRootName; private GameObject siphonObject; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { Transform transform = FindModelChild(siphonRootName); if (!transform) { transform = base.transform; } siphonObject = UnityEngine.Object.Instantiate(siphonPrefab, transform.position, transform.rotation, transform); NetworkServer.Spawn(siphonObject); } } public override void OnExit() { if (NetworkServer.active && (bool)siphonObject) { NetworkServer.Destroy(siphonObject); } base.OnExit(); } } } namespace EntityStates.Missions.GeodeSecretMission { public class GeodeSecretMissionEntityStates : EntityState { protected GeodeSecretMissionController geodeSecretMissionController; public override void OnEnter() { geodeSecretMissionController = base.gameObject.GetComponent(); base.OnEnter(); } } public class GeodeSecretMissionEntryState : GeodeSecretMissionEntityStates { } public class GeodeSecretMissionRewardState : GeodeSecretMissionEntityStates { private Xoroshiro128Plus rng; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); DropRewards(); } } public void DropRewards() { int participatingPlayerCount = Run.instance.participatingPlayerCount; if (participatingPlayerCount > 0 && (bool)base.gameObject && (bool)geodeSecretMissionController.rewardDropTable) { int num = geodeSecretMissionController.numberOfRewardsSpawned; if (geodeSecretMissionController.increaseRewardPerPlayer) { num *= participatingPlayerCount; } float angle = 360f / (float)num; UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); UnityEngine.Vector3 position = geodeSecretMissionController.rewardSpawnLocation.transform.position; int num2 = 0; while (num2 < num) { GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo); pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(geodeSecretMissionController.rewardDisplayTier); pickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTablePlusForcedStorm(geodeSecretMissionController.numberOfRewardOptions, geodeSecretMissionController.rewardDropTable, geodeSecretMissionController.rewardDropTable, rng); pickupInfo.rotation = UnityEngine.Quaternion.identity; pickupInfo.prefabOverride = geodeSecretMissionController.rewardPrefab; PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector); num2++; vector = quaternion * vector; } } } } } namespace EntityStates.Missions.LunarScavengerEncounter { public class WaitForAllMonstersDead : BaseState { public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { FixedUpdateServer(); } } private void FixedUpdateServer() { if (TeamComponent.GetTeamMembers(TeamIndex.Monster).Count == 0) { outer.SetNextState(new FadeOut()); } } } public class FadeOut : BaseState { public static float delay; public static float duration; private Run.TimeStamp startTime; private Light light; private float initialIntensity; private float initialAmbientIntensity; private UnityEngine.Color initialAmbientColor; private UnityEngine.Color initialFogColor; private PostProcessVolume postProcessVolume; private bool finished; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { startTime = Run.TimeStamp.now + delay; } light = GetComponent().FindChild("PrimaryLight").GetComponent(); initialIntensity = light.intensity; initialAmbientIntensity = RenderSettings.ambientIntensity; initialAmbientColor = RenderSettings.ambientLight; initialFogColor = RenderSettings.fogColor; light.GetComponent().enabled = false; postProcessVolume = GetComponent(); postProcessVolume.enabled = true; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(startTime); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); startTime = reader.ReadTimeStamp(); } public override void Update() { base.Update(); float num = Mathf.Clamp01(startTime.timeSince / duration); num *= num; light.intensity = Mathf.Lerp(initialIntensity, 0f, num); RenderSettings.ambientIntensity = Mathf.Lerp(initialAmbientIntensity, 0f, num); RenderSettings.ambientLight = UnityEngine.Color.Lerp(initialAmbientColor, UnityEngine.Color.black, num); RenderSettings.fogColor = UnityEngine.Color.Lerp(initialFogColor, UnityEngine.Color.black, num); if (!Mathf.Approximately(postProcessVolume.weight, num)) { PostProcessVolume.DispatchVolumeSettingsChangedEvent(); } postProcessVolume.weight = num; } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { FixedUpdateServer(); } if (!(startTime.timeSince > duration)) { return; } foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { if (readOnlyInstances.hasEffectiveAuthority) { EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(readOnlyInstances.gameObject, "Body"); if ((bool)entityStateMachine && !(entityStateMachine.state is Idle)) { entityStateMachine.SetInterruptState(new Idle(), InterruptPriority.Frozen); } } } } private void FixedUpdateServer() { if ((startTime + duration).hasPassed && !finished) { finished = true; Run.instance.BeginGameOver(RoR2Content.GameEndings.LimboEnding); } } } } namespace EntityStates.Missions.Goldshores { public class ActivateBeacons : EntityState { public override void OnEnter() { base.OnEnter(); if ((bool)GoldshoresMissionController.instance) { GoldshoresMissionController.instance.SpawnBeacons(); } } public override void OnExit() { base.OnExit(); if (!outer.destroying && (bool)GoldshoresMissionController.instance) { GoldshoresMissionController.instance.BeginTransitionIntoBossfight(); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)GoldshoresMissionController.instance && GoldshoresMissionController.instance.beaconsActive >= GoldshoresMissionController.instance.beaconsRequiredToSpawnBoss) { outer.SetNextState(new GoldshoresBossfight()); } } } public class Exit : EntityState { public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(LegacyResourcesAPI.Load("SpawnCards/InteractableSpawnCard/iscGoldshoresPortal"), new DirectorPlacementRule { maxDistance = float.PositiveInfinity, minDistance = 10f, placementMode = DirectorPlacementRule.PlacementMode.NearestNode, position = base.transform.position, spawnOnTarget = GoldshoresMissionController.instance.bossSpawnPosition }, Run.instance.stageRng)); if ((bool)gameObject) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "PORTAL_GOLDSHORES_OPEN" }); gameObject.GetComponent().useRunNextStageScene = true; } if ((string.IsNullOrEmpty("FalseSonBossComplete") || !Run.instance.GetEventFlag("FalseSonBossComplete")) && IsValidStormTier() && (bool)DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(LegacyResourcesAPI.Load("SpawnCards/InteractableSpawnCard/iscColossusPortal"), new DirectorPlacementRule { maxDistance = 30f, minDistance = 10f, placementMode = DirectorPlacementRule.PlacementMode.NearestNode, position = base.transform.position }, Run.instance.stageRng))) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "PORTAL_STORM_OPEN" }); } for (int num = CombatDirector.instancesList.Count - 1; num >= 0; num--) { CombatDirector.instancesList[num].enabled = false; } } } private bool IsValidStormTier() { Run instance = Run.instance; int stageOrder = instance.nextStageScene.stageOrder; ExpansionDef requiredExpansion = GoldshoresMissionController.instance.requiredExpansion; if (instance.IsExpansionEnabled(requiredExpansion) && (stageOrder == 2 || stageOrder == 3 || stageOrder == 4)) { return true; } return false; } public override void OnExit() { base.OnExit(); } } public class GoldshoresBossfight : EntityState { private GoldshoresMissionController missionController; public static float shieldRemovalDuration; public static GameObject shieldRemovalEffectPrefab; public static GameObject shieldRegenerationEffectPrefab; public static GameObject combatEncounterPrefab; private static float transitionDuration = 3f; private bool hasSpawnedBoss; private int serverCycleCount; private Run.FixedTimeStamp bossInvulnerabilityStartTime; private ScriptedCombatEncounter scriptedCombatEncounter; private bool bossImmunity; private bool bossShouldBeInvulnerable => missionController.beaconsActive < missionController.beaconsToSpawnOnMap; public static event Action onOneCycleGoldTitanKill; public override void OnEnter() { base.OnEnter(); missionController = GetComponent(); bossInvulnerabilityStartTime = Run.FixedTimeStamp.negativeInfinity; } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { ServerFixedUpdate(); } } private void SetBossImmunity(bool newBossImmunity) { if (!scriptedCombatEncounter || newBossImmunity == bossImmunity) { return; } bossImmunity = newBossImmunity; foreach (CharacterMaster readOnlyMembers in scriptedCombatEncounter.combatSquad.readOnlyMembersList) { CharacterBody body = readOnlyMembers.GetBody(); if ((bool)body) { if (bossImmunity) { body.AddBuff(RoR2Content.Buffs.Immune); continue; } EffectManager.SpawnEffect(shieldRemovalEffectPrefab, new EffectData { origin = body.coreTransform.position }, transmit: true); body.RemoveBuff(RoR2Content.Buffs.Immune); } } } private void ExtinguishBeacons() { foreach (GameObject beaconInstance in missionController.beaconInstanceList) { beaconInstance.GetComponent().SetNextState(new NotReady()); } } private void ServerFixedUpdate() { if (base.fixedAge >= transitionDuration) { missionController.ExitTransitionIntoBossfight(); if (!hasSpawnedBoss) { SpawnBoss(); } else if (scriptedCombatEncounter.combatSquad.readOnlyMembersList.Count == 0) { outer.SetNextState(new Exit()); if (serverCycleCount < 1) { GoldshoresBossfight.onOneCycleGoldTitanKill?.Invoke(); } return; } } if (!scriptedCombatEncounter) { return; } if (!bossImmunity) { if (bossInvulnerabilityStartTime.hasPassed) { ExtinguishBeacons(); SetBossImmunity(newBossImmunity: true); serverCycleCount++; } } else if (missionController.beaconsActive >= missionController.beaconsToSpawnOnMap) { SetBossImmunity(newBossImmunity: false); bossInvulnerabilityStartTime = Run.FixedTimeStamp.now + shieldRemovalDuration; } } private void SpawnBoss() { if (!hasSpawnedBoss) { if (!scriptedCombatEncounter) { scriptedCombatEncounter = UnityEngine.Object.Instantiate(combatEncounterPrefab).GetComponent(); scriptedCombatEncounter.GetComponent().dropPosition = missionController.bossSpawnPosition; NetworkServer.Spawn(scriptedCombatEncounter.gameObject); } scriptedCombatEncounter.BeginEncounter(); hasSpawnedBoss = scriptedCombatEncounter.hasSpawnedServer; if (hasSpawnedBoss) { SetBossImmunity(newBossImmunity: true); } } } } } namespace EntityStates.Missions.BrotherEncounter { public class BrotherEncounterBaseState : EntityState { protected ChildLocator childLocator; protected virtual bool shouldEnableArenaWalls => true; protected virtual bool shouldEnableArenaNodes => true; public override void OnEnter() { base.OnEnter(); childLocator = GetComponent(); Transform transform = childLocator.FindChild("ArenaWalls"); Transform transform2 = childLocator.FindChild("ArenaNodes"); if ((bool)transform) { transform.gameObject.SetActive(shouldEnableArenaWalls); } if ((bool)transform2) { transform2.gameObject.SetActive(shouldEnableArenaNodes); } } public override void OnExit() { base.OnExit(); } public void KillAllMonsters() { if (!NetworkServer.active) { return; } foreach (TeamComponent item in new List(TeamComponent.GetTeamMembers(TeamIndex.Monster))) { if ((bool)item) { HealthComponent component = item.GetComponent(); if ((bool)component) { component.Suicide(); } } } } } public abstract class BrotherEncounterPhaseBaseState : BrotherEncounterBaseState { [SerializeField] public float durationBeforeEnablingCombatEncounter; [SerializeField] public GameObject speechControllerPrefab; protected ScriptedCombatEncounter phaseScriptedCombatEncounter; protected GameObject phaseControllerObject; protected GameObject phaseControllerSubObjectContainer; protected BossGroup phaseBossGroup; private bool hasSpawned; private bool finishedServer; private const float minimumDurationPerPhase = 2f; private Run.FixedTimeStamp healthBarShowTime = Run.FixedTimeStamp.positiveInfinity; protected abstract EntityState nextState { get; } protected abstract string phaseControllerChildString { get; } protected virtual float healthBarShowDelay => 0f; public override void OnEnter() { base.OnEnter(); if ((bool)PhaseCounter.instance) { PhaseCounter.instance.GoToNextPhase(); } if ((bool)childLocator) { phaseControllerObject = childLocator.FindChild(phaseControllerChildString).gameObject; if ((bool)phaseControllerObject) { phaseScriptedCombatEncounter = phaseControllerObject.GetComponent(); phaseBossGroup = phaseControllerObject.GetComponent(); phaseControllerSubObjectContainer = phaseControllerObject.transform.Find("PhaseObjects").gameObject; phaseControllerSubObjectContainer.SetActive(value: true); } GameObject gameObject = childLocator.FindChild("AllPhases").gameObject; if ((bool)gameObject) { gameObject.SetActive(value: true); } } healthBarShowTime = Run.FixedTimeStamp.now + healthBarShowDelay; if ((bool)DirectorCore.instance) { CombatDirector[] components = DirectorCore.instance.GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].enabled = false; } } if (NetworkServer.active && (object)phaseScriptedCombatEncounter != null) { phaseScriptedCombatEncounter.combatSquad.onMemberAddedServer += OnMemberAddedServer; } } public override void OnExit() { if ((object)phaseScriptedCombatEncounter != null) { phaseScriptedCombatEncounter.combatSquad.onMemberAddedServer -= OnMemberAddedServer; } if ((bool)phaseControllerSubObjectContainer) { phaseControllerSubObjectContainer.SetActive(value: false); } if ((bool)phaseBossGroup) { phaseBossGroup.shouldDisplayHealthBarOnHud = false; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); phaseBossGroup.shouldDisplayHealthBarOnHud = healthBarShowTime.hasPassed; if (!hasSpawned) { if (base.fixedAge > durationBeforeEnablingCombatEncounter) { BeginEncounter(); } } else if (NetworkServer.active && !finishedServer && base.fixedAge > 2f + durationBeforeEnablingCombatEncounter && (bool)phaseScriptedCombatEncounter && phaseScriptedCombatEncounter.combatSquad.memberCount == 0) { finishedServer = true; outer.SetNextState(nextState); } } protected void BeginEncounter() { hasSpawned = true; PreEncounterBegin(); if (NetworkServer.active) { phaseScriptedCombatEncounter.BeginEncounter(); } } protected virtual void PreEncounterBegin() { } protected virtual void OnMemberAddedServer(CharacterMaster master) { if ((bool)speechControllerPrefab) { UnityEngine.Object.Instantiate(speechControllerPrefab, master.transform).GetComponent().characterMaster = master; } } } public class PreEncounter : BaseState { public static float duration; private ChildLocator childLocator; public override void OnEnter() { base.OnEnter(); childLocator = GetComponent(); childLocator.FindChild("PreEncounter").gameObject.SetActive(value: true); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new Phase1()); } } public override void OnExit() { childLocator.FindChild("PreEncounter").gameObject.SetActive(value: false); base.OnExit(); } } public class Phase1 : BrotherEncounterPhaseBaseState { public static string prespawnSoundString; public static float prespawnSoundDelay; public static GameObject centerOrbDestroyEffect; private bool hasPlayedPrespawnSound; protected override string phaseControllerChildString => "Phase1"; protected override EntityState nextState => new Phase2(); public override void OnEnter() { KillAllMonsters(); base.OnEnter(); } protected override void PreEncounterBegin() { base.PreEncounterBegin(); Transform transform = childLocator.FindChild("CenterOrbEffect"); transform.gameObject.SetActive(value: false); EffectManager.SpawnEffect(centerOrbDestroyEffect, new EffectData { origin = transform.transform.position }, transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (!hasPlayedPrespawnSound && base.fixedAge > prespawnSoundDelay) { Transform transform = childLocator.FindChild("CenterOrbEffect"); Util.PlaySound(prespawnSoundString, transform.gameObject); hasPlayedPrespawnSound = true; } } protected override void OnMemberAddedServer(CharacterMaster master) { base.OnMemberAddedServer(master); } } public class Phase2 : BrotherEncounterPhaseBaseState { public static float delayBetweenPillarActivation; private List pillarsToActive = new List(); private float pillarActivationStopwatch; protected override string phaseControllerChildString => "Phase2"; protected override EntityState nextState => new Phase3(); public override void OnEnter() { base.OnEnter(); GameObject gameObject = childLocator.FindChild("BlockingPillars").gameObject; if ((bool)gameObject) { gameObject.SetActive(value: true); for (int i = 0; i < gameObject.transform.childCount; i++) { pillarsToActive.Add(gameObject.transform.GetChild(i).gameObject); } } } public override void FixedUpdate() { base.FixedUpdate(); pillarActivationStopwatch += GetDeltaTime(); if (pillarsToActive.Count > 0 && pillarActivationStopwatch > delayBetweenPillarActivation) { pillarActivationStopwatch = 0f; pillarsToActive[0].SetActive(value: true); pillarsToActive.RemoveAt(0); } } } public class Phase3 : BrotherEncounterPhaseBaseState { protected override string phaseControllerChildString => "Phase3"; protected override EntityState nextState => new Phase4(); public override void OnEnter() { base.OnEnter(); } public override void OnExit() { KillAllMonsters(); base.OnExit(); } protected override void OnMemberAddedServer(CharacterMaster master) { base.OnMemberAddedServer(master); if (!master.hasBody) { return; } CharacterBody body = master.GetBody(); if ((bool)body) { CharacterDeathBehavior component = body.GetComponent(); if ((bool)component) { component.deathState = new SerializableEntityStateType(typeof(InstantDeathState)); } } } } public class Phase4 : BrotherEncounterPhaseBaseState { protected override string phaseControllerChildString => "Phase4"; protected override EntityState nextState => new BossDeath(); protected override float healthBarShowDelay => 6f; public override void OnEnter() { base.OnEnter(); BeginEncounter(); } } public class BossDeath : BrotherEncounterBaseState { public override void OnEnter() { base.OnEnter(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { outer.SetNextState(new EncounterFinished()); } } } public class EncounterFinished : BrotherEncounterBaseState { protected override bool shouldEnableArenaNodes => false; public override void OnEnter() { base.OnEnter(); } } } namespace EntityStates.Missions.ArtifactWorld.TrialController { public class BeforeTrial1 : BeforeTrial { } public class DuringTrial1 : DuringTrial { public static float trialDuration; public override EntityState GetNextState() { return new AfterTrial1(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= trialDuration) { outer.SetNextState(GetNextState()); } } } public class AfterTrial1 : AfterTrial { public override Type GetNextStateType() { return typeof(FinishTrial1); } } public class FinishTrial1 : FinishTrial { } public class AfterTrial2 : AfterTrial { public override Type GetNextStateType() { return typeof(FinishTrial2); } } public class FinishTrial2 : FinishTrial { } public class ArtifactTrialControllerBaseState : EntityState { protected PurchaseInteraction purchaseInteraction; protected ChildLocator childLocator; public override void OnEnter() { base.OnEnter(); purchaseInteraction = GetComponent(); childLocator = GetComponent(); } } public class BeforeTrial : ArtifactTrialControllerBaseState { public override void OnEnter() { base.OnEnter(); purchaseInteraction.enabled = true; childLocator.FindChild("BeforeTrial").gameObject.SetActive(value: true); } public override void OnExit() { childLocator.FindChild("BeforeTrial").gameObject.SetActive(value: false); base.OnExit(); } } public class DuringTrial : ArtifactTrialControllerBaseState { public virtual EntityState GetNextState() { return new AfterTrial(); } public override void OnEnter() { base.OnEnter(); purchaseInteraction.enabled = false; childLocator.FindChild("DuringTrial").gameObject.SetActive(value: true); } public override void OnExit() { childLocator.FindChild("DuringTrial").gameObject.SetActive(value: false); base.OnExit(); } } public class AfterTrial : ArtifactTrialControllerBaseState { public virtual Type GetNextStateType() { return typeof(FinishTrial); } public override void OnEnter() { base.OnEnter(); purchaseInteraction.enabled = true; childLocator.FindChild("AfterTrial").gameObject.SetActive(value: true); outer.mainStateType = new SerializableEntityStateType(GetNextStateType()); Highlight component = GetComponent(); Transform transform = childLocator.FindChild("CompletedArtifactMesh"); if ((bool)component && (bool)transform) { component.targetRenderer = transform.GetComponent(); } } public override void OnExit() { childLocator.FindChild("AfterTrial").gameObject.SetActive(value: false); base.OnExit(); } } public class FinishTrial : ArtifactTrialControllerBaseState { [SerializeField] public string achievementName; public override void OnEnter() { base.OnEnter(); childLocator.FindChild("FinishTrial").gameObject.SetActive(value: true); AchievementDef achievementDef = AchievementManager.GetAchievementDef(achievementName); if (achievementDef == null) { return; } foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList) { AchievementManager.GetUserAchievementManager(readOnlyLocalUsers).GrantAchievement(achievementDef); } } } } namespace EntityStates.Missions.Arena.NullWard { public class NullWardBaseState : EntityState { public static float wardRadiusOff; public static float wardRadiusOn; public static float wardWaitingRadius; protected SphereZone sphereZone; protected PurchaseInteraction purchaseInteraction; protected ChildLocator childLocator; protected ArenaMissionController arenaMissionController => ArenaMissionController.instance; public override void OnEnter() { base.OnEnter(); sphereZone = GetComponent(); sphereZone.enabled = true; purchaseInteraction = GetComponent(); childLocator = GetComponent(); base.gameObject.GetComponent().teamIndex = TeamIndex.Player; } } public class Off : NullWardBaseState { public override void OnEnter() { base.OnEnter(); sphereZone.Networkradius = NullWardBaseState.wardRadiusOff; purchaseInteraction.SetAvailable(newAvailable: false); sphereZone.enabled = false; } } public class WardOnAndReady : NullWardBaseState { public static string soundLoopStartEvent; public static string soundLoopEndEvent; public override void OnEnter() { base.OnEnter(); sphereZone.Networkradius = NullWardBaseState.wardWaitingRadius; purchaseInteraction.SetAvailable(newAvailable: true); childLocator.FindChild("WardOnEffect").gameObject.SetActive(value: true); sphereZone.enabled = true; Util.PlaySound(soundLoopStartEvent, base.gameObject); } public override void OnExit() { Util.PlaySound(soundLoopEndEvent, base.gameObject); base.OnExit(); } } public class Active : NullWardBaseState { public static string soundEntryEvent; public static string soundLoopStartEvent; public static string soundLoopEndEvent; private static Run.FixedTimeStamp startTime; private HoldoutZoneController holdoutZoneController; public override void OnEnter() { base.OnEnter(); holdoutZoneController = GetComponent(); holdoutZoneController.enabled = true; holdoutZoneController.baseRadius = NullWardBaseState.wardRadiusOn; purchaseInteraction.SetAvailable(newAvailable: false); base.arenaMissionController.rewardSpawnPosition = childLocator.FindChild("RewardSpawn").gameObject; base.arenaMissionController.monsterSpawnPosition = childLocator.FindChild("MonsterSpawn").gameObject; childLocator.FindChild("ActiveEffect").gameObject.SetActive(value: true); if (NetworkServer.active) { base.arenaMissionController.BeginRound(); } if (base.isAuthority) { startTime = Run.FixedTimeStamp.now; } Util.PlaySound(soundEntryEvent, base.gameObject); Util.PlaySound(soundLoopStartEvent, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); sphereZone.Networkradius = holdoutZoneController.currentRadius; if (base.isAuthority && holdoutZoneController.charge >= 1f) { outer.SetNextState(new Complete()); } } public override void OnExit() { if ((bool)holdoutZoneController) { holdoutZoneController.enabled = false; } Util.PlaySound(soundLoopEndEvent, base.gameObject); childLocator.FindChild("ActiveEffect").gameObject.SetActive(value: false); childLocator.FindChild("WardOnEffect").gameObject.SetActive(value: false); base.OnExit(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(startTime); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); startTime = reader.ReadFixedTimeStamp(); } } public class Complete : NullWardBaseState { public static float duration; public static string soundEntryEvent; public override void OnEnter() { base.OnEnter(); sphereZone.Networkradius = NullWardBaseState.wardRadiusOn; purchaseInteraction.SetAvailable(newAvailable: false); childLocator.FindChild("CompleteEffect").gameObject.SetActive(value: true); if (NetworkServer.active) { base.arenaMissionController.EndRound(); } } public override void FixedUpdate() { base.FixedUpdate(); sphereZone.Networkradius = Mathf.Lerp(NullWardBaseState.wardRadiusOn, NullWardBaseState.wardRadiusOff, base.fixedAge / duration); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new Off()); } } } } namespace EntityStates.MinorConstruct { public class DeathState : GenericCharacterDeath { public static GameObject explosionPrefab; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { EffectManager.SimpleEffect(explosionPrefab, base.transform.position, base.transform.rotation, transmit: true); EntityState.Destroy(base.gameObject); } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class FindSurface : NoCastSpawn { [SerializeField] public int raycastCount; [SerializeField] public float maxRaycastLength; public override void OnEnter() { RaycastHit hitInfo = default(RaycastHit); UnityEngine.Vector3 corePosition = base.characterBody.corePosition; if (base.isAuthority && !(base.characterBody.master.minionOwnership?.ownerMaster)) { for (int i = 0; i < raycastCount; i++) { if (Physics.Raycast(corePosition, UnityEngine.Random.onUnitSphere, out hitInfo, maxRaycastLength, LayerIndex.world.mask)) { base.transform.position = hitInfo.point; base.transform.up = hitInfo.normal; } } } base.OnEnter(); } } public class NoCastSpawn : BaseState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); outer.SetNextStateToMain(); } } public class BaseHideState : BaseState { [SerializeField] public string enterSoundString; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string childToEnable; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); Transform transform = FindModelChild(childToEnable); if ((bool)transform) { transform.gameObject.SetActive(value: true); } } public override void OnExit() { Transform transform = FindModelChild(childToEnable); if ((bool)transform) { transform.gameObject.SetActive(value: false); } base.OnExit(); } } public class Hidden : BaseHideState { [SerializeField] public BuffDef buffDef; public override void OnEnter() { base.OnEnter(); if ((bool)buffDef) { base.characterBody.AddBuff(buffDef); } } public override void FixedUpdate() { base.FixedUpdate(); if (!base.characterBody.outOfCombat || !base.characterBody.outOfDanger) { outer.SetNextState(new Revealed()); } } public override void OnExit() { if ((bool)buffDef) { base.characterBody.RemoveBuff(buffDef); } base.OnExit(); } } public class Revealed : BaseHideState { public override void FixedUpdate() { base.FixedUpdate(); if (base.characterBody.outOfCombat && base.characterBody.outOfDanger) { outer.SetNextState(new Hidden()); } } } } namespace EntityStates.MinorConstruct.Weapon { public class ChargeConstructBeam : BaseState { [SerializeField] public string enterSoundString; [SerializeField] public string exitSoundString; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string chargeEffectMuzzle; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public float baseDuration; private float duration; private GameObject chargeInstance; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); Util.PlaySound(enterSoundString, base.gameObject); Transform transform = FindModelChild(chargeEffectMuzzle); if ((bool)transform && (bool)chargeEffectPrefab) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeInstance.transform.parent = base.gameObject.transform; ScaleParticleSystemDuration component = chargeInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } public override void Update() { base.Update(); if ((bool)chargeInstance) { Ray aimRay = GetAimRay(); chargeInstance.transform.forward = aimRay.direction; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new FireConstructBeam()); } } public override void OnExit() { Util.PlaySound(exitSoundString, base.gameObject); if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireConstructBeam : GenericProjectileBaseState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.MiniMushroom { public class InPlant : BaseState { public static GameObject burrowPrefab; public static float baseDuration; public static string burrowInSoundString; private float duration; private static int PlantStartStateHash = Animator.StringToHash("PlantStart"); private static int EmptyStateHash = Animator.StringToHash("Empty"); private static int PlantStartParamHash = Animator.StringToHash("PlantStart.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(burrowInSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false); PlayAnimation("Plant", PlantStartStateHash, PlantStartParamHash, duration); } public override void OnExit() { PlayAnimation("Plant", EmptyStateHash); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new Plant()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Plant : BaseState { public static float healFraction; public static float baseMaxDuration; public static float baseMinDuration; public static float mushroomRadius; public static string healSoundLoop; public static string healSoundStop; private float maxDuration; private float minDuration; private GameObject mushroomWard; private uint soundID; private static int PlantLoopStateHash = Animator.StringToHash("PlantLoop"); private static int EmptyStateHash = Animator.StringToHash("Empty"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Plant", PlantLoopStateHash); maxDuration = baseMaxDuration / attackSpeedStat; minDuration = baseMinDuration / attackSpeedStat; soundID = Util.PlaySound(healSoundLoop, base.characterBody.modelLocator.modelTransform.gameObject); if (NetworkServer.active && mushroomWard == null) { mushroomWard = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/MiniMushroomWard"), base.characterBody.footPosition, UnityEngine.Quaternion.identity); mushroomWard.GetComponent().teamIndex = base.teamComponent.teamIndex; if ((bool)mushroomWard) { HealingWard component = mushroomWard.GetComponent(); component.healFraction = healFraction; component.healPoints = 0f; component.Networkradius = mushroomRadius; } NetworkServer.Spawn(mushroomWard); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { bool flag = base.inputBank.moveVector.sqrMagnitude > 0.1f; if (base.fixedAge > maxDuration || (base.fixedAge > minDuration && flag)) { outer.SetNextState(new UnPlant()); } } } public override void OnExit() { PlayAnimation("Plant", EmptyStateHash); AkSoundEngine.StopPlayingID(soundID); Util.PlaySound(healSoundStop, base.gameObject); if ((bool)mushroomWard) { EntityState.Destroy(mushroomWard); } base.OnExit(); } } public class SpawnState : BaseState { public static GameObject burrowPrefab; public static float duration = 4f; public static string spawnSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class SporeGrenade : BaseState { public static GameObject chargeEffectPrefab; public static string attackSoundString; public static string chargeUpSoundString; public static float recoilAmplitude = 1f; public static GameObject projectilePrefab; public static float baseDuration = 2f; public static string muzzleString; public static float damageCoefficient; public static float timeToTarget = 3f; public static float projectileVelocity = 55f; public static float minimumDistance; public static float maximumDistance; public static float baseChargeTime = 2f; private uint chargeupSoundID; private Ray projectileRay; private Transform modelTransform; private float duration; private float chargeTime; private bool hasFired; private Animator modelAnimator; private GameObject chargeEffectInstance; private static int ChargeStateHash = Animator.StringToHash("Charge"); private static int isChargedParamHash = Animator.StringToHash("isCharged"); private static int EmptyStateHash = Animator.StringToHash("Empty"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; chargeTime = baseChargeTime / attackSpeedStat; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetBool(isChargedParamHash, value: false); PlayAnimation("Gesture, Additive", ChargeStateHash); chargeupSoundID = Util.PlaySound(chargeUpSoundString, base.characterBody.modelLocator.modelTransform.gameObject); } Transform transform = FindModelChild("ChargeSpot"); if ((bool)transform) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform); } } public override void FixedUpdate() { base.FixedUpdate(); if (!(base.fixedAge >= chargeTime)) { return; } if (!hasFired) { hasFired = true; modelAnimator?.SetBool(isChargedParamHash, value: true); if (base.isAuthority) { FireGrenade(muzzleString); } } if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override void OnExit() { PlayAnimation("Gesture, Additive", EmptyStateHash); AkSoundEngine.StopPlayingID(chargeupSoundID); if ((bool)chargeEffectInstance) { EntityState.Destroy(chargeEffectInstance); } base.OnExit(); } private void FireGrenade(string targetMuzzle) { Ray aimRay = GetAimRay(); Ray ray = new Ray(aimRay.origin, UnityEngine.Vector3.up); Transform transform = FindModelChild(targetMuzzle); if ((bool)transform) { ray.origin = transform.position; } BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.filterByLoS = false; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.RefreshCandidates(); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); bool flag = false; UnityEngine.Vector3 vector = UnityEngine.Vector3.zero; RaycastHit hitInfo; if ((bool)hurtBox) { vector = hurtBox.transform.position; flag = true; } else if (Physics.Raycast(aimRay, out hitInfo, 1000f, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) { vector = hitInfo.point; flag = true; } float magnitude = projectileVelocity; if (flag) { UnityEngine.Vector3 vector2 = vector - ray.origin; UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z); float magnitude2 = vector3.magnitude; UnityEngine.Vector2 vector4 = vector3 / magnitude2; if (magnitude2 < minimumDistance) { magnitude2 = minimumDistance; } if (magnitude2 > maximumDistance) { magnitude2 = maximumDistance; } float y = Trajectory.CalculateInitialYSpeed(timeToTarget, vector2.y); float num = magnitude2 / timeToTarget; UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector4.x * num, y, vector4.y * num); magnitude = direction.magnitude; ray.direction = direction; } UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(ray.direction + UnityEngine.Random.insideUnitSphere * 0.05f); ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, rotation, base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude); } } public class UnPlant : BaseState { public static GameObject plantEffectPrefab; public static float baseDuration; public static string UnplantOutSoundString; private float stopwatch; private Transform modelTransform; private ChildLocator childLocator; private float duration; private static int PlantEndStateHash = Animator.StringToHash("PlantEnd"); private static int PlantEndParamHash = Animator.StringToHash("PlantEnd.playbackRate"); private static int EmptyStateHash = Animator.StringToHash("Empty"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; EffectManager.SimpleMuzzleFlash(plantEffectPrefab, base.gameObject, "BurrowCenter", transmit: false); Util.PlaySound(UnplantOutSoundString, base.gameObject); PlayAnimation("Plant", PlantEndStateHash, PlantEndParamHash, duration); } public override void OnExit() { PlayAnimation("Plant, Additive", EmptyStateHash); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.Merc { public class Assaulter : BaseState { private Transform modelTransform; public static GameObject dashPrefab; public static float smallHopVelocity; public static float dashPrepDuration; public static float dashDuration = 0.3f; public static float speedCoefficient = 25f; public static string beginSoundString; public static string endSoundString; public static float damageCoefficient; public static float procCoefficient; public static GameObject hitEffectPrefab; public static float hitPauseDuration; private float stopwatch; private UnityEngine.Vector3 dashVector = UnityEngine.Vector3.zero; private Animator animator; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private OverlapAttack overlapAttack; private ChildLocator childLocator; private bool isDashing; private bool inHitPause; private float hitPauseTimer; private CameraTargetParams.AimRequest aimRequest; private int originalLayer; private static int AssaulterPrepStateHash = Animator.StringToHash("AssaulterPrep"); private static int AssaulterPrepParamHash = Animator.StringToHash("AssaulterPrep.playbackRate"); private static int EvisLoopExitStateHash = Animator.StringToHash("EvisLoopExit"); public bool hasHit { get; private set; } public int dashIndex { private get; set; } public override void Reset() { base.Reset(); modelTransform = null; stopwatch = 0f; dashVector = UnityEngine.Vector3.zero; animator = null; characterModel = null; hurtboxGroup = null; if (overlapAttack != null) { overlapAttack.Reset(); } childLocator = null; isDashing = false; inHitPause = false; hitPauseTimer = 0f; hasHit = false; dashIndex = 0; } public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } if ((bool)modelTransform) { animator = modelTransform.GetComponent(); characterModel = modelTransform.GetComponent(); childLocator = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); if ((bool)childLocator) { childLocator.FindChild("PreDashEffect").gameObject.SetActive(value: true); } } SmallHop(base.characterMotor, smallHopVelocity); PlayAnimation("FullBody, Override", AssaulterPrepStateHash, AssaulterPrepParamHash, dashPrepDuration); dashVector = base.inputBank.aimDirection; overlapAttack = InitMeleeOverlap(damageCoefficient, hitEffectPrefab, modelTransform, "Assaulter"); overlapAttack.damageType = DamageType.Stun1s; if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); } } private void CreateDashEffect() { Transform transform = childLocator.FindChild("DashCenter"); if ((bool)transform && (bool)dashPrefab) { if (!EffectManager.ShouldUsePooledEffect(dashPrefab)) { UnityEngine.Object.Instantiate(dashPrefab, transform.position, Util.QuaternionSafeLookRotation(dashVector), transform); } else { EffectManager.GetAndActivatePooledEffect(dashPrefab, transform.position, Util.QuaternionSafeLookRotation(dashVector), transform); } } if ((bool)childLocator) { childLocator.FindChild("PreDashEffect").gameObject.SetActive(value: false); } } public override void FixedUpdate() { base.FixedUpdate(); base.characterDirection.forward = dashVector; if (stopwatch > dashPrepDuration / attackSpeedStat && !isDashing) { isDashing = true; dashVector = base.inputBank.aimDirection; CreateDashEffect(); PlayCrossfade("FullBody, Override", "AssaulterLoop", 0.1f); originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal; base.characterMotor.Motor.RebuildCollidableLayers(); if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = 0.7f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matMercEnergized"); temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent()); } } float deltaTime = GetDeltaTime(); if (!isDashing) { stopwatch += deltaTime; } else if (base.isAuthority) { base.characterMotor.velocity = UnityEngine.Vector3.zero; if (!inHitPause) { bool num = overlapAttack.Fire(); stopwatch += deltaTime; if (num) { if (!hasHit) { hasHit = true; } inHitPause = true; hitPauseTimer = hitPauseDuration / attackSpeedStat; if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance2.duration = hitPauseDuration / attackSpeedStat; temporaryOverlayInstance2.animateShaderAlpha = true; temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance2.destroyComponentOnEnd = true; temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load("Materials/matMercEvisTarget"); temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent()); } } base.characterMotor.rootMotion += dashVector * moveSpeedStat * speedCoefficient * deltaTime; } else { hitPauseTimer -= deltaTime; if (hitPauseTimer < 0f) { inHitPause = false; } } } if (stopwatch >= dashDuration + dashPrepDuration / attackSpeedStat && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { base.gameObject.layer = originalLayer; base.characterMotor.Motor.RebuildCollidableLayers(); Util.PlaySound(endSoundString, base.gameObject); if (base.isAuthority) { base.characterMotor.velocity *= 0.1f; SmallHop(base.characterMotor, smallHopVelocity); } aimRequest?.Dispose(); if ((bool)childLocator) { childLocator.FindChild("PreDashEffect").gameObject.SetActive(value: false); } PlayAnimation("FullBody, Override", EvisLoopExitStateHash); if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); } base.OnExit(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)dashIndex); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); dashIndex = reader.ReadByte(); } } public class PrepAssaulter2 : BaseState { public static float baseDuration; public static float smallHopVelocity; public static string enterSoundString; private float duration; private static int AssaulterPrepStateHash = Animator.StringToHash("AssaulterPrep"); private static int AssaulterPrepParamHash = Animator.StringToHash("AssaulterPrep.playbackRate"); public int dashIndex { private get; set; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("FullBody, Override", AssaulterPrepStateHash, AssaulterPrepParamHash, baseDuration); FindModelChild("PreDashEffect").gameObject.SetActive(value: true); Util.PlaySound(enterSoundString, base.gameObject); Ray aimRay = GetAimRay(); base.characterDirection.forward = aimRay.direction; base.characterDirection.moveVector = aimRay.direction; SmallHop(base.characterMotor, smallHopVelocity); if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } } public override void OnExit() { if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 0.2f); } FindModelChild("PreDashEffect").gameObject.SetActive(value: false); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new Assaulter2()); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)dashIndex); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); dashIndex = reader.ReadByte(); } } public class Assaulter2 : BasicMeleeAttack { public static float speedCoefficientOnExit; public static float speedCoefficient; public static string endSoundString; public static float exitSmallHop; public static GameObject selfOnHitOverlayEffectPrefab; public bool grantAnotherDash; private Transform modelTransform; private UnityEngine.Vector3 dashVector; private int originalLayer; private static int EvisLoopExitStateHash = Animator.StringToHash("EvisLoopExit"); private static int AssaulterLoopStateHash = Animator.StringToHash("AssaulterLoop"); private bool bufferedSkill2; private UnityEngine.Vector3 dashVelocity => dashVector * moveSpeedStat * speedCoefficient; public override void OnEnter() { base.OnEnter(); dashVector = base.inputBank.aimDirection; originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal; base.characterMotor.Motor.RebuildCollidableLayers(); base.characterMotor.Motor.ForceUnground(); base.characterMotor.velocity = UnityEngine.Vector3.zero; modelTransform = GetModelTransform(); if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = 0.7f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matMercEnergized"); temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent()); } PlayCrossfade("FullBody, Override", "AssaulterLoop", 0.1f); base.characterDirection.forward = base.characterMotor.velocity.normalized; if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } } public override void OnExit() { if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); } base.characterMotor.velocity *= speedCoefficientOnExit; SmallHop(base.characterMotor, exitSmallHop); Util.PlaySound(endSoundString, base.gameObject); PlayAnimation("FullBody, Override", EvisLoopExitStateHash); base.gameObject.layer = originalLayer; base.characterMotor.Motor.RebuildCollidableLayers(); base.OnExit(); } protected override void PlayAnimation() { base.PlayAnimation(); PlayCrossfade("FullBody, Override", AssaulterLoopStateHash, 0.1f); } protected override void AuthorityFixedUpdate() { base.AuthorityFixedUpdate(); if (!base.authorityInHitPause) { base.characterMotor.rootMotion += dashVelocity * GetDeltaTime(); base.characterDirection.forward = dashVelocity; base.characterDirection.moveVector = dashVelocity; base.characterBody.isSprinting = true; if (bufferedSkill2) { base.skillLocator.secondary.ExecuteIfReady(); bufferedSkill2 = false; } } if ((bool)base.skillLocator && base.skillLocator.secondary.IsReady() && base.inputBank.skill2.down) { bufferedSkill2 = true; } } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); overlapAttack.damageType = DamageType.Stun1s; overlapAttack.damage = damageCoefficient * damageStat; } protected override void OnMeleeHitAuthority() { base.OnMeleeHitAuthority(); grantAnotherDash = true; float num = hitPauseDuration / attackSpeedStat; if ((bool)selfOnHitOverlayEffectPrefab && num > 1f / 30f) { EffectData effectData = new EffectData { origin = base.transform.position, genericFloat = hitPauseDuration / attackSpeedStat }; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(selfOnHitOverlayEffectPrefab, effectData, transmit: true); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class Evis : BaseState { private Transform modelTransform; public static GameObject blinkPrefab; public static float duration = 2f; public static float damageCoefficient; public static float damageFrequency; public static float procCoefficient; public static string beginSoundString; public static string endSoundString; public static float maxRadius; public static GameObject hitEffectPrefab; public static string slashSoundString; public static string impactSoundString; public static string dashSoundString; public static float slashPitch; public static float smallHopVelocity; public static float lingeringInvincibilityDuration; private Animator animator; private CharacterModel characterModel; private float stopwatch; private float attackStopwatch; private bool crit; private static float minimumDuration = 0.5f; private CameraTargetParams.AimRequest aimRequest; public override void OnEnter() { base.OnEnter(); CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); Util.PlayAttackSpeedSound(beginSoundString, base.gameObject, 1.2f); crit = Util.CheckRoll(critStat, base.characterBody.master); modelTransform = GetModelTransform(); if ((bool)modelTransform) { animator = modelTransform.GetComponent(); characterModel = modelTransform.GetComponent(); } if ((bool)characterModel) { characterModel.invisibilityCount++; } if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); stopwatch += deltaTime; attackStopwatch += deltaTime; float num = 1f / damageFrequency / attackSpeedStat; if (attackStopwatch >= num) { attackStopwatch -= num; HurtBox hurtBox = SearchForTarget(); if ((bool)hurtBox) { Util.PlayAttackSpeedSound(slashSoundString, base.gameObject, slashPitch); Util.PlaySound(dashSoundString, base.gameObject); Util.PlaySound(impactSoundString, base.gameObject); HurtBoxGroup hurtBoxGroup = hurtBox.hurtBoxGroup; HurtBox hurtBox2 = hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, hurtBoxGroup.hurtBoxes.Length - 1)]; if ((bool)hurtBox2) { UnityEngine.Vector3 position = hurtBox2.transform.position; UnityEngine.Vector2 normalized = UnityEngine.Random.insideUnitCircle.normalized; EffectManager.SimpleImpactEffect(normal: new UnityEngine.Vector3(normalized.x, 0f, normalized.y), effectPrefab: hitEffectPrefab, hitPos: position, transmit: false); Transform transform = hurtBox.hurtBoxGroup.transform; TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(transform.gameObject); temporaryOverlayInstance.duration = num; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matMercEvisTarget"); temporaryOverlayInstance.AddToCharacterModel(transform.GetComponent()); if (NetworkServer.active) { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = damageCoefficient * damageStat; damageInfo.attacker = base.gameObject; damageInfo.procCoefficient = procCoefficient; damageInfo.position = hurtBox2.transform.position; damageInfo.crit = crit; hurtBox2.healthComponent.TakeDamage(damageInfo); GlobalEventManager.instance.OnHitEnemy(damageInfo, hurtBox2.healthComponent.gameObject); GlobalEventManager.instance.OnHitAll(damageInfo, hurtBox2.healthComponent.gameObject); } } } else if (base.isAuthority && stopwatch > minimumDuration) { outer.SetNextStateToMain(); } } if ((bool)base.characterMotor) { base.characterMotor.velocity = UnityEngine.Vector3.zero; } if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private HurtBox SearchForTarget() { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = base.transform.position; bullseyeSearch.searchDirection = UnityEngine.Random.onUnitSphere; bullseyeSearch.maxDistanceFilter = maxRadius; bullseyeSearch.teamMaskFilter = TeamMask.GetUnprotectedTeams(GetTeam()); bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); return bullseyeSearch.GetResults().FirstOrDefault(); } private void CreateBlinkEffect(UnityEngine.Vector3 origin) { EffectData effectData = new EffectData(); effectData.rotation = Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up); effectData.origin = origin; EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false); } public override void OnExit() { Util.PlaySound(endSoundString, base.gameObject); CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); modelTransform = GetModelTransform(); if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = 0.6f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matMercEvisTarget"); temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent()); TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance2.duration = 0.7f; temporaryOverlayInstance2.animateShaderAlpha = true; temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance2.destroyComponentOnEnd = true; temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load("Materials/matHuntressFlashExpanded"); temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent()); } if ((bool)characterModel) { characterModel.invisibilityCount--; } aimRequest?.Dispose(); if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, lingeringInvincibilityDuration); } Util.PlaySound(endSoundString, base.gameObject); SmallHop(base.characterMotor, smallHopVelocity); base.OnExit(); } } public class EvisDash : BaseState { private Transform modelTransform; public static GameObject blinkPrefab; private float stopwatch; private UnityEngine.Vector3 dashVector = UnityEngine.Vector3.zero; public static float smallHopVelocity; public static float dashPrepDuration; public static float dashDuration = 0.3f; public static float speedCoefficient = 25f; public static string beginSoundString; public static string endSoundString; public static float overlapSphereRadius; public static float lollypopFactor; private Animator animator; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private bool isDashing; private CameraTargetParams.AimRequest aimRequest; private static int EvisPrepStateHash = Animator.StringToHash("EvisPrep"); private static int EvisPrepParamHash = Animator.StringToHash("EvisPrep.playbackRate"); private static int EvisLoopExitStateHash = Animator.StringToHash("EvisLoopExit"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } if ((bool)modelTransform) { animator = modelTransform.GetComponent(); characterModel = modelTransform.GetComponent(); } if (base.isAuthority) { SmallHop(base.characterMotor, smallHopVelocity); } if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } PlayAnimation("FullBody, Override", EvisPrepStateHash, EvisPrepParamHash, dashPrepDuration); dashVector = base.inputBank.aimDirection; base.characterDirection.forward = dashVector; } private void CreateBlinkEffect(UnityEngine.Vector3 origin) { EffectData effectData = new EffectData(); effectData.rotation = Util.QuaternionSafeLookRotation(dashVector); effectData.origin = origin; EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch > dashPrepDuration && !isDashing) { isDashing = true; dashVector = base.inputBank.aimDirection; CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); PlayCrossfade("FullBody, Override", "EvisLoop", 0.1f); if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = 0.6f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matHuntressFlashBright"); temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent()); TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance2.duration = 0.7f; temporaryOverlayInstance2.animateShaderAlpha = true; temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance2.destroyComponentOnEnd = true; temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load("Materials/matHuntressFlashExpanded"); temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent()); } } bool flag = stopwatch >= dashDuration + dashPrepDuration; if (isDashing) { if ((bool)base.characterMotor && (bool)base.characterDirection) { base.characterMotor.rootMotion += dashVector * (moveSpeedStat * speedCoefficient * GetDeltaTime()); } if (base.isAuthority) { Collider[] colliders; int num = HGPhysics.OverlapSphere(out colliders, base.transform.position, base.characterBody.radius + overlapSphereRadius * (flag ? lollypopFactor : 1f), LayerIndex.entityPrecise.mask); for (int i = 0; i < num; i++) { HurtBox component = colliders[i].GetComponent(); if ((bool)component && component.healthComponent != base.healthComponent) { Evis nextState = new Evis(); outer.SetNextState(nextState); break; } } HGPhysics.ReturnResults(colliders); } } if (flag && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { Util.PlaySound(endSoundString, base.gameObject); base.characterMotor.velocity *= 0.1f; SmallHop(base.characterMotor, smallHopVelocity); aimRequest?.Dispose(); PlayAnimation("FullBody, Override", EvisLoopExitStateHash); if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); } base.OnExit(); } } public class FocusedAssaultDash : BasicMeleeAttack { [SerializeField] public float speedCoefficientOnExit; [SerializeField] public float speedCoefficient; [SerializeField] public string endSoundString; [SerializeField] public float exitSmallHop; [SerializeField] public float delayedDamageCoefficient; [SerializeField] public float delayedProcCoefficient; [SerializeField] public float delay; [SerializeField] public string enterAnimationLayerName = "FullBody, Override"; [SerializeField] public string enterAnimationStateName = "AssaulterLoop"; [SerializeField] public float enterAnimationCrossfadeDuration = 0.1f; [SerializeField] public string exitAnimationLayerName = "FullBody, Override"; [SerializeField] public string exitAnimationStateName = "EvisLoopExit"; [SerializeField] public Material enterOverlayMaterial; [SerializeField] public float enterOverlayDuration = 0.7f; [SerializeField] public GameObject delayedEffectPrefab; [SerializeField] public GameObject orbEffect; [SerializeField] public float delayPerHit; [SerializeField] public GameObject selfOnHitOverlayEffectPrefab; private Transform modelTransform; private UnityEngine.Vector3 dashVector; private int originalLayer; private int currentHitCount; private UnityEngine.Vector3 dashVelocity => dashVector * moveSpeedStat * speedCoefficient; public override void OnEnter() { base.OnEnter(); dashVector = base.inputBank.aimDirection; originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal; base.characterMotor.Motor.RebuildCollidableLayers(); base.characterMotor.Motor.ForceUnground(); base.characterMotor.velocity = UnityEngine.Vector3.zero; modelTransform = GetModelTransform(); if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = enterOverlayDuration; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = enterOverlayMaterial; temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent()); } PlayCrossfade(enterAnimationLayerName, enterAnimationStateName, enterAnimationCrossfadeDuration); base.characterDirection.forward = base.characterMotor.velocity.normalized; if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } } public override void OnExit() { if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); } base.characterMotor.velocity *= speedCoefficientOnExit; SmallHop(base.characterMotor, exitSmallHop); Util.PlaySound(endSoundString, base.gameObject); PlayAnimation(exitAnimationLayerName, exitAnimationStateName); base.gameObject.layer = originalLayer; base.characterMotor.Motor.RebuildCollidableLayers(); base.OnExit(); } protected override void PlayAnimation() { base.PlayAnimation(); PlayCrossfade(enterAnimationLayerName, enterAnimationStateName, enterAnimationCrossfadeDuration); } protected override void AuthorityFixedUpdate() { base.AuthorityFixedUpdate(); if (!base.authorityInHitPause) { base.characterMotor.rootMotion += dashVelocity * GetDeltaTime(); base.characterDirection.forward = dashVelocity; base.characterDirection.moveVector = dashVelocity; base.characterBody.isSprinting = true; } } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); overlapAttack.damage = damageCoefficient * damageStat; } protected override void OnMeleeHitAuthority() { base.OnMeleeHitAuthority(); float num = hitPauseDuration / attackSpeedStat; if ((bool)selfOnHitOverlayEffectPrefab && num > 1f / 30f) { EffectData effectData = new EffectData { origin = base.transform.position, genericFloat = hitPauseDuration / attackSpeedStat }; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(selfOnHitOverlayEffectPrefab, effectData, transmit: true); } foreach (HurtBox hitResult in hitResults) { currentHitCount++; float damageValue = base.characterBody.damage * delayedDamageCoefficient; float num2 = delay + delayPerHit * (float)currentHitCount; bool isCrit = RollCrit(); HandleHit(base.gameObject, hitResult, damageValue, delayedProcCoefficient, isCrit, num2, orbEffect, delayedEffectPrefab); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } private static void HandleHit(GameObject attackerObject, HurtBox victimHurtBox, float damageValue, float procCoefficient, bool isCrit, float delay, GameObject orbEffectPrefab, GameObject orbImpactEffectPrefab) { if (!NetworkServer.active) { NetworkWriter networkWriter = new NetworkWriter(); networkWriter.StartMessage(77); networkWriter.Write(attackerObject); networkWriter.Write(HurtBoxReference.FromHurtBox(victimHurtBox)); networkWriter.Write(damageValue); networkWriter.Write(procCoefficient); networkWriter.Write(isCrit); networkWriter.Write(delay); networkWriter.WriteEffectIndex(EffectCatalog.FindEffectIndexFromPrefab(orbEffectPrefab)); networkWriter.WriteEffectIndex(EffectCatalog.FindEffectIndexFromPrefab(orbImpactEffectPrefab)); networkWriter.FinishMessage(); ClientScene.readyConnection?.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal); } else if ((bool)victimHurtBox && (bool)victimHurtBox.healthComponent) { SetStateOnHurt.SetStunOnObject(victimHurtBox.healthComponent.gameObject, delay); OrbManager.instance.AddOrb(new DelayedHitOrb { attacker = attackerObject, target = victimHurtBox, damageColorIndex = DamageColorIndex.Default, damageValue = damageValue, damageType = DamageType.ApplyMercExpose, isCrit = isCrit, procChainMask = default(ProcChainMask), procCoefficient = procCoefficient, delay = delay, orbEffect = orbEffectPrefab, delayedEffectPrefab = orbImpactEffectPrefab }); } } [NetworkMessageHandler(msgType = 77, client = false, server = true)] private static void HandleReportMercFocusedAssaultHitReplaceMeLater(NetworkMessage netMsg) { GameObject attackerObject = netMsg.reader.ReadGameObject(); HurtBox victimHurtBox = netMsg.reader.ReadHurtBoxReference().ResolveHurtBox(); float damageValue = netMsg.reader.ReadSingle(); float num = netMsg.reader.ReadSingle(); bool isCrit = netMsg.reader.ReadBoolean(); float num2 = netMsg.reader.ReadSingle(); GameObject orbEffectPrefab = EffectCatalog.GetEffectDef(netMsg.reader.ReadEffectIndex())?.prefab ?? null; GameObject orbImpactEffectPrefab = EffectCatalog.GetEffectDef(netMsg.reader.ReadEffectIndex())?.prefab ?? null; HandleHit(attackerObject, victimHurtBox, damageValue, num, isCrit, num2, orbEffectPrefab, orbImpactEffectPrefab); } } public class FocusedAssaultPrep : BaseState { [SerializeField] public float baseDuration; [SerializeField] public float smallHopVelocity; [SerializeField] public string enterSoundString; private float duration; private static int AssaulterPrepStateHash = Animator.StringToHash("AssaulterPrep"); private static int AssaulterPrepParamHash = Animator.StringToHash("AssaulterPrep.playbackRate"); public int dashIndex { private get; set; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("FullBody, Override", AssaulterPrepStateHash, AssaulterPrepParamHash, baseDuration); FindModelChildGameObject("PreDashEffect")?.SetActive(value: true); Util.PlaySound(enterSoundString, base.gameObject); Ray aimRay = GetAimRay(); base.characterDirection.forward = aimRay.direction; base.characterDirection.moveVector = aimRay.direction; SmallHop(base.characterMotor, smallHopVelocity); if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } } public override void OnExit() { if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 0.2f); } FindModelChildGameObject("PreDashEffect")?.SetActive(value: false); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new FocusedAssaultDash()); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)dashIndex); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); dashIndex = reader.ReadByte(); } } public class GroundLight : BaseState { public enum ComboState { GroundLight1, GroundLight2, GroundLight3 } private struct ComboStateInfo { private string mecanimStateName; private string mecanimPlaybackRateName; } public static float baseComboAttackDuration; public static float baseFinisherAttackDuration; public static float baseEarlyExitDuration; public static string comboAttackSoundString; public static string finisherAttackSoundString; public static float comboDamageCoefficient; public static float finisherDamageCoefficient; public static float forceMagnitude; public static GameObject comboHitEffectPrefab; public static GameObject finisherHitEffectPrefab; public static GameObject comboSwingEffectPrefab; public static GameObject finisherSwingEffectPrefab; public static float hitPauseDuration; public static float selfForceMagnitude; public static string hitSoundString; public static float slashPitch; private float stopwatch; private float attackDuration; private float earlyExitDuration; private Animator animator; private OverlapAttack overlapAttack; private float hitPauseTimer; private bool isInHitPause; private bool hasSwung; private bool hasHit; private GameObject swingEffectInstance; public ComboState comboState; private UnityEngine.Vector3 characterForward; private string slashChildName; private HitStopCachedState hitStopCachedState; private GameObject swingEffectPrefab; private GameObject hitEffectPrefab; private string attackSoundString; private static int GroundLight1StateHash = Animator.StringToHash("GroundLight1"); private static int GroundLight2StateHash = Animator.StringToHash("GroundLight2"); private static int GroundLight3StateHash = Animator.StringToHash("GroundLight3"); private static int GroundLightParamHash = Animator.StringToHash("GroundLight.playbackRate"); private static int SwordactiveParamHash = Animator.StringToHash("Sword.active"); public override void OnEnter() { base.OnEnter(); stopwatch = 0f; earlyExitDuration = baseEarlyExitDuration / attackSpeedStat; animator = GetModelAnimator(); bool @bool = animator.GetBool("isMoving"); bool bool2 = animator.GetBool("isGrounded"); switch (comboState) { case ComboState.GroundLight1: attackDuration = baseComboAttackDuration / attackSpeedStat; overlapAttack = InitMeleeOverlap(comboDamageCoefficient, hitEffectPrefab, GetModelTransform(), "Sword"); if (@bool || !bool2) { PlayAnimation("Gesture, Additive", GroundLight1StateHash, GroundLightParamHash, attackDuration); PlayAnimation("Gesture, Override", GroundLight1StateHash, GroundLightParamHash, attackDuration); } else { PlayAnimation("FullBody, Override", GroundLight1StateHash, GroundLightParamHash, attackDuration); } slashChildName = "GroundLight1Slash"; swingEffectPrefab = comboSwingEffectPrefab; hitEffectPrefab = comboHitEffectPrefab; attackSoundString = comboAttackSoundString; break; case ComboState.GroundLight2: attackDuration = baseComboAttackDuration / attackSpeedStat; overlapAttack = InitMeleeOverlap(comboDamageCoefficient, hitEffectPrefab, GetModelTransform(), "Sword"); if (@bool || !bool2) { PlayAnimation("Gesture, Additive", GroundLight2StateHash, GroundLightParamHash, attackDuration); PlayAnimation("Gesture, Override", GroundLight2StateHash, GroundLightParamHash, attackDuration); } else { PlayAnimation("FullBody, Override", GroundLight2StateHash, GroundLightParamHash, attackDuration); } slashChildName = "GroundLight2Slash"; swingEffectPrefab = comboSwingEffectPrefab; hitEffectPrefab = comboHitEffectPrefab; attackSoundString = comboAttackSoundString; break; case ComboState.GroundLight3: attackDuration = baseFinisherAttackDuration / attackSpeedStat; overlapAttack = InitMeleeOverlap(finisherDamageCoefficient, hitEffectPrefab, GetModelTransform(), "SwordLarge"); if (@bool || !bool2) { PlayAnimation("Gesture, Additive", GroundLight3StateHash, GroundLightParamHash, attackDuration); PlayAnimation("Gesture, Override", GroundLight3StateHash, GroundLightParamHash, attackDuration); } else { PlayAnimation("FullBody, Override", GroundLight3StateHash, GroundLightParamHash, attackDuration); } slashChildName = "GroundLight3Slash"; swingEffectPrefab = finisherSwingEffectPrefab; hitEffectPrefab = finisherHitEffectPrefab; attackSoundString = finisherAttackSoundString; break; } base.characterBody.SetAimTimer(attackDuration + 1f); overlapAttack.hitEffectPrefab = hitEffectPrefab; } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); hitPauseTimer -= GetDeltaTime(); if (base.isAuthority) { bool flag = FireMeleeOverlap(overlapAttack, animator, "Sword.active", forceMagnitude); hasHit |= flag; if (flag) { Util.PlaySound(hitSoundString, base.gameObject); if (!isInHitPause) { hitStopCachedState = CreateHitStopCachedState(base.characterMotor, animator, "GroundLight.playbackRate"); hitPauseTimer = hitPauseDuration / attackSpeedStat; isInHitPause = true; } } if (hitPauseTimer <= 0f && isInHitPause) { ConsumeHitStopCachedState(hitStopCachedState, base.characterMotor, animator); isInHitPause = false; } } if (animator.GetFloat(SwordactiveParamHash) > 0f && !hasSwung) { Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, slashPitch); HealthComponent healthComponent = base.characterBody.healthComponent; CharacterDirection component = base.characterBody.GetComponent(); if ((bool)healthComponent) { healthComponent.TakeDamageForce(selfForceMagnitude * component.forward, alwaysApply: true); } hasSwung = true; EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, slashChildName, transmit: false); } if (!isInHitPause) { stopwatch += GetDeltaTime(); } else { base.characterMotor.velocity = UnityEngine.Vector3.zero; animator.SetFloat(GroundLightParamHash, 0f); } if (base.isAuthority && stopwatch >= attackDuration - earlyExitDuration) { if (!hasSwung) { overlapAttack.Fire(); } if (base.inputBank.skill1.down && comboState != ComboState.GroundLight3) { GroundLight groundLight = new GroundLight(); groundLight.comboState = comboState + 1; outer.SetNextState(groundLight); } else if (stopwatch >= attackDuration) { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)comboState); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); comboState = (ComboState)reader.ReadByte(); } } public class Uppercut : BaseState { public static GameObject swingEffectPrefab; public static GameObject hitEffectPrefab; public static string enterSoundString; public static string attackSoundString; public static string hitSoundString; public static float slashPitch; public static float hitPauseDuration; public static float upwardForceStrength; public static float baseDuration; public static float baseDamageCoefficient; public static string slashChildName; public static float moveSpeedBonusCoefficient; public static string hitboxString; public static AnimationCurve yVelocityCurve; protected Animator animator; protected float duration; protected float hitInterval; protected bool hasSwung; protected float hitPauseTimer; protected bool isInHitPause; protected OverlapAttack overlapAttack; protected HitStopCachedState hitStopCachedState; private static int UppercutExitStateHash = Animator.StringToHash("UppercutExit"); private static int UppercutStateHash = Animator.StringToHash("Uppercut"); private static int UppercutParamHash = Animator.StringToHash("Uppercut.playbackRate"); private static int SwordactiveParamHash = Animator.StringToHash("Sword.active"); public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); duration = baseDuration / attackSpeedStat; overlapAttack = InitMeleeOverlap(baseDamageCoefficient, hitEffectPrefab, GetModelTransform(), hitboxString); overlapAttack.forceVector = UnityEngine.Vector3.up * upwardForceStrength; if ((bool)base.characterDirection && (bool)base.inputBank) { base.characterDirection.forward = base.inputBank.aimDirection; } Util.PlaySound(enterSoundString, base.gameObject); PlayAnim(); } protected virtual void PlayAnim() { PlayCrossfade("FullBody, Override", UppercutStateHash, UppercutParamHash, duration, 0.1f); } public override void OnExit() { base.OnExit(); PlayAnimation("FullBody, Override", UppercutExitStateHash); } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); hitPauseTimer -= deltaTime; if (!base.isAuthority) { return; } if (animator.GetFloat(SwordactiveParamHash) > 0.2f && !hasSwung) { hasSwung = true; base.characterMotor.Motor.ForceUnground(); Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, slashPitch); EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, slashChildName, transmit: true); } if (FireMeleeOverlap(overlapAttack, animator, SwordactiveParamHash, 0f, calculateForceVector: false)) { Util.PlaySound(hitSoundString, base.gameObject); if (!isInHitPause) { hitStopCachedState = CreateHitStopCachedState(base.characterMotor, animator, "Uppercut.playbackRate"); hitPauseTimer = hitPauseDuration / attackSpeedStat; isInHitPause = true; } } if (hitPauseTimer <= 0f && isInHitPause) { ConsumeHitStopCachedState(hitStopCachedState, base.characterMotor, animator); base.characterMotor.Motor.ForceUnground(); isInHitPause = false; } if (!isInHitPause) { if ((bool)base.characterMotor && (bool)base.characterDirection) { UnityEngine.Vector3 velocity = base.characterDirection.forward * moveSpeedStat * Mathf.Lerp(moveSpeedBonusCoefficient, 0f, base.age / duration); velocity.y = yVelocityCurve.Evaluate(base.fixedAge / duration); base.characterMotor.velocity = velocity; } } else { base.fixedAge -= deltaTime; base.characterMotor.velocity = UnityEngine.Vector3.zero; hitPauseTimer -= deltaTime; animator.SetFloat(UppercutParamHash, 0f); } if (base.fixedAge >= duration) { if (hasSwung) { hasSwung = true; overlapAttack.Fire(); } outer.SetNextStateToMain(); } } } public class WhirlwindBase : BaseState { public static GameObject swingEffectPrefab; public static GameObject hitEffectPrefab; public static string attackSoundString; public static string hitSoundString; public static float slashPitch; public static float hitPauseDuration; [SerializeField] public float baseDuration; [SerializeField] public float baseDamageCoefficient; [SerializeField] public string slashChildName; [SerializeField] public float selfForceMagnitude; [SerializeField] public float moveSpeedBonusCoefficient; [SerializeField] public float smallHopVelocity; [SerializeField] public string hitboxString; protected Animator animator; protected float duration; protected float hitInterval; protected int swingCount; protected float hitPauseTimer; protected bool isInHitPause; protected OverlapAttack overlapAttack; protected HitStopCachedState hitStopCachedState; private static int SwordactiveParamHash = Animator.StringToHash("Sword.active"); private static int WhirlwindplaybackRateParamHash = Animator.StringToHash("Whirlwind.playbackRate"); public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); duration = baseDuration / attackSpeedStat; overlapAttack = InitMeleeOverlap(baseDamageCoefficient, hitEffectPrefab, GetModelTransform(), hitboxString); if ((bool)base.characterDirection && (bool)base.inputBank) { base.characterDirection.forward = base.inputBank.aimDirection; } SmallHop(base.characterMotor, smallHopVelocity); PlayAnim(); } protected virtual void PlayAnim() { } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); hitPauseTimer -= GetDeltaTime(); if (animator.GetFloat("Sword.active") > (float)swingCount) { swingCount++; Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, slashPitch); EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, slashChildName, transmit: false); if (base.isAuthority) { overlapAttack.ResetIgnoredHealthComponents(); if ((bool)base.characterMotor) { base.characterMotor.ApplyForce(selfForceMagnitude * base.characterDirection.forward, alwaysApply: true); } } } if (!base.isAuthority) { return; } if (FireMeleeOverlap(overlapAttack, animator, SwordactiveParamHash, 0f)) { Util.PlaySound(hitSoundString, base.gameObject); if (!isInHitPause) { hitStopCachedState = CreateHitStopCachedState(base.characterMotor, animator, "Whirlwind.playbackRate"); hitPauseTimer = hitPauseDuration / attackSpeedStat; isInHitPause = true; } } if (hitPauseTimer <= 0f && isInHitPause) { ConsumeHitStopCachedState(hitStopCachedState, base.characterMotor, animator); isInHitPause = false; } if (!isInHitPause) { if ((bool)base.characterMotor && (bool)base.characterDirection) { UnityEngine.Vector3 velocity = base.characterDirection.forward * moveSpeedStat * Mathf.Lerp(moveSpeedBonusCoefficient, 1f, base.age / duration); velocity.y = base.characterMotor.velocity.y; base.characterMotor.velocity = velocity; } } else { base.characterMotor.velocity = UnityEngine.Vector3.zero; hitPauseTimer -= GetDeltaTime(); animator.SetFloat(WhirlwindplaybackRateParamHash, 0f); } if (base.fixedAge >= duration) { while (swingCount < 2) { swingCount++; overlapAttack.Fire(); } outer.SetNextStateToMain(); } } } public class WhirlwindAir : WhirlwindBase { private static int WhirlwindAirExitStateHash = Animator.StringToHash("WhirlwindAirExit"); private static int WhirlwindAirStateHash = Animator.StringToHash("WhirlwindAir"); private static int WhirlwindParamHash = Animator.StringToHash("Whirlwind.playbackRate"); protected override void PlayAnim() { PlayCrossfade("FullBody, Override", WhirlwindAirStateHash, WhirlwindParamHash, duration, 0.1f); } public override void OnExit() { base.OnExit(); PlayAnimation("FullBody, Override", WhirlwindAirExitStateHash); } } public class WhirlwindEntry : BaseState { public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { EntityState nextState = (((bool)base.characterMotor && base.characterMotor.isGrounded) ? ((WhirlwindBase)new WhirlwindGround()) : ((WhirlwindBase)new WhirlwindAir())); outer.SetNextState(nextState); } } } public class WhirlwindGround : WhirlwindBase { private static int WhirlwindGroundStateHash = Animator.StringToHash("WhirlwindGround"); private static int LightImpactStateHash = Animator.StringToHash("LightImpact"); private static int WhirlwindParamHash = Animator.StringToHash("Whirlwind.playbackRate"); protected override void PlayAnim() { PlayCrossfade("FullBody, Override", WhirlwindGroundStateHash, WhirlwindParamHash, duration, 0.1f); } public override void OnExit() { base.OnExit(); int layerIndex = animator.GetLayerIndex("Impact"); if (layerIndex >= 0) { animator.SetLayerWeight(layerIndex, 3f); PlayAnimation("Impact", LightImpactStateHash); } } } } namespace EntityStates.Merc.Weapon { public class GroundLight2 : BasicMeleeAttack, SteppedSkillDef.IStepSetter { public int step; public static float recoilAmplitude; public static float baseDurationBeforeInterruptable; [SerializeField] public float bloom; public static float comboFinisherBaseDuration; public static GameObject comboFinisherSwingEffectPrefab; public static float comboFinisherhitPauseDuration; public static float comboFinisherDamageCoefficient; public static float comboFinisherBloom; public static float comboFinisherBaseDurationBeforeInterruptable; public static string slash1Sound; public static string slash3Sound; private string animationStateName; private float durationBeforeInterruptable; private bool isComboFinisher => step == 2; protected override bool allowExitFire { get { if ((bool)base.characterBody) { return !base.characterBody.isSprinting; } return false; } } void SteppedSkillDef.IStepSetter.SetStep(int i) { step = i; } public override void OnEnter() { if (isComboFinisher) { swingEffectPrefab = comboFinisherSwingEffectPrefab; hitPauseDuration = comboFinisherhitPauseDuration; damageCoefficient = comboFinisherDamageCoefficient; bloom = comboFinisherBloom; hitBoxGroupName = "SwordLarge"; baseDuration = comboFinisherBaseDuration; } base.OnEnter(); base.characterDirection.forward = GetAimRay().direction; durationBeforeInterruptable = (isComboFinisher ? (comboFinisherBaseDurationBeforeInterruptable / attackSpeedStat) : (baseDurationBeforeInterruptable / attackSpeedStat)); } public override void OnExit() { base.OnExit(); } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); if (isComboFinisher) { overlapAttack.damageType = DamageType.ApplyMercExpose; } } protected override void PlayAnimation() { animationStateName = ""; string soundString = null; switch (step) { case 0: animationStateName = "GroundLight1"; soundString = slash1Sound; break; case 1: animationStateName = "GroundLight2"; soundString = slash1Sound; break; case 2: animationStateName = "GroundLight3"; soundString = slash3Sound; break; } bool @bool = animator.GetBool("isMoving"); bool bool2 = animator.GetBool("isGrounded"); if (!@bool && bool2) { PlayCrossfade("FullBody, Override", animationStateName, "GroundLight.playbackRate", duration, 0.05f); } else { PlayCrossfade("Gesture, Additive", animationStateName, "GroundLight.playbackRate", duration, 0.05f); PlayCrossfade("Gesture, Override", animationStateName, "GroundLight.playbackRate", duration, 0.05f); } Util.PlaySound(soundString, base.gameObject); } protected override void OnMeleeHitAuthority() { base.OnMeleeHitAuthority(); base.characterBody.AddSpreadBloom(bloom); } protected override void BeginMeleeAttackEffect() { swingEffectMuzzleString = animationStateName; AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); base.BeginMeleeAttackEffect(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)step); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); step = reader.ReadByte(); } public override InterruptPriority GetMinimumInterruptPriority() { if (!(base.fixedAge < durationBeforeInterruptable)) { return InterruptPriority.Skill; } return InterruptPriority.PrioritySkill; } } public class ThrowEvisProjectile : GenericProjectileBaseState { public static float shortHopVelocity; private static int GroundLight3StateHash = Animator.StringToHash("GroundLight3"); private static int GroundLightParamHash = Animator.StringToHash("GroundLight.playbackRate"); public override void OnEnter() { base.OnEnter(); if ((bool)base.characterMotor) { base.characterMotor.velocity.y = Mathf.Max(base.characterMotor.velocity.y, shortHopVelocity); } } protected override void PlayAnimation(float duration) { Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { bool @bool = modelAnimator.GetBool("isMoving"); bool bool2 = modelAnimator.GetBool("isGrounded"); if (@bool || !bool2) { PlayAnimation("Gesture, Additive", GroundLight3StateHash, GroundLightParamHash, duration); PlayAnimation("Gesture, Override", GroundLight3StateHash, GroundLightParamHash, duration); } else { PlayAnimation("FullBody, Override", GroundLight3StateHash, GroundLightParamHash, duration); } } } protected override Ray ModifyProjectileAimRay(Ray aimRay) { TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, projectilePrefab, base.gameObject); return aimRay; } } } namespace EntityStates.MegaConstruct { public class FallingDeath : GenericCharacterDeath { public static float deathDelay; public static GameObject enterEffectPrefab; public static GameObject deathEffectPrefab; public static float explosionForce; public static string standableSurfaceChildName; private bool hasDied; public override void OnEnter() { base.OnEnter(); EffectManager.SimpleImpactEffect(enterEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: true); MasterSpawnSlotController component = GetComponent(); if (NetworkServer.active && (bool)component) { component.KillAll(); } ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { Transform transform = modelChildLocator.FindChild(standableSurfaceChildName); if ((bool)transform) { transform.gameObject.SetActive(value: false); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > deathDelay && NetworkServer.active && !hasDied) { hasDied = true; EffectManager.SimpleImpactEffect(deathEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: true); DestroyBodyAsapServer(); } } public override void OnExit() { Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { Rigidbody component = GetComponent(); RagdollController component2 = modelTransform.GetComponent(); if ((bool)component2 && (bool)component) { component2.BeginRagdoll(component.velocity); } ExplodeRigidbodiesOnStart component3 = modelTransform.GetComponent(); if ((bool)component3) { component3.force = explosionForce; component3.enabled = true; } } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.enabled = false; } base.OnExit(); } } public class RaiseShield : FlyState { [SerializeField] public GameObject attachmentPrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationEnterStateName; [SerializeField] public float duration; private NetworkedBodyAttachment attachment; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active && (bool)attachmentPrefab) { attachment = UnityEngine.Object.Instantiate(attachmentPrefab).GetComponent(); attachment.AttachToGameObjectAndSpawn(base.characterBody.gameObject); } MasterSpawnSlotController component = GetComponent(); if (NetworkServer.active && (bool)component) { component.SpawnAllOpen(base.gameObject, Run.instance.stageRng); } PlayAnimation(animationLayerName, animationEnterStateName); } protected override bool CanExecuteSkill(GenericSkill skillSlot) { return false; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new ExitShield()); } } public override void OnExit() { if (NetworkServer.active && (bool)attachment) { EntityState.Destroy(attachment.gameObject); } base.OnExit(); } } public class ExitShield : BaseState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackParameterName; [SerializeField] public float baseDuration; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, baseDuration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > baseDuration) { outer.SetNextStateToMain(); } } } public class Spawn : BaseState { [SerializeField] public float duration; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public int numPads; [SerializeField] public string padChildLocatorName; [SerializeField] public GameObject padPrefab; [SerializeField] public string enterSoundString; [SerializeField] public bool depleteStocksPrimary; [SerializeField] public bool depleteStocksSecondary; [SerializeField] public bool depleteStocksUtility; [SerializeField] public bool depleteStocksSpecial; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } Util.PlaySound(enterSoundString, base.gameObject); } private void CheckForDepleteStocks(SkillSlot slot, bool deplete) { GenericSkill skill = base.skillLocator.GetSkill(slot); if (deplete && (bool)skill) { skill.RemoveAllStocks(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if (base.isAuthority) { CheckForDepleteStocks(SkillSlot.Primary, depleteStocksPrimary); CheckForDepleteStocks(SkillSlot.Secondary, depleteStocksSecondary); CheckForDepleteStocks(SkillSlot.Utility, depleteStocksUtility); CheckForDepleteStocks(SkillSlot.Special, depleteStocksSpecial); } base.OnExit(); } } public class SpawnMinorConstructs : BaseState { [SerializeField] public float duration; [SerializeField] public int numToSpawn; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } MasterSpawnSlotController component = GetComponent(); if (NetworkServer.active && (bool)component) { component.SpawnRandomOpen(numToSpawn, Run.instance.stageRng, base.gameObject); } Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.MajorConstruct { public class Death : GenericCharacterDeath { [SerializeField] public float duration; [SerializeField] public GameObject beginEffect; [SerializeField] public string beginMuzzleName; [SerializeField] public GameObject padEffect; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; protected override bool shouldAutoDestroy => false; protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayAnimation(animationLayerName, animationStateName); } public override void OnEnter() { base.OnEnter(); if ((bool)beginEffect) { EffectManager.SimpleMuzzleFlash(beginEffect, base.gameObject, beginMuzzleName, transmit: false); } FindModelChild("Collision").gameObject.SetActive(value: false); MasterSpawnSlotController component = GetComponent(); if (NetworkServer.active) { _ = (bool)component; } } } public class Spawn : BaseState { [SerializeField] public float duration; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public int numPads; [SerializeField] public float padRingRadius; [SerializeField] public float maxRaycastDistance; [SerializeField] public GameObject padPrefab; [SerializeField] public float maxPadDistance; [SerializeField] public GameObject padEffectPrefab; [SerializeField] public bool alignPadsToNormal; [SerializeField] public string enterSoundString; [SerializeField] public bool depleteStocksPrimary; [SerializeField] public bool depleteStocksSecondary; [SerializeField] public bool depleteStocksUtility; [SerializeField] public bool depleteStocksSpecial; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } Util.PlaySound(enterSoundString, base.gameObject); MasterSpawnSlotController component = GetComponent(); if (!NetworkServer.active || !padPrefab || !component) { return; } RaycastHit hitInfo = default(RaycastHit); for (int i = 0; i < numPads; i++) { UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(0f, 360f * ((float)i / (float)numPads), 0f); UnityEngine.Vector3 vector = base.characterBody.corePosition + quaternion * UnityEngine.Vector3.forward * padRingRadius; UnityEngine.Vector3 origin = vector + UnityEngine.Vector3.up * maxRaycastDistance; if (Physics.Raycast(vector, UnityEngine.Vector3.up, out hitInfo, maxRaycastDistance, LayerIndex.world.mask)) { origin = hitInfo.point; } if (Physics.Raycast(origin, UnityEngine.Vector3.down, out hitInfo, maxRaycastDistance * 2f, LayerIndex.world.mask) && UnityEngine.Vector3.Distance(base.characterBody.corePosition, hitInfo.point) < maxPadDistance) { if (alignPadsToNormal) { quaternion = UnityEngine.Quaternion.FromToRotation(UnityEngine.Vector3.up, hitInfo.normal) * quaternion; } GameObject obj = UnityEngine.Object.Instantiate(padPrefab, hitInfo.point, quaternion); NetworkedBodySpawnSlot component2 = obj.GetComponent(); if ((bool)component2) { component.slots.Add(component2); } NetworkServer.Spawn(obj); if ((bool)padEffectPrefab) { EffectData effectData = new EffectData { origin = hitInfo.point, rotation = quaternion }; EffectManager.SpawnEffect(padEffectPrefab, effectData, transmit: true); } } } } private void CheckForDepleteStocks(SkillSlot slot, bool deplete) { GenericSkill skill = base.skillLocator.GetSkill(slot); if (deplete && (bool)skill) { skill.RemoveAllStocks(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if (base.isAuthority) { CheckForDepleteStocks(SkillSlot.Primary, depleteStocksPrimary); CheckForDepleteStocks(SkillSlot.Secondary, depleteStocksSecondary); CheckForDepleteStocks(SkillSlot.Utility, depleteStocksUtility); CheckForDepleteStocks(SkillSlot.Special, depleteStocksSpecial); } base.OnExit(); } } public class SpawnMinorConstructs : BaseState { [SerializeField] public float duration; [SerializeField] public int numToSpawn; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParam; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } MasterSpawnSlotController component = GetComponent(); if (NetworkServer.active && (bool)component) { component.SpawnRandomOpen(numToSpawn, Run.instance.stageRng, base.gameObject); } Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SwitchStance : BaseState { private const string stanceStateMachineName = "Stance"; public override void OnEnter() { base.OnEnter(); if (!base.isAuthority) { return; } EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Stance"); EntityState state = entityStateMachine.state; if (!(state is Raised)) { if (state is Lowered) { entityStateMachine.SetNextState(new LoweredToRaised()); } } else { entityStateMachine.SetNextState(new RaisedToLowered()); } outer.SetNextStateToMain(); } } } namespace EntityStates.MajorConstruct.Stance { public class Lowered : BaseState { [SerializeField] public GameObject attachmentPrefab; private NetworkedBodyAttachment attachment; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active && (bool)attachmentPrefab) { attachment = UnityEngine.Object.Instantiate(attachmentPrefab).GetComponent(); attachment.AttachToGameObjectAndSpawn(base.characterBody.gameObject); } } public override void OnExit() { if ((bool)attachment) { EntityState.Destroy(attachment.gameObject); } base.OnExit(); } } public class LoweredToRaised : BaseState { [SerializeField] public float duration; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParameter; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParameter, duration); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new Raised()); } } } public class Raised : BaseState { } public class RaisedToLowered : BaseState { [SerializeField] public float duration; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackRateParameter; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParameter, duration); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new Lowered()); } } } } namespace EntityStates.MajorConstruct.Weapon { public class ChargeLaser : BaseState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackParameterName; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, duration); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new FireLaser()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class FireLaser : FireBeam { [SerializeField] public float duration; [SerializeField] public float aimMaxSpeed; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackParameterName; [SerializeField] public LoopSoundDef loopSoundDef; private LoopSoundManager.SoundLoopPtr loopPtr; private AimAnimator.DirectionOverrideRequest animatorDirectionOverrideRequest; private UnityEngine.Vector3 aimDirection; private UnityEngine.Vector3 aimVelocity; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, duration); if ((bool)loopSoundDef) { loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSoundDef); } AimAnimator component = GetComponent(); if ((bool)component) { animatorDirectionOverrideRequest = component.RequestDirectionOverride(GetAimDirection); } aimDirection = GetTargetDirection(); } public override void OnExit() { animatorDirectionOverrideRequest?.Dispose(); LoopSoundManager.StopSoundLoopLocal(loopPtr); base.OnExit(); } public override void FixedUpdate() { aimDirection = UnityEngine.Vector3.RotateTowards(aimDirection, GetTargetDirection(), aimMaxSpeed * (MathF.PI / 180f) * GetDeltaTime(), float.PositiveInfinity); base.FixedUpdate(); } public override void ModifyBullet(BulletAttack bulletAttack) { } protected override EntityState GetNextState() { return new TerminateLaser(GetBeamEndPoint()); } public override bool ShouldFireLaser() { return duration > base.fixedAge; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } private UnityEngine.Vector3 GetAimDirection() { return aimDirection; } private UnityEngine.Vector3 GetTargetDirection() { if ((bool)base.inputBank) { return base.inputBank.aimDirection; } return base.transform.forward; } public override Ray GetLaserRay() { if ((bool)base.inputBank) { return new Ray(base.inputBank.aimOrigin, aimDirection); } return new Ray(base.transform.position, aimDirection); } } public class TerminateLaser : BaseState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string animationPlaybackParameterName; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public GameObject explosionEffectPrefab; [SerializeField] public float blastDamageCoefficient; [SerializeField] public float blastForceMagnitude; [SerializeField] public float blastRadius; [SerializeField] public UnityEngine.Vector3 blastBonusForce; [SerializeField] public string enterSoundString; private UnityEngine.Vector3 blastPosition; public TerminateLaser() { } public TerminateLaser(UnityEngine.Vector3 blastPosition) { this.blastPosition = blastPosition; } public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, duration); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } Util.PlaySound(enterSoundString, base.gameObject); if (base.isAuthority) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * blastDamageCoefficient; blastAttack.baseForce = blastForceMagnitude; blastAttack.position = blastPosition; blastAttack.radius = blastRadius; blastAttack.bonusForce = blastBonusForce; blastAttack.Fire(); EffectData effectData = new EffectData { origin = blastPosition, scale = blastRadius }; EffectManager.SpawnEffect(explosionEffectPrefab, effectData, transmit: true); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.Mage { public class FlyUpState : MageCharacterMain { public static GameObject blinkPrefab; public static float duration = 0.3f; public static string beginSoundString; public static string endSoundString; public static AnimationCurve speedCoefficientCurve; public static GameObject muzzleflashEffect; public static float blastAttackRadius; public static float blastAttackDamageCoefficient; public static float blastAttackProcCoefficient; public static float blastAttackForce; private UnityEngine.Vector3 flyVector = UnityEngine.Vector3.zero; private Transform modelTransform; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private UnityEngine.Vector3 blastPosition; public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); flyVector = UnityEngine.Vector3.up; CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); PlayCrossfade("Body", "FlyUp", "FlyUp.playbackRate", duration, 0.1f); base.characterMotor.Motor.ForceUnground(); base.characterMotor.velocity = UnityEngine.Vector3.zero; EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleLeft", transmit: false); EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleRight", transmit: false); if (base.isAuthority) { blastPosition = base.characterBody.corePosition; } if (NetworkServer.active) { BlastAttack obj = new BlastAttack { radius = blastAttackRadius, procCoefficient = blastAttackProcCoefficient, position = blastPosition, attacker = base.gameObject, crit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master), baseDamage = base.characterBody.damage * blastAttackDamageCoefficient, falloffModel = BlastAttack.FalloffModel.None, baseForce = blastAttackForce }; obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker); obj.damageType = DamageType.Stun1s; obj.attackerFiltering = AttackerFiltering.NeverHitSelf; obj.Fire(); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(blastPosition); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); blastPosition = reader.ReadVector3(); } public override void HandleMovements() { base.HandleMovements(); base.characterMotor.rootMotion += flyVector * (moveSpeedStat * speedCoefficientCurve.Evaluate(base.fixedAge / duration) * GetDeltaTime()); base.characterMotor.velocity.y = 0f; } protected override void UpdateAnimationParameters() { base.UpdateAnimationParameters(); } private void CreateBlinkEffect(UnityEngine.Vector3 origin) { EffectData effectData = new EffectData(); effectData.rotation = Util.QuaternionSafeLookRotation(flyVector); effectData.origin = origin; EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if (!outer.destroying) { Util.PlaySound(endSoundString, base.gameObject); } base.OnExit(); } } public class MageCharacterMain : GenericCharacterMain { private EntityStateMachine jetpackStateMachine; public bool jumpButtonState; private bool heldPress; private bool jumpToggledState; private float oldJumpHeldTime; private float jumpButtonHeldTime; public override void OnEnter() { base.OnEnter(); jetpackStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Jet"); } public override void ProcessJump() { if (hasCharacterMotor && hasInputBank && base.isAuthority) { if (NetworkUser.readOnlyLocalPlayersList[0]?.localUser?.userProfile.toggleArtificerHover ?? true) { if (base.inputBank.jump.down) { oldJumpHeldTime = jumpButtonHeldTime; jumpButtonHeldTime += Time.deltaTime; heldPress = oldJumpHeldTime < 0.5f && jumpButtonHeldTime >= 0.5f; } else { oldJumpHeldTime = 0f; jumpButtonHeldTime = 0f; heldPress = false; } if (!base.characterMotor.isGrounded) { if (base.characterMotor.jumpCount == base.characterBody.maxJumpCount) { if (base.inputBank.jump.justPressed) { jumpButtonState = !jumpButtonState; } } else if (heldPress) { jumpButtonState = !jumpButtonState; } } else { jumpButtonState = false; } } else { jumpButtonState = base.inputBank.jump.down; } bool num = jumpButtonState && base.characterMotor.velocity.y < 0f && !base.characterMotor.isGrounded; bool flag = jetpackStateMachine.state.GetType() == typeof(JetpackOn); if (num && !flag) { jetpackStateMachine.SetNextState(new JetpackOn()); } if (!num && flag) { jetpackStateMachine.SetNextState(new Idle()); } } base.ProcessJump(); } public override void OnExit() { if (base.isAuthority && (bool)jetpackStateMachine) { jetpackStateMachine.SetNextState(new Idle()); } base.OnExit(); } } public class JetpackOn : BaseState { public static float hoverVelocity; public static float hoverAcceleration; private Transform jetOnEffect; protected static UnityEngine.Vector3 _tempVec3 = UnityEngine.Vector3.one; public override void Reset() { base.Reset(); jetOnEffect = null; } public override void OnEnter() { base.OnEnter(); jetOnEffect = FindModelChild("JetOn"); if ((bool)jetOnEffect) { jetOnEffect.gameObject.SetActive(value: true); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { float y = base.characterMotor.velocity.y; y = Mathf.MoveTowards(y, hoverVelocity, hoverAcceleration * GetDeltaTime()); base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, y, base.characterMotor.velocity.z); } } public override void OnExit() { base.OnExit(); if ((bool)jetOnEffect) { jetOnEffect.gameObject.SetActive(value: false); } } } } namespace EntityStates.Mage.Weapon { public class ChargeMeteor : BaseState { public static float baseChargeDuration; public static float baseDuration; public static GameObject areaIndicatorPrefab; public static float minMeteorRadius = 0f; public static float maxMeteorRadius = 10f; public static GameObject meteorEffect; public static float minDamageCoefficient; public static float maxDamageCoefficient; public static float procCoefficient; public static float force; public static GameObject muzzleflashEffect; private float stopwatch; private GameObject areaIndicatorInstance; private bool fireMeteor; private float radius; private float chargeDuration; private float duration; private BlastAttack blastAttack; private EffectData _effectData; private UnityEngine.Vector3 _cachedScale = UnityEngine.Vector3.one; private EffectManagerHelper _emh_areaIndicatorInstance; public override void Reset() { base.Reset(); stopwatch = 0f; areaIndicatorInstance = null; fireMeteor = false; radius = 0f; chargeDuration = 0f; duration = 0f; if (blastAttack != null) { blastAttack.Reset(); } if (_effectData != null) { _effectData.Reset(); } _emh_areaIndicatorInstance = null; } public override void OnEnter() { base.OnEnter(); chargeDuration = baseChargeDuration / attackSpeedStat; duration = baseDuration / attackSpeedStat; UpdateAreaIndicator(); } private void UpdateAreaIndicator() { if ((bool)areaIndicatorInstance) { float maxDistance = 1000f; if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask)) { areaIndicatorInstance.transform.position = hitInfo.point; areaIndicatorInstance.transform.up = hitInfo.normal; } } else if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab)) { areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab); } else { _emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity); areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject; } radius = Util.Remap(Mathf.Clamp01(stopwatch / chargeDuration), 0f, 1f, minMeteorRadius, maxMeteorRadius); _cachedScale.x = radius; _cachedScale.y = radius; _cachedScale.z = radius; areaIndicatorInstance.transform.localScale = _cachedScale; } public override void Update() { base.Update(); UpdateAreaIndicator(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if ((stopwatch >= duration || base.inputBank.skill2.justReleased) && base.isAuthority) { fireMeteor = true; outer.SetNextStateToMain(); } } public override void OnExit() { EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "Muzzle", transmit: false); if ((bool)areaIndicatorInstance) { if (fireMeteor) { float num = Util.Remap(Mathf.Clamp01(stopwatch / chargeDuration), 0f, 1f, minDamageCoefficient, maxDamageCoefficient); if (_effectData == null) { _effectData = new EffectData(); } _effectData.origin = areaIndicatorInstance.transform.position; _effectData.scale = radius; EffectManager.SpawnEffect(meteorEffect, _effectData, transmit: true); if (blastAttack == null) { blastAttack = new BlastAttack(); } blastAttack.radius = radius; blastAttack.procCoefficient = procCoefficient; blastAttack.position = areaIndicatorInstance.transform.position; blastAttack.attacker = base.gameObject; blastAttack.crit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master); blastAttack.baseDamage = base.characterBody.damage * num; blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot; blastAttack.baseForce = force; blastAttack.teamIndex = TeamComponent.GetObjectTeam(blastAttack.attacker); blastAttack.Fire(); } if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null) { _emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance); } else { EntityState.Destroy(areaIndicatorInstance.gameObject); } areaIndicatorInstance = null; _emh_areaIndicatorInstance = null; } base.OnExit(); } } public abstract class BaseChargeBombState : BaseSkillState { [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string chargeSoundString; [SerializeField] public float baseDuration = 1.5f; [SerializeField] public float minBloomRadius; [SerializeField] public float maxBloomRadius; [SerializeField] public GameObject crosshairOverridePrefab; [SerializeField] public float minChargeDuration = 0.5f; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private uint loopSoundInstanceId; private static int EmptyStateHash = Animator.StringToHash("Empty"); private static int ChargeNovaBombStateHash = Animator.StringToHash("ChargeNovaBomb"); private static int ChargeNovaBombParamHash = Animator.StringToHash("ChargeNovaBomb.playbackRate"); protected float duration { get; private set; } protected Animator animator { get; private set; } protected ChildLocator childLocator { get; private set; } protected GameObject chargeEffectInstance { get; private set; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; animator = GetModelAnimator(); childLocator = GetModelChildLocator(); if ((bool)childLocator) { Transform transform = childLocator.FindChild("MuzzleBetween") ?? base.characterBody.coreTransform; if ((bool)transform && (bool)chargeEffectPrefab) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); ObjectScaleCurve component2 = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } if ((bool)component2) { component2.timeMax = duration; } } } PlayChargeAnimation(); loopSoundInstanceId = Util.PlayAttackSpeedSound(chargeSoundString, base.gameObject, attackSpeedStat); if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } StartAimMode(duration + 2f); } public override void OnExit() { crosshairOverrideRequest?.Dispose(); AkSoundEngine.StopPlayingID(loopSoundInstanceId); if (!outer.destroying) { PlayAnimation("Gesture, Additive", EmptyStateHash); } EntityState.Destroy(chargeEffectInstance); base.OnExit(); } protected float CalcCharge() { return Mathf.Clamp01(base.fixedAge / duration); } public override void FixedUpdate() { base.FixedUpdate(); float charge = CalcCharge(); if (base.isAuthority && ((!IsKeyDownAuthority() && base.fixedAge >= minChargeDuration) || base.fixedAge >= duration)) { BaseThrowBombState nextState = GetNextState(); nextState.charge = charge; outer.SetNextState(nextState); } } public override void Update() { base.Update(); base.characterBody.SetSpreadBloom(Util.Remap(CalcCharge(), 0f, 1f, minBloomRadius, maxBloomRadius)); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } protected abstract BaseThrowBombState GetNextState(); protected virtual void PlayChargeAnimation() { PlayAnimation("Gesture, Additive", ChargeNovaBombStateHash, ChargeNovaBombParamHash, duration); } } public abstract class BaseThrowBombState : BaseState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float baseDuration; [SerializeField] public float minDamageCoefficient; [SerializeField] public float maxDamageCoefficient; [SerializeField] public float force; [SerializeField] public float selfForce; protected float duration; public float charge; private static int FireNovaBombStateHash = Animator.StringToHash("FireNovaBomb"); private static int FireNovaBombParamHash = Animator.StringToHash("FireNovaBomb.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayThrowAnimation(); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "MuzzleLeft", transmit: false); EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "MuzzleRight", transmit: false); } Fire(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override void OnExit() { base.OnExit(); } private void Fire() { if (base.isAuthority) { Ray ray = GetAimRay(); if (projectilePrefab != null) { float num = Util.Remap(charge, 0f, 1f, minDamageCoefficient, maxDamageCoefficient); float num2 = charge * force; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = ray.origin; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * num; fireProjectileInfo.force = num2; fireProjectileInfo.crit = RollCrit(); FireProjectileInfo projectileInfo = fireProjectileInfo; ModifyProjectile(ref projectileInfo); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, ref projectileInfo); ProjectileManager.instance.FireProjectile(projectileInfo); } if ((bool)base.characterMotor) { base.characterMotor.ApplyForce(ray.direction * ((0f - selfForce) * charge)); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } protected virtual void PlayThrowAnimation() { PlayAnimation("Gesture, Additive", FireNovaBombStateHash, FireNovaBombParamHash, duration); } protected virtual void ModifyProjectile(ref FireProjectileInfo projectileInfo) { } } public class ChargeNovabomb : BaseChargeBombState { protected override BaseThrowBombState GetNextState() { return new ThrowNovabomb(); } } public class ThrowNovabomb : BaseThrowBombState { } public class ChargeIcebomb : BaseChargeBombState { protected override BaseThrowBombState GetNextState() { return new ThrowIcebomb(); } } public class ThrowIcebomb : BaseThrowBombState { } public class FireFireBolt : BaseState, SteppedSkillDef.IStepSetter { public enum Gauntlet { Left, Right } [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float procCoefficient; [SerializeField] public float damageCoefficient; [SerializeField] public float force = 20f; public static float attackSpeedAltAnimationThreshold; [SerializeField] public float baseDuration; [SerializeField] public string attackSoundString; [SerializeField] public float attackSoundPitch; public static float bloom; private float duration; private bool hasFiredGauntlet; private string muzzleString; private Transform muzzleTransform; private Animator animator; private ChildLocator childLocator; private Gauntlet gauntlet; private static int EmptyStateHash = Animator.StringToHash("Empty"); private static int Cast1LeftStateHash = Animator.StringToHash("Cast1Left"); private static int FireGauntletLeftStateHash = Animator.StringToHash("FireGauntletLeft"); private static int Cast1RightStateHash = Animator.StringToHash("Cast1Right"); private static int FireGauntletRightStateHash = Animator.StringToHash("FireGauntletRight"); private static int HoldGauntletsUpStateHash = Animator.StringToHash("HoldGauntletsUp"); private static int FireGauntletParamHash = Animator.StringToHash("FireGauntlet.playbackRate"); public void SetStep(int i) { gauntlet = (Gauntlet)i; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch); base.characterBody.SetAimTimer(2f); animator = GetModelAnimator(); if ((bool)animator) { childLocator = animator.GetComponent(); } switch (gauntlet) { case Gauntlet.Left: muzzleString = "MuzzleLeft"; if (attackSpeedStat < attackSpeedAltAnimationThreshold) { PlayCrossfade("Gesture, Additive", Cast1LeftStateHash, FireGauntletParamHash, duration, 0.1f); PlayAnimation("Gesture Left, Additive", EmptyStateHash); PlayAnimation("Gesture Right, Additive", EmptyStateHash); } else { PlayAnimation("Gesture Left, Additive", FireGauntletLeftStateHash, FireGauntletParamHash, duration); PlayAnimation("Gesture, Additive", HoldGauntletsUpStateHash, FireGauntletParamHash, duration); FireGauntlet(); } break; case Gauntlet.Right: muzzleString = "MuzzleRight"; if (attackSpeedStat < attackSpeedAltAnimationThreshold) { PlayCrossfade("Gesture, Additive", Cast1RightStateHash, FireGauntletParamHash, duration, 0.1f); PlayAnimation("Gesture Left, Additive", EmptyStateHash); PlayAnimation("Gesture Right, Additive", EmptyStateHash); } else { PlayAnimation("Gesture Right, Additive", FireGauntletRightStateHash, FireGauntletParamHash, duration); PlayAnimation("Gesture, Additive", HoldGauntletsUpStateHash, FireGauntletParamHash, duration); FireGauntlet(); } break; } } public override void OnExit() { base.OnExit(); } private void FireGauntlet() { if (!hasFiredGauntlet) { base.characterBody.AddSpreadBloom(bloom); hasFiredGauntlet = true; Ray ray = GetAimRay(); if ((bool)childLocator) { muzzleTransform = childLocator.FindChild(muzzleString); } if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (base.isAuthority) { TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageCoefficient * damageStat, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } } public override void FixedUpdate() { base.FixedUpdate(); if (animator.GetFloat("FireGauntlet.fire") > 0f && !hasFiredGauntlet) { FireGauntlet(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)gauntlet); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); gauntlet = (Gauntlet)reader.ReadByte(); } } public class FireIceBolt : FireFireBolt { } public class FireLightningBolt : FireFireBolt { } public class FireIceOrb : BaseState { public enum Gauntlet { Left, Right } public static GameObject projectilePrefab; public static GameObject effectPrefab; public static float baseDuration = 2f; public static float damageCoefficient = 1.2f; public static string attackString; private float duration; private bool hasFiredGauntlet; private string muzzleString; private Animator animator; public Gauntlet gauntlet; private static int FireGauntletLeftStateHash = Animator.StringToHash("FireGauntletLeft"); private static int FireGauntletRightStateHash = Animator.StringToHash("FireGauntletRight"); private static int HoldGauntletsUpStateHash = Animator.StringToHash("HoldGauntletsUp"); private static int FireGauntletParamHash = Animator.StringToHash("FireGauntlet.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; switch (gauntlet) { case Gauntlet.Left: muzzleString = "MuzzleLeft"; PlayAnimation("Gesture Left, Additive", FireGauntletLeftStateHash, FireGauntletParamHash, duration); break; case Gauntlet.Right: muzzleString = "MuzzleRight"; PlayAnimation("Gesture Right, Additive", FireGauntletRightStateHash, FireGauntletParamHash, duration); break; } PlayAnimation("Gesture, Additive", HoldGauntletsUpStateHash, FireGauntletParamHash, duration); Util.PlaySound(attackString, base.gameObject); animator = GetModelAnimator(); base.characterBody.SetAimTimer(2f); FireGauntlet(); } public override void OnExit() { base.OnExit(); } private void FireGauntlet() { hasFiredGauntlet = true; Ray aimRay = GetAimRay(); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleString, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void FixedUpdate() { base.FixedUpdate(); if (animator.GetFloat("FireGauntlet.fire") > 0f && !hasFiredGauntlet) { FireGauntlet(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireLaserbolt : BaseState { public enum Gauntlet { Left, Right } public static GameObject muzzleEffectPrefab; public static GameObject tracerEffectPrefab; public static GameObject impactEffectPrefab; public static float baseDuration = 2f; public static float damageCoefficient = 1.2f; public static float force = 20f; public static string attackString; private float duration; private bool hasFiredGauntlet; private string muzzleString; private Animator animator; public Gauntlet gauntlet; private static int FireGauntletLeftStateHash = Animator.StringToHash("FireGauntletLeft"); private static int FireGauntletRightStateHash = Animator.StringToHash("FireGauntletRight"); private static int HoldGauntletsUpStateHash = Animator.StringToHash("HoldGauntletsUp"); private static int FireGauntletParamHash = Animator.StringToHash("FireGauntlet.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; switch (gauntlet) { case Gauntlet.Left: muzzleString = "MuzzleLeft"; PlayAnimation("Gesture Left, Additive", FireGauntletLeftStateHash, FireGauntletParamHash, duration); break; case Gauntlet.Right: muzzleString = "MuzzleRight"; PlayAnimation("Gesture Right, Additive", FireGauntletRightStateHash, FireGauntletParamHash, duration); break; } PlayAnimation("Gesture, Additive", HoldGauntletsUpStateHash, FireGauntletParamHash, duration); Util.PlaySound(attackString, base.gameObject); animator = GetModelAnimator(); base.characterBody.SetAimTimer(2f); FireGauntlet(); } public override void OnExit() { base.OnExit(); } private void FireGauntlet() { hasFiredGauntlet = true; Ray aimRay = GetAimRay(); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = base.characterBody.spreadBloomAngle; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleString; bulletAttack.hitEffectPrefab = impactEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.radius = 0.1f; bulletAttack.smartCollision = false; bulletAttack.Fire(); } } public override void FixedUpdate() { base.FixedUpdate(); if (animator.GetFloat("FireGauntlet.fire") > 0f && !hasFiredGauntlet) { FireGauntlet(); } if (base.fixedAge >= duration && base.isAuthority) { if (base.inputBank.skill1.down) { FireLaserbolt fireLaserbolt = new FireLaserbolt(); fireLaserbolt.gauntlet = ((gauntlet == Gauntlet.Left) ? Gauntlet.Right : Gauntlet.Left); outer.SetNextState(fireLaserbolt); } else { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireRoller : BaseState { public static GameObject fireProjectilePrefab; public static GameObject iceProjectilePrefab; public static GameObject lightningProjectilePrefab; public static GameObject fireMuzzleflashEffectPrefab; public static GameObject iceMuzzleflashEffectPrefab; public static GameObject lightningMuzzleflashEffectPrefab; public static GameObject fireAreaIndicatorPrefab; public static GameObject iceAreaIndicatorPrefab; public static GameObject lightningAreaIndicatorPrefab; public static string fireAttackSoundString; public static string iceAttackSoundString; public static string lightningAttackSoundString; public static float targetProjectileSpeed; public static float baseEntryDuration = 2f; public static float baseDuration = 2f; public static float baseExitDuration = 2f; public static float fireDamageCoefficient; public static float iceDamageCoefficient; public static float lightningDamageCoefficient; private float stopwatch; private float fireDuration; private float entryDuration; private float exitDuration; private bool hasFiredRoller; private bool hasBegunExit; private GameObject areaIndicatorInstance; private string muzzleString; private Transform muzzleTransform; private Animator animator; private ChildLocator childLocator; private GameObject areaIndicatorPrefab; private float damageCoefficient = 1.2f; private string attackString; private GameObject projectilePrefab; private GameObject muzzleflashEffectPrefab; private EffectManagerHelper _emh_areaIndicatorInstance; private static int EmptyStateHash = Animator.StringToHash("Empty"); private static int EnterRollerStateHash = Animator.StringToHash("EnterRoller"); private static int EnterRollerParamHash = Animator.StringToHash("EnterRoller.playbackRate"); private static int FireRollerStateHash = Animator.StringToHash("FireRoller"); private static int FireRollerParamHash = Animator.StringToHash("FireRoller.playbackRate"); private static int ExitRollerStateHash = Animator.StringToHash("ExitRoller"); private static int ExitRollerParamHash = Animator.StringToHash("ExitRoller.playbackRate"); public override void Reset() { base.Reset(); fireDuration = 0f; entryDuration = 0f; exitDuration = 0f; hasFiredRoller = false; hasBegunExit = false; areaIndicatorInstance = null; muzzleString = string.Empty; muzzleTransform = null; animator = null; childLocator = null; areaIndicatorPrefab = null; damageCoefficient = 1.2f; attackString = string.Empty; projectilePrefab = null; muzzleflashEffectPrefab = null; _emh_areaIndicatorInstance = null; } public override void OnEnter() { base.OnEnter(); InitElement(MageElement.Ice); stopwatch = 0f; entryDuration = baseEntryDuration / attackSpeedStat; fireDuration = baseDuration / attackSpeedStat; exitDuration = baseExitDuration / attackSpeedStat; Util.PlaySound(attackString, base.gameObject); base.characterBody.SetAimTimer(fireDuration + entryDuration + exitDuration + 2f); animator = GetModelAnimator(); if ((bool)animator) { childLocator = animator.GetComponent(); } muzzleString = "MuzzleRight"; if ((bool)childLocator) { muzzleTransform = childLocator.FindChild(muzzleString); } PlayAnimation("Gesture Left, Additive", EmptyStateHash); PlayAnimation("Gesture Right, Additive", EmptyStateHash); PlayAnimation("Gesture, Additive", EnterRollerStateHash, EnterRollerParamHash, entryDuration); if ((bool)areaIndicatorPrefab) { if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab)) { areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab); return; } _emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity); areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject; } } private void UpdateAreaIndicator() { if ((bool)areaIndicatorInstance) { float maxDistance = 1000f; if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask)) { areaIndicatorInstance.transform.position = hitInfo.point; areaIndicatorInstance.transform.rotation = Util.QuaternionSafeLookRotation(base.transform.position - areaIndicatorInstance.transform.position, hitInfo.normal); } } } public override void Update() { base.Update(); UpdateAreaIndicator(); } protected void DestroyAreaIndicator() { if (areaIndicatorInstance != null) { if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null) { _emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance); } else { EntityState.Destroy(areaIndicatorInstance); } areaIndicatorInstance = null; _emh_areaIndicatorInstance = null; } } public override void OnExit() { base.OnExit(); DestroyAreaIndicator(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= entryDuration && !hasFiredRoller) { PlayAnimation("Gesture, Additive", FireRollerStateHash, FireRollerParamHash, fireDuration); FireRollerProjectile(); DestroyAreaIndicator(); } if (stopwatch >= entryDuration + fireDuration && !hasBegunExit) { hasBegunExit = true; PlayAnimation("Gesture, Additive", ExitRollerStateHash, ExitRollerParamHash, exitDuration); } if (stopwatch >= entryDuration + fireDuration + exitDuration && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireRollerProjectile() { hasFiredRoller = true; if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (!base.isAuthority || !(projectilePrefab != null)) { return; } float maxDistance = 1000f; Ray aimRay = GetAimRay(); UnityEngine.Vector3 forward = aimRay.direction; UnityEngine.Vector3 vector = aimRay.origin; float magnitude = targetProjectileSpeed; if ((bool)muzzleTransform) { vector = muzzleTransform.position; if (Physics.Raycast(aimRay, out var hitInfo, maxDistance, LayerIndex.world.mask)) { float num = magnitude; UnityEngine.Vector3 vector2 = hitInfo.point - vector; UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z); float magnitude2 = vector3.magnitude; float y = Trajectory.CalculateInitialYSpeed(magnitude2 / num, vector2.y); UnityEngine.Vector3 vector4 = new UnityEngine.Vector3(vector3.x / magnitude2 * num, y, vector3.y / magnitude2 * num); magnitude = vector4.magnitude; forward = vector4 / magnitude; } } ProjectileManager.instance.FireProjectile(projectilePrefab, vector, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude); } private void InitElement(MageElement defaultElement) { MageCalibrationController component = GetComponent(); if ((bool)component) { MageElement activeCalibrationElement = component.GetActiveCalibrationElement(); if (activeCalibrationElement != 0) { defaultElement = activeCalibrationElement; } } switch (defaultElement) { case MageElement.Fire: damageCoefficient = fireDamageCoefficient; attackString = fireAttackSoundString; projectilePrefab = fireProjectilePrefab; muzzleflashEffectPrefab = fireMuzzleflashEffectPrefab; areaIndicatorPrefab = fireAreaIndicatorPrefab; break; case MageElement.Ice: damageCoefficient = iceDamageCoefficient; attackString = iceAttackSoundString; projectilePrefab = iceProjectilePrefab; muzzleflashEffectPrefab = iceMuzzleflashEffectPrefab; areaIndicatorPrefab = iceAreaIndicatorPrefab; break; case MageElement.Lightning: damageCoefficient = lightningDamageCoefficient; attackString = lightningAttackSoundString; projectilePrefab = lightningProjectilePrefab; muzzleflashEffectPrefab = lightningMuzzleflashEffectPrefab; areaIndicatorPrefab = lightningAreaIndicatorPrefab; break; } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Flamethrower : BaseState { [SerializeField] public GameObject flamethrowerEffectPrefab; public static GameObject impactEffectPrefab; public static GameObject tracerEffectPrefab; [SerializeField] public float maxDistance; public static float radius; public static float baseEntryDuration = 1f; public static float baseFlamethrowerDuration = 2f; public static float totalDamageCoefficient = 1.2f; public static float procCoefficientPerTick; public static float tickFrequency; public static float force = 20f; public static string startAttackSoundString; public static string endAttackSoundString; public static float ignitePercentChance; public static float recoilForce; private float tickDamageCoefficient; private float flamethrowerStopwatch; private float stopwatch; private float entryDuration; private float flamethrowerDuration; private bool hasBegunFlamethrower; private ChildLocator childLocator; private Transform leftFlamethrowerTransform; private Transform rightFlamethrowerTransform; private Transform leftMuzzleTransform; private Transform rightMuzzleTransform; private bool isCrit; private static int PrepFlamethrowerStateHash = Animator.StringToHash("PrepFlamethrower"); private static int ExitFlamethrowerStateHash = Animator.StringToHash("ExitFlamethrower"); private static int FlamethrowerParamHash = Animator.StringToHash("Flamethrower.playbackRate"); private const float flamethrowerEffectBaseDistance = 16f; private static int FlamethrowerStateHash = Animator.StringToHash("Flamethrower"); public override void OnEnter() { base.OnEnter(); stopwatch = 0f; entryDuration = baseEntryDuration / attackSpeedStat; flamethrowerDuration = baseFlamethrowerDuration; Transform modelTransform = GetModelTransform(); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(entryDuration + flamethrowerDuration + 1f); } if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); leftMuzzleTransform = childLocator.FindChild("MuzzleLeft"); rightMuzzleTransform = childLocator.FindChild("MuzzleRight"); } int num = Mathf.CeilToInt(flamethrowerDuration * tickFrequency); tickDamageCoefficient = totalDamageCoefficient / (float)num; if (base.isAuthority && (bool)base.characterBody) { isCrit = Util.CheckRoll(critStat, base.characterBody.master); } PlayAnimation("Gesture, Additive", PrepFlamethrowerStateHash, FlamethrowerParamHash, entryDuration); } public override void OnExit() { Util.PlaySound(endAttackSoundString, base.gameObject); PlayCrossfade("Gesture, Additive", ExitFlamethrowerStateHash, 0.1f); if ((bool)leftFlamethrowerTransform) { EntityState.Destroy(leftFlamethrowerTransform.gameObject); } if ((bool)rightFlamethrowerTransform) { EntityState.Destroy(rightFlamethrowerTransform.gameObject); } base.OnExit(); } private void FireGauntlet(string muzzleString) { Ray aimRay = GetAimRay(); if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = 0f; bulletAttack.damage = tickDamageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.muzzleName = muzzleString; bulletAttack.hitEffectPrefab = impactEffectPrefab; bulletAttack.isCrit = isCrit; bulletAttack.radius = radius; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.stopperMask = LayerIndex.world.mask; bulletAttack.procCoefficient = procCoefficientPerTick; bulletAttack.maxDistance = maxDistance; bulletAttack.smartCollision = true; bulletAttack.damageType = (Util.CheckRoll(ignitePercentChance, base.characterBody.master) ? DamageType.IgniteOnHit : DamageType.Generic); bulletAttack.allowTrajectoryAimAssist = false; bulletAttack.Fire(); if ((bool)base.characterMotor) { base.characterMotor.ApplyForce(aimRay.direction * (0f - recoilForce)); } } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= entryDuration && !hasBegunFlamethrower) { hasBegunFlamethrower = true; Util.PlaySound(startAttackSoundString, base.gameObject); PlayAnimation("Gesture, Additive", FlamethrowerStateHash, FlamethrowerParamHash, flamethrowerDuration); if ((bool)childLocator) { Transform transform = childLocator.FindChild("MuzzleLeft"); Transform transform2 = childLocator.FindChild("MuzzleRight"); if ((bool)transform) { leftFlamethrowerTransform = UnityEngine.Object.Instantiate(flamethrowerEffectPrefab, transform).transform; } if ((bool)transform2) { rightFlamethrowerTransform = UnityEngine.Object.Instantiate(flamethrowerEffectPrefab, transform2).transform; } if ((bool)leftFlamethrowerTransform) { leftFlamethrowerTransform.GetComponent().newDuration = flamethrowerDuration; } if ((bool)rightFlamethrowerTransform) { rightFlamethrowerTransform.GetComponent().newDuration = flamethrowerDuration; } } FireGauntlet("MuzzleCenter"); } if (hasBegunFlamethrower) { flamethrowerStopwatch += Time.deltaTime; float num = 1f / tickFrequency / attackSpeedStat; if (flamethrowerStopwatch > num) { flamethrowerStopwatch -= num; FireGauntlet("MuzzleCenter"); } UpdateFlamethrowerEffect(); } if (stopwatch >= flamethrowerDuration + entryDuration && base.isAuthority) { outer.SetNextStateToMain(); } } private void UpdateFlamethrowerEffect() { Ray aimRay = GetAimRay(); UnityEngine.Vector3 direction = aimRay.direction; UnityEngine.Vector3 direction2 = aimRay.direction; if ((bool)leftFlamethrowerTransform) { leftFlamethrowerTransform.forward = direction; } if ((bool)rightFlamethrowerTransform) { rightFlamethrowerTransform.forward = direction2; } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class IceNova : BaseState { public static GameObject impactEffectPrefab; public static GameObject novaEffectPrefab; public static float baseStartDuration; public static float baseEndDuration = 2f; public static float damageCoefficient = 1.2f; public static float procCoefficient; public static float force = 20f; public static float novaRadius; public static string attackString; private float stopwatch; private float startDuration; private float endDuration; private bool hasCastNova; public override void OnEnter() { base.OnEnter(); stopwatch = 0f; endDuration = baseEndDuration / attackSpeedStat; startDuration = baseStartDuration / attackSpeedStat; } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= startDuration && !hasCastNova) { hasCastNova = true; EffectManager.SpawnEffect(novaEffectPrefab, new EffectData { origin = base.transform.position, scale = novaRadius }, transmit: true); BlastAttack obj = new BlastAttack { radius = novaRadius, procCoefficient = procCoefficient, position = base.transform.position, attacker = base.gameObject, crit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master), baseDamage = base.characterBody.damage * damageCoefficient, falloffModel = BlastAttack.FalloffModel.None, damageType = DamageType.Freeze2s, baseForce = force }; obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker); obj.Fire(); } if (stopwatch >= startDuration + endDuration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class PrepWall : BaseState { public static float baseDuration; public static GameObject areaIndicatorPrefab; public static GameObject projectilePrefab; public static float damageCoefficient; public static GameObject muzzleflashEffect; public static GameObject goodCrosshairPrefab; public static GameObject badCrosshairPrefab; public static string prepWallSoundString; public static float maxDistance; public static string fireSoundString; public static float maxSlopeAngle; private float duration; private float stopwatch; private bool goodPlacement; private GameObject areaIndicatorInstance; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private EffectManagerHelper _emh_areaIndicatorInstance; private static int PrepWallStateHash = Animator.StringToHash("PrepWall"); private static int PrepWallParamHash = Animator.StringToHash("PrepWall.playbackRate"); private static int FireWallStateHash = Animator.StringToHash("FireWall"); public override void Reset() { base.Reset(); duration = 0f; stopwatch = 0f; goodPlacement = false; areaIndicatorInstance = null; _emh_areaIndicatorInstance = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; base.characterBody.SetAimTimer(duration + 2f); PlayAnimation("Gesture, Additive", PrepWallStateHash, PrepWallParamHash, duration); Util.PlaySound(prepWallSoundString, base.gameObject); if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab)) { areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab); } else { _emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity); areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject; } UpdateAreaIndicator(); } private void UpdateAreaIndicator() { bool flag = goodPlacement; goodPlacement = false; areaIndicatorInstance.SetActive(value: true); if ((bool)areaIndicatorInstance) { float num = maxDistance; float extraRaycastDistance = 0f; Ray aimRay = GetAimRay(); if (Physics.Raycast(CameraRigController.ModifyAimRayIfApplicable(aimRay, base.gameObject, out extraRaycastDistance), out var hitInfo, num + extraRaycastDistance, LayerIndex.world.mask)) { areaIndicatorInstance.transform.position = hitInfo.point; areaIndicatorInstance.transform.up = hitInfo.normal; areaIndicatorInstance.transform.forward = -aimRay.direction; goodPlacement = UnityEngine.Vector3.Angle(UnityEngine.Vector3.up, hitInfo.normal) < maxSlopeAngle; } if (flag != goodPlacement || crosshairOverrideRequest == null) { crosshairOverrideRequest?.Dispose(); GameObject crosshairPrefab = (goodPlacement ? goodCrosshairPrefab : badCrosshairPrefab); crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill); } } areaIndicatorInstance.SetActive(goodPlacement); } public override void Update() { base.Update(); UpdateAreaIndicator(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && !base.inputBank.skill3.down && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if (!outer.destroying) { if (goodPlacement) { PlayAnimation("Gesture, Additive", FireWallStateHash); Util.PlaySound(fireSoundString, base.gameObject); if ((bool)areaIndicatorInstance && base.isAuthority) { EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleLeft", transmit: true); EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleRight", transmit: true); UnityEngine.Vector3 forward = areaIndicatorInstance.transform.forward; forward.y = 0f; forward.Normalize(); UnityEngine.Vector3 vector = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, forward); bool crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(projectilePrefab, areaIndicatorInstance.transform.position + UnityEngine.Vector3.up, Util.QuaternionSafeLookRotation(vector), base.gameObject, damageStat * damageCoefficient, 0f, crit); ProjectileManager.instance.FireProjectile(projectilePrefab, areaIndicatorInstance.transform.position + UnityEngine.Vector3.up, Util.QuaternionSafeLookRotation(-vector), base.gameObject, damageStat * damageCoefficient, 0f, crit); } } else { base.skillLocator.utility.AddOneStock(); PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.2f); } } if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null) { _emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance); } else { EntityState.Destroy(areaIndicatorInstance.gameObject); } areaIndicatorInstance = null; _emh_areaIndicatorInstance = null; crosshairOverrideRequest?.Dispose(); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } } namespace EntityStates.LunarWisp { public class ChargeLunarGuns : BaseState { public static string muzzleNameRoot; public static string muzzleNameOne; public static string muzzleNameTwo; public static float baseDuration; public static string windUpSound; public static GameObject chargeEffectPrefab; private GameObject chargeInstance; private GameObject chargeInstanceTwo; private float duration; public static float spinUpDuration; public static float chargeEffectDelay; private bool chargeEffectSpawned; private bool upToSpeed; private uint loopedSoundID; protected Transform muzzleTransformRoot; protected Transform muzzleTransformOne; protected Transform muzzleTransformTwo; public override void OnEnter() { base.OnEnter(); duration = (baseDuration + spinUpDuration) / attackSpeedStat; muzzleTransformRoot = FindModelChild(muzzleNameRoot); muzzleTransformOne = FindModelChild(muzzleNameOne); muzzleTransformTwo = FindModelChild(muzzleNameTwo); loopedSoundID = Util.PlaySound(windUpSound, base.gameObject); PlayCrossfade("Gesture", "MinigunSpinUp", 0.2f); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void FixedUpdate() { base.FixedUpdate(); StartAimMode(0.5f); if (base.fixedAge >= chargeEffectDelay && !chargeEffectSpawned) { chargeEffectSpawned = true; if ((bool)muzzleTransformOne && (bool)muzzleTransformTwo && (bool)chargeEffectPrefab) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransformOne.position, muzzleTransformOne.rotation); chargeInstance.transform.parent = muzzleTransformOne; chargeInstanceTwo = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransformTwo.position, muzzleTransformTwo.rotation); chargeInstanceTwo.transform.parent = muzzleTransformTwo; ScaleParticleSystemDuration component = chargeInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } if (base.fixedAge >= spinUpDuration && !upToSpeed) { upToSpeed = true; } if (base.fixedAge >= duration && base.isAuthority) { FireLunarGuns fireLunarGuns = new FireLunarGuns(); fireLunarGuns.muzzleTransformOne = muzzleTransformOne; fireLunarGuns.muzzleTransformTwo = muzzleTransformTwo; fireLunarGuns.muzzleNameOne = muzzleNameOne; fireLunarGuns.muzzleNameTwo = muzzleNameTwo; outer.SetNextState(fireLunarGuns); } } public override void OnExit() { base.OnExit(); AkSoundEngine.StopPlayingID(loopedSoundID); if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } if ((bool)chargeInstanceTwo) { EntityState.Destroy(chargeInstanceTwo); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class DeathState : GenericCharacterDeath { public static GameObject deathEffectPrefab; public static string deathEffectMuzzleName; public static float velocityMagnitude; public static float explosionForce; private LunarWispFXController FXController; protected override bool shouldAutoDestroy => false; public override void OnEnter() { base.OnEnter(); LunarWispFXController component = base.characterBody.GetComponent(); if ((bool)component) { component.TurnOffFX(); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { RagdollController component2 = modelTransform.GetComponent(); Rigidbody component3 = GetComponent(); if ((bool)component2 && (bool)component3) { component2.BeginRagdoll(component3.velocity * velocityMagnitude); } ExplodeRigidbodiesOnStart component4 = modelTransform.GetComponent(); if ((bool)component4) { component4.force = explosionForce; component4.enabled = true; } } if ((bool)base.modelLocator) { base.modelLocator.autoUpdateModelTransform = false; } FindModelChild("StandableSurface").gameObject.SetActive(value: false); if (NetworkServer.active) { EffectData effectData = new EffectData { origin = FindModelChild(deathEffectMuzzleName).position }; EffectManager.SpawnEffect(deathEffectPrefab, effectData, transmit: true); DestroyBodyAsapServer(); } } } public class FireLunarGuns : BaseState { public static GameObject muzzleVfxPrefab; public static float baseDuration; private float duration; public static float baseFireInterval; public static int baseBulletCount; public static float baseDamagePerSecondCoefficient; public static float baseForcePerSecond; public static float baseProcCoefficientPerSecond; public static float bulletMinSpread; public static float bulletMaxSpread; public static GameObject bulletTracerEffectPrefab; public static GameObject bulletHitEffectPrefab; public static bool bulletHitEffectNormal; public static float bulletMaxDistance; public static string fireSound; public static string windLoopSound; public static string windDownSound; public static string shootLoopSound; private uint windLoopSoundID; private uint shootLoopSoundID; private Transform muzzleTransform; public Transform muzzleTransformOne; public Transform muzzleTransformTwo; [SerializeField] public string muzzleNameOne; [SerializeField] public string muzzleNameTwo; private GameObject muzzleVFXInstanceOne; private GameObject muzzleVFXInstanceTwo; private float fireTimer; private float baseFireRate; private float baseBulletsPerSecond; private Run.FixedTimeStamp critEndTime; private Run.FixedTimeStamp lastCritCheck; protected ref InputBankTest.ButtonState skillButtonState => ref base.inputBank.skill1; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; muzzleTransformOne = FindModelChild(muzzleNameOne); muzzleTransformTwo = FindModelChild(muzzleNameTwo); if ((bool)muzzleTransformOne && (bool)muzzleTransformTwo && (bool)muzzleVfxPrefab) { muzzleVFXInstanceOne = UnityEngine.Object.Instantiate(muzzleVfxPrefab, muzzleTransformOne.position, muzzleTransformOne.rotation); muzzleVFXInstanceOne.transform.parent = muzzleTransformOne; muzzleVFXInstanceTwo = UnityEngine.Object.Instantiate(muzzleVfxPrefab, muzzleTransformTwo.position, muzzleTransformTwo.rotation); muzzleVFXInstanceTwo.transform.parent = muzzleTransformTwo; } baseFireRate = 1f / baseFireInterval; baseBulletsPerSecond = (float)baseBulletCount * baseFireRate; critEndTime = Run.FixedTimeStamp.negativeInfinity; lastCritCheck = Run.FixedTimeStamp.negativeInfinity; windLoopSoundID = Util.PlaySound(windLoopSound, base.gameObject); shootLoopSoundID = Util.PlaySound(shootLoopSound, base.gameObject); } private void UpdateCrits() { if (lastCritCheck.timeSince >= 1f) { lastCritCheck = Run.FixedTimeStamp.now; if (RollCrit()) { critEndTime = Run.FixedTimeStamp.now + 2f; } } } public override void OnExit() { Util.PlaySound(windDownSound, base.gameObject); if ((bool)muzzleVFXInstanceOne) { EntityState.Destroy(muzzleVFXInstanceOne.gameObject); muzzleVFXInstanceOne = null; } if ((bool)muzzleVFXInstanceTwo) { EntityState.Destroy(muzzleVFXInstanceTwo.gameObject); muzzleVFXInstanceTwo = null; } AkSoundEngine.StopPlayingID(windLoopSoundID); AkSoundEngine.StopPlayingID(shootLoopSoundID); PlayCrossfade("Gesture", "MinigunSpinDown", 0.2f); base.OnExit(); } private void OnFireShared() { Util.PlaySound(fireSound, base.gameObject); if (base.isAuthority) { OnFireAuthority(); } } private void OnFireAuthority() { UpdateCrits(); bool isCrit = !critEndTime.hasPassed; float damage = baseDamagePerSecondCoefficient / baseBulletsPerSecond * damageStat; float force = baseForcePerSecond / baseBulletsPerSecond; float procCoefficient = baseProcCoefficientPerSecond / baseBulletsPerSecond; StartAimMode(0.5f); Ray aimRay = GetAimRay(); BulletAttack bulletAttack = new BulletAttack(); bulletAttack.bulletCount = (uint)baseBulletCount / 2u; bulletAttack.aimVector = aimRay.direction; bulletAttack.origin = aimRay.origin; bulletAttack.damage = damage; bulletAttack.damageColorIndex = DamageColorIndex.Default; bulletAttack.damageType = DamageType.Generic; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.maxDistance = bulletMaxDistance; bulletAttack.force = force; bulletAttack.hitMask = LayerIndex.CommonMasks.bullet; bulletAttack.minSpread = bulletMinSpread; bulletAttack.maxSpread = bulletMaxSpread; bulletAttack.isCrit = isCrit; bulletAttack.owner = base.gameObject; bulletAttack.muzzleName = muzzleNameOne; bulletAttack.smartCollision = false; bulletAttack.procChainMask = default(ProcChainMask); bulletAttack.procCoefficient = procCoefficient; bulletAttack.radius = 0f; bulletAttack.sniper = false; bulletAttack.stopperMask = LayerIndex.CommonMasks.bullet; bulletAttack.weapon = null; bulletAttack.tracerEffectPrefab = bulletTracerEffectPrefab; bulletAttack.spreadPitchScale = 1f; bulletAttack.spreadYawScale = 1f; bulletAttack.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal; bulletAttack.hitEffectPrefab = bulletHitEffectPrefab; bulletAttack.HitEffectNormal = bulletHitEffectNormal; bulletAttack.Fire(); BulletAttack bulletAttack2 = new BulletAttack(); bulletAttack2.bulletCount = (uint)baseBulletCount / 2u; bulletAttack2.aimVector = aimRay.direction; bulletAttack2.origin = aimRay.origin; bulletAttack2.damage = damage; bulletAttack2.damageColorIndex = DamageColorIndex.Default; bulletAttack2.damageType = DamageType.Generic; bulletAttack2.falloffModel = BulletAttack.FalloffModel.None; bulletAttack2.maxDistance = bulletMaxDistance; bulletAttack2.force = force; bulletAttack2.hitMask = LayerIndex.CommonMasks.bullet; bulletAttack2.minSpread = bulletMinSpread; bulletAttack2.maxSpread = bulletMaxSpread; bulletAttack2.isCrit = isCrit; bulletAttack2.owner = base.gameObject; bulletAttack2.muzzleName = muzzleNameTwo; bulletAttack2.smartCollision = false; bulletAttack2.procChainMask = default(ProcChainMask); bulletAttack2.procCoefficient = procCoefficient; bulletAttack2.radius = 0f; bulletAttack2.sniper = false; bulletAttack2.stopperMask = LayerIndex.CommonMasks.bullet; bulletAttack2.weapon = null; bulletAttack2.tracerEffectPrefab = bulletTracerEffectPrefab; bulletAttack2.spreadPitchScale = 1f; bulletAttack2.spreadYawScale = 1f; bulletAttack2.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal; bulletAttack2.hitEffectPrefab = bulletHitEffectPrefab; bulletAttack2.HitEffectNormal = bulletHitEffectNormal; bulletAttack2.Fire(); } public override void FixedUpdate() { base.FixedUpdate(); fireTimer -= GetDeltaTime(); if (fireTimer <= 0f) { float num = baseFireInterval / attackSpeedStat; fireTimer += num; OnFireShared(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SeekingBomb : BaseState { public static float baseDuration = 3f; public static GameObject chargingEffectPrefab; public static GameObject projectilePrefab; public static string spinUpSoundString; public static string fireBombSoundString; public static string spinDownSoundString; public static float bombDamageCoefficient; public static float bombForce; public static string muzzleName; public float novaRadius; private float duration; public static float spinUpDuration; private bool upToSpeed; private GameObject chargeEffectInstance; private uint chargeLoopSoundID; public override void OnEnter() { base.OnEnter(); duration = (baseDuration + spinUpDuration) / attackSpeedStat; chargeLoopSoundID = Util.PlaySound(spinUpSoundString, base.gameObject); PlayCrossfade("Gesture", "BombStart", 0.2f); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void OnExit() { base.OnExit(); AkSoundEngine.StopPlayingID(chargeLoopSoundID); if ((bool)chargeEffectInstance) { EntityState.Destroy(chargeEffectInstance); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= spinUpDuration && !upToSpeed) { upToSpeed = true; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(muzzleName); if ((bool)transform && (bool)chargingEffectPrefab) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargingEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; chargeEffectInstance.GetComponent().newDuration = duration; } } } } if (base.fixedAge >= duration && base.isAuthority) { FireBomb(); outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } private void FireBomb() { Util.PlaySound(fireBombSoundString, base.gameObject); Ray aimRay = GetAimRay(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { aimRay.origin = component.FindChild(muzzleName).transform.position; } } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * bombDamageCoefficient, bombForce, Util.CheckRoll(critStat, base.characterBody.master)); } Util.PlaySound(spinDownSoundString, base.gameObject); PlayCrossfade("Gesture", "BombStop", 0.2f); } } public class SpawnState : BaseState { public static float duration; public static string spawnSoundString; public static float spawnEffectsDelay; private bool spawnEffectsTriggered; public static GameObject spawnEffectPrefab; public static string spawnEffectMuzzleName; public static float printDuration; private float mPrintDuration; private LunarWispFXController FXController; private static int SpawnStateHash = Animator.StringToHash("Spawn"); public override void OnEnter() { base.OnEnter(); FXController = base.characterBody.GetComponent(); FXController.TurnOffFX(); mPrintDuration = printDuration; Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", SpawnStateHash); PrintController component = GetModelTransform().gameObject.GetComponent(); component.enabled = false; component.printTime = mPrintDuration; component.startingPrintHeight = 25f; component.maxPrintHeight = 3.15f; component.startingPrintBias = 4f; component.maxPrintBias = 1.4f; component.disableWhenFinished = true; component.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); component.enabled = true; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= spawnEffectsDelay && !spawnEffectsTriggered) { spawnEffectsTriggered = true; EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectMuzzleName, transmit: false); if ((bool)FXController) { FXController.TurnOnFX(); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.LunarTeleporter { public class LunarTeleporterBaseState : BaseState { protected GenericInteraction genericInteraction; protected Interactability preferredInteractability = Interactability.Available; protected TeleporterInteraction teleporterInteraction; public override void OnEnter() { base.OnEnter(); genericInteraction = GetComponent(); teleporterInteraction = base.transform.root.GetComponent(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)TeleporterInteraction.instance) { if (TeleporterInteraction.instance.isIdle) { genericInteraction.Networkinteractability = preferredInteractability; } else { genericInteraction.Networkinteractability = Interactability.Disabled; } } } } public class Idle : LunarTeleporterBaseState { private static int IdleStateHash = Animator.StringToHash("Idle"); public override void OnEnter() { base.OnEnter(); preferredInteractability = Interactability.Available; PlayAnimation("Base", IdleStateHash); outer.mainStateType = new SerializableEntityStateType(typeof(IdleToActive)); if (NetworkServer.active) { teleporterInteraction.sceneExitController.useRunNextStageScene = true; } } } public class Active : LunarTeleporterBaseState { private static int ActiveStateHash = Animator.StringToHash("Active"); public override void OnEnter() { base.OnEnter(); preferredInteractability = Interactability.Available; PlayAnimation("Base", ActiveStateHash); outer.mainStateType = new SerializableEntityStateType(typeof(ActiveToIdle)); if (NetworkServer.active) { teleporterInteraction.sceneExitController.useRunNextStageScene = false; } } } public class IdleToActive : LunarTeleporterBaseState { public static float duration; private static int IdleToActiveStateHash = Animator.StringToHash("IdleToActive"); private static int playbackRateParamHash = Animator.StringToHash("playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", IdleToActiveStateHash, playbackRateParamHash, duration); preferredInteractability = Interactability.Disabled; Util.PlaySound("Play_boss_spawn_rumble", base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new Active()); } } public override void OnExit() { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "LUNAR_TELEPORTER_ACTIVE" }); base.OnExit(); } } public class ActiveToIdle : LunarTeleporterBaseState { public static float duration; private static int ActiveToIdleStateHash = Animator.StringToHash("ActiveToIdle"); private static int playbackRateParamHash = Animator.StringToHash("playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", ActiveToIdleStateHash, playbackRateParamHash, duration); preferredInteractability = Interactability.Disabled; Util.PlaySound("Play_boss_spawn_rumble", base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new Idle()); } } public override void OnExit() { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "LUNAR_TELEPORTER_IDLE" }); base.OnExit(); } } } namespace EntityStates.LunarGolem { public class ChargeTwinShot : BaseState { public static float baseDuration = 3f; public static float laserMaxWidth = 0.2f; public static GameObject effectPrefab; public static string chargeSoundString; private float duration; private uint chargePlayID; private List chargeEffects = new List(); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); chargePlayID = Util.PlayAttackSpeedSound(chargeSoundString, base.gameObject, attackSpeedStat); PlayCrossfade("Gesture, Additive", "ChargeTwinShot", "TwinShot.playbackRate", duration, 0.1f); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { List list = new List(); list.Add(component.FindChild("MuzzleLT")); list.Add(component.FindChild("MuzzleLB")); list.Add(component.FindChild("MuzzleRT")); list.Add(component.FindChild("MuzzleRB")); if ((bool)effectPrefab) { for (int i = 0; i < list.Count; i++) { if ((bool)list[i]) { GameObject gameObject = UnityEngine.Object.Instantiate(effectPrefab, list[i].position, list[i].rotation); gameObject.transform.parent = list[i]; ScaleParticleSystemDuration component2 = gameObject.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } chargeEffects.Add(gameObject); } } } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void OnExit() { AkSoundEngine.StopPlayingID(chargePlayID); base.OnExit(); for (int i = 0; i < chargeEffects.Count; i++) { if ((bool)chargeEffects[i]) { EntityState.Destroy(chargeEffects[i]); } } } public override void Update() { base.Update(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireTwinShots nextState = new FireTwinShots(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class DeathState : GenericCharacterDeath { public static GameObject deathExplosionEffect; public override void OnEnter() { base.OnEnter(); if ((bool)deathExplosionEffect) { EffectManager.SimpleMuzzleFlash(deathExplosionEffect, base.gameObject, "Center", transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); } } public class FireTwinShots : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static GameObject dustEffectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float blastRadius; public static float force; public static float baseDuration = 2f; public static string attackSoundString; public static float aimTime = 2f; public static string leftMuzzleTop; public static string rightMuzzleTop; public static string leftMuzzleBot; public static string rightMuzzleBot; public static int refireCount = 6; public static float baseAimDelay = 0.1f; public static float minLeadTime = 2f; public static float maxLeadTime = 2f; public static float fireSoundPlaybackRate; public static bool useSeriesFire = true; private int refireIndex; private Ray initialAimRay; private bool fired; private float aimDelay; private float duration; private static int FireTwinShotStateHash = Animator.StringToHash("FireTwinShot"); private static int BufferEmptyShotStateHash = Animator.StringToHash("BufferEmpty"); private static int FireTwinShotParamHash = Animator.StringToHash("FireTwinShot.playbackRate"); private static int FireRightShotStateHash = Animator.StringToHash("FireRightShot"); private static int FireLeftShotStateHash = Animator.StringToHash("FireLeftShot"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; aimDelay = baseAimDelay / attackSpeedStat; if ((bool)base.characterBody) { base.characterBody.SetAimTimer(aimTime); } if (!useSeriesFire) { PlayAnimation("Gesture, Additive", FireTwinShotStateHash, FireTwinShotParamHash, duration); } else { PlayAnimation("Gesture, Additive", BufferEmptyShotStateHash); } Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, fireSoundPlaybackRate); initialAimRay = GetAimRay(); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!fired && aimDelay <= base.fixedAge) { fired = true; if (base.isAuthority) { Fire(); } } if (base.fixedAge >= duration && base.isAuthority) { if (refireIndex < refireCount) { outer.SetNextState(new FireTwinShots { refireIndex = refireIndex + 1 }); } else { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.WritePackedUInt32((uint)refireIndex); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); refireIndex = (int)reader.ReadPackedUInt32(); } private void Fire() { Ray aimRay = GetAimRay(); UnityEngine.Quaternion a = UnityEngine.Quaternion.LookRotation(initialAimRay.direction); UnityEngine.Quaternion b = UnityEngine.Quaternion.LookRotation(aimRay.direction); float num = Util.Remap(Util.Remap(refireIndex, 0f, refireCount - 1, 0f, 1f), 0f, 1f, minLeadTime, maxLeadTime) / aimDelay; UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.SlerpUnclamped(a, b, 1f + num); Ray ray = new Ray(aimRay.origin, quaternion * UnityEngine.Vector3.forward); if (refireIndex == 0 && (bool)dustEffectPrefab) { EffectManager.SimpleMuzzleFlash(dustEffectPrefab, base.gameObject, "Root", transmit: true); } int num2 = refireIndex; if (!useSeriesFire) { num2 = refireIndex + 3; } while (refireIndex <= num2) { string muzzleName = ""; bool flipProjectile = false; switch (refireIndex % 4) { case 0: muzzleName = rightMuzzleTop; PlayAnimation("Gesture, Right Additive", FireRightShotStateHash); flipProjectile = true; break; case 1: muzzleName = leftMuzzleTop; PlayAnimation("Gesture, Left Additive", FireLeftShotStateHash); break; case 2: muzzleName = rightMuzzleBot; PlayAnimation("Gesture, Right Additive", FireRightShotStateHash); flipProjectile = true; break; case 3: muzzleName = leftMuzzleBot; PlayAnimation("Gesture, Left Additive", FireLeftShotStateHash); break; } FireSingle(muzzleName, ray.direction, flipProjectile); refireIndex++; } refireIndex--; } private void FireSingle(string muzzleName, UnityEngine.Vector3 aimDirection, bool flipProjectile) { ChildLocator modelChildLocator = GetModelChildLocator(); if (!modelChildLocator) { return; } Transform transform = modelChildLocator.FindChild(muzzleName); if ((bool)transform) { if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: true); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, transform.position, Util.QuaternionSafeLookRotation(aimDirection, (!flipProjectile) ? UnityEngine.Vector3.up : UnityEngine.Vector3.down), base.gameObject, damageStat * damageCoefficient, force, RollCrit()); } } } } public class Shell : BaseState { public static float baseDuration; public static float buffDuration; public static float preShieldAnimDuration; public static GameObject preShieldEffect; public static string preShieldSoundString; public static string shieldActivateSoundString; private bool readyToActivate; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(preShieldSoundString, base.gameObject); PlayCrossfade("Gesture, Additive", "PreShield", 0.2f); EffectManager.SimpleMuzzleFlash(preShieldEffect, base.gameObject, "Center", transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= preShieldAnimDuration && !readyToActivate) { readyToActivate = true; Util.PlaySound(shieldActivateSoundString, base.gameObject); base.characterBody.AddTimedBuff(RoR2Content.Buffs.LunarShell, buffDuration); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { base.OnExit(); } } public class SpawnState : BaseState { public static float duration = 1.333f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.LunarExploderMonster { public class DeathState : GenericCharacterDeath { public static GameObject deathPreExplosionVFX; public static GameObject deathExplosionEffect; public static GameObject projectilePrefab; public static float projectileVerticalSpawnOffset; public static float projectileDamageCoefficient; public static int projectileCount; public static float duration; public static float deathExplosionRadius; public static string muzzleName; private GameObject deathPreExplosionInstance; private Transform muzzleTransform; private bool hasExploded; private UnityEngine.Vector3? explosionPosition; protected override bool shouldAutoDestroy => false; protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayCrossfade("Body", "Death", "Death.playbackRate", duration, 0.1f); } public override void OnEnter() { base.OnEnter(); muzzleTransform = FindModelChild(muzzleName); if (!muzzleTransform) { return; } explosionPosition = muzzleTransform.position; if ((bool)deathPreExplosionVFX) { deathPreExplosionInstance = UnityEngine.Object.Instantiate(deathPreExplosionVFX, muzzleTransform.position, muzzleTransform.rotation); deathPreExplosionInstance.transform.parent = muzzleTransform; deathPreExplosionInstance.transform.localScale = UnityEngine.Vector3.one * deathExplosionRadius; ScaleParticleSystemDuration component = deathPreExplosionInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)muzzleTransform) { explosionPosition = muzzleTransform.position; } if (base.fixedAge >= duration && !hasExploded) { if (base.isAuthority) { FireExplosion(); } base.modelLocator?.modelTransform?.gameObject.SetActive(value: false); ProjectileDotZone projectileDotZone = projectilePrefab?.GetComponent(); if ((bool)projectileDotZone) { base.modelLocator?.StartCoroutine(DoDestroyAfrerProjectileDestroyed(projectileDotZone.lifetime + 0.5f)); } hasExploded = true; } } private IEnumerator DoDestroyAfrerProjectileDestroyed(float delay) { yield return new WaitForSeconds(delay); DestroyModel(); if (NetworkServer.active) { DestroyBodyAsapServer(); } } public override void OnExit() { DestroyModel(); base.OnExit(); } private void FireExplosion() { if (!hasExploded && (bool)base.cachedModelTransform && base.isAuthority) { for (int i = 0; i < projectileCount; i++) { float num = 360f / (float)projectileCount; UnityEngine.Vector3 forward = Util.QuaternionSafeLookRotation(base.cachedModelTransform.forward, base.cachedModelTransform.up) * Util.ApplySpread(UnityEngine.Vector3.forward, 0f, 0f, 1f, 1f, num * (float)i); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = base.characterBody.corePosition + UnityEngine.Vector3.up * projectileVerticalSpawnOffset; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(forward); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * projectileDamageCoefficient; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } if ((bool)deathExplosionEffect) { EffectManager.SpawnEffect(deathExplosionEffect, new EffectData { origin = base.characterBody.corePosition, scale = deathExplosionRadius }, transmit: true); } } } } public class SpawnState : GenericCharacterSpawnState { public static GameObject spawnEffectPrefab; public static string spawnEffectChildString; public override void OnEnter() { base.OnEnter(); if ((bool)spawnEffectPrefab) { EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectChildString, transmit: false); } } } } namespace EntityStates.LunarExploderMonster.Weapon { public class FireExploderShards : GenericProjectileBaseState { private static int FireExploderShardsStateHash = Animator.StringToHash("FireExploderShards"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Gesture, Additive", FireExploderShardsStateHash); base.characterBody.SetAimTimer(0f); } } } namespace EntityStates.LockedMage { public class UnlockingMage : BaseState { public static GameObject unlockingMageChargeEffectPrefab; public static GameObject unlockingMageExplosionEffectPrefab; public static float unlockingDuration; public static string unlockingChargeSFXString; public static float unlockingChargeSFXStringPitch; public static string unlockingExplosionSFXString; public static float unlockingExplosionSFXStringPitch; private bool unlocked; public static event Action onOpened; public override void OnEnter() { base.OnEnter(); EffectManager.SimpleEffect(unlockingMageChargeEffectPrefab, base.transform.position, Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up), transmit: false); Util.PlayAttackSpeedSound(unlockingChargeSFXString, base.gameObject, unlockingChargeSFXStringPitch); GetModelTransform().GetComponent().FindChild("Suspension").gameObject.SetActive(value: false); } public override void FixedUpdate() { base.FixedUpdate(); if (!(base.fixedAge >= unlockingDuration) || unlocked) { return; } base.gameObject.SetActive(value: false); EffectManager.SimpleEffect(unlockingMageExplosionEffectPrefab, base.transform.position, Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up), transmit: false); Util.PlayAttackSpeedSound(unlockingExplosionSFXString, base.gameObject, unlockingExplosionSFXStringPitch); unlocked = true; if (NetworkServer.active) { PurchaseInteraction component = GetComponent(); if ((bool)component && (bool)component.lastActivator) { UnlockingMage.onOpened?.Invoke(component.lastActivator); } } } } } namespace EntityStates.Loader { public class BeginOvercharge : BaseState { public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { GetComponent().ConsumeChargeAuthority(); } outer.SetNextStateToMain(); } } public class BigPunch : LoaderMeleeAttack { public static int maxShockCount; public static float maxShockFOV; public static float maxShockDistance; public static float shockDamageCoefficient; public static float shockProcCoefficient; public static float knockbackForce; public static float shorthopVelocityOnEnter; private bool hasHit; private bool hasKnockbackedSelf; private static int BigPunchStateHash = Animator.StringToHash("BigPunch"); private static int BigPunchParamHash = Animator.StringToHash("BigPunch.playbackRate"); private UnityEngine.Vector3 punchVector => base.characterDirection.forward.normalized; public override void OnEnter() { base.OnEnter(); base.characterMotor.velocity.y = shorthopVelocityOnEnter; } protected override void PlayAnimation() { base.PlayAnimation(); PlayAnimation("FullBody, Override", BigPunchStateHash, BigPunchParamHash, duration); } protected override void AuthorityFixedUpdate() { base.AuthorityFixedUpdate(); if (hasHit && !hasKnockbackedSelf && !base.authorityInHitPause) { hasKnockbackedSelf = true; base.healthComponent.TakeDamageForce(punchVector * (0f - knockbackForce), alwaysApply: true); } } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); overlapAttack.maximumOverlapTargets = 1; } protected override void OnMeleeHitAuthority() { if (!hasHit) { base.OnMeleeHitAuthority(); hasHit = true; if ((bool)FindModelChild(swingEffectMuzzleString)) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.position = GetAimRay().origin; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(punchVector); fireProjectileInfo.crit = RollCrit(); fireProjectileInfo.damage = 1f * damageStat; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.projectilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/LoaderZapCone"); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } } private void FireSecondaryRaysServer() { Ray aimRay = GetAimRay(); TeamIndex team = GetTeam(); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(team); bullseyeSearch.maxAngleFilter = maxShockFOV * 0.5f; bullseyeSearch.maxDistanceFilter = maxShockDistance; bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = punchVector; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.filterByLoS = false; bullseyeSearch.RefreshCandidates(); List list = bullseyeSearch.GetResults().Where(Util.IsValid).ToList(); Transform transform = FindModelChild(swingEffectMuzzleString); if (!transform) { return; } for (int i = 0; i < Mathf.Min(list.Count, maxShockCount); i++) { HurtBox hurtBox = list[i]; if ((bool)hurtBox) { LightningOrb lightningOrb = new LightningOrb(); lightningOrb.bouncedObjects = new List(); lightningOrb.attacker = base.gameObject; lightningOrb.teamIndex = team; lightningOrb.damageValue = damageStat * shockDamageCoefficient; lightningOrb.isCrit = RollCrit(); lightningOrb.origin = transform.position; lightningOrb.bouncesRemaining = 0; lightningOrb.lightningType = LightningOrb.LightningType.Loader; lightningOrb.procCoefficient = shockProcCoefficient; lightningOrb.target = hurtBox; OrbManager.instance.AddOrb(lightningOrb); } } } } public class BaseChargeFist : BaseSkillState { private class ArcVisualizer : IDisposable { private readonly UnityEngine.Vector3[] points; private readonly float duration; private readonly GameObject arcVisualizerInstance; private readonly LineRenderer lineRenderer; public ArcVisualizer(GameObject arcVisualizerPrefab, float duration, int vertexCount) { arcVisualizerInstance = UnityEngine.Object.Instantiate(arcVisualizerPrefab); lineRenderer = arcVisualizerInstance.GetComponent(); lineRenderer.positionCount = vertexCount; points = new UnityEngine.Vector3[vertexCount]; this.duration = duration; } public void Dispose() { EntityState.Destroy(arcVisualizerInstance); } public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float characterMaxSpeed, float characterAcceleration) { arcVisualizerInstance.transform.position = origin; if (!lineRenderer.useWorldSpace) { UnityEngine.Vector3 eulerAngles = UnityEngine.Quaternion.LookRotation(initialVelocity).eulerAngles; eulerAngles.x = 0f; eulerAngles.z = 0f; UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(eulerAngles); arcVisualizerInstance.transform.rotation = rotation; origin = UnityEngine.Vector3.zero; initialVelocity = UnityEngine.Quaternion.Inverse(rotation) * initialVelocity; } else { arcVisualizerInstance.transform.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.Cross(initialVelocity, UnityEngine.Vector3.up)); } float y = Physics.gravity.y; float num = duration / (float)points.Length; UnityEngine.Vector3 vector = origin; UnityEngine.Vector3 vector2 = initialVelocity; float num2 = num; float num3 = y * num2; float maxDistanceDelta = characterAcceleration * num2; for (int i = 0; i < points.Length; i++) { points[i] = vector; UnityEngine.Vector2 current = Util.Vector3XZToVector2XY(vector2); current = UnityEngine.Vector2.MoveTowards(current, UnityEngine.Vector3.zero, maxDistanceDelta); vector2.x = current.x; vector2.z = current.y; vector2.y += num3; vector += vector2 * num2; } lineRenderer.SetPositions(points); } } public static GameObject arcVisualizerPrefab; public static float arcVisualizerSimulationLength; public static int arcVisualizerVertexCount; [SerializeField] public float baseChargeDuration = 1f; public static float minChargeForChargedAttack; public static GameObject chargeVfxPrefab; public static string chargeVfxChildLocatorName; public static GameObject crosshairOverridePrefab; public static float walkSpeedCoefficient; public static string startChargeLoopSFXString; public static string endChargeLoopSFXString; public static string enterSFXString; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private Transform chargeVfxInstanceTransform; private int gauntlet; private uint soundID; private static int EmptyStateHash = Animator.StringToHash("Empty"); private static int ChargePunchIntroStateHash = Animator.StringToHash("ChargePunchIntro"); private static int ChargePunchIntroParamHash = Animator.StringToHash("ChargePunchIntro.playbackRate"); protected float chargeDuration { get; private set; } protected float charge { get; private set; } public override void OnEnter() { base.OnEnter(); chargeDuration = baseChargeDuration / attackSpeedStat; Util.PlaySound(enterSFXString, base.gameObject); soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnExit() { if ((bool)chargeVfxInstanceTransform) { EntityState.Destroy(chargeVfxInstanceTransform.gameObject); PlayAnimation("Gesture, Additive", EmptyStateHash); PlayAnimation("Gesture, Override", EmptyStateHash); crosshairOverrideRequest?.Dispose(); chargeVfxInstanceTransform = null; } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; Util.PlaySound(endChargeLoopSFXString, base.gameObject); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); charge = Mathf.Clamp01(base.fixedAge / chargeDuration); AkSoundEngine.SetRTPCValueByPlayingID("loaderShift_chargeAmount", charge * 100f, soundID); base.characterBody.SetSpreadBloom(charge); base.characterBody.SetAimTimer(3f); if (charge >= minChargeForChargedAttack && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab) { if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } Transform transform = FindModelChild(chargeVfxChildLocatorName); if ((bool)transform) { chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform; ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent(); if ((bool)component) { component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration; } } PlayCrossfade("Gesture, Additive", ChargePunchIntroStateHash, ChargePunchIntroParamHash, chargeDuration, 0.1f); PlayCrossfade("Gesture, Override", ChargePunchIntroStateHash, ChargePunchIntroParamHash, chargeDuration, 0.1f); } if ((bool)chargeVfxInstanceTransform) { base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; } if (base.isAuthority) { AuthorityFixedUpdate(); } } public override void Update() { base.Update(); Mathf.Clamp01(base.age / chargeDuration); } private void AuthorityFixedUpdate() { if (!ShouldKeepChargingAuthority()) { outer.SetNextState(GetNextStateAuthority()); } } protected virtual bool ShouldKeepChargingAuthority() { return IsKeyDownAuthority(); } protected virtual EntityState GetNextStateAuthority() { return new SwingChargedFist { charge = charge }; } } public class ChargeFist : BaseChargeFist { } public class ChargeZapFist : BaseChargeFist { protected override bool ShouldKeepChargingAuthority() { return base.fixedAge < base.chargeDuration; } protected override EntityState GetNextStateAuthority() { return new SwingZapFist { charge = base.charge }; } } public class FireHook : BaseSkillState { [SerializeField] public GameObject projectilePrefab; public static float damageCoefficient; public static GameObject muzzleflashEffectPrefab; public static string fireSoundString; public GameObject hookInstance; protected ProjectileStickOnImpact hookStickOnImpact; private bool isStuck; private bool hadHookInstance; private uint soundID; private static int FireHookIntroStateHash = Animator.StringToHash("FireHookIntro"); private static int FireHookLoopStateHash = Animator.StringToHash("FireHookLoop"); private static int FireHookExitStateHash = Animator.StringToHash("FireHookExit"); public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.position = ray.origin; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(ray.direction); fireProjectileInfo.crit = base.characterBody.RollCrit(); fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = 0f; fireProjectileInfo.damageColorIndex = DamageColorIndex.Default; fireProjectileInfo.procChainMask = default(ProcChainMask); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.owner = base.gameObject; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "MuzzleLeft", transmit: false); Util.PlaySound(fireSoundString, base.gameObject); PlayAnimation("Grapple", FireHookIntroStateHash); } public void SetHookReference(GameObject hook) { hookInstance = hook; hookStickOnImpact = hook.GetComponent(); hadHookInstance = true; } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)hookStickOnImpact) { if (hookStickOnImpact.stuck && !isStuck) { PlayAnimation("Grapple", FireHookLoopStateHash); } isStuck = hookStickOnImpact.stuck; } if (base.isAuthority && !hookInstance && hadHookInstance) { outer.SetNextStateToMain(); } } public override void OnExit() { PlayAnimation("Grapple", FireHookExitStateHash); EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "MuzzleLeft", transmit: false); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class FireYankHook : FireHook { } public class PreGroundSlam : BaseCharacterMain { public static float baseDuration; public static string enterSoundString; public static float upwardVelocity; private float duration; private static int PreGroundSlamStateHash = Animator.StringToHash("PreGroundSlam"); private static int GroundSlamParamHash = Animator.StringToHash("GroundSlam.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Body", PreGroundSlamStateHash, GroundSlamParamHash, duration); Util.PlaySound(enterSoundString, base.gameObject); base.characterMotor.Motor.ForceUnground(); base.characterMotor.disableAirControlUntilCollision = false; base.characterMotor.velocity.y = upwardVelocity; } public override void FixedUpdate() { base.FixedUpdate(); base.characterMotor.moveDirection = base.inputBank.moveVector; if (base.fixedAge > duration) { outer.SetNextState(new GroundSlam()); } } } public class GroundSlam : BaseCharacterMain { public static float airControl; public static float minimumDuration; public static float blastRadius; public static float blastProcCoefficient; public static float blastDamageCoefficient; public static float blastForce; public static string enterSoundString; public static float initialVerticalVelocity; public static float exitVerticalVelocity; public static float verticalAcceleration; public static float exitSlowdownCoefficient; public static UnityEngine.Vector3 blastBonusForce; public static GameObject blastImpactEffectPrefab; public static GameObject blastEffectPrefab; public static GameObject fistEffectPrefab; private float previousAirControl; private GameObject leftFistEffectInstance; private GameObject rightFistEffectInstance; private bool detonateNextFrame; public override void OnEnter() { base.OnEnter(); PlayCrossfade("Body", "GroundSlam", 0.2f); if (base.isAuthority) { base.characterMotor.onMovementHit += OnMovementHit; base.characterMotor.velocity.y = initialVerticalVelocity; } Util.PlaySound(enterSoundString, base.gameObject); previousAirControl = base.characterMotor.airControl; base.characterMotor.airControl = airControl; leftFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("MechHandR")); rightFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("MechHandL")); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && (bool)base.characterMotor) { base.characterMotor.moveDirection = base.inputBank.moveVector; base.characterDirection.moveVector = base.characterMotor.moveDirection; base.characterMotor.velocity.y += verticalAcceleration * GetDeltaTime(); if (base.fixedAge >= minimumDuration && (detonateNextFrame || base.characterMotor.Motor.GroundingStatus.IsStableOnGround)) { DetonateAuthority(); outer.SetNextStateToMain(); } } } public override void OnExit() { if (base.isAuthority) { base.characterMotor.onMovementHit -= OnMovementHit; base.characterMotor.Motor.ForceUnground(); base.characterMotor.velocity *= exitSlowdownCoefficient; base.characterMotor.velocity.y = exitVerticalVelocity; } base.characterMotor.airControl = previousAirControl; EntityState.Destroy(leftFistEffectInstance); EntityState.Destroy(rightFistEffectInstance); base.OnExit(); } private void OnMovementHit(ref CharacterMotor.MovementHitInfo movementHitInfo) { detonateNextFrame = true; } protected BlastAttack.Result DetonateAuthority() { UnityEngine.Vector3 footPosition = base.characterBody.footPosition; EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = footPosition, scale = blastRadius }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * blastDamageCoefficient, baseForce = blastForce, bonusForce = blastBonusForce, crit = RollCrit(), damageType = DamageType.Stun1s, falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius, position = footPosition, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } } public class LoaderMeleeAttack : BasicMeleeAttack { public static GameObject overchargeImpactEffectPrefab; public static float barrierPercentagePerHit; protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); if (HasBuff(JunkContent.Buffs.LoaderOvercharged)) { overlapAttack.damage *= 2f; overlapAttack.hitEffectPrefab = overchargeImpactEffectPrefab; overlapAttack.damageType |= (DamageTypeCombo)DamageType.Stun1s; } } protected override void OnMeleeHitAuthority() { base.OnMeleeHitAuthority(); base.healthComponent.AddBarrierAuthority(barrierPercentagePerHit * base.healthComponent.fullBarrier); } } public class BaseSwingChargedFist : LoaderMeleeAttack { public float charge; [SerializeField] public float minLungeSpeed; [SerializeField] public float maxLungeSpeed; [SerializeField] public float minPunchForce; [SerializeField] public float maxPunchForce; [SerializeField] public float minDuration; [SerializeField] public float maxDuration; public static bool disableAirControlUntilCollision; public static float speedCoefficientOnExit; public static float velocityDamageCoefficient; protected UnityEngine.Vector3 punchVelocity; private float bonusDamage; private static int ChargePunchStateHash = Animator.StringToHash("ChargePunch"); private static int ChargePunchParamHash = Animator.StringToHash("ChargePunch.playbackRate"); public float punchSpeed { get; private set; } public static event Action onHitAuthorityGlobal; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { base.characterMotor.Motor.ForceUnground(); base.characterMotor.disableAirControlUntilCollision |= disableAirControlUntilCollision; punchVelocity = CalculateLungeVelocity(base.characterMotor.velocity, GetAimRay().direction, charge, minLungeSpeed, maxLungeSpeed); base.characterMotor.velocity = punchVelocity; base.characterDirection.forward = base.characterMotor.velocity.normalized; punchSpeed = base.characterMotor.velocity.magnitude; bonusDamage = punchSpeed * (velocityDamageCoefficient * damageStat); } } protected override float CalcDuration() { return Mathf.Lerp(minDuration, maxDuration, charge); } protected override void PlayAnimation() { base.PlayAnimation(); PlayAnimation("FullBody, Override", ChargePunchStateHash, ChargePunchParamHash, duration); } protected override void AuthorityFixedUpdate() { base.AuthorityFixedUpdate(); if (!base.authorityInHitPause) { base.characterMotor.velocity = punchVelocity; base.characterDirection.forward = punchVelocity; base.characterBody.isSprinting = true; } } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); overlapAttack.damage = damageCoefficient * damageStat + bonusDamage; overlapAttack.forceVector = base.characterMotor.velocity + GetAimRay().direction * Mathf.Lerp(minPunchForce, maxPunchForce, charge); if (base.fixedAge + GetDeltaTime() >= duration) { HitBoxGroup hitBoxGroup = FindHitBoxGroup("PunchLollypop"); if ((bool)hitBoxGroup) { base.hitBoxGroup = hitBoxGroup; overlapAttack.hitBoxGroup = hitBoxGroup; } } } protected override void OnMeleeHitAuthority() { base.OnMeleeHitAuthority(); BaseSwingChargedFist.onHitAuthorityGlobal?.Invoke(this); } public override void OnExit() { base.OnExit(); base.characterMotor.velocity *= speedCoefficientOnExit; } public static UnityEngine.Vector3 CalculateLungeVelocity(UnityEngine.Vector3 currentVelocity, UnityEngine.Vector3 aimDirection, float charge, float minLungeSpeed, float maxLungeSpeed) { currentVelocity = ((UnityEngine.Vector3.Dot(currentVelocity, aimDirection) < 0f) ? UnityEngine.Vector3.zero : UnityEngine.Vector3.Project(currentVelocity, aimDirection)); return currentVelocity + aimDirection * Mathf.Lerp(minLungeSpeed, maxLungeSpeed, charge); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SwingChargedFist : BaseSwingChargedFist { } public class SwingZapFist : BaseSwingChargedFist { public static float selfKnockback; private bool hasHit; protected override void OnMeleeHitAuthority() { if (!hasHit) { base.OnMeleeHitAuthority(); hasHit = true; if ((bool)FindModelChild(swingEffectMuzzleString)) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.position = FindModelChild(swingEffectMuzzleString).position; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(punchVelocity); fireProjectileInfo.crit = base.isCritAuthority; fireProjectileInfo.damage = 1f * damageStat; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.projectilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/LoaderZapCone"); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } } protected override void AuthorityExitHitPause() { base.AuthorityExitHitPause(); outer.SetNextStateToMain(); } public override void OnExit() { base.OnExit(); if (base.isAuthority && hasHit && (bool)base.healthComponent) { UnityEngine.Vector3 vector = punchVelocity; vector.y = Mathf.Min(vector.y, 0f); vector = vector.normalized; vector *= 0f - selfKnockback; if ((bool)base.characterMotor) { base.characterMotor.ApplyForce(vector, alwaysApply: true); } } } } public class SwingComboFist : LoaderMeleeAttack, SteppedSkillDef.IStepSetter { public int gauntlet; void SteppedSkillDef.IStepSetter.SetStep(int i) { gauntlet = i; } protected override void PlayAnimation() { string animationStateName = ((gauntlet == 0) ? "SwingFistRight" : "SwingFistLeft"); float num = Mathf.Max(duration, 0.2f); PlayCrossfade("Gesture, Additive", animationStateName, "SwingFist.playbackRate", num, 0.1f); PlayCrossfade("Gesture, Override", animationStateName, "SwingFist.playbackRate", num, 0.1f); } protected override void BeginMeleeAttackEffect() { swingEffectMuzzleString = ((gauntlet == 0) ? "SwingRight" : "SwingLeft"); base.BeginMeleeAttackEffect(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)gauntlet); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); gauntlet = reader.ReadByte(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ThrowPylon : BaseState { public static GameObject projectilePrefab; public static float baseDuration; public static float damageCoefficient; public static string muzzleString; public static GameObject muzzleflashObject; public static string soundString; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; if (base.isAuthority) { Ray aimRay = GetAimRay(); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.crit = RollCrit(); fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.damageColorIndex = DamageColorIndex.Default; fireProjectileInfo.force = 0f; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.position = aimRay.origin; fireProjectileInfo.procChainMask = default(ProcChainMask); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction); fireProjectileInfo.target = null; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } EffectManager.SimpleMuzzleFlash(muzzleflashObject, base.gameObject, muzzleString, transmit: false); Util.PlaySound(soundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && duration <= base.age) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } } namespace EntityStates.LemurianBruiserMonster { public class ChargeMegaFireball : BaseState { public static float baseDuration = 1f; public static GameObject chargeEffectPrefab; public static string attackString; private float duration; private GameObject chargeInstance; private EffectManagerHelper _emh_chargeInstance; public override void Reset() { base.Reset(); duration = 0f; chargeInstance = null; _emh_chargeInstance = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Animator modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleMouth"); if ((bool)transform && (bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation); chargeInstance = _emh_chargeInstance.gameObject; } chargeInstance.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeInstance.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } } } if ((bool)modelAnimator) { PlayCrossfade("Gesture, Additive", "ChargeMegaFireball", "ChargeMegaFireball.playbackRate", duration, 0.1f); } } public override void OnExit() { base.OnExit(); if ((bool)chargeInstance) { if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null) { _emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance); } else { EntityState.Destroy(chargeInstance); } chargeInstance = null; _emh_chargeInstance = null; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireMegaFireball nextState = new FireMegaFireball(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireMegaFireball : BaseState { public static GameObject projectilePrefab; public static GameObject muzzleflashEffectPrefab; public static int projectileCount = 3; public static float totalYawSpread = 5f; public static float baseDuration = 2f; public static float baseFireDuration = 0.2f; public static float damageCoefficient = 1.2f; public static float projectileSpeed; public static float force = 20f; public static string attackString; private float duration; private float fireDuration; private int projectilesFired; private static int FireMegaFireballStateHash = Animator.StringToHash("FireMegaFireball"); private static int FireMegaFireballParamHash = Animator.StringToHash("FireMegaFireball.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; fireDuration = baseFireDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", FireMegaFireballStateHash, FireMegaFireballParamHash, duration); Util.PlaySound(attackString, base.gameObject); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); string muzzleName = "MuzzleMouth"; if (base.isAuthority) { int num = Mathf.FloorToInt(base.fixedAge / fireDuration * (float)projectileCount); if (projectilesFired <= num && projectilesFired < projectileCount) { if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleName, transmit: false); } Ray aimRay = GetAimRay(); float speedOverride = projectileSpeed; float bonusYaw = (float)Mathf.FloorToInt((float)projectilesFired - (float)(projectileCount - 1) / 2f) / (float)(projectileCount - 1) * totalYawSpread; UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speedOverride); projectilesFired++; } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Flamebreath : BaseState { public static GameObject flamethrowerEffectPrefab; public static GameObject impactEffectPrefab; public static GameObject tracerEffectPrefab; public static float maxDistance; public static float radius; public static float baseEntryDuration = 1f; public static float baseExitDuration = 0.5f; public static float baseFlamethrowerDuration = 2f; public static float totalDamageCoefficient = 1.2f; public static float procCoefficientPerTick; public static float tickFrequency; public static float force = 20f; public static string startAttackSoundString; public static string endAttackSoundString; public static float ignitePercentChance; public static float maxSpread; private float tickDamageCoefficient; private float flamethrowerStopwatch; private float stopwatch; private float entryDuration; private float exitDuration; private float flamethrowerDuration; private bool hasBegunFlamethrower; private ChildLocator childLocator; private Transform flamethrowerEffectInstance; private Transform muzzleTransform; private bool isCrit; private BulletAttack bulletAttack; private EffectManagerHelper _emh_flamethrowerEffectInstance; private static int PrepFlamebreathStateHash = Animator.StringToHash("PrepFlamebreath"); private static int PrepFlamebreathParamHash = Animator.StringToHash("PrepFlamebreath.playbackRate"); private const float flamethrowerEffectBaseDistance = 16f; private static int FlamebreathStateHash = Animator.StringToHash("Flamebreath"); private static int FlamebreathParamHash = Animator.StringToHash("Flamebreath.playbackRate"); public override void Reset() { base.Reset(); tickDamageCoefficient = 0f; flamethrowerStopwatch = 0f; stopwatch = 0f; entryDuration = 0f; exitDuration = 0f; flamethrowerDuration = 0f; hasBegunFlamethrower = false; childLocator = null; flamethrowerEffectInstance = null; muzzleTransform = null; isCrit = false; if (bulletAttack != null) { bulletAttack.Reset(); } _emh_flamethrowerEffectInstance = null; } public override void OnEnter() { base.OnEnter(); stopwatch = 0f; entryDuration = baseEntryDuration / attackSpeedStat; exitDuration = baseExitDuration / attackSpeedStat; flamethrowerDuration = baseFlamethrowerDuration; Transform modelTransform = GetModelTransform(); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(entryDuration + flamethrowerDuration + 1f); } if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); modelTransform.GetComponent().enabled = true; } float num = flamethrowerDuration * tickFrequency; tickDamageCoefficient = totalDamageCoefficient / num; if (base.isAuthority && (bool)base.characterBody) { isCrit = Util.CheckRoll(critStat, base.characterBody.master); } PlayAnimation("Gesture, Override", PrepFlamebreathStateHash, PrepFlamebreathParamHash, entryDuration); } protected void DestroyFlameThrowerEffect() { if (flamethrowerEffectInstance != null) { if (_emh_flamethrowerEffectInstance != null && _emh_flamethrowerEffectInstance.OwningPool != null) { _emh_flamethrowerEffectInstance.OwningPool.ReturnObject(_emh_flamethrowerEffectInstance); } else { EntityState.Destroy(flamethrowerEffectInstance.gameObject); } flamethrowerEffectInstance = null; _emh_flamethrowerEffectInstance = null; } } public override void OnExit() { Util.PlaySound(endAttackSoundString, base.gameObject); PlayCrossfade("Gesture, Override", "BufferEmpty", 0.1f); DestroyFlameThrowerEffect(); base.OnExit(); } private void FireFlame(string muzzleString) { GetAimRay(); if (base.isAuthority && (bool)muzzleTransform) { if (bulletAttack == null) { bulletAttack = new BulletAttack(); } bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = muzzleTransform.position; bulletAttack.aimVector = muzzleTransform.forward; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = maxSpread; bulletAttack.damage = tickDamageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.muzzleName = muzzleString; bulletAttack.hitEffectPrefab = impactEffectPrefab; bulletAttack.isCrit = isCrit; bulletAttack.radius = radius; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.stopperMask = LayerIndex.world.mask; bulletAttack.procCoefficient = procCoefficientPerTick; bulletAttack.maxDistance = maxDistance; bulletAttack.smartCollision = true; bulletAttack.damageType = (Util.CheckRoll(ignitePercentChance, base.characterBody.master) ? DamageType.IgniteOnHit : DamageType.Generic); bulletAttack.Fire(); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= entryDuration && stopwatch < entryDuration + flamethrowerDuration && !hasBegunFlamethrower) { hasBegunFlamethrower = true; Util.PlaySound(startAttackSoundString, base.gameObject); PlayAnimation("Gesture, Override", FlamebreathStateHash, FlamebreathParamHash, flamethrowerDuration); if ((bool)childLocator) { muzzleTransform = childLocator.FindChild("MuzzleMouth"); if (!EffectManager.ShouldUsePooledEffect(flamethrowerEffectPrefab)) { flamethrowerEffectInstance = UnityEngine.Object.Instantiate(flamethrowerEffectPrefab, muzzleTransform).transform; } else { _emh_flamethrowerEffectInstance = EffectManager.GetAndActivatePooledEffect(flamethrowerEffectPrefab, muzzleTransform, inResetLocal: true); flamethrowerEffectInstance = _emh_flamethrowerEffectInstance.gameObject.transform; } flamethrowerEffectInstance.transform.localPosition = UnityEngine.Vector3.zero; flamethrowerEffectInstance.GetComponent().newDuration = flamethrowerDuration; } } if (stopwatch >= entryDuration + flamethrowerDuration && hasBegunFlamethrower) { hasBegunFlamethrower = false; PlayCrossfade("Gesture, Override", "ExitFlamebreath", "ExitFlamebreath.playbackRate", exitDuration, 0.1f); } if (hasBegunFlamethrower) { flamethrowerStopwatch += Time.deltaTime; if (flamethrowerStopwatch > 1f / tickFrequency) { flamethrowerStopwatch -= 1f / tickFrequency; FireFlame("MuzzleCenter"); } } else { DestroyFlameThrowerEffect(); } if (stopwatch >= flamethrowerDuration + entryDuration + exitDuration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class SpawnState : EntityState { public static float duration = 2f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); GetModelAnimator(); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); if ((bool)spawnEffectPrefab) { EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "SpawnEffectOrigin", transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.LemurianMonster { public class Bite : BaseState { public static float baseDuration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float radius = 3f; public static GameObject hitEffectPrefab; public static GameObject biteEffectPrefab; public static string attackString; private OverlapAttack attack; private Animator modelAnimator; private float duration; private bool hasBit; private static int BiteStateHash = Animator.StringToHash("Bite"); private static int BiteParamHash = Animator.StringToHash("Bite.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat); if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Bite"); } if ((bool)modelAnimator) { PlayAnimation("Gesture", BiteStateHash, BiteParamHash, duration); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Bite.hitBoxActive") > 0.1f) { if (!hasBit) { EffectManager.SimpleMuzzleFlash(biteEffectPrefab, base.gameObject, "MuzzleMouth", transmit: true); hasBit = true; } attack.forceVector = base.transform.forward * forceMagnitude; attack.Fire(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ChargeFireball : BaseState { public static float baseDuration = 1f; public static GameObject chargeVfxPrefab; public static string attackString; private float duration; private GameObject chargeVfxInstance; protected EffectManagerHelper _efhChargeEffect; private static int ChargeFireballStateHash = Animator.StringToHash("ChargeFireball"); private static int ChargeFireballParamHash = Animator.StringToHash("ChargeFireball.playbackRate"); public override void Reset() { base.Reset(); duration = 0f; chargeVfxInstance = null; _efhChargeEffect = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; GetModelAnimator(); Transform modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleMouth"); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(chargeVfxPrefab)) { chargeVfxInstance = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform.position, transform.rotation); } else { _efhChargeEffect = EffectManager.GetAndActivatePooledEffect(chargeVfxPrefab, transform.position, transform.rotation); chargeVfxInstance = _efhChargeEffect.gameObject; } chargeVfxInstance.transform.parent = transform; } } } PlayAnimation("Gesture", ChargeFireballStateHash, ChargeFireballParamHash, duration); } public override void OnExit() { base.OnExit(); if (!chargeVfxInstance) { return; } if (!EffectManager.UsePools) { EntityState.Destroy(chargeVfxInstance); return; } if (_efhChargeEffect != null && _efhChargeEffect.OwningPool != null) { _efhChargeEffect.OwningPool.ReturnObject(_efhChargeEffect); return; } if (_efhChargeEffect != null) { UnityEngine.Debug.LogFormat("ChargeFireball has no owning pool {0} {1}", base.gameObject.name, base.gameObject.GetInstanceID()); } EntityState.Destroy(chargeVfxInstance); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireFireball nextState = new FireFireball(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireFireball : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static float baseDuration = 2f; public static float damageCoefficient = 1.2f; public static float force = 20f; public static string attackString; private float duration; private static int FireFireballStateHash = Animator.StringToHash("FireFireball"); private static int FireFireballParamHash = Animator.StringToHash("FireFireball.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture", FireFireballStateHash, FireFireballParamHash, duration); Util.PlaySound(attackString, base.gameObject); Ray aimRay = GetAimRay(); string muzzleName = "MuzzleMouth"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class LeapAttackState : BaseState { public static float baseDuration = 3.5f; public static float damage = 10f; public static float forceMagnitude = 16f; private OverlapAttack attack; private Animator modelAnimator; private RootMotionAccumulator rootMotionAccumulator; private float duration; public override void OnEnter() { base.OnEnter(); rootMotionAccumulator = GetModelRootMotionAccumulator(); modelAnimator = GetModelAnimator(); duration = baseDuration / attackSpeedStat; attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damage; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "LeapAttack"); } PlayCrossfade("Body", "LeapAttack", "LeapAttack.playbackRate", duration, 0.1f); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)rootMotionAccumulator) { UnityEngine.Vector3 vector = rootMotionAccumulator.ExtractRootMotion(); if (vector != UnityEngine.Vector3.zero && base.isAuthority && (bool)base.characterMotor) { base.characterMotor.rootMotion += vector; } } if (base.isAuthority) { attack.forceVector = (base.characterDirection ? (base.characterDirection.forward * forceMagnitude) : UnityEngine.Vector3.zero); if ((bool)modelAnimator && modelAnimator.GetFloat("LeapAttack.hitBoxActive") > 0.5f) { attack.Fire(); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : EntityState { public static float duration = 2f; public static string spawnSoundString; public static string devotionHissSoundString; public static string devotionSpawnSoundString; public override void OnEnter() { base.OnEnter(); CharacterBody component = base.gameObject.GetComponent(); if ((component.bodyFlags & CharacterBody.BodyFlags.Devotion) != 0 && component.master.devotionInventoryPrefab != null) { Util.PlaySound(devotionHissSoundString, base.gameObject); Util.PlaySound(devotionSpawnSoundString, base.gameObject); } else { Util.PlaySound(spawnSoundString, base.gameObject); } PlayAnimation("Body", "Spawn1", "Spawn1.playbackRate", duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.LaserTurbine { public class LaserTurbineBaseState : EntityState { private GenericOwnership genericOwnership; private SimpleLeash simpleLeash; private MemoizedGetComponent bodyGetComponent; protected LaserTurbineController laserTurbineController { get; private set; } protected SimpleRotateToDirection simpleRotateToDirection { get; private set; } protected CharacterBody ownerBody => bodyGetComponent.Get(genericOwnership?.ownerObject); protected virtual bool shouldFollow => true; public override void OnEnter() { base.OnEnter(); genericOwnership = GetComponent(); simpleLeash = GetComponent(); simpleRotateToDirection = GetComponent(); laserTurbineController = GetComponent(); } protected InputBankTest GetInputBank() { return ownerBody?.inputBank; } protected Ray GetAimRay() { return new Ray(base.transform.position, base.transform.forward); } protected Transform GetMuzzleTransform() { return base.transform; } public override void Update() { base.Update(); if ((bool)ownerBody && shouldFollow) { simpleLeash.leashOrigin = ownerBody.corePosition; simpleRotateToDirection.targetRotation = UnityEngine.Quaternion.LookRotation(ownerBody.inputBank.aimDirection); } } protected float GetDamage() { float num = 1f; if ((bool)ownerBody) { num = ownerBody.damage; if ((bool)ownerBody.inventory) { num *= (float)ownerBody.inventory.GetItemCount(RoR2Content.Items.LaserTurbine); } } return num; } } public class RechargeState : LaserTurbineBaseState { public static float baseDuration = 60f; public static int killChargesRequired = 4; public static int killChargeDuration = 4; public Run.FixedTimeStamp startTime { get; private set; } public Run.FixedTimeStamp readyTime { get; private set; } public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { startTime = Run.FixedTimeStamp.now; readyTime = startTime + baseDuration; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.ownerBody.GetBuffCount(RoR2Content.Buffs.LaserTurbineKillCharge) >= killChargesRequired) { if (NetworkServer.active) { base.laserTurbineController.ExpendCharge(); } outer.SetNextState(new ReadyState()); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(startTime); writer.Write(readyTime); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); startTime = reader.ReadFixedTimeStamp(); readyTime = reader.ReadFixedTimeStamp(); } } public class ReadyState : LaserTurbineBaseState { public static float baseDuration; public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= baseDuration) { outer.SetNextState(new AimState()); } } } public class AimState : LaserTurbineBaseState { public static float targetAcquisitionRadius; private bool foundTarget; protected override bool shouldFollow => false; public override void OnEnter() { base.OnEnter(); if (!base.isAuthority) { return; } TeamMask enemyTeams = TeamMask.GetEnemyTeams(base.ownerBody.teamComponent.teamIndex); HurtBox[] hurtBoxes = new SphereSearch { radius = targetAcquisitionRadius, mask = LayerIndex.entityPrecise.mask, origin = base.transform.position, queryTriggerInteraction = QueryTriggerInteraction.UseGlobal }.RefreshCandidates().FilterCandidatesByHurtBoxTeam(enemyTeams).OrderCandidatesByDistance() .FilterCandidatesByDistinctHurtBoxEntities() .GetHurtBoxes(); float blastRadius = FireMainBeamState.secondBombPrefab.GetComponent().blastRadius; int num = -1; int num2 = 0; for (int i = 0; i < hurtBoxes.Length; i++) { HurtBox[] hurtBoxes2 = new SphereSearch { radius = blastRadius, mask = LayerIndex.entityPrecise.mask, origin = hurtBoxes[i].transform.position, queryTriggerInteraction = QueryTriggerInteraction.UseGlobal }.RefreshCandidates().FilterCandidatesByHurtBoxTeam(enemyTeams).FilterCandidatesByDistinctHurtBoxEntities() .GetHurtBoxes(); if (hurtBoxes2.Length > num2) { num = i; num2 = hurtBoxes2.Length; } } if (num != -1) { base.simpleRotateToDirection.targetRotation = UnityEngine.Quaternion.LookRotation(hurtBoxes[num].transform.position - base.transform.position); foundTarget = true; } } public override void Update() { base.Update(); if (base.isAuthority) { if (foundTarget) { outer.SetNextState(new ChargeMainBeamState()); } else { outer.SetNextState(new ReadyState()); } } } } public class ChargeMainBeamState : LaserTurbineBaseState { public static float baseDuration; public static GameObject beamIndicatorPrefab; private GameObject beamIndicatorInstance; private ChildLocator beamIndicatorChildLocator; private Transform beamIndicatorEndTransform; protected override bool shouldFollow => false; public override void OnEnter() { base.OnEnter(); beamIndicatorInstance = UnityEngine.Object.Instantiate(beamIndicatorPrefab, GetMuzzleTransform(), worldPositionStays: false); beamIndicatorChildLocator = beamIndicatorInstance.GetComponent(); if ((bool)beamIndicatorChildLocator) { beamIndicatorEndTransform = beamIndicatorChildLocator.FindChild("End"); } } public override void OnExit() { EntityState.Destroy(beamIndicatorInstance); base.OnExit(); } public override void Update() { base.Update(); if (base.isAuthority && base.fixedAge >= baseDuration) { outer.SetNextState(new FireMainBeamState()); } if ((bool)beamIndicatorInstance && (bool)beamIndicatorEndTransform) { float num = 1000f; Ray aimRay = GetAimRay(); _ = beamIndicatorInstance.transform.parent.position; UnityEngine.Vector3 point = aimRay.GetPoint(num); if (Util.CharacterRaycast(base.ownerBody.gameObject, aimRay, out var hitInfo, num, (int)LayerIndex.entityPrecise.mask | (int)LayerIndex.world.mask, QueryTriggerInteraction.UseGlobal)) { point = hitInfo.point; } beamIndicatorEndTransform.transform.position = point; } } } public class FireMainBeamState : LaserTurbineBaseState { public static float baseDuration; public static float mainBeamDamageCoefficient; public static float mainBeamProcCoefficient; public static float mainBeamForce; public static float mainBeamRadius; public static float mainBeamMaxDistance; public static GameObject forwardBeamTracerEffect; public static GameObject backwardBeamTracerEffect; public static GameObject mainBeamImpactEffect; public static GameObject secondBombPrefab; public static float secondBombDamageCoefficient; private Ray initialAimRay; private UnityEngine.Vector3 beamHitPosition; private bool isCrit; protected override bool shouldFollow => true; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { initialAimRay = GetAimRay(); } if (NetworkServer.active) { isCrit = base.ownerBody.RollCrit(); FireBeamServer(initialAimRay, forwardBeamTracerEffect, mainBeamMaxDistance, isInitialBeam: true); } base.laserTurbineController.showTurbineDisplay = false; } public override void Update() { base.Update(); if (base.isAuthority && base.fixedAge >= baseDuration) { outer.SetNextState(new RechargeState()); } } public override void OnExit() { if (NetworkServer.active && !outer.destroying) { UnityEngine.Vector3 direction = initialAimRay.origin - beamHitPosition; Ray aimRay = new Ray(beamHitPosition, direction); FireBeamServer(aimRay, backwardBeamTracerEffect, direction.magnitude, isInitialBeam: false); } base.laserTurbineController.showTurbineDisplay = true; base.OnExit(); } private void FireBeamServer(Ray aimRay, GameObject tracerEffectPrefab, float maxDistance, bool isInitialBeam) { bool didHit = false; BulletAttack obj = new BulletAttack { origin = aimRay.origin, aimVector = aimRay.direction, bulletCount = 1u, damage = GetDamage() * mainBeamDamageCoefficient, damageColorIndex = DamageColorIndex.Item, damageType = DamageType.Generic, falloffModel = BulletAttack.FalloffModel.None, force = mainBeamForce, hitEffectPrefab = mainBeamImpactEffect, HitEffectNormal = false, hitMask = LayerIndex.entityPrecise.mask, isCrit = isCrit, maxDistance = maxDistance, minSpread = 0f, maxSpread = 0f, muzzleName = "", owner = base.ownerBody.gameObject, procChainMask = default(ProcChainMask), procCoefficient = mainBeamProcCoefficient, queryTriggerInteraction = QueryTriggerInteraction.UseGlobal, radius = mainBeamRadius, smartCollision = true, sniper = false, spreadPitchScale = 1f, spreadYawScale = 1f, stopperMask = LayerIndex.world.mask, tracerEffectPrefab = (isInitialBeam ? tracerEffectPrefab : null), weapon = base.gameObject }; TeamIndex teamIndex = base.ownerBody.teamComponent.teamIndex; obj.hitCallback = delegate(BulletAttack _bulletAttack, ref BulletAttack.BulletHit info) { bool flag = BulletAttack.defaultHitCallback(_bulletAttack, ref info); if (!isInitialBeam) { return true; } if (flag) { HealthComponent healthComponent = (info.hitHurtBox ? info.hitHurtBox.healthComponent : null); if ((bool)healthComponent && healthComponent.alive && info.hitHurtBox.teamIndex != teamIndex) { flag = false; } } if (!flag) { didHit = true; beamHitPosition = info.point; } return flag; }; obj.filterCallback = delegate(BulletAttack _bulletAttack, ref BulletAttack.BulletHit info) { return (!info.entityObject || (object)info.entityObject != _bulletAttack.owner) && BulletAttack.defaultFilterCallback(_bulletAttack, ref info); }; obj.Fire(); if (!didHit) { if (Physics.Raycast(aimRay, out var hitInfo, mainBeamMaxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { didHit = true; beamHitPosition = hitInfo.point; } else { beamHitPosition = aimRay.GetPoint(mainBeamMaxDistance); } } if (didHit && isInitialBeam) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = secondBombPrefab; fireProjectileInfo.owner = base.ownerBody.gameObject; fireProjectileInfo.position = beamHitPosition - aimRay.direction * 0.5f; fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; fireProjectileInfo.damage = GetDamage() * secondBombDamageCoefficient; fireProjectileInfo.damageColorIndex = DamageColorIndex.Item; fireProjectileInfo.crit = isCrit; ProjectileManager.instance.FireProjectile(fireProjectileInfo); } if (!isInitialBeam) { EffectData effectData = new EffectData { origin = aimRay.origin, start = base.transform.position }; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); UnityEngine.Vector3 origin = initialAimRay.origin; UnityEngine.Vector3 direction = initialAimRay.direction; writer.Write(origin); writer.Write(direction); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); UnityEngine.Vector3 origin = reader.ReadVector3(); UnityEngine.Vector3 direction = reader.ReadVector3(); initialAimRay = new Ray(origin, direction); } } } namespace EntityStates.VagrantMonster { public class ChargeMegaNova : BaseState { public static float baseDuration = 3f; public static GameObject chargingEffectPrefab; public static GameObject areaIndicatorPrefab; public static string chargingSoundString; public static float novaRadius; private float duration; private float stopwatch; private GameObject chargeEffectInstance; private GameObject areaIndicatorInstance; private uint soundID; private EffectManagerHelper _emh_chargeEffectInstance; private EffectManagerHelper _emh_areaIndicatorInstance; private UnityEngine.Vector3 _cachedScaleVector = UnityEngine.Vector3.one; public override void Reset() { base.Reset(); duration = 0f; stopwatch = 0f; chargeEffectInstance = null; areaIndicatorInstance = null; soundID = 0u; _emh_chargeEffectInstance = null; _emh_areaIndicatorInstance = null; } public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); PlayCrossfade("Gesture, Override", "ChargeMegaNova", "ChargeMegaNova.playbackRate", duration, 0.3f); soundID = Util.PlayAttackSpeedSound(chargingSoundString, base.gameObject, attackSpeedStat); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild("HullCenter"); Transform transform2 = component.FindChild("NovaCenter"); if ((bool)transform && (bool)chargingEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargingEffectPrefab)) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargingEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargingEffectPrefab, transform.position, transform.rotation); chargeEffectInstance = _emh_chargeEffectInstance.gameObject; } _cachedScaleVector.x = novaRadius; _cachedScaleVector.y = novaRadius; _cachedScaleVector.z = novaRadius; chargeEffectInstance.transform.localScale = _cachedScaleVector; chargeEffectInstance.transform.parent = transform; chargeEffectInstance.GetComponent().newDuration = duration; } if ((bool)transform2 && (bool)areaIndicatorPrefab) { if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab)) { areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab, transform2.position, transform2.rotation); } else { _emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, transform2.position, transform2.rotation); areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject; } _cachedScaleVector.x = novaRadius * 2f; _cachedScaleVector.y = novaRadius * 2f; _cachedScaleVector.z = novaRadius * 2f; areaIndicatorInstance.transform.localScale = _cachedScaleVector; areaIndicatorInstance.transform.parent = transform2; } } public override void OnExit() { base.OnExit(); AkSoundEngine.StopPlayingID(soundID); if ((bool)chargeEffectInstance) { if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null) { _emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance); } else { EntityState.Destroy(chargeEffectInstance); } _emh_chargeEffectInstance = null; chargeEffectInstance = null; } if ((bool)areaIndicatorInstance) { if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null) { _emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance); } else { EntityState.Destroy(areaIndicatorInstance); } _emh_areaIndicatorInstance = null; areaIndicatorInstance = null; } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { FireMegaNova fireMegaNova = new FireMegaNova(); fireMegaNova.novaRadius = novaRadius; outer.SetNextState(fireMegaNova); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class ChargeTrackingBomb : BaseState { public static float baseDuration = 3f; public static GameObject chargingEffectPrefab; public static string chargingSoundString; private float duration; private float stopwatch; private GameObject chargeEffectInstance; private uint soundID; private EffectManagerHelper _emh_chargeEffectInstance; public override void Reset() { base.Reset(); duration = 0f; stopwatch = 0f; chargeEffectInstance = null; soundID = 0u; _emh_chargeEffectInstance = null; } public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); PlayCrossfade("Gesture, Override", "ChargeTrackingBomb", "ChargeTrackingBomb.playbackRate", duration, 0.3f); soundID = Util.PlayAttackSpeedSound(chargingSoundString, base.gameObject, attackSpeedStat); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild("TrackingBombMuzzle"); if ((bool)transform && (bool)chargingEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargingEffectPrefab)) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargingEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargingEffectPrefab, transform.position, transform.rotation); chargeEffectInstance = _emh_chargeEffectInstance.gameObject; } chargeEffectInstance.transform.parent = transform; chargeEffectInstance.GetComponent().newDuration = duration; } } public override void OnExit() { base.OnExit(); AkSoundEngine.StopPlayingID(soundID); if ((bool)chargeEffectInstance) { if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null) { _emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance); } else { EntityState.Destroy(chargeEffectInstance); } } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextState(new FireTrackingBomb()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class DeathState : BaseState { public static GameObject initialExplosion; public static string deathString; public override void OnEnter() { base.OnEnter(); Util.PlaySound(deathString, base.gameObject); if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if (base.isAuthority && (bool)initialExplosion) { EffectManager.SimpleImpactEffect(initialExplosion, base.transform.position, UnityEngine.Vector3.up, transmit: true); } EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class ExplosionAttack : BaseState { public static float minRadius; public static float maxRadius; public static int explosionCount; public static float baseDuration; public static float damageCoefficient; public static float force; public static float damageScaling; public static GameObject novaEffectPrefab; private float explosionTimer; private float explosionInterval; private int explosionIndex; public override void OnEnter() { base.OnEnter(); explosionInterval = baseDuration / (float)explosionCount; explosionIndex = 0; } public override void FixedUpdate() { base.FixedUpdate(); explosionTimer -= GetDeltaTime(); if (!(explosionTimer <= 0f)) { return; } if (explosionIndex >= explosionCount) { if (base.isAuthority) { outer.SetNextStateToMain(); } } else { explosionTimer += explosionInterval; Explode(); explosionIndex++; } } public override void OnExit() { base.OnExit(); } private void Explode() { float t = (float)explosionIndex / (float)(explosionCount - 1); float num = Mathf.Lerp(minRadius, maxRadius, t); EffectManager.SpawnEffect(novaEffectPrefab, new EffectData { origin = base.transform.position, scale = num }, transmit: false); if (NetworkServer.active) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * damageCoefficient * Mathf.Pow(damageScaling, explosionIndex); blastAttack.baseForce = force; blastAttack.position = base.transform.position; blastAttack.radius = num; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); } } } public class FireMegaNova : BaseState { public static float baseDuration = 3f; public static GameObject novaEffectPrefab; public static GameObject novaImpactEffectPrefab; public static string novaSoundString; public static float novaDamageCoefficient; public static float novaForce; public float novaRadius; private float duration; private float stopwatch; private static int FireMegaNovaStateHash = Animator.StringToHash("FireMegaNova"); private static int FireMegaNovaParamHash = Animator.StringToHash("FireMegaNova.playbackRate"); public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Override", FireMegaNovaStateHash, FireMegaNovaParamHash, duration); Detonate(); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void Detonate() { UnityEngine.Vector3 position = base.transform.position; Util.PlaySound(novaSoundString, base.gameObject); if ((bool)novaEffectPrefab) { EffectManager.SimpleMuzzleFlash(novaEffectPrefab, base.gameObject, "NovaCenter", transmit: false); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = 3f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matVagrantEnergized"); temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent()); } if (NetworkServer.active) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.baseDamage = damageStat * novaDamageCoefficient; blastAttack.baseForce = novaForce; blastAttack.bonusForce = UnityEngine.Vector3.zero; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = base.characterBody.RollCrit(); blastAttack.damageColorIndex = DamageColorIndex.Default; blastAttack.damageType = DamageType.Generic; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.inflictor = base.gameObject; blastAttack.position = position; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = 3f; blastAttack.radius = novaRadius; blastAttack.losType = BlastAttack.LoSType.NearestHit; blastAttack.teamIndex = base.teamComponent.teamIndex; blastAttack.impactEffect = EffectCatalog.FindEffectIndexFromPrefab(novaImpactEffectPrefab); blastAttack.Fire(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class FireTrackingBomb : BaseState { public static float baseDuration = 3f; public static GameObject projectilePrefab; public static GameObject muzzleEffectPrefab; public static string fireBombSoundString; public static float bombDamageCoefficient; public static float bombForce; public float novaRadius; private float duration; private float stopwatch; private static int FireTrackingBombStateHash = Animator.StringToHash("FireTrackingBomb"); private static int FireTrackingBombParamHash = Animator.StringToHash("FireTrackingBomb.playbackRate"); public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Override", FireTrackingBombStateHash, FireTrackingBombParamHash, duration); FireBomb(); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireBomb() { Ray aimRay = GetAimRay(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { aimRay.origin = component.FindChild("TrackingBombMuzzle").transform.position; } } EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "TrackingBombMuzzle", transmit: false); if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * bombDamageCoefficient, bombForce, Util.CheckRoll(critStat, base.characterBody.master)); } } } public class SpawnState : BaseState { private float stopwatch; public static float duration = 4f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); if ((bool)spawnEffectPrefab) { EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "SpawnOrigin", transmit: false); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { modelTransform.GetComponent().enabled = true; } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.VagrantMonster.Weapon { public class JellyBarrage : BaseState { private float stopwatch; private float missileStopwatch; public static float baseDuration; public static string muzzleString; public static float missileSpawnFrequency; public static float missileSpawnDelay; public static float damageCoefficient; public static float maxSpread; public static GameObject projectilePrefab; public static GameObject muzzleflashPrefab; private ChildLocator childLocator; public override void OnEnter() { base.OnEnter(); missileStopwatch -= missileSpawnDelay; if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "") { Util.PlaySound(base.sfxLocator.barkSound, base.gameObject); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); if ((bool)childLocator) { _ = (bool)childLocator.FindChild(muzzleString); } } } private void FireBlob(Ray projectileRay, float bonusPitch, float bonusYaw) { projectileRay.direction = Util.ApplySpread(projectileRay.direction, 0f, maxSpread, 1f, 1f, bonusYaw, bonusPitch); ProjectileManager.instance.FireProjectile(projectilePrefab, projectileRay.origin, Util.QuaternionSafeLookRotation(projectileRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); stopwatch += deltaTime; missileStopwatch += deltaTime; if (missileStopwatch >= 1f / missileSpawnFrequency) { missileStopwatch -= 1f / missileSpawnFrequency; Transform transform = childLocator.FindChild(muzzleString); if ((bool)transform) { Ray projectileRay = default(Ray); projectileRay.origin = transform.position; projectileRay.direction = GetAimRay().direction; float maxDistance = 1000f; if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask)) { projectileRay.direction = hitInfo.point - transform.position; } FireBlob(projectileRay, 0f, 0f); } } if (stopwatch >= baseDuration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class JellyStorm : BaseState { private float stopwatch; private float missileStopwatch; public static float stormDuration; public static float stormToIdleTransitionDuration; public static string stormPointChildString; public static float missileSpawnFrequency; public static float missileSpawnDelay; public static int missileTurretCount; public static float missileTurretYawFrequency; public static float missileTurretPitchFrequency; public static float missileTurretPitchMagnitude; public static float missileSpeed; public static float damageCoefficient; public static GameObject projectilePrefab; public static GameObject effectPrefab; private bool beginExitTransition; private ChildLocator childLocator; private static int StormEnterStateHash = Animator.StringToHash("StormEnter"); public override void OnEnter() { base.OnEnter(); missileStopwatch -= missileSpawnDelay; if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "") { Util.PlaySound(base.sfxLocator.barkSound, base.gameObject); } PlayAnimation("Gesture", StormEnterStateHash); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); if ((bool)childLocator) { _ = (bool)childLocator.FindChild(stormPointChildString); } } } private void FireBlob(Ray aimRay, float bonusPitch, float bonusYaw, float speed) { UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw, bonusPitch); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speed); } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); stopwatch += deltaTime; missileStopwatch += deltaTime; if (missileStopwatch >= 1f / missileSpawnFrequency && !beginExitTransition) { missileStopwatch -= 1f / missileSpawnFrequency; Transform transform = childLocator.FindChild(stormPointChildString); if ((bool)transform) { for (int i = 0; i < missileTurretCount; i++) { float bonusYaw = 360f / (float)missileTurretCount * (float)i + 360f * missileTurretYawFrequency * stopwatch; float bonusPitch = Mathf.Sin(MathF.PI * 2f * missileTurretPitchFrequency * stopwatch) * missileTurretPitchMagnitude; Ray aimRay = default(Ray); aimRay.origin = transform.position; aimRay.direction = transform.transform.forward; FireBlob(aimRay, bonusPitch, bonusYaw, missileSpeed); } } } if (stopwatch >= stormDuration - stormToIdleTransitionDuration && !beginExitTransition) { beginExitTransition = true; PlayCrossfade("Gesture", "StormExit", "StormExit.playbackRate", stormToIdleTransitionDuration, 0.5f); } if (stopwatch >= stormDuration && base.isAuthority) { outer.SetNextStateToMain(); } } } } namespace EntityStates.JellyfishMonster { public class DeathState : GenericCharacterDeath { public static GameObject enterEffectPrefab; public override void OnEnter() { base.OnEnter(); DestroyModel(); if (NetworkServer.active) { DestroyBodyAsapServer(); } } protected override void CreateDeathEffects() { base.CreateDeathEffects(); if ((bool)enterEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(enterEffectPrefab)) { EffectManager.SimpleEffect(enterEffectPrefab, base.transform.position, base.transform.rotation, transmit: false); } else { EffectManager.GetAndActivatePooledEffect(enterEffectPrefab, base.transform.position, base.transform.rotation); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class JellyNova : BaseState { public static float baseDuration = 3f; public static GameObject chargingEffectPrefab; public static GameObject novaEffectPrefab; public static string chargingSoundString; public static string novaSoundString; public static float novaDamageCoefficient; public static float novaRadius; public static float novaForce; private bool hasExploded; private float duration; private float stopwatch; private GameObject chargeEffect; private PrintController printController; private uint soundID; private UnityEngine.Vector3 _cachedScale = UnityEngine.Vector3.one; private BlastAttack attack; private EffectData _effectData; private EffectManagerHelper _emh_chargeEffect; public override void Reset() { base.Reset(); hasExploded = false; duration = 0f; chargeEffect = null; printController = null; soundID = 0u; if (attack != null) { attack.Reset(); } if (_effectData != null) { _effectData.Reset(); } _emh_chargeEffect = null; } public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); PlayCrossfade("Body", "Nova", "Nova.playbackRate", duration, 0.1f); soundID = Util.PlaySound(chargingSoundString, base.gameObject); if ((bool)chargingEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargingEffectPrefab)) { chargeEffect = UnityEngine.Object.Instantiate(chargingEffectPrefab, base.transform.position, base.transform.rotation); } else { _emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargingEffectPrefab, base.transform.position, base.transform.rotation); chargeEffect = _emh_chargeEffect.gameObject; } chargeEffect.transform.parent = base.transform; _cachedScale.x = novaRadius; _cachedScale.y = novaRadius; _cachedScale.z = novaRadius; chargeEffect.transform.localScale = _cachedScale; chargeEffect.GetComponent().newDuration = duration; } if ((bool)modelTransform) { printController = modelTransform.GetComponent(); if ((bool)printController) { printController.enabled = true; printController.printTime = duration; } } } protected void DestroyChargeEffect() { if ((bool)chargeEffect) { if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null) { _emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect); } else { EntityState.Destroy(chargeEffect); } _emh_chargeEffect = null; chargeEffect = null; } } public override void OnExit() { base.OnExit(); AkSoundEngine.StopPlayingID(soundID); DestroyChargeEffect(); if ((bool)printController) { printController.enabled = false; } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority && !hasExploded) { Detonate(); } } private void Detonate() { hasExploded = true; Util.PlaySound(novaSoundString, base.gameObject); if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } DestroyChargeEffect(); if ((bool)novaEffectPrefab) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.origin = base.transform.position; _effectData.scale = novaRadius; EffectManager.SpawnEffect(novaEffectPrefab, _effectData, transmit: true); } if (attack == null) { attack = new BlastAttack(); } attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); attack.baseDamage = damageStat * novaDamageCoefficient; attack.baseForce = novaForce; attack.position = base.transform.position; attack.radius = novaRadius; attack.procCoefficient = 2f; attack.attackerFiltering = AttackerFiltering.NeverHitSelf; attack.Fire(); if ((bool)base.healthComponent) { base.healthComponent.Suicide(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class SpawnState : BaseState { public static float duration = 4f; public static string spawnSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Jellyfish { public class Dash : BaseState { public static float duration = 1.8f; public static float speedCoefficient = 2f; private Animator modelAnimator; private static int swimrateParamHash = Animator.StringToHash("swim.rate"); public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = base.rigidbodyMotor.rigid.transform.forward * base.characterBody.moveSpeed * speedCoefficient; } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.rigidbodyMotor && (bool)modelAnimator) { modelAnimator.SetFloat(swimrateParamHash, UnityEngine.Vector3.Magnitude(base.rigidbodyMotor.rigid.velocity)); } if (base.fixedAge >= duration) { outer.SetNextState(new SwimState()); } } } public class SwimState : BaseState { private Animator modelAnimator; private bool skill1InputReceived; private bool skill2InputReceived; private bool skill3InputReceived; private bool skill4InputReceived; private bool jumpInputReceived; private static int swimrateParamHash = Animator.StringToHash("swim.rate"); public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); } public override void Update() { base.Update(); if ((bool)base.inputBank) { skill1InputReceived = base.inputBank.skill1.down; skill2InputReceived |= base.inputBank.skill2.down; skill3InputReceived |= base.inputBank.skill3.down; skill4InputReceived |= base.inputBank.skill4.down; jumpInputReceived |= base.inputBank.jump.down; } } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } if ((bool)base.inputBank) { if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = base.inputBank.moveVector * base.characterBody.moveSpeed; if ((bool)modelAnimator) { modelAnimator.SetFloat(swimrateParamHash, UnityEngine.Vector3.Magnitude(base.rigidbodyMotor.rigid.velocity)); } } if ((bool)base.rigidbodyDirection) { base.rigidbodyDirection.aimDirection = GetAimRay().direction; } } if ((bool)base.skillLocator) { if ((bool)base.skillLocator.primary && skill1InputReceived) { base.skillLocator.primary.ExecuteIfReady(); } if ((bool)base.skillLocator.secondary && skill2InputReceived) { base.skillLocator.secondary.ExecuteIfReady(); } if ((bool)base.skillLocator.utility && skill3InputReceived) { base.skillLocator.utility.ExecuteIfReady(); } if ((bool)base.skillLocator.special && skill4InputReceived) { base.skillLocator.special.ExecuteIfReady(); } } } } } namespace EntityStates.Interactables.StoneGate { public class Opening : BaseState { public static string leftGateChildLocatorEntry; public static string rightGateChildLocatorEntry; public static AnimationCurve doorPositionCurve; public static float duration; public static string doorBeginOpenEffectChildLocatorEntry; public static string doorBeginOpenSoundString; public static string doorFinishedOpenEffectChildLocatorEntry; public static string doorFinishedOpenSoundString; private ChildLocator childLocator; private bool doorIsOpen; private Transform leftGateTransform; private Transform rightGateTransform; public override void OnEnter() { base.OnEnter(); childLocator = GetComponent(); childLocator.FindChild(doorBeginOpenEffectChildLocatorEntry).gameObject.SetActive(value: true); Util.PlaySound(doorBeginOpenSoundString, base.gameObject); if (NetworkServer.active) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "STONEGATE_OPEN" }); } } public override void Update() { base.Update(); UpdateGateTransform(ref leftGateTransform, leftGateChildLocatorEntry); UpdateGateTransform(ref rightGateTransform, rightGateChildLocatorEntry); } private void UpdateGateTransform(ref Transform gateTransform, string childLocatorString) { if (!gateTransform) { gateTransform = childLocator.FindChild(childLocatorString); return; } UnityEngine.Vector3 localPosition = gateTransform.localPosition; gateTransform.localPosition = new UnityEngine.Vector3(localPosition.x, localPosition.y, doorPositionCurve.Evaluate(base.age / duration)); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && !doorIsOpen) { doorIsOpen = true; Util.PlaySound(doorFinishedOpenSoundString, base.gameObject); childLocator.FindChild(doorBeginOpenEffectChildLocatorEntry).gameObject.SetActive(value: false); childLocator.FindChild(doorFinishedOpenEffectChildLocatorEntry).gameObject.SetActive(value: true); } } } } namespace EntityStates.Interactables.MSObelisk { public class ReadyToEndGame : BaseState { public static string chargeupChildString; public static string chargeupSoundString; public static float chargeupDuration; private ChildLocator childLocator; private PurchaseInteraction purchaseInteraction; private bool ready; public override void OnEnter() { base.OnEnter(); childLocator = GetComponent(); purchaseInteraction = GetComponent(); purchaseInteraction.NetworkcontextToken = "MSOBELISK_CONTEXT_CONFIRMATION"; purchaseInteraction.Networkavailable = false; childLocator.FindChild(chargeupChildString).gameObject.SetActive(value: true); Util.PlaySound(chargeupSoundString, base.gameObject); ReadOnlyCollection instances = PlayerCharacterMasterController.instances; for (int i = 0; i < instances.Count; i++) { instances[i].master.preventGameOver = true; } for (int j = 0; j < CameraRigController.readOnlyInstancesList.Count; j++) { CameraRigController.readOnlyInstancesList[j].disableSpectating = true; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= chargeupDuration && !ready) { ready = true; purchaseInteraction.Networkavailable = true; base.gameObject.GetComponent().mainStateType = new SerializableEntityStateType(typeof(EndingGame)); } } } public class EndingGame : BaseState { public static GameObject destroyEffectPrefab; public static float timeBetweenDestroy; public static float timeUntilEndGame; private float destroyTimer; private float endGameTimer; private bool beginEndingGame; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { FixedUpdateServer(); } } private void FixedUpdateServer() { destroyTimer -= GetDeltaTime(); if (!beginEndingGame) { if (!(destroyTimer <= 0f)) { return; } destroyTimer = timeBetweenDestroy; ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Player); if (teamMembers.Count > 0) { GameObject gameObject = teamMembers[0].gameObject; CharacterBody component = gameObject.GetComponent(); if ((bool)component) { EffectManager.SpawnEffect(destroyEffectPrefab, new EffectData { origin = component.corePosition, scale = component.radius }, transmit: true); EntityState.Destroy(gameObject.gameObject); } } else { beginEndingGame = true; } } else { endGameTimer += GetDeltaTime(); if (endGameTimer >= timeUntilEndGame && (bool)Run.instance) { DoFinalAction(); } } } private void DoFinalAction() { bool flag = false; for (int i = 0; i < CharacterMaster.readOnlyInstancesList.Count; i++) { if (CharacterMaster.readOnlyInstancesList[i].inventory.GetItemCount(RoR2Content.Items.LunarTrinket) > 0) { flag = true; break; } } if (flag) { outer.SetNextState(new TransitionToNextStage()); return; } Run.instance.BeginGameOver(RoR2Content.GameEndings.ObliterationEnding); outer.SetNextState(new Idle()); } } public class TransitionToNextStage : BaseState { public static float duration; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { Stage.instance.BeginAdvanceStage(SceneCatalog.GetSceneDefFromSceneName("limbo")); outer.SetNextState(new Idle()); } } } } namespace EntityStates.Interactables.GoldBeacon { public class GoldBeaconBaseState : BaseState { protected void SetReady(bool ready) { Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { PrintController component = modelTransform.GetComponent(); component.paused = !ready; if (!ready) { component.age = 0f; } ChildLocator component2 = modelTransform.GetComponent(); if ((bool)component2) { component2.FindChild("Purchased").gameObject.SetActive(ready); } } PurchaseInteraction component3 = GetComponent(); if ((bool)component3) { component3.SetAvailable(!ready); } HologramProjector component4 = GetComponent(); if ((bool)component4) { component4.hologramPivot.gameObject.SetActive(!ready); } } } public class NotReady : GoldBeaconBaseState { public static int count { get; private set; } public override void OnEnter() { base.OnEnter(); SetReady(ready: false); SetPingable(value: true); count++; } public override void OnExit() { count--; base.OnExit(); } } public class Ready : GoldBeaconBaseState { public static GameObject activationEffectPrefab; public static int count { get; private set; } public override void OnEnter() { base.OnEnter(); SetReady(ready: true); SetPingable(value: false); count++; } public override void OnExit() { count--; if (!outer.destroying) { EffectManager.SpawnEffect(activationEffectPrefab, new EffectData { origin = base.transform.position, scale = 10f }, transmit: false); } base.OnExit(); } } } namespace EntityStates.InfiniteTowerSafeWard { public class Active : BaseSafeWardState { [SerializeField] public float radius; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; private InfiniteTowerRun run; public override void OnEnter() { base.OnEnter(); if ((bool)safeWardController) { safeWardController.SetIndicatorEnabled(enabled: false); } PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)purchaseInteraction) { purchaseInteraction.SetAvailable(newAvailable: false); } if ((bool)zone) { zone.Networkradius = radius; } run = Run.instance as InfiniteTowerRun; } public void SelfDestruct() { if (NetworkServer.active) { outer.SetNextState(new SelfDestruct()); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)zone && (bool)run) { float num = 1f; if ((bool)run.waveController) { num = run.waveController.zoneRadiusPercentage; } zone.Networkradius = radius * num; } } } public class AwaitingActivation : BaseSafeWardState { [SerializeField] public float radius; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)purchaseInteraction) { purchaseInteraction.SetAvailable(newAvailable: true); } if ((bool)zone) { zone.Networkradius = radius; } } public void Activate() { if (NetworkServer.active) { outer.SetNextState(new Active()); } } } public class AwaitingPortalUse : BaseSafeWardState { [SerializeField] public float radius; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)purchaseInteraction) { purchaseInteraction.SetAvailable(newAvailable: false); } if ((bool)zone) { zone.Networkradius = radius; } } } public class BaseSafeWardState : EntityState { protected PurchaseInteraction purchaseInteraction; protected VerticalTubeZone zone; protected Animator animator; [SerializeField] public string objectiveToken; private GenericObjectiveProvider genericObjectiveProvider; protected InfiniteTowerSafeWardController safeWardController; public override void OnEnter() { base.OnEnter(); purchaseInteraction = GetComponent(); zone = GetComponent(); animator = base.gameObject.GetComponentInChildren(); safeWardController = base.gameObject.GetComponent(); if (!string.IsNullOrEmpty(objectiveToken)) { genericObjectiveProvider = base.gameObject.AddComponent(); genericObjectiveProvider.objectiveToken = objectiveToken; } } public override void PlayAnimation(string layerName, string animationStateName) { if ((bool)animator && !string.IsNullOrEmpty(layerName)) { EntityState.PlayAnimationOnAnimator(animator, layerName, animationStateName); } } public override void OnExit() { if ((bool)genericObjectiveProvider) { EntityState.Destroy(genericObjectiveProvider); } base.OnExit(); } } public class Burrow : BaseSafeWardState { [SerializeField] public float duration; [SerializeField] public float radius; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)zone) { zone.Networkradius = radius; } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { outer.SetNextState(new AwaitingActivation()); } } } public class CorrallingPlayers : BaseSafeWardState { [SerializeField] public float duration; [SerializeField] public float initialRadius; [SerializeField] public float finalRadius; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)purchaseInteraction) { purchaseInteraction.SetAvailable(newAvailable: false); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)zone) { float t = Mathf.Min(1f, base.fixedAge / duration); zone.Networkradius = Mathf.Lerp(initialRadius, finalRadius, t); } if (NetworkServer.active && base.fixedAge >= duration) { outer.SetNextState(new AwaitingActivation()); } } } public class SelfDestruct : BaseSafeWardState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { EntityState.Destroy(base.gameObject); } } } public class Travelling : BaseSafeWardState { [SerializeField] public float radius; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; [SerializeField] public float minDistanceToNewLocation; [SerializeField] public float maxDistanceToNewLocation; [SerializeField] public float travelSpeed; [SerializeField] public float travelHeight; [SerializeField] public float pathMaxSlope; [SerializeField] public float pathMaxJumpHeight; [SerializeField] public float pathMaxSpeed; [SerializeField] public int pathNodeInclusionPeriod; [SerializeField] public string voSoundString; [SerializeField] public float minimumVoDelay; [SerializeField] public float maximumVoDelay; [SerializeField] public LoopSoundDef loopSoundDef; private LoopSoundManager.SoundLoopPtr loopPtr; private const HullMask wardHullMask = HullMask.Human; private const HullClassification pathHullClassification = HullClassification.Human; private bool didFail; private NodeGraph groundNodeGraph; private List potentialEndNodes; private List catmullRomPoints = new List(); private UnityEngine.Vector3 rotationVelocity; private RoR2.Path groundPath; private int catmullRomIndex; private CatmullRom3 currentCurve; private float tCurve; private float voTimer; private Xoroshiro128Plus rng; public Travelling() { } public Travelling(Xoroshiro128Plus rng) { this.rng = rng; } public override void OnEnter() { base.OnEnter(); didFail = false; PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); ResetVoTimer(); if ((bool)loopSoundDef) { loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSoundDef); } if ((bool)zone) { zone.Networkradius = radius; } if (NetworkServer.active) { groundNodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); potentialEndNodes = groundNodeGraph.FindNodesInRangeWithFlagConditions(base.transform.position, 0f, minDistanceToNewLocation, HullMask.Human, NodeFlags.TeleporterOK, NodeFlags.None, preventOverhead: false); Util.ShuffleList(potentialEndNodes, rng); List list = groundNodeGraph.FindNodesInRangeWithFlagConditions(base.transform.position, minDistanceToNewLocation, maxDistanceToNewLocation, HullMask.Human, NodeFlags.TeleporterOK, NodeFlags.None, preventOverhead: false); Util.ShuffleList(list, rng); potentialEndNodes.AddRange(list); groundPath = new RoR2.Path(groundNodeGraph); } } public override void OnExit() { LoopSoundManager.StopSoundLoopLocal(loopPtr); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); voTimer -= GetDeltaTime(); if (voTimer <= 0f) { ResetVoTimer(); Util.PlaySound(voSoundString, base.gameObject); } if (!NetworkServer.active) { return; } if (!didFail) { if (currentCurve == null) { if (potentialEndNodes.Count > 0) { EvaluateNextEndpoint(); } else { didFail = true; UnityEngine.Debug.LogError("SafeWard failed to find endpoint!"); } } else { tCurve = currentCurve.AdvanceTByDistance(tCurve, travelSpeed * GetDeltaTime()); tCurve = Mathf.Min(1f, tCurve); base.transform.position = currentCurve.Evaluate(tCurve); UnityEngine.Vector3 vector = currentCurve.EvaluateDerivative(tCurve); vector.y = 0f; vector = vector.normalized; UnityEngine.Vector3 forward = UnityEngine.Vector3.SmoothDamp(base.transform.forward, vector, ref rotationVelocity, 0.5f); base.transform.forward = forward; while (tCurve >= 1f && GetRemainingCurveSegmentCount() > 0) { tCurve -= 1f; catmullRomIndex++; UpdateCurveSegmentPoints(); } } } if (didFail || (GetRemainingCurveSegmentCount() <= 0 && tCurve >= 1f)) { outer.SetNextState(new Burrow()); } } private void EvaluateNextEndpoint() { int index = potentialEndNodes.Count - 1; NodeGraph.NodeIndex nodeIndex = potentialEndNodes[index]; potentialEndNodes.RemoveAt(index); NodeGraph.PathRequest pathRequest = new NodeGraph.PathRequest { startPos = base.transform.position, endPos = nodeIndex, hullClassification = HullClassification.Human, maxJumpHeight = pathMaxJumpHeight, maxSlope = pathMaxSlope, maxSpeed = pathMaxSpeed, path = groundPath }; PathTask pathTask = groundNodeGraph.ComputePath(pathRequest); if (pathTask == null || pathTask.status != PathTask.TaskStatus.Complete || !pathTask.wasReachable || pathTask.path.waypointsCount <= 1 || !groundNodeGraph.GetNodePosition(nodeIndex, out var _)) { return; } _ = 1f / (float)(pathTask.path.waypointsCount - 1); for (int i = 0; i < pathTask.path.waypointsCount; i++) { if (i % pathNodeInclusionPeriod != 0 && i != pathTask.path.waypointsCount - 1) { continue; } RoR2.Path.Waypoint waypoint = pathTask.path[i]; if (groundNodeGraph.GetNodePosition(waypoint.nodeIndex, out var position2)) { if (i > 0 && i < pathTask.path.waypointsCount - 1) { position2.y += travelHeight; } catmullRomPoints.Add(position2); } } if (catmullRomPoints.Count > 1) { UnityEngine.Vector3 item = 2f * catmullRomPoints[0] - catmullRomPoints[1]; catmullRomPoints.Insert(0, item); UnityEngine.Vector3 item2 = 2f * catmullRomPoints[catmullRomPoints.Count - 1] - catmullRomPoints[catmullRomPoints.Count - 2]; catmullRomPoints.Add(item2); DirectorCore.instance.AddOccupiedNode(groundNodeGraph, nodeIndex); catmullRomIndex = 0; currentCurve = new CatmullRom3(); tCurve = 0f; UpdateCurveSegmentPoints(); } else { catmullRomPoints.Clear(); } } private void UpdateCurveSegmentPoints() { currentCurve.SetPoints(catmullRomPoints[catmullRomIndex], catmullRomPoints[catmullRomIndex + 1], catmullRomPoints[catmullRomIndex + 2], catmullRomPoints[catmullRomIndex + 3]); } private int GetRemainingCurveSegmentCount() { return catmullRomPoints.Count - 4 - catmullRomIndex; } private void ResetVoTimer() { voTimer = UnityEngine.Random.Range(minimumVoDelay, maximumVoDelay); } } public class Unburrow : BaseSafeWardState { [SerializeField] public float duration; [SerializeField] public float radius; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; private Xoroshiro128Plus rng; public Unburrow() { } public Unburrow(Xoroshiro128Plus rng) { this.rng = rng; } public override void OnEnter() { base.OnEnter(); if ((bool)safeWardController) { safeWardController.SetIndicatorEnabled(enabled: true); } PlayAnimation(animationLayerName, animationStateName); Util.PlaySound(enterSoundString, base.gameObject); if ((bool)purchaseInteraction) { purchaseInteraction.SetAvailable(newAvailable: false); } if ((bool)zone) { zone.Networkradius = radius; } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { outer.SetNextState(new Travelling(rng)); } } } } namespace EntityStates.MagmaWorm { public class BlinkState : EntityStates.ImpBossMonster.BlinkState { } public class DeathState : GenericCharacterDeath { public static GameObject initialDeathExplosionEffect; public static string deathSoundString; public static float duration; private float stopwatch; public override void OnEnter() { base.OnEnter(); WormBodyPositions2 component = GetComponent(); WormBodyPositionsDriver component2 = GetComponent(); if ((bool)component) { component2.yDamperConstant = 0f; component2.ySpringConstant = 0f; component2.maxTurnSpeed = 0f; component.meatballCount = 0; Util.PlaySound(deathSoundString, component.bones[0].gameObject); } Transform modelTransform = GetModelTransform(); if (!modelTransform) { return; } PrintController printController = modelTransform.gameObject.AddComponent(); printController.printTime = duration; printController.enabled = true; printController.startingPrintHeight = 99999f; printController.maxPrintHeight = 99999f; printController.startingPrintBias = 1f; printController.maxPrintBias = 3.5f; printController.animateFlowmapPower = true; printController.startingFlowmapPower = 1.14f; printController.maxFlowmapPower = 30f; printController.disableWhenFinished = false; printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); ParticleSystem[] componentsInChildren = modelTransform.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].Stop(); } ChildLocator component3 = modelTransform.GetComponent(); if ((bool)component3) { Transform transform = component3.FindChild("PP"); if ((bool)transform) { PostProcessDuration component4 = transform.GetComponent(); if ((bool)component4) { component4.enabled = true; component4.maxDuration = duration; } } } if (NetworkServer.active) { EffectManager.SimpleMuzzleFlash(initialDeathExplosionEffect, base.gameObject, "HeadCenter", transmit: true); } } public override void FixedUpdate() { stopwatch += GetDeltaTime(); if (NetworkServer.active && stopwatch > duration) { EntityState.Destroy(base.gameObject); } } } public class Leap : BaseState { private enum LeapState { Burrow, Ascend, Fall, Resurface } private Transform modelBaseTransform; private readonly float diveDepth = 200f; private readonly UnityEngine.Vector3 idealDiveVelocity = UnityEngine.Vector3.down * 90f; private readonly UnityEngine.Vector3 idealLeapVelocity = UnityEngine.Vector3.up * 90f; private float leapAcceleration = 80f; private float resurfaceSpeed = 60f; private UnityEngine.Vector3 velocity; private LeapState leapState; public override void OnEnter() { base.OnEnter(); modelBaseTransform = GetModelBaseTransform(); leapState = LeapState.Burrow; } public override void FixedUpdate() { base.FixedUpdate(); switch (leapState) { case LeapState.Burrow: if ((bool)modelBaseTransform) { if (modelBaseTransform.position.y >= base.transform.position.y - diveDepth) { velocity = UnityEngine.Vector3.MoveTowards(velocity, idealDiveVelocity, leapAcceleration * GetDeltaTime()); modelBaseTransform.position += velocity * GetDeltaTime(); } else { leapState = LeapState.Ascend; } } break; case LeapState.Ascend: if ((bool)modelBaseTransform) { if (modelBaseTransform.position.y <= base.transform.position.y) { velocity = UnityEngine.Vector3.MoveTowards(velocity, idealLeapVelocity, leapAcceleration * GetDeltaTime()); modelBaseTransform.position += velocity * GetDeltaTime(); } else { leapState = LeapState.Fall; } } break; case LeapState.Fall: if ((bool)modelBaseTransform) { if (modelBaseTransform.position.y >= base.transform.position.y - diveDepth) { velocity += Physics.gravity * GetDeltaTime(); modelBaseTransform.position += velocity * GetDeltaTime(); } else { leapState = LeapState.Resurface; } } break; case LeapState.Resurface: velocity = UnityEngine.Vector3.zero; modelBaseTransform.position = UnityEngine.Vector3.MoveTowards(modelBaseTransform.position, base.transform.position, resurfaceSpeed * GetDeltaTime()); if (modelBaseTransform.position.y >= base.transform.position.y) { outer.SetNextStateToMain(); } break; } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SteerAtTarget : BaseSkillState { private WormBodyPositionsDriver wormBodyPositionsDriver; private UnityEngine.Vector3? targetPosition; private static readonly float fastTurnThreshold = Mathf.Cos(MathF.PI / 6f); private static readonly float slowTurnThreshold = Mathf.Cos(MathF.PI / 3f); private static readonly float fastTurnRate = 180f; private static readonly float slowTurnRate = 90f; public override void OnEnter() { base.OnEnter(); wormBodyPositionsDriver = GetComponent(); if (base.isAuthority) { Ray aimRay = GetAimRay(); if (Util.CharacterRaycast(base.gameObject, aimRay, out var hitInfo, 1000f, LayerIndex.CommonMasks.bullet, QueryTriggerInteraction.UseGlobal)) { targetPosition = hitInfo.point; } } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && targetPosition.HasValue) { UnityEngine.Vector3 vector = targetPosition.Value - wormBodyPositionsDriver.chaserPosition; if (vector != UnityEngine.Vector3.zero && wormBodyPositionsDriver.chaserVelocity != UnityEngine.Vector3.zero) { UnityEngine.Vector3 normalized = vector.normalized; UnityEngine.Vector3 normalized2 = wormBodyPositionsDriver.chaserVelocity.normalized; float num = UnityEngine.Vector3.Dot(normalized, normalized2); float num2 = 0f; if (num >= slowTurnThreshold) { num2 = slowTurnRate; if (num >= fastTurnThreshold) { num2 = fastTurnRate; } } if (num2 != 0f) { wormBodyPositionsDriver.chaserVelocity = UnityEngine.Vector3.RotateTowards(wormBodyPositionsDriver.chaserVelocity, vector, MathF.PI / 180f * num2 * GetDeltaTime(), 0f); } } } if (base.isAuthority && !IsKeyDownAuthority()) { outer.SetNextStateToMain(); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); if (targetPosition.HasValue) { writer.Write(value: true); writer.Write(targetPosition.Value); } else { writer.Write(value: false); } } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); if (reader.ReadBoolean()) { targetPosition = reader.ReadVector3(); } else { targetPosition = null; } } } public class SwitchStance : BaseState { public static float leapingDuration = 10f; public static float groundStanceSpring = 3f; public static float groundStanceDamping = 3f; public static float groundStanceSpeedMultiplier = 1.5f; public static float leapStanceSpring = 3f; public static float leapStanceDamping = 1f; public static float leapStanceSpeedMultiplier = 1f; public override void OnEnter() { base.OnEnter(); SetStanceParameters(leaping: true); } public override void OnExit() { base.OnExit(); SetStanceParameters(leaping: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= leapingDuration) { outer.SetNextStateToMain(); } } private void SetStanceParameters(bool leaping) { if (!NetworkServer.active) { return; } WormBodyPositions2 component = GetComponent(); WormBodyPositionsDriver component2 = GetComponent(); if ((bool)component) { if (leaping) { component2.ySpringConstant = leapStanceSpring; component2.yDamperConstant = leapStanceDamping; component.speedMultiplier = leapStanceSpeedMultiplier; component2.allowShoving = false; } else { component2.ySpringConstant = groundStanceSpring; component2.yDamperConstant = groundStanceDamping; component.speedMultiplier = groundStanceSpeedMultiplier; component2.allowShoving = true; } component.shouldFireMeatballsOnImpact = leaping; } } } } namespace EntityStates.ImpBossMonster { public class BlinkState : BaseState { private Transform modelTransform; [SerializeField] public bool disappearWhileBlinking; [SerializeField] public GameObject blinkPrefab; [SerializeField] public GameObject blinkDestinationPrefab; [SerializeField] public Material destealthMaterial; private UnityEngine.Vector3 blinkDestination = UnityEngine.Vector3.zero; private UnityEngine.Vector3 blinkStart = UnityEngine.Vector3.zero; [SerializeField] public float duration = 0.3f; [SerializeField] public float exitDuration; [SerializeField] public float destinationAlertDuration; [SerializeField] public float blinkDistance = 25f; [SerializeField] public string beginSoundString; [SerializeField] public string endSoundString; [SerializeField] public float blastAttackRadius; [SerializeField] public float blastAttackDamageCoefficient; [SerializeField] public float blastAttackForce; [SerializeField] public float blastAttackProcCoefficient; private Animator animator; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private ChildLocator childLocator; private GameObject blinkDestinationInstance; private bool isExiting; private bool hasBlinked; private BullseyeSearch search; private BlastAttack attack; private EffectData _effectData; private EffectManagerHelper _emh_blinkDestinationInstance; private int originalLayer; private static int BlinkEndStateHash = Animator.StringToHash("BlinkEnd"); private static int BlinkEndParamHash = Animator.StringToHash("BlinkEnd.playbackRate"); public override void Reset() { base.Reset(); modelTransform = null; blinkDestination = UnityEngine.Vector3.zero; blinkStart = UnityEngine.Vector3.zero; animator = null; characterModel = null; hurtboxGroup = null; childLocator = null; blinkDestinationInstance = null; isExiting = false; hasBlinked = false; if (search != null) { search.Reset(); } if (attack != null) { attack.Reset(); } if (_effectData != null) { _effectData.Reset(); } _emh_blinkDestinationInstance = null; } public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); if ((bool)modelTransform) { animator = modelTransform.GetComponent(); characterModel = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); childLocator = modelTransform.GetComponent(); } if (disappearWhileBlinking) { if ((bool)characterModel) { characterModel.invisibilityCount++; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)childLocator) { childLocator.FindChild("DustCenter").gameObject.SetActive(value: false); } } if ((bool)base.characterMotor) { base.characterMotor.enabled = false; } originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal; base.characterMotor.Motor.RebuildCollidableLayers(); CalculateBlinkDestination(); CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); } private void CalculateBlinkDestination() { UnityEngine.Vector3 vector = UnityEngine.Vector3.zero; Ray aimRay = GetAimRay(); if (search == null) { search = new BullseyeSearch(); } search.searchOrigin = aimRay.origin; search.searchDirection = aimRay.direction; search.maxDistanceFilter = blinkDistance; search.teamMaskFilter = TeamMask.allButNeutral; search.filterByLoS = false; search.teamMaskFilter.RemoveTeam(TeamComponent.GetObjectTeam(base.gameObject)); search.sortMode = BullseyeSearch.SortMode.Angle; search.RefreshCandidates(); HurtBox hurtBox = search.GetResults().FirstOrDefault(); if ((bool)hurtBox) { vector = hurtBox.transform.position - base.transform.position; } blinkDestination = base.transform.position; blinkStart = base.transform.position; NodeGraph groundNodes = SceneInfo.instance.groundNodes; NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(base.transform.position + vector, base.characterBody.hullClassification); groundNodes.GetNodePosition(nodeIndex, out blinkDestination); blinkDestination += base.transform.position - base.characterBody.footPosition; base.characterDirection.forward = vector; } private void CreateBlinkEffect(UnityEngine.Vector3 origin) { if ((bool)blinkPrefab) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.rotation = Util.QuaternionSafeLookRotation(blinkDestination - blinkStart); _effectData.origin = origin; EffectManager.SpawnEffect(blinkPrefab, _effectData, transmit: false); } } private void SetPosition(UnityEngine.Vector3 newPosition) { if ((bool)base.characterMotor) { base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.characterMotor) { base.characterMotor.velocity = UnityEngine.Vector3.zero; } if (!hasBlinked) { SetPosition(UnityEngine.Vector3.Lerp(blinkStart, blinkDestination, base.fixedAge / duration)); } if (base.fixedAge >= duration - destinationAlertDuration && !hasBlinked) { hasBlinked = true; if ((bool)blinkDestinationPrefab) { if (!EffectManager.ShouldUsePooledEffect(blinkDestinationPrefab)) { blinkDestinationInstance = UnityEngine.Object.Instantiate(blinkDestinationPrefab, blinkDestination, UnityEngine.Quaternion.identity); } else { _emh_blinkDestinationInstance = EffectManager.GetAndActivatePooledEffect(blinkDestinationPrefab, blinkDestination, UnityEngine.Quaternion.identity); blinkDestinationInstance = _emh_blinkDestinationInstance.gameObject; } blinkDestinationInstance.GetComponent().newDuration = destinationAlertDuration; } SetPosition(blinkDestination); } if (base.fixedAge >= duration) { ExitCleanup(); } if (base.fixedAge >= duration + exitDuration && base.isAuthority) { outer.SetNextStateToMain(); } } private void ExitCleanup() { if (isExiting) { return; } isExiting = true; base.gameObject.layer = originalLayer; base.characterMotor.Motor.RebuildCollidableLayers(); Util.PlaySound(endSoundString, base.gameObject); CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); modelTransform = GetModelTransform(); if (blastAttackDamageCoefficient > 0f) { if (attack == null) { attack = new BlastAttack(); } attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); attack.baseDamage = damageStat * blastAttackDamageCoefficient; attack.baseForce = blastAttackForce; attack.position = blinkDestination; attack.radius = blastAttackRadius; attack.falloffModel = BlastAttack.FalloffModel.Linear; attack.attackerFiltering = AttackerFiltering.NeverHitSelf; attack.Fire(); } if (disappearWhileBlinking) { if ((bool)modelTransform && (bool)destealthMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(animator.gameObject); temporaryOverlayInstance.duration = 1f; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = destealthMaterial; temporaryOverlayInstance.inspectorCharacterModel = animator.gameObject.GetComponent(); temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } if ((bool)characterModel) { characterModel.invisibilityCount--; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)childLocator) { childLocator.FindChild("DustCenter").gameObject.SetActive(value: true); } PlayAnimation("Gesture, Additive", BlinkEndStateHash, BlinkEndParamHash, exitDuration); } if ((bool)blinkDestinationInstance) { if (_emh_blinkDestinationInstance != null && _emh_blinkDestinationInstance.OwningPool != null) { _emh_blinkDestinationInstance.OwningPool.ReturnObject(_emh_blinkDestinationInstance); } else { EntityState.Destroy(blinkDestinationInstance); } _emh_blinkDestinationInstance = null; blinkDestinationInstance = null; } if ((bool)base.characterMotor) { base.characterMotor.enabled = true; } } public override void OnExit() { base.OnExit(); ExitCleanup(); } } public class DeathState : GenericCharacterDeath { public static GameObject initialEffect; public static GameObject deathEffect; private static float duration = 3.3166666f; private float stopwatch; private Animator animator; private bool hasPlayedDeathEffect; private bool attemptedDeathBehavior; private EffectManagerHelper _emh_initialEffect; private MaterialPropertyBlock block; private static int DeathStateHash = Animator.StringToHash("Death"); private static int DeathEffectParamHash = Animator.StringToHash("DeathEffect"); public override void Reset() { base.Reset(); stopwatch = 0f; animator = null; hasPlayedDeathEffect = false; attemptedDeathBehavior = false; _emh_initialEffect = null; if (block == null) { block = new MaterialPropertyBlock(); } } public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); if ((bool)base.characterMotor) { base.characterMotor.enabled = false; } if ((bool)base.modelLocator) { Transform modelTransform = base.modelLocator.modelTransform; ChildLocator component = modelTransform.GetComponent(); CharacterModel component2 = modelTransform.GetComponent(); if ((bool)component) { component.FindChild("DustCenter").gameObject.SetActive(value: false); if ((bool)initialEffect) { EffectManager.SimpleMuzzleFlash(initialEffect, base.gameObject, "DeathCenter", transmit: false); if (EffectManager.ShouldUsePooledEffect(initialEffect)) { _emh_initialEffect = EffectManager.LastSpawnedEffect; } } } if ((bool)component2) { for (int i = 0; i < component2.baseRendererInfos.Length; i++) { component2.baseRendererInfos[i].ignoreOverlays = true; } } } PlayAnimation("Fullbody Override", DeathStateHash); } public override void FixedUpdate() { if ((bool)animator) { stopwatch += GetDeltaTime(); if (!hasPlayedDeathEffect && animator.GetFloat(DeathEffectParamHash) > 0.5f) { hasPlayedDeathEffect = true; EffectManager.SimpleMuzzleFlash(deathEffect, base.gameObject, "DeathCenter", transmit: false); } if (stopwatch >= duration) { AttemptDeathBehavior(); } } } private void AttemptDeathBehavior() { if (attemptedDeathBehavior) { return; } attemptedDeathBehavior = true; if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if (NetworkServer.active) { if (_emh_initialEffect != null && _emh_initialEffect.OwningPool != null) { _emh_initialEffect.OwningPool.ReturnObject(_emh_initialEffect); _emh_initialEffect = null; } EntityState.Destroy(base.gameObject); } } public override void OnExit() { if (!outer.destroying) { AttemptDeathBehavior(); } base.OnExit(); } } public class FireVoidspikes : BaseState { public static float baseDuration = 3.5f; public static float damageCoefficient = 4f; public static float procCoefficient; public static float selfForce; public static float forceMagnitude = 16f; public static GameObject hitEffectPrefab; public static GameObject swipeEffectPrefab; public static string enterSoundString; public static string attackSoundString; public static float walkSpeedPenaltyCoefficient; public static int projectileCount; public static float projectileYawSpread; public static float projectileDamageCoefficient; public static float projectileSpeed; public static float projectileSpeedPerProjectile; public static GameObject projectilePrefab; private OverlapAttack attack; private Animator modelAnimator; private float duration; private int slashCount; private Transform modelTransform; private int chosenAnim = -1; private static int FireVoidspikesLStateHash = Animator.StringToHash("FireVoidspikesL"); private static int FireVoidspikesRStateHash = Animator.StringToHash("FireVoidspikesR"); private static int FireVoidspikesParamHash = Animator.StringToHash("FireVoidspikes.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedPenaltyCoefficient; attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = GetTeam(); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); attack.procCoefficient = procCoefficient; attack.damageType = DamageType.BleedOnHit; Util.PlaySound(enterSoundString, base.gameObject); if (base.isAuthority) { chosenAnim = ((!Util.CheckRoll(50f)) ? 1 : 0); } if ((bool)modelAnimator) { int animationStateHash = ((chosenAnim == 1) ? FireVoidspikesLStateHash : FireVoidspikesRStateHash); PlayAnimation("Gesture, Additive", animationStateHash, FireVoidspikesParamHash, duration); PlayAnimation("Gesture, Override", animationStateHash, FireVoidspikesParamHash, duration); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration + 3f); } } public override void OnExit() { if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = 1f; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)modelAnimator && slashCount <= 0) { if (modelAnimator.GetFloat("HandR.hitBoxActive") > 0.1f) { FireSpikeFan(GetAimRay(), "FireVoidspikesR", "HandR"); } if (modelAnimator.GetFloat("HandL.hitBoxActive") > 0.1f) { FireSpikeFan(GetAimRay(), "FireVoidspikesL", "HandL"); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireSpikeFan(Ray aimRay, string muzzleName, string hitBoxGroupName) { Util.PlaySound(attackSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(swipeEffectPrefab, base.gameObject, muzzleName, transmit: false); slashCount++; if (base.isAuthority) { UnityEngine.Vector3 forward = base.characterDirection.forward; if ((bool)modelTransform) { attack.hitBoxGroup = FindHitBoxGroup(hitBoxGroupName); attack.forceVector = forward * forceMagnitude; attack.Fire(); } if ((bool)base.characterMotor) { base.characterMotor.ApplyForce(forward * selfForce, alwaysApply: true); } for (int i = 0; i < projectileCount; i++) { FireSpikeAuthority(aimRay, 0f, ((float)projectileCount / 2f - (float)i) * projectileYawSpread, projectileSpeed + projectileSpeedPerProjectile * (float)i); } } } private void FireSpikeAuthority(Ray aimRay, float bonusPitch, float bonusYaw, float speed) { UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw, bonusPitch); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * projectileDamageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speed); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((char)chosenAnim); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); chosenAnim = reader.ReadChar(); } } public class GroundPound : BaseState { private float stopwatch; public static float baseDuration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float blastAttackRadius; private BlastAttack attack; public static string initialAttackSoundString; public static GameObject chargeEffectPrefab; public static GameObject slamEffectPrefab; public static GameObject hitEffectPrefab; public static GameObject swipeEffectPrefab; private Animator modelAnimator; private Transform modelTransform; private bool hasAttacked; private float duration; private ChildLocator childLocator; private int attackCount; public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); Util.PlaySound(initialAttackSoundString, base.gameObject); attack = new BlastAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); attack.baseDamage = damageStat * damageCoefficient; attack.baseForce = forceMagnitude; attack.radius = blastAttackRadius; attack.falloffModel = BlastAttack.FalloffModel.SweetSpot; attack.attackerFiltering = AttackerFiltering.NeverHitSelf; duration = baseDuration / attackSpeedStat; PlayCrossfade("Fullbody Override", "GroundPound", "GroundPound.playbackRate", duration, 0.2f); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration + 3f); } if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if ((bool)modelAnimator) { if (modelAnimator.GetFloat("GroundPound.hitBoxActive") > 0.5f) { if (!hasAttacked) { if (NetworkServer.active) { attack.position = childLocator.FindChild("GroundPoundCenter").transform.position; attack.Fire(); } if (base.isAuthority) { EffectManager.SimpleMuzzleFlash(slamEffectPrefab, base.gameObject, "GroundPoundCenter", transmit: true); } EffectManager.SimpleMuzzleFlash(swipeEffectPrefab, base.gameObject, (attackCount % 2 == 0) ? "FireVoidspikesL" : "FireVoidspikesR", transmit: true); attackCount++; hasAttacked = true; } } else { hasAttacked = false; } } if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : BaseState { private float stopwatch; public static float duration = 4f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; public static Material destealthMaterial; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); Animator modelAnimator = GetModelAnimator(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); if ((bool)spawnEffectPrefab) { EffectData effectData = new EffectData(); effectData.origin = base.transform.position; EffectManager.SpawnEffect(spawnEffectPrefab, effectData, transmit: false); } if ((bool)destealthMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelAnimator.gameObject); temporaryOverlayInstance.duration = 1f; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = destealthMaterial; temporaryOverlayInstance.inspectorCharacterModel = modelAnimator.gameObject.GetComponent(); temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.ImpMonster { public class Backstab : BaseState { public static float baseDuration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float radius = 3f; public static GameObject hitEffectPrefab; public static GameObject biteEffectPrefab; private OverlapAttack attack; private Animator modelAnimator; private float duration; private bool hasBit; private static int BackstabStateHash = Animator.StringToHash("Backstab"); private static int BackstabParamHash = Animator.StringToHash("Backstab.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Backstab"); } if ((bool)modelAnimator) { PlayAnimation("Gesture", BackstabStateHash, BackstabParamHash, duration); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Bite.hitBoxActive") > 0.1f) { if (!hasBit) { EffectManager.SimpleMuzzleFlash(biteEffectPrefab, base.gameObject, "MuzzleMouth", transmit: true); hasBit = true; } attack.forceVector = base.transform.forward * forceMagnitude; attack.Fire(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class BlinkState : BaseState { private Transform modelTransform; public static GameObject blinkPrefab; public static Material destealthMaterial; private float stopwatch; private UnityEngine.Vector3 blinkDestination = UnityEngine.Vector3.zero; private UnityEngine.Vector3 blinkStart = UnityEngine.Vector3.zero; public static float duration = 0.3f; public static float blinkDistance = 25f; public static string beginSoundString; public static string endSoundString; private Animator animator; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private static int BlinkEndStateHash = Animator.StringToHash("BlinkEnd"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); if ((bool)modelTransform) { animator = modelTransform.GetComponent(); characterModel = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); } if ((bool)characterModel) { characterModel.invisibilityCount++; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)base.characterMotor) { base.characterMotor.enabled = false; } UnityEngine.Vector3 vector = base.inputBank.moveVector * blinkDistance; blinkDestination = base.transform.position; blinkStart = base.transform.position; NodeGraph groundNodes = SceneInfo.instance.groundNodes; NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(base.transform.position + vector, base.characterBody.hullClassification); groundNodes.GetNodePosition(nodeIndex, out blinkDestination); blinkDestination += base.transform.position - base.characterBody.footPosition; CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); } private void CreateBlinkEffect(UnityEngine.Vector3 origin) { EffectData effectData = new EffectData(); effectData.rotation = Util.QuaternionSafeLookRotation(blinkDestination - blinkStart); effectData.origin = origin; EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false); } private void SetPosition(UnityEngine.Vector3 newPosition) { if ((bool)base.characterMotor) { base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if ((bool)base.characterMotor && (bool)base.characterDirection) { base.characterMotor.velocity = UnityEngine.Vector3.zero; } SetPosition(UnityEngine.Vector3.Lerp(blinkStart, blinkDestination, stopwatch / duration)); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { Util.PlaySound(endSoundString, base.gameObject); CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); modelTransform = GetModelTransform(); if ((bool)modelTransform && (bool)destealthMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(animator.gameObject); temporaryOverlayInstance.duration = 1f; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = destealthMaterial; temporaryOverlayInstance.inspectorCharacterModel = animator.gameObject.GetComponent(); temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } if ((bool)characterModel) { characterModel.invisibilityCount--; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)base.characterMotor) { base.characterMotor.enabled = true; } PlayAnimation("Gesture, Additive", BlinkEndStateHash); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ChargeSpines : BaseState { public static float baseDuration = 1f; public static GameObject effectPrefab; private float duration; private GameObject chargeEffect; private EffectManagerHelper _emh_chargeEffect; private static int ChargeSpinesStateHash = Animator.StringToHash("ChargeSpines"); private static int ChargeSpinesParamHash = Animator.StringToHash("ChargeSpines.playbackRate"); public override void Reset() { base.Reset(); duration = 0f; chargeEffect = null; _emh_chargeEffect = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleMouth"); if ((bool)transform && (bool)effectPrefab) { if (!EffectManager.ShouldUsePooledEffect(effectPrefab)) { chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation); chargeEffect = _emh_chargeEffect.gameObject; } chargeEffect.transform.parent = transform; } } } PlayAnimation("Gesture", ChargeSpinesStateHash, ChargeSpinesParamHash, duration); } public override void OnExit() { base.OnExit(); if ((bool)chargeEffect) { if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null) { _emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect); } else { EntityState.Destroy(chargeEffect); } _emh_chargeEffect = null; chargeEffect = null; } } public override void Update() { base.Update(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireSpines nextState = new FireSpines(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class DeathState : GenericCharacterDeath { public static GameObject initialEffect; public static GameObject deathEffect; private static float duration = 1.333f; private float stopwatch; private Animator animator; private bool hasPlayedDeathEffect; public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); if ((bool)base.characterMotor) { base.characterMotor.enabled = false; } if ((bool)base.modelLocator && (bool)base.modelLocator.modelTransform.GetComponent() && (bool)initialEffect) { EffectManager.SimpleMuzzleFlash(initialEffect, base.gameObject, "Base", transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)animator) { stopwatch += GetDeltaTime(); if (!hasPlayedDeathEffect && animator.GetFloat("DeathEffect") > 0.5f) { hasPlayedDeathEffect = true; EffectManager.SimpleMuzzleFlash(deathEffect, base.gameObject, "Center", transmit: false); } if (stopwatch >= duration) { EntityState.Destroy(base.gameObject); } } } } public class DoubleSlash : BaseState { public static float baseDuration = 3.5f; public static float damageCoefficient = 4f; public static float procCoefficient; public static float selfForce; public static float forceMagnitude = 16f; public static GameObject hitEffectPrefab; public static GameObject swipeEffectPrefab; public static string enterSoundString; public static string slashSoundString; public static float walkSpeedPenaltyCoefficient; private OverlapAttack attack; private Animator modelAnimator; private float duration; private int slashCount; private Transform modelTransform; private static int DoubleSlashStateHash = Animator.StringToHash("DoubleSlash"); private static int DoubleSlashParamHash = Animator.StringToHash("DoubleSlash.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedPenaltyCoefficient; attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); attack.procCoefficient = procCoefficient; attack.damageType = DamageType.BleedOnHit; Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); if ((bool)modelAnimator) { PlayAnimation("Gesture, Additive", DoubleSlashStateHash, DoubleSlashParamHash, duration); PlayAnimation("Gesture, Override", DoubleSlashStateHash, DoubleSlashParamHash, duration); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration + 2f); } } public override void OnExit() { base.characterMotor.walkSpeedPenaltyCoefficient = 1f; base.OnExit(); } private void HandleSlash(string animatorParamName, string muzzleName, string hitBoxGroupName) { if (!(modelAnimator.GetFloat(animatorParamName) > 0.1f)) { return; } Util.PlaySound(slashSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(swipeEffectPrefab, base.gameObject, muzzleName, transmit: true); slashCount++; if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == hitBoxGroupName); } if ((bool)base.healthComponent) { base.healthComponent.TakeDamageForce(base.characterDirection.forward * selfForce, alwaysApply: true); } attack.ResetIgnoredHealthComponents(); if ((bool)base.characterDirection) { attack.forceVector = base.characterDirection.forward * forceMagnitude; } attack.Fire(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)modelAnimator) { switch (slashCount) { case 0: HandleSlash("HandR.hitBoxActive", "SwipeRight", "HandR"); break; case 1: HandleSlash("HandL.hitBoxActive", "SwipeLeft", "HandL"); break; } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireSpines : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static float baseDuration = 2f; public static float durationBetweenThrows = 0.1f; public static int spineCountMax = 3; public static float damageCoefficient = 1.2f; public static float force = 20f; private int spineCount; private float spineTimer; private float duration; private static int FireSpinesStateHash = Animator.StringToHash("FireSpines"); private static int FireSpinesParamHash = Animator.StringToHash("FireSpines.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture", FireSpinesStateHash, FireSpinesParamHash, duration); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); spineTimer += GetDeltaTime(); if (spineTimer >= durationBetweenThrows / attackSpeedStat && spineCount < spineCountMax) { spineCount++; Ray aimRay = GetAimRay(); string muzzleName = "MuzzleMouth"; spineTimer -= durationBetweenThrows / attackSpeedStat; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class SpawnState : BaseState { private float stopwatch; public static float duration = 4f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); if ((bool)spawnEffectPrefab) { EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "Base", transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.ImpMonster.Weapon { public class CloakPermanent : BaseState { public override void OnEnter() { base.OnEnter(); if ((bool)base.characterBody && NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.Cloak); } } public override void OnExit() { if ((bool)base.characterBody && NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.Huntress { public class BeginArrowSnipe : BaseBeginArrowBarrage { protected override EntityState InstantiateNextState() { return new AimArrowSnipe(); } } public class AimArrowSnipe : BaseArrowBarrage { public static SkillDef primarySkillDef; public static GameObject crosshairOverridePrefab; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private GenericSkill primarySkillSlot; private AimAnimator modelAimAnimator; public override void OnEnter() { base.OnEnter(); modelAimAnimator = GetModelTransform().GetComponent(); if ((bool)modelAimAnimator) { modelAimAnimator.enabled = true; } primarySkillSlot = (base.skillLocator ? base.skillLocator.primary : null); if ((bool)primarySkillSlot) { primarySkillSlot.SetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual); } PlayCrossfade("Body", "ArrowBarrageLoop", 0.1f); if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } } protected override void HandlePrimaryAttack() { if ((bool)primarySkillSlot) { primarySkillSlot.ExecuteIfReady(); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } if (!primarySkillSlot || primarySkillSlot.stock == 0) { outer.SetNextStateToMain(); } } public override void OnExit() { if ((bool)primarySkillSlot) { primarySkillSlot.UnsetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual); } crosshairOverrideRequest?.Dispose(); base.OnExit(); } } public class ArrowRain : BaseArrowBarrage { public static float arrowRainRadius = 0f; public static float damageCoefficient; public static GameObject projectilePrefab; public static GameObject areaIndicatorPrefab; public static GameObject muzzleFlashEffect; private GameObject areaIndicatorInstance; private bool shouldFireArrowRain; private EffectManagerHelper _emh_areaIndicatorInstance; private UnityEngine.Vector3 _cachedAreaIndicatorScale = UnityEngine.Vector3.one; private static int LoopArrowRainStateHash = Animator.StringToHash("LoopArrowRain"); public override void Reset() { base.Reset(); areaIndicatorInstance = null; shouldFireArrowRain = false; _emh_areaIndicatorInstance = null; } public override void OnEnter() { base.OnEnter(); PlayAnimation("FullBody, Override", LoopArrowRainStateHash); if ((bool)areaIndicatorPrefab) { if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab)) { areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab); } else { _emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity); areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject; } if (areaIndicatorInstance != null) { _cachedAreaIndicatorScale.x = arrowRainRadius; _cachedAreaIndicatorScale.y = arrowRainRadius; _cachedAreaIndicatorScale.z = arrowRainRadius; areaIndicatorInstance.transform.localScale = _cachedAreaIndicatorScale; } } } private void UpdateAreaIndicator() { if ((bool)areaIndicatorInstance) { float maxDistance = 1000f; if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask)) { areaIndicatorInstance.transform.position = hitInfo.point; areaIndicatorInstance.transform.up = hitInfo.normal; } } } public override void Update() { base.Update(); UpdateAreaIndicator(); } protected override void HandlePrimaryAttack() { base.HandlePrimaryAttack(); shouldFireArrowRain = true; outer.SetNextStateToMain(); } protected void DoFireArrowRain() { EffectManager.SimpleMuzzleFlash(muzzleFlashEffect, base.gameObject, "Muzzle", transmit: false); if ((bool)areaIndicatorInstance && shouldFireArrowRain) { ProjectileManager.instance.FireProjectile(projectilePrefab, areaIndicatorInstance.transform.position, areaIndicatorInstance.transform.rotation, base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { if (shouldFireArrowRain && !outer.destroying) { DoFireArrowRain(); } if ((bool)areaIndicatorInstance) { if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null) { _emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance); } else { EntityState.Destroy(areaIndicatorInstance.gameObject); } areaIndicatorInstance = null; _emh_areaIndicatorInstance = null; } base.OnExit(); } } public class BaseArrowBarrage : BaseState { [SerializeField] public float maxDuration; [SerializeField] public string beginLoopSoundString; [SerializeField] public string endLoopSoundString; [SerializeField] public string fireSoundString; private HuntressTracker huntressTracker; private CameraTargetParams.AimRequest aimRequest; private static int FireArrowRainStateHash = Animator.StringToHash("FireArrowRain"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginLoopSoundString, base.gameObject); huntressTracker = GetComponent(); if ((bool)huntressTracker) { huntressTracker.enabled = false; } if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.characterMotor) { base.characterMotor.velocity = UnityEngine.Vector3.zero; } if (base.isAuthority && (bool)base.inputBank) { if ((bool)base.skillLocator && base.skillLocator.utility.IsReady() && base.inputBank.skill3.justPressed) { outer.SetNextStateToMain(); } else if (base.fixedAge >= maxDuration || base.inputBank.skill1.justPressed || base.inputBank.skill4.justPressed) { HandlePrimaryAttack(); } } } protected virtual void HandlePrimaryAttack() { } public override void OnExit() { PlayAnimation("FullBody, Override", FireArrowRainStateHash); Util.PlaySound(endLoopSoundString, base.gameObject); Util.PlaySound(fireSoundString, base.gameObject); aimRequest?.Dispose(); if ((bool)huntressTracker) { huntressTracker.enabled = true; } base.OnExit(); } } public class BackflipState : BaseState { public static float duration = 0.9f; public static float initialSpeedCoefficient; public static float finalSpeedCoefficient; public static string dodgeSoundString; public static float dodgeFOV; public static float orbDamageCoefficient; public static float orbRange; public static int orbCountMax; public static float orbPrefireDuration; public static float orbFrequency; public static float orbProcCoefficient; public static string muzzleString; public static float smallHopStrength; public static GameObject muzzleflashEffectPrefab; private ChildLocator childLocator; private float stopwatch; private float orbStopwatch; private UnityEngine.Vector3 forwardDirection; private Animator animator; private int orbCount; private static int BackflipStateHash = Animator.StringToHash("Backflip"); private static int BackflipParamHash = Animator.StringToHash("Backflip.playbackRate"); private static int FireSeekingArrowStateHash = Animator.StringToHash("FireSeekingArrow"); public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); base.characterMotor.velocity.y = Mathf.Max(base.characterMotor.velocity.y, 0f); animator = GetModelAnimator(); Util.PlaySound(dodgeSoundString, base.gameObject); orbStopwatch = 0f - orbPrefireDuration; if ((bool)base.characterMotor && smallHopStrength != 0f) { base.characterMotor.velocity.y = smallHopStrength; } if (base.isAuthority && (bool)base.inputBank) { forwardDirection = -UnityEngine.Vector3.ProjectOnPlane(base.inputBank.aimDirection, UnityEngine.Vector3.up); } base.characterDirection.moveVector = -forwardDirection; PlayAnimation("FullBody, Override", BackflipStateHash, BackflipParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); stopwatch += deltaTime; orbStopwatch += deltaTime; if ((bool)base.cameraTargetParams) { base.cameraTargetParams.fovOverride = Mathf.Lerp(dodgeFOV, 60f, stopwatch / duration); } if ((bool)base.characterMotor && (bool)base.characterDirection) { UnityEngine.Vector3 velocity = base.characterMotor.velocity; UnityEngine.Vector3 velocity2 = forwardDirection * (moveSpeedStat * Mathf.Lerp(initialSpeedCoefficient, finalSpeedCoefficient, stopwatch / duration)); base.characterMotor.velocity = velocity2; base.characterMotor.velocity.y = velocity.y; base.characterMotor.moveDirection = forwardDirection; } if (orbStopwatch >= 1f / orbFrequency / attackSpeedStat && orbCount < orbCountMax) { orbStopwatch -= 1f / orbFrequency / attackSpeedStat; FireOrbArrow(); } if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireOrbArrow() { if (NetworkServer.active) { orbCount++; HuntressArrowOrb huntressArrowOrb = new HuntressArrowOrb(); huntressArrowOrb.damageValue = base.characterBody.damage * orbDamageCoefficient; huntressArrowOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master); huntressArrowOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); huntressArrowOrb.attacker = base.gameObject; huntressArrowOrb.damageColorIndex = DamageColorIndex.Poison; huntressArrowOrb.procChainMask.AddProc(ProcType.HealOnHit); huntressArrowOrb.procCoefficient = orbProcCoefficient; Ray aimRay = GetAimRay(); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.maxDistanceFilter = orbRange; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; bullseyeSearch.teamMaskFilter.RemoveTeam(huntressArrowOrb.teamIndex); bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.RefreshCandidates(); List list = bullseyeSearch.GetResults().ToList(); HurtBox hurtBox = ((list.Count > 0) ? list[UnityEngine.Random.Range(0, list.Count)] : null); if ((bool)hurtBox) { Transform transform = childLocator.FindChild(muzzleString).transform; EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true); huntressArrowOrb.origin = transform.position; huntressArrowOrb.target = hurtBox; PlayAnimation("Gesture, Override", FireSeekingArrowStateHash); PlayAnimation("Gesture, Additive", FireSeekingArrowStateHash); OrbManager.instance.AddOrb(huntressArrowOrb); } } } public override void OnExit() { base.OnExit(); if ((bool)base.cameraTargetParams) { base.cameraTargetParams.fovOverride = -1f; } int layerIndex = animator.GetLayerIndex("Impact"); if (layerIndex >= 0) { animator.SetLayerWeight(layerIndex, 1.5f); animator.PlayInFixedTime("LightImpact", layerIndex, 0f); } } } public class BeginArrowRain : BaseBeginArrowBarrage { protected override EntityState InstantiateNextState() { return new ArrowRain(); } } public class BaseBeginArrowBarrage : BaseState { private Transform modelTransform; [SerializeField] public float basePrepDuration; [SerializeField] public float blinkDuration = 0.3f; [SerializeField] public float jumpCoefficient = 25f; public static GameObject blinkPrefab; public static string blinkSoundString; [SerializeField] public UnityEngine.Vector3 blinkVector; private UnityEngine.Vector3 worldBlinkVector; private float prepDuration; private bool beginBlink; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; protected CameraTargetParams.AimRequest aimRequest; private static int BeginArrowRainStateHash = Animator.StringToHash("BeginArrowRain"); private static int BeginArrowRainParamHash = Animator.StringToHash("BeginArrowRain.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(blinkSoundString, base.gameObject); modelTransform = GetModelTransform(); if ((bool)modelTransform) { characterModel = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); } prepDuration = basePrepDuration / attackSpeedStat; PlayAnimation("FullBody, Override", BeginArrowRainStateHash, BeginArrowRainParamHash, prepDuration); if ((bool)base.characterMotor) { base.characterMotor.velocity = UnityEngine.Vector3.zero; } if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } UnityEngine.Vector3 direction = GetAimRay().direction; direction.y = 0f; direction.Normalize(); UnityEngine.Vector3 up = UnityEngine.Vector3.up; worldBlinkVector = UnityEngine.Matrix4x4.TRS(base.transform.position, Util.QuaternionSafeLookRotation(direction, up), new UnityEngine.Vector3(1f, 1f, 1f)).MultiplyPoint3x4(blinkVector) - base.transform.position; worldBlinkVector.Normalize(); } private void CreateBlinkEffect(UnityEngine.Vector3 origin) { EffectData effectData = new EffectData(); effectData.rotation = Util.QuaternionSafeLookRotation(worldBlinkVector); effectData.origin = origin; EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= prepDuration && !beginBlink) { beginBlink = true; CreateBlinkEffect(base.transform.position); if ((bool)characterModel) { characterModel.invisibilityCount++; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } } if (beginBlink && (bool)base.characterMotor) { base.characterMotor.velocity = UnityEngine.Vector3.zero; base.characterMotor.rootMotion += worldBlinkVector * (base.characterBody.jumpPower * jumpCoefficient * GetDeltaTime()); } if (base.fixedAge >= blinkDuration + prepDuration && base.isAuthority) { outer.SetNextState(InstantiateNextState()); } } protected virtual EntityState InstantiateNextState() { return null; } public override void OnExit() { CreateBlinkEffect(base.transform.position); modelTransform = GetModelTransform(); if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = 0.6f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matHuntressFlashBright"); temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent()); TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance2.duration = 0.7f; temporaryOverlayInstance2.animateShaderAlpha = true; temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance2.destroyComponentOnEnd = true; temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load("Materials/matHuntressFlashExpanded"); temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent()); } if ((bool)characterModel) { characterModel.invisibilityCount--; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } aimRequest?.Dispose(); base.OnExit(); } } public class BlinkState : BaseState { private Transform modelTransform; public static GameObject blinkPrefab; private float stopwatch; private UnityEngine.Vector3 blinkVector = UnityEngine.Vector3.zero; [SerializeField] public float duration = 0.3f; [SerializeField] public float speedCoefficient = 25f; [SerializeField] public string beginSoundString; [SerializeField] public string endSoundString; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); if ((bool)modelTransform) { characterModel = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); } if ((bool)characterModel) { characterModel.invisibilityCount++; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } blinkVector = GetBlinkVector(); CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); } protected virtual UnityEngine.Vector3 GetBlinkVector() { return base.inputBank.aimDirection; } private void CreateBlinkEffect(UnityEngine.Vector3 origin) { EffectData effectData = new EffectData(); effectData.rotation = Util.QuaternionSafeLookRotation(blinkVector); effectData.origin = origin; EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if ((bool)base.characterMotor && (bool)base.characterDirection) { base.characterMotor.velocity = UnityEngine.Vector3.zero; base.characterMotor.rootMotion += blinkVector * (moveSpeedStat * speedCoefficient * GetDeltaTime()); } if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if (!outer.destroying) { Util.PlaySound(endSoundString, base.gameObject); CreateBlinkEffect(Util.GetCorePosition(base.gameObject)); modelTransform = GetModelTransform(); if ((bool)modelTransform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance.duration = 0.6f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matHuntressFlashBright"); temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent()); TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject); temporaryOverlayInstance2.duration = 0.7f; temporaryOverlayInstance2.animateShaderAlpha = true; temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance2.destroyComponentOnEnd = true; temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load("Materials/matHuntressFlashExpanded"); temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent()); } } if ((bool)characterModel) { characterModel.invisibilityCount--; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)base.characterMotor) { base.characterMotor.disableAirControlUntilCollision = false; } base.OnExit(); } } public class MiniBlinkState : BlinkState { protected override UnityEngine.Vector3 GetBlinkVector() { return ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized; } } } namespace EntityStates.Huntress.Weapon { public class FireArrowSnipe : GenericBulletBaseState { public float charge; public static float recoilAmplitude; private static int FireArrowSnipeStateHash = Animator.StringToHash("FireArrowSnipe"); private static int FireArrowSnipeParamHash = Animator.StringToHash("FireArrowSnipe.playbackRate"); protected override void ModifyBullet(BulletAttack bulletAttack) { base.ModifyBullet(bulletAttack); bulletAttack.falloffModel = BulletAttack.FalloffModel.None; _ = (bool)(base.skillLocator ? base.skillLocator.primary : null); } protected override void FireBullet(Ray aimRay) { base.FireBullet(aimRay); base.characterBody.SetSpreadBloom(0.2f, canOnlyIncreaseBloom: false); AddRecoil(-0.6f * recoilAmplitude, -0.8f * recoilAmplitude, -0.1f * recoilAmplitude, 0.1f * recoilAmplitude); PlayAnimation("Body", FireArrowSnipeStateHash, FireArrowSnipeParamHash, duration); base.healthComponent.TakeDamageForce(aimRay.direction * -400f, alwaysApply: true); } } } namespace EntityStates.Huntress.HuntressWeapon { public class ChargeArrow : BaseState { public static float baseTotalDuration; public static float baseMaxChargeTime; public static int maxCharges; public static GameObject chargeEffectPrefab; public static GameObject muzzleflashEffectPrefab; public static string chargeStockSoundString; public static string chargeLoopStartSoundString; public static string chargeLoopStopSoundString; public static float minBonusBloom; public static float maxBonusBloom; public static float minArrowDamageCoefficient; public static float maxArrowDamageCoefficient; public static float orbDamageCoefficient; public static float orbRange; public static float orbFrequency; public static float orbProcCoefficient; private float stopwatch; private GameObject chargeLeftInstance; private GameObject chargeRightInstance; private Animator animator; private int charge; private int lastCharge; private ChildLocator childLocator; private float totalDuration; private float maxChargeTime; private bool cachedSprinting; private float originalMinYaw; private float originalMaxYaw; private string muzzleString; private static int chargingArrowParamHash = Animator.StringToHash("chargingArrow"); private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty"); private static int FireSeekingArrowStateHash = Animator.StringToHash("FireSeekingArrow"); public override void OnEnter() { base.OnEnter(); totalDuration = baseTotalDuration / attackSpeedStat; maxChargeTime = baseMaxChargeTime / attackSpeedStat; muzzleString = "Muzzle"; Transform modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); animator = GetModelAnimator(); cachedSprinting = base.characterBody.isSprinting; if (!cachedSprinting) { animator.SetBool(chargingArrowParamHash, value: true); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(maxChargeTime + 1f); } } public override void OnExit() { base.OnExit(); animator.SetBool(chargingArrowParamHash, value: false); if (!cachedSprinting) { PlayAnimation("Gesture, Override", BufferEmptyStateHash); PlayAnimation("Gesture, Additive", BufferEmptyStateHash); } } private void FireOrbArrow() { if (NetworkServer.active) { HuntressArrowOrb huntressArrowOrb = new HuntressArrowOrb(); huntressArrowOrb.damageValue = base.characterBody.damage * orbDamageCoefficient; huntressArrowOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master); huntressArrowOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); huntressArrowOrb.attacker = base.gameObject; huntressArrowOrb.damageColorIndex = DamageColorIndex.Poison; huntressArrowOrb.procChainMask.AddProc(ProcType.HealOnHit); huntressArrowOrb.procCoefficient = orbProcCoefficient; Ray aimRay = GetAimRay(); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.maxDistanceFilter = orbRange; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; bullseyeSearch.teamMaskFilter.RemoveTeam(huntressArrowOrb.teamIndex); bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.RefreshCandidates(); List list = bullseyeSearch.GetResults().ToList(); HurtBox hurtBox = ((list.Count > 0) ? list[UnityEngine.Random.Range(0, list.Count)] : null); if ((bool)hurtBox) { Transform transform = childLocator.FindChild(muzzleString).transform; EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true); huntressArrowOrb.origin = transform.position; huntressArrowOrb.target = hurtBox; PlayAnimation("Gesture, Override", FireSeekingArrowStateHash); PlayAnimation("Gesture, Additive", FireSeekingArrowStateHash); OrbManager.instance.AddOrb(huntressArrowOrb); } } } public override void FixedUpdate() { base.FixedUpdate(); if (cachedSprinting != base.characterBody.isSprinting && base.isAuthority) { outer.SetNextStateToMain(); } else if (!cachedSprinting) { lastCharge = charge; stopwatch += GetDeltaTime(); charge = Mathf.Min((int)(stopwatch / maxChargeTime * (float)maxCharges), maxCharges); float damageCoefficient = Mathf.Lerp(minArrowDamageCoefficient, maxArrowDamageCoefficient, charge); if (lastCharge < charge && charge == maxCharges) { EffectManager.SimpleMuzzleFlash(chargeEffectPrefab, base.gameObject, muzzleString, transmit: false); } if ((stopwatch >= totalDuration || !base.inputBank || !base.inputBank.skill1.down) && base.isAuthority) { FireArrow fireArrow = new FireArrow(); fireArrow.damageCoefficient = damageCoefficient; outer.SetNextState(fireArrow); } } else { stopwatch += GetDeltaTime(); if (stopwatch >= 1f / orbFrequency / attackSpeedStat) { stopwatch -= 1f / orbFrequency / attackSpeedStat; FireOrbArrow(); } if ((!base.inputBank || !base.inputBank.skill1.down) && base.isAuthority) { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireArrow : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject projectilePrefab; public static int arrowCountMax = 1; public float damageCoefficient; public static float fireDuration = 1f; public static float baseDuration = 2f; public static float arcAngle = 5f; public static float recoilAmplitude = 1f; public static string attackSoundString; public static float spreadBloomValue = 0.3f; public static float smallHopStrength; private Ray aimRay; private Transform modelTransform; private float duration; private float fireTimer; private int grenadeCount; private static int fireArrowHash = Animator.StringToHash("FireArrow"); private static int fireArrowParamHash = Animator.StringToHash("FireArrow.playbackRate"); private void FireGrenade(string targetMuzzle) { Util.PlaySound(attackSoundString, base.gameObject); aimRay = GetAimRay(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { aimRay.origin = transform.position; } } } AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { float x = UnityEngine.Random.Range(0f, base.characterBody.spreadBloomAngle); float z = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 up = UnityEngine.Vector3.up; UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction); UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward); float y = vector.y; vector.y = 0f; float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle; UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelTransform = GetModelTransform(); if ((bool)base.characterMotor && smallHopStrength != 0f) { base.characterMotor.velocity.y = smallHopStrength; } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { fireTimer -= GetDeltaTime(); float num = fireDuration / attackSpeedStat / (float)arrowCountMax; if (fireTimer <= 0f && grenadeCount < arrowCountMax) { PlayAnimation("Gesture, Additive", fireArrowHash, fireArrowParamHash, duration - num); PlayAnimation("Gesture, Override", fireArrowHash, fireArrowParamHash, duration - num); FireGrenade("Muzzle"); fireTimer += num; grenadeCount++; } if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireArrowOld : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static float baseDuration = 2f; public static float damageCoefficient = 1.2f; public static float force = 20f; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Ray aimRay = GetAimRay(); StartAimMode(aimRay); string muzzleName = "Muzzle"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Gesture"); modelAnimator.SetFloat("FireArrow.playbackRate", attackSpeedStat); modelAnimator.PlayInFixedTime("FireArrow", layerIndex, 0f); muzzleName = "MuzzleRight"; modelAnimator.Update(0f); if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireGlaive : BaseState { public static GameObject projectilePrefab; public static float baseDuration = 2f; public static float damageCoefficient = 1.2f; public static float force = 20f; private float duration; private static int FireGlaiveStateHash = Animator.StringToHash("FireGlaive"); private static int FireGlaiveParamHash = Animator.StringToHash("FireGlaive.playbackRate"); public override void OnEnter() { base.OnEnter(); Ray aimRay = GetAimRay(); StartAimMode(aimRay); Transform modelTransform = GetModelTransform(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture", FireGlaiveStateHash, FireGlaiveParamHash, duration); UnityEngine.Vector3 position = aimRay.origin; UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(aimRay.direction); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("RightHand"); if ((bool)transform) { position = transform.position; } } } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, position, rotation, base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireSeekingArrow : BaseState { [SerializeField] public float orbDamageCoefficient; [SerializeField] public float orbProcCoefficient; [SerializeField] public string muzzleString; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public string attackSoundString; [SerializeField] public float baseDuration; [SerializeField] public int maxArrowCount; [SerializeField] public float baseArrowReloadDuration; private float duration; protected float arrowReloadDuration; private float arrowReloadTimer; protected bool isCrit; private int firedArrowCount; private HurtBox initialOrbTarget; private ChildLocator childLocator; private HuntressTracker huntressTracker; private Animator animator; private static int fireSeekingShotStateHash = Animator.StringToHash("FireSeekingShot"); private static int fireSeekingShotParamHash = Animator.StringToHash("FireSeekingShot.playbackRate"); public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); huntressTracker = GetComponent(); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); animator = modelTransform.GetComponent(); } Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); if ((bool)huntressTracker && base.isAuthority) { initialOrbTarget = huntressTracker.GetTrackingTarget(); } duration = baseDuration / attackSpeedStat; arrowReloadDuration = baseArrowReloadDuration / attackSpeedStat; if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration + 1f); } PlayCrossfade("Gesture, Override", fireSeekingShotStateHash, fireSeekingShotParamHash, duration, duration * 0.2f / attackSpeedStat); PlayCrossfade("Gesture, Additive", fireSeekingShotStateHash, fireSeekingShotParamHash, duration, duration * 0.2f / attackSpeedStat); isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master); } public override void OnExit() { base.OnExit(); FireOrbArrow(); } protected virtual GenericDamageOrb CreateArrowOrb() { return new HuntressArrowOrb(); } private void FireOrbArrow() { if (firedArrowCount < maxArrowCount && !(arrowReloadTimer > 0f) && NetworkServer.active) { firedArrowCount++; arrowReloadTimer = arrowReloadDuration; GenericDamageOrb genericDamageOrb = CreateArrowOrb(); genericDamageOrb.damageValue = base.characterBody.damage * orbDamageCoefficient; genericDamageOrb.isCrit = isCrit; genericDamageOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); genericDamageOrb.attacker = base.gameObject; genericDamageOrb.procCoefficient = orbProcCoefficient; HurtBox hurtBox = initialOrbTarget; if ((bool)hurtBox) { Transform transform = childLocator.FindChild(muzzleString); EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true); genericDamageOrb.origin = transform.position; genericDamageOrb.target = hurtBox; OrbManager.instance.AddOrb(genericDamageOrb); } } } public override void FixedUpdate() { base.FixedUpdate(); arrowReloadTimer -= GetDeltaTime(); if (animator.GetFloat("FireSeekingShot.fire") > 0f) { FireOrbArrow(); } if (base.fixedAge > duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } public override void OnSerialize(NetworkWriter writer) { writer.Write(HurtBoxReference.FromHurtBox(initialOrbTarget)); } public override void OnDeserialize(NetworkReader reader) { initialOrbTarget = reader.ReadHurtBoxReference().ResolveHurtBox(); } } public class FireFlurrySeekingArrow : FireSeekingArrow { public static GameObject critMuzzleflashEffectPrefab; public static int critMaxArrowCount; public static float critBaseArrowReloadDuration; public override void OnEnter() { base.OnEnter(); if (isCrit) { muzzleflashEffectPrefab = critMuzzleflashEffectPrefab; maxArrowCount = critMaxArrowCount; arrowReloadDuration = critBaseArrowReloadDuration / attackSpeedStat; } } protected override GenericDamageOrb CreateArrowOrb() { return new HuntressFlurryArrowOrb(); } } public class IdleTracking : BaseState { public static float maxTrackingDistance = 20f; public static float maxTrackingAngle = 20f; public static float orbDamageCoefficient; public static float orbProcCoefficient; public static string muzzleString; public static GameObject muzzleflashEffectPrefab; public static string attackSoundString; public static float fireFrequency; private float fireTimer; private Transform trackingIndicatorTransform; private HurtBox trackingTarget; private ChildLocator childLocator; private BullseyeSearch search; private GameObject TrackingIndicatorPrefab; private EffectManagerHelper _emh_trackingIndicator; private static int FireSeekingArrowStateHash = Animator.StringToHash("FireSeekingArrow"); public override void Reset() { base.Reset(); fireTimer = 0f; trackingIndicatorTransform = null; trackingTarget = null; childLocator = null; if (search != null) { search.Reset(); } _emh_trackingIndicator = null; } public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); } } protected void DestroyTrackingIndicator() { if ((bool)trackingIndicatorTransform) { if (_emh_trackingIndicator != null && _emh_trackingIndicator.OwningPool != null) { _emh_trackingIndicator.OwningPool.ReturnObject(_emh_trackingIndicator); } else { EntityState.Destroy(trackingIndicatorTransform.gameObject); } trackingIndicatorTransform = null; _emh_trackingIndicator = null; } } public override void OnExit() { DestroyTrackingIndicator(); base.OnExit(); } private void FireOrbArrow() { if (NetworkServer.active) { HuntressArrowOrb huntressArrowOrb = new HuntressArrowOrb(); huntressArrowOrb.damageValue = base.characterBody.damage * orbDamageCoefficient; huntressArrowOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master); huntressArrowOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); huntressArrowOrb.attacker = base.gameObject; huntressArrowOrb.damageColorIndex = DamageColorIndex.Poison; huntressArrowOrb.procChainMask.AddProc(ProcType.HealOnHit); huntressArrowOrb.procCoefficient = orbProcCoefficient; HurtBox hurtBox = trackingTarget; if ((bool)hurtBox) { Transform transform = childLocator.FindChild(muzzleString).transform; EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true); huntressArrowOrb.origin = transform.position; huntressArrowOrb.target = hurtBox; PlayAnimation("Gesture, Override", FireSeekingArrowStateHash); PlayAnimation("Gesture, Additive", FireSeekingArrowStateHash); Util.PlaySound(attackSoundString, base.gameObject); OrbManager.instance.AddOrb(huntressArrowOrb); } } } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } fireTimer -= GetDeltaTime(); if ((bool)base.characterBody) { float extraRaycastDistance = 0f; Ray ray = CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance); if (search == null) { search = new BullseyeSearch(); } search.searchOrigin = ray.origin; search.searchDirection = ray.direction; search.maxDistanceFilter = maxTrackingDistance + extraRaycastDistance; search.maxAngleFilter = maxTrackingAngle; search.teamMaskFilter = TeamMask.allButNeutral; search.teamMaskFilter.RemoveTeam(TeamComponent.GetObjectTeam(base.gameObject)); search.sortMode = BullseyeSearch.SortMode.DistanceAndAngle; search.RefreshCandidates(); trackingTarget = search.GetResults().FirstOrDefault(); } if ((bool)trackingTarget) { if (!trackingIndicatorTransform) { if (TrackingIndicatorPrefab == null) { TrackingIndicatorPrefab = LegacyResourcesAPI.Load("Prefabs/ShieldTransferIndicator"); } if (!EffectManager.ShouldUsePooledEffect(TrackingIndicatorPrefab)) { trackingIndicatorTransform = UnityEngine.Object.Instantiate(TrackingIndicatorPrefab, trackingTarget.transform.position, UnityEngine.Quaternion.identity).transform; } else { _emh_trackingIndicator = EffectManager.GetAndActivatePooledEffect(TrackingIndicatorPrefab, trackingTarget.transform.position, UnityEngine.Quaternion.identity); trackingIndicatorTransform = _emh_trackingIndicator.gameObject.transform; } } trackingIndicatorTransform.position = trackingTarget.transform.position; if ((bool)base.inputBank && base.inputBank.skill1.down && fireTimer <= 0f) { fireTimer = 1f / fireFrequency / attackSpeedStat; FireOrbArrow(); } } else { DestroyTrackingIndicator(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } } public class ThrowGlaive : BaseState { public static float baseDuration = 3f; public static GameObject chargePrefab; public static GameObject muzzleFlashPrefab; public static float smallHopStrength; public static float antigravityStrength; public static float damageCoefficient = 1.2f; public static float damageCoefficientPerBounce = 1.1f; public static float glaiveProcCoefficient; public static int maxBounceCount; public static float glaiveTravelSpeed; public static float glaiveBounceRange; public static string attackSoundString; private float duration; private float stopwatch; private Animator animator; private GameObject chargeEffect; private Transform modelTransform; private HuntressTracker huntressTracker; private ChildLocator childLocator; private bool hasTriedToThrowGlaive; private bool hasSuccessfullyThrownGlaive; private HurtBox initialOrbTarget; private EffectManagerHelper _emh_chargeEffect; private static int ThrowGlaiveStateHash = Animator.StringToHash("ThrowGlaive"); private static int ThrowGlaiveParamHash = Animator.StringToHash("ThrowGlaive.playbackRate"); public override void Reset() { base.Reset(); duration = 0f; stopwatch = 0f; animator = null; chargeEffect = null; modelTransform = null; huntressTracker = null; childLocator = null; hasTriedToThrowGlaive = false; hasSuccessfullyThrownGlaive = false; initialOrbTarget = null; _emh_chargeEffect = null; } public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; modelTransform = GetModelTransform(); animator = GetModelAnimator(); huntressTracker = GetComponent(); Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); if ((bool)huntressTracker && base.isAuthority) { initialOrbTarget = huntressTracker.GetTrackingTarget(); } if ((bool)base.characterMotor && smallHopStrength != 0f) { base.characterMotor.velocity.y = smallHopStrength; } PlayAnimation("FullBody, Override", ThrowGlaiveStateHash, ThrowGlaiveParamHash, duration); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); if ((bool)childLocator) { Transform transform = childLocator.FindChild("HandR"); if ((bool)transform && (bool)chargePrefab) { if (!EffectManager.ShouldUsePooledEffect(chargePrefab)) { chargeEffect = UnityEngine.Object.Instantiate(chargePrefab, transform.position, transform.rotation); } else { _emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargePrefab, transform.position, transform.rotation); chargeEffect = _emh_chargeEffect.gameObject; } chargeEffect.transform.parent = transform; } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } protected void DestroyChargeEffect() { if ((bool)chargeEffect) { if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null) { _emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect); } else { EntityState.Destroy(chargeEffect); } chargeEffect = null; _emh_chargeEffect = null; } } public override void OnExit() { base.OnExit(); DestroyChargeEffect(); int layerIndex = animator.GetLayerIndex("Impact"); if (layerIndex >= 0) { animator.SetLayerWeight(layerIndex, 1.5f); animator.PlayInFixedTime("LightImpact", layerIndex, 0f); } if (!hasTriedToThrowGlaive) { FireOrbGlaive(); } if (!hasSuccessfullyThrownGlaive && NetworkServer.active) { base.skillLocator.secondary.AddOneStock(); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (!hasTriedToThrowGlaive && animator.GetFloat("ThrowGlaive.fire") > 0f) { DestroyChargeEffect(); FireOrbGlaive(); } base.characterMotor.velocity.y += antigravityStrength * GetDeltaTime() * (1f - stopwatch / duration); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireOrbGlaive() { if (NetworkServer.active && !hasTriedToThrowGlaive) { hasTriedToThrowGlaive = true; LightningOrb lightningOrb = new LightningOrb(); lightningOrb.lightningType = LightningOrb.LightningType.HuntressGlaive; lightningOrb.damageValue = base.characterBody.damage * damageCoefficient; lightningOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master); lightningOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); lightningOrb.attacker = base.gameObject; lightningOrb.procCoefficient = glaiveProcCoefficient; lightningOrb.bouncesRemaining = maxBounceCount; lightningOrb.speed = glaiveTravelSpeed; lightningOrb.bouncedObjects = new List(); lightningOrb.range = glaiveBounceRange; lightningOrb.damageCoefficientPerBounce = damageCoefficientPerBounce; HurtBox hurtBox = initialOrbTarget; if ((bool)hurtBox) { hasSuccessfullyThrownGlaive = true; Transform transform = childLocator.FindChild("HandR"); EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, "HandR", transmit: true); lightningOrb.origin = transform.position; lightningOrb.target = hurtBox; OrbManager.instance.AddOrb(lightningOrb); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnSerialize(NetworkWriter writer) { writer.Write(HurtBoxReference.FromHurtBox(initialOrbTarget)); } public override void OnDeserialize(NetworkReader reader) { initialOrbTarget = reader.ReadHurtBoxReference().ResolveHurtBox(); } } } namespace EntityStates.HermitCrab { public class Burrowed : BaseState { public static float mortarCooldown; public float duration; public override void OnEnter() { base.OnEnter(); PlayCrossfade("Body", "Burrowed", 0.1f); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { if (base.inputBank.moveVector.sqrMagnitude > 0.1f) { outer.SetNextState(new BurrowOut()); } if (base.fixedAge >= duration && base.inputBank.skill1.down) { outer.SetNextState(new FireMortar()); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class BurrowIn : BaseState { public static GameObject burrowPrefab; public static float baseDuration; public static string burrowInSoundString; private float stopwatch; private float duration; private Transform modelTransform; private ChildLocator childLocator; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayCrossfade("Body", "BurrowIn", "BurrowIn.playbackRate", duration, 0.1f); modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); Util.PlaySound(burrowInSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { Burrowed nextState = new Burrowed(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class BurrowOut : BaseState { public static GameObject burrowPrefab; public static float baseDuration; public static string burrowOutSoundString; private float stopwatch; private Transform modelTransform; private ChildLocator childLocator; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayCrossfade("Body", "BurrowOut", "BurrowOut.playbackRate", duration, 0.1f); modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); Util.PlaySound(burrowOutSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireMortar : BaseState { public static GameObject mortarProjectilePrefab; public static GameObject mortarMuzzleflashEffect; public static int mortarCount; public static string mortarMuzzleName; public static string mortarSoundString; public static float mortarDamageCoefficient; public static float baseDuration; public static float timeToTarget = 3f; public static float projectileVelocity = 55f; public static float minimumDistance; private float stopwatch; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayCrossfade("Gesture, Additive", "FireMortar", 0f); Util.PlaySound(mortarSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(mortarMuzzleflashEffect, base.gameObject, mortarMuzzleName, transmit: false); if (base.isAuthority) { Fire(); } } private void Fire() { Ray aimRay = GetAimRay(); Ray ray = new Ray(aimRay.origin, UnityEngine.Vector3.up); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.filterByLoS = false; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.RefreshCandidates(); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); bool flag = false; UnityEngine.Vector3 vector = UnityEngine.Vector3.zero; RaycastHit hitInfo; if ((bool)hurtBox) { vector = hurtBox.transform.position; flag = true; } else if (Physics.Raycast(aimRay, out hitInfo, 1000f, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) { vector = hitInfo.point; flag = true; } float magnitude = projectileVelocity; if (flag) { UnityEngine.Vector3 vector2 = vector - ray.origin; UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z); float magnitude2 = vector3.magnitude; UnityEngine.Vector2 vector4 = vector3 / magnitude2; if (magnitude2 < minimumDistance) { magnitude2 = minimumDistance; } float y = Trajectory.CalculateInitialYSpeed(timeToTarget, vector2.y); float num = magnitude2 / timeToTarget; UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector4.x * num, y, vector4.y * num); magnitude = direction.magnitude; ray.direction = direction; } for (int i = 0; i < mortarCount; i++) { UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(ray.direction + ((i != 0) ? (UnityEngine.Random.insideUnitSphere * 0.05f) : UnityEngine.Vector3.zero)); ProjectileManager.instance.FireProjectile(mortarProjectilePrefab, ray.origin, rotation, base.gameObject, damageStat * mortarDamageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch > duration) { Burrowed burrowed = new Burrowed(); burrowed.duration = Burrowed.mortarCooldown; outer.SetNextState(burrowed); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class SpawnState : BaseState { private float stopwatch; public static GameObject burrowPrefab; public static float duration = 4f; public static string spawnSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Heretic { public class SpawnState : BaseState { public static float duration = 4f; public static string spawnSoundString; public static GameObject effectPrefab; public static Material overlayMaterial; public static float overlayDuration; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(spawnSoundString, base.gameObject); EffectManager.SimpleEffect(effectPrefab, base.characterBody.corePosition, UnityEngine.Quaternion.identity, transmit: false); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { CharacterModel component = modelTransform.GetComponent(); if ((bool)component && (bool)overlayMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(component.gameObject); temporaryOverlayInstance.duration = overlayDuration; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = overlayMaterial; temporaryOverlayInstance.inspectorCharacterModel = component; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class SpawnOnNewStageState : SpawnState { public override void OnEnter() { base.OnEnter(); outer.SetNextStateToMain(); } } } namespace EntityStates.Heretic.Weapon { public class Squawk : EntityState { [SerializeField] public string soundName; public override void OnEnter() { base.OnEnter(); Util.PlaySound(soundName, base.gameObject); outer.SetNextStateToMain(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Headstompers { public class BaseHeadstompersState : EntityState { private static readonly List instancesList = new List(); protected NetworkedBodyAttachment networkedBodyAttachment; protected GameObject bodyGameObject; protected CharacterBody body; protected CharacterMotor bodyMotor; protected InputBankTest bodyInputBank; protected bool jumpButtonDown { get { if ((bool)bodyInputBank) { return bodyInputBank.jump.down; } return false; } } protected bool slamButtonDown { get { if ((bool)bodyInputBank) { return bodyInputBank.interact.down; } return false; } } protected bool isGrounded { get { if ((bool)bodyMotor) { return bodyMotor.isGrounded; } return false; } } public static BaseHeadstompersState FindForBody(CharacterBody body) { for (int i = 0; i < instancesList.Count; i++) { if ((object)instancesList[i].body == body) { return instancesList[i]; } } return null; } public override void OnEnter() { base.OnEnter(); instancesList.Add(this); networkedBodyAttachment = GetComponent(); if ((bool)networkedBodyAttachment) { bodyGameObject = networkedBodyAttachment.attachedBodyObject; body = networkedBodyAttachment.attachedBody; if ((bool)bodyGameObject) { bodyMotor = bodyGameObject.GetComponent(); bodyInputBank = bodyGameObject.GetComponent(); } } } public override void OnExit() { instancesList.Remove(this); base.OnExit(); } protected bool ReturnToIdleIfGroundedAuthority() { if ((bool)bodyMotor && bodyMotor.isGrounded) { outer.SetNextState(new HeadstompersIdle()); return true; } return false; } } public class HeadstompersIdle : BaseHeadstompersState { private float inputStopwatch; public static float inputConfirmationDelay = 0.1f; private bool jumpBoostOk; public static GameObject jumpEffect; public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { FixedUpdateAuthority(); } } private void FixedUpdateAuthority() { inputStopwatch = (base.slamButtonDown ? (inputStopwatch + GetDeltaTime()) : 0f); if (base.isGrounded) { jumpBoostOk = true; } else if (jumpBoostOk && base.jumpButtonDown && (bool)bodyMotor) { UnityEngine.Vector3 velocity = bodyMotor.velocity; if (velocity.y > 0f) { velocity.y *= 2f; bodyMotor.velocity = velocity; jumpBoostOk = false; } EffectManager.SimpleImpactEffect(jumpEffect, bodyGameObject.transform.position, UnityEngine.Vector3.up, transmit: true); } if (inputStopwatch >= inputConfirmationDelay && !base.isGrounded) { outer.SetNextState(new HeadstompersCharge()); } } } public class HeadstompersCharge : BaseHeadstompersState { private float inputStopwatch; public static float maxChargeDuration = 0.5f; public static float minVelocityY = 1f; public static float accelerationY = 10f; public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { FixedUpdateAuthority(); } } private void FixedUpdateAuthority() { if (ReturnToIdleIfGroundedAuthority()) { return; } inputStopwatch = (base.slamButtonDown ? (inputStopwatch + Time.deltaTime) : 0f); if (inputStopwatch >= maxChargeDuration) { outer.SetNextState(new HeadstompersFall()); } else if (!base.slamButtonDown) { outer.SetNextState(new HeadstompersIdle()); } else if ((bool)bodyMotor) { UnityEngine.Vector3 velocity = bodyMotor.velocity; if (velocity.y < minVelocityY) { velocity.y = Mathf.MoveTowards(velocity.y, minVelocityY, accelerationY * Time.deltaTime); bodyMotor.velocity = velocity; } } } } public class HeadstompersFall : BaseHeadstompersState { private float stopwatch; public static float maxFallDuration = 0f; public static float maxFallSpeed = 30f; public static float maxDistance = 30f; public static float initialFallSpeed = 10f; public static float accelerationY = 40f; public static float minimumRadius = 5f; public static float maximumRadius = 100f; public static float minimumDamageCoefficient = 10f; public static float maximumDamageCoefficient = 100f; public static float seekCone = 20f; public static float springboardSpeed = 30f; private Transform seekTransform; private bool seekLost; private CharacterMotor onHitGroundProvider; private float initialY; public override void OnEnter() { base.OnEnter(); if (!base.isAuthority) { return; } if ((bool)body) { TeamMask allButNeutral = TeamMask.allButNeutral; TeamIndex objectTeam = TeamComponent.GetObjectTeam(bodyGameObject); if (objectTeam != TeamIndex.None) { allButNeutral.RemoveTeam(objectTeam); } BullseyeSearch obj = new BullseyeSearch { filterByLoS = true, maxDistanceFilter = 300f, maxAngleFilter = seekCone, searchOrigin = body.footPosition, searchDirection = UnityEngine.Vector3.down, sortMode = BullseyeSearch.SortMode.Angle, teamMaskFilter = allButNeutral, viewer = body }; initialY = body.footPosition.y; obj.RefreshCandidates(); seekTransform = obj.GetResults().FirstOrDefault()?.transform; } SetOnHitGroundProviderAuthority(bodyMotor); if ((bool)bodyMotor) { bodyMotor.velocity.y = Mathf.Min(bodyMotor.velocity.y, 0f - initialFallSpeed); } } private void SetOnHitGroundProviderAuthority(CharacterMotor newOnHitGroundProvider) { if ((object)onHitGroundProvider != null) { onHitGroundProvider.onHitGroundAuthority -= OnMotorHitGroundAuthority; } onHitGroundProvider = newOnHitGroundProvider; if ((object)onHitGroundProvider != null) { onHitGroundProvider.onHitGroundAuthority += OnMotorHitGroundAuthority; } } public override void OnExit() { SetOnHitGroundProviderAuthority(null); base.OnExit(); } private void OnMotorHitGroundAuthority(ref CharacterMotor.HitGroundInfo hitGroundInfo) { DoStompExplosionAuthority(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { FixedUpdateAuthority(); } } private void FixedUpdateAuthority() { stopwatch += Time.deltaTime; if (base.isGrounded) { DoStompExplosionAuthority(); } else if (stopwatch >= maxFallDuration) { outer.SetNextState(new HeadstompersCooldown()); } else { if (!bodyMotor) { return; } UnityEngine.Vector3 velocity = bodyMotor.velocity; if (velocity.y > 0f - maxFallSpeed) { velocity.y = Mathf.MoveTowards(velocity.y, 0f - maxFallSpeed, accelerationY * Time.deltaTime); } if ((bool)seekTransform && !seekLost) { UnityEngine.Vector3 normalized = (seekTransform.position - body.footPosition).normalized; if (UnityEngine.Vector3.Dot(UnityEngine.Vector3.down, normalized) >= Mathf.Cos(seekCone * (MathF.PI / 180f))) { if (velocity.y < 0f) { UnityEngine.Vector3 vector = normalized * (0f - velocity.y); vector.y = 0f; UnityEngine.Vector3 vector2 = velocity; vector2.y = 0f; vector2 = vector; velocity.x = vector2.x; velocity.z = vector2.z; } } else { seekLost = true; } } bodyMotor.velocity = velocity; } } private void DoStompExplosionAuthority() { if ((bool)body) { RoR2.Inventory inventory = body.inventory; if (((!inventory || inventory.GetItemCount(RoR2Content.Items.FallBoots) != 0) ? 1 : 0) > (false ? 1 : 0)) { bodyMotor.velocity = UnityEngine.Vector3.zero; float num = Mathf.Max(0f, initialY - body.footPosition.y); if (num > 0f) { float t = Mathf.InverseLerp(0f, maxDistance, num); float num2 = Mathf.Lerp(minimumDamageCoefficient, maximumDamageCoefficient, t); float num3 = Mathf.Lerp(minimumRadius, maximumRadius, t); BlastAttack obj = new BlastAttack { attacker = body.gameObject, inflictor = body.gameObject }; obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker); obj.position = body.footPosition; obj.procCoefficient = 1f; obj.radius = num3; obj.baseForce = 200f * num2; obj.bonusForce = UnityEngine.Vector3.up * 2000f; obj.baseDamage = body.damage * num2; obj.falloffModel = BlastAttack.FalloffModel.SweetSpot; obj.crit = Util.CheckRoll(body.crit, body.master); obj.damageColorIndex = DamageColorIndex.Item; obj.attackerFiltering = AttackerFiltering.NeverHitSelf; obj.Fire(); EffectData effectData = new EffectData(); effectData.origin = body.footPosition; effectData.scale = num3; EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/BootShockwave"), effectData, transmit: true); } } } SetOnHitGroundProviderAuthority(null); outer.SetNextState(new HeadstompersCooldown()); } } public class HeadstompersCooldown : BaseHeadstompersState { public static float baseDuration = 10f; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration; if ((bool)body) { RoR2.Inventory inventory = body.inventory; int num = ((!inventory) ? 1 : inventory.GetItemCount(RoR2Content.Items.FallBoots)); if (num > 0) { duration /= num; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { FixedUpdateAuthority(); } } private void FixedUpdateAuthority() { if (base.fixedAge >= duration) { outer.SetNextState(new HeadstompersIdle()); } } } } namespace EntityStates.HAND { public class Overclock : BaseState { public static float baseDuration = 0.25f; public static GameObject healEffectPrefab; public static float healPercentage = 0.15f; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { _ = (bool)base.characterBody; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > baseDuration && base.isAuthority) { outer.SetNextStateToMain(); } } } } namespace EntityStates.HAND.Weapon { public class ChargeSlam : BaseState { public static float baseDuration = 3.5f; private float duration; private Animator modelAnimator; private static int ChargeSlamStateHash = Animator.StringToHash("ChargeSlam"); private static int ChargeSlamParamHash = Animator.StringToHash("ChargeSlam.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayAnimation("Gesture", ChargeSlamStateHash, ChargeSlamParamHash, duration); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(4f); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.characterMotor.isGrounded && base.isAuthority) { outer.SetNextState(new Slam()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireWinch : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static float duration = 2f; public static float baseDuration = 2f; public static float damageCoefficient = 1.2f; public static float force = 20f; public override void OnEnter() { base.OnEnter(); Ray aimRay = GetAimRay(); StartAimMode(aimRay); string muzzleName = "WinchHole"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration / attackSpeedStat && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FullSwing : BaseState { public static float baseDuration = 3.5f; public static float returnToIdlePercentage; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float radius = 3f; public static GameObject hitEffectPrefab; public static GameObject swingEffectPrefab; private Transform hammerChildTransform; private OverlapAttack attack; private Animator modelAnimator; private float duration; private bool hasSwung; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Hammer"); ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { hammerChildTransform = component.FindChild("SwingCenter"); } } if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Gesture"); if (modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("FullSwing3") || modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("FullSwing1")) { PlayCrossfade("Gesture", "FullSwing2", "FullSwing.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f); } else if (modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("FullSwing2")) { PlayCrossfade("Gesture", "FullSwing3", "FullSwing.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f); } else { PlayCrossfade("Gesture", "FullSwing1", "FullSwing.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f); } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Hammer.hitBoxActive") > 0.5f) { if (!hasSwung) { EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "SwingCenter", transmit: true); hasSwung = true; } attack.forceVector = hammerChildTransform.right * (0f - forceMagnitude); attack.Fire(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } private static void PullEnemies(UnityEngine.Vector3 position, UnityEngine.Vector3 direction, float coneAngle, float maxDistance, float force, TeamIndex excludedTeam) { float num = Mathf.Cos(coneAngle * 0.5f * (MathF.PI / 180f)); Collider[] colliders; int num2 = HGPhysics.OverlapSphere(out colliders, position, maxDistance); for (int i = 0; i < num2; i++) { Collider collider = colliders[i]; UnityEngine.Vector3 position2 = collider.transform.position; UnityEngine.Vector3 normalized = (position - position2).normalized; if (!(UnityEngine.Vector3.Dot(-normalized, direction) >= num)) { continue; } TeamIndex teamIndex = TeamIndex.Neutral; TeamComponent component = collider.GetComponent(); if (!component) { continue; } teamIndex = component.teamIndex; if (teamIndex != excludedTeam) { CharacterMotor component2 = collider.GetComponent(); if ((bool)component2) { component2.ApplyForce(normalized * force); } Rigidbody component3 = collider.GetComponent(); if ((bool)component3) { component3.AddForce(normalized * force, ForceMode.Impulse); } } } HGPhysics.ReturnResults(colliders); } } public class Slam : BaseState { public static float baseDuration = 3.5f; public static float returnToIdlePercentage; public static float impactDamageCoefficient = 2f; public static float earthquakeDamageCoefficient = 2f; public static float forceMagnitude = 16f; public static float radius = 3f; public static GameObject hitEffectPrefab; public static GameObject swingEffectPrefab; public static GameObject projectilePrefab; private Transform hammerChildTransform; private OverlapAttack attack; private Animator modelAnimator; private float duration; private bool hasSwung; private static int SlamStateHash = Animator.StringToHash("Slam"); private static int SlamParamHash = Animator.StringToHash("Slam.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = impactDamageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Hammer"); ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { hammerChildTransform = component.FindChild("SwingCenter"); } } if ((bool)modelAnimator) { PlayAnimation("Gesture", SlamStateHash, SlamParamHash, duration); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Hammer.hitBoxActive") > 0.5f) { if (!hasSwung) { Ray aimRay = GetAimRay(); EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "SwingCenter", transmit: true); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * earthquakeDamageCoefficient, forceMagnitude, Util.CheckRoll(critStat, base.characterBody.master)); hasSwung = true; } attack.forceVector = hammerChildTransform.right; attack.Fire(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.Halcyonite { public class ChargeTriLaser : BaseState { public static float baseDuration = 3f; public static float laserMaxWidth = 0.2f; public static GameObject effectPrefab; public static GameObject laserPrefab; public static string attackSoundString; private float duration; private uint chargePlayID; private GameObject chargeEffect; private GameObject laserEffect; private LineRenderer laserLineComponent; private UnityEngine.Vector3 laserDirection; private UnityEngine.Vector3 visualEndPosition; private float flashTimer; private bool laserOn; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayCrossfade("FullBody Override", "TriLaserEnter", "TriLaser.playbackRate", duration, 0.1f); Transform modelTransform = GetModelTransform(); chargePlayID = Util.PlayAttackSpeedSound("Play_halcyonite_skill2_chargeup", base.gameObject, attackSpeedStat); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleLaser"); if ((bool)transform) { if ((bool)effectPrefab) { chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); chargeEffect.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffect.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } if ((bool)laserPrefab) { laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation); laserEffect.transform.parent = transform; laserLineComponent = laserEffect.GetComponent(); } } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } flashTimer = 0f; laserOn = true; } public override void OnExit() { AkSoundEngine.StopPlayingID(chargePlayID); base.OnExit(); if ((bool)chargeEffect) { EntityState.Destroy(chargeEffect); } if ((bool)laserEffect) { EntityState.Destroy(laserEffect); } PlayAnimation("FullBody Override", "BufferEmpty"); } public override void Update() { base.Update(); if (!laserEffect || !laserLineComponent) { return; } float num = 1000f; Ray aimRay = GetAimRay(); UnityEngine.Vector3 position = laserEffect.transform.parent.position; UnityEngine.Vector3 point = aimRay.GetPoint(num); laserDirection = point - position; if (Physics.Raycast(aimRay, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask)) { point = hitInfo.point; } laserLineComponent.SetPosition(0, position); laserLineComponent.SetPosition(1, point); float num2; if (duration - base.age > 0.5f) { num2 = base.age / duration; } else { flashTimer -= Time.deltaTime; if (flashTimer <= 0f) { laserOn = !laserOn; flashTimer = 1f / 30f; } num2 = (laserOn ? 1f : 0f); } num2 *= laserMaxWidth; laserLineComponent.startWidth = num2; laserLineComponent.endWidth = num2; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { TriLaser triLaser = new TriLaser(); triLaser.laserDirection = laserDirection; outer.SetNextState(triLaser); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class DeathState : GenericCharacterDeath { public override void OnEnter() { base.OnEnter(); ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if ((bool)component) { component.FindChild("ChestGlow").transform.gameObject.GetComponent().Stop(); } } } public class GoldenSlash : BasicMeleeAttack { [SerializeField] public GameObject swordPrefab; protected override void PlayAnimation() { ChildLocator component = GetModelTransform().GetComponent(); if ((bool)component && (bool)swordPrefab) { int childIndex = component.FindChildIndex("SwordPoint"); EffectData effectData = new EffectData(); effectData.origin = base.characterBody.transform.position; effectData.rotation = Util.QuaternionSafeLookRotation(base.characterBody.transform.forward); effectData.SetChildLocatorTransformReference(base.characterBody.transform.gameObject, childIndex); EffectManager.SpawnEffect(swordPrefab, effectData, transmit: true); } PlayCrossfade("FullBody Override", "GoldenSlash", "GoldenSlash.playbackRate", duration, 0.1f); } public override void OnExit() { PlayAnimation("FullBody Override", "BufferEmpty"); base.OnExit(); } } public class GoldenSwipe : BasicMeleeAttack { [SerializeField] public GameObject swordPrefab; protected override void PlayAnimation() { ChildLocator component = GetModelTransform().GetComponent(); if ((bool)component && (bool)swordPrefab) { int childIndex = component.FindChildIndex("SwordPoint"); EffectData effectData = new EffectData(); effectData.origin = base.characterBody.transform.position; effectData.rotation = Util.QuaternionSafeLookRotation(base.characterBody.transform.forward); effectData.SetChildLocatorTransformReference(base.characterBody.transform.gameObject, childIndex); EffectManager.SpawnEffect(swordPrefab, effectData, transmit: true); } PlayCrossfade("FullBody Override", "GoldenSwipe", "GoldenSwipe.playbackRate", duration, 0.1f); } public override void OnExit() { PlayAnimation("FullBody Override", "BufferEmpty"); base.OnExit(); } } public class SpawnState : EntityState { public static float duration = 2f; public static float startingPrintHeight; public static float maxPrintHeight; public static float startingPrintBias; public static float maxPrintBias; public static string spawnSoundString; public override void OnEnter() { base.OnEnter(); base.gameObject.GetComponent(); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", "Spawn", "Spawn.playbackRate", duration); PrintController printController = GetModelTransform().gameObject.AddComponent(); printController.printTime = duration; printController.enabled = true; printController.startingPrintHeight = startingPrintHeight; printController.maxPrintHeight = maxPrintHeight; printController.startingPrintBias = startingPrintBias; printController.maxPrintBias = maxPrintBias; printController.disableWhenFinished = true; printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class TriLaser : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float blastRadius; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float baseDuration = 2f; public static string attackSoundString; public UnityEngine.Vector3 laserDirection; private float duration; private Ray modifiedAimRay; public float fireBeamTimer = 0.5f; private int timesFired; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; } public override void FixedUpdate() { base.FixedUpdate(); fireBeamTimer += Time.deltaTime; if (timesFired < 3 && fireBeamTimer > 0.5f) { FireTriLaser(); fireBeamTimer = 0f; timesFired++; } if (base.fixedAge >= duration && timesFired > 2 && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireTriLaser() { duration = baseDuration / attackSpeedStat; modifiedAimRay = GetAimRay(); modifiedAimRay.direction = laserDirection; GetModelAnimator(); Transform modelTransform = GetModelTransform(); Util.PlaySound(attackSoundString, base.gameObject); string text = "MuzzleLaser"; Util.PlaySound("Play_halcyonite_skill2_shoot", base.gameObject); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } PlayCrossfade("FullBody Override", "TriLaserFire", "TriLaser.playbackRate", duration * 0.5f, 0.1f); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false); } if (!base.isAuthority) { return; } float num = 1000f; UnityEngine.Vector3 vector = modifiedAimRay.origin + modifiedAimRay.direction * num; if (Physics.Raycast(modifiedAimRay, out var hitInfo, num, LayerIndex.CommonMasks.laser)) { vector = hitInfo.point; } BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * damageCoefficient; blastAttack.baseForce = force * 0.2f; blastAttack.position = vector; blastAttack.radius = blastRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot; blastAttack.bonusForce = force * modifiedAimRay.direction; blastAttack.Fire(); _ = modifiedAimRay.origin; if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { int childIndex = component.FindChildIndex(text); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = vector, start = modifiedAimRay.origin }; effectData.SetChildLocatorTransformReference(base.gameObject, childIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); EffectManager.SpawnEffect(hitEffectPrefab, effectData, transmit: true); } } } public override void OnExit() { PlayCrossfade("FullBody Override", "TriLaserExit", "TriLaser.playbackRate", duration, 0.1f); base.OnExit(); } } public class WhirlwindRush : BaseState { public static float chargeMovementSpeedCoefficient; public static float turnSpeed; public static float turnSmoothTime; public static float damageCoefficient; public static GameObject hitEffectPrefab; private Animator animator; private UnityEngine.Vector3 targetMoveVector; private UnityEngine.Vector3 targetMoveVectorVelocity; private HitBoxGroup hitboxGroup; private ChildLocator childLocator; [SerializeField] public float spinUpDuration = 1f; [SerializeField] public float duration = 2f; [SerializeField] public float endSpinDuration = 1f; [SerializeField] public GameObject projectilePrefab; private bool firedWhirlWind; private static int forwardSpeedParamHash = Animator.StringToHash("forwardSpeed"); private float originalMoveSpeed = 6.6f; private float originalAccSpeed = 40f; [SerializeField] public float rushingMoveSpeed = 13.5f; [SerializeField] public float rushingAccSpeed = 200f; private UnityEngine.Vector3 safePosition; private float ageStartedWhirlwind; private float intervalToCheckForSafePath = 1f; public override void OnEnter() { originalMoveSpeed = base.characterBody.baseMoveSpeed; originalAccSpeed = base.characterBody.baseAcceleration; base.characterBody.baseMoveSpeed = 0.5f; base.characterMotor.moveDirection = UnityEngine.Vector3.zero; safePosition = base.characterBody.corePosition; animator = GetModelAnimator(); childLocator = animator.GetComponent(); PlayCrossfade("FullBody Override", "WhirlwindRushEnter", "WhirlwindRush.playbackRate", duration, 0.1f); Util.PlaySound("Play_halcyonite_skill3_start", base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); bool stopWhirlwind = base.fixedAge > duration + spinUpDuration + endSpinDuration; if (base.fixedAge > spinUpDuration * 0.5f && !firedWhirlWind) { ProjectileManager.instance.FireProjectile(projectilePrefab, base.gameObject.transform.position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); firedWhirlWind = true; Util.PlaySound("Play_halcyonite_skill3_loop", base.gameObject); } if (firedWhirlWind && !stopWhirlwind) { if (base.fixedAge - ageStartedWhirlwind > intervalToCheckForSafePath) { HandleIdentifySafePathForward(ref stopWhirlwind); } else { HandleProceedAlongPath(ref stopWhirlwind); } } if (base.fixedAge > duration + spinUpDuration && !stopWhirlwind) { base.characterBody.baseMoveSpeed = 0f; if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = 0f; } if ((bool)base.characterBody) { base.characterBody.isSprinting = false; } if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } } if (stopWhirlwind) { base.characterBody.baseMoveSpeed = originalMoveSpeed; base.characterBody.baseAcceleration = originalAccSpeed; if ((bool)base.characterMotor) { base.characterMotor.walkSpeedPenaltyCoefficient = 1f; } if ((bool)base.characterBody) { base.characterBody.isSprinting = false; } if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } Util.PlaySound("Stop_halcyonite_skill3_loop", base.gameObject); outer.SetNextStateToMain(); } } private void HandleIdentifySafePathForward(ref bool stopWhirlwind) { UnityEngine.Vector3 vector = base.inputBank.aimDirection * rushingMoveSpeed * GetDeltaTime(); vector.y = 0f; vector += base.characterBody.aimOrigin; UnityEngine.Debug.DrawLine(base.characterBody.aimOrigin, base.characterBody.aimOrigin + UnityEngine.Vector3.right, UnityEngine.Color.grey, 10f); UnityEngine.Debug.DrawRay(vector + UnityEngine.Vector3.up * 2f, UnityEngine.Vector3.down, UnityEngine.Color.green, 10f); UnityEngine.Debug.DrawLine(vector + UnityEngine.Vector3.up * 2f, vector + UnityEngine.Vector3.up * 2f + UnityEngine.Vector3.up * -10f, UnityEngine.Color.yellow, 10f); if (!Physics.Raycast(new Ray(vector + UnityEngine.Vector3.up * 2f, UnityEngine.Vector3.down), out var _, 10f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault, QueryTriggerInteraction.Ignore)) { stopWhirlwind = true; } else { ageStartedWhirlwind = base.fixedAge; } } private void HandleProceedAlongPath(ref bool stopWhirlwind) { if (!base.characterMotor.isGrounded) { TeleportHelper.TeleportBody(base.characterBody, safePosition); stopWhirlwind = true; } else { safePosition = base.characterBody.footPosition; } targetMoveVector = UnityEngine.Vector3.ProjectOnPlane(UnityEngine.Vector3.SmoothDamp(targetMoveVector, base.inputBank.aimDirection, ref targetMoveVectorVelocity, turnSmoothTime, turnSpeed), UnityEngine.Vector3.up).normalized; base.characterDirection.moveVector = targetMoveVector; UnityEngine.Vector3 forward = base.characterDirection.forward; float value = moveSpeedStat * chargeMovementSpeedCoefficient; base.characterMotor.moveDirection = forward * chargeMovementSpeedCoefficient; animator.SetFloat(forwardSpeedParamHash, value); base.characterBody.baseMoveSpeed = rushingMoveSpeed; base.characterBody.baseAcceleration = rushingAccSpeed; } public override void OnExit() { base.characterMotor.moveDirection = UnityEngine.Vector3.zero; PlayCrossfade("FullBody Override", "WhirlwindRushExit", "WhirlwindRush.playbackRate", duration, 0.1f); Util.PlaySound("Play_halcyonite_skill3_end", base.gameObject); Util.PlaySound("Stop_halcyonite_skill3_loop", base.gameObject); base.characterBody.RecalculateStats(); base.OnExit(); } } } namespace EntityStates.Gup { public class GupSpikesState : BasicMeleeAttack { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string playbackRateParam; [SerializeField] public float crossfadeDuration; [SerializeField] public string initialHitboxActiveParameter; [SerializeField] public string initialHitboxName; private HitBox initialHitBox; public override void OnEnter() { base.OnEnter(); StartAimMode(0f); if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if (!hitBoxGroup) { return; } HitBox[] hitBoxes = hitBoxGroup.hitBoxes; foreach (HitBox hitBox in hitBoxes) { if (hitBox.gameObject.name == initialHitboxName) { initialHitBox = hitBox; break; } } } protected override void PlayAnimation() { PlayCrossfade(animationLayerName, animationStateName, playbackRateParam, duration, crossfadeDuration); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)initialHitBox) { initialHitBox.enabled = animator.GetFloat(initialHitboxActiveParameter) > 0.5f; } } } internal class SpawnState : GenericCharacterSpawnState { public static GameObject spawnEffectPrefab; public static string spawnEffectMuzzle; public override void OnEnter() { base.OnEnter(); if ((bool)spawnEffectPrefab) { EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData { origin = FindModelChild(spawnEffectMuzzle).position, scale = base.characterBody.radius }, transmit: true); } } } public class BaseSplitDeath : GenericCharacterDeath { [SerializeField] public CharacterSpawnCard characterSpawnCard; [SerializeField] public int spawnCount; [SerializeField] public float deathDelay; [SerializeField] public float moneyMultiplier; public static float spawnRadiusCoefficient = 0.5f; public static GameObject deathEffectPrefab; private bool hasDied; public override void OnEnter() { base.OnEnter(); } public override void FixedUpdate() { base.FixedUpdate(); if (!(base.fixedAge > deathDelay) || hasDied) { return; } hasDied = true; if (NetworkServer.active) { EffectManager.SpawnEffect(deathEffectPrefab, new EffectData { origin = base.characterBody.corePosition, scale = base.characterBody.radius }, transmit: true); if ((bool)characterSpawnCard && spawnCount > 0 && (ulong)(base.healthComponent.killingDamageType & (DamageType.VoidDeath | DamageType.OutOfBounds)) == 0L) { BodySplitter bodySplitter = new BodySplitter(); bodySplitter.body = base.characterBody; bodySplitter.masterSummon.masterPrefab = characterSpawnCard.prefab; bodySplitter.count = spawnCount; bodySplitter.splinterInitialVelocityLocal = new UnityEngine.Vector3(0f, 20f, 10f); bodySplitter.minSpawnCircleRadius = base.characterBody.radius * spawnRadiusCoefficient; bodySplitter.moneyMultiplier = moneyMultiplier; bodySplitter.Perform(); } DestroyBodyAsapServer(); } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class GupDeath : BaseSplitDeath { } public class GeepDeath : BaseSplitDeath { } public class GipDeath : BaseSplitDeath { } } namespace EntityStates.GummyClone { public class GummyCloneDeathState : BaseState { [SerializeField] public string soundString; [SerializeField] public GameObject effectPrefab; public override void OnEnter() { base.OnEnter(); Util.PlaySound(soundString, base.gameObject); if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if (base.isAuthority && (bool)effectPrefab) { EffectManager.SimpleImpactEffect(effectPrefab, base.transform.position, UnityEngine.Vector3.up, transmit: true); } EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class GummyCloneSpawnState : BaseState { [SerializeField] public float duration = 4f; [SerializeField] public string soundString; [SerializeField] public float initialDelay; [SerializeField] public GameObject effectPrefab; private bool hasFinished; private Animator modelAnimator; private CharacterModel characterModel; private CameraTargetParams.AimRequest aimRequest; public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } if ((bool)modelAnimator) { GameObject gameObject = modelAnimator.gameObject; characterModel = gameObject.GetComponent(); characterModel.invisibilityCount++; } if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } } public override void OnExit() { base.OnExit(); if (!hasFinished) { characterModel.invisibilityCount--; } aimRequest?.Dispose(); if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 3f); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= initialDelay && !hasFinished) { hasFinished = true; characterModel.invisibilityCount--; duration = initialDelay; if ((bool)effectPrefab) { EffectManager.SimpleEffect(effectPrefab, base.transform.position, UnityEngine.Quaternion.identity, transmit: false); } Util.PlaySound(soundString, base.gameObject); } if (base.fixedAge >= duration && hasFinished && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.ArchWispMonster { public class ChargeCannons : EntityStates.GreaterWispMonster.ChargeCannons { public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireCannons nextState = new FireCannons(); outer.SetNextState(nextState); } } } public class FireCannons : EntityStates.GreaterWispMonster.FireCannons { } public class DeathState : EntityStates.GreaterWispMonster.DeathState { } } namespace EntityStates.GreaterWispMonster { public class ChargeCannons : BaseState { [SerializeField] public float baseDuration = 3f; [SerializeField] public GameObject effectPrefab; [SerializeField] public string attackString; protected float duration; private GameObject chargeEffectLeft; private GameObject chargeEffectRight; private const float soundDuration = 2f; private uint soundID; private EffectManagerHelper _emh_chargeEffectLeft; private EffectManagerHelper _emh_chargeEffectRight; private static int ChargeCannonsStateHash = Animator.StringToHash("ChargeCannons"); private static int ChargeCannonsParamHash = Animator.StringToHash("ChargeCannons.playbackRate"); private static int EmptyStateHash = Animator.StringToHash("Empty"); public override void Reset() { base.Reset(); duration = 0f; chargeEffectLeft = null; chargeEffectRight = null; _emh_chargeEffectLeft = null; _emh_chargeEffectRight = null; } public override void OnEnter() { base.OnEnter(); soundID = Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat * (2f / baseDuration)); duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); GetModelAnimator(); PlayAnimation("Gesture", ChargeCannonsStateHash, ChargeCannonsParamHash, duration); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component && (bool)effectPrefab) { Transform transform = component.FindChild("MuzzleLeft"); Transform transform2 = component.FindChild("MuzzleRight"); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(effectPrefab)) { chargeEffectLeft = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffectLeft = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation); chargeEffectLeft = _emh_chargeEffectLeft.gameObject; } chargeEffectLeft.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffectLeft.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } if ((bool)transform2) { if (!EffectManager.ShouldUsePooledEffect(effectPrefab)) { chargeEffectRight = UnityEngine.Object.Instantiate(effectPrefab, transform2.position, transform2.rotation); } else { _emh_chargeEffectRight = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform2.position, transform2.rotation); chargeEffectRight = _emh_chargeEffectRight.gameObject; } chargeEffectRight.transform.parent = transform2; ScaleParticleSystemDuration component3 = chargeEffectRight.GetComponent(); if ((bool)component3) { component3.newDuration = duration; } } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void OnExit() { if (base.fixedAge < duration - 0.1f) { AkSoundEngine.StopPlayingID(soundID); } PlayAnimation("Gesture", EmptyStateHash); if (_emh_chargeEffectLeft != null && _emh_chargeEffectLeft.OwningPool != null) { _emh_chargeEffectLeft.OwningPool.ReturnObject(_emh_chargeEffectLeft); } else { EntityState.Destroy(chargeEffectLeft); } chargeEffectLeft = null; _emh_chargeEffectLeft = null; if (_emh_chargeEffectRight != null && _emh_chargeEffectRight.OwningPool != null) { _emh_chargeEffectRight.OwningPool.ReturnObject(_emh_chargeEffectRight); } else { EntityState.Destroy(chargeEffectRight); } chargeEffectRight = null; _emh_chargeEffectRight = null; base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireCannons nextState = new FireCannons(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireCannons : BaseState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject effectPrefab; public static float baseDuration = 2f; [SerializeField] public float damageCoefficient = 1.2f; [SerializeField] public float force = 20f; private float duration; private static int FireCannonsStateHash = Animator.StringToHash("FireCannons"); private static int FireCannonsParamHash = Animator.StringToHash("FireCannons.playbackRate"); public override void OnEnter() { base.OnEnter(); Ray aimRay = GetAimRay(); string text = "MuzzleLeft"; string text2 = "MuzzleRight"; duration = baseDuration / attackSpeedStat; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false); EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text2, transmit: false); } PlayAnimation("Gesture", FireCannonsStateHash, FireCannonsParamHash, duration); if (!base.isAuthority || !base.modelLocator || !base.modelLocator.modelTransform) { return; } ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if ((bool)component) { int childIndex = component.FindChildIndex(text); int childIndex2 = component.FindChildIndex(text2); Transform transform = component.FindChild(childIndex); Transform transform2 = component.FindChild(childIndex2); if ((bool)transform) { ProjectileManager.instance.FireProjectile(projectilePrefab, transform.position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } if ((bool)transform2) { ProjectileManager.instance.FireProjectile(projectilePrefab, transform2.position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class DeathState : GenericCharacterDeath { [SerializeField] public GameObject initialEffect; [SerializeField] public GameObject deathEffect; private static float duration = 2f; private GameObject initialEffectInstance; private bool spawnedEffect; private EffectData _effectData; protected EffectManagerHelper _efh_initializeEffectInstance; public override void Reset() { base.Reset(); initialEffectInstance = null; spawnedEffect = false; if (_effectData != null) { _effectData.Reset(); } _efh_initializeEffectInstance = null; } public override void OnEnter() { base.OnEnter(); if (!base.modelLocator) { return; } ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild("Mask"); transform.gameObject.SetActive(value: true); transform.GetComponent().timeMax = duration; if ((bool)initialEffect) { if (!EffectManager.ShouldUsePooledEffect(initialEffect)) { initialEffectInstance = UnityEngine.Object.Instantiate(initialEffect, transform.position, transform.rotation, transform); return; } _efh_initializeEffectInstance = EffectManager.GetAndActivatePooledEffect(initialEffect, transform.position, transform.rotation); initialEffectInstance = _efh_initializeEffectInstance.gameObject; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && NetworkServer.active && (bool)deathEffect && !spawnedEffect) { spawnedEffect = true; if (_effectData == null) { _effectData = new EffectData(); } _effectData.origin = base.transform.position; EffectManager.SpawnEffect(deathEffect, _effectData, transmit: true); if (base.isAuthority) { outer.SetNextStateToMain(); } } } public override void OnExit() { base.OnExit(); UnityEngine.Debug.LogError("gwisp death onexit"); EntityState.Destroy(base.gameObject); if (!initialEffectInstance) { return; } if (!EffectManager.UsePools) { EntityState.Destroy(initialEffectInstance); return; } if (_efh_initializeEffectInstance != null && _efh_initializeEffectInstance.OwningPool != null) { _efh_initializeEffectInstance.OwningPool.ReturnObject(_efh_initializeEffectInstance); } else { if (_efh_initializeEffectInstance != null) { UnityEngine.Debug.LogFormat("GreaterWispDeathState has no owning pool {0} {1}", base.gameObject.name, base.gameObject.GetInstanceID()); } EntityState.Destroy(initialEffectInstance); } initialEffectInstance = null; _efh_initializeEffectInstance = null; } } public class SpawnState : BaseState { public static float duration = 4f; public static string spawnSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.GravekeeperMonster.Weapon { public class GravekeeperBarrage : BaseState { private float stopwatch; private float missileStopwatch; public static float baseDuration; public static string muzzleString; public static float missileSpawnFrequency; public static float missileSpawnDelay; public static float missileForce; public static float damageCoefficient; public static float maxSpread; public static GameObject projectilePrefab; public static GameObject muzzleflashPrefab; public static string jarEffectChildLocatorString; public static string jarOpenSoundString; public static string jarCloseSoundString; public static GameObject jarOpenEffectPrefab; public static GameObject jarCloseEffectPrefab; private ChildLocator childLocator; private static int BeginGravekeeperBarrageStateHash = Animator.StringToHash("BeginGravekeeperBarrage"); private static int EndGravekeeperBarrageStateHash = Animator.StringToHash("EndGravekeeperBarrage"); public override void OnEnter() { base.OnEnter(); missileStopwatch -= missileSpawnDelay; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); if ((bool)childLocator) { childLocator.FindChild("JarEffectLoop").gameObject.SetActive(value: true); } } PlayAnimation("Jar, Override", BeginGravekeeperBarrageStateHash); EffectManager.SimpleMuzzleFlash(jarOpenEffectPrefab, base.gameObject, jarEffectChildLocatorString, transmit: false); Util.PlaySound(jarOpenSoundString, base.gameObject); base.characterBody.SetAimTimer(baseDuration + 2f); } private void FireBlob(Ray projectileRay, float bonusPitch, float bonusYaw) { projectileRay.direction = Util.ApplySpread(projectileRay.direction, 0f, maxSpread, 1f, 1f, bonusYaw, bonusPitch); EffectManager.SimpleMuzzleFlash(muzzleflashPrefab, base.gameObject, muzzleString, transmit: false); if (NetworkServer.active) { ProjectileManager.instance.FireProjectile(projectilePrefab, projectileRay.origin, Util.QuaternionSafeLookRotation(projectileRay.direction), base.gameObject, damageStat * damageCoefficient, missileForce, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { PlayCrossfade("Jar, Override", EndGravekeeperBarrageStateHash, 0.06f); EffectManager.SimpleMuzzleFlash(jarCloseEffectPrefab, base.gameObject, jarEffectChildLocatorString, transmit: false); Util.PlaySound(jarCloseSoundString, base.gameObject); if ((bool)childLocator) { childLocator.FindChild("JarEffectLoop").gameObject.SetActive(value: false); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); stopwatch += deltaTime; missileStopwatch += deltaTime; if (missileStopwatch >= 1f / missileSpawnFrequency) { missileStopwatch -= 1f / missileSpawnFrequency; Transform transform = childLocator.FindChild(muzzleString); if ((bool)transform) { Ray projectileRay = default(Ray); projectileRay.origin = transform.position; projectileRay.direction = GetAimRay().direction; float maxDistance = 1000f; if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask)) { projectileRay.direction = hitInfo.point - transform.position; } FireBlob(projectileRay, 0f, 0f); } } if (stopwatch >= baseDuration && base.isAuthority) { outer.SetNextStateToMain(); } } } } namespace EntityStates.GravekeeperBoss { public class FireHook : BaseState { public static float baseDuration = 3f; public static string soundString; public static string muzzleString; public static float projectileDamageCoefficient; public static GameObject muzzleflashEffectPrefab; public static GameObject projectilePrefab; public static float spread; public static int projectileCount; public static float projectileForce; private float duration; private Animator modelAnimator; public override void OnEnter() { base.OnEnter(); base.fixedAge = 0f; duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayCrossfade("Body", "FireHook", "FireHook.playbackRate", duration, 0.03f); } ChildLocator component = modelAnimator.GetComponent(); if ((bool)component) { component.FindChild(muzzleString); } Util.PlayAttackSpeedSound(soundString, base.gameObject, attackSpeedStat); EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); Ray aimRay = GetAimRay(); if (NetworkServer.active) { FireSingleHook(aimRay, 0f, 0f); for (int i = 0; i < projectileCount; i++) { float bonusPitch = UnityEngine.Random.Range(0f - spread, spread) / 2f; float bonusYaw = UnityEngine.Random.Range(0f - spread, spread) / 2f; FireSingleHook(aimRay, bonusPitch, bonusYaw); } } } private void FireSingleHook(Ray aimRay, float bonusPitch, float bonusYaw) { UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw, bonusPitch); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * projectileDamageCoefficient, projectileForce, Util.CheckRoll(critStat, base.characterBody.master)); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class PrepHook : BaseState { public static float baseDuration = 3f; public static GameObject chargeEffectPrefab; public static string muzzleString; public static string attackString; private float duration; private GameObject chargeInstance; private Animator modelAnimator; private EffectManagerHelper _emh_chargeInstance; public override void Reset() { base.Reset(); duration = 0f; chargeInstance = null; modelAnimator = null; _emh_chargeInstance = null; } public override void OnEnter() { base.OnEnter(); base.fixedAge = 0f; duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayCrossfade("Body", "PrepHook", "PrepHook.playbackRate", duration, 0.5f); modelAnimator.GetComponent().enabled = true; } if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.inputBank.aimDirection; } if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(muzzleString); if ((bool)transform && (bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation); chargeInstance = _emh_chargeInstance.gameObject; } chargeInstance.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeInstance.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } } } Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new FireHook()); } } public override void OnExit() { if ((bool)chargeInstance) { if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null) { _emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance); } else { EntityState.Destroy(chargeInstance); } chargeInstance = null; _emh_chargeInstance = null; } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class SpawnState : BaseState { public static float duration = 4f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "Root", transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.GrandParentSun { public abstract class GrandParentSunBase : BaseState { [SerializeField] public GameObject enterEffectPrefab; protected GrandParentSunController sunController { get; private set; } protected Transform vfxRoot { get; private set; } protected virtual bool shouldEnableSunController => false; protected abstract float desiredVfxScale { get; } public override void OnEnter() { base.OnEnter(); sunController = GetComponent(); sunController.enabled = shouldEnableSunController; vfxRoot = base.transform.Find("VfxRoot"); if ((bool)enterEffectPrefab) { EffectManager.SimpleImpactEffect(enterEffectPrefab, vfxRoot.position, UnityEngine.Vector3.up, transmit: false); } SetVfxScale(desiredVfxScale); } public override void Update() { base.Update(); SetVfxScale(desiredVfxScale); } private void SetVfxScale(float newScale) { newScale = Mathf.Max(newScale, 0.01f); if ((bool)vfxRoot && vfxRoot.transform.localScale.x != newScale) { vfxRoot.transform.localScale = new UnityEngine.Vector3(newScale, newScale, newScale); } } } public class GrandParentSunDeath : GrandParentSunBase { public static float baseDuration; private float duration; protected override float desiredVfxScale => 1f - Mathf.Clamp01(base.age / duration); public override void OnEnter() { base.OnEnter(); duration = baseDuration; } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { NetworkServer.Destroy(base.gameObject); } } } public class GrandParentSunMain : GrandParentSunBase { private GenericOwnership ownership; protected override bool shouldEnableSunController => true; protected override float desiredVfxScale => 1f; public override void OnEnter() { base.OnEnter(); ownership = GetComponent(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && !ownership.ownerObject) { outer.SetNextState(new GrandParentSunDeath()); } } } public class GrandParentSunSpawn : GrandParentSunBase { public static float baseDuration; private float duration; protected override float desiredVfxScale => Mathf.Clamp01(base.age / duration); public override void OnEnter() { base.OnEnter(); duration = baseDuration; } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new GrandParentSunMain()); } } } } namespace EntityStates.GrandParentBoss { public class DeathState : EntityStates.ParentMonster.DeathState { } public class FireSecondaryProjectile : BaseState { [SerializeField] public float baseDuration = 3f; [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleEffectPrefab; [SerializeField] public float damageCoefficient; [SerializeField] public float force; [SerializeField] public string muzzleName = "SecondaryProjectileMuzzle"; [SerializeField] public string animationStateName = "FireSecondaryProjectile"; [SerializeField] public string playbackRateParam = "FireSecondaryProjectile.playbackRate"; [SerializeField] public string animationLayerName = "Body"; [SerializeField] public float baseFireDelay; private float duration; private float fireDelay; private bool hasFired; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; fireDelay = baseFireDelay / attackSpeedStat; if (fireDelay <= Time.fixedDeltaTime * 2f) { Fire(); } PlayCrossfade(animationLayerName, animationStateName, playbackRateParam, duration, 0.2f); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!hasFired && base.fixedAge >= fireDelay) { Fire(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void Fire() { hasFired = true; if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false); } if (!base.isAuthority || !projectilePrefab) { return; } Ray aimRay = GetAimRay(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { aimRay.origin = component.FindChild(muzzleName).transform.position; } } ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public class GroundSwipe : BasicMeleeAttack, SteppedSkillDef.IStepSetter { [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public GameObject projectilePrefab; [SerializeField] public float baseChargeStartDelay; [SerializeField] public float baseFireProjectileDelay; [SerializeField] public float projectileDamageCoefficient; [SerializeField] public float projectileForce; [SerializeField] public float maxBullseyeDistance; [SerializeField] public float maxBullseyeAngle; [SerializeField] public float minProjectileDistance; [SerializeField] public float maxProjectileDistance; [SerializeField] public float projectileHorizontalSpeed; [SerializeField] public string chargeSoundName; [SerializeField] public string hitBoxGroupNameLeft; [SerializeField] public string animationLayerName = "Body"; [SerializeField] public string muzzleNameLeft = "SecondaryProjectileMuzzle"; [SerializeField] public string muzzleNameRight = "SecondaryProjectileMuzzle"; [SerializeField] public string animationStateNameLeft = "FireSecondaryProjectile"; [SerializeField] public string animationStateNameRight = "FireSecondaryProjectile"; [SerializeField] public string playbackRateParam = "GroundSwipe.playbackRate"; private GameObject chargeEffectInstance; private bool hasFired; private float chargeStartDelay; private float fireProjectileDelay; private int step; protected ChildLocator childLocator { get; private set; } void SteppedSkillDef.IStepSetter.SetStep(int i) { step = i; } public override void OnEnter() { base.OnEnter(); hasFired = false; chargeStartDelay = baseChargeStartDelay / attackSpeedStat; fireProjectileDelay = baseFireProjectileDelay / attackSpeedStat; childLocator = GetModelChildLocator(); } public override void OnExit() { EntityState.Destroy(chargeEffectInstance); base.OnExit(); } protected override void PlayAnimation() { PlayCrossfade(animationLayerName, GetAnimationStateName(), playbackRateParam, duration, 1f); } public string GetMuzzleName() { if (step % 2 == 0) { return muzzleNameLeft; } return muzzleNameRight; } public string GetAnimationStateName() { if (step % 2 == 0) { return animationStateNameLeft; } return animationStateNameRight; } public override string GetHitBoxGroupName() { if (step % 2 == 0) { return hitBoxGroupNameLeft; } return hitBoxGroupName; } public override void FixedUpdate() { base.FixedUpdate(); if (!chargeEffectInstance && (bool)childLocator && base.fixedAge >= chargeStartDelay) { Transform transform = childLocator.FindChild(GetMuzzleName()) ?? base.characterBody.coreTransform; if ((bool)transform) { if ((bool)chargeEffectPrefab) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent(); ObjectScaleCurve component2 = chargeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } if ((bool)component2) { component2.timeMax = duration; } } if (chargeSoundName != null) { Util.PlaySound(chargeSoundName, base.gameObject); } } } if (base.isAuthority && !hasFired && (bool)projectilePrefab && base.fixedAge >= fireProjectileDelay) { hasFired = true; Ray aimRay = GetAimRay(); Ray ray = aimRay; Transform transform2 = childLocator.FindChild(GetMuzzleName()); if ((bool)transform2) { ray.origin = transform2.position; } BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.viewer = base.characterBody; bullseyeSearch.searchOrigin = base.characterBody.corePosition; bullseyeSearch.searchDirection = base.characterBody.corePosition; bullseyeSearch.maxDistanceFilter = maxBullseyeDistance; bullseyeSearch.maxAngleFilter = maxBullseyeAngle; bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam()); bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle; bullseyeSearch.RefreshCandidates(); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); UnityEngine.Vector3? vector = null; RaycastHit hitInfo; if ((bool)hurtBox) { vector = hurtBox.transform.position; } else if (Physics.Raycast(aimRay, out hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { vector = hitInfo.point; } FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = ray.origin; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * projectileDamageCoefficient; fireProjectileInfo.force = projectileForce; fireProjectileInfo.crit = RollCrit(); FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; if (vector.HasValue) { UnityEngine.Vector3 vector2 = vector.Value - ray.origin; UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z); float magnitude = vector3.magnitude; UnityEngine.Vector2 vector4 = vector3 / magnitude; magnitude = Mathf.Clamp(magnitude, minProjectileDistance, maxProjectileDistance); float y = Trajectory.CalculateInitialYSpeed(magnitude / projectileHorizontalSpeed, vector2.y); UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector4.x * projectileHorizontalSpeed, y, vector4.y * projectileHorizontalSpeed); fireProjectileInfo2.speedOverride = direction.magnitude; ray.direction = direction; } else { fireProjectileInfo2.speedOverride = projectileHorizontalSpeed; } fireProjectileInfo2.rotation = Util.QuaternionSafeLookRotation(ray.direction); ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } } } public class Offspring : BaseState { [SerializeField] public GameObject SpawnerPodsPrefab; public static float randomRadius = 8f; public static float maxRange = 9999f; private Animator animator; private ChildLocator childLocator; private Transform modelTransform; private float duration; public static float baseDuration = 3.5f; public static string attackSoundString; private float summonInterval; private static float summonDuration = 3.26f; public static int maxSummonCount = 5; private float summonTimer; private bool isSummoning; private int summonCount; public static GameObject spawnEffect; private static int SpawnPodWarnStateHash = Animator.StringToHash("SpawnPodWarn"); private static int SpawnPodWarnParamHash = Animator.StringToHash("spawnPodWarn.playbackRate"); public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); duration = baseDuration; Util.PlaySound(attackSoundString, base.gameObject); summonInterval = summonDuration / (float)maxSummonCount; isSummoning = true; } public override void FixedUpdate() { base.FixedUpdate(); if (isSummoning) { summonTimer += GetDeltaTime(); if (NetworkServer.active && summonTimer > 0f && summonCount < maxSummonCount) { summonCount++; summonTimer -= summonInterval; SpawnPods(); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void SpawnPods() { UnityEngine.Vector3 zero = UnityEngine.Vector3.zero; Ray aimRay = GetAimRay(); aimRay.origin += UnityEngine.Random.insideUnitSphere * randomRadius; if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask)) { zero = hitInfo.point; } zero = base.transform.position; Transform transform = FindTargetFarthest(zero, GetTeam()); if ((bool)transform) { DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load("SpawnCards/CharacterSpawnCards/cscParentPod"), new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = 3f, maxDistance = 20f, spawnOnTarget = transform }, RoR2Application.rng); directorSpawnRequest.summonerBodyObject = base.gameObject; directorSpawnRequest.onSpawnedServer = (Action)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action)delegate(SpawnCard.SpawnResult spawnResult) { RoR2.Inventory inventory = spawnResult.spawnedInstance.GetComponent().inventory; RoR2.Inventory inventory2 = base.characterBody.inventory; inventory.CopyEquipmentFrom(inventory2); }); DirectorCore.instance.TrySpawnObject(directorSpawnRequest); PlayAnimation("Body", SpawnPodWarnStateHash, SpawnPodWarnParamHash, duration); } } private Transform FindTargetFarthest(UnityEngine.Vector3 point, TeamIndex myTeam) { float num = 0f; Transform result = null; TeamMask enemyTeams = TeamMask.GetEnemyTeams(myTeam); for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++) { if (!enemyTeams.HasTeam(teamIndex)) { ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamIndex); for (int i = 0; i < teamMembers.Count; i++) { float num2 = UnityEngine.Vector3.Magnitude(teamMembers[i].transform.position - point); if (num2 > num && num2 < maxRange) { num = num2; result = teamMembers[i].transform; } } } } return result; } } public class PortalFist : BaseState { public static float baseDuration; public static GameObject portalInEffectPrefab; public static GameObject portalOutEffectPrefab; public static string portalMuzzleString; public static string fistMeshChildLocatorString; public static string fistBoneChildLocatorString; public static string mecanimFistVisibilityString; public static float fistOverlayDuration; public static Material fistOverlayMaterial; public static float targetSearchMaxDistance; private GameObject fistMeshGameObject; private GameObject fistBoneGameObject; private GameObject fistTargetGameObject; private string fistTargetMuzzleString; private Animator modelAnimator; private CharacterModel characterModel; private float duration; private bool fistWasOutOfPortal = true; public override void OnEnter() { base.OnEnter(); fistMeshGameObject = FindModelChild(fistMeshChildLocatorString).gameObject; fistBoneGameObject = FindModelChild(fistBoneChildLocatorString).gameObject; modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { characterModel = modelTransform.GetComponent(); } duration = baseDuration / attackSpeedStat; PlayCrossfade("Body", "PortalFist", "PortalFist.playbackRate", duration, 0.3f); Transform transform = FindModelChild("PortalFistTargetRig"); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.viewer = base.characterBody; bullseyeSearch.searchOrigin = base.characterBody.corePosition; bullseyeSearch.searchDirection = base.characterBody.corePosition; bullseyeSearch.maxDistanceFilter = targetSearchMaxDistance; bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam()); bullseyeSearch.teamMaskFilter.RemoveTeam(TeamIndex.Neutral); bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle; bullseyeSearch.RefreshCandidates(); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); if ((bool)hurtBox) { transform.position = hurtBox.transform.position; fistTargetMuzzleString = $"PortalFistTargetPosition{UnityEngine.Random.Range(1, 5).ToString()}"; fistTargetGameObject = FindModelChild(fistTargetMuzzleString).gameObject; } } public override void Update() { base.Update(); bool flag = modelAnimator.GetFloat(mecanimFistVisibilityString) > 0.5f; if (flag != fistWasOutOfPortal) { fistWasOutOfPortal = flag; EffectManager.SimpleMuzzleFlash(flag ? portalOutEffectPrefab : portalInEffectPrefab, base.gameObject, portalMuzzleString, transmit: false); EffectManager.SimpleMuzzleFlash(flag ? portalOutEffectPrefab : portalInEffectPrefab, base.gameObject, fistTargetMuzzleString, transmit: false); if ((bool)characterModel && (bool)fistOverlayMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(characterModel.gameObject); temporaryOverlayInstance.duration = fistOverlayDuration; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = fistOverlayMaterial; temporaryOverlayInstance.inspectorCharacterModel = characterModel; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } } if ((bool)fistTargetGameObject && !flag) { fistBoneGameObject.transform.SetPositionAndRotation(fistTargetGameObject.transform.position, fistTargetGameObject.transform.rotation); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } } public class PortalJump : BaseState { private BullseyeSearch enemyFinder; public static float duration = 3f; public static float retreatDuration = 2.433f; public static float emergeDuration = 2.933f; public static float portalScaleDuration = 2f; public static float effectsDuration = 2f; private bool retreatDone; private bool teleported; private bool canMoveDuringTeleport; private bool hasEmerged; private HurtBox foundBullseye; public static float telezoneRadius; public static float skillDistance = 2000f; private float stopwatch; private UnityEngine.Vector3 destinationPressence = UnityEngine.Vector3.zero; private UnityEngine.Vector3 startPressence = UnityEngine.Vector3.zero; private Transform modelTransform; private Animator animator; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; public static GameObject jumpInEffectPrefab; public static GameObject jumpOutEffectPrefab; public static UnityEngine.Vector3 teleportOffset; private GrandparentEnergyFXController FXController; private static int RetreatStateHash = Animator.StringToHash("Retreat"); private static int RetreatParamHash = Animator.StringToHash("retreat.playbackRate"); private static int EmergeStateHash = Animator.StringToHash("Emerge"); private static int EmergeParamHash = Animator.StringToHash("emerge.playbackRate"); public override void OnEnter() { base.OnEnter(); modelTransform = GetModelTransform(); if ((bool)modelTransform) { animator = modelTransform.GetComponent(); characterModel = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); PlayAnimation("Body", RetreatStateHash, RetreatParamHash, retreatDuration); EffectData effectData = new EffectData { origin = base.characterBody.modelLocator.modelTransform.GetComponent().FindChild("Portal").position }; EffectManager.SpawnEffect(jumpInEffectPrefab, effectData, transmit: true); } FXController = base.characterBody.GetComponent(); if ((bool)FXController) { FXController.portalObject = base.characterBody.modelLocator.modelTransform.GetComponent().FindChild("Portal").GetComponentInChildren() .gameObject; } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= retreatDuration && !retreatDone) { retreatDone = true; if ((bool)FXController) { ScaleObject(FXController.portalObject, scaleUp: false); } } if (stopwatch >= retreatDuration + portalScaleDuration && !teleported) { teleported = true; canMoveDuringTeleport = true; if ((bool)FXController) { FXController.portalObject.GetComponent().enabled = false; } DoTeleport(); } if ((bool)base.characterMotor && (bool)base.characterDirection) { base.characterMotor.velocity = UnityEngine.Vector3.zero; } if (canMoveDuringTeleport) { SetPosition(UnityEngine.Vector3.Lerp(startPressence, destinationPressence, stopwatch / duration)); } if (stopwatch >= retreatDuration + portalScaleDuration + duration && canMoveDuringTeleport) { canMoveDuringTeleport = false; if ((bool)FXController) { FXController.portalObject.transform.position = base.characterBody.modelLocator.modelTransform.GetComponent().FindChild("Portal").position; ScaleObject(FXController.portalObject, scaleUp: true); } } if (stopwatch >= retreatDuration + portalScaleDuration * 2f + duration && !hasEmerged) { hasEmerged = true; if ((bool)FXController) { FXController.portalObject.GetComponent().enabled = false; } modelTransform = GetModelTransform(); if ((bool)modelTransform) { PlayAnimation("Body", EmergeStateHash, EmergeParamHash, duration); EffectData effectData = new EffectData { origin = base.characterBody.modelLocator.modelTransform.GetComponent().FindChild("Portal").position }; EffectManager.SpawnEffect(jumpOutEffectPrefab, effectData, transmit: true); if ((bool)characterModel) { characterModel.invisibilityCount--; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)base.characterMotor) { base.characterMotor.enabled = true; } } } if (stopwatch >= retreatDuration + portalScaleDuration * 2f + duration + emergeDuration && base.isAuthority) { outer.SetNextStateToMain(); } } private void DoTeleport() { Ray aimRay = GetAimRay(); enemyFinder = new BullseyeSearch(); enemyFinder.maxDistanceFilter = skillDistance; enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.filterByLoS = false; enemyFinder.sortMode = BullseyeSearch.SortMode.Distance; enemyFinder.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } enemyFinder.RefreshCandidates(); foundBullseye = enemyFinder.GetResults().LastOrDefault(); modelTransform = GetModelTransform(); if ((bool)characterModel) { characterModel.invisibilityCount++; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)base.characterMotor) { base.characterMotor.enabled = false; } UnityEngine.Vector3 vector = base.inputBank.moveVector * skillDistance; destinationPressence = base.transform.position; startPressence = base.transform.position; NodeGraph groundNodes = SceneInfo.instance.groundNodes; UnityEngine.Vector3 position = startPressence + vector; if ((bool)foundBullseye) { position = foundBullseye.transform.position; } NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(position, base.characterBody.hullClassification); groundNodes.GetNodePosition(nodeIndex, out destinationPressence); destinationPressence += base.transform.position - base.characterBody.footPosition; } private void SetPosition(UnityEngine.Vector3 newPosition) { if ((bool)base.characterMotor) { base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity); } } private void ScaleObject(GameObject objectToScaleDown, bool scaleUp) { float valueEnd = (scaleUp ? 1f : 0f); float valueStart = (scaleUp ? 0f : 1f); ObjectScaleCurve component = objectToScaleDown.GetComponent(); component.timeMax = portalScaleDuration; component.curveX = AnimationCurve.Linear(0f, valueStart, 1f, valueEnd); component.curveY = AnimationCurve.Linear(0f, valueStart, 1f, valueEnd); component.curveZ = AnimationCurve.Linear(0f, valueStart, 1f, valueEnd); component.overallCurve = AnimationCurve.EaseInOut(0f, valueStart, 1f, valueEnd); component.enabled = true; } public override void OnExit() { base.OnExit(); } } public class SpawnState : GenericCharacterSpawnState { public static GameObject preSpawnEffect; public static string preSpawnEffectMuzzle; public static float preSpawnDuration; public static GameObject spawnEffect; public static string spawnEffectMuzzle; public static Material spawnOverlayMaterial; public static float spawnOverlayDuration; public static float blastAttackRadius; public static float blastAttackForce; public static float blastAttackBonusForce; private bool hasSpawned; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private bool preSpawnIsDone; private static int Spawn1StateHash = Animator.StringToHash("Spawn1"); private static int Spawn1ParamHash = Animator.StringToHash("Spawn1.playbackRate"); private bool isInvisible; public override void OnEnter() { base.OnEnter(); characterModel = base.modelLocator.modelTransform.GetComponent(); hurtboxGroup = base.modelLocator.modelTransform.GetComponent(); ToggleInvisibility(newInvisible: true); if ((bool)preSpawnEffect) { EffectManager.SimpleMuzzleFlash(preSpawnEffect, base.gameObject, preSpawnEffectMuzzle, transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (!preSpawnIsDone && base.fixedAge > preSpawnDuration) { preSpawnIsDone = true; ToggleInvisibility(newInvisible: false); PlayAnimation("Body", Spawn1StateHash, Spawn1ParamHash, duration - preSpawnDuration); if ((bool)spawnEffect) { EffectManager.SimpleMuzzleFlash(spawnEffect, base.gameObject, spawnEffectMuzzle, transmit: false); } if (base.isAuthority) { BlastAttack obj = new BlastAttack { attacker = base.gameObject, inflictor = base.gameObject }; obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker); obj.position = base.characterBody.corePosition; obj.procCoefficient = 1f; obj.radius = blastAttackRadius; obj.baseForce = blastAttackForce; obj.bonusForce = UnityEngine.Vector3.up * blastAttackBonusForce; obj.baseDamage = 0f; obj.falloffModel = BlastAttack.FalloffModel.Linear; obj.damageColorIndex = DamageColorIndex.Item; obj.attackerFiltering = AttackerFiltering.NeverHitSelf; obj.Fire(); } if ((bool)characterModel && (bool)spawnOverlayMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(characterModel.gameObject); temporaryOverlayInstance.duration = spawnOverlayDuration; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = spawnOverlayMaterial; temporaryOverlayInstance.inspectorCharacterModel = characterModel; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } } } private void ToggleInvisibility(bool newInvisible) { if (isInvisible != newInvisible) { isInvisible = newInvisible; if ((bool)characterModel) { characterModel.invisibilityCount += (isInvisible ? 1 : (-1)); } if ((bool)hurtboxGroup) { hurtboxGroup.hurtBoxesDeactivatorCounter += (isInvisible ? 1 : (-1)); } } } public override void OnExit() { ToggleInvisibility(newInvisible: false); base.OnExit(); } } public class SpiritPull : BaseState { private BullseyeSearch enemyFinder; public static float lockOnAngle; private UnityEngine.Vector3 teleporterIndicatorInstance; private Transform modelTransform; public static float pullTimer; public static float zoneRadius; public static float initialDelay; private float duration = 4f; public static float maxRange; public static string teleportZoneString; public static GameObject teleportZoneEffect; public static GameObject playerTeleportEffect; public static float effectsDuration = 2f; public static float playerTeleportEffectsDuration = 1f; private bool effectsDone; private bool gatheredVictims; private bool teleported; private float stopwatch; private List Startpositions; private List Endpositions; public static int stacks; private List results = new List(); private HurtBox foundBullseye; private BullseyeSearch search; private GameObject spiritPullLocationObject; public static string indicatorOnPlayerSoundLoop; public static string indicatorOnPlayerSoundStop; public static string teleportedPlayerSound; public override void OnEnter() { base.OnEnter(); Startpositions = new List(); Endpositions = new List(); Ray aimRay = GetAimRay(); modelTransform = GetModelTransform(); enemyFinder = new BullseyeSearch(); enemyFinder.maxDistanceFilter = 2000f; enemyFinder.maxAngleFilter = lockOnAngle; enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.filterByLoS = false; enemyFinder.sortMode = BullseyeSearch.SortMode.Distance; enemyFinder.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } enemyFinder.RefreshCandidates(); foundBullseye = enemyFinder.GetResults().LastOrDefault(); _ = UnityEngine.Vector3.zero; if ((bool)foundBullseye) { teleporterIndicatorInstance = foundBullseye.transform.position; if (Physics.Raycast(teleporterIndicatorInstance, UnityEngine.Vector3.down, out var hitInfo, 500f, LayerIndex.world.mask)) { teleporterIndicatorInstance = hitInfo.point; _ = teleporterIndicatorInstance; } EffectData effectData = new EffectData { origin = teleporterIndicatorInstance, rotation = teleportZoneEffect.transform.rotation, scale = zoneRadius * 2f }; EffectManager.SpawnEffect(teleportZoneEffect, effectData, transmit: true); if (spiritPullLocationObject == null) { spiritPullLocationObject = new GameObject(); } spiritPullLocationObject.transform.position = effectData.origin; Util.PlaySound(indicatorOnPlayerSoundLoop, spiritPullLocationObject); } } private Transform FindTargetFarthest(UnityEngine.Vector3 point, TeamIndex enemyTeam) { ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(enemyTeam); float num = 0f; Transform result = null; for (int i = 0; i < teamMembers.Count; i++) { float num2 = UnityEngine.Vector3.SqrMagnitude(teamMembers[i].transform.position - point); if (num2 > num && num2 < maxRange) { num = num2; result = teamMembers[i].transform; } } return result; } public override void FixedUpdate() { base.FixedUpdate(); pullTimer -= Time.deltaTime; base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= effectsDuration && !gatheredVictims) { effectsDone = true; gatheredVictims = true; GetPlayersInsideTeleportZone(); } if (stopwatch >= effectsDuration + playerTeleportEffectsDuration && !teleported) { teleported = true; TeleportPlayers(); } if ((bool)base.characterMotor && (bool)base.characterDirection) { base.characterMotor.velocity = UnityEngine.Vector3.zero; } if (effectsDone) { SetPositions(); } if (stopwatch >= effectsDuration + playerTeleportEffectsDuration + duration && base.isAuthority) { effectsDone = false; outer.SetNextStateToMain(); } } private void GetPlayersInsideTeleportZone() { Startpositions.Clear(); Endpositions.Clear(); if (!foundBullseye) { return; } for (int i = 0; i < stacks; i++) { search = new BullseyeSearch(); search.filterByLoS = false; search.maxDistanceFilter = zoneRadius; search.searchOrigin = new UnityEngine.Vector3(teleporterIndicatorInstance.x, teleporterIndicatorInstance.y + zoneRadius * (float)i, teleporterIndicatorInstance.z); search.sortMode = BullseyeSearch.SortMode.Distance; search.teamMaskFilter = TeamMask.allButNeutral; search.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); search.RefreshCandidates(); search.queryTriggerInteraction = QueryTriggerInteraction.Collide; for (int j = 0; j < search.GetResults().ToList().Count; j++) { if (!results.Contains(search.GetResults().ToList()[j])) { results.Add(search.GetResults().ToList()[j]); } } } if (results.Count <= 0) { return; } for (int k = 0; k < results.Count; k++) { HurtBox hurtBox = results[k]; Transform transform = hurtBox.healthComponent.body.modelLocator.modelTransform; EffectData effectData = new EffectData { origin = hurtBox.healthComponent.body.footPosition }; EffectManager.SpawnEffect(playerTeleportEffect, effectData, transmit: true); if ((bool)transform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(transform.gameObject); temporaryOverlayInstance.duration = 0.6f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matGrandparentTeleportFlash"); temporaryOverlayInstance.AddToCharacterModel(transform.GetComponent()); } } } private void TeleportPlayers() { if (results.Count <= 0) { return; } for (int i = 0; i < results.Count; i++) { HurtBox hurtBox = results[i]; CharacterModel component = hurtBox.healthComponent.body.modelLocator.modelTransform.GetComponent(); HurtBoxGroup component2 = hurtBox.healthComponent.body.modelLocator.modelTransform.GetComponent(); Startpositions.Add(hurtBox.transform.position); if ((bool)component2) { int hurtBoxesDeactivatorCounter = component2.hurtBoxesDeactivatorCounter + 1; component2.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)component) { component.invisibilityCount++; } CharacterMotor component3 = hurtBox.healthComponent.gameObject.GetComponent(); if ((bool)component3) { component3.enabled = false; } duration = initialDelay; GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(base.gameObject); if ((bool)teleportEffectPrefab) { UnityEngine.Object.Instantiate(teleportEffectPrefab, base.gameObject.transform.position, UnityEngine.Quaternion.identity); } Util.PlaySound(teleportedPlayerSound, hurtBox.gameObject); base.characterMotor.velocity = UnityEngine.Vector3.zero; UnityEngine.Vector3 position = base.characterBody.modelLocator.modelTransform.GetComponent().FindChild(teleportZoneString).position; NodeGraph groundNodes = SceneInfo.instance.groundNodes; NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(position, base.characterBody.hullClassification); groundNodes.GetNodePosition(nodeIndex, out position); position += hurtBox.healthComponent.body.transform.position - hurtBox.healthComponent.body.footPosition; position = new UnityEngine.Vector3(position.x, position.y + 0.1f, position.z); Endpositions.Add(position); } } private void SetPositions() { if (results.Count <= 0) { return; } for (int i = 0; i < results.Count; i++) { CharacterMotor component = results[i].healthComponent.gameObject.GetComponent(); if ((bool)component) { UnityEngine.Vector3 position = UnityEngine.Vector3.Lerp(Startpositions[i], Endpositions[i], stopwatch / duration); component.Motor.SetPositionAndRotation(position, UnityEngine.Quaternion.identity); } } } public override void OnExit() { base.OnExit(); Util.PlaySound(indicatorOnPlayerSoundStop, spiritPullLocationObject); if (results.Count <= 0) { return; } for (int i = 0; i < results.Count; i++) { HurtBox hurtBox = results[i]; CharacterModel component = hurtBox.healthComponent.body.modelLocator.modelTransform.GetComponent(); HurtBoxGroup component2 = hurtBox.healthComponent.body.modelLocator.modelTransform.GetComponent(); Transform transform = hurtBox.healthComponent.body.modelLocator.modelTransform; if ((bool)transform) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(transform.gameObject); temporaryOverlayInstance.duration = 0.6f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matGrandparentTeleportFlash"); temporaryOverlayInstance.AddToCharacterModel(transform.GetComponent()); } EffectData effectData = new EffectData { origin = hurtBox.healthComponent.body.footPosition }; EffectManager.SpawnEffect(playerTeleportEffect, effectData, transmit: true); if ((bool)component2) { int hurtBoxesDeactivatorCounter = component2.hurtBoxesDeactivatorCounter - 1; component2.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)component) { component.invisibilityCount--; } CharacterMotor component3 = hurtBox.healthComponent.gameObject.GetComponent(); if ((bool)component3) { component3.enabled = true; } } } } } namespace EntityStates.GrandParent { public class ChannelSun : ChannelSunBase { public static string animLayerName; public static string animStateName; public static GameObject sunPrefab; public static float sunPrefabDiameter = 10f; public static float sunPlacementMinDistance = 100f; public static float sunPlacementIdealAltitudeBonus = 200f; private GameObject sunInstance; public UnityEngine.Vector3? sunSpawnPosition; public override void OnEnter() { base.OnEnter(); PlayAnimation(animLayerName, animStateName); if (NetworkServer.active) { sunSpawnPosition = sunSpawnPosition ?? FindSunSpawnPosition(base.transform.position); if (sunSpawnPosition.HasValue) { sunInstance = CreateSun(sunSpawnPosition.Value); } } } public override void OnExit() { if (NetworkServer.active && (bool)sunInstance) { sunInstance.GetComponent().ownerObject = null; sunInstance = null; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && !IsKeyDownAuthority()) { outer.SetNextState(new ChannelSunEnd()); } } private GameObject CreateSun(UnityEngine.Vector3 sunSpawnPosition) { GameObject obj = UnityEngine.Object.Instantiate(sunPrefab, sunSpawnPosition, UnityEngine.Quaternion.identity); obj.GetComponent().ownerObject = base.gameObject; NetworkServer.Spawn(obj); return obj; } private static UnityEngine.Vector3? FindSunNodePosition(UnityEngine.Vector3 searchOrigin) { NodeGraph airNodes = SceneInfo.instance.airNodes; NodeGraph.NodeIndex nodeIndex = airNodes.FindClosestNodeWithFlagConditions(searchOrigin, HullClassification.Golem, NodeFlags.None, NodeFlags.None, preventOverhead: false); if (nodeIndex == NodeGraph.NodeIndex.invalid) { return null; } float num = sunPlacementMinDistance; float num2 = num * num; _ = NodeGraph.NodeIndex.invalid; float num3 = 0f; NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(airNodes, HullMask.Golem); nodeGraphSpider.AddNodeForNextStep(nodeIndex); int num4 = 0; int i = 0; while (nodeGraphSpider.PerformStep()) { num4++; for (; i < nodeGraphSpider.collectedSteps.Count; i++) { NodeGraphSpider.StepInfo stepInfo = nodeGraphSpider.collectedSteps[i]; airNodes.GetNodePosition(stepInfo.node, out var position); float sqrMagnitude = (position - searchOrigin).sqrMagnitude; if (sqrMagnitude > num3) { num3 = sqrMagnitude; _ = stepInfo.node; if (num3 >= num2) { return position; } } } } return null; } public static UnityEngine.Vector3? FindSunSpawnPosition(UnityEngine.Vector3 searchOrigin) { UnityEngine.Vector3? vector = FindSunNodePosition(searchOrigin); if (vector.HasValue) { UnityEngine.Vector3 value = vector.Value; float num = sunPlacementIdealAltitudeBonus; float num2 = sunPrefabDiameter * 0.5f; if (Physics.Raycast(value, UnityEngine.Vector3.up, out var hitInfo, sunPlacementIdealAltitudeBonus + num2, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { num = Mathf.Clamp(hitInfo.distance - num2, 0f, num); } value.y += num; return value; } return null; } } public abstract class ChannelSunBase : BaseSkillState { [SerializeField] public GameObject handVfxPrefab; public static string leftHandVfxTargetNameInChildLocator; public static string rightHandVfxTargetNameInChildLocator; private GameObject leftHandVfxInstance; private GameObject rightHandVfxInstance; public override void OnEnter() { base.OnEnter(); if ((bool)handVfxPrefab) { ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { CreateVfxInstanceForHand(modelChildLocator, leftHandVfxTargetNameInChildLocator, ref leftHandVfxInstance); CreateVfxInstanceForHand(modelChildLocator, rightHandVfxTargetNameInChildLocator, ref rightHandVfxInstance); } } } public override void OnExit() { DestroyVfxInstance(ref leftHandVfxInstance); DestroyVfxInstance(ref rightHandVfxInstance); base.OnExit(); } protected void CreateVfxInstanceForHand(ChildLocator childLocator, string nameInChildLocator, ref GameObject dest) { Transform transform = childLocator.FindChild(nameInChildLocator); if ((bool)transform) { dest = UnityEngine.Object.Instantiate(handVfxPrefab, transform); } else { dest = null; } } protected void DestroyVfxInstance(ref GameObject vfxInstance) { EntityState.Destroy(vfxInstance); vfxInstance = null; } } public class ChannelSunEnd : ChannelSunBase { public static string animLayerName; public static string animStateName; public static string animPlaybackRateParam; public static float baseDuration; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animLayerName, animStateName, animPlaybackRateParam, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } public class ChannelSunStart : ChannelSunBase { public static string animLayerName; public static string animStateName; public static string animPlaybackRateParam; public static string beginSoundName; public static float baseDuration; public static GameObject beamVfxPrefab; private float duration; private UnityEngine.Vector3? sunSpawnPosition; private ParticleSystem leftHandBeamParticleSystem; private ParticleSystem rightHandBeamParticleSystem; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation(animLayerName, animStateName, animPlaybackRateParam, duration); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { AimAnimator component = modelTransform.GetComponent(); if ((bool)component) { component.enabled = true; } } if (base.isAuthority) { sunSpawnPosition = sunSpawnPosition ?? ChannelSun.FindSunSpawnPosition(base.transform.position); } ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator && sunSpawnPosition.HasValue) { CreateBeamEffect(modelChildLocator, ChannelSunBase.leftHandVfxTargetNameInChildLocator, sunSpawnPosition.Value, ref leftHandBeamParticleSystem); CreateBeamEffect(modelChildLocator, ChannelSunBase.rightHandVfxTargetNameInChildLocator, sunSpawnPosition.Value, ref rightHandBeamParticleSystem); } if (beginSoundName != null) { Util.PlaySound(beginSoundName, base.gameObject); } } public override void OnExit() { EndBeamEffect(ref leftHandBeamParticleSystem); EndBeamEffect(ref rightHandBeamParticleSystem); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new ChannelSun { activatorSkillSlot = base.activatorSkillSlot, sunSpawnPosition = sunSpawnPosition }); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(sunSpawnPosition.HasValue); if (sunSpawnPosition.HasValue) { writer.Write(sunSpawnPosition.Value); } } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); sunSpawnPosition = null; if (reader.ReadBoolean()) { sunSpawnPosition = reader.ReadVector3(); } } private void CreateBeamEffect(ChildLocator childLocator, string nameInChildLocator, UnityEngine.Vector3 targetPosition, ref ParticleSystem dest) { Transform transform = childLocator.FindChild(nameInChildLocator); if ((bool)transform) { ChildLocator component = UnityEngine.Object.Instantiate(beamVfxPrefab, transform).GetComponent(); component.FindChild("EndPoint").SetPositionAndRotation(targetPosition, UnityEngine.Quaternion.identity); Transform transform2 = component.FindChild("BeamParticles"); dest = transform2.GetComponent(); } else { dest = null; } } private void EndBeamEffect(ref ParticleSystem particleSystem) { if ((bool)particleSystem) { ParticleSystem.MainModule main = particleSystem.main; main.loop = false; particleSystem.Stop(); } particleSystem = null; } } } namespace EntityStates.TitanMonster { public class ChargeGoldMegaLaser : ChargeMegaLaser { public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireGoldMegaLaser nextState = new FireGoldMegaLaser(); outer.SetNextState(nextState); } } } public class ChargeMegaLaser : BaseState { public static float baseDuration = 3f; public static float laserMaxWidth = 0.2f; [SerializeField] public GameObject effectPrefab; [SerializeField] public GameObject laserPrefab; public static string chargeAttackSoundString; public static float lockOnAngle; private HurtBox lockedOnHurtBox; public float duration; private GameObject chargeEffect; private GameObject laserEffect; private LineRenderer laserLineComponent; private UnityEngine.Vector3 visualEndPosition; private float flashTimer; private bool laserOn; private BullseyeSearch enemyFinder; private const float originalSoundDuration = 2.1f; private EffectManagerHelper _emh_chargeEffect; private EffectManagerHelper _emh_laserEffect; public override void Reset() { base.Reset(); lockedOnHurtBox = null; duration = 0f; chargeEffect = null; laserEffect = null; laserLineComponent = null; visualEndPosition = UnityEngine.Vector3.zero; flashTimer = 0f; laserOn = false; if (enemyFinder != null) { enemyFinder.Reset(); } _emh_chargeEffect = null; _emh_laserEffect = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(chargeAttackSoundString, base.gameObject, 2.1f / duration); Ray aimRay = GetAimRay(); enemyFinder = new BullseyeSearch(); enemyFinder.maxDistanceFilter = 2000f; enemyFinder.maxAngleFilter = lockOnAngle; enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.filterByLoS = false; enemyFinder.sortMode = BullseyeSearch.SortMode.Angle; enemyFinder.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleLaser"); if ((bool)transform) { if ((bool)effectPrefab) { if (!EffectManager.ShouldUsePooledEffect(effectPrefab)) { chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation); chargeEffect = _emh_chargeEffect.gameObject; } chargeEffect.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffect.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } if ((bool)laserPrefab) { if (!EffectManager.ShouldUsePooledEffect(laserPrefab)) { laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation); } else { _emh_laserEffect = EffectManager.GetAndActivatePooledEffect(laserPrefab, transform.position, transform.rotation); laserEffect = _emh_laserEffect.gameObject; } laserEffect.transform.parent = transform; laserLineComponent = laserEffect.GetComponent(); } } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } flashTimer = 0f; laserOn = true; } public override void OnExit() { base.OnExit(); if ((bool)chargeEffect) { if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null) { _emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect); } else { EntityState.Destroy(chargeEffect); } _emh_chargeEffect = null; chargeEffect = null; } if ((bool)laserEffect) { if (_emh_laserEffect != null && _emh_laserEffect.OwningPool != null) { _emh_laserEffect.OwningPool.ReturnObject(_emh_laserEffect); } else { EntityState.Destroy(laserEffect); } _emh_laserEffect = null; laserEffect = null; } } public override void Update() { base.Update(); if (!laserEffect || !laserLineComponent) { return; } float num = 1000f; Ray aimRay = GetAimRay(); enemyFinder.RefreshCandidates(); lockedOnHurtBox = enemyFinder.GetResults().FirstOrDefault(); if ((bool)lockedOnHurtBox) { aimRay.direction = lockedOnHurtBox.transform.position - aimRay.origin; } UnityEngine.Vector3 position = laserEffect.transform.parent.position; UnityEngine.Vector3 point = aimRay.GetPoint(num); if (Physics.Raycast(aimRay, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault)) { point = hitInfo.point; } laserLineComponent.SetPosition(0, position); laserLineComponent.SetPosition(1, point); float num2; if (duration - base.age > 0.5f) { num2 = base.age / duration; } else { flashTimer -= Time.deltaTime; if (flashTimer <= 0f) { laserOn = !laserOn; flashTimer = 1f / 30f; } num2 = (laserOn ? 1f : 0f); } num2 *= laserMaxWidth; laserLineComponent.startWidth = num2; laserLineComponent.endWidth = num2; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireMegaLaser nextState = new FireMegaLaser(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class DeathState : GenericCharacterDeath { public static GameObject initialEffect; [SerializeField] public GameObject deathEffect; public static float duration = 2f; private float stopwatch; private Transform centerTransform; private Transform modelBaseTransform; private bool attemptedDeathBehavior; private EffectData _effectData; public override void Reset() { base.Reset(); centerTransform = null; modelBaseTransform = null; attemptedDeathBehavior = false; if (_effectData != null) { _effectData.Reset(); } } public override void OnEnter() { base.OnEnter(); if (!base.modelLocator) { return; } ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if ((bool)component) { centerTransform = component.FindChild("Center"); if ((bool)initialEffect) { if (!EffectManager.ShouldUsePooledEffect(initialEffect)) { GameObject obj = UnityEngine.Object.Instantiate(initialEffect, centerTransform.position, centerTransform.rotation); obj.GetComponent().newDuration = duration + 2f; obj.transform.parent = centerTransform; } else { EffectManager.GetAndActivatePooledEffect(initialEffect, centerTransform.position, centerTransform.rotation, centerTransform).gameObject.GetComponent().newDuration = duration + 2f; } } } modelBaseTransform = base.modelLocator.modelBaseTransform; } private void AttemptDeathBehavior() { if (attemptedDeathBehavior) { return; } attemptedDeathBehavior = true; if ((bool)deathEffect && NetworkServer.active) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.origin = centerTransform.position; EffectManager.SpawnEffect(deathEffect, _effectData, transmit: true); } if ((bool)modelBaseTransform) { EntityState.Destroy(modelBaseTransform.gameObject); modelBaseTransform = null; } if (NetworkServer.active) { EntityState.Destroy(base.gameObject); } } public override void FixedUpdate() { stopwatch += GetDeltaTime(); if (stopwatch >= duration) { AttemptDeathBehavior(); } } public override void OnExit() { if (!outer.destroying) { AttemptDeathBehavior(); } base.OnExit(); } } public class DeathStateGold : DeathState { } public class FireFist : BaseState { private enum SubState { Prep, FireFist, Exit } private class Predictor { private enum ExtrapolationType { None, Linear, Polar } private Transform bodyTransform; private Transform targetTransform; private UnityEngine.Vector3 targetPosition0; private UnityEngine.Vector3 targetPosition1; private UnityEngine.Vector3 targetPosition2; private int collectedPositions; public bool hasTargetTransform => targetTransform; public bool isPredictionReady => collectedPositions > 2; public Predictor(Transform bodyTransform) { this.bodyTransform = bodyTransform; } private void PushTargetPosition(UnityEngine.Vector3 newTargetPosition) { targetPosition2 = targetPosition1; targetPosition1 = targetPosition0; targetPosition0 = newTargetPosition; collectedPositions++; } public void SetTargetTransform(Transform newTargetTransform) { targetTransform = newTargetTransform; targetPosition2 = (targetPosition1 = (targetPosition0 = newTargetTransform.position)); collectedPositions = 1; } public void Update() { if ((bool)targetTransform) { PushTargetPosition(targetTransform.position); } } public bool GetPredictedTargetPosition(float time, out UnityEngine.Vector3 predictedPosition) { UnityEngine.Vector3 vector = targetPosition1 - targetPosition2; UnityEngine.Vector3 vector2 = targetPosition0 - targetPosition1; vector.y = 0f; vector2.y = 0f; ExtrapolationType extrapolationType; if (vector == UnityEngine.Vector3.zero || vector2 == UnityEngine.Vector3.zero) { extrapolationType = ExtrapolationType.None; } else { UnityEngine.Vector3 normalized = vector.normalized; UnityEngine.Vector3 normalized2 = vector2.normalized; extrapolationType = ((UnityEngine.Vector3.Dot(normalized, normalized2) > 0.98f) ? ExtrapolationType.Linear : ExtrapolationType.Polar); } float num = 1f / Time.deltaTime; predictedPosition = targetPosition0; switch (extrapolationType) { case ExtrapolationType.Linear: predictedPosition = targetPosition0 + vector2 * (time * num); break; case ExtrapolationType.Polar: { UnityEngine.Vector3 position = bodyTransform.position; UnityEngine.Vector3 vector3 = Util.Vector3XZToVector2XY(targetPosition2 - position); UnityEngine.Vector3 vector4 = Util.Vector3XZToVector2XY(targetPosition1 - position); UnityEngine.Vector3 vector5 = Util.Vector3XZToVector2XY(targetPosition0 - position); float magnitude = vector3.magnitude; float magnitude2 = vector4.magnitude; float magnitude3 = vector5.magnitude; float num2 = UnityEngine.Vector2.SignedAngle(vector3, vector4) * num; float num3 = UnityEngine.Vector2.SignedAngle(vector4, vector5) * num; float num4 = (magnitude2 - magnitude) * num; float num5 = (magnitude3 - magnitude2) * num; float num6 = (num2 + num3) * 0.5f; float num7 = (num4 + num5) * 0.5f; float num8 = magnitude3 + num7 * time; if (num8 < 0f) { num8 = 0f; } UnityEngine.Vector2 vector6 = Util.RotateVector2(vector5, num6 * time); vector6 *= num8 * magnitude3; predictedPosition = position; predictedPosition.x += vector6.x; predictedPosition.z += vector6.y; break; } } if (Physics.Raycast(new Ray(predictedPosition + UnityEngine.Vector3.up * 1f, UnityEngine.Vector3.down), out var hitInfo, 200f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { predictedPosition = hitInfo.point; return true; } return false; } } public static float entryDuration = 1f; public static float fireDuration = 2f; public static float exitDuration = 1f; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public GameObject fistEffectPrefab; [SerializeField] public GameObject fireEffectPrefab; [SerializeField] public GameObject fistProjectilePrefab; public static float maxDistance = 40f; public static float trackingDuration = 0.5f; public static float fistDamageCoefficient = 2f; public static float fistForce = 2000f; public static string chargeFistAttackSoundString; private bool hasShownPrediction; private bool predictionOk; protected UnityEngine.Vector3 predictedTargetPosition; private AimAnimator aimAnimator; private GameObject chargeEffect; private Transform fistTransform; private float stopwatch; private EffectData _effectData; protected BullseyeSearch enemyFinder; private EffectManagerHelper _emh_chargeEffect; private SubState subState; private Predictor predictor; private GameObject predictorDebug; private static int FireFistStateHash = Animator.StringToHash("FireFist"); public override void Reset() { base.Reset(); hasShownPrediction = false; predictionOk = false; predictedTargetPosition = UnityEngine.Vector3.zero; aimAnimator = null; chargeEffect = null; fistTransform = null; stopwatch = 0f; subState = SubState.Prep; if (_effectData != null) { _effectData.Reset(); } if (enemyFinder != null) { enemyFinder.Reset(); } predictor = null; predictorDebug = null; _emh_chargeEffect = null; } public override void OnEnter() { base.OnEnter(); stopwatch = 0f; if ((bool)base.modelLocator) { ChildLocator component = base.modelLocator.modelTransform.GetComponent(); aimAnimator = base.modelLocator.modelTransform.GetComponent(); if ((bool)aimAnimator) { aimAnimator.enabled = true; } if ((bool)component) { fistTransform = component.FindChild("RightFist"); if ((bool)fistTransform) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeEffect = UnityEngine.Object.Instantiate(chargeEffectPrefab, fistTransform); } else { _emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, fistTransform, inResetLocal: true); chargeEffect = _emh_chargeEffect.gameObject; } } } } subState = SubState.Prep; PlayCrossfade("Body", "PrepFist", "PrepFist.playbackRate", entryDuration, 0.1f); Util.PlayAttackSpeedSound(chargeFistAttackSoundString, base.gameObject, attackSpeedStat); if (NetworkServer.active) { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } bullseyeSearch.maxDistanceFilter = maxDistance; bullseyeSearch.maxAngleFilter = 90f; Ray aimRay = GetAimRay(); bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.filterByLoS = false; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.RefreshCandidates(); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); if ((bool)hurtBox) { predictor = new Predictor(base.transform); predictor.SetTargetTransform(hurtBox.transform); } } } protected void DestroyChargeEffect() { if ((bool)chargeEffect) { if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null) { _emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect); } else { EntityState.Destroy(chargeEffect); } chargeEffect = null; _emh_chargeEffect = null; } } public override void OnExit() { base.OnExit(); DestroyChargeEffect(); EntityState.Destroy(predictorDebug); predictorDebug = null; } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); switch (subState) { case SubState.Prep: if (predictor != null) { predictor.Update(); } if (stopwatch <= trackingDuration) { if (predictor != null) { predictionOk = predictor.GetPredictedTargetPosition(entryDuration - trackingDuration, out predictedTargetPosition); if (predictionOk && (bool)predictorDebug) { predictorDebug.transform.position = predictedTargetPosition; } } } else if (!hasShownPrediction) { hasShownPrediction = true; PlacePredictedAttack(); } if (stopwatch >= entryDuration) { predictor = null; subState = SubState.FireFist; stopwatch = 0f; PlayAnimation("Body", FireFistStateHash); DestroyChargeEffect(); if (!EffectManager.ShouldUsePooledEffect(fireEffectPrefab)) { UnityEngine.Object.Instantiate(fireEffectPrefab, fistTransform.position, UnityEngine.Quaternion.identity, fistTransform); } else { EffectManager.GetAndActivatePooledEffect(fireEffectPrefab, fistTransform.position, UnityEngine.Quaternion.identity, fistTransform); } } break; case SubState.FireFist: if (stopwatch >= fireDuration) { subState = SubState.Exit; stopwatch = 0f; PlayCrossfade("Body", "ExitFist", "ExitFist.playbackRate", exitDuration, 0.3f); } break; case SubState.Exit: if (stopwatch >= exitDuration && base.isAuthority) { outer.SetNextStateToMain(); } break; } } protected virtual void PlacePredictedAttack() { PlaceSingleDelayBlast(predictedTargetPosition, 0f); } protected void PlaceSingleDelayBlast(UnityEngine.Vector3 position, float delay) { if (base.isAuthority) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = fistProjectilePrefab; fireProjectileInfo.position = position; fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * fistDamageCoefficient; fireProjectileInfo.force = fistForce; fireProjectileInfo.crit = base.characterBody.RollCrit(); fireProjectileInfo.fuseOverride = entryDuration - trackingDuration + delay; ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } } public class FireGoldFist : FireFist { public static int fistCount; public static float distanceBetweenFists; public static float delayBetweenFists; protected override void PlacePredictedAttack() { int num = 0; UnityEngine.Vector3 vector = predictedTargetPosition; UnityEngine.Vector3 vector2 = UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f) * UnityEngine.Vector3.forward; for (int i = -(fistCount / 2); i < fistCount / 2; i++) { UnityEngine.Vector3 vector3 = vector + vector2 * distanceBetweenFists * i; float num2 = 60f; if (Physics.Raycast(new Ray(vector3 + UnityEngine.Vector3.up * (num2 / 2f), UnityEngine.Vector3.down), out var hitInfo, num2, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { vector3 = hitInfo.point; } PlaceSingleDelayBlast(vector3, delayBetweenFists * (float)num); num++; } } } public class FireGoldMegaLaser : FireMegaLaser { public static GameObject projectilePrefab; public static float projectileFireFrequency; public static float projectileDamageCoefficient; public static float projectileMinSpread; public static float projectileMaxSpread; private float projectileStopwatch; public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } projectileStopwatch += GetDeltaTime() * attackSpeedStat; if (projectileStopwatch >= 1f / projectileFireFrequency) { Ray ray = GetAimRay(); if ((bool)muzzleTransform) { ray.origin = muzzleTransform.transform.position; } ray.direction = Util.ApplySpread(ray.direction, projectileMinSpread, projectileMaxSpread, 1f, 1f); projectileStopwatch -= 1f / projectileFireFrequency; ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageStat * FireMegaLaser.damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } } public class FireMegaLaser : BaseState { [SerializeField] public GameObject effectPrefab; [SerializeField] public GameObject hitEffectPrefab; [SerializeField] public GameObject laserPrefab; public static string playAttackSoundString; public static string playLoopSoundString; public static string stopLoopSoundString; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float fireFrequency; public static float maxDistance; public static float minimumDuration; public static float maximumDuration; public static float lockOnAngle; public static float procCoefficientPerTick; private HurtBox lockedOnHurtBox; private float fireStopwatch; private float stopwatch; private Ray aimRay; private Transform modelTransform; private GameObject laserEffect; private ChildLocator laserChildLocator; private Transform laserEffectEnd; protected Transform muzzleTransform; private BulletAttack bulletAttack; private EffectManagerHelper _emh_laserEffect; private BullseyeSearch enemyFinder; private bool foundAnyTarget; public override void Reset() { base.Reset(); lockedOnHurtBox = null; modelTransform = null; laserEffect = null; laserChildLocator = null; laserEffectEnd = null; muzzleTransform = null; if (bulletAttack != null) { bulletAttack.Reset(); } if (enemyFinder != null) { enemyFinder.Reset(); } foundAnyTarget = false; _emh_laserEffect = null; } public override void OnEnter() { base.OnEnter(); base.characterBody.SetAimTimer(maximumDuration); Util.PlaySound(playAttackSoundString, base.gameObject); Util.PlaySound(playLoopSoundString, base.gameObject); PlayCrossfade("Gesture, Additive", "FireLaserLoop", 0.25f); enemyFinder = new BullseyeSearch(); enemyFinder.viewer = base.characterBody; enemyFinder.maxDistanceFilter = maxDistance; enemyFinder.maxAngleFilter = lockOnAngle; enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.filterByLoS = false; enemyFinder.sortMode = BullseyeSearch.SortMode.Angle; enemyFinder.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } aimRay = GetAimRay(); modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { muzzleTransform = component.FindChild("MuzzleLaser"); if ((bool)muzzleTransform && (bool)laserPrefab) { if (!EffectManager.ShouldUsePooledEffect(laserPrefab)) { laserEffect = UnityEngine.Object.Instantiate(laserPrefab, muzzleTransform.position, muzzleTransform.rotation); } else { _emh_laserEffect = EffectManager.GetAndActivatePooledEffect(laserPrefab, muzzleTransform.position, muzzleTransform.rotation); laserEffect = _emh_laserEffect.gameObject; } laserEffect.transform.parent = muzzleTransform; laserChildLocator = laserEffect.GetComponent(); laserEffectEnd = laserChildLocator.FindChild("LaserEnd"); } } } UpdateLockOn(); } public override void OnExit() { if ((bool)laserEffect) { if (_emh_laserEffect != null && _emh_laserEffect.OwningPool != null) { _emh_laserEffect.OwningPool.ReturnObject(_emh_laserEffect); } else { EntityState.Destroy(laserEffect); } _emh_laserEffect = null; laserEffect = null; } base.characterBody.SetAimTimer(2f); Util.PlaySound(stopLoopSoundString, base.gameObject); PlayCrossfade("Gesture, Additive", "FireLaserEnd", 0.25f); base.OnExit(); } private void UpdateLockOn() { if (base.isAuthority) { enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.RefreshCandidates(); foundAnyTarget = (lockedOnHurtBox = enemyFinder.GetResults().FirstOrDefault()); } } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); fireStopwatch += deltaTime; stopwatch += deltaTime; aimRay = GetAimRay(); UnityEngine.Vector3 vector = aimRay.origin; if ((bool)muzzleTransform) { vector = muzzleTransform.position; } RaycastHit hitInfo; UnityEngine.Vector3 vector2 = (lockedOnHurtBox ? lockedOnHurtBox.transform.position : ((!Util.CharacterRaycast(base.gameObject, aimRay, out hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) ? aimRay.GetPoint(maxDistance) : hitInfo.point)); Ray ray = new Ray(vector, vector2 - vector); bool flag = false; if ((bool)laserEffect && (bool)laserChildLocator) { if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo2, (vector2 - vector).magnitude, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal)) { vector2 = hitInfo2.point; if (Util.CharacterRaycast(base.gameObject, new Ray(vector2 - ray.direction * 0.1f, -ray.direction), out var _, hitInfo2.distance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal)) { vector2 = ray.GetPoint(0.1f); flag = true; } } laserEffect.transform.rotation = Util.QuaternionSafeLookRotation(vector2 - vector); laserEffectEnd.transform.position = vector2; } if (fireStopwatch > 1f / fireFrequency) { string targetMuzzle = "MuzzleLaser"; if (!flag) { FireBullet(modelTransform, ray, targetMuzzle, (vector2 - ray.origin).magnitude + 0.1f); } UpdateLockOn(); fireStopwatch -= 1f / fireFrequency; } if (base.isAuthority && (((!base.inputBank || !base.inputBank.skill4.down) && stopwatch > minimumDuration) || stopwatch > maximumDuration)) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } private void FireBullet(Transform modelTransform, Ray aimRay, string targetMuzzle, float maxDistance) { if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { if (bulletAttack == null) { bulletAttack = new BulletAttack(); } bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.bulletCount = 1u; bulletAttack.damage = damageCoefficient * damageStat / fireFrequency; bulletAttack.force = force; bulletAttack.muzzleName = targetMuzzle; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.procCoefficient = procCoefficientPerTick; bulletAttack.HitEffectNormal = false; bulletAttack.radius = 0f; bulletAttack.maxDistance = maxDistance; bulletAttack.Fire(); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(HurtBoxReference.FromHurtBox(lockedOnHurtBox)); writer.Write(stopwatch); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); HurtBoxReference hurtBoxReference = reader.ReadHurtBoxReference(); stopwatch = reader.ReadSingle(); lockedOnHurtBox = hurtBoxReference.ResolveGameObject()?.GetComponent(); } } public class RechargeRocks : BaseState { public static float baseDuration = 3f; public static float baseRechargeDuration = 2f; public static GameObject effectPrefab; public static string attackSoundString; public static GameObject rockControllerPrefab; private int rocksFired; private float duration; private float stopwatch; private float rechargeStopwatch; private GameObject chargeEffect; public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); Util.PlaySound(attackSoundString, base.gameObject); PlayCrossfade("Body", "RechargeRocks", "RechargeRocks.playbackRate", duration, 0.2f); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("LeftFist"); if ((bool)transform && (bool)effectPrefab) { chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); chargeEffect.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffect.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } } } if (NetworkServer.active) { GameObject obj = UnityEngine.Object.Instantiate(rockControllerPrefab); obj.GetComponent().SetOwner(base.gameObject); NetworkServer.Spawn(obj); } } public override void OnExit() { base.OnExit(); if ((bool)chargeEffect) { EntityState.Destroy(chargeEffect); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class SpawnState : BaseState { public static float duration = 4f; public static GameObject burrowPrefab; public static string spawnSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(spawnSoundString, base.gameObject); ChildLocator component = GetModelTransform().GetComponent(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Transform transform = component.FindChild("BurrowCenter"); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(burrowPrefab)) { UnityEngine.Object.Instantiate(burrowPrefab, transform.position, UnityEngine.Quaternion.identity); } else { EffectManager.GetAndActivatePooledEffect(burrowPrefab, transform.position, UnityEngine.Quaternion.identity); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.GolemMonster { public class ChargeLaser : BaseState { public static float baseDuration = 3f; public static float laserMaxWidth = 0.2f; public static GameObject effectPrefab; public static GameObject laserPrefab; public static string attackSoundString; private float duration; private uint chargePlayID; private GameObject chargeEffect; private GameObject laserEffect; private LineRenderer laserLineComponent; private UnityEngine.Vector3 laserDirection; private UnityEngine.Vector3 visualEndPosition; private float flashTimer; private bool laserOn; protected EffectManagerHelper _efh_Charge; public override void Reset() { base.Reset(); duration = 0f; chargePlayID = 0u; chargeEffect = null; laserLineComponent = null; laserDirection = UnityEngine.Vector3.zero; visualEndPosition = UnityEngine.Vector3.zero; flashTimer = 0f; laserOn = false; _efh_Charge = null; } public override void OnEnter() { base.OnEnter(); SetAIUpdateFrequency(alwaysUpdate: true); duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); chargePlayID = Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleLaser"); if ((bool)transform) { if ((bool)effectPrefab) { if (!EffectManager.ShouldUsePooledEffect(effectPrefab)) { chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); } else { _efh_Charge = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation); chargeEffect = _efh_Charge.gameObject; } chargeEffect.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffect.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } if ((bool)laserPrefab && laserEffect == null) { laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation); } if (laserEffect != null) { if (!laserEffect.activeInHierarchy) { laserEffect.SetActive(value: true); } if (laserEffect.transform.parent != transform) { laserEffect.transform.parent = transform; } laserLineComponent = laserEffect.GetComponent(); } } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } flashTimer = 0f; laserOn = true; } public override void OnExit() { AkSoundEngine.StopPlayingID(chargePlayID); base.OnExit(); SetAIUpdateFrequency(alwaysUpdate: false); if ((bool)chargeEffect) { if (!EffectManager.UsePools) { EntityState.Destroy(chargeEffect); } else if (_efh_Charge != null && _efh_Charge.OwningPool != null) { if (!_efh_Charge.OwningPool.IsObjectInPool(_efh_Charge)) { _efh_Charge.OwningPool.ReturnObject(_efh_Charge); } } else { if (_efh_Charge != null) { UnityEngine.Debug.LogFormat("ChargeLaser has no owning pool {0} {1}", base.gameObject.name, base.gameObject.GetInstanceID()); } EntityState.Destroy(chargeEffect); } } if ((bool)laserEffect && laserEffect.activeInHierarchy) { laserEffect.SetActive(value: false); } } public override void Update() { base.Update(); if (!laserEffect || !laserLineComponent) { return; } float num = 1000f; Ray aimRay = GetAimRay(); UnityEngine.Vector3 position = laserEffect.transform.parent.position; UnityEngine.Vector3 point = aimRay.GetPoint(num); laserDirection = point - position; if (Physics.Raycast(aimRay, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask)) { point = hitInfo.point; } laserLineComponent.SetPosition(0, position); laserLineComponent.SetPosition(1, point); float num2; if (duration - base.age > 0.5f) { num2 = base.age / duration; } else { flashTimer -= Time.deltaTime; if (flashTimer <= 0f) { laserOn = !laserOn; flashTimer = 1f / 30f; } num2 = (laserOn ? 1f : 0f); } num2 *= laserMaxWidth; laserLineComponent.startWidth = num2; laserLineComponent.endWidth = num2; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireLaser fireLaser = new FireLaser(); fireLaser.laserDirection = laserDirection; outer.SetNextState(fireLaser); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ClapState : BaseState { public static float duration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float radius = 3f; private BlastAttack attack; public static string attackSoundString; private Animator modelAnimator; private Transform modelTransform; private bool hasAttacked; private GameObject leftHandChargeEffect; private GameObject rightHandChargeEffect; private EffectManagerHelper _emh_leftHandChargeEffect; private EffectManagerHelper _emh_rightHandChargeEffect; public override void Reset() { base.Reset(); modelAnimator = null; modelTransform = null; hasAttacked = false; leftHandChargeEffect = null; rightHandChargeEffect = null; if (attack != null) { attack.Reset(); } _emh_leftHandChargeEffect = null; _emh_rightHandChargeEffect = null; } public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); PlayCrossfade("Body", "Clap", "Clap.playbackRate", duration, 0.1f); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component) { return; } GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/GolemClapCharge"); Transform transform = component.FindChild("HandL"); Transform transform2 = component.FindChild("HandR"); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(gameObject)) { leftHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, transform); } else { _emh_leftHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, transform, inResetLocal: true); leftHandChargeEffect = _emh_leftHandChargeEffect.gameObject; } } if ((bool)transform2) { if (!EffectManager.ShouldUsePooledEffect(gameObject)) { rightHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, transform2); return; } _emh_rightHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, transform2, inResetLocal: true); rightHandChargeEffect = _emh_rightHandChargeEffect.gameObject; } } protected void DestroyChargeEffects() { if (_emh_leftHandChargeEffect != null && _emh_leftHandChargeEffect.OwningPool != null) { _emh_leftHandChargeEffect.OwningPool.ReturnObject(_emh_leftHandChargeEffect); } else { EntityState.Destroy(leftHandChargeEffect); } leftHandChargeEffect = null; _emh_leftHandChargeEffect = null; if (_emh_rightHandChargeEffect != null && _emh_rightHandChargeEffect.OwningPool != null) { _emh_rightHandChargeEffect.OwningPool.ReturnObject(_emh_rightHandChargeEffect); } else { EntityState.Destroy(rightHandChargeEffect); } rightHandChargeEffect = null; _emh_rightHandChargeEffect = null; } public override void OnExit() { DestroyChargeEffects(); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)modelAnimator && modelAnimator.GetFloat("Clap.hitBoxActive") > 0.5f && !hasAttacked) { if (base.isAuthority && (bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("ClapZone"); if ((bool)transform) { attack = new BlastAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); attack.baseDamage = damageStat * damageCoefficient; attack.baseForce = forceMagnitude; attack.position = transform.position; attack.radius = radius; attack.attackerFiltering = AttackerFiltering.NeverHitSelf; attack.Fire(); } } } hasAttacked = true; DestroyChargeEffects(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class DeathState : GenericCharacterDeath { public static GameObject initialDeathExplosionPrefab; public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild("Head"); if ((bool)transform && (bool)initialDeathExplosionPrefab) { if (!EffectManager.ShouldUsePooledEffect(initialDeathExplosionPrefab)) { UnityEngine.Object.Instantiate(initialDeathExplosionPrefab, transform.position, UnityEngine.Quaternion.identity).transform.parent = transform; } else { EffectManager.GetAndActivatePooledEffect(initialDeathExplosionPrefab, transform.position, UnityEngine.Quaternion.identity, transform); } } } } public class FireLaser : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float blastRadius; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float baseDuration = 2f; public static string attackSoundString; public UnityEngine.Vector3 laserDirection; private float duration; private Ray modifiedAimRay; private static int FireLaserStateHash = Animator.StringToHash("FireLaser"); private static int FireLaserParamHash = Animator.StringToHash("FireLaser.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modifiedAimRay = GetAimRay(); modifiedAimRay.direction = laserDirection; GetModelAnimator(); Transform modelTransform = GetModelTransform(); Util.PlaySound(attackSoundString, base.gameObject); string text = "MuzzleLaser"; if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } PlayAnimation("Gesture", FireLaserStateHash, FireLaserParamHash, duration); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false); } if (!base.isAuthority) { return; } float num = 1000f; UnityEngine.Vector3 vector = modifiedAimRay.origin + modifiedAimRay.direction * num; if (Physics.Raycast(modifiedAimRay, out var hitInfo, num, LayerIndex.CommonMasks.laser)) { vector = hitInfo.point; } BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * damageCoefficient; blastAttack.baseForce = force * 0.2f; blastAttack.position = vector; blastAttack.radius = blastRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot; blastAttack.bonusForce = force * modifiedAimRay.direction; blastAttack.Fire(); _ = modifiedAimRay.origin; if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { int childIndex = component.FindChildIndex(text); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = vector, start = modifiedAimRay.origin }; effectData.SetChildLocatorTransformReference(base.gameObject, childIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); EffectManager.SpawnEffect(hitEffectPrefab, effectData, transmit: true); } } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class SpawnState : GenericCharacterSpawnState { private GameObject eyeGameObject; public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { modelTransform.GetComponent().enabled = true; } eyeGameObject = FindModelChild("Eye")?.gameObject; if ((bool)eyeGameObject) { eyeGameObject.SetActive(value: false); } if (base.characterBody.HasBuff(DLC2Content.Buffs.EliteAurelionite)) { PrintController component = base.modelLocator.modelTransform.gameObject.GetComponent(); component.enabled = false; component.printTime = duration; component.startingPrintHeight = -101.78f; component.maxPrintHeight = -93f; component.startingPrintBias = 2f; component.maxPrintBias = 0.95f; component.disableWhenFinished = true; component.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); component.enabled = true; } } public override void OnExit() { if (!outer.destroying && (bool)eyeGameObject) { eyeGameObject.SetActive(value: true); } } } } namespace EntityStates.GoldGat { public class BaseGoldGatState : EntityState { protected NetworkedBodyAttachment networkedBodyAttachment; protected GameObject bodyGameObject; protected CharacterBody body; protected ChildLocator gunChildLocator; protected Animator gunAnimator; protected Transform gunTransform; protected CharacterMaster bodyMaster; protected EquipmentSlot bodyEquipmentSlot; protected InputBankTest bodyInputBank; protected AimAnimator bodyAimAnimator; public bool shouldFire; private bool linkedToDisplay; public override void OnEnter() { base.OnEnter(); networkedBodyAttachment = GetComponent(); if (!networkedBodyAttachment) { return; } bodyGameObject = networkedBodyAttachment.attachedBodyObject; body = networkedBodyAttachment.attachedBody; if ((bool)bodyGameObject) { bodyMaster = body.master; bodyInputBank = bodyGameObject.GetComponent(); bodyEquipmentSlot = body.equipmentSlot; ModelLocator component = body.GetComponent(); if ((bool)component) { bodyAimAnimator = component.modelTransform.GetComponent(); } LinkToDisplay(); } } private void LinkToDisplay() { if (linkedToDisplay || !bodyEquipmentSlot) { return; } gunTransform = bodyEquipmentSlot.FindActiveEquipmentDisplay(); if ((bool)gunTransform) { gunChildLocator = gunTransform.GetComponentInChildren(); if ((bool)gunChildLocator && (bool)base.modelLocator) { base.modelLocator.modelTransform = gunChildLocator.transform; gunAnimator = GetModelAnimator(); linkedToDisplay = true; } } } public override void FixedUpdate() { base.Update(); if (base.isAuthority && (bool)bodyInputBank) { if (bodyInputBank.activateEquipment.justPressed) { shouldFire = !shouldFire; } if (body.inventory.GetItemCount(RoR2Content.Items.AutoCastEquipment) > 0) { shouldFire = true; } } LinkToDisplay(); if ((bool)bodyAimAnimator && (bool)gunAnimator) { bodyAimAnimator.UpdateAnimatorParameters(gunAnimator, -45f, 45f, 0f, 0f); } } protected bool CheckReturnToIdle() { if (!base.isAuthority) { return false; } if (((bool)bodyMaster && bodyMaster.money == 0) || !shouldFire) { outer.SetNextState(new GoldGatIdle { shouldFire = shouldFire }); return true; } return false; } } public class GoldGatIdle : BaseGoldGatState { public static string windDownSoundString; public override void OnEnter() { base.OnEnter(); Util.PlaySound(windDownSoundString, base.gameObject); } public override void Update() { base.Update(); if ((bool)gunAnimator) { gunAnimator.SetFloat("Crank.playbackRate", 0f, 1f, GetDeltaTime()); } if (base.isAuthority && shouldFire && bodyMaster.money != 0 && bodyEquipmentSlot.stock > 0) { outer.SetNextState(new GoldGatFire { shouldFire = shouldFire }); } } } public class GoldGatFire : BaseGoldGatState { public static float minFireFrequency; public static float maxFireFrequency; public static float minSpread; public static float maxSpread; public static float windUpDuration; public static float force; public static float damageCoefficient; public static float procCoefficient; public static string attackSoundString; public static GameObject tracerEffectPrefab; public static GameObject impactEffectPrefab; public static GameObject muzzleFlashEffectPrefab; public static int baseMoneyCostPerBullet; public static string windUpSoundString; public static string windUpRTPC; public float totalStopwatch; private float stopwatch; private float fireFrequency; private uint loopSoundID; private static int CrankplaybackRateParamHash = Animator.StringToHash("Crank.playbackRate"); public override void OnEnter() { base.OnEnter(); loopSoundID = Util.PlaySound(windUpSoundString, base.gameObject); FireBullet(); } private void FireBullet() { body.SetAimTimer(2f); float t = Mathf.Clamp01(totalStopwatch / windUpDuration); fireFrequency = Mathf.Lerp(minFireFrequency, maxFireFrequency, t); float num = Mathf.Lerp(minSpread, maxSpread, t); Util.PlaySound(attackSoundString, base.gameObject); int num2 = (int)((float)baseMoneyCostPerBullet * (1f + ((float)TeamManager.instance.GetTeamLevel(bodyMaster.teamIndex) - 1f) * 0.25f)); if (base.isAuthority) { Transform aimOriginTransform = body.aimOriginTransform; if ((bool)gunChildLocator) { gunChildLocator.FindChild("Muzzle"); } if ((bool)aimOriginTransform) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = networkedBodyAttachment.attachedBodyObject; bulletAttack.aimVector = bodyInputBank.aimDirection; bulletAttack.origin = bodyInputBank.aimOrigin; bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet; bulletAttack.force = force; bulletAttack.damage = body.damage * damageCoefficient; bulletAttack.damageColorIndex = DamageColorIndex.Item; bulletAttack.bulletCount = 1u; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = num; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(body.crit, bodyMaster); bulletAttack.procCoefficient = procCoefficient; bulletAttack.muzzleName = "Muzzle"; bulletAttack.weapon = base.gameObject; bulletAttack.Fire(); gunAnimator?.Play("Fire"); } } if (NetworkServer.active) { bodyMaster.money = (uint)Mathf.Max(0f, bodyMaster.money - num2); } gunAnimator?.SetFloat(CrankplaybackRateParamHash, fireFrequency); EffectManager.SimpleMuzzleFlash(muzzleFlashEffectPrefab, base.gameObject, "Muzzle", transmit: false); } public override void Update() { base.Update(); float deltaTime = Time.deltaTime; totalStopwatch += deltaTime; stopwatch += deltaTime; AkSoundEngine.SetRTPCValueByPlayingID(windUpRTPC, Mathf.InverseLerp(minFireFrequency, maxFireFrequency, fireFrequency) * 100f, loopSoundID); if (!CheckReturnToIdle() && stopwatch > 1f / fireFrequency) { stopwatch = 0f; FireBullet(); } } public override void OnExit() { AkSoundEngine.StopPlayingID(loopSoundID); base.OnExit(); } } } namespace EntityStates.GlobalSkills.WoundSlash { public class WoundSlash : BaseSkillState { public static float blastRadius; public static float blastDamageCoefficient; public static float blastForce; public static float blastProcCoefficient; public static GameObject blastImpactEffectPrefab; public static GameObject slashEffectPrefab; public static float slashEffectOffset; public static float baseDuration; public static string soundString; public static float shortHopVelocity; private float duration => baseDuration / attackSpeedStat; public override void OnEnter() { base.OnEnter(); Ray aimRay = GetAimRay(); UnityEngine.Vector3 vector = base.characterBody.corePosition + aimRay.direction * slashEffectOffset; Util.PlaySound(soundString, base.gameObject); EffectData effectData = new EffectData { origin = vector, rotation = Util.QuaternionSafeLookRotation(aimRay.direction) }; EffectManager.SpawnEffect(slashEffectPrefab, effectData, transmit: true); if (NetworkServer.active) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.baseDamage = blastDamageCoefficient * damageStat; blastAttack.baseForce = blastForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = RollCrit(); blastAttack.damageType = DamageType.Generic; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.inflictor = base.gameObject; blastAttack.position = vector; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = blastProcCoefficient; blastAttack.radius = blastRadius; blastAttack.teamIndex = base.teamComponent.teamIndex; blastAttack.impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab); blastAttack.Fire(); } if (base.isAuthority && (bool)base.characterMotor) { base.characterMotor.velocity.y = Mathf.Max(base.characterMotor.velocity.y, shortHopVelocity); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } } namespace EntityStates.GlobalSkills.LunarNeedle { public class ChargeLunarSecondary : BaseChargeBombState { [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string playbackRateParam; protected override BaseThrowBombState GetNextState() { return new ThrowLunarSecondary(); } protected override void PlayChargeAnimation() { PlayAnimation(animationLayerName, animationStateName, playbackRateParam, base.duration); } } public class FireLunarNeedle : BaseSkillState { public static float baseDuration; public static float damageCoefficient; public static GameObject projectilePrefab; public static float recoilAmplitude; public static float spreadBloomValue; public static GameObject muzzleFlashEffectPrefab; public static string fireSound; public static float maxSpread; private float duration; [SerializeField] public string animationLayerName = "Gesture, Override"; [SerializeField] public string animationStateName = "FireLunarNeedle"; [SerializeField] public string playbackRateParam = "FireLunarNeedle.playbackRate"; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; if (base.isAuthority) { Ray aimRay = GetAimRay(); aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, maxSpread, 1f, 1f); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.position = aimRay.origin; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction); fireProjectileInfo.crit = base.characterBody.RollCrit(); fireProjectileInfo.damage = base.characterBody.damage * damageCoefficient; fireProjectileInfo.damageColorIndex = DamageColorIndex.Default; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.procChainMask = default(ProcChainMask); fireProjectileInfo.force = 0f; fireProjectileInfo.useFuseOverride = false; fireProjectileInfo.useSpeedOverride = false; fireProjectileInfo.target = null; fireProjectileInfo.projectilePrefab = projectilePrefab; ProjectileManager.instance.FireProjectile(fireProjectileInfo); } AddRecoil(-0.4f * recoilAmplitude, -0.8f * recoilAmplitude, -0.3f * recoilAmplitude, 0.3f * recoilAmplitude); base.characterBody.AddSpreadBloom(spreadBloomValue); StartAimMode(); EffectManager.SimpleMuzzleFlash(muzzleFlashEffectPrefab, base.gameObject, "Head", transmit: false); Util.PlaySound(fireSound, base.gameObject); PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ThrowLunarSecondary : BaseThrowBombState { [SerializeField] public float minSpeed; [SerializeField] public float maxSpeed; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string playbackRateParam; protected override void PlayThrowAnimation() { PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration); } protected override void ModifyProjectile(ref FireProjectileInfo projectileInfo) { projectileInfo.speedOverride = Util.Remap(charge, 0f, 1f, minSpeed, maxSpeed); projectileInfo.useSpeedOverride = true; } } } namespace EntityStates.GlobalSkills.LunarDetonator { public class Detonate : BaseState { private class DetonationController { public HurtBox[] detonationTargets; public CharacterBody characterBody; public float damageStat; public bool isCrit; public float interval; private int i; private float timer; private bool _active; public bool active { get { return _active; } set { if (_active != value) { _active = value; if (_active) { RoR2Application.onFixedUpdate += FixedUpdate; } else { RoR2Application.onFixedUpdate -= FixedUpdate; } } } } private void FixedUpdate() { if (!characterBody || !characterBody.healthComponent || !characterBody.healthComponent.alive) { active = false; return; } timer -= Time.deltaTime; if (!(timer <= 0f)) { return; } for (timer = interval; i < detonationTargets.Length; i++) { try { HurtBox a = null; Util.Swap(ref a, ref detonationTargets[i]); if (DoDetonation(a)) { break; } } catch (Exception message) { UnityEngine.Debug.LogError(message); } } if (i >= detonationTargets.Length) { active = false; } } private bool DoDetonation(HurtBox targetHurtBox) { if (!targetHurtBox) { return false; } HealthComponent healthComponent = targetHurtBox.healthComponent; if (!healthComponent) { return false; } CharacterBody body = healthComponent.body; if (!body) { return false; } if (body.GetBuffCount(RoR2Content.Buffs.LunarDetonationCharge) <= 0) { return false; } LunarDetonatorOrb lunarDetonatorOrb = new LunarDetonatorOrb(); lunarDetonatorOrb.origin = characterBody.corePosition; lunarDetonatorOrb.target = targetHurtBox; lunarDetonatorOrb.attacker = characterBody.gameObject; lunarDetonatorOrb.baseDamage = damageStat * baseDamageCoefficient; lunarDetonatorOrb.damagePerStack = damageStat * damageCoefficientPerStack; lunarDetonatorOrb.damageColorIndex = DamageColorIndex.Default; lunarDetonatorOrb.isCrit = isCrit; lunarDetonatorOrb.procChainMask = default(ProcChainMask); lunarDetonatorOrb.procCoefficient = 1f; lunarDetonatorOrb.detonationEffectPrefab = detonationEffectPrefab; lunarDetonatorOrb.travelSpeed = 120f; lunarDetonatorOrb.orbEffectPrefab = orbEffectPrefab; OrbManager.instance.AddOrb(lunarDetonatorOrb); return true; } } public static float baseDuration; public static float baseDamageCoefficient; public static float damageCoefficientPerStack; public static float procCoefficient; public static float detonationInterval; public static GameObject detonationEffectPrefab; public static GameObject orbEffectPrefab; public static GameObject enterEffectPrefab; public static string enterSoundString; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string playbackRateParam; private float duration; private HurtBox[] detonationTargets; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; EffectManager.SimpleImpactEffect(enterEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: false); Util.PlaySound(enterSoundString, base.gameObject); if (NetworkServer.active) { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.filterByDistinctEntity = true; bullseyeSearch.filterByLoS = false; bullseyeSearch.maxDistanceFilter = float.PositiveInfinity; bullseyeSearch.minDistanceFilter = 0f; bullseyeSearch.minAngleFilter = 0f; bullseyeSearch.maxAngleFilter = 180f; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.teamMaskFilter = TeamMask.GetUnprotectedTeams(GetTeam()); bullseyeSearch.searchOrigin = base.characterBody.corePosition; bullseyeSearch.viewer = null; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); IEnumerable results = bullseyeSearch.GetResults(); detonationTargets = results.ToArray(); new DetonationController { characterBody = base.characterBody, interval = detonationInterval, detonationTargets = detonationTargets, damageStat = damageStat, isCrit = RollCrit(), active = true }; } PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } } namespace EntityStates.Geode { public class GeodeEntityStates : EntityState { protected GeodeController geodeController; protected GameObject cleansingIndicator; protected GameObject geodeModel; protected Renderer geodeTrunkRenderer; protected GameObject geodeBase; protected GameObject geodeIdleVFX; protected int sliceHeightNameId; public override void OnEnter() { base.OnEnter(); geodeController = base.gameObject.GetComponent(); ChildLocator component = base.gameObject.GetComponent(); cleansingIndicator = component.FindChildGameObject(0); geodeModel = component.FindChildGameObject(1); geodeBase = component.FindChildGameObject(2); geodeIdleVFX = component.FindChildGameObject(3); geodeTrunkRenderer = geodeModel.GetComponent(); geodeTrunkRenderer.material.EnableKeyword("_SLICEHEIGHT"); int propertyIndex = geodeTrunkRenderer.material.shader.FindPropertyIndex("_SliceHeight"); sliceHeightNameId = geodeTrunkRenderer.material.shader.GetPropertyNameId(propertyIndex); } public override void OnExit() { base.OnExit(); } } public class GeodeShatter : GeodeEntityStates { private SphereSearch sphereSearch; private List hitHurtBoxes; private bool cleansingActive = true; private float stopWatch; protected bool rewardGiven; [Tooltip("The prefab to use for the reward pickup.")] [SerializeField] public GameObject rewardPickupPrefab; [SerializeField] public PickupDropTable rewardDropTable; [SerializeField] public int rewardOptionCount = 1; [SerializeField] public ItemTier rewardDisplayTier; [SerializeField] public UnityEngine.Vector3 rewardOffset; [SerializeField] public float cleansingDuration = 6f; [SerializeField] public float cleansingTicksPerSecond = 1.5f; protected Xoroshiro128Plus rng; public override void OnEnter() { base.OnEnter(); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/GeodeShatterVFX"), new EffectData { origin = base.gameObject.transform.position }, transmit: false); Util.PlaySound("Play_env_meridian_geode_activate", base.gameObject); Util.PlaySound("Play_env_meridian_geode_active_loop", base.gameObject); cleansingIndicator.SetActive(value: true); sphereSearch = new SphereSearch(); CharacterBody characterBody = geodeController.lastInteractor?.GetComponent(); if (!geodeController.ShouldRegenerate) { geodeBase.SetActive(value: false); } geodeTrunkRenderer.material.SetFloat(sliceHeightNameId, geodeController.startingPrintHeight); geodeIdleVFX.SetActive(value: false); geodeModel.SetActive(value: false); if (!NetworkServer.active) { return; } if ((bool)characterBody && characterBody.HasBuff(DLC2Content.Buffs.GeodeBuff) && geodeController.ShouldDropReward) { rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); RemoveGeodeBuffFromAllPlayers(); int participatingPlayerCount = Run.instance.participatingPlayerCount; if (!(base.gameObject == null) && !(rewardDropTable == null) && participatingPlayerCount != 0 && participatingPlayerCount > 0 && (bool)base.gameObject && (bool)rewardDropTable && !rewardGiven) { rewardGiven = true; int num = participatingPlayerCount; float angle = 360f / (float)num; UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); UnityEngine.Vector3 position = base.gameObject.transform.position + rewardOffset; int num2 = 0; while (num2 < num) { GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo); pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier); pickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(rewardOptionCount, rewardDropTable, rng); pickupInfo.rotation = UnityEngine.Quaternion.identity; pickupInfo.prefabOverride = rewardPickupPrefab; PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector); num2++; vector = quaternion * vector; } } } else { RemoveGeodeBuffFromAllPlayers(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= cleansingDuration) { cleansingActive = false; Util.PlaySound("Stop_env_meridian_geode_active_loop", base.gameObject); outer.SetNextState(new GeodeInert()); } else { if (!cleansingActive) { return; } stopWatch += Time.deltaTime; if (stopWatch > 1f / cleansingTicksPerSecond && sphereSearch != null) { stopWatch -= 1f / cleansingTicksPerSecond; if (NetworkServer.active) { HandleCleanseNearbyPlayers(); } } } } private void HandleCleanseNearbyPlayers() { hitHurtBoxes = CollectionPool>.RentCollection(); SearchForPlayers(hitHurtBoxes); for (int i = 0; i < hitHurtBoxes.Count; i++) { HurtBox hurtBox = hitHurtBoxes[i]; CharacterBody body = hurtBox.healthComponent.body; bool isPlayerControlled = body.isPlayerControlled; if ((bool)hurtBox && hurtBox.healthComponent.alive && isPlayerControlled && !body.HasBuff(DLC2Content.Buffs.GeodeBuff)) { Util.PlaySound("Play_env_meridian_geode_cleanse_debuff", body.gameObject); Util.CleanseBody(body, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: true, removeDots: true, removeStun: true, removeNearbyProjectiles: true); hurtBox.healthComponent.AddBarrier(hurtBox.healthComponent.fullHealth * geodeController.barrierToHealthPercentage); body.AddBuff(DLC2Content.Buffs.GeodeBuff); } } } protected void RemoveGeodeBuffFromAllPlayers() { foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { CharacterBody currentBody = instance.networkUser.GetCurrentBody(); if (currentBody.HasBuff(DLC2Content.Buffs.GeodeBuff)) { currentBody.RemoveBuff(DLC2Content.Buffs.GeodeBuff); } } } protected void SearchForPlayers(List dest) { TeamMask mask = default(TeamMask); mask.AddTeam(TeamIndex.Player); sphereSearch.mask = LayerIndex.entityPrecise.mask; sphereSearch.origin = base.gameObject.transform.position; sphereSearch.radius = geodeController.geodeBuffRadius; sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal; sphereSearch.RefreshCandidates(); sphereSearch.FilterCandidatesByHurtBoxTeam(mask); sphereSearch.OrderCandidatesByDistance(); sphereSearch.FilterCandidatesByDistinctHurtBoxEntities(); sphereSearch.GetHurtBoxes(dest); sphereSearch.ClearCandidates(); } } public class GeodeInert : GeodeEntityStates { [SerializeField] public float reactivationDuration; public override void OnEnter() { base.OnEnter(); cleansingIndicator.SetActive(value: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= reactivationDuration && geodeController.ShouldRegenerate) { outer.SetNextState(new GeodeRegenerate()); } else if (!geodeController.ShouldRegenerate) { EntityState.Destroy(base.gameObject); } } } public class GeodeRegenerate : GeodeEntityStates { private new float age; public override void OnEnter() { base.OnEnter(); geodeModel.SetActive(value: true); } public override void FixedUpdate() { base.FixedUpdate(); age += Time.deltaTime; float printThreshold = geodeController.printCurve.Evaluate(age / geodeController.printTime); SetPrintThreshold(printThreshold); if (age >= geodeController.idleVFXRegenerationTimer && !geodeIdleVFX.activeInHierarchy) { geodeIdleVFX.SetActive(value: true); } if (age >= geodeController.printTime) { if (NetworkServer.active) { geodeController.SetAvailable(activeState: true); } outer.SetNextState(new GeodeEntityStates()); } } private void SetPrintThreshold(float sample) { float num = 1f - sample; float value = sample * geodeController.maxPrintHeight + num * geodeController.startingPrintHeight; geodeTrunkRenderer.material.SetFloat(sliceHeightNameId, value); } public override void OnExit() { base.OnExit(); age = 0f; } } } namespace EntityStates.GameOver { public class BaseGameOverControllerState : BaseState { protected GameOverController gameOverController { get; private set; } protected GameEndingDef gameEnding { get; private set; } public override void OnEnter() { base.OnEnter(); gameOverController = GetComponent(); gameEnding = gameOverController.runReport.gameEnding; } } public class RoR2MainEndingStart : BaseGameOverControllerState { public static float duration = 6f; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { outer.SetNextState(new RoR2MainEndingSetSceneAndWaitForPlayers()); } } public override void OnEnter() { base.OnEnter(); } public override void OnExit() { base.OnExit(); } } public class RoR2MainEndingSetSceneAndWaitForPlayers : BaseGameOverControllerState { private SceneDef desiredSceneDef; public override void OnEnter() { base.OnEnter(); FadeToBlackManager.ForceFullBlack(); FadeToBlackManager.fadeCount++; desiredSceneDef = SceneCatalog.GetSceneDefFromSceneName("outro"); if (NetworkServer.active) { Run.instance.AdvanceStage(desiredSceneDef); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && NetworkUser.AllParticipatingNetworkUsersReady() && SceneCatalog.mostRecentSceneDef == desiredSceneDef) { outer.SetNextState(new RoR2MainEndingPlayCutscene()); } } public override void OnExit() { FadeToBlackManager.fadeCount--; base.OnExit(); } } public class RoR2MainEndingPlayCutscene : BaseGameOverControllerState { public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (!OutroCutsceneController.instance || OutroCutsceneController.instance.cutsceneIsFinished)) { outer.SetNextStateToMain(); } } public override void OnExit() { if ((bool)OutroCutsceneController.instance && (bool)OutroCutsceneController.instance.playableDirector) { OutroCutsceneController.instance.playableDirector.time = OutroCutsceneController.instance.playableDirector.duration; } base.OnExit(); } } public class LingerShort : BaseGameOverControllerState { private static readonly float duration = 3f; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } public class FinishEndingContent : BaseGameOverControllerState { public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { outer.SetNextState(base.gameEnding.showCredits ? ((BaseGameOverControllerState)new ShowCredits()) : ((BaseGameOverControllerState)new ShowReport())); } } } public class ShowCredits : BaseGameOverControllerState { private GameObject creditsControllerInstance; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { creditsControllerInstance = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/CreditsController")); NetworkServer.Spawn(creditsControllerInstance); } } public override void OnExit() { if (NetworkServer.active && (bool)creditsControllerInstance) { EntityState.Destroy(creditsControllerInstance); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && !creditsControllerInstance) { outer.SetNextState(new ShowReport()); } } } public class ShowReport : BaseGameOverControllerState { public override void OnEnter() { base.OnEnter(); if (NetworkClient.active) { base.gameOverController.shouldDisplayGameEndReportPanels = true; } } public override void OnExit() { base.OnExit(); } } public class RebirthEndingFadeToBlack : BaseGameOverControllerState { [SerializeField] public float delay; [SerializeField] public float duration; [SerializeField] public GameObject screenPrefab; private Run.TimeStamp startTime; private UnityEngine.UI.Image image; private GameObject screenInstance; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { startTime = Run.TimeStamp.now + delay; } screenInstance = UnityEngine.Object.Instantiate(screenPrefab, RoR2Application.instance.mainCanvas.transform); image = screenInstance.GetComponentInChildren(); image.raycastTarget = false; UpdateImageAlpha(0f); } public override void OnExit() { FadeToBlackManager.ForceFullBlack(); EntityState.Destroy(screenInstance); screenInstance = null; image = null; base.OnExit(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(startTime); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); startTime = reader.ReadTimeStamp(); } public override void FixedUpdate() { base.FixedUpdate(); UpdateImageAlpha(Mathf.Max(0f, Mathf.Min(1f, startTime.timeSince / duration))); if (NetworkServer.active && (startTime + duration).hasPassed) { outer.SetNextStateToMain(); } } private void UpdateImageAlpha(float finalAlpha) { UnityEngine.Color color = image.color; color.a = finalAlpha; image.color = color; } } public class RebirthEndingStart : BaseGameOverControllerState { [SerializeField] public float duration; private bool hasSceneExited; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration && hasSceneExited) { outer.SetNextState(new RebirthEndingFadeToBlack()); } } public override void OnEnter() { base.OnEnter(); SceneExitController.onFinishExit += OnFinishSceneExit; } public override void OnExit() { SceneExitController.onFinishExit -= OnFinishSceneExit; base.OnExit(); } private void OnFinishSceneExit(SceneExitController obj) { hasSceneExited = true; } } public class VoidEndingFadeToBlack : BaseGameOverControllerState { [SerializeField] public float delay; [SerializeField] public float duration; [SerializeField] public GameObject screenPrefab; private Run.TimeStamp startTime; private UnityEngine.UI.Image image; private GameObject screenInstance; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { startTime = Run.TimeStamp.now + delay; } screenInstance = UnityEngine.Object.Instantiate(screenPrefab, RoR2Application.instance.mainCanvas.transform); image = screenInstance.GetComponentInChildren(); image.raycastTarget = false; UpdateImageAlpha(0f); } public override void OnExit() { FadeToBlackManager.ForceFullBlack(); EntityState.Destroy(screenInstance); screenInstance = null; image = null; base.OnExit(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(startTime); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); startTime = reader.ReadTimeStamp(); } public override void FixedUpdate() { base.FixedUpdate(); UpdateImageAlpha(Mathf.Max(0f, Mathf.Min(1f, startTime.timeSince / duration))); if (NetworkServer.active && (startTime + duration).hasPassed) { outer.SetNextStateToMain(); } } private void UpdateImageAlpha(float finalAlpha) { UnityEngine.Color color = image.color; color.a = finalAlpha; image.color = color; } } public class VoidEndingPlayCutscene : BaseGameOverControllerState { public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (!OutroCutsceneController.instance || OutroCutsceneController.instance.cutsceneIsFinished)) { outer.SetNextStateToMain(); } } public override void OnExit() { if ((bool)OutroCutsceneController.instance && (bool)OutroCutsceneController.instance.playableDirector) { OutroCutsceneController.instance.playableDirector.time = OutroCutsceneController.instance.playableDirector.duration; } base.OnExit(); } } public class VoidEndingSetSceneAndWaitForPlayers : BaseGameOverControllerState { [SerializeField] public SceneDef desiredSceneDef; public override void OnEnter() { base.OnEnter(); FadeToBlackManager.ForceFullBlack(); FadeToBlackManager.fadeCount++; if (NetworkServer.active) { Run.instance.AdvanceStage(desiredSceneDef); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && NetworkUser.AllParticipatingNetworkUsersReady() && SceneCatalog.mostRecentSceneDef == desiredSceneDef) { outer.SetNextState(new VoidEndingPlayCutscene()); } } public override void OnExit() { FadeToBlackManager.fadeCount--; base.OnExit(); } } public class VoidEndingStart : BaseGameOverControllerState { [SerializeField] public float duration; private bool hasSceneExited; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration && hasSceneExited) { outer.SetNextState(new VoidEndingFadeToBlack()); } } public override void OnEnter() { base.OnEnter(); SceneExitController.onFinishExit += OnFinishSceneExit; } public override void OnExit() { SceneExitController.onFinishExit -= OnFinishSceneExit; base.OnExit(); } private void OnFinishSceneExit(SceneExitController obj) { hasSceneExited = true; } } } namespace EntityStates.FlyingVermin { public class FallingDeath : GenericCharacterDeath { public static float initialVerticalVelocity; public static float deathDelay; public static GameObject deathEffectPrefab; private bool hasDied; public override void OnEnter() { base.OnEnter(); if ((bool)base.characterMotor) { base.characterMotor.velocity.y = initialVerticalVelocity; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > deathDelay && NetworkServer.active && !hasDied) { hasDied = true; EffectManager.SimpleImpactEffect(deathEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: true); DestroyBodyAsapServer(); } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class SpawnState : GenericCharacterSpawnState { } } namespace EntityStates.FlyingVermin.Weapon { public class Spit : GenericProjectileBaseState { private static int SpitStateHash = Animator.StringToHash("Spit"); private static int SpitParamHash = Animator.StringToHash("Spit.playbackRate"); public override void OnEnter() { base.OnEnter(); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(5f); } } protected override void PlayAnimation(float duration) { base.PlayAnimation(duration); PlayAnimation("Gesture, Additive", SpitStateHash, SpitParamHash, duration); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } protected override void FireProjectile() { if (base.isAuthority) { Ray aimRay = GetAimRay(); aimRay = ModifyProjectileAimRay(aimRay); aimRay.direction = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, 0f, projectilePitchBonus); float damage = damageStat * damageCoefficient; BaseAI component = outer.commonComponents.characterBody.master.GetComponent(); if ((object)component != null && component.shouldMissFirstOffScreenShot && component.currentEnemy.characterBody.teamComponent.teamIndex == TeamIndex.Player) { component.shouldMissFirstOffScreenShot = false; aimRay.direction = OffScreenMissHelper.ApplyRandomTrajectoryOffset(aimRay.direction); damage = 0f; } ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damage, force, Util.CheckRoll(critStat, base.characterBody.master)); } } } } namespace EntityStates.FlyingVermin.Mode { public class GrantFlight : BaseState { protected ICharacterGravityParameterProvider characterGravityParameterProvider; protected ICharacterFlightParameterProvider characterFlightParameterProvider; public override void OnEnter() { base.OnEnter(); characterGravityParameterProvider = base.gameObject.GetComponent(); characterFlightParameterProvider = base.gameObject.GetComponent(); if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount++; characterGravityParameterProvider.gravityParameters = gravityParameters; } if (characterFlightParameterProvider != null) { CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters; flightParameters.channeledFlightGranterCount++; characterFlightParameterProvider.flightParameters = flightParameters; } } public override void OnExit() { if (characterFlightParameterProvider != null) { CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters; flightParameters.channeledFlightGranterCount--; characterFlightParameterProvider.flightParameters = flightParameters; } if (characterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount--; characterGravityParameterProvider.gravityParameters = gravityParameters; } base.OnExit(); } } } namespace EntityStates.Fauna { public class BirdsharkDeathState : BaseState { [SerializeField] public GameObject initialExplosion; [SerializeField] public string deathSoundString; public override void OnEnter() { base.OnEnter(); Util.PlaySound(deathSoundString, base.gameObject); if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if ((bool)initialExplosion && NetworkServer.active) { EffectManager.SimpleImpactEffect(initialExplosion, base.transform.position, UnityEngine.Vector3.up, transmit: true); } EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class VultureEggDeathState : BirdsharkDeathState { public static int healPackCount; public static float healPackMaxVelocity; public static float fractionalHealing; public static float scale; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { for (int i = 0; i < healPackCount; i++) { GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/HealPack"), base.transform.position, UnityEngine.Random.rotation); obj.GetComponent().teamIndex = TeamIndex.Player; obj.GetComponentInChildren().fractionalHealing = fractionalHealing; obj.transform.localScale = new UnityEngine.Vector3(scale, scale, scale); obj.GetComponent().AddForce(UnityEngine.Random.insideUnitSphere * healPackMaxVelocity, ForceMode.VelocityChange); NetworkServer.Spawn(obj); } } } } public class HabitatFruitDeathState : BaseState { [SerializeField] public static GameObject initialExplosion; [SerializeField] public static string deathSoundString; public static int healPackCount; public static float healPackMaxVelocity; public static float fractionalHealing; public static float scale; public override void OnEnter() { base.OnEnter(); Util.PlaySound(deathSoundString, base.gameObject); if ((bool)initialExplosion && NetworkServer.active) { EffectManager.SimpleImpactEffect(initialExplosion, base.transform.position, UnityEngine.Vector3.up, transmit: true); } if (NetworkServer.active) { for (int i = 0; i < healPackCount; i++) { GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/HealPack"), base.transform.position, UnityEngine.Random.rotation); obj.GetComponent().teamIndex = TeamIndex.Player; obj.GetComponentInChildren().fractionalHealing = fractionalHealing; obj.transform.localScale = new UnityEngine.Vector3(scale, scale, scale); obj.GetComponent().AddForce(UnityEngine.Random.insideUnitSphere * healPackMaxVelocity, ForceMode.VelocityChange); NetworkServer.Spawn(obj); } } EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.FalseSonBoss { public class ClubForsakenBoss : BaseSkillState { [SerializeField] public float baseChargeDuration = 1f; public static float minChargeForChargedAttack; public static GameObject chargeVfxPrefab; public static string chargeVfxChildLocatorName; public static GameObject crosshairOverridePrefab; public static float walkSpeedCoefficient; public static string startChargeLoopSFXString; public static string endChargeLoopSFXString; public static string enterSFXString; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private Transform chargeVfxInstanceTransform; private int gauntlet; private uint soundID; private bool chargeAnimPlayed; protected float chargeDuration { get; private set; } protected float charge { get; private set; } public override void OnEnter() { base.OnEnter(); chargeDuration = baseChargeDuration; Util.PlaySound(enterSFXString, base.gameObject); soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnExit() { if ((bool)chargeVfxInstanceTransform) { EntityState.Destroy(chargeVfxInstanceTransform.gameObject); PlayAnimation("Gesture, Additive", "Empty"); PlayAnimation("Gesture, Override", "Empty"); crosshairOverrideRequest?.Dispose(); chargeVfxInstanceTransform = null; } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; Util.PlaySound(endChargeLoopSFXString, base.gameObject); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); charge = Mathf.Clamp01(base.fixedAge / chargeDuration); AkSoundEngine.SetRTPCValueByPlayingID("loaderShift_chargeAmount", charge * 100f, soundID); base.characterBody.SetSpreadBloom(charge); base.characterBody.SetAimTimer(3f); if (charge >= minChargeForChargedAttack && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab) { if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } Transform transform = FindModelChild(chargeVfxChildLocatorName); if ((bool)transform) { chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform; ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent(); if ((bool)component) { component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration; } } if (!chargeAnimPlayed) { PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f); PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f); chargeAnimPlayed = true; } } if ((bool)chargeVfxInstanceTransform) { base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; } if (base.isAuthority) { AuthorityFixedUpdate(); } } public override void Update() { base.Update(); Mathf.Clamp01(base.age / chargeDuration); } private void AuthorityFixedUpdate() { ShouldKeepChargingAuthority(); } protected virtual bool ShouldKeepChargingAuthority() { return IsKeyDownAuthority(); } } public class CorruptedPaths : BaseCharacterMain { [SerializeField] public float baseDuration; public float charge; public static float minimumDuration; public static float blastRadius; public static float blastProcCoefficient; public static float blastDamageCoefficient; public static float blastForce; public static string enterSoundString; public static UnityEngine.Vector3 blastBonusForce; public static GameObject blastImpactEffectPrefab; public static GameObject blastEffectPrefab; public static GameObject fistEffectPrefab; public static GameObject swingEffectPrefab; private GameObject leftFistEffectInstance; private GameObject rightFistEffectInstance; private GameObject swingEffectInstance; private bool detonateNextFrame; public override void OnEnter() { base.OnEnter(); baseDuration /= attackSpeedStat; PlayAnimation("FullBody, Override", "ChargeSwing", "ChargeSwing.playbackRate", baseDuration); Util.PlaySound(enterSoundString, base.gameObject); swingEffectInstance = UnityEngine.Object.Instantiate(swingEffectPrefab, FindModelChild("OverHeadSwingPoint")); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= minimumDuration) { DetonateAuthority(); if (base.characterBody.GetBuffCount(DLC2Content.Buffs.CorruptionFesters) == 0) { outer.SetNextState(new CorruptedPathsDash()); } else { outer.SetNextStateToMain(); } } } public override void OnExit() { base.OnExit(); } protected BlastAttack.Result DetonateAuthority() { UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position; EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = position, scale = blastRadius }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * (blastDamageCoefficient * charge) + (base.characterBody.maxHealth - (base.characterBody.baseMaxHealth + base.characterBody.levelMaxHealth * (float)((int)base.characterBody.level - 1))) * 0.01f, baseForce = blastForce, bonusForce = blastBonusForce, crit = RollCrit(), falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius, position = position, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class CorruptedPathsDash : BaseState { private Transform modelTransform; public static GameObject dashPrefab; public static float smallHopVelocity = 0.35f; public static float dashPrepDuration = 0.8f; public static float dashDuration = 0.05f; public static float speedCoefficient = 15f; public static float gapToEnemy = 0f; public static string beginSoundString; public static string endSoundString; public static float damageCoefficient = 2f; public static float procCoefficient; public static GameObject hitEffectPrefab; public static float hitPauseDuration; private float stopwatch; private UnityEngine.Vector3 dashVector = UnityEngine.Vector3.zero; private Animator animator; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private OverlapAttack overlapAttack; private ChildLocator childLocator; private bool isDashing; private bool inHitPause; private float hitPauseTimer; private CameraTargetParams.AimRequest aimRequest; private CharacterBody survivorBody; public static GameObject explosionEffect; public BlastAttack explosionAttack; private float maxHealth; private int originalLayer; public bool hasHit { get; private set; } public int dashIndex { private get; set; } public override void OnEnter() { base.OnEnter(); dashDuration = UnityEngine.Vector3.Distance(base.characterBody.master.GetComponent().currentEnemy.characterBody.transform.position, base.transform.position) * 0.1f / speedCoefficient - gapToEnemy; Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); survivorBody = base.gameObject.GetComponent(); if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } if ((bool)modelTransform) { animator = modelTransform.GetComponent(); characterModel = modelTransform.GetComponent(); childLocator = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); _ = (bool)childLocator; } SmallHop(base.characterMotor, smallHopVelocity); PlayAnimation("FullBody, Override", "StepBrothersPrep", "StepBrothersPrep.playbackRate", dashPrepDuration); dashVector = base.inputBank.aimDirection; overlapAttack = InitMeleeOverlap(0f, hitEffectPrefab, modelTransform, "StepBrothers"); if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); } } private void CreateDashEffect() { Transform transform = childLocator.FindChild("DashCenter"); if ((bool)transform && (bool)dashPrefab) { UnityEngine.Object.Instantiate(dashPrefab, transform.position, Util.QuaternionSafeLookRotation(dashVector), transform); } } public override void FixedUpdate() { base.FixedUpdate(); base.characterDirection.forward = dashVector; if (stopwatch > dashPrepDuration && !isDashing) { isDashing = true; dashVector = base.inputBank.aimDirection; CreateDashEffect(); PlayCrossfade("FullBody, Override", "StepBrothersLoop", 0.1f); originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal; base.characterMotor.Motor.RebuildCollidableLayers(); } if (!isDashing) { stopwatch += GetDeltaTime(); } else if (base.isAuthority) { base.characterMotor.velocity = UnityEngine.Vector3.zero; if (!inHitPause) { bool num = overlapAttack.Fire(); stopwatch += GetDeltaTime(); if (num) { UnityEngine.Vector3 position = base.gameObject.transform.position; EffectManager.SpawnEffect(explosionEffect, new EffectData { origin = position, scale = 1f }, transmit: true); explosionAttack = new BlastAttack(); explosionAttack.attacker = base.gameObject; explosionAttack.inflictor = base.gameObject; explosionAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); explosionAttack.baseDamage = damageStat * damageCoefficient; explosionAttack.position = position; explosionAttack.radius = 20f; explosionAttack.Fire(); if (!hasHit) { hasHit = true; } inHitPause = true; hitPauseTimer = hitPauseDuration / attackSpeedStat; } base.characterMotor.rootMotion += dashVector * moveSpeedStat * speedCoefficient * GetDeltaTime(); } else { hitPauseTimer -= GetDeltaTime(); if (hitPauseTimer < 0f) { inHitPause = false; } } } if (stopwatch >= dashDuration + dashPrepDuration && base.isAuthority) { outer.SetNextState(GetNextStateAuthority()); } } public override void OnExit() { base.gameObject.layer = originalLayer; base.characterMotor.Motor.RebuildCollidableLayers(); Util.PlaySound(endSoundString, base.gameObject); if (base.isAuthority) { base.characterMotor.velocity *= -0.3f; SmallHop(base.characterMotor, smallHopVelocity); } aimRequest?.Dispose(); _ = (bool)childLocator; PlayAnimation("FullBody, Override", "StepBrothersLoopExit"); if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); } base.OnExit(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)dashIndex); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); dashIndex = reader.ReadByte(); } protected virtual EntityState GetNextStateAuthority() { return new FissureSlam(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class CrystalDeathState : GenericCharacterDeath { public static GameObject deathEffectPrefab; public static float duration = 3f; public float vfxSize = 8f; private bool playedSFX; private bool _shouldAutoDestroy; protected override bool shouldAutoDestroy => _shouldAutoDestroy; public override void OnEnter() { base.OnEnter(); } protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayAnimation("FullBody, Override", "Phase1Death", "StepBrothersPrep.playbackRate", duration); MeridianEventTriggerInteraction.instance.musicPhaseOne.SetActive(value: false); MeridianEventTriggerInteraction.instance.musicPhaseTwo.SetActive(value: true); } public override void FixedUpdate() { if (base.fixedAge >= 2f && !playedSFX) { Util.PlaySound("Play_boss_falseson_phaseTransition_kneel", base.characterBody.gameObject); Util.PlaySound("Play_boss_falseson_VO_groan", base.gameObject); playedSFX = true; } if (!_shouldAutoDestroy && NetworkServer.active && base.fixedAge >= duration + 0.5f) { EffectManager.SpawnEffect(deathEffectPrefab, new EffectData { origin = base.characterBody.corePosition, scale = vfxSize }, transmit: true); _shouldAutoDestroy = true; } base.FixedUpdate(); } public override void OnExit() { DestroyBodyAsapServer(); DestroyModel(); base.OnExit(); MeridianEventTriggerInteraction.FSBFPhaseBaseState.readyToSpawnNextBossBody = true; DestroyBodyServer(); } private void DestroyBodyServer() { if (NetworkServer.active) { OnPreDestroyBodyServer(); EntityState.Destroy(base.gameObject); } } } public class BrokenCrystalDeathState : GenericCharacterDeath { public static float duration = 3f; public static GameObject deathEffectPrefab; public float vfxSize = 8f; private bool playedSFX; private bool _shouldAutoDestroy; protected override bool shouldAutoDestroy => _shouldAutoDestroy; public override void OnEnter() { base.OnEnter(); } protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { MeridianEventTriggerInteraction.instance.musicPhaseTwo.SetActive(value: false); MeridianEventTriggerInteraction.instance.musicPhaseThree.SetActive(value: true); PlayAnimation("FullBody, Override", "Phase2Death", "StepBrothersPrep.playbackRate", duration); } public override void FixedUpdate() { if (base.fixedAge >= 2f && !playedSFX) { Util.PlaySound("Play_boss_falseson_phaseTransition_kneel", base.characterBody.gameObject); Util.PlaySound("Play_boss_falseson_VO_anger", base.characterBody.gameObject); playedSFX = true; } if (!_shouldAutoDestroy && NetworkServer.active && (double)base.fixedAge >= (double)duration + 0.5) { _shouldAutoDestroy = true; EffectManager.SpawnEffect(deathEffectPrefab, new EffectData { origin = base.characterBody.corePosition, scale = vfxSize }, transmit: true); } base.FixedUpdate(); } public override void OnExit() { DestroyModel(); base.OnExit(); MeridianEventTriggerInteraction.FSBFPhaseBaseState.readyToSpawnNextBossBody = true; DestroyBodyServer(); } private void DestroyBodyServer() { if (NetworkServer.active) { OnPreDestroyBodyServer(); EntityState.Destroy(base.gameObject); } } } public class SkyJumpDeathState : GenericCharacterDeath { [SerializeField] public float duration = 4.5f; public GameObject deathEffectPrefab; public float vfxSize = 8f; private float beginUpwardMovementTime = 0.96086955f; private bool startedFlying; private UnityEngine.Vector3 cachedDeathPosition; private bool _shouldAutoDestroy; [SerializeField] public GameObject falseSonJumpAwayVFX; [SerializeField] public ItemTier rewardDisplayTier; [Tooltip("The prefab to use for the reward pickup.")] [SerializeField] public GameObject rewardPickupPrefab; [SerializeField] public UnityEngine.Vector3 rewardOffset; [SerializeField] public string falseSonSurvivorAchievement; private PickupIndex halcyonSeed; [SerializeField] public int rewardOptionCount = 1; [SerializeField] public PickupDropTable dtColossusBuffDropTable; public bool rewardGiven; private bool playedSFX; protected override bool shouldAutoDestroy => _shouldAutoDestroy; public static event Action falseSonDeathEvent; public static event Action falseSonUnlockEvent; public override void OnEnter() { base.OnEnter(); SkyJumpDeathState.falseSonDeathEvent?.Invoke(); beginUpwardMovementTime *= duration; cachedDeathPosition = base.gameObject.transform.position; EffectManager.SpawnEffect(LegacyResourcesAPI.Load("FalseSonBoss/FalseSonBossLightningStreakDeath"), new EffectData { origin = base.characterBody.corePosition, scale = vfxSize }, transmit: true); halcyonSeed = PickupCatalog.FindPickupIndex("TitanGoldDuringTP"); GiveColossusItem(); } protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayAnimation("FullBody, Override", "Phase3Death", "StepBrothersPrep.playbackRate", duration); Util.PlaySound("Play_boss_falseson_VO_defeat", base.gameObject); MeridianEventTriggerInteraction.instance.musicPhaseThree.SetActive(value: false); MeridianEventTriggerInteraction.instance.musicPhaseBossDead.SetActive(value: true); } public override void FixedUpdate() { if (base.fixedAge >= 0.35f && !playedSFX) { Util.PlaySound("Play_boss_falseson_phaseTransition_kneel", base.characterBody.gameObject); Util.PlaySound("Play_boss_falseson_VO_groan", base.characterBody.gameObject); playedSFX = true; } if (base.fixedAge > beginUpwardMovementTime) { if (!startedFlying) { if (NetworkServer.active) { LightningStormController.SetStormActive(b: false); } startedFlying = true; EffectManager.SpawnEffect(falseSonJumpAwayVFX, new EffectData { origin = cachedDeathPosition }, transmit: false); } base.characterMotor.rootMotion += UnityEngine.Vector3.up * moveSpeedStat; } if (!_shouldAutoDestroy && NetworkServer.active && base.fixedAge >= duration + 0.5f) { _shouldAutoDestroy = true; } base.FixedUpdate(); } public override void OnExit() { DestroyBodyAsapServer(); DestroyModel(); base.OnExit(); MeridianEventTriggerInteraction.FSBFPhaseBaseState.readyToSpawnNextBossBody = true; DestroyBodyServer(); } private void DestroyBodyServer() { if (NetworkServer.active) { OnPreDestroyBodyServer(); EntityState.Destroy(base.gameObject); } } private void GiveColossusItem() { if (!NetworkServer.active) { return; } int participatingPlayerCount = Run.instance.participatingPlayerCount; if (dtColossusBuffDropTable == null || participatingPlayerCount == 0) { return; } if (FalseSonUnlockStateMet()) { SkyJumpDeathState.falseSonUnlockEvent?.Invoke(); dtColossusBuffDropTable = LegacyResourcesAPI.Load("DropTables/dtAurelioniteHeartPickupDropTable"); } Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); if (participatingPlayerCount > 0 && (bool)base.gameObject && (bool)dtColossusBuffDropTable && !rewardGiven) { rewardGiven = true; int num = participatingPlayerCount; float angle = 360f / (float)num; UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); UnityEngine.Vector3 position = cachedDeathPosition + rewardOffset; int num2 = 0; while (num2 < num) { GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo); pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier); pickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(rewardOptionCount, dtColossusBuffDropTable, rng); pickupInfo.rotation = UnityEngine.Quaternion.identity; pickupInfo.prefabOverride = rewardPickupPrefab; PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector); num2++; vector = quaternion * vector; } } } private bool FalseSonUnlockStateMet() { bool result = false; if (MeridianEventTriggerInteraction.instance.isGoldTitanSpawned) { return true; } foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (!(instance == null) && instance.master.inventory.GetItemCount(RoR2Content.Items.TitanGoldDuringTP) > 0) { result = true; GameObject effectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/DelusionItemDissolveVFX"); EffectData effectData = new EffectData { origin = instance.master.GetBody().transform.position, genericFloat = 1.5f, genericUInt = (uint)(halcyonSeed.itemIndex + 1) }; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true); instance.master.inventory.RemoveItem(halcyonSeed.itemIndex); } } return result; } } public class FalseSonBossGenericStateWithSwing : GenericCharacterMain { private bool transitioningToMeleeSwingState; public override void OnEnter() { base.OnEnter(); transitioningToMeleeSwingState = false; } public override void Update() { if (base.characterBody == null || base.characterBody.coreTransform == null) { if (outer != null) { outer.SetNextStateToMain(); } return; } base.Update(); if (!transitioningToMeleeSwingState) { FalseSonBossStateHelper.TrySwitchToMeleeSwing(ref transitioningToMeleeSwingState, base.characterBody.coreTransform, base.characterDirection.forward, null, outer); } } public override void FixedUpdate() { if (!transitioningToMeleeSwingState) { base.FixedUpdate(); } } public override InterruptPriority GetMinimumInterruptPriority() { if (transitioningToMeleeSwingState) { return InterruptPriority.Frozen; } return InterruptPriority.Any; } } public static class FalseSonBossStateHelper { private static int hitLimit = 2; private static float coolDownDuration = 2f; private static int hitCount = 0; private static float coolDownTimeStamp = -3f; private static float maxDistanceSquared = 225f; private static bool CheckPlayerOrMinionsForProximity(PlayerCharacterMasterController playerController, UnityEngine.Vector3 playerPosition, UnityEngine.Vector3 aimDirection, UnityEngine.Vector3 bossPosition) { UnityEngine.Vector3 vectorToCharacter; if (CharacterIsInFrontOfUs(playerPosition)) { return true; } MinionOwnership.MinionGroup minionGroup = MinionOwnership.MinionGroup.FindGroup(playerController.master.netId); if (minionGroup == null || minionGroup.memberCount < 1) { return false; } MinionOwnership[] members = minionGroup.members; foreach (MinionOwnership minionOwnership in members) { if (!(minionOwnership == null)) { UnityEngine.Vector3 value = (minionOwnership.GetComponent()?.GetBody()?.corePosition).Value; if (value != UnityEngine.Vector3.zero && CharacterIsInFrontOfUs(value)) { return true; } } } return false; bool CharacterIsInFrontOfUs(UnityEngine.Vector3 position) { vectorToCharacter = position - bossPosition; if (UnityEngine.Vector3.SqrMagnitude(vectorToCharacter) > maxDistanceSquared) { return false; } if (UnityEngine.Vector3.Dot(vectorToCharacter.normalized, aimDirection) <= 0f) { return false; } return true; } } public static bool TrySwitchToMeleeSwing(ref bool stateAborted, Transform bossTransform, UnityEngine.Vector3 aimDirection, GenericSkill previousSkill, EntityStateMachine outer) { if (bossTransform == null) { return false; } if (PlatformSystems.networkManager.serverFixedTime - coolDownTimeStamp < coolDownDuration) { return false; } stateAborted = false; foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (!(instance == null)) { CharacterBody body = instance.master.GetBody(); if (!(body == null) && CheckPlayerOrMinionsForProximity(instance, body.corePosition, aimDirection, bossTransform.position)) { stateAborted = true; break; } } } if (stateAborted) { outer.SetNextState(new SwatAwayPlayersWindup()); if ((bool)previousSkill) { previousSkill.Reset(); } hitCount++; if (hitCount >= hitLimit) { coolDownTimeStamp = PlatformSystems.networkManager.serverFixedTime; hitCount = 0; } } return stateAborted; } } public class FissureSlam : BaseCharacterMain { [SerializeField] public float baseDuration; [SerializeField] public int totalFissures = 5; [SerializeField] public float delayBetweenFissures = 0.001f; public float charge; public static float minimumDuration; public static float blastRadius; public static float blastProcCoefficient; public static float blastDamageCoefficient; public static float blastForce; public static string enterSoundString; public static UnityEngine.Vector3 blastBonusForce; public static GameObject blastImpactEffectPrefab; public static GameObject blastEffectPrefab; public static GameObject fistEffectPrefab; public static GameObject swingEffectPrefab; public static GameObject fissureSlamObject; private GameObject leftFistEffectInstance; private GameObject rightFistEffectInstance; private GameObject swingEffectInstance; private bool detonateNextFrame; private bool amServer; private bool slamComplete; private float fissureExplosionDelay = 0.7f; private float fissureExplosionTimer; private NodeGraph nodeGraph; private List possibleNodesToTarget; private List playersToTarget; private List fissurePositions; private int totalFissuresFired; private float timeToGenerateNextFissure; public static GameObject crackWarningEffectPrefab; public static GameObject fissureExplosionEffectPrefab; public static GameObject pillarProjectilePrefab; private bool stateAborted; public override void OnEnter() { base.OnEnter(); amServer = NetworkServer.active; baseDuration /= attackSpeedStat; PlayAnimation("FullBody, Override", "ChargeSwing", "ChargeSwing.playbackRate", baseDuration); Util.PlaySound(enterSoundString, base.gameObject); leftFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("HandR")); rightFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("HandL")); swingEffectInstance = UnityEngine.Object.Instantiate(swingEffectPrefab, FindModelChild("OverHeadSwingPoint")); nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); possibleNodesToTarget = nodeGraph.FindNodesInRange(base.characterBody.corePosition, 0f, 30f, HullMask.Human); playersToTarget = new List(); fissurePositions = new List(); totalFissuresFired = 0; timeToGenerateNextFissure = 0f; if (!amServer) { return; } foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (!(instance == null) && !(instance.master.GetBodyObject() == null)) { playersToTarget.Add(instance.master.GetBodyObject()); } } Util.ShuffleList(playersToTarget); RaycastToFindGroundPointOfNextPlayer(); } private void RaycastToFindGroundPointOfNextPlayer() { if (fissurePositions.Count >= totalFissures) { return; } if (fissurePositions.Count < playersToTarget.Count && playersToTarget.Count > 0) { if (Physics.Raycast(new Ray(playersToTarget[fissurePositions.Count].transform.position + UnityEngine.Vector3.up * 1f, UnityEngine.Vector3.down), out var hitInfo, 200f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { fissurePositions.Add(hitInfo.point); } else { if (possibleNodesToTarget.Count < 1) { return; } int index = UnityEngine.Random.Range(0, possibleNodesToTarget.Count); nodeGraph.GetNodePosition(possibleNodesToTarget[index], out var position); fissurePositions.Add(position); possibleNodesToTarget.RemoveAt(index); } } if (fissurePositions.Count >= playersToTarget.Count) { FillRemainingFissurePositions(); } } private void FillRemainingFissurePositions() { if (fissurePositions.Count >= totalFissures) { return; } int num = Mathf.Max(totalFissures - fissurePositions.Count, 0); for (int i = 0; i < num; i++) { if (possibleNodesToTarget.Count < 1) { break; } int index = UnityEngine.Random.Range(0, possibleNodesToTarget.Count); nodeGraph.GetNodePosition(possibleNodesToTarget[index], out var position); fissurePositions.Add(position); possibleNodesToTarget.RemoveAt(index); } } public override void FixedUpdate() { base.FixedUpdate(); if (stateAborted) { return; } RaycastToFindGroundPointOfNextPlayer(); if (!slamComplete && base.fixedAge >= baseDuration - baseDuration * 0.8f && amServer) { DetonateAuthority(); slamComplete = true; FillRemainingFissurePositions(); int num = Mathf.Min(totalFissures, fissurePositions.Count); for (int i = 0; i < num; i++) { EffectManager.SpawnEffect(crackWarningEffectPrefab, new EffectData { origin = fissurePositions[i] + UnityEngine.Vector3.up * 0.01f }, transmit: true); } } if (!slamComplete || !amServer) { return; } fissureExplosionTimer += Time.deltaTime; if (fissureExplosionTimer > fissureExplosionDelay) { int num2 = Mathf.Min(totalFissures, fissurePositions.Count); for (int j = 0; j < num2; j++) { ProjectileManager.instance.FireProjectile(pillarProjectilePrefab, fissurePositions[j], UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * (blastDamageCoefficient * 0.2f), 0f, Util.CheckRoll(base.characterBody.crit, base.characterBody.master)); } outer.SetNextStateToMain(); } } public override void OnExit() { if (!stateAborted) { EntityState.Destroy(leftFistEffectInstance); EntityState.Destroy(rightFistEffectInstance); base.OnExit(); } } protected BlastAttack.Result DetonateAuthority() { UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position; EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = position, scale = blastRadius }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * blastDamageCoefficient, baseForce = blastForce, bonusForce = blastBonusForce, crit = RollCrit(), falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius + 3f, position = position, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } internal class List { } public class FissureSlamWindup : BaseSkillState { [SerializeField] public float baseChargeDuration = 1f; [SerializeField] public float chargeThreshold = 3f; public static float minChargeForChargedAttack; public static GameObject chargeVfxPrefab; public static string chargeVfxChildLocatorName; public static GameObject crosshairOverridePrefab; public static float walkSpeedCoefficient; public static string startChargeLoopSFXString; public static string endChargeLoopSFXString; public static string enterSFXString; private int gauntlet; private uint soundID; private Transform chargeVfxInstanceTransform; private bool chargeAnimPlayed; private bool stateAborted; protected float chargeDuration { get; private set; } protected float charge { get; private set; } public override void OnEnter() { base.OnEnter(); chargeDuration = 0.5f; Util.PlaySound(enterSFXString, base.gameObject); soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject); if (base.characterBody.GetBuffCount(DLC2Content.Buffs.WeakenedBeating) > 0) { charge = 0.5f; } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnExit() { if (!stateAborted) { if ((bool)chargeVfxInstanceTransform) { EntityState.Destroy(chargeVfxInstanceTransform.gameObject); PlayAnimation("Gesture, Additive", "Empty"); PlayAnimation("Gesture, Override", "Empty"); chargeVfxInstanceTransform = null; } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; Util.PlaySound(endChargeLoopSFXString, base.gameObject); base.OnExit(); } } public override void FixedUpdate() { if (stateAborted) { return; } base.FixedUpdate(); charge += Time.deltaTime; base.characterBody.SetSpreadBloom(charge); base.characterBody.SetAimTimer(3f); if (charge <= 3f && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab) { Transform transform = FindModelChild(chargeVfxChildLocatorName); if ((bool)transform) { chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform; ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent(); if ((bool)component) { component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration; } } if (!chargeAnimPlayed) { PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", chargeDuration, 0.1f); PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", chargeDuration, 0.1f); chargeAnimPlayed = true; } } else if (charge > baseChargeDuration) { outer.SetNextState(GetNextStateAuthority()); } if ((bool)chargeVfxInstanceTransform) { base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; } } public override void Update() { if (!stateAborted) { base.Update(); Mathf.Clamp01(base.age / chargeDuration); } } protected virtual EntityState GetNextStateAuthority() { return new FissureSlam(); } } public class HeroRelicSwing : BasicMeleeAttack { private float swingTimer; protected override void PlayAnimation() { string animationStateName = "SwingClubRight"; float num = Mathf.Max(duration, 0.2f); PlayCrossfade("Gesture, Additive", animationStateName, "SwingClub.playbackRate", num, 0.1f); PlayCrossfade("Gesture, Override", animationStateName, "SwingClub.playbackRate", num, 0.1f); } protected override void BeginMeleeAttackEffect() { swingEffectMuzzleString = "SwingRight"; base.BeginMeleeAttackEffect(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } public override void FixedUpdate() { base.FixedUpdate(); swingTimer += Time.deltaTime; if (swingTimer > baseDuration) { outer.SetNextState(GetNextStateAuthority()); } } protected virtual EntityState GetNextStateAuthority() { return new HeroRelicSwingLeft(); } } public class HeroRelicSwingLeft : BasicMeleeAttack { private float swingTimer; protected override void PlayAnimation() { string animationStateName = "SwingClubLeft"; float num = Mathf.Max(duration, 0.2f); PlayCrossfade("Gesture, Additive", animationStateName, "SwingClub.playbackRate", num, 0.1f); PlayCrossfade("Gesture, Override", animationStateName, "SwingClub.playbackRate", num, 0.1f); } protected override void BeginMeleeAttackEffect() { swingEffectMuzzleString = "SwingLeft"; base.BeginMeleeAttackEffect(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } public override void FixedUpdate() { base.FixedUpdate(); swingTimer += Time.deltaTime; if (swingTimer > baseDuration) { outer.SetNextStateToMain(); } } } public class LunarGazeCharge : BaseState { public static float baseDuration = 3f; public static float laserMaxWidth = 0.2f; [SerializeField] public GameObject effectPrefab; [SerializeField] public GameObject laserPrefab; public static string chargeAttackSoundString; public static float lockOnAngle; private HurtBox lockedOnHurtBox; public float duration; private GameObject chargeEffect; private GameObject laserEffect; private LineRenderer laserLineComponent; private UnityEngine.Vector3 visualEndPosition; private float flashTimer; private bool laserOn; private BullseyeSearch enemyFinder; private const float originalSoundDuration = 2.1f; protected EntityState fireState; public override void OnEnter() { base.OnEnter(); fireState = new LunarGazeFire(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", "LaserBlastStart", "LaserBlast.playbackRate", duration); PlayAnimation("Gesture, Override", "LaserBlastStart", "LaserBlast.playbackRate", duration); Transform modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(chargeAttackSoundString, base.gameObject, 2.1f / duration); Ray aimRay = GetAimRay(); enemyFinder = new BullseyeSearch(); if ((bool)base.characterBody) { enemyFinder.viewer = base.characterBody; } enemyFinder.maxDistanceFilter = 2000f; enemyFinder.maxAngleFilter = lockOnAngle; enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.filterByLoS = false; enemyFinder.sortMode = BullseyeSearch.SortMode.Angle; enemyFinder.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleLaser"); if ((bool)transform) { if ((bool)effectPrefab) { chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); chargeEffect.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffect.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } if ((bool)laserPrefab) { laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation); laserEffect.transform.parent = transform; laserLineComponent = laserEffect.GetComponent(); } } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } flashTimer = 0f; laserOn = true; } public override void OnExit() { PlayAnimation("FullBody, Override", "Empty"); base.OnExit(); if ((bool)chargeEffect) { EntityState.Destroy(chargeEffect); } if ((bool)laserEffect) { EntityState.Destroy(laserEffect); } } public override void Update() { base.Update(); if (!laserEffect || !laserLineComponent) { return; } float num = 1000f; Ray aimRay = GetAimRay(); enemyFinder.RefreshCandidates(); lockedOnHurtBox = enemyFinder.GetResults().FirstOrDefault(); if ((bool)lockedOnHurtBox) { aimRay.direction = lockedOnHurtBox.transform.position - aimRay.origin; } UnityEngine.Vector3 position = laserEffect.transform.parent.position; UnityEngine.Vector3 point = aimRay.GetPoint(num); if (Physics.Raycast(aimRay, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault)) { point = hitInfo.point; } laserLineComponent.SetPosition(0, position); laserLineComponent.SetPosition(1, point); float num2; if (duration - base.age > 0.5f) { num2 = base.age / duration; } else { flashTimer -= Time.deltaTime; if (flashTimer <= 0f) { laserOn = !laserOn; flashTimer = 1f / 30f; } num2 = (laserOn ? 1f : 0f); } num2 *= laserMaxWidth; laserLineComponent.startWidth = num2; laserLineComponent.endWidth = num2; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { EntityState nextState = fireState; outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class LunarGazeChargePlus : LunarGazeCharge { public override void OnEnter() { base.OnEnter(); fireState = new LunarGazeFirePlus(); } } public class LunarGazeFire : BaseState { [SerializeField] public GameObject effectPrefab; [SerializeField] public GameObject hitEffectPrefab; [SerializeField] public GameObject laserPrefab; public static string playAttackSoundString; public static string playLoopSoundString; public static string stopLoopSoundString; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float fireFrequency; public static float maxDistance; public static float minimumDuration; public static float maximumDuration; public static float lockOnAngle; public static float procCoefficientPerTick; public static DamageType lunarGazeDamageType; public static bool isLunarGazePlusPlus; private HurtBox lockedOnHurtBox; private float fireStopwatch; private float stopwatch; private Ray aimRay; private Transform modelTransform; private GameObject laserEffect; private ChildLocator laserChildLocator; private Transform laserEffectEnd; protected Transform muzzleTransform; private BullseyeSearch enemyFinder; private bool foundAnyTarget; public override void OnEnter() { base.OnEnter(); base.characterBody.SetAimTimer(maximumDuration); Util.PlaySound(playAttackSoundString, base.gameObject); Util.PlaySound(playLoopSoundString, base.gameObject); PlayCrossfade("Gesture, Additive", "LaserBlastLoop", 0.25f); PlayCrossfade("Gesture, Override", "LaserBlastLoop", 0.25f); enemyFinder = new BullseyeSearch(); enemyFinder.viewer = base.characterBody; enemyFinder.maxDistanceFilter = maxDistance; enemyFinder.maxAngleFilter = lockOnAngle; enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.filterByLoS = false; enemyFinder.sortMode = BullseyeSearch.SortMode.Angle; enemyFinder.teamMaskFilter = TeamMask.allButNeutral; if ((bool)base.teamComponent) { enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex); } aimRay = GetAimRay(); modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { muzzleTransform = component.FindChild("MuzzleLaser"); if ((bool)muzzleTransform && (bool)laserPrefab) { laserEffect = UnityEngine.Object.Instantiate(laserPrefab, muzzleTransform.position, muzzleTransform.rotation); laserEffect.transform.parent = muzzleTransform; laserChildLocator = laserEffect.GetComponent(); laserEffectEnd = laserChildLocator.FindChild("LaserEnd"); } } } UpdateLockOn(); } public override void OnExit() { PlayCrossfade("Gesture, Additive", "Empty", 0.25f); PlayCrossfade("Gesture, Override", "Empty", 0.25f); if ((bool)laserEffect) { EntityState.Destroy(laserEffect); } base.characterBody.SetAimTimer(2f); Util.PlaySound(stopLoopSoundString, base.gameObject); base.OnExit(); } private void UpdateLockOn() { if (base.isAuthority) { enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.RefreshCandidates(); HurtBox hurtBox = enemyFinder.GetResults().FirstOrDefault(); if (!(lockedOnHurtBox != null) || !(hurtBox == null) || !enemyFinder.CheckVisible(lockedOnHurtBox.healthComponent.gameObject)) { lockedOnHurtBox = hurtBox; foundAnyTarget = hurtBox; } } } public override void FixedUpdate() { base.FixedUpdate(); fireStopwatch += GetDeltaTime(); stopwatch += GetDeltaTime(); aimRay = GetAimRay(); UnityEngine.Vector3 vector = aimRay.origin; if ((bool)muzzleTransform) { vector = muzzleTransform.position; } RaycastHit hitInfo; UnityEngine.Vector3 vector2 = (lockedOnHurtBox ? lockedOnHurtBox.transform.position : ((!Util.CharacterRaycast(base.gameObject, aimRay, out hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) ? aimRay.GetPoint(maxDistance) : hitInfo.point)); Ray ray = new Ray(vector, vector2 - vector); bool flag = false; if ((bool)laserEffect && (bool)laserChildLocator) { if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo2, (vector2 - vector).magnitude, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal)) { vector2 = hitInfo2.point; if (Util.CharacterRaycast(base.gameObject, new Ray(vector2 - ray.direction * 0.1f, -ray.direction), out var _, hitInfo2.distance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal)) { vector2 = ray.GetPoint(0.1f); flag = true; } } laserEffect.transform.rotation = Util.QuaternionSafeLookRotation(vector2 - vector); laserEffectEnd.transform.position = vector2; } if (fireStopwatch > 1f / fireFrequency) { string targetMuzzle = "MuzzleLaser"; if (!flag) { FireBullet(modelTransform, ray, targetMuzzle, (vector2 - ray.origin).magnitude + 0.1f); } UpdateLockOn(); fireStopwatch -= 1f / fireFrequency; } if (base.isAuthority && (((!base.inputBank || !base.inputBank.skill4.down) && stopwatch > minimumDuration) || stopwatch > maximumDuration)) { Util.PlaySound("Play_boss_falseson_skill3_lunarGaze_end", base.gameObject); outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } private void FireBullet(Transform modelTransform, Ray aimRay, string targetMuzzle, float maxDistance) { if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (!base.isAuthority) { return; } if (isLunarGazePlusPlus) { if (Util.CheckRoll(10f)) { lunarGazeDamageType = DamageType.LunarRuin; } else { lunarGazeDamageType = DamageType.Generic; } } BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.bulletCount = 1u; bulletAttack.damage = damageCoefficient * damageStat / fireFrequency; bulletAttack.force = force; bulletAttack.damageType = lunarGazeDamageType; bulletAttack.muzzleName = targetMuzzle; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.procCoefficient = procCoefficientPerTick; bulletAttack.HitEffectNormal = false; bulletAttack.radius = 0f; bulletAttack.maxDistance = maxDistance; bulletAttack.Fire(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(HurtBoxReference.FromHurtBox(lockedOnHurtBox)); writer.Write(stopwatch); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); HurtBoxReference hurtBoxReference = reader.ReadHurtBoxReference(); stopwatch = reader.ReadSingle(); lockedOnHurtBox = hurtBoxReference.ResolveGameObject()?.GetComponent(); } } public class LunarGazeFirePlus : LunarGazeFire { public static float plusDamageCoefficient; public override void OnEnter() { LunarGazeFire.playAttackSoundString = "Play_boss_falseson_skill3plus_lunarGaze_start"; LunarGazeFire.playLoopSoundString = "Play_boss_falseson_skill3plus_lunarGaze_active_loop"; LunarGazeFire.stopLoopSoundString = "Stop_boss_falseson_skill3plus_lunarGaze_active_loop"; LunarGazeFire.isLunarGazePlusPlus = true; LunarGazeFire.damageCoefficient += plusDamageCoefficient; base.OnEnter(); } public override void OnExit() { Util.PlaySound("Play_boss_falseson_skill3plus_lunarGaze_end", base.gameObject); base.OnExit(); } } public class LunarRain : BaseState { [SerializeField] public float duration; [SerializeField] public float warningDuration; [SerializeField] public float delayBetweenDrops = 0.2f; [SerializeField] public float lunarRadius; [SerializeField] public int totalLunarDrops = 7; [SerializeField] public float percentVarianceRotation = 0.25f; [SerializeField] public float percentVarianceInRadius = 0.2f; public static GameObject warningFXPrefab; public static GameObject rainCrashEffectPrefab; public static GameObject lunarRainPrefab; public static GameObject blastImpactEffectPrefab; [SerializeField] public GameObject blastEffectPrefab; [SerializeField] public float blastRadius = 2f; public static float blastProcCoefficient; public static float blastDamageCoefficient; public static float blastForce; public static UnityEngine.Vector3 blastBonusForce; private NodeGraph nodeGraph; private List nodesToTeleportTo; private List fissureLocs; private UnityEngine.Vector3 fissureLocation; private bool lunarRainStarted; private float lunarRainStartTime; private int totalWarned; private int totalFired; private int totalLunarDropsToFire; private float nextDropTime; public override void OnEnter() { base.OnEnter(); new System.Random(); nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); fissureLocs = new List(); totalLunarDrops = ((totalLunarDrops > 0) ? totalLunarDrops : 7); float num = ((lunarRadius > 0f) ? lunarRadius : 30f); Transform transform = base.characterBody.transform; UnityEngine.Vector3 position = transform.position; UnityEngine.Vector3 angleOffset2 = UnityEngine.Quaternion.AngleAxis(-90f, UnityEngine.Vector3.up) * transform.forward; angleOffset2.y = 0f; NodeGraph.NodeIndex nodeIndex = nodeGraph.FindClosestNode(position, HullClassification.Human); for (int j = 0; j < totalLunarDrops; j++) { UnityEngine.Vector3 position2 = GeneratePositionAroundCircle(j, totalLunarDrops, position, num * UnityEngine.Random.Range(0.7f, 1.3f), angleOffset2); NodeGraph.NodeIndex nodeIndex2 = SceneInfo.instance.groundNodes.FindClosestNode(position2, HullClassification.Human); if (!fissureLocs.Contains(nodeIndex2) && nodeIndex2 != nodeIndex) { fissureLocs.Add(nodeIndex2); } else { num *= 1.5f; } } Util.ShuffleList(fissureLocs); totalFired = 0; nextDropTime = base.fixedAge + delayBetweenDrops; totalLunarDropsToFire = Mathf.Min(totalLunarDrops, fissureLocs.Count); PlayAnimation("FullBody, Override", "LunarRain", "LunarRain.playbackRate", duration); UnityEngine.Vector3 GeneratePositionAroundCircle(int i, int total, UnityEngine.Vector3 center, float radius, UnityEngine.Vector3 angleOffset) { float num2 = MathF.PI * 2f / (float)total; float f = num2 * (float)i + num2 * UnityEngine.Random.Range(1f - percentVarianceRotation, 1f + percentVarianceRotation); float x = Mathf.Cos(f); float z = Mathf.Sin(f); UnityEngine.Vector3 vector = new UnityEngine.Vector3(x, 0f, z); radius *= UnityEngine.Random.Range(1f - percentVarianceInRadius, 1f + percentVarianceInRadius); return vector * radius + center; } } private void SpawnRainWarning(NodeGraph.NodeIndex node) { nodeGraph.GetNodePosition(node, out fissureLocation); EffectManager.SpawnEffect(warningFXPrefab, new EffectData { origin = fissureLocation }, transmit: true); } public override void FixedUpdate() { base.FixedUpdate(); if (totalWarned < totalLunarDropsToFire) { SpawnRainWarning(fissureLocs[totalWarned++]); if (totalWarned >= totalLunarDropsToFire) { lunarRainStartTime = base.fixedAge + warningDuration + duration * 0.7f; } return; } if (!lunarRainStarted && base.fixedAge > lunarRainStartTime) { lunarRainStarted = true; DetonateAuthority(); } if (!lunarRainStarted || base.fixedAge < nextDropTime) { return; } if (totalFired >= totalLunarDropsToFire) { outer.SetNextStateToMain(); return; } FireRain(fissureLocs[totalFired++]); if (totalFired < totalLunarDropsToFire) { FireRain(fissureLocs[totalFired++]); } } private void FireRain(NodeGraph.NodeIndex node) { if (NetworkServer.active) { nodeGraph.GetNodePosition(node, out fissureLocation); nextDropTime = base.fixedAge + delayBetweenDrops; EffectManager.SpawnEffect(rainCrashEffectPrefab, new EffectData { origin = fissureLocation }, transmit: true); NetworkServer.Spawn(UnityEngine.Object.Instantiate(lunarRainPrefab, fissureLocation, UnityEngine.Quaternion.identity)); } } public override void OnExit() { base.OnExit(); } protected BlastAttack.Result DetonateAuthority() { UnityEngine.Vector3 position = FindModelChild("Root").transform.position; EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = position, scale = blastRadius }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * blastDamageCoefficient, baseForce = blastForce, bonusForce = blastBonusForce, crit = RollCrit(), falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius, position = base.gameObject.transform.position, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class OverloadSpike : BaseState { [SerializeField] public float duration; public static GameObject rainCrashEffectPrefab; public static GameObject lunarRainPrefab; public static GameObject blastImpactEffectPrefab; public static GameObject blastEffectPrefab; public static float blastRadius; public static float blastProcCoefficient; public static float blastDamageCoefficient; public static float blastForce; public static UnityEngine.Vector3 blastBonusForce; private bool firedSpike; public override void OnEnter() { base.OnEnter(); if (!base.characterBody.GetComponent().firedLunarSpike) { PlayAnimation("FullBody, Override", "OverloadErruption", "OverloadErruption.playbackRate", duration); } else { outer.SetNextStateToMain(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration - duration * 0.3f && !firedSpike && !base.characterBody.GetComponent().firedLunarSpike) { DetonateAuthority(); base.characterBody.GetComponent().SpawnLunarSpike(); firedSpike = true; } if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } public override void OnExit() { outer.SetNextStateToMain(); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } protected BlastAttack.Result DetonateAuthority() { EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = base.gameObject.transform.position, scale = blastRadius }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * blastDamageCoefficient, baseForce = blastForce, bonusForce = blastBonusForce, crit = RollCrit(), falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius, position = base.gameObject.transform.position, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } } public class PrimeDevastator : BaseState { [SerializeField] private float duration = 4f; [SerializeField] private float damageCoefficient = 2f; public static float slamEffectDelay; public static float playerLightningDelay; public static GameObject projectilePrefab; private Transform modelTransform; protected Transform muzzleTransform; public static GameObject blastImpactEffectPrefab; public static GameObject blastEffectPrefab; public static GameObject disablingLightningPrefab; public static GameObject lightningEffectPrefab; public static float blastRadius; public static float blastProcCoefficient; public static float blastDamageCoefficient; public static float blastForce; public static UnityEngine.Vector3 blastBonusForce; private Ray projectileRay; public static float arcAngle = 7f; public static float spreadBloomValue = 0.3f; public static GameObject chargeEffectPrefab; private bool chargeEffectSpawned; private bool slamEffectSpawned; private bool playerLightningSpawned; private bool orbsSpawned; private float orbSpawnTimer; private int orbNumber; public override void OnEnter() { base.OnEnter(); PlayAnimation("FullBody, Override", "PrimeDevastator", "PrimeDevastator.playbackRate", duration); } public override void FixedUpdate() { base.FixedUpdate(); if (!chargeEffectSpawned && base.fixedAge > duration * 0.3f) { chargeEffectSpawned = true; EffectManager.SpawnEffect(chargeEffectPrefab, new EffectData { origin = base.gameObject.transform.position, scale = 10f }, transmit: true); } if (!slamEffectSpawned && base.fixedAge > slamEffectDelay) { slamEffectSpawned = true; DetonateAuthority(); } if (!playerLightningSpawned && base.isAuthority && base.fixedAge > playerLightningDelay) { playerLightningSpawned = true; if ((bool)disablingLightningPrefab) { foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (!(instance == null)) { CharacterBody body = instance.master.GetBody(); if (!(body == null)) { body.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 420f); EffectManager.SpawnEffect(lightningEffectPrefab, new EffectData { origin = body.corePosition, scale = blastRadius }, transmit: true); } } } } } if (!orbsSpawned && base.isAuthority && base.fixedAge > playerLightningDelay) { orbSpawnTimer += Time.deltaTime; if (orbSpawnTimer > 0.5f) { FireDevastator("MuzzleOrb1"); orbNumber++; orbSpawnTimer = 0f; } if (orbNumber >= 4) { orbsSpawned = true; } } if (base.fixedAge >= duration + 1f && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireDevastator(string targetMuzzle) { projectileRay = GetAimRay(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { projectileRay.origin = transform.position; } } } if (base.isAuthority) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = base.gameObject.transform.position + new UnityEngine.Vector3(7f, 0f, 0f); fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = 0f; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnExit() { base.OnExit(); } protected BlastAttack.Result DetonateAuthority() { EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = base.gameObject.transform.position, scale = blastRadius }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * blastDamageCoefficient, baseForce = blastForce, bonusForce = blastBonusForce, crit = RollCrit(), falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius, position = base.gameObject.transform.position, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class HeartSpawnState : BaseState { [SerializeField] private float baseAnimDuration = 2f; [SerializeField] private float baseSpawnDuration = 4f; [SerializeField] private GameObject spawnEffect; [SerializeField] private float vfxSize = 6f; private bool playedSFX; public override void OnEnter() { base.OnEnter(); Util.PlaySound("Play_boss_falseson_spawn", base.gameObject); Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject); PlayAnimation("Body", "Phase1Spawn", "StepBrothersPrep.playbackRate", baseAnimDuration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > 1f && !playedSFX) { Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject); playedSFX = true; } if (base.fixedAge > baseSpawnDuration) { outer.SetNextStateToMain(); } } } public class Lightning1SpawnState : BaseState { public static float baseDuration = 3f; public static GameObject spawnEffect; public static float vfxSize = 6f; private bool playedSFX; public override void OnEnter() { base.OnEnter(); Util.PlaySound("Play_boss_falseson_spawn", base.gameObject); PlayAnimation("Body", "Phase2Spawn", "StepBrothersPrep.playbackRate", baseDuration); PlayAnimation("FullBody, Override", "BufferEmpty"); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("FalseSonBoss/FalseSonBossLightningNovaSpawn"), new EffectData { origin = base.transform.position, scale = vfxSize }, transmit: true); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > 1f && !playedSFX) { Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject); playedSFX = true; } if (base.fixedAge > baseDuration) { outer.SetNextStateToMain(); } } } public class Lightning2SpawnState : BaseState { public static float baseDuration = 3f; public static GameObject spawnEffect; public static float vfxSize = 6f; private bool playedSFX; public override void OnEnter() { base.OnEnter(); Util.PlaySound("Play_boss_falseson_spawn", base.gameObject); Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject); PlayAnimation("Body", "Phase3Spawn", "StepBrothersPrep.playbackRate", baseDuration); PlayAnimation("FullBody, Override", "BufferEmpty"); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("FalseSonBoss/FalseSonBossLightningNovaSpawn"), new EffectData { origin = base.transform.position, scale = vfxSize }, transmit: true); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > 1f && !playedSFX) { Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject); playedSFX = true; } if (base.fixedAge > baseDuration) { outer.SetNextStateToMain(); } } } public class SwatAwayPlayersSlam : BaseCharacterMain { [SerializeField] public float baseDuration; [SerializeField] public float damageCoefficient; [SerializeField] public string hitBoxGroupName; [SerializeField] public GameObject hitEffectPrefab; [SerializeField] public float procCoefficient; [SerializeField] public float pushAwayForce; [SerializeField] public UnityEngine.Vector3 forceVector; [SerializeField] public NetworkSoundEventDef impactSound; public float charge; public static float minimumDuration; public static float blastRadius; public static float blastProcCoefficient; public static float blastDamageCoefficient; public static float blastForce; public static string enterSoundString; public static UnityEngine.Vector3 blastBonusForce; public static GameObject blastImpactEffectPrefab; public static GameObject blastEffectPrefab; public static GameObject fistEffectPrefab; public static GameObject swingEffectPrefab; public static GameObject fissureSlamObject; private GameObject swingEffectInstance; private bool detonateNextFrame; private bool slamComplete; protected HitBoxGroup hitBoxGroup; private OverlapAttack overlapAttack; public override void OnEnter() { base.OnEnter(); baseDuration /= attackSpeedStat; PlayAnimation("FullBody, Override", "ChargeSwing", "ChargeSwing.playbackRate", baseDuration); Util.PlaySound(enterSoundString, base.gameObject); swingEffectInstance = UnityEngine.Object.Instantiate(swingEffectPrefab, FindModelChild("OverHeadSwingPoint")); if (base.isAuthority) { hitBoxGroup = FindHitBoxGroup(GetHitBoxGroupName()); if ((bool)hitBoxGroup) { overlapAttack = new OverlapAttack { attacker = base.gameObject, damage = damageCoefficient * damageStat, damageColorIndex = DamageColorIndex.Default, damageType = DamageType.Generic, forceVector = forceVector, hitBoxGroup = hitBoxGroup, hitEffectPrefab = hitEffectPrefab, impactSound = (impactSound?.index ?? NetworkSoundEventIndex.Invalid), inflictor = base.gameObject, isCrit = RollCrit(), procChainMask = default(ProcChainMask), pushAwayForce = pushAwayForce, procCoefficient = procCoefficient, teamIndex = GetTeam() }; } } } public override void FixedUpdate() { base.FixedUpdate(); if (!slamComplete && base.fixedAge >= baseDuration - baseDuration * 0.8f) { BeginMeleeAttack(); slamComplete = true; } if (slamComplete) { outer.SetNextStateToMain(); } } public override void OnExit() { base.OnExit(); } protected void BeginMeleeAttack() { UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position; EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = position, scale = blastRadius }, transmit: true); if (base.isAuthority && overlapAttack != null) { overlapAttack.Fire(); } } public virtual string GetHitBoxGroupName() { return hitBoxGroupName; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class SwatAwayPlayersWindup : BaseSkillState { [SerializeField] public float baseChargeDuration = 1f; [SerializeField] public float chargeThreshold = 3f; public static float minChargeForChargedAttack; public static GameObject chargeVfxPrefab; public static string chargeVfxChildLocatorName; public static GameObject crosshairOverridePrefab; public static float walkSpeedCoefficient; public static string startChargeLoopSFXString; public static string endChargeLoopSFXString; public static string enterSFXString; private int gauntlet; private uint soundID; private Transform chargeVfxInstanceTransform; private bool chargeAnimPlayed; private bool stateAborted; protected float chargeDuration { get; private set; } protected float charge { get; private set; } public override void OnEnter() { base.OnEnter(); chargeDuration = 0.5f; Util.PlaySound(enterSFXString, base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } public override void OnExit() { if (!stateAborted) { if ((bool)chargeVfxInstanceTransform) { EntityState.Destroy(chargeVfxInstanceTransform.gameObject); PlayAnimation("Gesture, Additive", "Empty"); PlayAnimation("Gesture, Override", "Empty"); chargeVfxInstanceTransform = null; } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; Util.PlaySound(endChargeLoopSFXString, base.gameObject); base.OnExit(); } } public override void FixedUpdate() { if (stateAborted) { return; } base.FixedUpdate(); charge += Time.deltaTime; base.characterBody.SetSpreadBloom(charge); base.characterBody.SetAimTimer(3f); if (charge <= 3f && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab) { Transform transform = FindModelChild(chargeVfxChildLocatorName); if ((bool)transform) { chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform; ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent(); if ((bool)component) { component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration; } } if (!chargeAnimPlayed) { PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", chargeDuration, 0.1f); PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", chargeDuration, 0.1f); chargeAnimPlayed = true; } } else if (charge > baseChargeDuration) { outer.SetNextState(GetNextStateAuthority()); } if ((bool)chargeVfxInstanceTransform) { base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; } } public override void Update() { if (!stateAborted) { base.Update(); Mathf.Clamp01(base.age / chargeDuration); } } protected virtual EntityState GetNextStateAuthority() { return new SwatAwayPlayersSlam(); } } public class TaintedOffering : GenericProjectileBaseState { [SerializeField] public float projectileYawBonus; [SerializeField] public float additionalShots = 8f; private BaseAI ai; public override void OnEnter() { base.OnEnter(); if ((bool)base.characterBody) { if (base.characterBody.master.TryGetComponent(out var component)) { ai = component; } base.characterBody.SetAimTimer(1f); } } public override void FixedUpdate() { stopwatch += GetDeltaTime(); if (stopwatch >= delayBeforeFiringProjectile && !firedProjectile) { firedProjectile = true; for (int num = 9; num > 0; num--) { switch (num) { case 9: projectileYawBonus = 0f; projectilePitchBonus = 0f; break; case 8: projectileYawBonus = -4f; projectilePitchBonus = -4f; break; case 7: projectileYawBonus = 4f; projectilePitchBonus = 4f; break; case 6: projectileYawBonus = 4f; projectilePitchBonus = -4f; break; case 5: projectileYawBonus = -4f; projectilePitchBonus = 4f; break; case 4: projectileYawBonus = 0f; projectilePitchBonus = 8f; break; case 3: projectileYawBonus = 0f; projectilePitchBonus = -8f; break; case 2: projectileYawBonus = 8f; projectilePitchBonus = 0f; break; case 1: projectileYawBonus = -8f; projectilePitchBonus = 0f; break; } FireProjectile(); } DoFireEffects(); } if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } protected override void PlayAnimation(float duration) { base.PlayAnimation(duration); PlayAnimation("Gesture, Additive", "FireLunarSpike", "LunarSpike.playbackRate", duration); PlayAnimation("Gesture, Override", "HoldGauntletsUp", "LunarSpike.playbackRate", duration); } protected override Ray ModifyProjectileAimRay(Ray aimRay) { aimRay.origin = base.modelLocator.modelTransform.GetComponent().FindChild("MuzzleRight").position; if (ai != null && ai.currentEnemy != null && ai.currentEnemy.GetBullseyePosition(out var position)) { aimRay.direction = position - aimRay.origin; } return aimRay; } protected override void FireProjectile() { if (base.isAuthority) { Ray aimRay = GetAimRay(); aimRay = ModifyProjectileAimRay(aimRay); aimRay.direction = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, projectileYawBonus, projectilePitchBonus); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } } namespace EntityStates.FalseSon { public class AurelioniteCore : BaseState { public override void OnEnter() { } } public class ChargedClubSwing : BaseState { [SerializeField] public float baseDuration; public float charge; public bool chargeMetMinimumHold; public static float playerWalkSpeedCoefficient; public static float minimumDuration; public static float blastRadius; public static float blastProcCoefficient; public static float blastDamageCoefficient; public static float blastForce; public static string enterSoundString; public static UnityEngine.Vector3 blastBonusForce; public static GameObject blastImpactEffectPrefab; public static GameObject blastEffectPrefab; public static GameObject swingEffectPrefab; public static float percentOfDurationToFireSwingEffect; public static float unchargedBlastRadius; public static float unchargedBlastProcCoefficient; public static float unchargedBlastDamageCoefficient; public static float unchargedBlastForce; public static UnityEngine.Vector3 unchargedBlastBonusForce; public static GameObject unchargedSwingVFX; public static float percentOfAnimationToHoldPlayer; private GameObject swingEffectInstance; private bool wasSprinting; private bool authorityDetonated; private bool detonateNextFrame; private bool firedSwingVFX; public override void OnEnter() { base.OnEnter(); baseDuration /= attackSpeedStat; PlayAnimation("FullBody, Override", "OverheadSwing", "ChargeSwing.playbackRate", baseDuration); wasSprinting = base.characterBody.isSprinting; base.characterMotor.walkSpeedPenaltyCoefficient = playerWalkSpeedCoefficient; if (chargeMetMinimumHold && base.isAuthority) { EffectData effectData = new EffectData(); ChildLocator modelChildLocator = GetModelChildLocator(); effectData.SetChildLocatorTransformReference(base.gameObject, modelChildLocator.FindChildIndex("OverHeadSwingPoint")); EffectManager.SpawnEffect(swingEffectPrefab, effectData, transmit: false); } base.characterBody.GetComponent()?.SetClubSwingAltSecondaryTimestamp(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { if (!chargeMetMinimumHold && !firedSwingVFX && base.fixedAge >= minimumDuration * percentOfDurationToFireSwingEffect) { SpawnSwingEffect(); firedSwingVFX = true; } if (!authorityDetonated && base.fixedAge >= minimumDuration) { DetonateAuthority(); authorityDetonated = true; } if (base.fixedAge >= baseDuration * percentOfAnimationToHoldPlayer) { outer.SetNextStateToMain(); } } } private void SpawnSwingEffect() { EffectData effectData = new EffectData(); ChildLocator modelChildLocator = GetModelChildLocator(); effectData.SetChildLocatorTransformReference(base.gameObject, modelChildLocator.FindChildIndex("SwingVertical")); EffectManager.SpawnEffect(unchargedSwingVFX, effectData, transmit: true); } public override void OnExit() { base.characterMotor.walkSpeedPenaltyCoefficient = 1f; base.characterBody.isSprinting = wasSprinting; base.characterBody.SetSpreadBloom(0f, canOnlyIncreaseBloom: false); base.OnExit(); } protected BlastAttack.Result DetonateAuthority() { BlastAttack blast = new BlastAttack(); if (chargeMetMinimumHold) { InitializeBlastAttackAsCharged(ref blast); } else { InitializeBlastAttackNormal(ref blast); } return blast.Fire(); } private void InitializeBlastAttackAsCharged(ref BlastAttack blast) { UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position; EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = position, scale = blastRadius * (charge + 1.25f) }, transmit: true); blast.attacker = base.gameObject; blast.baseDamage = damageStat * (blastDamageCoefficient * charge) + (base.characterBody.maxHealth - (base.characterBody.baseMaxHealth + base.characterBody.levelMaxHealth * (float)((int)base.characterBody.level - 1))) * 0.01f; blast.baseForce = blastForce; blast.bonusForce = blastBonusForce; blast.crit = RollCrit(); blast.falloffModel = BlastAttack.FalloffModel.None; blast.procCoefficient = blastProcCoefficient; blast.radius = blastRadius * (charge + 1.55f); blast.position = position; blast.attackerFiltering = AttackerFiltering.NeverHitSelf; blast.impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab); blast.teamIndex = base.teamComponent.teamIndex; } private void InitializeBlastAttackNormal(ref BlastAttack blast) { UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position; blast.attacker = base.gameObject; blast.baseDamage = damageStat * (unchargedBlastDamageCoefficient * charge); blast.baseForce = unchargedBlastForce; blast.bonusForce = unchargedBlastBonusForce; blast.crit = RollCrit(); blast.falloffModel = BlastAttack.FalloffModel.None; blast.procCoefficient = unchargedBlastProcCoefficient; blast.radius = unchargedBlastRadius; blast.position = position; blast.attackerFiltering = AttackerFiltering.NeverHitSelf; blast.impactEffect = EffectIndex.Invalid; blast.teamIndex = base.teamComponent.teamIndex; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class ClubForsaken : BaseSkillState, SteppedSkillDef.IStepSetter { private class ArcVisualizer : IDisposable { private readonly UnityEngine.Vector3[] points; private readonly float duration; private readonly GameObject arcVisualizerInstance; private readonly LineRenderer lineRenderer; public ArcVisualizer(GameObject arcVisualizerPrefab, float duration, int vertexCount) { arcVisualizerInstance = UnityEngine.Object.Instantiate(arcVisualizerPrefab); lineRenderer = arcVisualizerInstance.GetComponent(); lineRenderer.positionCount = vertexCount; points = new UnityEngine.Vector3[vertexCount]; this.duration = duration; } public void Dispose() { EntityState.Destroy(arcVisualizerInstance); } public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float characterMaxSpeed, float characterAcceleration) { arcVisualizerInstance.transform.position = origin; if (!lineRenderer.useWorldSpace) { UnityEngine.Vector3 eulerAngles = UnityEngine.Quaternion.LookRotation(initialVelocity).eulerAngles; eulerAngles.x = 0f; eulerAngles.z = 0f; UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(eulerAngles); arcVisualizerInstance.transform.rotation = rotation; origin = UnityEngine.Vector3.zero; initialVelocity = UnityEngine.Quaternion.Inverse(rotation) * initialVelocity; } else { arcVisualizerInstance.transform.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.Cross(initialVelocity, UnityEngine.Vector3.up)); } float y = Physics.gravity.y; float num = duration / (float)points.Length; UnityEngine.Vector3 vector = origin; UnityEngine.Vector3 vector2 = initialVelocity; float num2 = num; float num3 = y * num2; float maxDistanceDelta = characterAcceleration * num2; for (int i = 0; i < points.Length; i++) { points[i] = vector; UnityEngine.Vector2 current = Util.Vector3XZToVector2XY(vector2); current = UnityEngine.Vector2.MoveTowards(current, UnityEngine.Vector3.zero, maxDistanceDelta); vector2.x = current.x; vector2.z = current.y; vector2.y += num3; vector += vector2 * num2; } lineRenderer.SetPositions(points); } } public int clubState; public static GameObject arcVisualizerPrefab; public static float arcVisualizerSimulationLength; public static int arcVisualizerVertexCount; [SerializeField] public float baseChargeDuration = 1f; public static float minChargeForChargedAttack; public static GameObject chargeVfxPrefab; public static string chargeVfxChildLocatorName; public static GameObject crosshairOverridePrefab; public static float walkSpeedCoefficient; public static string startChargeLoopSFXString; public static string endChargeLoopSFXString; public static string enterSFXString; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private Transform chargeVfxInstanceTransform; private int gauntlet; private uint soundID; private bool chargeAnimPlayed; protected float chargeDuration { get; private set; } protected float charge { get; private set; } void SteppedSkillDef.IStepSetter.SetStep(int i) { clubState = i; } public override void OnEnter() { base.OnEnter(); chargeDuration = baseChargeDuration / attackSpeedStat; Util.PlaySound(enterSFXString, base.gameObject); soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnExit() { if ((bool)chargeVfxInstanceTransform) { EntityState.Destroy(chargeVfxInstanceTransform.gameObject); PlayAnimation("Gesture, Additive", "Empty"); PlayAnimation("Gesture, Override", "Empty"); crosshairOverrideRequest?.Dispose(); chargeVfxInstanceTransform = null; } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; Util.PlaySound(endChargeLoopSFXString, base.gameObject); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); charge = Mathf.Clamp01(base.fixedAge / chargeDuration); AkSoundEngine.SetRTPCValueByPlayingID("charFalseSon_skill1_chargeAmount", charge * 100f, soundID); base.characterBody.SetSpreadBloom(charge); base.characterBody.SetAimTimer(3f); if (charge >= minChargeForChargedAttack && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab) { if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } Transform transform = FindModelChild(chargeVfxChildLocatorName); if ((bool)transform) { chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform; ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent(); if ((bool)component) { component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration; } } if (!chargeAnimPlayed) { PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f); PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f); chargeAnimPlayed = true; } } if ((bool)chargeVfxInstanceTransform) { base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; } if (base.isAuthority) { AuthorityFixedUpdate(); } } public override void Update() { base.Update(); Mathf.Clamp01(base.age / chargeDuration); } private void AuthorityFixedUpdate() { if (!ShouldKeepChargingAuthority()) { outer.SetNextState(GetNextStateAuthority()); } } protected virtual bool ShouldKeepChargingAuthority() { return IsKeyDownAuthority(); } protected virtual EntityState GetNextStateAuthority() { if (charge > minChargeForChargedAttack) { if (!base.isGrounded) { return new PreClubGroundSlam { charge = charge }; } return new ChargedClubSwing { charge = charge }; } return new ClubSwing2 { club = clubState }; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)clubState); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); clubState = reader.ReadByte(); } } public class ClubForsaken2 : BaseSkillState { private class ArcVisualizer : IDisposable { private readonly UnityEngine.Vector3[] points; private readonly float duration; private readonly GameObject arcVisualizerInstance; private readonly LineRenderer lineRenderer; public ArcVisualizer(GameObject arcVisualizerPrefab, float duration, int vertexCount) { arcVisualizerInstance = UnityEngine.Object.Instantiate(arcVisualizerPrefab); lineRenderer = arcVisualizerInstance.GetComponent(); lineRenderer.positionCount = vertexCount; points = new UnityEngine.Vector3[vertexCount]; this.duration = duration; } public void Dispose() { EntityState.Destroy(arcVisualizerInstance); } public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float characterMaxSpeed, float characterAcceleration) { arcVisualizerInstance.transform.position = origin; if (!lineRenderer.useWorldSpace) { UnityEngine.Vector3 eulerAngles = UnityEngine.Quaternion.LookRotation(initialVelocity).eulerAngles; eulerAngles.x = 0f; eulerAngles.z = 0f; UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(eulerAngles); arcVisualizerInstance.transform.rotation = rotation; origin = UnityEngine.Vector3.zero; initialVelocity = UnityEngine.Quaternion.Inverse(rotation) * initialVelocity; } else { arcVisualizerInstance.transform.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.Cross(initialVelocity, UnityEngine.Vector3.up)); } float y = Physics.gravity.y; float num = duration / (float)points.Length; UnityEngine.Vector3 vector = origin; UnityEngine.Vector3 vector2 = initialVelocity; float num2 = num; float num3 = y * num2; float maxDistanceDelta = characterAcceleration * num2; for (int i = 0; i < points.Length; i++) { points[i] = vector; UnityEngine.Vector2 current = Util.Vector3XZToVector2XY(vector2); current = UnityEngine.Vector2.MoveTowards(current, UnityEngine.Vector3.zero, maxDistanceDelta); vector2.x = current.x; vector2.z = current.y; vector2.y += num3; vector += vector2 * num2; } lineRenderer.SetPositions(points); } } public static GameObject arcVisualizerPrefab; public static float arcVisualizerSimulationLength; public static int arcVisualizerVertexCount; [SerializeField] public float baseChargeDuration = 1f; public static float minChargeForChargedAttack; public static GameObject chargeVfxPrefab; public static string chargeVfxChildLocatorName; public static GameObject crosshairOverridePrefab; public static float walkSpeedCoefficient; public static string startChargeLoopSFXString; public static string endChargeLoopSFXString; public static string enterSFXString; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private Transform chargeVfxInstanceTransform; private int gauntlet; private uint soundID; private bool chargeAnimPlayed; protected float chargeDuration { get; private set; } protected float charge { get; private set; } public override void OnEnter() { base.OnEnter(); chargeDuration = baseChargeDuration / attackSpeedStat; Util.PlaySound(enterSFXString, base.gameObject); soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnExit() { if ((bool)chargeVfxInstanceTransform) { EntityState.Destroy(chargeVfxInstanceTransform.gameObject); PlayAnimation("Gesture, Additive", "Empty"); PlayAnimation("Gesture, Override", "Empty"); crosshairOverrideRequest?.Dispose(); chargeVfxInstanceTransform = null; } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; Util.PlaySound(endChargeLoopSFXString, base.gameObject); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); charge = Mathf.Clamp01(base.fixedAge / chargeDuration); AkSoundEngine.SetRTPCValueByPlayingID("charFalseSon_skill1_chargeAmount", charge * 100f, soundID); base.characterBody.SetSpreadBloom(charge); base.characterBody.SetAimTimer(3f); if (charge >= minChargeForChargedAttack && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab) { if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } Transform transform = FindModelChild(chargeVfxChildLocatorName); if ((bool)transform) { chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform; ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent(); if ((bool)component) { component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration; } } if (!chargeAnimPlayed) { PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f); PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f); chargeAnimPlayed = true; } } if ((bool)chargeVfxInstanceTransform) { base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; } if (base.isAuthority) { AuthorityFixedUpdate(); } } public override void Update() { base.Update(); Mathf.Clamp01(base.age / chargeDuration); } private void AuthorityFixedUpdate() { if (!ShouldKeepChargingAuthority()) { outer.SetNextState(GetNextStateAuthority()); } } protected virtual bool ShouldKeepChargingAuthority() { return IsKeyDownAuthority(); } protected virtual EntityState GetNextStateAuthority() { if (!base.isGrounded) { return new PreClubGroundSlam { charge = charge }; } return new ChargedClubSwing { charge = charge }; } } public class PreClubGroundSlam : BaseState { public float charge; public static float baseDuration; public static string enterSoundString; public static float upwardVelocity; private float duration; private bool forceAnimWrapUp = true; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Body", "PreGroundSlam", "GroundSlam.playbackRate", duration); Util.PlaySound(enterSoundString, base.gameObject); base.characterMotor.Motor.ForceUnground(); base.characterMotor.disableAirControlUntilCollision = false; base.characterMotor.velocity.y = upwardVelocity; base.characterBody.bodyFlags |= CharacterBody.BodyFlags.IgnoreFallDamage; } public override void FixedUpdate() { base.FixedUpdate(); base.characterMotor.moveDirection = base.inputBank.moveVector; base.characterBody.SetSpreadBloom(charge); if (base.fixedAge > duration) { forceAnimWrapUp = false; outer.SetNextState(new ClubGroundSlam { charge = charge }); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } public override void ModifyNextState(EntityState nextState) { ClubGroundSlam clubGroundSlam = nextState as ClubGroundSlam; forceAnimWrapUp = clubGroundSlam == null; } public override void OnExit() { base.OnExit(); if (forceAnimWrapUp) { PlayAnimation("Gesture, Override", "Empty"); PlayAnimation("Gesture, Additive", "Empty"); PlayAnimation("Body", "Idle"); base.characterBody.bodyFlags &= ~CharacterBody.BodyFlags.IgnoreFallDamage; } } } public class ClubGroundSlam : BaseState { public float charge; public static float airControl; public static float minimumDuration; public static float blastRadius; public static float blastProcCoefficient; public static float blastDamageCoefficient; public static float blastForce; public static string enterSoundString; public static float initialVerticalVelocity; public static float exitVerticalVelocity; public static float verticalAcceleration; public static float exitSlowdownCoefficient; public static UnityEngine.Vector3 blastBonusForce; public static GameObject blastImpactEffectPrefab; public static GameObject blastEffectPrefab; public static float normalizedVFXPositionBetweenFootAndClub; public static float normalizedBlastPositionBetweenFootAndClub; public static float smallHopVelocity; public static float heightInfluencePercent; private float previousAirControl; private float timeInAir; private float airClubTimer; private bool hitTheGround; private float delayBeforeExit; private bool detonateNextFrame; public override void OnEnter() { base.OnEnter(); PlayCrossfade("Body", "GroundSlam", 0.2f); if (base.isAuthority) { base.characterMotor.onHitGroundAuthority += OnHitGroundAuthority; base.characterMotor.velocity.y = initialVerticalVelocity; } Util.PlaySound(enterSoundString, base.gameObject); previousAirControl = base.characterMotor.airControl; base.characterMotor.airControl = airControl; base.characterBody.bodyFlags |= CharacterBody.BodyFlags.IgnoreFallDamage; } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); airClubTimer += deltaTime; timeInAir = 0f; if (airClubTimer > 0.5f) { timeInAir = airClubTimer; } if (base.isAuthority && (bool)base.characterMotor) { base.characterMotor.moveDirection = base.inputBank.moveVector; base.characterDirection.moveVector = base.characterMotor.moveDirection; base.characterMotor.velocity.y += verticalAcceleration * deltaTime; if (!hitTheGround && base.fixedAge >= minimumDuration && (detonateNextFrame || (base.characterMotor.Motor.GroundingStatus.IsStableOnGround && !base.characterMotor.Motor.LastGroundingStatus.IsStableOnGround))) { PlayAnimation("Body", "GroundSlamExit"); DetonateAuthority(); hitTheGround = true; delayBeforeExit = base.fixedAge; } else if (hitTheGround && base.fixedAge >= delayBeforeExit + 0.1f) { outer.SetNextStateToMain(); } else { base.characterBody.SetSpreadBloom(charge); } } } public override void OnExit() { if (!base.isAuthority) { PlayAnimation("Body", "GroundSlamExit"); } base.characterBody.SetSpreadBloom(0f, canOnlyIncreaseBloom: false); if (base.isAuthority) { base.characterMotor.onHitGroundAuthority -= OnHitGroundAuthority; base.characterMotor.velocity *= exitSlowdownCoefficient; base.characterMotor.velocity.y = exitVerticalVelocity; if (!hitTheGround) { PlayAnimation("Body", "Idle"); } } base.characterMotor.airControl = previousAirControl; base.characterBody.bodyFlags &= ~CharacterBody.BodyFlags.IgnoreFallDamage; SmallHop(base.characterMotor, smallHopVelocity + airClubTimer * heightInfluencePercent); base.OnExit(); } private void OnHitGroundAuthority(ref CharacterMotor.HitGroundInfo hitGroundInfo) { detonateNextFrame = true; } protected BlastAttack.Result DetonateAuthority() { UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position; UnityEngine.Vector3 footPosition = base.characterBody.footPosition; UnityEngine.Vector3 origin = footPosition + (position - footPosition) * normalizedVFXPositionBetweenFootAndClub; UnityEngine.Vector3 position2 = footPosition + (position - footPosition) * normalizedBlastPositionBetweenFootAndClub; EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = origin, scale = blastRadius * (charge + 1.25f + timeInAir * 2f) }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * (blastDamageCoefficient * charge) + (base.characterBody.maxHealth - (base.characterBody.baseMaxHealth + base.characterBody.levelMaxHealth * (float)((int)base.characterBody.level - 1))) * 0.01f, baseForce = blastForce, bonusForce = blastBonusForce, crit = RollCrit(), falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius * (charge + 1.25f + timeInAir * 2f), position = position2, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class ClubSwing : BasicMeleeAttack, SteppedSkillDef.IStepSetter, ISkillOverrideHandoff { public int club; public static GameObject secondarySwingEffectPrefab; [SerializeField] public SkillDef secondaryOverrideSkill; [SerializeField] public SkillDef specialOverrideSkill; [SerializeField] public float secondaryAltCooldownDuration = 0.7f; private SkillStateOverrideData skillOverrideData; private float startTimeStamp; private bool resetClubSwing; private bool clearOverrides = true; private FalseSonController falseSonController; void SteppedSkillDef.IStepSetter.SetStep(int i) { club = i; } public override void OnEnter() { base.OnEnter(); falseSonController = base.characterBody.GetComponent(); if (CheckReadyForSecondaryAlt()) { GenerateSkillOverrideData(); } else { EnsureSkillOverrideState(readyToFire: false); } clearOverrides = true; startTimeStamp = Time.time; } void ISkillOverrideHandoff.TransferSkillOverride(SkillStateOverrideData skillOverrideData) { this.skillOverrideData = skillOverrideData; } private bool CheckReadyForSecondaryAlt() { if (base.inputBank.skill1.down) { return Time.time - falseSonController.GetClubSwingAltSecondaryTimestamp() > secondaryAltCooldownDuration; } return false; } private void EnsureSkillOverrideState(bool readyToFire) { if (readyToFire ^ (skillOverrideData != null)) { if (readyToFire) { GenerateSkillOverrideData(); } else { ClearSkillOverrideData(); } } } private void GenerateSkillOverrideData() { if (skillOverrideData == null) { skillOverrideData = new SkillStateOverrideData(base.characterBody); skillOverrideData.secondarySkillOverride = secondaryOverrideSkill; skillOverrideData.overrideFullReloadOnAssign = true; skillOverrideData.simulateRestockForOverridenSkills = false; skillOverrideData.OverrideSkills(base.skillLocator); } } private void ClearSkillOverrideData() { if (skillOverrideData != null) { skillOverrideData.ClearOverrides(); } skillOverrideData = null; } public override void FixedUpdate() { if (skillOverrideData != null) { skillOverrideData.StepRestock(); } bool flag = CheckReadyForSecondaryAlt(); EnsureSkillOverrideState(flag); if (flag && base.inputBank.skill2.justPressed) { ResetClubSwing(); outer.SetNextState(GetNextStateAuthority()); } base.FixedUpdate(); } private void ResetClubSwing() { SteppedSkillDef.InstanceData instanceData = (SteppedSkillDef.InstanceData)(base.skillLocator.GetSkill(SkillSlot.Primary)?.skillInstanceData); if (instanceData != null) { instanceData.step = 0; club = 0; resetClubSwing = true; } } protected override void PlayAnimation() { string animationStateName = ((club == 0) ? "SwingClubRight" : "SwingClubLeft"); float num = Mathf.Max(duration, 0.2f); PlayCrossfade("Gesture, Additive", animationStateName, "SwingClub.playbackRate", num, 0.1f); PlayCrossfade("Gesture, Override", animationStateName, "SwingClub.playbackRate", num, 0.1f); } protected override void BeginMeleeAttackEffect() { swingEffectPrefab = ((club == 0) ? swingEffectPrefab : secondarySwingEffectPrefab); swingEffectMuzzleString = ((club == 0) ? "SwingRight" : "SwingLeft"); base.BeginMeleeAttackEffect(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)club); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); club = reader.ReadByte(); } public override void OnExit() { base.OnExit(); if (clearOverrides && skillOverrideData != null) { skillOverrideData.ClearOverrides(); } } public override void ModifyNextState(EntityState nextState) { base.ModifyNextState(nextState); if (nextState is ISkillOverrideHandoff skillOverrideHandoff && skillOverrideData != null) { skillOverrideHandoff.TransferSkillOverride(skillOverrideData); clearOverrides = false; } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } protected virtual EntityState GetNextStateAuthority() { return new ClubSwing3(); } } public class ClubSwing2 : BasicMeleeAttack, SteppedSkillDef.IStepSetter { public int club; public static float recoilAmplitude; public static float baseDurationBeforeInterruptable; [SerializeField] public float bloom; public static float comboFinisherBaseDuration; public static GameObject comboFinisherSwingEffectPrefab; public static float comboFinisherhitPauseDuration; public static float comboFinisherDamageCoefficient; public static float comboFinisherBloom; public static float comboFinisherBaseDurationBeforeInterruptable; public static string slash1Sound; public static string slash3Sound; private string animationStateName; private string meleeStreakStateName; private float durationBeforeInterruptable; private bool isComboFinisher => club == 1; protected override bool allowExitFire { get { if ((bool)base.characterBody) { return !base.characterBody.isSprinting; } return false; } } void SteppedSkillDef.IStepSetter.SetStep(int i) { club = i; } public override void OnEnter() { base.OnEnter(); if (isComboFinisher) { swingEffectPrefab = comboFinisherSwingEffectPrefab; hitPauseDuration = comboFinisherhitPauseDuration; damageCoefficient = comboFinisherDamageCoefficient; bloom = comboFinisherBloom; hitBoxGroupName = "SwordLarge"; baseDuration = comboFinisherBaseDuration; } base.OnEnter(); base.characterDirection.forward = GetAimRay().direction; durationBeforeInterruptable = (isComboFinisher ? (comboFinisherBaseDurationBeforeInterruptable / attackSpeedStat) : (baseDurationBeforeInterruptable / attackSpeedStat)); } public override void OnExit() { base.OnExit(); } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); _ = isComboFinisher; } protected override void PlayAnimation() { animationStateName = ""; string soundString = null; switch (club) { case 0: animationStateName = "SwingClubRight"; meleeStreakStateName = "SwingRight"; soundString = slash1Sound; break; case 1: animationStateName = "SwingClubLeft"; meleeStreakStateName = "SwingLeft"; soundString = slash1Sound; break; } bool @bool = animator.GetBool("isMoving"); bool bool2 = animator.GetBool("isGrounded"); if (!@bool && bool2) { PlayCrossfade("FullBody, Override", animationStateName, "SwingClub.playbackRate", duration, 0.05f); } else { PlayCrossfade("Gesture, Additive", animationStateName, "SwingClub.playbackRate", duration, 0.05f); PlayCrossfade("Gesture, Override", animationStateName, "SwingClub.playbackRate", duration, 0.05f); } Util.PlaySound(soundString, base.gameObject); } protected override void OnMeleeHitAuthority() { base.OnMeleeHitAuthority(); base.characterBody.AddSpreadBloom(bloom); } protected override void BeginMeleeAttackEffect() { swingEffectMuzzleString = meleeStreakStateName; AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); base.BeginMeleeAttackEffect(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)club); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); club = reader.ReadByte(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } } public class ClubSwing3 : BaseSkillState, ISkillOverrideHandoff { private class ArcVisualizer : IDisposable { private readonly UnityEngine.Vector3[] points; private readonly float duration; private readonly GameObject arcVisualizerInstance; private readonly LineRenderer lineRenderer; public ArcVisualizer(GameObject arcVisualizerPrefab, float duration, int vertexCount) { arcVisualizerInstance = UnityEngine.Object.Instantiate(arcVisualizerPrefab); lineRenderer = arcVisualizerInstance.GetComponent(); lineRenderer.positionCount = vertexCount; points = new UnityEngine.Vector3[vertexCount]; this.duration = duration; } public void Dispose() { EntityState.Destroy(arcVisualizerInstance); } public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float characterMaxSpeed, float characterAcceleration) { arcVisualizerInstance.transform.position = origin; if (!lineRenderer.useWorldSpace) { UnityEngine.Vector3 eulerAngles = UnityEngine.Quaternion.LookRotation(initialVelocity).eulerAngles; eulerAngles.x = 0f; eulerAngles.z = 0f; UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(eulerAngles); arcVisualizerInstance.transform.rotation = rotation; origin = UnityEngine.Vector3.zero; initialVelocity = UnityEngine.Quaternion.Inverse(rotation) * initialVelocity; } else { arcVisualizerInstance.transform.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.Cross(initialVelocity, UnityEngine.Vector3.up)); } float y = Physics.gravity.y; float num = duration / (float)points.Length; UnityEngine.Vector3 vector = origin; UnityEngine.Vector3 vector2 = initialVelocity; float num2 = num; float num3 = y * num2; float maxDistanceDelta = characterAcceleration * num2; for (int i = 0; i < points.Length; i++) { points[i] = vector; UnityEngine.Vector2 current = Util.Vector3XZToVector2XY(vector2); current = UnityEngine.Vector2.MoveTowards(current, UnityEngine.Vector3.zero, maxDistanceDelta); vector2.x = current.x; vector2.z = current.y; vector2.y += num3; vector += vector2 * num2; } lineRenderer.SetPositions(points); } } public static GameObject arcVisualizerPrefab; public static float arcVisualizerSimulationLength; public static int arcVisualizerVertexCount; [SerializeField] public float baseChargeDuration = 1f; [SerializeField] public float minChargeToDisplayAttackCharging; [SerializeField] public float minChargeToChargeAttack; [SerializeField] public float cooldownOnCancelDuration = 1f; public static GameObject chargeVfxPrefab; public static string chargeVfxChildLocatorName; public static GameObject crosshairOverridePrefab; public static float walkSpeedCoefficient; public static string startChargeLoopSFXString; public static string endChargeLoopSFXString; public static string enterSFXString; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private Transform chargeVfxInstanceTransform; private int gauntlet; private uint soundID; private bool chargeAnimPlayed; private SkillStateOverrideData skillOverrideData; private bool clearOverrides = true; private bool nonAuthority_AllowEarlyCancelAnimationToFinish; private float cooldownTimestamp = -1f; protected float chargeDuration { get; private set; } protected float charge { get; private set; } public override void OnEnter() { base.OnEnter(); chargeDuration = baseChargeDuration / attackSpeedStat; Util.PlaySound(enterSFXString, base.gameObject); soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject); clearOverrides = true; ResetPrimarySwingCount(); } private void ResetPrimarySwingCount() { SteppedSkillDef.InstanceData instanceData = (SteppedSkillDef.InstanceData)(base.skillLocator.GetSkill(SkillSlot.Primary)?.skillInstanceData); if (instanceData != null) { instanceData.step = 0; } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void FixedUpdate() { if (skillOverrideData != null) { skillOverrideData.StepRestock(); } if (cooldownTimestamp != -1f) { if (!(Time.time - cooldownTimestamp < cooldownOnCancelDuration)) { outer.SetNextStateToMain(); } return; } base.FixedUpdate(); charge = Mathf.Clamp01(base.fixedAge / chargeDuration); AkSoundEngine.SetRTPCValueByPlayingID("charFalseSon_skill1_chargeAmount", charge * 100f, soundID); base.characterBody.SetSpreadBloom(charge); base.characterBody.SetAimTimer(3f); if (charge >= minChargeToDisplayAttackCharging && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab) { if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } Transform transform = FindModelChild(chargeVfxChildLocatorName); if ((bool)transform && charge > minChargeToChargeAttack) { chargeVfxInstanceTransform = EffectManager.GetAndActivatePooledEffect(chargeVfxPrefab, transform, inResetLocal: true)?.transform; ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent(); if ((bool)component) { component.newDuration = (1f - minChargeToDisplayAttackCharging) * chargeDuration; } } if (!chargeAnimPlayed) { PlayAnimation("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f); PlayAnimation("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f); chargeAnimPlayed = true; } } if ((bool)chargeVfxInstanceTransform) { base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; } if (base.isAuthority) { AuthorityFixedUpdate(); } } public override void Update() { base.Update(); Mathf.Clamp01(base.age / chargeDuration); } private void AuthorityFixedUpdate() { if (!base.inputBank.skill1.down && !base.inputBank.skill2.down) { if ((base.inputBank.skill2.justReleased || base.inputBank.skill1.justReleased) && CanOverheadSwing()) { outer.SetNextState(GetNextStateAuthority()); } else { HandleEarlyCancel(); } } } private void HandleEarlyCancel() { if (cooldownTimestamp == -1f) { PlayAnimation("Gesture, Additive", "ChargeSwingExit"); PlayAnimation("Gesture, Override", "ChargeSwingExit"); cooldownTimestamp = Time.time; } } private bool CanOverheadSwing() { if (!(charge > minChargeToChargeAttack)) { return base.isGrounded; } return true; } protected virtual bool ShouldKeepChargingAuthority() { return IsKeyDownAuthority(); } protected virtual EntityState GetNextStateAuthority() { if (!base.isGrounded) { return new PreClubGroundSlam { charge = charge }; } if (charge > minChargeToChargeAttack) { return new ChargedClubSwing { charge = charge, chargeMetMinimumHold = (charge > minChargeToChargeAttack) }; } return new OverheadClubSwing(); } public override void OnExit() { if (clearOverrides) { skillOverrideData?.ClearOverrides(); } if ((bool)chargeVfxInstanceTransform) { EntityState.Destroy(chargeVfxInstanceTransform.gameObject); crosshairOverrideRequest?.Dispose(); chargeVfxInstanceTransform = null; } if (!nonAuthority_AllowEarlyCancelAnimationToFinish) { PlayAnimation("Gesture, Additive", "Empty"); PlayAnimation("Gesture, Override", "Empty"); } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; Util.PlaySound(endChargeLoopSFXString, base.gameObject); base.OnExit(); } public override void ModifyNextState(EntityState nextState) { base.ModifyNextState(nextState); if (nextState is ISkillOverrideHandoff skillOverrideHandoff) { skillOverrideHandoff.TransferSkillOverride(skillOverrideData); clearOverrides = false; if (!base.isAuthority && nextState is IdleSkillOverrideHandoff) { HandleEarlyCancel(); nonAuthority_AllowEarlyCancelAnimationToFinish = true; } } } public void TransferSkillOverride(SkillStateOverrideData skillOverrideData) { this.skillOverrideData = skillOverrideData; } } public class LaserFather : BaseSkillState { [SerializeField] public float baseChargeDuration = 1f; [SerializeField] public GameObject chargeCompletePrefab; public static float minChargeForChargedAttack; public static GameObject chargeVfxPrefab; public static string chargeVfxChildLocatorName; public static GameObject crosshairOverridePrefab; public static float walkSpeedCoefficient; public static string startChargeLoopSFXString; public static string endChargeLoopSFXString; public static string enterSFXString; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private Transform chargeVfxInstanceTransform; private int gauntlet; private uint soundID; public static float baseDuration = 3f; public static float laserMaxWidth = 0.2f; public static GameObject effectPrefab; public static GameObject laserPrefab; public static string attackSoundString; private float duration; private uint chargePlayID; private GameObject chargeEffect; private GameObject laserEffect; private LineRenderer laserLineComponent; private UnityEngine.Vector3 laserDirection; private UnityEngine.Vector3 visualEndPosition; private float flashTimer; private bool laserOn; private bool chargeAnimPlayed; private bool chargeFinished; private bool chargeStarted; private bool cancellingAttack; protected float chargeDuration { get; private set; } protected float charge { get; private set; } public override void OnEnter() { base.OnEnter(); chargeDuration = baseChargeDuration / attackSpeedStat; soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject); duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); chargePlayID = Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleLaser"); if ((bool)transform) { if ((bool)effectPrefab) { chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); chargeEffect.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffect.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } if ((bool)laserPrefab) { laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation); laserEffect.transform.parent = transform; laserLineComponent = laserEffect.GetComponent(); } } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } flashTimer = 0f; laserOn = true; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void ModifyNextState(EntityState nextState) { base.ModifyNextState(nextState); LaserFatherCharged laserFatherCharged = nextState as LaserFatherCharged; cancellingAttack = laserFatherCharged == null; } public override void OnExit() { if ((bool)chargeVfxInstanceTransform) { EntityState.Destroy(chargeVfxInstanceTransform.gameObject); crosshairOverrideRequest?.Dispose(); chargeVfxInstanceTransform = null; } PlayAnimation("Gesture, Additive", "Empty"); PlayAnimation("Gesture, Override", "Empty"); if (cancellingAttack) { PlayAnimation("Gesture, Head, Additive", "Empty"); PlayAnimation("Gesture, Head, Override", "Buffer Empty"); } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; Util.PlaySound(endChargeLoopSFXString, base.gameObject); AkSoundEngine.StopPlayingID(chargePlayID); Util.PlaySound("Stop_falseson_skill4_laser_loop", base.gameObject); Util.PlaySound("Stop_falseson_skill4_laser_charge_loop", base.gameObject); base.OnExit(); if ((bool)chargeEffect) { EntityState.Destroy(chargeEffect); } if ((bool)laserEffect) { EntityState.Destroy(laserEffect); } } public override void FixedUpdate() { base.FixedUpdate(); charge = Mathf.Clamp01(base.fixedAge / chargeDuration); AkSoundEngine.SetRTPCValueByPlayingID("charFalseSon_skill4_chargeAmount", charge * 100f, soundID); base.characterBody.SetSpreadBloom(charge); base.characterBody.SetAimTimer(3f); if (charge >= minChargeForChargedAttack && !chargeStarted) { chargeStarted = true; base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; PlayCrossfade("Gesture, Head, Additive", "LaserChargeIntro", "LaserChargeIntro.playbackRate", 0.2f * chargeDuration, 0.1f); PlayCrossfade("Gesture, Head, Override", "LaserChargeIntro", "LaserChargeIntro.playbackRate", 0.2f * chargeDuration, 0.1f); } if (base.isAuthority) { AuthorityFixedUpdate(); } if (!(charge > 0.85f) || chargeFinished) { return; } ChildLocator component = GetModelTransform().GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleLaser"); if ((bool)transform) { chargeCompletePrefab = LegacyResourcesAPI.Load("FalseSon/FalseSonLaserChargeComplete"); EffectManager.SpawnEffect(chargeCompletePrefab, new EffectData { origin = transform.transform.position, scale = 1f }, transmit: true); chargeFinished = true; } } } public override void Update() { base.Update(); Mathf.Clamp01(base.age / chargeDuration); } private void AuthorityFixedUpdate() { if (!ShouldKeepChargingAuthority()) { outer.SetNextState(GetNextStateAuthority()); } } protected virtual bool ShouldKeepChargingAuthority() { return IsKeyDownAuthority(); } protected virtual EntityState GetNextStateAuthority() { if (charge < 0.175f) { charge = 0.175f; } return new LaserFatherCharged { charge = charge, walkSpeedCoefficient = walkSpeedCoefficient }; } } public class LaserFatherBurst : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float blastRadius; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float baseDuration = 2f; public static string attackSoundString; public static float laserTimerPercent = 0.12f; public UnityEngine.Vector3 laserDirection; private float duration; private Ray modifiedAimRay; public float charge; private float maxSecondaryStock; private float secondaryStock; private Transform modelTransform; protected Transform muzzleTransform; private string targetMuzzle; private float rayDistance; private bool firedLaser; public override void OnEnter() { base.OnEnter(); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } duration = baseDuration / attackSpeedStat; PlayCrossfade("Gesture, Override", "FireLaser", "FireLaser.playbackRate", duration, 0.1f); PlayCrossfade("Gesture, Additive", "FireLaser", "FireLaser.playbackRate", duration, 0.1f); maxSecondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock; secondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).stock; int num = (int)(maxSecondaryStock * 0.3f); int num2 = (int)maxSecondaryStock - (int)secondaryStock; if (num2 > 0) { if (num2 < num) { base.skillLocator.GetSkill(SkillSlot.Secondary).stock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock; } else { base.skillLocator.GetSkill(SkillSlot.Secondary).stock = base.skillLocator.GetSkill(SkillSlot.Secondary).stock + num; } } } public void FireBurstLaser() { modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { muzzleTransform = component.FindChild("MuzzleLaser"); } } rayDistance = 1000f; Ray aimRay = GetAimRay(); UnityEngine.Vector3 position = muzzleTransform.transform.parent.position; UnityEngine.Vector3 point = aimRay.GetPoint(rayDistance); laserDirection = point - position; modifiedAimRay = GetAimRay(); modifiedAimRay.direction = laserDirection; TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref modifiedAimRay, rayDistance, base.gameObject); GetModelAnimator(); Util.PlaySound(attackSoundString, base.gameObject); targetMuzzle = "MuzzleLaser"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (!base.isAuthority) { return; } rayDistance = 200f; UnityEngine.Vector3 vector = modifiedAimRay.origin + modifiedAimRay.direction * rayDistance; if (Physics.Raycast(modifiedAimRay, out var hitInfo, rayDistance, LayerIndex.CommonMasks.laser)) { vector = hitInfo.point; } BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * damageCoefficient; blastAttack.baseForce = force * 0.2f; blastAttack.position = vector; blastAttack.radius = blastRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot; blastAttack.bonusForce = force * modifiedAimRay.direction; blastAttack.Fire(); _ = modifiedAimRay.origin; if (!modelTransform) { return; } ChildLocator component2 = modelTransform.GetComponent(); if ((bool)component2) { int childIndex = component2.FindChildIndex(targetMuzzle); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = vector, start = modifiedAimRay.origin }; effectData.SetChildLocatorTransformReference(base.gameObject, childIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); EffectManager.SpawnEffect(hitEffectPrefab, effectData, transmit: true); } } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration * laserTimerPercent && !firedLaser) { firedLaser = true; FireBurstLaser(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class LaserFatherCharged : BaseState { [SerializeField] public GameObject effectPrefab; [SerializeField] public GameObject hitEffectPrefab; [SerializeField] public GameObject laserPrefab; public static string playAttackSoundString; public static string playLoopSoundString; public static string stopLoopSoundString; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float fireFrequency; public static float maxDistance; public static float minimumDuration; public static float maximumDuration; public static float lockOnAngle; public static float procCoefficientPerTick; private HurtBox lockedOnHurtBox; private float fireStopwatch; private float stopwatch; private float refillSecondaryStopwatch; private float maxSecondaryStock; private float secondaryStock; private Ray aimRay; private Transform modelTransform; private GameObject laserEffect; private ChildLocator laserChildLocator; private Transform laserEffectEnd; public float charge; protected Transform muzzleTransform; private float bonusDuration; protected CameraTargetParams.AimRequest aimRequest; public static int abilityAimType; private float duration; public float walkSpeedCoefficient = 1f; private int lunarSpikeCount; public static event Action laserTracking; public override void OnEnter() { base.OnEnter(); duration = maximumDuration; aimRequest = base.cameraTargetParams.RequestAimType((CameraTargetParams.AimType)abilityAimType); base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; FalseSonController component = GetComponent(); if ((bool)component) { lunarSpikeCount = component.GetTotalSpikeCount(); } else { lunarSpikeCount = 0; } Util.PlaySound("Play_falseson_skill4_laser_start", base.gameObject); PlayCrossfade("Gesture, Head, Override", "FireLaserLoop", 0.25f); PlayCrossfade("Gesture, Head, Additive", "FireLaserLoop", 0.25f); aimRay = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, maxDistance, base.gameObject); modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component2 = modelTransform.GetComponent(); if ((bool)component2) { muzzleTransform = component2.FindChild("MuzzleLaser"); if ((bool)muzzleTransform && (bool)laserPrefab) { laserEffect = UnityEngine.Object.Instantiate(laserPrefab, muzzleTransform.position, muzzleTransform.rotation); laserEffect.transform.parent = muzzleTransform; laserChildLocator = laserEffect.GetComponent(); laserEffectEnd = laserChildLocator.FindChild("LaserEnd"); } } } bonusDuration = 0f; for (int i = 1; i <= lunarSpikeCount; i++) { bonusDuration += 1f / (0.5f * (float)i + 1f); } if (bonusDuration < 0f) { bonusDuration = 0f; } duration += bonusDuration; base.characterBody.SetAimTimer(duration); float num = base.characterBody.attackSpeed - base.characterBody.baseAttackSpeed; fireFrequency += num * 0.3f; maxSecondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock; secondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock; LaserFatherCharged.laserTracking?.Invoke(duration); } public override void OnExit() { aimRequest?.Dispose(); if ((bool)laserEffect) { LaserFatherCharged.laserTracking?.Invoke(0f); EntityState.Destroy(laserEffect); } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; base.characterBody.SetAimTimer(2f); Util.PlaySound("Stop_falseson_skill4_laser_loop", base.gameObject); Util.PlaySound("Stop_falseson_skill4_laser_charge_loop", base.gameObject); Util.PlaySound("Play_falseson_skill4_laser_end", base.gameObject); PlayAnimation("Gesture, Head, Override", "FireLaserLoopEnd"); PlayAnimation("Gesture, Head, Additive", "FireLaserLoopEnd"); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); fireStopwatch += deltaTime; stopwatch += deltaTime; refillSecondaryStopwatch += deltaTime; if (refillSecondaryStopwatch > 1f) { maxSecondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock; secondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).stock; if (secondaryStock < maxSecondaryStock) { base.skillLocator.GetSkill(SkillSlot.Secondary).stock++; refillSecondaryStopwatch = 0f; } } aimRay = GetAimRay(); UnityEngine.Vector3 vector = aimRay.origin; if ((bool)muzzleTransform) { vector = muzzleTransform.position; } UnityEngine.Vector3 vector2; if ((bool)lockedOnHurtBox) { vector2 = lockedOnHurtBox.transform.position; } else { TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, maxDistance, base.gameObject); vector2 = ((!Util.CharacterRaycast(base.gameObject, aimRay, out var hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) ? aimRay.GetPoint(maxDistance) : hitInfo.point); } Ray ray = new Ray(vector, vector2 - vector); bool flag = false; if ((bool)laserEffect && (bool)laserChildLocator) { if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo2, (vector2 - vector).magnitude, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal)) { vector2 = hitInfo2.point; if (Util.CharacterRaycast(base.gameObject, new Ray(vector2 - ray.direction * 0.1f, -ray.direction), out var _, hitInfo2.distance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal)) { vector2 = ray.GetPoint(0.1f); flag = true; } } laserEffect.transform.rotation = Util.QuaternionSafeLookRotation(vector2 - vector); laserEffectEnd.transform.position = vector2; } if (fireStopwatch > 1f / fireFrequency) { string targetMuzzle = "MuzzleLaser"; if (!flag) { FireBullet(modelTransform, ray, targetMuzzle, (vector2 - ray.origin).magnitude + 0.1f); } fireStopwatch -= 1f / fireFrequency; } if (base.isAuthority && stopwatch > duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } private void FireBullet(Transform modelTransform, Ray aimRay, string targetMuzzle, float maxDistance) { if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { if (charge > 0.85f) { charge = 1f; } BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.bulletCount = 1u; bulletAttack.damage = damageCoefficient * damageStat * charge; bulletAttack.force = force; bulletAttack.muzzleName = targetMuzzle; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.procCoefficient = procCoefficientPerTick; bulletAttack.HitEffectNormal = false; bulletAttack.radius = 1f; bulletAttack.maxDistance = maxDistance; bulletAttack.Fire(); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(HurtBoxReference.FromHurtBox(lockedOnHurtBox)); writer.Write(stopwatch); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); HurtBoxReference hurtBoxReference = reader.ReadHurtBoxReference(); stopwatch = reader.ReadSingle(); lockedOnHurtBox = hurtBoxReference.ResolveGameObject()?.GetComponent(); } } public class LunarSpikes : BaseState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float procCoefficient; [SerializeField] public float damageCoefficient; [SerializeField] public float force = 20f; public static float attackSpeedAltAnimationThreshold; [SerializeField] public float baseDuration; [SerializeField] public string attackSoundString; [SerializeField] public float attackSoundPitch; public static float bloom; private float duration; private bool hasFiredSpike; private string muzzleString; private Transform muzzleTransform; private Animator animator; private ChildLocator childLocator; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch); base.characterBody.SetAimTimer(2f); animator = GetModelAnimator(); if ((bool)animator) { childLocator = animator.GetComponent(); } muzzleString = "MuzzleRight"; if (attackSpeedStat < attackSpeedAltAnimationThreshold) { PlayCrossfade("Gesture, Additive", "FireLunarSpike", "LunarSpike.playbackRate", duration, 0.1f); PlayCrossfade("Gesture, Override", "FireLunarSpike", "LunarSpike.playbackRate", duration, 0.1f); FireLunarSpike(); } else { PlayAnimation("Gesture, Override", "HoldGauntletsUp", "LunarSpike.playbackRate", duration); FireLunarSpike(); } } public override void OnExit() { base.OnExit(); } private void FireLunarSpike() { if (!hasFiredSpike) { base.characterBody.AddSpreadBloom(bloom); hasFiredSpike = true; Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); if ((bool)childLocator) { muzzleTransform = childLocator.FindChild(muzzleString); } if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageCoefficient * damageStat, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Void); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class LunarSpikesShotgun : BaseState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject muzzleflashEffectPrefab; [SerializeField] public float procCoefficient; [SerializeField] public float damageCoefficient; [SerializeField] public float force = 20f; public static float attackSpeedAltAnimationThreshold; [SerializeField] public float baseDuration; [SerializeField] public string attackSoundString; [SerializeField] public float attackSoundPitch; public static float bloom; private float duration; private bool hasFiredSpike; private string muzzleString; private Transform muzzleTransform; private Animator animator; private ChildLocator childLocator; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch); base.characterBody.SetAimTimer(2f); animator = GetModelAnimator(); if ((bool)animator) { childLocator = animator.GetComponent(); } muzzleString = "MuzzleRight"; if (attackSpeedStat < attackSpeedAltAnimationThreshold) { PlayCrossfade("Gesture, Additive", "FireLunarSpike", "LunarSpike.playbackRate", duration, 0.1f); PlayCrossfade("Gesture, Override", "FireLunarSpike", "LunarSpike.playbackRate", duration, 0.1f); FireLunarSpike(); } else { PlayAnimation("Gesture, Override", "HoldGauntletsUp", "LunarSpike.playbackRate", duration); FireLunarSpike(); } } public override void OnExit() { base.OnExit(); } private void FireLunarSpike() { if (!hasFiredSpike) { base.characterBody.AddSpreadBloom(bloom); hasFiredSpike = true; Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); if ((bool)childLocator) { muzzleTransform = childLocator.FindChild(muzzleString); } if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageCoefficient * damageStat, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Void); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class OverheadClubSwing : BasicMeleeAttack { protected override void PlayAnimation() { PlayAnimation("FullBody, Override", "OverheadSwing", "ChargeSwing.playbackRate", duration); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class StepBrothers : BaseState { private Transform modelTransform; public static GameObject dashPrefab; public static float smallHopVelocity; public static float dashPrepDuration; public static float dashDuration = 0.3f; public static float speedCoefficient = 25f; public static string beginSoundString; public static float damageCoefficient; public static float procCoefficient; public static GameObject hitEffectPrefab; public static float hitPauseDuration; private float stopwatch; private UnityEngine.Vector3 dashVector = UnityEngine.Vector3.zero; private Animator animator; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private OverlapAttack overlapAttack; private ChildLocator childLocator; private bool isDashing; private bool inHitPause; private float hitPauseTimer; private CameraTargetParams.AimRequest aimRequest; private CharacterBody survivorBody; public static GameObject explosionEffect; public BlastAttack explosionAttack; private int originalLayer; public bool hasHit { get; private set; } public int dashIndex { private get; set; } public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); survivorBody = base.gameObject.GetComponent(); if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } if ((bool)modelTransform) { animator = modelTransform.GetComponent(); characterModel = modelTransform.GetComponent(); childLocator = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); _ = (bool)childLocator; } PlayAnimation("FullBody, Override", "StepBrothersPrep", "StepBrothersPrep.playbackRate", dashPrepDuration); dashVector = base.inputBank.aimDirection; overlapAttack = InitMeleeOverlap(0f, hitEffectPrefab, modelTransform, "StepBrothers"); if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); } } private void CreateDashEffect() { Transform transform = childLocator.FindChild("DashCenter"); if ((bool)transform && (bool)dashPrefab) { UnityEngine.Object.Instantiate(dashPrefab, transform.position, Util.QuaternionSafeLookRotation(dashVector), transform); } } public override void FixedUpdate() { base.FixedUpdate(); base.characterDirection.forward = dashVector; if (stopwatch > dashPrepDuration / attackSpeedStat && !isDashing) { isDashing = true; dashVector = base.inputBank.aimDirection; CreateDashEffect(); PlayCrossfade("FullBody, Override", "StepBrothersLoop", 0.1f); originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal; base.characterMotor.Motor.RebuildCollidableLayers(); } if (!isDashing) { stopwatch += GetDeltaTime(); } else if (base.isAuthority) { base.characterMotor.velocity = UnityEngine.Vector3.zero; if (!inHitPause) { bool num = overlapAttack.Fire(); stopwatch += GetDeltaTime(); if (num) { UnityEngine.Vector3 position = base.gameObject.transform.position; UnityEngine.Object.Instantiate(explosionEffect, position, UnityEngine.Quaternion.identity); explosionAttack = new BlastAttack(); explosionAttack.attacker = base.gameObject; explosionAttack.inflictor = base.gameObject; explosionAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); explosionAttack.baseDamage = damageStat * damageCoefficient; explosionAttack.position = position; explosionAttack.radius = 20f; explosionAttack.Fire(); if (!hasHit) { hasHit = true; } inHitPause = true; hitPauseTimer = hitPauseDuration / attackSpeedStat; } base.characterMotor.rootMotion += dashVector * moveSpeedStat * speedCoefficient * GetDeltaTime(); } else { hitPauseTimer -= GetDeltaTime(); if (hitPauseTimer < 0f) { inHitPause = false; } } } if (stopwatch >= dashDuration + dashPrepDuration / attackSpeedStat && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { base.gameObject.layer = originalLayer; base.characterMotor.Motor.RebuildCollidableLayers(); _ = base.isAuthority; aimRequest?.Dispose(); _ = (bool)childLocator; PlayAnimation("FullBody, Override", "StepBrothersLoopExit"); if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); } base.OnExit(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)dashIndex); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); dashIndex = reader.ReadByte(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class TheTamperedHeart : BaseState { public override void OnEnter() { } } } namespace EntityStates.EngiTurret { public class DeathState : GenericCharacterDeath { [SerializeField] public GameObject initialExplosion; [SerializeField] public GameObject deathExplosion; private float deathDuration; protected override bool shouldAutoDestroy => false; protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Body"); modelAnimator.PlayInFixedTime("Death", layerIndex); modelAnimator.Update(0f); deathDuration = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length; if ((bool)initialExplosion) { UnityEngine.Object.Instantiate(initialExplosion, base.transform.position, base.transform.rotation, base.transform); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > deathDuration && NetworkServer.active && (bool)deathExplosion) { EffectManager.SpawnEffect(deathExplosion, new EffectData { origin = base.transform.position, scale = 2f }, transmit: true); EntityState.Destroy(base.gameObject); } } public override void OnExit() { DestroyModel(); base.OnExit(); } } } namespace EntityStates.EngiTurret.EngiTurretWeapon { public class FireBeam : BaseState { [SerializeField] public GameObject effectPrefab; [SerializeField] public GameObject hitEffectPrefab; [SerializeField] public GameObject laserPrefab; [SerializeField] public string muzzleString; [SerializeField] public string attackSoundString; [SerializeField] public float damageCoefficient; [SerializeField] public float procCoefficient; [SerializeField] public float force; [SerializeField] public float minSpread; [SerializeField] public float maxSpread; [SerializeField] public int bulletCount; [SerializeField] public float fireFrequency; [SerializeField] public float maxDistance; private float fireTimer; private Ray laserRay; private Transform modelTransform; private GameObject laserEffectInstance; private Transform laserEffectInstanceEndTransform; private UnityEngine.Vector3 laserEndPoint; private float prevLaserDistance; private bool forceCast; private BulletAttack bulletAttack; private EffectManagerHelper _emh_laserEffect; public override void Reset() { base.Reset(); fireTimer = 0f; laserEndPoint = UnityEngine.Vector3.zero; modelTransform = null; laserEffectInstance = null; laserEffectInstanceEndTransform = null; forceCast = true; if (bulletAttack != null) { bulletAttack.Reset(); } _emh_laserEffect = null; } public override void OnEnter() { base.OnEnter(); Util.PlaySound(attackSoundString, base.gameObject); fireTimer = 0f; forceCast = true; modelTransform = GetModelTransform(); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild(muzzleString); if ((bool)transform && (bool)laserPrefab) { if (!EffectManager.ShouldUsePooledEffect(laserPrefab)) { laserEffectInstance = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation); } else { _emh_laserEffect = EffectManager.GetAndActivatePooledEffect(laserPrefab, transform.position, transform.rotation); laserEffectInstance = _emh_laserEffect.gameObject; } if ((bool)laserEffectInstance) { ChildLocator component2 = laserEffectInstance.GetComponent(); laserEffectInstanceEndTransform = component2.FindChild("LaserEnd"); } laserEffectInstance.transform.parent = transform; } } public override void OnExit() { if ((bool)laserEffectInstance) { if (_emh_laserEffect != null && _emh_laserEffect.OwningPool != null) { _emh_laserEffect.OwningPool.ReturnObject(_emh_laserEffect); } else { EntityState.Destroy(laserEffectInstance); } laserEffectInstance = null; _emh_laserEffect = null; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!(Time.deltaTime > 0f)) { return; } laserRay = GetLaserRay(); fireTimer += Time.deltaTime; float num = fireFrequency * base.characterBody.attackSpeed; float num2 = 1f / num; if (fireTimer > num2) { if (base.isAuthority) { laserEndPoint = FireBullet(laserRay, muzzleString); prevLaserDistance = (laserEndPoint - laserRay.origin).magnitude; } else { forceCast = true; } fireTimer = 0f; } else if (!forceCast && prevLaserDistance > float.Epsilon) { laserEndPoint = laserRay.origin + laserRay.direction * prevLaserDistance; } if (forceCast) { forceCast = false; if ((bool)laserEffectInstance && (bool)laserEffectInstanceEndTransform) { float distance = maxDistance; _ = laserEffectInstance.transform.parent.position; laserEndPoint = laserRay.GetPoint(distance); if (Util.CharacterRaycast(base.gameObject, laserRay, out var hitInfo, distance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal)) { laserEndPoint = hitInfo.point; prevLaserDistance = (laserEndPoint - laserRay.origin).magnitude; } } } if ((bool)laserEffectInstance && (bool)laserEffectInstanceEndTransform) { laserEffectInstanceEndTransform.position = laserEndPoint; } if (base.isAuthority && !ShouldFireLaser()) { outer.SetNextStateToMain(); } } protected UnityEngine.Vector3 GetBeamEndPoint() { UnityEngine.Vector3 point = laserRay.GetPoint(maxDistance); if (Util.CharacterRaycast(base.gameObject, laserRay, out var hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal)) { point = hitInfo.point; } return point; } protected virtual EntityState GetNextState() { return EntityStateCatalog.InstantiateState(ref outer.mainStateType); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } public virtual void ModifyBullet(BulletAttack bulletAttack) { bulletAttack.damageType |= (DamageTypeCombo)DamageType.SlowOnHit; } public virtual bool ShouldFireLaser() { if ((bool)base.inputBank) { return base.inputBank.skill1.down; } return false; } public virtual Ray GetLaserRay() { return GetAimRay(); } private UnityEngine.Vector3 FireBullet(Ray laserRay, string targetMuzzle) { if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { if (bulletAttack == null) { bulletAttack = new BulletAttack(); } bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = laserRay.origin; bulletAttack.aimVector = laserRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.bulletCount = 1u; bulletAttack.damage = damageCoefficient * damageStat / fireFrequency; bulletAttack.procCoefficient = procCoefficient / fireFrequency; bulletAttack.force = force; bulletAttack.muzzleName = targetMuzzle; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.HitEffectNormal = false; bulletAttack.radius = 0f; bulletAttack.maxDistance = maxDistance; ModifyBullet(bulletAttack); return bulletAttack.Fire_ReturnHit(); } return UnityEngine.Vector3.zero; } } public class FireGauss : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static string attackSoundString; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float baseDuration = 2f; public int bulletCountCurrent = 1; private float duration; private static int FireGaussStateHash = Animator.StringToHash("FireGauss"); private static int FireGaussParamHash = Animator.StringToHash("FireGauss.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(attackSoundString, base.gameObject); Ray aimRay = GetAimRay(); StartAimMode(aimRay); PlayAnimation("Gesture", FireGaussStateHash, FireGaussParamHash, duration); string muzzleName = "Muzzle"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.bulletCount = 1u; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleName; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.HitEffectNormal = false; bulletAttack.radius = 0.15f; bulletAttack.Fire(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.Engi.SpiderMine { public class BaseSpiderMineState : BaseState { protected static int IdleToArmedStateHash = Animator.StringToHash("IdleToArmed"); protected static int IdleToArmedParamHash = Animator.StringToHash("IdleToArmed.playbackRate"); protected static int ArmedToChaseStateHash = Animator.StringToHash("ArmedToChase"); protected static int ArmedToChaseParamHash = Animator.StringToHash("ArmedToChase.playbackRate"); protected static int ChaseStateHash = Animator.StringToHash("Chase"); [SerializeField] public string enterSoundString; [SerializeField] public string childLocatorStringToEnable; protected ProjectileStickOnImpact projectileStickOnImpact { get; private set; } protected ProjectileTargetComponent projectileTargetComponent { get; private set; } protected ProjectileGhostController projectileGhostController { get; private set; } protected virtual bool shouldStick => false; public override void OnEnter() { base.OnEnter(); projectileStickOnImpact = GetComponent(); projectileTargetComponent = GetComponent(); projectileGhostController = base.projectileController.ghost; if ((bool)base.modelLocator && (bool)projectileGhostController) { base.modelLocator.modelBaseTransform = projectileGhostController.transform; base.modelLocator.modelTransform = base.modelLocator.modelBaseTransform.Find("mdlEngiSpiderMine"); base.modelLocator.preserveModel = true; base.modelLocator.noCorpse = true; } if (projectileStickOnImpact.enabled != shouldStick) { projectileStickOnImpact.enabled = shouldStick; } Transform transform = FindModelChild(childLocatorStringToEnable); if ((bool)transform) { transform.gameObject.SetActive(value: true); } Util.PlaySound(enterSoundString, base.gameObject); } protected void EmitDustEffect() { if ((bool)projectileGhostController) { projectileGhostController.transform.Find("Ring").GetComponent().Play(); } } } public class WaitForStick : BaseSpiderMineState { private static int IdleStateHash = Animator.StringToHash("Idle"); protected override bool shouldStick => true; public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", IdleStateHash); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.projectileStickOnImpact.stuck) { outer.SetNextState(new Burrow()); } } } public class Burrow : BaseSpiderMineState { public static float baseDuration; private float duration; protected override bool shouldStick => true; public override void OnEnter() { base.OnEnter(); duration = baseDuration; PlayAnimation("Base", BaseSpiderMineState.IdleToArmedStateHash, BaseSpiderMineState.IdleToArmedParamHash, duration); EmitDustEffect(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { EntityState entityState = null; if (!base.projectileStickOnImpact.stuck) { entityState = new WaitForStick(); } else if (duration <= base.fixedAge) { entityState = new WaitForTarget(); } if (entityState != null) { outer.SetNextState(entityState); } } } } public class WaitForTarget : BaseSpiderMineState { private static int ArmedStateHash = Animator.StringToHash("Armed"); protected ProjectileSphereTargetFinder targetFinder { get; private set; } protected override bool shouldStick => true; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { targetFinder = GetComponent(); targetFinder.enabled = true; } PlayAnimation("Base", ArmedStateHash); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { EntityState entityState = null; if (!base.projectileStickOnImpact.stuck) { entityState = new WaitForStick(); } else if ((bool)base.projectileTargetComponent.target) { entityState = new Unburrow(); } if (entityState != null) { outer.SetNextState(entityState); } } } public override void OnExit() { if ((bool)targetFinder) { targetFinder.enabled = false; } base.OnExit(); } } public class Unburrow : BaseSpiderMineState { public static float baseDuration; public static int betterTargetSearchLimit; private float duration; protected override bool shouldStick => true; public override void OnEnter() { base.OnEnter(); duration = baseDuration; Util.PlaySound("Play_beetle_worker_idle", base.gameObject); PlayAnimation("Base", BaseSpiderMineState.ArmedToChaseStateHash, BaseSpiderMineState.ArmedToChaseParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } EntityState entityState = null; if (!base.projectileStickOnImpact.stuck) { entityState = new WaitForStick(); } else if ((bool)base.projectileTargetComponent.target) { if (duration <= base.fixedAge) { FindBetterTarget(base.projectileTargetComponent.target); entityState = new ChaseTarget(); } } else { entityState = new Burrow(); } if (entityState != null) { outer.SetNextState(entityState); } } private BullseyeSearch CreateBullseyeSearch(UnityEngine.Vector3 origin) { return new BullseyeSearch { searchOrigin = origin, filterByDistinctEntity = true, maxDistanceFilter = Detonate.blastRadius, sortMode = BullseyeSearch.SortMode.Distance, maxAngleFilter = 360f, teamMaskFilter = TeamMask.GetEnemyTeams(base.projectileController.teamFilter.teamIndex) }; } private void FindBetterTarget(Transform initialTarget) { BullseyeSearch bullseyeSearch = CreateBullseyeSearch(initialTarget.position); bullseyeSearch.RefreshCandidates(); HurtBox[] array = bullseyeSearch.GetResults().ToArray(); int num = array.Length; int num2 = -1; int i = 0; for (int num3 = Math.Min(array.Length, betterTargetSearchLimit); i < num3; i++) { HurtBox hurtBox = array[i]; int num4 = CountTargets(hurtBox.transform.position); if (num < num4) { num = num4; num2 = i; } } if (num2 != -1) { base.projectileTargetComponent.target = array[num2].transform; } } private int CountTargets(UnityEngine.Vector3 origin) { BullseyeSearch bullseyeSearch = CreateBullseyeSearch(origin); bullseyeSearch.RefreshCandidates(); return bullseyeSearch.GetResults().Count(); } } public class ChaseTarget : BaseSpiderMineState { private class OrientationHelper : MonoBehaviour { private Rigidbody rigidbody; private void Awake() { rigidbody = GetComponent(); } private void OnCollisionStay(Collision collision) { int contactCount = collision.contactCount; if (contactCount == 0) { return; } UnityEngine.Vector3 forward = collision.GetContact(0).normal; for (int i = 1; i < contactCount; i++) { UnityEngine.Vector3 normal = collision.GetContact(i).normal; if (forward.y < normal.y) { forward = normal; } } rigidbody.MoveRotation(UnityEngine.Quaternion.LookRotation(forward)); } } public static float speed; public static float triggerRadius; private bool passedDetonationRadius; private float bestDistance; private OrientationHelper orientationHelper; private Transform target => base.projectileTargetComponent.target; protected override bool shouldStick => false; public override void OnEnter() { base.OnEnter(); passedDetonationRadius = false; bestDistance = float.PositiveInfinity; PlayAnimation("Base", BaseSpiderMineState.ChaseStateHash); if (base.isAuthority) { orientationHelper = base.gameObject.AddComponent(); } } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } if (!target) { base.rigidbody.AddForce(UnityEngine.Vector3.up, ForceMode.VelocityChange); outer.SetNextState(new WaitForStick()); return; } UnityEngine.Vector3 position = target.position; UnityEngine.Vector3 position2 = base.transform.position; UnityEngine.Vector3 vector = position - position2; float magnitude = vector.magnitude; float y = base.rigidbody.velocity.y; UnityEngine.Vector3 velocity = vector * (speed / magnitude); velocity.y = y; base.rigidbody.velocity = velocity; if (!passedDetonationRadius && magnitude <= triggerRadius) { passedDetonationRadius = true; } if (magnitude < bestDistance) { bestDistance = magnitude; } else if (passedDetonationRadius) { outer.SetNextState(new PreDetonate()); } } public override void OnExit() { Transform transform = FindModelChild(childLocatorStringToEnable); if ((bool)transform) { transform.gameObject.SetActive(value: false); } if ((object)orientationHelper != null) { EntityState.Destroy(orientationHelper); orientationHelper = null; } base.OnExit(); } } public class PreDetonate : BaseSpiderMineState { public static float baseDuration; private float duration; protected override bool shouldStick => false; public override void OnEnter() { base.OnEnter(); duration = baseDuration; base.rigidbody.isKinematic = true; } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && duration <= base.fixedAge) { outer.SetNextState(new Detonate()); } } } public class Detonate : BaseSpiderMineState { public static float blastRadius; public static GameObject blastEffectPrefab; [SerializeField] private List childLocatorStringToDisable = new List { "Armed", "Chase", "PreDetonate" }; protected override bool shouldStick => false; public override void OnEnter() { base.OnEnter(); if (!NetworkServer.active) { return; } ProjectileDamage component = GetComponent(); UnityEngine.Vector3 position = base.transform.position; BlastAttack blastAttack = new BlastAttack(); blastAttack.position = position; blastAttack.attacker = base.projectileController.owner; blastAttack.baseDamage = component.damage; blastAttack.baseForce = component.force; blastAttack.bonusForce = UnityEngine.Vector3.zero; blastAttack.crit = component.crit; blastAttack.damageColorIndex = component.damageColorIndex; blastAttack.damageType = component.damageType; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.inflictor = base.gameObject; blastAttack.procChainMask = base.projectileController.procChainMask; blastAttack.radius = blastRadius; blastAttack.teamIndex = base.projectileController.teamFilter.teamIndex; blastAttack.procCoefficient = base.projectileController.procCoefficient; blastAttack.Fire(); EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = position, scale = blastRadius }, transmit: true); float duration = 0.25f; PlayAnimation("Base", BaseSpiderMineState.IdleToArmedStateHash, BaseSpiderMineState.IdleToArmedParamHash, duration); foreach (string item in childLocatorStringToDisable) { Transform transform = FindModelChild(item); if ((bool)transform) { transform.gameObject.SetActive(value: false); } } EntityState.Destroy(base.gameObject); } } } namespace EntityStates.Engi.MineDeployer { public class BaseMineDeployerState : BaseState { public static List instancesList = new List(); public GameObject owner { get; private set; } public override void OnEnter() { base.OnEnter(); owner = base.projectileController?.owner; instancesList.Add(this); } public override void OnExit() { instancesList.Remove(this); base.OnExit(); } } public class FireMine : BaseMineDeployerState { public static float duration; public static float launchApex; public static float patternRadius; public static GameObject projectilePrefab; private int fireIndex; private static UnityEngine.Vector3[] velocities; private static bool velocitiesResolved; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { ResolveVelocities(); Transform transform = base.transform.Find("FirePoint"); ProjectileDamage component = GetComponent(); UnityEngine.Vector3 forward = transform.TransformVector(velocities[fireIndex]); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.crit = component.crit; fireProjectileInfo.damage = component.damage; fireProjectileInfo.damageColorIndex = component.damageColorIndex; fireProjectileInfo.force = component.force; fireProjectileInfo.owner = base.owner; fireProjectileInfo.position = transform.position; fireProjectileInfo.procChainMask = base.projectileController.procChainMask; fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(forward); fireProjectileInfo.fuseOverride = -1f; fireProjectileInfo.useFuseOverride = false; fireProjectileInfo.speedOverride = forward.magnitude; fireProjectileInfo.useSpeedOverride = true; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && duration <= base.fixedAge) { int num = fireIndex + 1; if (num < velocities.Length) { outer.SetNextState(new FireMine { fireIndex = num }); } else { outer.SetNextState(new WaitForDeath()); } } } private static UnityEngine.Vector3[] GeneratePoints(float radius) { UnityEngine.Vector3[] array = new UnityEngine.Vector3[9]; UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(60f, UnityEngine.Vector3.up); UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(120f, UnityEngine.Vector3.up); UnityEngine.Vector3 forward = UnityEngine.Vector3.forward; array[0] = forward; array[1] = quaternion2 * array[0]; array[2] = quaternion2 * array[1]; float num = 1f; float num2 = UnityEngine.Vector3.Distance(array[0], array[1]); float num3 = Mathf.Sqrt(num * num + num2 * num2) / num; array[3] = quaternion * (array[2] * num3); array[4] = quaternion2 * array[3]; array[5] = quaternion2 * array[4]; num3 = 1f; array[6] = quaternion * (array[5] * num3); array[7] = quaternion2 * array[6]; array[8] = quaternion2 * array[7]; float num4 = radius / array[8].magnitude; for (int i = 0; i < array.Length; i++) { array[i] *= num4; } return array; } private static UnityEngine.Vector3[] GenerateHexPoints(float radius) { UnityEngine.Vector3[] array = new UnityEngine.Vector3[6]; UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(60f, UnityEngine.Vector3.up); ref UnityEngine.Vector3 reference = ref array[0]; reference = UnityEngine.Vector3.forward * radius; for (int i = 1; i < array.Length; i++) { ref UnityEngine.Vector3 reference2 = ref array[i]; reference2 = quaternion * reference; reference = ref reference2; } return array; } private static UnityEngine.Vector3[] GeneratePointsFromPattern(GameObject patternObject) { Transform transform = patternObject.transform; UnityEngine.Vector3 position = transform.position; List list = new List(); for (int i = 0; i < transform.childCount; i++) { Transform child = transform.GetChild(i); if (child.gameObject.activeInHierarchy) { list.Add(child.position - position); } } return list.ToArray(); } private static UnityEngine.Vector3[] GenerateVelocitiesFromPoints(UnityEngine.Vector3[] points, float apex) { UnityEngine.Vector3[] array = new UnityEngine.Vector3[points.Length]; float num = Trajectory.CalculateInitialYSpeedForHeight(apex); for (int i = 0; i < points.Length; i++) { UnityEngine.Vector3 normalized = points[i].normalized; float num2 = Trajectory.CalculateGroundSpeedToClearDistance(num, points[i].magnitude); UnityEngine.Vector3 vector = normalized * num2; vector.y = num; array[i] = vector; } return array; } private static void ResolveVelocities() { if (!velocitiesResolved) { velocities = GenerateVelocitiesFromPoints(GeneratePoints(patternRadius), launchApex); if (!Application.isEditor) { velocitiesResolved = true; } } } } public class WaitForDeath : BaseMineDeployerState { public static float duration; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && duration <= base.fixedAge) { EntityState.Destroy(base.gameObject); } } } public class WaitForStick : BaseMineDeployerState { private ProjectileStickOnImpact projectileStickOnImpact; public override void OnEnter() { base.OnEnter(); projectileStickOnImpact = GetComponent(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && projectileStickOnImpact.stuck) { outer.SetNextState(new FireMine()); } } } } namespace EntityStates.Engi.Mine { public class BaseMineArmingState : BaseState { [SerializeField] public float damageScale; [SerializeField] public float forceScale; [SerializeField] public float blastRadiusScale; [SerializeField] public float triggerRadius; [SerializeField] public string onEnterSfx; [SerializeField] public float onEnterSfxPlaybackRate; [SerializeField] public string pathToChildToEnable; private Transform enabledChild; public override void OnEnter() { base.OnEnter(); Util.PlayAttackSpeedSound(onEnterSfx, base.gameObject, onEnterSfxPlaybackRate); if (!string.IsNullOrEmpty(pathToChildToEnable)) { enabledChild = base.transform.Find(pathToChildToEnable); if ((bool)enabledChild) { enabledChild.gameObject.SetActive(value: true); } } } public override void OnExit() { if ((bool)enabledChild) { enabledChild.gameObject.SetActive(value: false); } base.OnExit(); } } public class MineArmingUnarmed : BaseMineArmingState { } public class MineArmingWeak : BaseMineArmingState { public static float duration; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && duration <= base.fixedAge) { outer.SetNextState(new MineArmingFull()); } } } public class MineArmingFull : BaseMineArmingState { } public class BaseMineState : BaseState { [SerializeField] public string enterSoundString; protected ProjectileStickOnImpact projectileStickOnImpact { get; private set; } protected EntityStateMachine armingStateMachine { get; private set; } protected virtual bool shouldStick => false; protected virtual bool shouldRevertToWaitForStickOnSurfaceLost => false; public override void OnEnter() { base.OnEnter(); projectileStickOnImpact = GetComponent(); armingStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Arming"); if (projectileStickOnImpact.enabled != shouldStick) { projectileStickOnImpact.enabled = shouldStick; } Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && shouldRevertToWaitForStickOnSurfaceLost && !projectileStickOnImpact.stuck) { outer.SetNextState(new WaitForStick()); } } } public class WaitForStick : BaseMineState { protected override bool shouldStick => true; protected override bool shouldRevertToWaitForStickOnSurfaceLost => false; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { base.armingStateMachine.SetNextState(new MineArmingUnarmed()); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.projectileStickOnImpact.stuck) { outer.SetNextState(new Arm()); } } } public class Arm : BaseMineState { public static float duration; protected override bool shouldStick => true; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && duration <= base.fixedAge) { outer.SetNextState(new WaitForTarget()); } } } public class WaitForTarget : BaseMineState { private ProjectileSphereTargetFinder targetFinder; private ProjectileTargetComponent projectileTargetComponent; private ProjectileImpactExplosion projectileImpactExplosion; protected override bool shouldStick => true; public override void OnEnter() { base.OnEnter(); projectileTargetComponent = GetComponent(); targetFinder = GetComponent(); if (NetworkServer.active) { targetFinder.enabled = true; base.armingStateMachine.SetNextState(new MineArmingWeak()); } } public override void OnExit() { if ((bool)targetFinder) { targetFinder.enabled = false; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)targetFinder) { if ((bool)projectileTargetComponent.target) { outer.SetNextState(new PreDetonate()); } if (base.armingStateMachine?.state is BaseMineArmingState baseMineArmingState) { targetFinder.enabled = baseMineArmingState.triggerRadius != 0f; targetFinder.lookRange = baseMineArmingState.triggerRadius; } } } } public class PreDetonate : BaseMineState { public static float duration; public static string pathToPrepForExplosionChildEffect; public static float detachForce; protected override bool shouldStick => false; protected override bool shouldRevertToWaitForStickOnSurfaceLost => false; public override void OnEnter() { base.OnEnter(); base.transform.Find(pathToPrepForExplosionChildEffect).gameObject.SetActive(value: true); base.rigidbody.AddForce(base.transform.forward * detachForce); base.rigidbody.AddTorque(UnityEngine.Random.onUnitSphere * 200f); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && duration <= base.fixedAge) { outer.SetNextState(new Detonate()); } } } public class Detonate : BaseMineState { public static float blastRadius; public static GameObject explosionEffectPrefab; protected override bool shouldStick => false; protected override bool shouldRevertToWaitForStickOnSurfaceLost => false; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { Explode(); } } private void Explode() { ProjectileDamage component = GetComponent(); float num = 0f; float num2 = 0f; float num3 = 0f; if (base.armingStateMachine?.state is BaseMineArmingState baseMineArmingState) { num = baseMineArmingState.damageScale; num2 = baseMineArmingState.forceScale; num3 = baseMineArmingState.blastRadiusScale; } float num4 = blastRadius * num3; BlastAttack blastAttack = new BlastAttack(); blastAttack.procChainMask = base.projectileController.procChainMask; blastAttack.procCoefficient = base.projectileController.procCoefficient; blastAttack.attacker = base.projectileController.owner; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = base.projectileController.teamFilter.teamIndex; blastAttack.procCoefficient = base.projectileController.procCoefficient; blastAttack.baseDamage = component.damage * num; blastAttack.baseForce = component.force * num2; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.crit = component.crit; blastAttack.radius = num4; blastAttack.position = base.transform.position; blastAttack.damageColorIndex = component.damageColorIndex; blastAttack.Fire(); if ((bool)explosionEffectPrefab) { EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = base.transform.position, rotation = base.transform.rotation, scale = num4 }, transmit: true); } EntityState.Destroy(base.gameObject); } } } namespace EntityStates.Engi.EngiWeapon { public class ChargeGrenades : BaseState { public static float baseTotalDuration; public static float baseMaxChargeTime; public static int maxCharges; public static GameObject chargeEffectPrefab; public static string chargeStockSoundString; public static string chargeLoopStartSoundString; public static string chargeLoopStopSoundString; public static int minGrenadeCount; public static int maxGrenadeCount; public static float minBonusBloom; public static float maxBonusBloom; private GameObject chargeLeftInstance; private GameObject chargeRightInstance; private int charge; private int lastCharge; private float totalDuration; private float maxChargeTime; private EffectManagerHelper _emh_chargeLeftInstance; private EffectManagerHelper _emh_chargeRightInstance; private static int ChargeGrenadesStateHash = Animator.StringToHash("ChargeGrenades"); private static int EmptyStateHash = Animator.StringToHash("Empty"); public override void Reset() { base.Reset(); chargeLeftInstance = null; chargeRightInstance = null; charge = 0; lastCharge = 0; totalDuration = 0f; maxChargeTime = 0f; _emh_chargeLeftInstance = null; _emh_chargeRightInstance = null; } public override void OnEnter() { base.OnEnter(); totalDuration = baseTotalDuration / attackSpeedStat; maxChargeTime = baseMaxChargeTime / attackSpeedStat; Transform modelTransform = GetModelTransform(); PlayAnimation("Gesture, Additive", ChargeGrenadesStateHash); Util.PlaySound(chargeLoopStartSoundString, base.gameObject); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild("MuzzleLeft"); if ((bool)transform && (bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeLeftInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeLeftInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation); chargeLeftInstance = _emh_chargeLeftInstance.gameObject; } chargeLeftInstance.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeLeftInstance.GetComponent(); if ((bool)component2) { component2.newDuration = totalDuration; } } Transform transform2 = component.FindChild("MuzzleRight"); if ((bool)transform2 && (bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeRightInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform2.position, transform2.rotation); } else { _emh_chargeRightInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform2.position, transform2.rotation); chargeRightInstance = _emh_chargeRightInstance.gameObject; } chargeRightInstance.transform.parent = transform2; ScaleParticleSystemDuration component3 = chargeRightInstance.GetComponent(); if ((bool)component3) { component3.newDuration = totalDuration; } } } public override void OnExit() { base.OnExit(); PlayAnimation("Gesture, Additive", EmptyStateHash); Util.PlaySound(chargeLoopStopSoundString, base.gameObject); if (chargeLeftInstance != null) { if (_emh_chargeLeftInstance != null && _emh_chargeLeftInstance.OwningPool != null) { _emh_chargeLeftInstance.OwningPool.ReturnObject(_emh_chargeLeftInstance); } else { EntityState.Destroy(chargeLeftInstance); } chargeLeftInstance = null; _emh_chargeLeftInstance = null; } if (chargeRightInstance != null) { if (_emh_chargeRightInstance != null && _emh_chargeRightInstance.OwningPool != null) { _emh_chargeRightInstance.OwningPool.ReturnObject(_emh_chargeRightInstance); } else { EntityState.Destroy(chargeRightInstance); } chargeRightInstance = null; _emh_chargeRightInstance = null; } } public override void FixedUpdate() { base.FixedUpdate(); lastCharge = charge; charge = Mathf.Min((int)(base.fixedAge / maxChargeTime * (float)maxCharges), maxCharges); float t = (float)charge / (float)maxCharges; float value = Mathf.Lerp(minBonusBloom, maxBonusBloom, t); base.characterBody.SetSpreadBloom(value); int num = Mathf.FloorToInt(Mathf.Lerp(minGrenadeCount, maxGrenadeCount, t)); if (lastCharge < charge) { Util.PlaySound(chargeStockSoundString, base.gameObject, "engiM1_chargePercent", 100f * ((float)(num - 1) / (float)maxGrenadeCount)); } if ((base.fixedAge >= totalDuration || !base.inputBank || !base.inputBank.skill1.down) && base.isAuthority) { FireGrenades fireGrenades = new FireGrenades(); fireGrenades.grenadeCountMax = num; outer.SetNextState(fireGrenades); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class EngiOtherShield : BaseState { public CharacterBody target; public float minimumDuration; private Indicator indicator; public override void OnEnter() { base.OnEnter(); if ((bool)target) { indicator = new Indicator(base.gameObject, LegacyResourcesAPI.Load("Prefabs/EngiShieldRetractIndicator")); indicator.active = true; indicator.targetTransform = Util.GetCoreTransform(target.gameObject); target.AddBuff(RoR2Content.Buffs.EngiShield); target.RecalculateStats(); HealthComponent component = target.GetComponent(); if ((bool)component) { component.RechargeShieldFull(); } } } public override void FixedUpdate() { base.FixedUpdate(); if (!target || !base.characterBody.healthComponent.alive) { outer.SetNextStateToMain(); } } public override void OnExit() { base.skillLocator.utility = base.skillLocator.FindSkill("GiveShield"); if (NetworkServer.active && (bool)target) { target.RemoveBuff(RoR2Content.Buffs.EngiShield); } if (base.isAuthority) { base.skillLocator.utility.RemoveAllStocks(); } if (indicator != null) { indicator.active = false; } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { if (!(base.fixedAge >= minimumDuration)) { return InterruptPriority.PrioritySkill; } return InterruptPriority.Skill; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(target.gameObject); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); GameObject gameObject = reader.ReadGameObject(); if ((bool)gameObject) { target = gameObject.GetComponent(); } } } public class EngiSelfShield : BaseState { public static float transferDelay = 0.1f; private HurtBox transferTarget; private BullseyeSearch friendLocator; private Indicator indicator; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active && (bool)base.characterBody) { base.characterBody.AddBuff(RoR2Content.Buffs.EngiShield); base.characterBody.RecalculateStats(); if ((bool)base.healthComponent) { base.healthComponent.RechargeShieldFull(); } } friendLocator = new BullseyeSearch(); friendLocator.teamMaskFilter = TeamMask.none; if ((bool)base.teamComponent) { friendLocator.teamMaskFilter.AddTeam(base.teamComponent.teamIndex); } friendLocator.maxDistanceFilter = 80f; friendLocator.maxAngleFilter = 20f; friendLocator.sortMode = BullseyeSearch.SortMode.Angle; friendLocator.filterByLoS = false; indicator = new Indicator(base.gameObject, LegacyResourcesAPI.Load("Prefabs/ShieldTransferIndicator")); } public override void OnExit() { base.skillLocator.utility = base.skillLocator.FindSkill("RetractShield"); if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.EngiShield); } if (base.isAuthority) { base.skillLocator.utility.RemoveAllStocks(); } indicator.active = false; base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority || !(base.fixedAge >= transferDelay) || !base.skillLocator.utility.IsReady()) { return; } if ((bool)base.characterBody) { float extraRaycastDistance = 0f; Ray ray = CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance); friendLocator.searchOrigin = ray.origin; friendLocator.searchDirection = ray.direction; friendLocator.maxDistanceFilter += extraRaycastDistance; friendLocator.RefreshCandidates(); friendLocator.FilterOutGameObject(base.gameObject); transferTarget = friendLocator.GetResults().FirstOrDefault(); } HealthComponent healthComponent = (transferTarget ? transferTarget.healthComponent : null); if ((bool)healthComponent) { indicator.targetTransform = Util.GetCoreTransform(healthComponent.gameObject); if ((bool)base.inputBank && base.inputBank.skill3.justPressed) { EngiOtherShield engiOtherShield = new EngiOtherShield(); engiOtherShield.target = healthComponent.gameObject.GetComponent(); outer.SetNextState(engiOtherShield); return; } } else { indicator.targetTransform = null; } indicator.active = indicator.targetTransform; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class EngiTeamShield : BaseState { public static float duration = 3f; public static float radius; public override void OnEnter() { base.OnEnter(); if (!base.teamComponent || !NetworkServer.active) { return; } ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(base.teamComponent.teamIndex); float num = radius * radius; UnityEngine.Vector3 position = base.transform.position; for (int i = 0; i < teamMembers.Count; i++) { if (!((teamMembers[i].transform.position - position).sqrMagnitude <= num)) { continue; } CharacterBody component = teamMembers[i].GetComponent(); if ((bool)component) { component.AddTimedBuff(JunkContent.Buffs.EngiTeamShield, duration); HealthComponent component2 = component.GetComponent(); if ((bool)component2) { component2.RechargeShieldFull(); } } } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireConcussionBlast : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static int grenadeCountMax = 3; public static float damageCoefficient; public static float fireDuration = 1f; public static float baseDuration = 2f; public static float minSpread = 0f; public static float maxSpread = 5f; public static float recoilAmplitude = 1f; public static string attackSoundString; public static float force; public static float maxDistance; public static float radius; public static GameObject tracerEffectPrefab; private Ray aimRay; private Transform modelTransform; private float duration; private float fireTimer; private int grenadeCount; private void FireGrenade(string targetMuzzle) { Util.PlaySound(attackSoundString, base.gameObject); aimRay = GetAimRay(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { aimRay.origin = transform.position; } } } AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = targetMuzzle; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.maxDistance = maxDistance; bulletAttack.radius = radius; bulletAttack.stopperMask = 0; bulletAttack.Fire(); } } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelTransform = GetModelTransform(); aimRay = GetAimRay(); StartAimMode(aimRay); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } fireTimer -= GetDeltaTime(); float num = fireDuration / attackSpeedStat / (float)grenadeCountMax; if (fireTimer <= 0f && grenadeCount < grenadeCountMax) { fireTimer += num; if (grenadeCount % 2 == 0) { FireGrenade("MuzzleLeft"); PlayCrossfade("Gesture, Left Cannon", "FireGrenadeLeft", 0.1f); } else { FireGrenade("MuzzleRight"); PlayCrossfade("Gesture, Right Cannon", "FireGrenadeRight", 0.1f); } grenadeCount++; } if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireGrenades : BaseState { public static GameObject effectPrefab; public static GameObject projectilePrefab; public int grenadeCountMax = 3; public static float damageCoefficient; public static float fireDuration = 1f; public static float baseDuration = 2f; public static float arcAngle = 5f; public static float recoilAmplitude = 1f; public static string attackSoundString; public static float spreadBloomValue = 0.3f; private Ray projectileRay; private Transform modelTransform; private float duration; private float fireTimer; private int grenadeCount; private void FireGrenade(string targetMuzzle) { Util.PlaySound(attackSoundString, base.gameObject); projectileRay = GetAimRay(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { projectileRay.origin = transform.position; } } } AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { float x = UnityEngine.Random.Range(0f, base.characterBody.spreadBloomAngle); float z = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 up = UnityEngine.Vector3.up; UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, projectileRay.direction); UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward); float y = vector.y; vector.y = 0f; float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle; UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * projectileRay.direction); ProjectileManager.instance.FireProjectile(projectilePrefab, projectileRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelTransform = GetModelTransform(); StartAimMode(); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); fireTimer -= GetDeltaTime(); float num = fireDuration / attackSpeedStat / (float)grenadeCountMax; if (fireTimer <= 0f && grenadeCount < grenadeCountMax) { fireTimer += num; if (grenadeCount % 2 == 0) { FireGrenade("MuzzleLeft"); PlayCrossfade("Gesture Left Cannon, Additive", "FireGrenadeLeft", 0.1f); } else { FireGrenade("MuzzleRight"); PlayCrossfade("Gesture Right Cannon, Additive", "FireGrenadeRight", 0.1f); } grenadeCount++; } if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireMines : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; [SerializeField] public GameObject projectilePrefab; [SerializeField] public float damageCoefficient; [SerializeField] public float force; public static float baseDuration = 2f; public static string throwMineSoundString; private float duration; public override void OnEnter() { base.OnEnter(); Util.PlaySound(throwMineSoundString, base.gameObject); duration = baseDuration / attackSpeedStat; Ray aimRay = GetAimRay(); StartAimMode(aimRay); if ((bool)GetModelAnimator()) { float num = duration * 0.3f; PlayCrossfade("Gesture, Additive", "FireMineRight", "FireMine.playbackRate", duration + num, 0.05f); } string muzzleName = "MuzzleCenter"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireBubbleShield : FireMines { } public class FireWallShield : FireMines { } public class FireSeekerGrenades : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject projectilePrefab; public static int grenadeCountMax = 3; public static float damageCoefficient; public static float fireDuration = 1f; public static float baseDuration = 2f; public static float minSpread = 0f; public static float maxSpread = 5f; public static float arcAngle = 5f; public static float recoilAmplitude = 1f; public static string attackSoundString; private Ray aimRay; private Transform modelTransform; private float duration; private float fireTimer; private int grenadeCount; private void FireGrenade(string targetMuzzle) { Util.PlaySound(attackSoundString, base.gameObject); aimRay = GetAimRay(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { aimRay.origin = transform.position; } } } AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { float x = UnityEngine.Random.Range(minSpread, maxSpread); float z = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 up = UnityEngine.Vector3.up; UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction); UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward); float y = vector.y; vector.y = 0f; float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle; UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelTransform = GetModelTransform(); aimRay = GetAimRay(); StartAimMode(aimRay); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } fireTimer -= GetDeltaTime(); float num = fireDuration / attackSpeedStat / (float)grenadeCountMax; if (fireTimer <= 0f && grenadeCount < grenadeCountMax) { fireTimer += num; if (grenadeCount % 2 == 0) { FireGrenade("MuzzleLeft"); PlayCrossfade("Gesture, Left Cannon", "FireGrenadeLeft", 0.1f); } else { FireGrenade("MuzzleRight"); PlayCrossfade("Gesture, Right Cannon", "FireGrenadeRight", 0.1f); } grenadeCount++; } if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireSpiderMine : FireMines { } public class PlaceTurret : BaseState { private struct PlacementInfo { public bool ok; public UnityEngine.Vector3 position; public UnityEngine.Quaternion rotation; } [SerializeField] public GameObject wristDisplayPrefab; [SerializeField] public string placeSoundString; [SerializeField] public GameObject blueprintPrefab; [SerializeField] public GameObject turretMasterPrefab; private const float placementMaxUp = 1f; private const float placementMaxDown = 3f; private const float placementForwardDistance = 2f; private const float entryDelay = 0.1f; private const float exitDelay = 0.25f; private const float turretRadius = 0.5f; private const float turretHeight = 1.82f; private const float turretCenter = 0f; private const float turretModelYOffset = -0.75f; private GameObject wristDisplayObject; private BlueprintController blueprints; private float exitCountdown; private bool exitPending; private float entryCountdown; private static int PrepTurretStateHash = Animator.StringToHash("PrepTurret"); private static int PlaceTurretStateHash = Animator.StringToHash("PlaceTurret"); private PlacementInfo currentPlacementInfo; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { currentPlacementInfo = GetPlacementInfo(); blueprints = UnityEngine.Object.Instantiate(blueprintPrefab, currentPlacementInfo.position, currentPlacementInfo.rotation).GetComponent(); } PlayAnimation("Gesture", PrepTurretStateHash); entryCountdown = 0.1f; exitCountdown = 0.25f; exitPending = false; if (!base.modelLocator) { return; } ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("WristDisplay"); if ((bool)transform) { wristDisplayObject = UnityEngine.Object.Instantiate(wristDisplayPrefab, transform); } } } private PlacementInfo GetPlacementInfo() { Ray aimRay = GetAimRay(); UnityEngine.Vector3 direction = aimRay.direction; direction.y = 0f; direction.Normalize(); aimRay.direction = direction; PlacementInfo result = default(PlacementInfo); result.ok = false; result.rotation = Util.QuaternionSafeLookRotation(-direction); Ray ray = new Ray(aimRay.GetPoint(2f) + UnityEngine.Vector3.up * 1f, UnityEngine.Vector3.down); float num = 4f; float num2 = num; if (Physics.SphereCast(ray, 0.5f, out var hitInfo, num, LayerIndex.world.mask) && hitInfo.normal.y > 0.5f) { num2 = hitInfo.distance; result.ok = true; } UnityEngine.Vector3 point = ray.GetPoint(num2 + 0.5f); result.position = point; if (result.ok) { float num3 = Mathf.Max(1.82f, 0f); if (Physics.CheckCapsule(result.position + UnityEngine.Vector3.up * (num3 - 0.5f), result.position + UnityEngine.Vector3.up * 0.5f, 0.45f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault)) { result.ok = false; } } return result; } private void DestroyBlueprints() { if ((bool)blueprints) { EntityState.Destroy(blueprints.gameObject); blueprints = null; } } public override void OnExit() { base.OnExit(); PlayAnimation("Gesture", PlaceTurretStateHash); if ((bool)wristDisplayObject) { EntityState.Destroy(wristDisplayObject); } DestroyBlueprints(); } public override void Update() { base.Update(); currentPlacementInfo = GetPlacementInfo(); if ((bool)blueprints) { blueprints.PushState(currentPlacementInfo.position, currentPlacementInfo.rotation, currentPlacementInfo.ok); } } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } entryCountdown -= GetDeltaTime(); if (exitPending) { exitCountdown -= GetDeltaTime(); if (exitCountdown <= 0f) { outer.SetNextStateToMain(); } } else { if (!base.inputBank || !(entryCountdown <= 0f)) { return; } if ((base.inputBank.skill1.down || base.inputBank.skill4.justPressed) && currentPlacementInfo.ok) { if ((bool)base.characterBody) { base.characterBody.SendConstructTurret(base.characterBody, currentPlacementInfo.position, currentPlacementInfo.rotation, MasterCatalog.FindMasterIndex(turretMasterPrefab)); if ((bool)base.skillLocator) { GenericSkill skill = base.skillLocator.GetSkill(SkillSlot.Special); if ((bool)skill) { skill.DeductStock(1); } } } Util.PlaySound(placeSoundString, base.gameObject); DestroyBlueprints(); exitPending = true; } if (base.inputBank.skill2.justPressed) { DestroyBlueprints(); exitPending = true; } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class PlaceWalkerTurret : PlaceTurret { } public class ThrowMineDeployer : AimThrowableBase { } } namespace EntityStates.Engi.EngiMissilePainter { public class BaseEngiMissilePainterState : BaseSkillState { public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class Startup : BaseEngiMissilePainterState { public static float baseDuration; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && duration <= base.fixedAge) { outer.SetNextState(new Paint()); } } } public class Paint : BaseEngiMissilePainterState { private struct IndicatorInfo { public int refCount; public EngiMissileIndicator indicator; } private class EngiMissileIndicator : Indicator { public int missileCount; public override void UpdateVisualizer() { base.UpdateVisualizer(); Transform transform = base.visualizerTransform.Find("DotOrigin"); for (int num = transform.childCount - 1; num >= missileCount; num--) { EntityState.Destroy(transform.GetChild(num)); } for (int i = transform.childCount; i < missileCount; i++) { GameObject gameObject = UnityEngine.Object.Instantiate(base.visualizerPrefab.transform.Find("DotOrigin/DotTemplate").gameObject, transform); FindRenderers(gameObject.transform); } if (transform.childCount > 0) { float num2 = 360f / (float)transform.childCount; float num3 = (float)(transform.childCount - 1) * 90f; for (int j = 0; j < transform.childCount; j++) { Transform child = transform.GetChild(j); child.gameObject.SetActive(value: true); child.localRotation = UnityEngine.Quaternion.Euler(0f, 0f, num3 + (float)j * num2); } } } public EngiMissileIndicator(GameObject owner, GameObject visualizerPrefab) : base(owner, visualizerPrefab) { } } public static GameObject crosshairOverridePrefab; public static GameObject stickyTargetIndicatorPrefab; public static float stackInterval; public static string enterSoundString; public static string exitSoundString; public static string loopSoundString; public static string lockOnSoundString; public static string stopLoopSoundString; public static float maxAngle; public static float maxDistance; private List targetsList; private Dictionary targetIndicators; private Indicator stickyTargetIndicator; private SkillDef engiConfirmTargetDummySkillDef; private SkillDef engiCancelTargetingDummySkillDef; private bool releasedKeyOnce; private float stackStopwatch; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private BullseyeSearch search; private bool queuedFiringState; private uint loopSoundID; private HealthComponent previousHighlightTargetHealthComponent; private HurtBox previousHighlightTargetHurtBox; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { targetsList = new List(); targetIndicators = new Dictionary(); stickyTargetIndicator = new Indicator(base.gameObject, stickyTargetIndicatorPrefab); search = new BullseyeSearch(); } PlayCrossfade("Gesture, Additive", "PrepHarpoons", 0.1f); Util.PlaySound(enterSoundString, base.gameObject); loopSoundID = Util.PlaySound(loopSoundString, base.gameObject); if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } engiConfirmTargetDummySkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("EngiConfirmTargetDummy")); engiCancelTargetingDummySkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("EngiCancelTargetingDummy")); base.skillLocator.primary.SetSkillOverride(this, engiConfirmTargetDummySkillDef, GenericSkill.SkillOverridePriority.Contextual); base.skillLocator.secondary.SetSkillOverride(this, engiCancelTargetingDummySkillDef, GenericSkill.SkillOverridePriority.Contextual); } public override void OnExit() { if (base.isAuthority && !outer.destroying && !queuedFiringState) { for (int i = 0; i < targetsList.Count; i++) { base.activatorSkillSlot.AddOneStock(); } } base.skillLocator.secondary.UnsetSkillOverride(this, engiCancelTargetingDummySkillDef, GenericSkill.SkillOverridePriority.Contextual); base.skillLocator.primary.UnsetSkillOverride(this, engiConfirmTargetDummySkillDef, GenericSkill.SkillOverridePriority.Contextual); if (targetIndicators != null) { foreach (KeyValuePair targetIndicator in targetIndicators) { targetIndicator.Value.indicator.active = false; } } if (stickyTargetIndicator != null) { stickyTargetIndicator.active = false; } crosshairOverrideRequest?.Dispose(); PlayCrossfade("Gesture, Additive", "ExitHarpoons", 0.1f); Util.PlaySound(exitSoundString, base.gameObject); Util.PlaySound(stopLoopSoundString, base.gameObject); base.OnExit(); } private void AddTargetAuthority(HurtBox hurtBox) { if (base.activatorSkillSlot.stock != 0) { Util.PlaySound(lockOnSoundString, base.gameObject); targetsList.Add(hurtBox); if (!targetIndicators.TryGetValue(hurtBox, out var value)) { IndicatorInfo indicatorInfo = default(IndicatorInfo); indicatorInfo.refCount = 0; indicatorInfo.indicator = new EngiMissileIndicator(base.gameObject, LegacyResourcesAPI.Load("Prefabs/EngiMissileTrackingIndicator")); value = indicatorInfo; value.indicator.targetTransform = hurtBox.transform; value.indicator.active = true; } value.refCount++; value.indicator.missileCount = value.refCount; targetIndicators[hurtBox] = value; base.activatorSkillSlot.DeductStock(1); } } private void RemoveTargetAtAuthority(int i) { HurtBox key = targetsList[i]; targetsList.RemoveAt(i); if (targetIndicators.TryGetValue(key, out var value)) { value.refCount--; value.indicator.missileCount = value.refCount; targetIndicators[key] = value; if (value.refCount == 0) { value.indicator.active = false; targetIndicators.Remove(key); } } } private void CleanTargetsList() { for (int num = targetsList.Count - 1; num >= 0; num--) { HurtBox hurtBox = targetsList[num]; if (!hurtBox.healthComponent || !hurtBox.healthComponent.alive) { RemoveTargetAtAuthority(num); base.activatorSkillSlot.AddOneStock(); } } for (int num2 = targetsList.Count - 1; num2 >= base.activatorSkillSlot.maxStock; num2--) { RemoveTargetAtAuthority(num2); } } public override void FixedUpdate() { base.FixedUpdate(); base.characterBody.SetAimTimer(3f); if (base.isAuthority) { AuthorityFixedUpdate(); } } private void GetCurrentTargetInfo(out HurtBox currentTargetHurtBox, out HealthComponent currentTargetHealthComponent) { Ray aimRay = GetAimRay(); search.filterByDistinctEntity = true; search.filterByLoS = true; search.minDistanceFilter = 0f; search.maxDistanceFilter = maxDistance; search.minAngleFilter = 0f; search.maxAngleFilter = maxAngle; search.viewer = base.characterBody; search.searchOrigin = aimRay.origin; search.searchDirection = aimRay.direction; search.sortMode = BullseyeSearch.SortMode.DistanceAndAngle; search.teamMaskFilter = TeamMask.GetUnprotectedTeams(GetTeam()); search.RefreshCandidates(); search.FilterOutGameObject(base.gameObject); foreach (HurtBox result in search.GetResults()) { if ((bool)result.healthComponent && result.healthComponent.alive) { currentTargetHurtBox = result; currentTargetHealthComponent = result.healthComponent; return; } } currentTargetHurtBox = null; currentTargetHealthComponent = null; } private void AuthorityFixedUpdate() { CleanTargetsList(); bool flag = false; GetCurrentTargetInfo(out var currentTargetHurtBox, out var currentTargetHealthComponent); if ((bool)currentTargetHurtBox) { stackStopwatch += GetDeltaTime(); if (base.inputBank.skill1.down && (previousHighlightTargetHealthComponent != currentTargetHealthComponent || stackStopwatch > stackInterval / attackSpeedStat || base.inputBank.skill1.justPressed)) { stackStopwatch = 0f; AddTargetAuthority(currentTargetHurtBox); } } if (base.inputBank.skill1.justReleased) { flag = true; } if (base.inputBank.skill2.justReleased) { outer.SetNextStateToMain(); return; } if (base.inputBank.skill3.justReleased) { if (releasedKeyOnce) { flag = true; } releasedKeyOnce = true; } if ((object)currentTargetHurtBox != previousHighlightTargetHurtBox) { previousHighlightTargetHurtBox = currentTargetHurtBox; previousHighlightTargetHealthComponent = currentTargetHealthComponent; stickyTargetIndicator.targetTransform = (((bool)currentTargetHurtBox && base.activatorSkillSlot.stock != 0) ? currentTargetHurtBox.transform : null); stackStopwatch = 0f; } stickyTargetIndicator.active = stickyTargetIndicator.targetTransform; if (flag) { queuedFiringState = true; outer.SetNextState(new Fire { targetsList = targetsList, activatorSkillSlot = base.activatorSkillSlot }); } } } public class Fire : BaseEngiMissilePainterState { public static float baseDurationPerMissile; public static float damageCoefficient; public static GameObject projectilePrefab; public static GameObject muzzleflashEffectPrefab; public List targetsList; private int fireIndex; private float durationPerMissile; private float stopwatch; private static int IdleHarpoonsStateHash = Animator.StringToHash("IdleHarpoons"); private static int FireHarpoonStateHash = Animator.StringToHash("FireHarpoon"); public override void OnEnter() { base.OnEnter(); durationPerMissile = baseDurationPerMissile / attackSpeedStat; PlayAnimation("Gesture, Additive", IdleHarpoonsStateHash); } public override void FixedUpdate() { base.FixedUpdate(); bool flag = false; if (base.isAuthority) { stopwatch += GetDeltaTime(); if (stopwatch >= durationPerMissile) { stopwatch -= durationPerMissile; while (fireIndex < targetsList.Count) { HurtBox hurtBox = targetsList[fireIndex++]; if (!hurtBox.healthComponent || !hurtBox.healthComponent.alive) { base.activatorSkillSlot.AddOneStock(); continue; } string text = ((fireIndex % 2 == 0) ? "MuzzleLeft" : "MuzzleRight"); UnityEngine.Vector3 position = base.inputBank.aimOrigin; Transform transform = FindModelChild(text); if (transform != null) { position = transform.position; } EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, text, transmit: true); FireMissile(hurtBox, position); flag = true; break; } if (fireIndex >= targetsList.Count) { outer.SetNextState(new Finish()); } } } if (flag) { PlayAnimation((fireIndex % 2 == 0) ? "Gesture Left Cannon, Additive" : "Gesture Right Cannon, Additive", FireHarpoonStateHash); } } private void FireMissile(HurtBox target, UnityEngine.Vector3 position) { MissileUtils.FireMissile(base.inputBank.aimOrigin, base.characterBody, default(ProcChainMask), target.gameObject, damageStat * damageCoefficient, RollCrit(), projectilePrefab, DamageColorIndex.Default, UnityEngine.Vector3.up, 0f, addMissileProc: false); } public override void OnExit() { base.OnExit(); PlayCrossfade("Gesture, Additive", "ExitHarpoons", 0.1f); } } public class Finish : BaseEngiMissilePainterState { public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { outer.SetNextState(new Idle()); } } } } namespace EntityStates.Engi.EngiWallShield { public class Undeployed : EntityStates.Engi.EngiBubbleShield.Undeployed { public override void OnEnter() { base.OnEnter(); } protected override void SetNextState() { UnityEngine.Vector3 forward = base.transform.forward; UnityEngine.Vector3 forward2 = new UnityEngine.Vector3(forward.x, 0f, forward.z); base.transform.forward = forward2; outer.SetNextState(new Deployed()); } } public class Deployed : EntityStates.Engi.EngiBubbleShield.Deployed { } } namespace EntityStates.Engi.EngiBubbleShield { public class Undeployed : EntityState { private ProjectileStickOnImpact projectileStickOnImpact; public override void OnEnter() { base.OnEnter(); ProjectileController component = GetComponent(); projectileStickOnImpact = GetComponent(); if (!NetworkServer.active || !component.owner) { return; } CharacterBody component2 = component.owner.GetComponent(); if ((bool)component2) { CharacterMaster master = component2.master; if ((bool)master) { master.AddDeployable(GetComponent(), DeployableSlot.EngiBubbleShield); } } } public override void FixedUpdate() { base.FixedUpdate(); if (projectileStickOnImpact.stuck && NetworkServer.active) { SetNextState(); } } protected virtual void SetNextState() { outer.SetNextState(new Deployed()); } } public class Deployed : EntityState { public static string childLocatorString; public static string initialSoundString; public static string destroySoundString; public static float delayToDeploy; public static float lifetime; [SerializeField] public GameObject destroyEffectPrefab; [SerializeField] public float destroyEffectRadius; private bool hasDeployed; public override void OnEnter() { base.OnEnter(); Util.PlaySound(initialSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (!hasDeployed && base.fixedAge >= delayToDeploy) { ChildLocator component = GetComponent(); if ((bool)component) { component.FindChild(childLocatorString).gameObject.SetActive(value: true); hasDeployed = true; } } if (base.fixedAge >= lifetime && NetworkServer.active) { EntityState.Destroy(base.gameObject); } } public override void OnExit() { base.OnExit(); EffectManager.SpawnEffect(destroyEffectPrefab, new EffectData { origin = base.transform.position, rotation = base.transform.rotation, scale = destroyEffectRadius }, transmit: false); Util.PlaySound(destroySoundString, base.gameObject); } } } namespace EntityStates.Duplicator { public class Duplicating : BaseState { public static float initialDelayDuration = 1f; public static float timeBetweenStartAndDropDroplet = 3f; public static string muzzleString; public static GameObject bakeEffectPrefab; public static GameObject releaseEffectPrefab; private GameObject bakeEffectInstance; private bool hasStartedCooking; private bool hasDroppedDroplet; private Transform muzzleTransform; private EffectManagerHelper _emh_bakeEffectInstance; private static int CookStateHash = Animator.StringToHash("Cook"); public override void Reset() { base.Reset(); bakeEffectInstance = null; hasStartedCooking = false; hasDroppedDroplet = false; muzzleTransform = null; _emh_bakeEffectInstance = null; } public override void OnEnter() { base.OnEnter(); ChildLocator component = GetModelTransform().GetComponent(); if ((bool)component) { muzzleTransform = component.FindChild(muzzleString); } } private void BeginCooking() { if (hasStartedCooking) { return; } hasStartedCooking = true; PlayAnimation("Body", CookStateHash); if ((bool)base.sfxLocator) { Util.PlaySound(base.sfxLocator.openSound, base.gameObject); } if ((bool)muzzleTransform) { if (!EffectManager.ShouldUsePooledEffect(bakeEffectPrefab)) { bakeEffectInstance = UnityEngine.Object.Instantiate(bakeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation); return; } _emh_bakeEffectInstance = EffectManager.GetAndActivatePooledEffect(bakeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation); bakeEffectInstance = _emh_bakeEffectInstance.gameObject; } } private void DropDroplet() { if (hasDroppedDroplet) { return; } hasDroppedDroplet = true; GetComponent().DropPickup(); if (!muzzleTransform) { return; } if ((bool)bakeEffectInstance) { if (_emh_bakeEffectInstance != null && _emh_bakeEffectInstance.OwningPool != null) { _emh_bakeEffectInstance.OwningPool.ReturnObject(_emh_bakeEffectInstance); } else { EntityState.Destroy(bakeEffectInstance); } _emh_bakeEffectInstance = null; bakeEffectInstance = null; } if ((bool)releaseEffectPrefab) { EffectManager.SimpleMuzzleFlash(releaseEffectPrefab, base.gameObject, muzzleString, transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= initialDelayDuration) { BeginCooking(); } if (base.fixedAge >= initialDelayDuration + timeBetweenStartAndDropDroplet) { DropDroplet(); } } } } namespace EntityStates.DroneWeaponsChainGun { public class AimChainGun : BaseDroneWeaponChainGunState { [SerializeField] public float minDuration; [SerializeField] public float maxEnemyDistanceToStartFiring; [SerializeField] public float searchRefreshSeconds; private BullseyeSearch enemyFinder; private float searchRefreshTimer; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { enemyFinder = new BullseyeSearch(); enemyFinder.teamMaskFilter = TeamMask.allButNeutral; enemyFinder.maxDistanceFilter = maxEnemyDistanceToStartFiring; enemyFinder.maxAngleFilter = float.MaxValue; enemyFinder.filterByLoS = true; enemyFinder.sortMode = BullseyeSearch.SortMode.Angle; if ((bool)bodyTeamComponent) { enemyFinder.teamMaskFilter.RemoveTeam(bodyTeamComponent.teamIndex); } } } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority || !(base.fixedAge > minDuration)) { return; } searchRefreshTimer -= GetDeltaTime(); if (!(searchRefreshTimer < 0f)) { return; } searchRefreshTimer = searchRefreshSeconds; Ray aimRay = GetAimRay(); enemyFinder.searchOrigin = aimRay.origin; enemyFinder.searchDirection = aimRay.direction; enemyFinder.RefreshCandidates(); using IEnumerator enumerator = enemyFinder.GetResults().GetEnumerator(); if (enumerator.MoveNext()) { HurtBox current = enumerator.Current; outer.SetNextState(new FireChainGun(current)); } } } public abstract class BaseDroneWeaponChainGunState : EntityState { private const string aimAnimatorChildName = "AimAnimator"; [SerializeField] public float pitchRangeMin; [SerializeField] public float pitchRangeMax; [SerializeField] public float yawRangeMin; [SerializeField] public float yawRangeMax; protected NetworkedBodyAttachment networkedBodyAttachment; protected GameObject bodyGameObject; protected CharacterBody body; protected List gunChildLocators; protected List gunAnimators; protected AimAnimator bodyAimAnimator; protected TeamComponent bodyTeamComponent; private bool linkedToDisplay; public override void OnEnter() { base.OnEnter(); networkedBodyAttachment = GetComponent(); if ((bool)networkedBodyAttachment) { bodyGameObject = networkedBodyAttachment.attachedBodyObject; body = networkedBodyAttachment.attachedBody; if ((bool)bodyGameObject && (bool)body) { ModelLocator component = body.GetComponent(); if ((bool)component) { bodyAimAnimator = component.modelTransform.GetComponent(); bodyTeamComponent = body.GetComponent(); } } } LinkToDisplay(); } private void LinkToDisplay() { if (linkedToDisplay) { return; } gunAnimators = new List(); gunChildLocators = new List(); if (!networkedBodyAttachment) { return; } bodyGameObject = networkedBodyAttachment.attachedBodyObject; body = networkedBodyAttachment.attachedBody; if (!bodyGameObject || !body) { return; } ModelLocator component = body.GetComponent(); if (!component || !component.modelTransform) { return; } bodyAimAnimator = component.modelTransform.GetComponent(); bodyTeamComponent = body.GetComponent(); CharacterModel component2 = component.modelTransform.GetComponent(); if (!component2) { return; } List itemDisplayObjects = component2.GetItemDisplayObjects(DLC1Content.Items.DroneWeaponsDisplay1.itemIndex); itemDisplayObjects.AddRange(component2.GetItemDisplayObjects(DLC1Content.Items.DroneWeaponsDisplay2.itemIndex)); foreach (GameObject item in itemDisplayObjects) { ChildLocator component3 = item.GetComponent(); if ((bool)component3) { gunChildLocators.Add(component3); Animator animator = component3.FindChildComponent("AimAnimator"); if ((bool)animator) { gunAnimators.Add(animator); } } } } public void PassDisplayLinks(List gunChildLocators, List gunAnimators) { if (!linkedToDisplay) { linkedToDisplay = true; this.gunAnimators = gunAnimators; this.gunChildLocators = gunChildLocators; } } public override void FixedUpdate() { base.FixedUpdate(); LinkToDisplay(); if (!bodyAimAnimator) { return; } foreach (Animator gunAnimator in gunAnimators) { bodyAimAnimator.UpdateAnimatorParameters(gunAnimator, pitchRangeMin, pitchRangeMax, yawRangeMin, yawRangeMax); } } protected Transform FindChild(string childName) { foreach (ChildLocator gunChildLocator in gunChildLocators) { Transform transform = gunChildLocator.FindChild(childName); if ((bool)transform) { return transform; } } return null; } protected Ray GetAimRay() { if ((bool)body.inputBank) { return new Ray(body.inputBank.aimOrigin, body.inputBank.aimDirection); } return new Ray(base.transform.position, base.transform.forward); } } public class FireChainGun : BaseDroneWeaponChainGunState { [SerializeField] public float baseDuration; [SerializeField] public GameObject orbEffectObject; [SerializeField] public float damageCoefficient; [SerializeField] public float orbSpeed; [SerializeField] public int shotCount; [SerializeField] public float procCoefficient; [SerializeField] public int additionalBounces; [SerializeField] public float bounceRange; [SerializeField] public float damageCoefficientPerBounce; [SerializeField] public int targetsToFindPerBounce; [SerializeField] public bool canBounceOnSameTarget; [SerializeField] public string muzzleName; [SerializeField] public GameObject muzzleFlashPrefab; [SerializeField] public string fireSoundString; private HurtBox targetHurtBox; private float duration; private int stepIndex; public FireChainGun() { } public FireChainGun(HurtBox targetHurtBox) { this.targetHurtBox = targetHurtBox; } public override void OnEnter() { base.OnEnter(); Transform transform = FindChild(muzzleName); if (!transform) { transform = body.coreTransform; } if (base.isAuthority) { duration = baseDuration / body.attackSpeed; ChainGunOrb chainGunOrb = new ChainGunOrb(orbEffectObject); chainGunOrb.damageValue = body.damage * damageCoefficient; chainGunOrb.isCrit = Util.CheckRoll(body.crit, body.master); chainGunOrb.teamIndex = TeamComponent.GetObjectTeam(body.gameObject); chainGunOrb.attacker = body.gameObject; chainGunOrb.procCoefficient = procCoefficient; chainGunOrb.procChainMask = default(ProcChainMask); chainGunOrb.origin = transform.position; chainGunOrb.target = targetHurtBox; chainGunOrb.speed = orbSpeed; chainGunOrb.bouncesRemaining = additionalBounces; chainGunOrb.bounceRange = bounceRange; chainGunOrb.damageCoefficientPerBounce = damageCoefficientPerBounce; chainGunOrb.targetsToFindPerBounce = targetsToFindPerBounce; chainGunOrb.canBounceOnSameTarget = canBounceOnSameTarget; chainGunOrb.damageColorIndex = DamageColorIndex.Item; OrbManager.instance.AddOrb(chainGunOrb); } if ((bool)transform) { EffectData effectData = new EffectData { origin = transform.position }; EffectManager.SpawnEffect(muzzleFlashPrefab, effectData, transmit: true); } Util.PlaySound(fireSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { BaseDroneWeaponChainGunState baseDroneWeaponChainGunState; if (stepIndex < shotCount) { baseDroneWeaponChainGunState = new FireChainGun(targetHurtBox); (baseDroneWeaponChainGunState as FireChainGun).stepIndex = stepIndex + 1; } else { baseDroneWeaponChainGunState = new AimChainGun(); } baseDroneWeaponChainGunState.PassDisplayLinks(gunChildLocators, gunAnimators); outer.SetNextState(baseDroneWeaponChainGunState); } } } } namespace EntityStates.Turret1 { public class SpawnState : BaseState { public static float duration = 4f; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); if ((bool)GetModelAnimator()) { PlayAnimation("Body", SpawnStateHash, SpawnParamHash, 1.5f); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class DeathState : EntityStates.EngiTurret.DeathState { } } namespace EntityStates.Drone { public class DeathState : GenericCharacterDeath { public class RigidbodyCollisionListener : MonoBehaviour { public DeathState deathState; private void OnCollisionEnter(Collision collision) { deathState.OnImpactServer(collision.GetContact(0).point); deathState.Explode(); } } [SerializeField] public GameObject initialExplosionEffect; [SerializeField] public GameObject deathExplosionEffect; [SerializeField] public string initialSoundString; [SerializeField] public string deathSoundString; [SerializeField] public float deathEffectRadius; [SerializeField] public float forceAmount = 20f; [SerializeField] public float deathDuration = 2f; [SerializeField] public bool destroyOnImpact; private RigidbodyCollisionListener rigidbodyCollisionListener; public override void OnEnter() { base.OnEnter(); Util.PlaySound(initialSoundString, base.gameObject); if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.forcePID.enabled = false; base.rigidbodyMotor.rigid.useGravity = true; base.rigidbodyMotor.rigid.AddForce(UnityEngine.Vector3.up * forceAmount, ForceMode.Force); base.rigidbodyMotor.rigid.collisionDetectionMode = CollisionDetectionMode.Continuous; } if ((bool)base.rigidbodyDirection) { base.rigidbodyDirection.enabled = false; } if ((bool)initialExplosionEffect) { EffectManager.SpawnEffect(deathExplosionEffect, new EffectData { origin = base.characterBody.corePosition, scale = base.characterBody.radius + deathEffectRadius }, transmit: false); } if (base.isAuthority && destroyOnImpact) { rigidbodyCollisionListener = base.gameObject.AddComponent(); rigidbodyCollisionListener.deathState = this; } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge > deathDuration) { Explode(); } } public void Explode() { EntityState.Destroy(base.gameObject); } public virtual void OnImpactServer(UnityEngine.Vector3 contactPoint) { string bodyName = BodyCatalog.GetBodyName(base.characterBody.bodyIndex); bodyName = bodyName.Replace("Body", ""); bodyName = "iscBroken" + bodyName; SpawnCard spawnCard = LegacyResourcesAPI.Load("SpawnCards/InteractableSpawnCard/" + bodyName); if (!(spawnCard != null)) { return; } DirectorPlacementRule placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Direct, position = contactPoint }; GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, placementRule, new Xoroshiro128Plus(0uL))); if ((bool)gameObject) { PurchaseInteraction component = gameObject.GetComponent(); if ((bool)component && component.costType == CostTypeIndex.Money) { component.Networkcost = Run.instance.GetDifficultyScaledCost(component.cost); } } } public override void OnExit() { if ((bool)deathExplosionEffect) { EffectManager.SpawnEffect(deathExplosionEffect, new EffectData { origin = base.characterBody.corePosition, scale = base.characterBody.radius + deathEffectRadius }, transmit: false); } if ((bool)rigidbodyCollisionListener) { EntityState.Destroy(rigidbodyCollisionListener); } Util.PlaySound(deathSoundString, base.gameObject); base.OnExit(); } } public class MegaDroneDeathState : GenericCharacterDeath { public static string initialSoundString; public static GameObject initialEffect; public static float initialEffectScale; public static float velocityMagnitude; public static float explosionForce; public override void OnEnter() { if (NetworkServer.active) { EntityState.Destroy(base.gameObject); } } public override void OnExit() { base.OnExit(); Util.PlaySound(initialSoundString, base.gameObject); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform && NetworkServer.active) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { component.FindChild("LeftJet").gameObject.SetActive(value: false); component.FindChild("RightJet").gameObject.SetActive(value: false); if ((bool)initialEffect) { EffectManager.SpawnEffect(initialEffect, new EffectData { origin = base.transform.position, scale = initialEffectScale }, transmit: true); } } } Rigidbody component2 = GetComponent(); RagdollController component3 = modelTransform.GetComponent(); if ((bool)component3 && (bool)component2) { component3.BeginRagdoll(component2.velocity * velocityMagnitude); } ExplodeRigidbodiesOnStart component4 = modelTransform.GetComponent(); if ((bool)component4) { component4.force = explosionForce; component4.enabled = true; } } } } namespace EntityStates.Drone.DroneWeapon { public class FireGatling : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static float baseDuration = 2f; public static string fireGatlingSoundString; public int bulletCountCurrent = 1; private float duration; private static int FireGatlingStateHash = Animator.StringToHash("FireGatling"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; string muzzleName = "Muzzle"; Util.PlaySound(fireGatlingSoundString, base.gameObject); PlayAnimation("Gesture", FireGatlingStateHash); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { Ray aimRay = GetAimRay(); BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleName; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.Fire(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireMegaTurret : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static string attackSoundString; public static float attackSoundPlaybackCoefficient; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static int maxBulletCount; public static float baseTotalDuration; private Transform modelTransform; private ChildLocator childLocator; private float fireStopwatch; private float stopwatch; private float durationBetweenShots; private float totalDuration; private int bulletCount; private static int FireGatStateHash = Animator.StringToHash("FireGat"); public override void OnEnter() { base.OnEnter(); fireStopwatch = 0f; totalDuration = baseTotalDuration / attackSpeedStat; durationBetweenShots = totalDuration / (float)maxBulletCount; GetAimRay(); Transform transform = GetModelTransform(); if ((bool)transform) { childLocator = transform.GetComponent(); } } private void FireBullet(string muzzleString) { Ray aimRay = GetAimRay(); _ = aimRay.origin; Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPlaybackCoefficient); PlayAnimation("Gesture, Additive", FireGatStateHash); if ((bool)childLocator) { Transform transform = childLocator.FindChild(muzzleString); if ((bool)transform) { _ = transform.position; } } if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleString, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleString; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.Fire(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); fireStopwatch += deltaTime; stopwatch += deltaTime; if (fireStopwatch >= durationBetweenShots) { bulletCount++; fireStopwatch -= durationBetweenShots; FireBullet((bulletCount % 2 == 0) ? "GatLeft" : "GatRight"); } if (stopwatch >= totalDuration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireMissileBarrage : BaseState { public static GameObject effectPrefab; public static GameObject projectilePrefab; public static float damageCoefficient = 1f; public static float baseFireInterval = 0.1f; public static float minSpread = 0f; public static float maxSpread = 5f; public static int maxMissileCount; private float fireTimer; private float fireInterval; private Transform modelTransform; private AimAnimator aimAnimator; private int missileCount; private static int FireMissileStateHash = Animator.StringToHash("FireMissile"); private void FireMissile(string targetMuzzle) { missileCount++; PlayAnimation("Gesture, Additive", FireMissileStateHash); Ray aimRay = GetAimRay(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { aimRay.origin = transform.position; } } } if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } if (base.isAuthority) { float x = UnityEngine.Random.Range(minSpread, maxSpread); float z = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 up = UnityEngine.Vector3.up; UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction); UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward); float y = vector.y; vector.y = 0f; float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f; UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnEnter() { base.OnEnter(); modelTransform = GetModelTransform(); fireInterval = baseFireInterval / attackSpeedStat; } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); fireTimer -= GetDeltaTime(); if (fireTimer <= 0f) { FireMissile("Muzzle"); fireTimer += fireInterval; } if (missileCount >= maxMissileCount && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireTurret : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static string attackSoundString; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float durationBetweenShots = 1f; public static float baseDuration = 2f; public int bulletCountCurrent = 1; private float duration = 2f; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; string muzzleName = "Muzzle"; Util.PlaySound(attackSoundString, base.gameObject); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { Ray aimRay = GetAimRay(); BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleName; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.Fire(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= durationBetweenShots / attackSpeedStat && bulletCountCurrent < bulletCount && base.isAuthority) { FireTurret fireTurret = new FireTurret(); fireTurret.bulletCountCurrent = bulletCountCurrent + 1; outer.SetNextState(fireTurret); } else if (base.fixedAge >= duration && bulletCountCurrent >= bulletCount && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireTwinRocket : BaseState { public static GameObject projectilePrefab; public static GameObject muzzleEffectPrefab; public static float damageCoefficient; public static float force; public static float baseDuration = 2f; private ChildLocator childLocator; private float stopwatch; private float duration; public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; GetAimRay(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); } FireProjectile("GatLeft"); FireProjectile("GatRight"); } public override void OnExit() { base.OnExit(); } private void FireProjectile(string muzzleString) { GetAimRay(); Transform transform = childLocator.FindChild(muzzleString); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (!base.isAuthority || !(projectilePrefab != null)) { return; } float maxDistance = 1000f; Ray aimRay = GetAimRay(); UnityEngine.Vector3 forward = aimRay.direction; UnityEngine.Vector3 position = aimRay.origin; if ((bool)transform) { position = transform.position; if (Physics.Raycast(aimRay, out var hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask)) { forward = hitInfo.point - transform.position; } } ProjectileManager.instance.FireProjectile(projectilePrefab, position, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration / attackSpeedStat && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class HealBeam : BaseState { public static float baseDuration; public static float healCoefficient = 5f; public static GameObject healBeamPrefab; public HurtBox target; private HealBeamController healBeamController; private float duration; private float lineWidthRefVelocity; public override void OnEnter() { base.OnEnter(); PlayCrossfade("Gesture", "Heal", 0.2f); duration = baseDuration / attackSpeedStat; float healRate = healCoefficient * damageStat / duration; Ray aimRay = GetAimRay(); Transform transform = FindModelChild("Muzzle"); if (NetworkServer.active) { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.none; if ((bool)base.teamComponent) { bullseyeSearch.teamMaskFilter.AddTeam(base.teamComponent.teamIndex); } bullseyeSearch.filterByLoS = false; bullseyeSearch.maxDistanceFilter = 50f; bullseyeSearch.maxAngleFilter = 180f; bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); target = bullseyeSearch.GetResults().FirstOrDefault(); if ((bool)transform && (bool)target) { GameObject gameObject = UnityEngine.Object.Instantiate(healBeamPrefab, transform); healBeamController = gameObject.GetComponent(); healBeamController.healRate = healRate; healBeamController.target = target; healBeamController.ownership.ownerObject = base.gameObject; NetworkServer.Spawn(gameObject); } } } public override void FixedUpdate() { base.FixedUpdate(); if ((base.fixedAge >= duration || !target) && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { PlayCrossfade("Gesture", "Empty", 0.2f); if ((bool)healBeamController) { healBeamController.BreakServer(); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); HurtBoxReference.FromHurtBox(target).Write(writer); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); HurtBoxReference hurtBoxReference = default(HurtBoxReference); hurtBoxReference.Read(reader); target = hurtBoxReference.ResolveGameObject()?.GetComponent(); } } public class StartHealBeam : BaseState { [SerializeField] public float baseDuration; [SerializeField] public float targetSelectionRange; [SerializeField] public float healRateCoefficient; [SerializeField] public GameObject healBeamPrefab; [SerializeField] public string muzzleName; [SerializeField] public int maxSimultaneousBeams; private HurtBox targetHurtBox; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; if (base.isAuthority) { Ray aimRay = GetAimRay(); targetHurtBox = FindTarget(aimRay); } if (NetworkServer.active && HealBeamController.GetHealBeamCountForOwner(base.gameObject) < maxSimultaneousBeams && (bool)targetHurtBox) { Transform transform = FindModelChild(muzzleName); if ((bool)transform) { GameObject obj = UnityEngine.Object.Instantiate(healBeamPrefab, transform); HealBeamController component = obj.GetComponent(); component.healRate = healRateCoefficient * damageStat * attackSpeedStat; component.target = targetHurtBox; component.ownership.ownerObject = base.gameObject; obj.AddComponent().duration = duration; NetworkServer.Spawn(obj); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { outer.SetNextStateToMain(); } } private HurtBox FindTarget(Ray aimRay) { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.none; if ((bool)base.teamComponent) { bullseyeSearch.teamMaskFilter.AddTeam(base.teamComponent.teamIndex); } bullseyeSearch.filterByLoS = false; bullseyeSearch.maxDistanceFilter = targetSelectionRange; bullseyeSearch.maxAngleFilter = 180f; bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); return bullseyeSearch.GetResults().Where(NotAlreadyHealingTarget).Where(IsHurt) .FirstOrDefault(); } private bool NotAlreadyHealingTarget(HurtBox hurtBox) { return !HealBeamController.HealBeamAlreadyExists(base.gameObject, hurtBox); } private static bool IsHurt(HurtBox hurtBox) { if (hurtBox.healthComponent.alive) { return hurtBox.healthComponent.health < hurtBox.healthComponent.fullHealth; } return false; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(HurtBoxReference.FromHurtBox(targetHurtBox)); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); targetHurtBox = reader.ReadHurtBoxReference().ResolveHurtBox(); } } public class Flamethrower : EntityStates.Mage.Weapon.Flamethrower { } } namespace EntityStates.Destructible { public class AltarSkeletonDeath : BaseState { public static GameObject explosionEffectPrefab; public static float explosionRadius; public static string deathSoundString; private float stopwatch; public static event Action onDeath; public override void OnEnter() { base.OnEnter(); Util.PlaySound(deathSoundString, base.gameObject); Explode(); } public override void FixedUpdate() { base.FixedUpdate(); } private void Explode() { if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if ((bool)explosionEffectPrefab && NetworkServer.active) { EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = base.transform.position, scale = explosionRadius, rotation = UnityEngine.Quaternion.identity }, transmit: false); } AltarSkeletonDeath.onDeath?.Invoke(); EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class ExplosivePotDeath : BaseState { public static GameObject chargePrefab; [Tooltip("How long the object will wait before exploding")] public static float chargeDuration; public static GameObject explosionEffectPrefab; public static float explosionRadius; public static float explosionDamageCoefficient; public static float explosionProcCoefficient; public static float explosionForce; public override void OnEnter() { base.OnEnter(); if ((bool)chargePrefab) { UnityEngine.Object.Instantiate(chargePrefab, base.transform); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= chargeDuration) { Explode(); } } public virtual void Explode() { if ((bool)explosionEffectPrefab) { EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = base.transform.position, scale = explosionRadius, rotation = UnityEngine.Quaternion.identity }, transmit: true); } BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient; blastAttack.radius = explosionRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.procCoefficient = explosionProcCoefficient; blastAttack.teamIndex = TeamIndex.None; blastAttack.damageType = DamageType.ClayGoo; blastAttack.position = base.transform.position; blastAttack.baseForce = explosionForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class FusionCellDeath : BaseState { public static string chargeChildEffectName; public static float chargeDuration; public static GameObject explosionEffectPrefab; public static float explosionRadius; public static float explosionDamageCoefficient; public static float explosionProcCoefficient; public static float explosionForce; private float stopwatch; public override void OnEnter() { base.OnEnter(); ChildLocator component = GetModelTransform().GetComponent(); if ((bool)component) { Transform transform = component.FindChild(chargeChildEffectName); if ((bool)transform) { transform.gameObject.SetActive(value: true); } } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch > chargeDuration) { Explode(); } } private void Explode() { if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if ((bool)explosionEffectPrefab && NetworkServer.active) { EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = base.transform.position, scale = explosionRadius, rotation = UnityEngine.Quaternion.identity }, transmit: true); } BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient; blastAttack.radius = explosionRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.procCoefficient = explosionProcCoefficient; blastAttack.teamIndex = TeamIndex.None; blastAttack.position = base.transform.position; blastAttack.baseForce = explosionForce; blastAttack.bonusForce = explosionForce * 0.5f * UnityEngine.Vector3.up; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class GauntletShardDeath : BaseState { public static GameObject explosionEffectPrefab; public static float explosionRadius; public static float explosionDamageCoefficient; public static float explosionProcCoefficient; public static float explosionForce; private float stopwatch; public override void OnEnter() { base.OnEnter(); Explode(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); } private void Explode() { if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if ((bool)explosionEffectPrefab && NetworkServer.active) { EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = base.transform.position, scale = explosionRadius, rotation = UnityEngine.Quaternion.identity }, transmit: true); } BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient; blastAttack.radius = explosionRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.procCoefficient = explosionProcCoefficient; blastAttack.teamIndex = TeamIndex.None; blastAttack.position = base.transform.position; blastAttack.baseForce = explosionForce; blastAttack.bonusForce = explosionForce * 0.5f * UnityEngine.Vector3.up; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class SulfurPodDeath : GenericCharacterDeath { public static GameObject chargePrefab; public static float chargeDuration; public static GameObject explosionEffectPrefab; public static float explosionRadius; public static float explosionDamageCoefficient; public static float explosionProcCoefficient; public static float explosionForce; private bool hasExploded; public override void OnEnter() { base.OnEnter(); if ((bool)chargePrefab) { UnityEngine.Object.Instantiate(chargePrefab, base.transform); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= chargeDuration) { Explode(); } } private void Explode() { if (!hasExploded) { hasExploded = true; if ((bool)explosionEffectPrefab) { EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = base.transform.position, scale = explosionRadius, rotation = UnityEngine.Quaternion.identity }, transmit: true); } DestroyModel(); if (NetworkServer.active) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.damageColorIndex = DamageColorIndex.Poison; blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient; blastAttack.radius = explosionRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.procCoefficient = explosionProcCoefficient; blastAttack.teamIndex = TeamIndex.None; blastAttack.damageType = DamageType.PoisonOnHit; blastAttack.position = base.transform.position; blastAttack.baseForce = explosionForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); DestroyBodyAsapServer(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class TimeCrystalDeath : BaseState { public static GameObject explosionEffectPrefab; public static float explosionRadius; public static float explosionDamageCoefficient; public static float explosionProcCoefficient; public static float explosionForce; private float stopwatch; public override void OnEnter() { base.OnEnter(); Explode(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); } private void Explode() { if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if ((bool)explosionEffectPrefab && NetworkServer.active) { EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = base.transform.position, scale = explosionRadius, rotation = UnityEngine.Quaternion.identity }, transmit: true); } BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient; blastAttack.radius = explosionRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.procCoefficient = explosionProcCoefficient; blastAttack.teamIndex = TeamIndex.None; blastAttack.position = base.transform.position; blastAttack.baseForce = explosionForce; blastAttack.bonusForce = explosionForce * 0.5f * UnityEngine.Vector3.up; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class CorruptedSpikeDeath : BaseState { public static GameObject chargePrefab; public static float chargeDuration; public static GameObject explosionEffectPrefab; public static float explosionRadius; public static float explosionDamageCoefficient; public static float explosionProcCoefficient; public static float explosionForce; public override void OnEnter() { base.OnEnter(); if ((bool)chargePrefab) { UnityEngine.Object.Instantiate(chargePrefab, base.transform); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= chargeDuration) { Explode(); } } private void Explode() { if ((bool)explosionEffectPrefab) { EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = base.transform.position, scale = explosionRadius, rotation = UnityEngine.Quaternion.identity }, transmit: true); } BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.baseDamage = 1f; blastAttack.radius = explosionRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.procCoefficient = explosionProcCoefficient; blastAttack.teamIndex = TeamIndex.None; blastAttack.position = base.transform.position; blastAttack.baseForce = explosionForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class LunarRainDeathState : BaseState { public static GameObject chargePrefab; [Tooltip("How long the object will wait before exploding")] public static float chargeDuration; public static GameObject explosionEffectPrefab; public static float baseDamage; public static float explosionRadius; public static float explosionDamageCoefficient; public static float explosionProcCoefficient; public static float explosionForce; public static float vfxScale; public static bool canRejectForce; public override void OnEnter() { base.OnEnter(); if (base.teamComponent != null) { base.teamComponent.teamIndex = TeamIndex.Monster; } if ((bool)chargePrefab) { EffectData effectData = new EffectData { scale = explosionRadius, origin = base.transform.position }; EffectManager.SpawnEffect(chargePrefab, effectData, transmit: false); } FlashEmission component = base.modelLocator.modelTransform.GetComponent(); if ((bool)component) { component.StartFlash(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= chargeDuration && NetworkServer.active) { Explode(); } } public virtual void Explode() { if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if ((bool)explosionEffectPrefab) { EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData { origin = base.transform.position, scale = vfxScale, rotation = base.transform.rotation }, transmit: true); } BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.baseDamage = baseDamage * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient; blastAttack.radius = explosionRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.procCoefficient = explosionProcCoefficient; blastAttack.teamIndex = TeamIndex.Monster; blastAttack.damageType = DamageType.LunarRuin; blastAttack.position = base.transform.position; blastAttack.baseForce = explosionForce; blastAttack.canRejectForce = canRejectForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.DeepVoidPortalBattery { public class BaseDeepVoidPortalBatteryState : BaseState { [SerializeField] public string onEnterSoundString; [SerializeField] public string onEnterChildToEnable; [SerializeField] public string animationStateName; public override void OnEnter() { base.OnEnter(); Util.PlaySound(onEnterSoundString, base.gameObject); GameObject gameObject = FindModelChildGameObject(onEnterChildToEnable); if ((bool)gameObject) { gameObject.SetActive(value: true); } PlayAnimation("Base", animationStateName); } public override void OnExit() { GameObject gameObject = FindModelChildGameObject(onEnterChildToEnable); if ((bool)gameObject) { gameObject.SetActive(value: false); } base.OnExit(); } } public class Idle : BaseDeepVoidPortalBatteryState { } public class Charging : BaseDeepVoidPortalBatteryState { [SerializeField] public GameObject chargingPositionIndicator; private CombatDirector combatDirector; private HoldoutZoneController holdoutZoneController; private VoidStageMissionController.FogRequest fogRequest; private ChargeIndicatorController chargeIndicatorController; public override void OnEnter() { base.OnEnter(); holdoutZoneController = GetComponent(); if ((bool)holdoutZoneController) { holdoutZoneController.enabled = true; } Transform targetTransform = FindModelChild("PositionIndicatorPosition").transform; PositionIndicator component = UnityEngine.Object.Instantiate(chargingPositionIndicator, base.transform.position, UnityEngine.Quaternion.identity).GetComponent(); component.targetTransform = targetTransform; chargeIndicatorController = component.GetComponent(); chargeIndicatorController.holdoutZoneController = holdoutZoneController; if (NetworkServer.active) { combatDirector = GetComponent(); if ((bool)combatDirector) { combatDirector.enabled = true; combatDirector.SetNextSpawnAsBoss(); } if ((bool)holdoutZoneController && (bool)VoidStageMissionController.instance) { fogRequest = VoidStageMissionController.instance.RequestFog(holdoutZoneController); } } } public override void OnExit() { if ((bool)chargeIndicatorController) { EntityState.Destroy(chargeIndicatorController.gameObject); } if ((bool)holdoutZoneController) { holdoutZoneController.enabled = false; } if (NetworkServer.active) { if ((bool)combatDirector) { combatDirector.enabled = false; } fogRequest?.Dispose(); fogRequest = null; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && holdoutZoneController.charge >= 1f) { outer.SetNextState(new Charged()); } } } public class Charged : BaseDeepVoidPortalBatteryState { public override void OnEnter() { base.OnEnter(); if ((bool)VoidStageMissionController.instance && NetworkServer.active) { VoidStageMissionController.instance.OnBatteryActivated(); } } } } namespace EntityStates.Croco { public class Bite : BasicMeleeAttack { public static float recoilAmplitude; public static float baseDurationBeforeInterruptable; [SerializeField] public float bloom; public static string biteSound; private string animationStateName; private float durationBeforeInterruptable; private CrocoDamageTypeController crocoDamageTypeController; private bool hasGrantedBuff; protected override bool allowExitFire { get { if ((bool)base.characterBody) { return !base.characterBody.isSprinting; } return false; } } public override void OnEnter() { base.OnEnter(); base.characterDirection.forward = GetAimRay().direction; durationBeforeInterruptable = baseDurationBeforeInterruptable / attackSpeedStat; crocoDamageTypeController = GetComponent(); } public override void OnExit() { base.OnExit(); } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); DamageTypeCombo damageTypeCombo = (crocoDamageTypeController ? crocoDamageTypeController.GetDamageType() : DamageTypeCombo.Generic); overlapAttack.damageType = damageTypeCombo | DamageType.BonusToLowHealth; } protected override void PlayAnimation() { float num = Mathf.Max(duration, 0.2f); PlayCrossfade("Gesture, Additive", "Bite", "Bite.playbackRate", num, 0.05f); PlayCrossfade("Gesture, Override", "Bite", "Bite.playbackRate", num, 0.05f); Util.PlaySound(biteSound, base.gameObject); } protected override void OnMeleeHitAuthority() { base.OnMeleeHitAuthority(); base.characterBody.AddSpreadBloom(bloom); if (!hasGrantedBuff) { hasGrantedBuff = true; base.characterBody.AddTimedBuffAuthority(RoR2Content.Buffs.CrocoRegen.buffIndex, 0.5f); } } protected override void BeginMeleeAttackEffect() { AddRecoil(0.9f * recoilAmplitude, 1.1f * recoilAmplitude, -0.1f * recoilAmplitude, 0.1f * recoilAmplitude); base.BeginMeleeAttackEffect(); } public override InterruptPriority GetMinimumInterruptPriority() { if (!(base.fixedAge < durationBeforeInterruptable)) { return InterruptPriority.Skill; } return InterruptPriority.Pain; } } public class Disease : BaseState { public static GameObject muzzleflashEffectPrefab; public static string muzzleString; public static float orbRange; public static float baseDuration; public static float damageCoefficient; public static int maxBounces; public static float bounceRange; public static float procCoefficient; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Ray aimRay = GetAimRay(); Transform transform = FindModelChild(muzzleString); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.maxDistanceFilter = orbRange; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; bullseyeSearch.teamMaskFilter.RemoveTeam(TeamComponent.GetObjectTeam(base.gameObject)); bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle; bullseyeSearch.RefreshCandidates(); EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true); List list = bullseyeSearch.GetResults().ToList(); if (list.Count > 0) { UnityEngine.Debug.LogFormat("Shooting at {0}", list[0]); HurtBox target = list.FirstOrDefault(); LightningOrb lightningOrb = new LightningOrb(); lightningOrb.attacker = base.gameObject; lightningOrb.bouncedObjects = new List(); lightningOrb.lightningType = LightningOrb.LightningType.CrocoDisease; lightningOrb.damageType = DamageType.PoisonOnHit; lightningOrb.damageValue = damageStat * damageCoefficient; lightningOrb.isCrit = RollCrit(); lightningOrb.procCoefficient = procCoefficient; lightningOrb.bouncesRemaining = maxBounces; lightningOrb.origin = transform.position; lightningOrb.target = target; lightningOrb.teamIndex = GetTeam(); lightningOrb.range = bounceRange; OrbManager.instance.AddOrb(lightningOrb); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class FireSpit : BaseState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject effectPrefab; [SerializeField] public float baseDuration = 2f; [SerializeField] public float damageCoefficient = 1.2f; [SerializeField] public float force = 20f; [SerializeField] public string attackString; [SerializeField] public float recoilAmplitude; [SerializeField] public float bloom; private float duration; private CrocoDamageTypeController crocoDamageTypeController; private static int FireSpitStateHash = Animator.StringToHash("FireSpit"); private static int FireSpitParamHash = Animator.StringToHash("FireSpit.playbackRate"); public override void OnEnter() { base.OnEnter(); crocoDamageTypeController = GetComponent(); Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); duration = baseDuration / attackSpeedStat; StartAimMode(duration + 2f); PlayAnimation("Gesture, Mouth", FireSpitStateHash, FireSpitParamHash, duration); Util.PlaySound(attackString, base.gameObject); AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude); base.characterBody.AddSpreadBloom(bloom); string muzzleName = "MouthMuzzle"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { DamageTypeCombo value = (crocoDamageTypeController ? crocoDamageTypeController.GetDamageType() : DamageTypeCombo.Generic); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = ray.origin; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.damageTypeOverride = value; fireProjectileInfo.force = force; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireDiseaseProjectile : FireSpit { } public class BaseLeap : BaseCharacterMain { public static float minimumDuration; public static float blastRadius; public static float blastProcCoefficient; [SerializeField] public float blastDamageCoefficient; [SerializeField] public float blastForce; public static string leapSoundString; public static GameObject projectilePrefab; [SerializeField] public UnityEngine.Vector3 blastBonusForce; [SerializeField] public GameObject blastImpactEffectPrefab; [SerializeField] public GameObject blastEffectPrefab; public static float airControl; public static float aimVelocity; public static float upwardVelocity; public static float forwardVelocity; public static float minimumY; public static float minYVelocityForAnim; public static float maxYVelocityForAnim; public static float knockbackForce; [SerializeField] public GameObject fistEffectPrefab; public static string soundLoopStartEvent; public static string soundLoopStopEvent; public static NetworkSoundEventDef landingSound; private float previousAirControl; private GameObject leftFistEffectInstance; private GameObject rightFistEffectInstance; protected bool isCritAuthority; protected CrocoDamageTypeController crocoDamageTypeController; private bool detonateNextFrame; private static int LightImpactStateHash = Animator.StringToHash("LightImpact"); private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty"); protected virtual DamageTypeCombo GetBlastDamageType() { return DamageType.Generic; } public override void OnEnter() { base.OnEnter(); crocoDamageTypeController = GetComponent(); previousAirControl = base.characterMotor.airControl; base.characterMotor.airControl = airControl; UnityEngine.Vector3 direction = GetAimRay().direction; if (base.isAuthority) { base.characterBody.isSprinting = true; direction.y = Mathf.Max(direction.y, minimumY); UnityEngine.Vector3 vector = direction.normalized * aimVelocity * moveSpeedStat; UnityEngine.Vector3 vector2 = UnityEngine.Vector3.up * upwardVelocity; UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(direction.x, 0f, direction.z).normalized * forwardVelocity; base.characterMotor.Motor.ForceUnground(); base.characterMotor.velocity = vector + vector2 + vector3; isCritAuthority = RollCrit(); } base.characterBody.bodyFlags |= CharacterBody.BodyFlags.IgnoreFallDamage; GetModelTransform().GetComponent().enabled = true; PlayCrossfade("Gesture, Override", "Leap", 0.1f); PlayCrossfade("Gesture, AdditiveHigh", "Leap", 0.1f); PlayCrossfade("Gesture, Override", "Leap", 0.1f); Util.PlaySound(leapSoundString, base.gameObject); base.characterDirection.moveVector = direction; leftFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("MuzzleHandL")); rightFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("MuzzleHandR")); if (base.isAuthority) { base.characterMotor.onMovementHit += OnMovementHit; } Util.PlaySound(soundLoopStartEvent, base.gameObject); } private void OnMovementHit(ref CharacterMotor.MovementHitInfo movementHitInfo) { detonateNextFrame = true; } private void onHitGroundServer(ref CharacterMotor.HitGroundInfo hitGroundInfo) { detonateNextFrame = true; } protected override void UpdateAnimationParameters() { base.UpdateAnimationParameters(); float value = Mathf.Clamp01(Util.Remap(base.estimatedVelocity.y, minYVelocityForAnim, maxYVelocityForAnim, 0f, 1f)) * 0.97f; base.modelAnimator.SetFloat("LeapCycle", value, 0.1f, Time.deltaTime); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && (bool)base.characterMotor) { base.characterMotor.moveDirection = base.inputBank.moveVector; if (base.fixedAge >= minimumDuration && (detonateNextFrame || (base.characterMotor.Motor.GroundingStatus.IsStableOnGround && !base.characterMotor.Motor.LastGroundingStatus.IsStableOnGround))) { DoImpactAuthority(); outer.SetNextStateToMain(); } } } protected virtual void DoImpactAuthority() { if ((bool)landingSound) { EffectManager.SimpleSoundEffect(landingSound.index, base.characterBody.footPosition, transmit: true); } } protected BlastAttack.Result DetonateAuthority() { UnityEngine.Vector3 footPosition = base.characterBody.footPosition; EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = footPosition, scale = blastRadius }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * blastDamageCoefficient, baseForce = blastForce, bonusForce = blastBonusForce, crit = isCritAuthority, damageType = GetBlastDamageType(), falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius, position = footPosition, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } protected void DropAcidPoolAuthority() { UnityEngine.Vector3 footPosition = base.characterBody.footPosition; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.crit = isCritAuthority; fireProjectileInfo.force = 0f; fireProjectileInfo.damage = damageStat; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; fireProjectileInfo.position = footPosition; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } public override void OnExit() { Util.PlaySound(soundLoopStopEvent, base.gameObject); if (base.isAuthority) { base.characterMotor.onMovementHit -= OnMovementHit; } base.characterBody.bodyFlags &= ~CharacterBody.BodyFlags.IgnoreFallDamage; base.characterMotor.airControl = previousAirControl; base.characterBody.isSprinting = false; int layerIndex = base.modelAnimator.GetLayerIndex("Impact"); if (layerIndex >= 0) { base.modelAnimator.SetLayerWeight(layerIndex, 2f); PlayAnimation("Impact", LightImpactStateHash); } PlayCrossfade("Gesture, Override", BufferEmptyStateHash, 0.1f); PlayCrossfade("Gesture, AdditiveHigh", BufferEmptyStateHash, 0.1f); EntityState.Destroy(leftFistEffectInstance); EntityState.Destroy(rightFistEffectInstance); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class Leap : BaseLeap { protected override DamageTypeCombo GetBlastDamageType() { return (crocoDamageTypeController ? crocoDamageTypeController.GetDamageType() : DamageTypeCombo.Generic) | DamageType.Stun1s; } protected override void DoImpactAuthority() { base.DoImpactAuthority(); DetonateAuthority(); DropAcidPoolAuthority(); } } public class ChainableLeap : BaseLeap { public static float refundPerHit; protected override DamageTypeCombo GetBlastDamageType() { return DamageType.Stun1s; } protected override void DoImpactAuthority() { base.DoImpactAuthority(); BlastAttack.Result result = DetonateAuthority(); base.skillLocator.utility.RunRecharge((float)result.hitCount * refundPerHit); } } public class Slash : BasicMeleeAttack, SteppedSkillDef.IStepSetter { public int step; public static float recoilAmplitude; public static float baseDurationBeforeInterruptable; [SerializeField] public float bloom; public static GameObject comboFinisherSwingEffectPrefab; public static float comboFinisherhitPauseDuration; public static float comboFinisherDamageCoefficient; public static float comboFinisherBloom; public static float comboFinisherBaseDurationBeforeInterruptable; public static string slash1Sound; public static string slash3Sound; private string animationStateName; private float durationBeforeInterruptable; private bool hasGrantedBuff; private bool isComboFinisher => step == 2; protected override bool allowExitFire { get { if ((bool)base.characterBody) { return !base.characterBody.isSprinting; } return false; } } void SteppedSkillDef.IStepSetter.SetStep(int i) { step = i; } public override void OnEnter() { if (isComboFinisher) { swingEffectPrefab = comboFinisherSwingEffectPrefab; hitPauseDuration = comboFinisherhitPauseDuration; damageCoefficient = comboFinisherDamageCoefficient; bloom = comboFinisherBloom; } base.OnEnter(); base.characterDirection.forward = GetAimRay().direction; durationBeforeInterruptable = (isComboFinisher ? (comboFinisherBaseDurationBeforeInterruptable / attackSpeedStat) : (baseDurationBeforeInterruptable / attackSpeedStat)); } public override void OnExit() { base.OnExit(); } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); } protected override void PlayAnimation() { animationStateName = ""; string soundString = null; switch (step) { case 0: animationStateName = "Slash1"; soundString = slash1Sound; break; case 1: animationStateName = "Slash2"; soundString = slash1Sound; break; case 2: animationStateName = "Slash3"; soundString = slash3Sound; break; } float num = Mathf.Max(duration, 0.2f); PlayCrossfade("Gesture, Additive", animationStateName, "Slash.playbackRate", num, 0.05f); PlayCrossfade("Gesture, Override", animationStateName, "Slash.playbackRate", num, 0.05f); Util.PlaySound(soundString, base.gameObject); } protected override void OnMeleeHitAuthority() { base.OnMeleeHitAuthority(); base.characterBody.AddSpreadBloom(bloom); if (!hasGrantedBuff && isComboFinisher) { hasGrantedBuff = true; base.characterBody.AddTimedBuffAuthority(RoR2Content.Buffs.CrocoRegen.buffIndex, 0.5f); } } protected override void BeginMeleeAttackEffect() { swingEffectMuzzleString = animationStateName; AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); base.BeginMeleeAttackEffect(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write((byte)step); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); step = reader.ReadByte(); } public override InterruptPriority GetMinimumInterruptPriority() { if (!(base.fixedAge < durationBeforeInterruptable)) { return InterruptPriority.Skill; } return InterruptPriority.PrioritySkill; } } public class Spawn : BaseState { public static float minimumSleepDuration; public static GameObject spawnEffectPrefab; private Animator modelAnimator; private static int SleepLoopStateHash = Animator.StringToHash("SleepLoop"); public override void OnEnter() { base.OnEnter(); base.modelLocator.normalizeToFloor = true; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetFloat(AnimationParameters.aimWeight, 0f); } PlayAnimation("Body", SleepLoopStateHash); EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData { origin = base.characterBody.footPosition }, transmit: false); } public override void OnExit() { if ((bool)modelAnimator) { modelAnimator.SetFloat(AnimationParameters.aimWeight, 1f); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= minimumSleepDuration && (base.inputBank.moveVector.sqrMagnitude >= Mathf.Epsilon || base.inputBank.CheckAnyButtonDown())) { outer.SetNextState(new WakeUp()); } } } public class WakeUp : BaseState { public static float duration; public static float delayBeforeAimAnimatorWeight; private Animator modelAnimator; private static int SleepToIdleStateHash = Animator.StringToHash("SleepToIdle"); private static int SleepToIdleParamHash = Animator.StringToHash("SleepToIdle.playbackRate"); public override void OnEnter() { base.OnEnter(); base.modelLocator.normalizeToFloor = true; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetFloat(AnimationParameters.aimWeight, 0f); } PlayAnimation("Body", SleepToIdleStateHash, SleepToIdleParamHash, duration); } public override void Update() { base.Update(); if ((bool)modelAnimator) { modelAnimator.SetFloat(AnimationParameters.aimWeight, Mathf.Clamp01((base.age - delayBeforeAimAnimatorWeight) / duration)); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override void OnExit() { if ((bool)modelAnimator) { modelAnimator.SetFloat(AnimationParameters.aimWeight, 1f); } base.OnExit(); } } } namespace EntityStates.Commando { public class DeathState : GenericCharacterDeath { private UnityEngine.Vector3 previousPosition; private float upSpeedVelocity; private float upSpeed; private Animator modelAnimator; protected override bool shouldAutoDestroy => false; public override void OnEnter() { base.OnEnter(); UnityEngine.Vector3 force = UnityEngine.Vector3.up * 3f; if ((bool)base.characterMotor) { force += base.characterMotor.velocity; base.characterMotor.enabled = false; } if ((bool)base.cachedModelTransform) { RagdollController component = base.cachedModelTransform.GetComponent(); if ((bool)component) { component.BeginRagdoll(force); } } } protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge > 4f) { EntityState.Destroy(base.gameObject); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class DodgeState : BaseState { [SerializeField] public float duration = 0.9f; [SerializeField] public float initialSpeedCoefficient; [SerializeField] public float finalSpeedCoefficient; public static string dodgeSoundString; public static GameObject jetEffect; public static float dodgeFOV; public static int primaryReloadStockCount; private float rollSpeed; private UnityEngine.Vector3 forwardDirection; private Animator animator; private UnityEngine.Vector3 previousPosition; private static int DodgeForwardStateHash = Animator.StringToHash("DodgeForward"); private static int DodgeBackwardStateHash = Animator.StringToHash("DodgeBackward"); private static int DodgeRightStateHash = Animator.StringToHash("DodgeRight"); private static int DodgeLeftStateHash = Animator.StringToHash("DodgeLeft"); private static int DodgeParamHash = Animator.StringToHash("Dodge.playbackRate"); public override void Reset() { base.Reset(); rollSpeed = 0f; forwardDirection = UnityEngine.Vector3.zero; animator = null; previousPosition = UnityEngine.Vector3.zero; } public override void OnEnter() { base.OnEnter(); Util.PlaySound(dodgeSoundString, base.gameObject); animator = GetModelAnimator(); ChildLocator component = animator.GetComponent(); if (base.isAuthority) { if ((bool)base.inputBank && (bool)base.characterDirection) { forwardDirection = ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized; } if ((bool)base.skillLocator.primary) { base.skillLocator.primary.Reset(); base.skillLocator.primary.stock = primaryReloadStockCount; } } UnityEngine.Vector3 rhs = (base.characterDirection ? base.characterDirection.forward : forwardDirection); UnityEngine.Vector3 rhs2 = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, rhs); float num = UnityEngine.Vector3.Dot(forwardDirection, rhs); float num2 = UnityEngine.Vector3.Dot(forwardDirection, rhs2); animator.SetFloat("forwardSpeed", num, 0.1f, GetDeltaTime()); animator.SetFloat("rightSpeed", num2, 0.1f, GetDeltaTime()); if (Mathf.Abs(num) > Mathf.Abs(num2)) { PlayAnimation("Body", (num > 0f) ? DodgeForwardStateHash : DodgeBackwardStateHash, DodgeParamHash, duration); } else { PlayAnimation("Body", (num2 > 0f) ? DodgeRightStateHash : DodgeLeftStateHash, DodgeParamHash, duration); } if ((bool)jetEffect) { Transform transform = component.FindChild("LeftJet"); Transform transform2 = component.FindChild("RightJet"); bool flag = EffectManager.ShouldUsePooledEffect(jetEffect); if ((bool)transform) { if (!flag) { UnityEngine.Object.Instantiate(jetEffect, transform); } else { EffectManager.GetAndActivatePooledEffect(jetEffect, transform, inResetLocal: true); } } if ((bool)transform2) { if (!flag) { UnityEngine.Object.Instantiate(jetEffect, transform2); } else { EffectManager.GetAndActivatePooledEffect(jetEffect, transform2, inResetLocal: true); } } } RecalculateRollSpeed(); if ((bool)base.characterMotor && (bool)base.characterDirection) { base.characterMotor.velocity.y = 0f; base.characterMotor.velocity = forwardDirection * rollSpeed; } UnityEngine.Vector3 vector = (base.characterMotor ? base.characterMotor.velocity : UnityEngine.Vector3.zero); previousPosition = base.transform.position - vector; } private void RecalculateRollSpeed() { rollSpeed = moveSpeedStat * Mathf.Lerp(initialSpeedCoefficient, finalSpeedCoefficient, base.fixedAge / duration); } public override void FixedUpdate() { base.FixedUpdate(); RecalculateRollSpeed(); if ((bool)base.cameraTargetParams) { base.cameraTargetParams.fovOverride = Mathf.Lerp(dodgeFOV, 60f, base.fixedAge / duration); } UnityEngine.Vector3 normalized = (base.transform.position - previousPosition).normalized; if ((bool)base.characterMotor && (bool)base.characterDirection && normalized != UnityEngine.Vector3.zero) { UnityEngine.Vector3 lhs = normalized * rollSpeed; float y = lhs.y; lhs.y = 0f; float num = Mathf.Max(UnityEngine.Vector3.Dot(lhs, forwardDirection), 0f); lhs = forwardDirection * num; lhs.y += Mathf.Max(y, 0f); base.characterMotor.velocity = lhs; } previousPosition = base.transform.position; if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { if ((bool)base.cameraTargetParams) { base.cameraTargetParams.fovOverride = -1f; } base.OnExit(); } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(forwardDirection); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); forwardDirection = reader.ReadVector3(); } } public class CombatDodge : DodgeState { public static float durationToFire; public static int bulletCount; public static GameObject muzzleEffectPrefab; public static GameObject tracerEffectPrefab; public static GameObject hitEffectPrefab; public static float damageCoefficient; public static float force; public static string firePistolSoundString; public static float recoilAmplitude = 1f; public static float range; private int bulletsFired; private BullseyeSearch search; private static int FirePistolLeftStateHash = Animator.StringToHash("FirePistol, Left"); private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right"); public override void OnEnter() { base.OnEnter(); search = new BullseyeSearch(); search.searchDirection = UnityEngine.Vector3.zero; search.teamMaskFilter = TeamMask.allButNeutral; search.teamMaskFilter.RemoveTeam(base.characterBody.teamComponent.teamIndex); search.filterByLoS = true; search.sortMode = BullseyeSearch.SortMode.Distance; search.maxDistanceFilter = range; } public override void FixedUpdate() { base.FixedUpdate(); float num = base.fixedAge / durationToFire; if (bulletsFired < bulletCount && num > (float)bulletsFired / (float)bulletCount) { if (bulletsFired % 2 == 0) { PlayAnimation("Gesture Additive, Left", FirePistolLeftStateHash); FireBullet("MuzzleLeft"); } else { PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash); FireBullet("MuzzleRight"); } } } private HurtBox PickNextTarget() { search.searchOrigin = GetAimRay().origin; search.RefreshCandidates(); List list = search.GetResults().ToList(); if (list.Count <= 0) { return null; } return list[UnityEngine.Random.Range(0, list.Count)]; } private void FireBullet(string targetMuzzle) { bulletsFired++; AddRecoil(-0.4f * recoilAmplitude, -0.8f * recoilAmplitude, -0.3f * recoilAmplitude, 0.3f * recoilAmplitude); if (base.isAuthority) { Ray aimRay = GetAimRay(); aimRay.direction = UnityEngine.Random.onUnitSphere; HurtBox hurtBox = PickNextTarget(); if ((bool)hurtBox) { aimRay.direction = hurtBox.transform.position - aimRay.origin; } Util.PlaySound(firePistolSoundString, base.gameObject); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, targetMuzzle, transmit: false); } BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = base.characterBody.spreadBloomAngle; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = targetMuzzle; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.radius = 0.1f; bulletAttack.smartCollision = true; bulletAttack.Fire(); } } } public class MainState : BaseState { private Animator modelAnimator; private GenericSkill skill1; private GenericSkill skill2; private GenericSkill skill3; private GenericSkill skill4; private bool skill1InputRecieved; private bool skill2InputRecieved; private bool skill3InputRecieved; private bool skill4InputRecieved; private UnityEngine.Vector3 previousPosition; private UnityEngine.Vector3 estimatedVelocity; private static int isMovingParamHash = Animator.StringToHash("isMoving"); private static int walkSpeedParamHash = Animator.StringToHash("walkSpeed"); private static int forwardSpeedParamHash = Animator.StringToHash("forwardSpeed"); private static int rightSpeedParamHash = Animator.StringToHash("rightSpeed"); public override void OnEnter() { base.OnEnter(); GenericSkill[] components = base.gameObject.GetComponents(); for (int i = 0; i < components.Length; i++) { if (components[i].skillName == "FirePistol") { skill1 = components[i]; } else if (components[i].skillName == "FireFMJ") { skill2 = components[i]; } else if (components[i].skillName == "Roll") { skill3 = components[i]; } else if (components[i].skillName == "FireBarrage") { skill4 = components[i]; } } modelAnimator = GetModelAnimator(); previousPosition = base.transform.position; if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Body"); modelAnimator.CrossFadeInFixedTime("Walk", 0.1f, layerIndex); modelAnimator.Update(0f); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { AimAnimator component = modelTransform.GetComponent(); if ((bool)component) { component.enabled = true; } } } public override void OnExit() { Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { AimAnimator component = modelTransform.GetComponent(); if ((bool)component) { component.enabled = false; } } if (base.isAuthority && (bool)base.characterMotor) { base.characterMotor.moveDirection = UnityEngine.Vector3.zero; } base.OnExit(); } public override void Update() { base.Update(); if (base.inputBank.skill1.down) { skill1InputRecieved = true; } if (base.inputBank.skill2.down) { skill2InputRecieved = true; } if (base.inputBank.skill3.down) { skill3InputRecieved = true; } if (base.inputBank.skill4.down) { skill4InputRecieved = true; } } public override void FixedUpdate() { base.FixedUpdate(); UnityEngine.Vector3 position = base.transform.position; float deltaTime = GetDeltaTime(); if (deltaTime != 0f) { estimatedVelocity = (position - previousPosition) / deltaTime; } if (base.isAuthority) { UnityEngine.Vector3 moveVector = base.inputBank.moveVector; if ((bool)base.characterMotor) { base.characterMotor.moveDirection = moveVector; if (skill3InputRecieved) { if ((bool)skill3) { skill3.ExecuteIfReady(); } skill3InputRecieved = false; } } if ((bool)base.characterDirection) { if ((bool)base.characterBody && base.characterBody.shouldAim) { base.characterDirection.moveVector = base.inputBank.aimDirection; } else { base.characterDirection.moveVector = moveVector; } } if (skill1InputRecieved) { if ((bool)skill1) { skill1.ExecuteIfReady(); } skill1InputRecieved = false; } if (skill2InputRecieved) { if ((bool)skill2) { skill2.ExecuteIfReady(); } skill2InputRecieved = false; } if (skill4InputRecieved) { if ((bool)skill4) { skill4.ExecuteIfReady(); } skill4InputRecieved = false; } } if ((bool)modelAnimator && (bool)base.characterDirection) { UnityEngine.Vector3 lhs = estimatedVelocity; lhs.y = 0f; UnityEngine.Vector3 forward = base.characterDirection.forward; UnityEngine.Vector3 rhs = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, forward); float magnitude = lhs.magnitude; float value = UnityEngine.Vector3.Dot(lhs, forward); float value2 = UnityEngine.Vector3.Dot(lhs, rhs); modelAnimator.SetBool(isMovingParamHash, magnitude != 0f); modelAnimator.SetFloat(walkSpeedParamHash, magnitude); modelAnimator.SetFloat(forwardSpeedParamHash, value, 0.2f, GetDeltaTime()); modelAnimator.SetFloat(rightSpeedParamHash, value2, 0.2f, GetDeltaTime()); } previousPosition = position; } } public class SlideState : BaseState { public static float slideDuration; public static float jumpDuration; public static AnimationCurve forwardSpeedCoefficientCurve; public static AnimationCurve jumpforwardSpeedCoefficientCurve; public static string soundString; public static GameObject jetEffectPrefab; public static GameObject slideEffectPrefab; private UnityEngine.Vector3 forwardDirection; private GameObject slideEffectInstance; private bool startedStateGrounded; private static int JumpStateHash = Animator.StringToHash("Jump"); private static int SlideForwardStateHash = Animator.StringToHash("SlideForward"); private static int SlideForwardParamHash = Animator.StringToHash("SlideForward.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(soundString, base.gameObject); if ((bool)base.inputBank && (bool)base.characterDirection) { base.characterDirection.forward = ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized; } if ((bool)base.characterMotor) { startedStateGrounded = base.characterMotor.isGrounded; } if ((bool)jetEffectPrefab) { Transform transform = FindModelChild("LeftJet"); Transform transform2 = FindModelChild("RightJet"); if ((bool)transform) { UnityEngine.Object.Instantiate(jetEffectPrefab, transform); } if ((bool)transform2) { UnityEngine.Object.Instantiate(jetEffectPrefab, transform2); } } base.characterBody.SetSpreadBloom(0f, canOnlyIncreaseBloom: false); if (!startedStateGrounded) { PlayAnimation("Body", JumpStateHash); UnityEngine.Vector3 velocity = base.characterMotor.velocity; velocity.y = base.characterBody.jumpPower; base.characterMotor.velocity = velocity; return; } PlayAnimation("Body", SlideForwardStateHash, SlideForwardParamHash, slideDuration); if ((bool)slideEffectPrefab) { Transform parent = FindModelChild("Base"); slideEffectInstance = UnityEngine.Object.Instantiate(slideEffectPrefab, parent); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { float num = (startedStateGrounded ? slideDuration : jumpDuration); if ((bool)base.inputBank && (bool)base.characterDirection) { base.characterDirection.moveVector = base.inputBank.moveVector; forwardDirection = base.characterDirection.forward; } if ((bool)base.characterMotor) { float num2 = 0f; num2 = ((!startedStateGrounded) ? jumpforwardSpeedCoefficientCurve.Evaluate(base.fixedAge / num) : forwardSpeedCoefficientCurve.Evaluate(base.fixedAge / num)); base.characterMotor.rootMotion += num2 * moveSpeedStat * forwardDirection * GetDeltaTime(); } if (base.fixedAge >= num) { outer.SetNextStateToMain(); } } } public override void OnExit() { PlayImpactAnimation(); if ((bool)slideEffectInstance) { EntityState.Destroy(slideEffectInstance); } base.OnExit(); } private void PlayImpactAnimation() { Animator modelAnimator = GetModelAnimator(); int layerIndex = modelAnimator.GetLayerIndex("Impact"); if (layerIndex >= 0) { modelAnimator.SetLayerWeight(layerIndex, 1f); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.Commando.CommandoWeapon { public class CastSmokescreen : BaseState { public static float baseDuration; public static float stealthDuration = 3f; public static string jumpSoundString; public static string startCloakSoundString; public static string stopCloakSoundString; public static GameObject initialEffectPrefab; public static GameObject smokescreenEffectPrefab; public static float damageCoefficient = 1.3f; public static float radius = 4f; public static float forceMagnitude = 100f; private float duration; private float totalDuration; private bool hasCastSmoke; private Animator animator; private void CastSmoke() { if (!hasCastSmoke) { Util.PlaySound(startCloakSoundString, base.gameObject); } else { Util.PlaySound(stopCloakSoundString, base.gameObject); } EffectManager.SpawnEffect(smokescreenEffectPrefab, new EffectData { origin = base.transform.position }, transmit: false); int layerIndex = animator.GetLayerIndex("Impact"); if (layerIndex >= 0) { animator.SetLayerWeight(layerIndex, 2f); animator.PlayInFixedTime("LightImpact", layerIndex, 0f); } if (NetworkServer.active) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * damageCoefficient; blastAttack.baseForce = forceMagnitude; blastAttack.position = base.transform.position; blastAttack.radius = radius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.damageType = DamageType.Stun1s; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); } } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; totalDuration = stealthDuration + totalDuration; PlayCrossfade("Gesture, Smokescreen", "CastSmokescreen", "CastSmokescreen.playbackRate", duration, 0.2f); animator = GetModelAnimator(); Util.PlaySound(jumpSoundString, base.gameObject); EffectManager.SpawnEffect(initialEffectPrefab, new EffectData { origin = base.transform.position }, transmit: true); if ((bool)base.characterBody && NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.CloakSpeed.buffIndex); } } public override void OnExit() { if ((bool)base.characterBody && NetworkServer.active) { if (base.characterBody.HasBuff(RoR2Content.Buffs.Cloak)) { base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak); } if (base.characterBody.HasBuff(RoR2Content.Buffs.CloakSpeed)) { base.characterBody.RemoveBuff(RoR2Content.Buffs.CloakSpeed); } } if (!outer.destroying) { CastSmoke(); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && !hasCastSmoke) { CastSmoke(); if ((bool)base.characterBody && NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.Cloak.buffIndex); } hasCastSmoke = true; } if (base.fixedAge >= totalDuration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { if (!hasCastSmoke) { return InterruptPriority.PrioritySkill; } return InterruptPriority.Any; } } public class CastSmokescreenNoDelay : BaseState { public static float duration; public static float minimumStateDuration = 3f; public static string startCloakSoundString; public static string stopCloakSoundString; public static GameObject smokescreenEffectPrefab; public static Material destealthMaterial; public static float damageCoefficient = 1.3f; public static float radius = 4f; public static float forceMagnitude = 100f; private float stopwatch; private bool hasCastSmoke; private Animator animator; public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); CastSmoke(); if ((bool)base.characterBody && NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.Cloak); base.characterBody.AddBuff(RoR2Content.Buffs.CloakSpeed); } } public override void OnExit() { if ((bool)base.characterBody && NetworkServer.active) { if (base.characterBody.HasBuff(RoR2Content.Buffs.Cloak)) { base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak); } if (base.characterBody.HasBuff(RoR2Content.Buffs.CloakSpeed)) { base.characterBody.RemoveBuff(RoR2Content.Buffs.CloakSpeed); } } if (!outer.destroying) { CastSmoke(); } if ((bool)destealthMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(animator.gameObject); temporaryOverlayInstance.duration = 1f; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = destealthMaterial; temporaryOverlayInstance.inspectorCharacterModel = animator.gameObject.GetComponent(); temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void CastSmoke() { if (!hasCastSmoke) { Util.PlaySound(startCloakSoundString, base.gameObject); hasCastSmoke = true; } else { Util.PlaySound(stopCloakSoundString, base.gameObject); } EffectManager.SpawnEffect(smokescreenEffectPrefab, new EffectData { origin = base.transform.position }, transmit: false); int layerIndex = animator.GetLayerIndex("Impact"); if (layerIndex >= 0) { animator.SetLayerWeight(layerIndex, 1f); animator.PlayInFixedTime("LightImpact", layerIndex, 0f); } if (NetworkServer.active) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * damageCoefficient; blastAttack.baseForce = forceMagnitude; blastAttack.position = base.transform.position; blastAttack.radius = radius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.damageType = DamageType.Stun1s; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); } } public override InterruptPriority GetMinimumInterruptPriority() { if (!(stopwatch > minimumStateDuration)) { return InterruptPriority.PrioritySkill; } return InterruptPriority.Any; } } public class FireBarrage : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static float baseDurationBetweenShots = 1f; public static float totalDuration = 2f; public static float bulletRadius = 1.5f; public static int baseBulletCount = 1; public static string fireBarrageSoundString; public static float recoilAmplitude; public static float spreadBloomValue; private int totalBulletsFired; private int bulletCount; public float stopwatchBetweenShots; private Animator modelAnimator; private Transform modelTransform; private float duration; private float durationBetweenShots; private static int FireBarrageStateHash = Animator.StringToHash("FireBarrage"); private static int FireBarrageParamHash = Animator.StringToHash("FireBarrage.playbackRate"); private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right"); public override void OnEnter() { base.OnEnter(); base.characterBody.SetSpreadBloom(0.2f, canOnlyIncreaseBloom: false); duration = totalDuration; durationBetweenShots = baseDurationBetweenShots / attackSpeedStat; bulletCount = (int)((float)baseBulletCount * attackSpeedStat); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); PlayCrossfade("Gesture, Additive", FireBarrageStateHash, FireBarrageParamHash, duration, 0.2f); PlayCrossfade("Gesture, Override", FireBarrageStateHash, FireBarrageParamHash, duration, 0.2f); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } FireBullet(); } private void FireBullet() { Ray aimRay = GetAimRay(); string muzzleName = "MuzzleRight"; if ((bool)modelAnimator) { if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash); } AddRecoil(-0.8f * recoilAmplitude, -1f * recoilAmplitude, -0.1f * recoilAmplitude, 0.15f * recoilAmplitude); if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.bulletCount = 1u; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleName; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.radius = bulletRadius; bulletAttack.smartCollision = true; bulletAttack.damageType = DamageType.Stun1s; bulletAttack.Fire(); } base.characterBody.AddSpreadBloom(spreadBloomValue); totalBulletsFired++; Util.PlaySound(fireBarrageSoundString, base.gameObject); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatchBetweenShots += GetDeltaTime(); if (stopwatchBetweenShots >= durationBetweenShots && totalBulletsFired < bulletCount) { stopwatchBetweenShots -= durationBetweenShots; FireBullet(); } if (base.fixedAge >= duration && totalBulletsFired == bulletCount && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireFMJ : GenericProjectileBaseState { private static int FireFMJStateHash = Animator.StringToHash("FireFMJ"); private static int FireFMJParamHash = Animator.StringToHash("FireFMJ.playbackRate"); protected override void PlayAnimation(float duration) { base.PlayAnimation(duration); if ((bool)GetModelAnimator()) { PlayAnimation("Gesture, Additive", FireFMJStateHash, FireFMJParamHash, duration); PlayAnimation("Gesture, Override", FireFMJStateHash, FireFMJParamHash, duration); } } protected override Ray ModifyProjectileAimRay(Ray aimRay) { TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, projectilePrefab, base.gameObject); return aimRay; } } public class FireLightsOut : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float baseDuration = 2f; public static string attackSoundString; public static float recoilAmplitude; private ChildLocator childLocator; public int bulletCountCurrent = 1; private float duration; private static int FireRevolverStateHash = Animator.StringToHash("FireRevolver"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; AddRecoil(-3f * recoilAmplitude, -4f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude); Ray aimRay = GetAimRay(); StartAimMode(aimRay); string muzzleName = "MuzzlePistol"; Util.PlaySound(attackSoundString, base.gameObject); PlayAnimation("Gesture, Additive", FireRevolverStateHash); PlayAnimation("Gesture, Override", FireRevolverStateHash); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { BulletAttack obj = new BulletAttack { owner = base.gameObject, weapon = base.gameObject, origin = aimRay.origin, aimVector = aimRay.direction, minSpread = minSpread, maxSpread = maxSpread, bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u), damage = damageCoefficient * damageStat, force = force, falloffModel = BulletAttack.FalloffModel.None, tracerEffectPrefab = tracerEffectPrefab, muzzleName = muzzleName, hitEffectPrefab = hitEffectPrefab, isCrit = Util.CheckRoll(critStat, base.characterBody.master), HitEffectNormal = false, radius = 0.5f }; obj.damageType |= (DamageTypeCombo)DamageType.ResetCooldownsOnKill; obj.smartCollision = true; obj.Fire(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } } public class FirePistol2 : BaseSkillState, SteppedSkillDef.IStepSetter { public static GameObject muzzleEffectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float force; public static float baseDuration = 2f; public static string firePistolSoundString; public static float recoilAmplitude = 1f; public static float spreadBloomValue = 0.3f; public static float commandoBoostBuffCoefficient = 0.4f; public static float trajectoryAimAssistMultiplier = 0.75f; private int pistol; private Ray aimRay; private float duration; private static int FirePistolLeftStateHash = Animator.StringToHash("FirePistol, Left"); private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right"); void SteppedSkillDef.IStepSetter.SetStep(int i) { pistol = i; } private void FireBullet(string targetMuzzle) { Util.PlaySound(firePistolSoundString, base.gameObject); if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, targetMuzzle, transmit: false); } AddRecoil(-0.4f * recoilAmplitude, -0.8f * recoilAmplitude, -0.3f * recoilAmplitude, 0.3f * recoilAmplitude); if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = base.characterBody.spreadBloomAngle; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = targetMuzzle; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.radius = 0.1f; bulletAttack.smartCollision = true; bulletAttack.trajectoryAimAssistMultiplier = trajectoryAimAssistMultiplier; bulletAttack.Fire(); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; aimRay = GetAimRay(); StartAimMode(aimRay, 3f); if (pistol % 2 == 0) { PlayAnimation("Gesture Additive, Left", FirePistolLeftStateHash); FireBullet("MuzzleLeft"); } else { PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash); FireBullet("MuzzleRight"); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { if (base.activatorSkillSlot.stock <= 0) { outer.SetNextState(new ReloadPistols()); } else { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireRocket : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static float damageCoefficient; public static float force; public static float baseDuration = 2f; private float duration; public int bulletCountCurrent = 1; private static int FireFMJStateHash = Animator.StringToHash("FireFMJ"); private static int FireFMJParamHash = Animator.StringToHash("FireFMJ.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Ray aimRay = GetAimRay(); StartAimMode(aimRay); string muzzleName = "MuzzleCenter"; PlayAnimation("Gesture", FireFMJStateHash, FireFMJParamHash, duration); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireShotgun : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float force; public static int bulletCount; public static float baseMaxDuration = 2f; public static float baseMinDuration = 0.5f; public static string attackSoundString; public static float recoilAmplitude; public static float spreadBloomValue = 0.3f; private float maxDuration; private float minDuration; private static int FireShotgunStateHash = Animator.StringToHash("FireShotgun"); private static int FireShotgunParamHash = Animator.StringToHash("FireShotgun.playbackRate"); private bool buttonReleased; public override void OnEnter() { base.OnEnter(); AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude); maxDuration = baseMaxDuration / attackSpeedStat; minDuration = baseMinDuration / attackSpeedStat; Ray aimRay = GetAimRay(); StartAimMode(aimRay); Util.PlaySound(attackSoundString, base.gameObject); PlayAnimation("Gesture, Additive", FireShotgunStateHash, FireShotgunParamHash, maxDuration * 1.1f); PlayAnimation("Gesture, Override", FireShotgunStateHash, FireShotgunParamHash, maxDuration * 1.1f); string muzzleName = "MuzzleShotgun"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = base.characterBody.spreadBloomAngle; bulletAttack.bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u); bulletAttack.procCoefficient = 1f / (float)bulletCount; bulletAttack.damage = damageCoefficient * damageStat / (float)bulletCount; bulletAttack.force = force; bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleName; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.HitEffectNormal = false; bulletAttack.radius = 0f; bulletAttack.Fire(); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); buttonReleased |= !base.inputBank.skill1.down; if (base.fixedAge >= maxDuration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { if (buttonReleased && base.fixedAge >= minDuration) { return InterruptPriority.Any; } return InterruptPriority.Skill; } } public class FireShotgunBlast : GenericBulletBaseState { public static float delayBetweenShotgunBlasts; private bool hasFiredSecondBlast; private static int FirePistolLeftStateHash = Animator.StringToHash("FirePistol, Left"); private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right"); public override void OnEnter() { muzzleName = "MuzzleLeft"; base.OnEnter(); PlayAnimation("Gesture Additive, Left", FirePistolLeftStateHash); PlayAnimation("Gesture Override, Left", FirePistolLeftStateHash); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void FixedUpdate() { base.FixedUpdate(); if (!hasFiredSecondBlast && delayBetweenShotgunBlasts / attackSpeedStat < base.fixedAge) { hasFiredSecondBlast = true; PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash); PlayAnimation("Gesture Override, Right", FirePistolRightStateHash); muzzleName = "MuzzleRight"; FireBullet(GetAimRay()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireShrapnel : BaseState { public static GameObject effectPrefab; public static GameObject hitEffectPrefab; public static GameObject tracerEffectPrefab; public static float damageCoefficient; public static float blastRadius; public static float force; public static float minSpread; public static float maxSpread; public static int bulletCount; public static float baseDuration = 2f; public static string attackSoundString; public static float maxDistance; private float duration; private Ray modifiedAimRay; private static int FireLaserStateHash = Animator.StringToHash("FireLaser"); private static int FireLaserParamHash = Animator.StringToHash("FireLaser.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modifiedAimRay = GetAimRay(); Util.PlaySound(attackSoundString, base.gameObject); string muzzleName = "MuzzleLaser"; if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } PlayAnimation("Gesture", FireLaserStateHash, FireLaserParamHash, duration); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { if (Physics.Raycast(modifiedAimRay, out var hitInfo, 1000f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault)) { BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * damageCoefficient; blastAttack.baseForce = force * 0.2f; blastAttack.position = hitInfo.point; blastAttack.radius = blastRadius; blastAttack.Fire(); } BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = modifiedAimRay.origin; bulletAttack.aimVector = modifiedAimRay.direction; bulletAttack.radius = 0.25f; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u); bulletAttack.damage = 0f; bulletAttack.procCoefficient = 0f; bulletAttack.force = force; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleName; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); bulletAttack.Fire(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireSweepBarrage : BaseState { public static string enterSound; public static string muzzle; public static string fireSoundString; public static GameObject muzzleEffectPrefab; public static GameObject tracerEffectPrefab; public static float baseTotalDuration; public static float baseFiringDuration; public static float fieldOfView; public static float maxDistance; public static float damageCoefficient; public static float procCoefficient; public static float force; public static int minimumFireCount; public static GameObject impactEffectPrefab; private float totalDuration; private float firingDuration; private int totalBulletsToFire; private int totalBulletsFired; private int targetHurtboxIndex; private float timeBetweenBullets; private List targetHurtboxes = new List(); private float fireTimer; private ChildLocator childLocator; private int muzzleIndex; private Transform muzzleTransform; private static int FireSweepBarrageStateHash = Animator.StringToHash("FireSweepBarrage"); private static int FireSweepBarrageParamHash = Animator.StringToHash("FireSweepBarrage.playbackRate"); private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right"); public override void OnEnter() { base.OnEnter(); totalDuration = baseTotalDuration / attackSpeedStat; firingDuration = baseFiringDuration / attackSpeedStat; base.characterBody.SetAimTimer(3f); PlayAnimation("Gesture, Additive", FireSweepBarrageStateHash, FireSweepBarrageParamHash, totalDuration); PlayAnimation("Gesture, Override", FireSweepBarrageStateHash, FireSweepBarrageParamHash, totalDuration); Util.PlaySound(enterSound, base.gameObject); Ray aimRay = GetAimRay(); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam()); bullseyeSearch.maxAngleFilter = fieldOfView * 0.5f; bullseyeSearch.maxDistanceFilter = maxDistance; bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle; bullseyeSearch.filterByLoS = true; bullseyeSearch.RefreshCandidates(); targetHurtboxes = bullseyeSearch.GetResults().Where(Util.IsValid).Distinct(default(HurtBox.EntityEqualityComparer)) .ToList(); totalBulletsToFire = Mathf.Max(targetHurtboxes.Count, minimumFireCount); timeBetweenBullets = firingDuration / (float)totalBulletsToFire; childLocator = GetModelTransform().GetComponent(); muzzleIndex = childLocator.FindChildIndex(muzzle); muzzleTransform = childLocator.FindChild(muzzleIndex); } private void Fire() { if (totalBulletsFired >= totalBulletsToFire) { return; } if (!string.IsNullOrEmpty(muzzle)) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzle, transmit: false); } Util.PlaySound(fireSoundString, base.gameObject); PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash); if (NetworkServer.active && targetHurtboxes.Count > 0) { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = damageStat * damageCoefficient; damageInfo.attacker = base.gameObject; damageInfo.procCoefficient = procCoefficient; damageInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); if (targetHurtboxIndex >= targetHurtboxes.Count) { targetHurtboxIndex = 0; } HurtBox hurtBox = targetHurtboxes[targetHurtboxIndex]; if ((bool)hurtBox) { HealthComponent healthComponent = hurtBox.healthComponent; if ((bool)healthComponent) { targetHurtboxIndex++; UnityEngine.Vector3 normalized = (hurtBox.transform.position - base.characterBody.corePosition).normalized; damageInfo.force = force * normalized; damageInfo.position = hurtBox.transform.position; EffectManager.SimpleImpactEffect(impactEffectPrefab, hurtBox.transform.position, normalized, transmit: true); healthComponent.TakeDamage(damageInfo); GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject); } if ((bool)tracerEffectPrefab && (bool)childLocator) { int childIndex = childLocator.FindChildIndex(muzzle); childLocator.FindChild(childIndex); EffectData effectData = new EffectData { origin = hurtBox.transform.position, start = muzzleTransform.position }; effectData.SetChildLocatorTransformReference(base.gameObject, childIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } } } totalBulletsFired++; } public override void FixedUpdate() { base.FixedUpdate(); fireTimer -= GetDeltaTime(); if (fireTimer <= 0f) { Fire(); fireTimer += timeBetweenBullets; } if (base.fixedAge >= totalDuration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireThermite : BaseState { public static GameObject effectPrefab; public static GameObject projectilePrefab; public static float damageCoefficient; public static float force; public static float selfForce; public static float baseDuration = 2f; private float duration; public int bulletCountCurrent = 1; private static int FireFMJStateHash = Animator.StringToHash("FireFMJ"); private static int FireFMJParamHash = Animator.StringToHash("FireFMJ.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Ray aimRay = GetAimRay(); StartAimMode(aimRay); PlayAnimation("Gesture", FireFMJStateHash, FireFMJParamHash, duration); string muzzleName = "MuzzleCenter"; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } if ((bool)base.characterMotor && !base.characterMotor.isGrounded) { UnityEngine.Vector3 vector = -aimRay.direction * selfForce; vector.y *= 0.5f; base.characterMotor.ApplyForce(vector, alwaysApply: true); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class PrepBarrage : BaseState { public static float baseDuration = 3f; public static string prepBarrageSoundString; private float duration; private Animator modelAnimator; private static int PrepBarrageStateHash = Animator.StringToHash("PrepBarrage"); private static int PrepBarrageParamHash = Animator.StringToHash("PrepBarrage.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayAnimation("Gesture", PrepBarrageStateHash, PrepBarrageParamHash, duration); } Util.PlaySound(prepBarrageSoundString, base.gameObject); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireBarrage nextState = new FireBarrage(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class PrepLightsOut : BaseState { public static float baseDuration = 3f; public static GameObject chargePrefab; public static GameObject specialCrosshairPrefab; public static string prepSoundString; private GameObject chargeEffect; private float duration; private ChildLocator childLocator; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private EffectManagerHelper _emh_chargeEffect; private static int PrepRevolverStateHash = Animator.StringToHash("PrepRevolver"); private static int PrepRevolverParamHash = Animator.StringToHash("PrepRevolver.playbackRate"); public override void Reset() { base.Reset(); chargeEffect = null; duration = 0f; childLocator = null; _emh_chargeEffect = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Additive", PrepRevolverStateHash, PrepRevolverParamHash, duration); PlayAnimation("Gesture, Override", PrepRevolverStateHash, PrepRevolverParamHash, duration); Util.PlaySound(prepSoundString, base.gameObject); if ((bool)specialCrosshairPrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, specialCrosshairPrefab, CrosshairUtils.OverridePriority.Skill); } Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); if ((bool)childLocator) { Transform transform = childLocator.FindChild("MuzzlePistol"); if ((bool)transform && (bool)chargePrefab) { if (!EffectManager.ShouldUsePooledEffect(chargePrefab)) { chargeEffect = UnityEngine.Object.Instantiate(chargePrefab, transform.position, transform.rotation); } else { _emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargePrefab, transform.position, transform.rotation); chargeEffect = _emh_chargeEffect.gameObject; } chargeEffect.transform.parent = transform; ScaleParticleSystemDuration component = chargeEffect.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new FireLightsOut()); } } public override void OnExit() { if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null) { _emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect); } else { EntityState.Destroy(chargeEffect); } chargeEffect = null; _emh_chargeEffect = null; base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ReloadPistols : GenericReload { private static int ReloadPistolsStateHash = Animator.StringToHash("ReloadPistols"); private static int ReloadPistolsParamHash = Animator.StringToHash("ReloadPistols.playbackRate"); private static int ReloadPistolsExitStateHash = Animator.StringToHash("ReloadPistolsExit"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Gesture, Override", ReloadPistolsStateHash, ReloadPistolsParamHash, duration); PlayAnimation("Gesture, Additive", ReloadPistolsStateHash, ReloadPistolsParamHash, duration); FindModelChild("GunMeshL")?.gameObject.SetActive(value: false); FindModelChild("GunMeshR")?.gameObject.SetActive(value: false); } public override void OnExit() { FindModelChild("ReloadFXL")?.gameObject.SetActive(value: false); FindModelChild("ReloadFXR")?.gameObject.SetActive(value: false); FindModelChild("GunMeshL")?.gameObject.SetActive(value: true); FindModelChild("GunMeshR")?.gameObject.SetActive(value: true); PlayAnimation("Gesture, Override", ReloadPistolsExitStateHash); PlayAnimation("Gesture, Additive", ReloadPistolsExitStateHash); base.OnExit(); } } public class ThrowGrenade : GenericProjectileBaseState { private static int ThrowGrenadeStateHash = Animator.StringToHash("ThrowGrenade"); private static int FireFMJParamHash = Animator.StringToHash("FireFMJ.playbackRate"); protected override void PlayAnimation(float duration) { if ((bool)GetModelAnimator()) { PlayAnimation("Gesture, Additive", ThrowGrenadeStateHash, FireFMJParamHash, duration * 2f); PlayAnimation("Gesture, Override", ThrowGrenadeStateHash, FireFMJParamHash, duration * 2f); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class ThrowStickyGrenade : ThrowGrenade { } } namespace EntityStates.ClaymanMonster { public class Leap : BaseState { public static string leapSoundString; public static float minimumDuration; public static float verticalJumpSpeed; public static float horizontalJumpSpeedCoefficient; private UnityEngine.Vector3 forwardDirection; private Animator animator; private float stopwatch; private bool playedImpact; private static int LeapcycleParamHash = Animator.StringToHash("Leap.cycle"); private static int LightImpactStateHash = Animator.StringToHash("LightImpact"); private static int IdleStateHash = Animator.StringToHash("Idle"); public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); Util.PlaySound(leapSoundString, base.gameObject); if ((bool)base.characterMotor) { base.characterMotor.velocity.y = verticalJumpSpeed; } forwardDirection = UnityEngine.Vector3.ProjectOnPlane(base.inputBank.aimDirection, UnityEngine.Vector3.up); base.characterDirection.moveVector = forwardDirection; PlayCrossfade("Body", "LeapAirLoop", 0.15f); } public override void FixedUpdate() { stopwatch += GetDeltaTime(); animator.SetFloat(LeapcycleParamHash, Mathf.Clamp01(Util.Remap(base.characterMotor.velocity.y, 0f - verticalJumpSpeed, verticalJumpSpeed, 1f, 0f))); UnityEngine.Vector3 velocity = forwardDirection * base.characterBody.moveSpeed * horizontalJumpSpeedCoefficient; velocity.y = base.characterMotor.velocity.y; base.characterMotor.velocity = velocity; base.FixedUpdate(); if (base.characterMotor.isGrounded && stopwatch > minimumDuration && !playedImpact) { playedImpact = true; int layerIndex = animator.GetLayerIndex("Impact"); if (layerIndex >= 0) { animator.SetLayerWeight(layerIndex, 1.5f); animator.PlayInFixedTime(LightImpactStateHash, layerIndex, 0f); } if (base.isAuthority) { outer.SetNextStateToMain(); } } } public override void OnExit() { PlayAnimation("Body", IdleStateHash); base.OnExit(); } } public class SpawnState : BaseState { public static float duration; public static string spawnSoundString; public static GameObject spawnEffectPrefab; public static string spawnEffectChildString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); ChildLocator component = GetModelTransform().GetComponent(); if ((bool)component) { Transform transform = component.FindChild(spawnEffectChildString); if ((bool)transform) { UnityEngine.Object.Instantiate(spawnEffectPrefab, transform.position, UnityEngine.Quaternion.identity); } } if (spawnSoundString.Length > 0) { Util.PlaySound(spawnSoundString, base.gameObject); } PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class SwipeForward : BaseState { public static float baseDuration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float selfForceMagnitude; public static float radius = 3f; public static GameObject hitEffectPrefab; public static GameObject swingEffectPrefab; public static string attackString; private OverlapAttack attack; private Animator modelAnimator; private float duration; private bool hasSlashed; private static int SwipeForwardStateHash = Animator.StringToHash("SwipeForward"); private static int SwipeForwardParamHash = Animator.StringToHash("SwipeForward.playbackRate"); private static int SwipeForwardHitboxActiveParamHash = Animator.StringToHash("SwipeForward.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); Util.PlaySound(attackString, base.gameObject); if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Sword"); } if ((bool)modelAnimator) { PlayAnimation("Gesture, Override", SwipeForwardStateHash, SwipeForwardParamHash, duration); PlayAnimation("Gesture, Additive", SwipeForwardStateHash, SwipeForwardParamHash, duration); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat(SwipeForwardHitboxActiveParamHash) > 0.1f) { if (!hasSlashed) { EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "SwingCenter", transmit: true); HealthComponent healthComponent = base.characterBody.healthComponent; CharacterDirection component = base.characterBody.GetComponent(); if ((bool)healthComponent) { healthComponent.TakeDamageForce(selfForceMagnitude * component.forward, alwaysApply: true); } hasSlashed = true; } attack.forceVector = base.transform.forward * forceMagnitude; attack.Fire(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.ClayGrenadier { public class FaceSlam : BaseState { public static float baseDuration = 3.5f; public static float baseDurationBeforeBlast = 1.5f; public static string animationLayerName = "Body"; public static string animationStateName = "FaceSlam"; public static string playbackRateParam = "FaceSlam.playbackRate"; private static int FaceSlamStateHash = Animator.StringToHash("FaceSlam"); private static int FaceSlamParamHash = Animator.StringToHash("FaceSlam.playbackRate"); public static GameObject chargeEffectPrefab; public static string chargeEffectMuzzleString; public static GameObject blastImpactEffect; public static float blastDamageCoefficient = 4f; public static float blastForceMagnitude = 16f; public static float blastUpwardForce; public static float blastRadius = 3f; public static string attackSoundString; public static string blastMuzzleString; public static GameObject projectilePrefab; public static float projectileDamageCoefficient; public static float projectileForce; public static float projectileSnapOnAngle; public static float healthCostFraction; private BlastAttack attack; private Animator modelAnimator; private Transform modelTransform; private bool hasFiredBlast; private float duration; private float durationBeforeBlast; private GameObject chargeInstance; public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); duration = baseDuration / attackSpeedStat; durationBeforeBlast = baseDurationBeforeBlast / attackSpeedStat; Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); PlayAnimation(animationLayerName, FaceSlamStateHash, FaceSlamParamHash, duration); if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } Transform transform = FindModelChild(chargeEffectMuzzleString); if ((bool)transform && (bool)chargeEffectPrefab) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeInstance.GetComponent(); if ((bool)component) { component.newDuration = durationBeforeBlast; } } } public override void OnExit() { if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > durationBeforeBlast && !hasFiredBlast) { hasFiredBlast = true; if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } UnityEngine.Vector3 footPosition = base.characterBody.footPosition; EffectManager.SpawnEffect(blastImpactEffect, new EffectData { origin = footPosition, scale = blastRadius }, transmit: true); if (NetworkServer.active && (bool)base.healthComponent) { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction; damageInfo.position = base.characterBody.corePosition; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.damageColorIndex = DamageColorIndex.Default; damageInfo.crit = false; damageInfo.attacker = null; damageInfo.inflictor = null; damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor; damageInfo.procCoefficient = 0f; damageInfo.procChainMask = default(ProcChainMask); base.healthComponent.TakeDamage(damageInfo); } if (base.isAuthority) { if ((bool)modelTransform) { Transform transform = FindModelChild(blastMuzzleString); if ((bool)transform) { attack = new BlastAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); attack.baseDamage = damageStat * blastDamageCoefficient; attack.baseForce = blastForceMagnitude; attack.position = transform.position; attack.radius = blastRadius; attack.bonusForce = new UnityEngine.Vector3(0f, blastUpwardForce, 0f); attack.damageType = DamageType.ClayGoo; attack.Fire(); } } UnityEngine.Vector3 position = footPosition; _ = UnityEngine.Vector3.up; if (Physics.Raycast(GetAimRay(), out var hitInfo, 1000f, LayerIndex.world.mask)) { position = hitInfo.point; } BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.viewer = base.characterBody; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; bullseyeSearch.teamMaskFilter.RemoveTeam(base.characterBody.teamComponent.teamIndex); bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle; bullseyeSearch.minDistanceFilter = 0f; bullseyeSearch.maxDistanceFilter = 1000f; bullseyeSearch.searchOrigin = base.inputBank.aimOrigin; bullseyeSearch.searchDirection = base.inputBank.aimDirection; bullseyeSearch.maxAngleFilter = projectileSnapOnAngle; bullseyeSearch.filterByLoS = false; bullseyeSearch.RefreshCandidates(); HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault(); if ((bool)hurtBox && (bool)hurtBox.healthComponent) { position = hurtBox.healthComponent.body.footPosition; } ProjectileManager.instance.FireProjectile(projectilePrefab, position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * projectileDamageCoefficient, projectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master)); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class SpawnState : BaseState { [SerializeField] public float duration; [SerializeField] public string spawnSoundString; [SerializeField] public GameObject spawnEffectPrefab; [SerializeField] public string spawnEffectChildString; [SerializeField] public float startingPrintBias; [SerializeField] public float maxPrintBias; [SerializeField] public float printDuration; [SerializeField] public float startingPrintHeight = 0.3f; [SerializeField] public float maxPrintHeight = 0.3f; [SerializeField] public string animationLayerName = "Body"; [SerializeField] public string animationStateName = "Spawn"; [SerializeField] public string playbackRateParam = "Spawn.playbackRate"; public override void OnEnter() { base.OnEnter(); EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectChildString, transmit: false); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration); PrintController printController = GetModelTransform().gameObject.AddComponent(); printController.printTime = printDuration; printController.enabled = true; printController.startingPrintHeight = startingPrintHeight; printController.maxPrintHeight = maxPrintHeight; printController.startingPrintBias = startingPrintBias; printController.maxPrintBias = maxPrintBias; printController.disableWhenFinished = true; printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class ThrowBarrel : GenericProjectileBaseState { [SerializeField] public float aimCalculationRaycastDistance; [SerializeField] public string animationLayerName = "Body"; [SerializeField] public string animationStateName = "FaceSlam"; [SerializeField] public string playbackRateParam = "FaceSlam.playbackRate"; [SerializeField] public int projectileCount; [SerializeField] public float projectilePitchBonusPerProjectile; [SerializeField] public float projectileYawBonusPerProjectile; [SerializeField] public GameObject chargeEffectPrefab; [SerializeField] public string chargeEffectMuzzleString; [SerializeField] public string enterSoundString; private GameObject chargeInstance; private int currentProjectileCount; protected override void PlayAnimation(float duration) { base.PlayAnimation(duration); PlayCrossfade(animationLayerName, animationStateName, playbackRateParam, duration, 0.2f); } public override void OnEnter() { base.OnEnter(); Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } base.characterBody.SetAimTimer(0f); Transform transform = FindModelChild(chargeEffectMuzzleString); if ((bool)transform && (bool)chargeEffectPrefab) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeInstance.transform.parent = transform; ScaleParticleSystemDuration component = chargeInstance.GetComponent(); if ((bool)component) { component.newDuration = delayBeforeFiringProjectile; } } } protected override Ray ModifyProjectileAimRay(Ray aimRay) { RaycastHit hitInfo = default(RaycastHit); Ray ray = aimRay; float desiredForwardSpeed = projectilePrefab.GetComponent().desiredForwardSpeed; ray.origin = aimRay.origin; if (Util.CharacterRaycast(base.gameObject, ray, out hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) { float num = desiredForwardSpeed; UnityEngine.Vector3 vector = hitInfo.point - aimRay.origin; UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z); float magnitude = vector2.magnitude; float y = Trajectory.CalculateInitialYSpeed(magnitude / num, vector.y); UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(vector2.x / magnitude * num, y, vector2.y / magnitude * num); desiredForwardSpeed = vector3.magnitude; aimRay.direction = vector3 / desiredForwardSpeed; } aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, projectileYawBonusPerProjectile * (float)currentProjectileCount, projectilePitchBonusPerProjectile * (float)currentProjectileCount); return aimRay; } protected override void FireProjectile() { for (int i = 0; i < projectileCount; i++) { base.FireProjectile(); currentProjectileCount++; } if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } } public override void OnExit() { if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } base.OnExit(); } } } namespace EntityStates.ClayBruiser.Weapon { public class MinigunState : BaseState { public static string muzzleName; private static readonly BuffDef slowBuff = RoR2Content.Buffs.Slow50; protected Transform muzzleTransform; protected ref InputBankTest.ButtonState skillButtonState => ref base.inputBank.skill1; public override void OnEnter() { base.OnEnter(); muzzleTransform = FindModelChild(muzzleName); if (NetworkServer.active && (bool)base.characterBody) { base.characterBody.AddBuff(slowBuff); } } public override void FixedUpdate() { base.FixedUpdate(); StartAimMode(); } public override void OnExit() { if (NetworkServer.active && (bool)base.characterBody) { base.characterBody.RemoveBuff(slowBuff); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class MinigunSpinUp : MinigunState { public static float baseDuration; public static string sound; public static GameObject chargeEffectPrefab; private GameObject chargeInstance; private float duration; private static int WeaponIsReadyParamHash = Animator.StringToHash("WeaponIsReady"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(sound, base.gameObject); GetModelAnimator().SetBool(WeaponIsReadyParamHash, value: true); if ((bool)muzzleTransform && (bool)chargeEffectPrefab) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation); chargeInstance.transform.parent = muzzleTransform; ScaleParticleSystemDuration component = chargeInstance.GetComponent(); if ((bool)component) { component.newDuration = duration; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new MinigunFire()); } } public override void OnExit() { base.OnExit(); if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } } } public class MinigunSpinDown : MinigunState { public static float baseDuration; public static string sound; private float duration; private static int WeaponIsReadyParamHash = Animator.StringToHash("WeaponIsReady"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(sound, base.gameObject, attackSpeedStat); GetModelAnimator().SetBool(WeaponIsReadyParamHash, value: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class MinigunFire : MinigunState { public static GameObject muzzleVfxPrefab; public static float baseFireInterval; public static int baseBulletCount; public static float baseDamagePerSecondCoefficient; public static float baseForcePerSecond; public static float baseProcCoefficientPerSecond; public static float bulletMinSpread; public static float bulletMaxSpread; public static GameObject bulletTracerEffectPrefab; public static GameObject bulletHitEffectPrefab; public static bool bulletHitEffectNormal; public static float bulletMaxDistance; public static string fireSound; public static string startSound; public static string endSound; private float fireTimer; private Transform muzzleVfxTransform; private float baseFireRate; private float baseBulletsPerSecond; private Run.FixedTimeStamp critEndTime; private Run.FixedTimeStamp lastCritCheck; public override void OnEnter() { base.OnEnter(); if ((bool)muzzleTransform && (bool)muzzleVfxPrefab) { muzzleVfxTransform = UnityEngine.Object.Instantiate(muzzleVfxPrefab, muzzleTransform).transform; } baseFireRate = 1f / baseFireInterval; baseBulletsPerSecond = (float)baseBulletCount * baseFireRate; critEndTime = Run.FixedTimeStamp.negativeInfinity; lastCritCheck = Run.FixedTimeStamp.negativeInfinity; Util.PlaySound(startSound, base.gameObject); PlayCrossfade("Gesture, Additive", "FireMinigun", 0.2f); } private void UpdateCrits() { if (lastCritCheck.timeSince >= 1f) { lastCritCheck = Run.FixedTimeStamp.now; if (RollCrit()) { critEndTime = Run.FixedTimeStamp.now + 2f; } } } public override void OnExit() { Util.PlaySound(endSound, base.gameObject); if ((bool)muzzleVfxTransform) { EntityState.Destroy(muzzleVfxTransform.gameObject); muzzleVfxTransform = null; } PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.2f); base.OnExit(); } private void OnFireShared() { Util.PlaySound(fireSound, base.gameObject); if (base.isAuthority) { OnFireAuthority(); } } private void OnFireAuthority() { UpdateCrits(); bool isCrit = !critEndTime.hasPassed; float damage = baseDamagePerSecondCoefficient / baseBulletsPerSecond * damageStat; float force = baseForcePerSecond / baseBulletsPerSecond; float procCoefficient = baseProcCoefficientPerSecond / baseBulletsPerSecond; Ray aimRay = GetAimRay(); BulletAttack bulletAttack = new BulletAttack(); bulletAttack.bulletCount = (uint)baseBulletCount; bulletAttack.aimVector = aimRay.direction; bulletAttack.origin = aimRay.origin; bulletAttack.damage = damage; bulletAttack.damageColorIndex = DamageColorIndex.Default; bulletAttack.damageType = DamageType.Generic; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.maxDistance = bulletMaxDistance; bulletAttack.force = force; bulletAttack.hitMask = LayerIndex.CommonMasks.bullet; bulletAttack.minSpread = bulletMinSpread; bulletAttack.maxSpread = bulletMaxSpread; bulletAttack.isCrit = isCrit; bulletAttack.owner = base.gameObject; bulletAttack.muzzleName = MinigunState.muzzleName; bulletAttack.smartCollision = false; bulletAttack.procChainMask = default(ProcChainMask); bulletAttack.procCoefficient = procCoefficient; bulletAttack.radius = 0f; bulletAttack.sniper = false; bulletAttack.stopperMask = LayerIndex.CommonMasks.bullet; bulletAttack.weapon = null; bulletAttack.tracerEffectPrefab = bulletTracerEffectPrefab; bulletAttack.spreadPitchScale = 1f; bulletAttack.spreadYawScale = 1f; bulletAttack.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal; bulletAttack.hitEffectPrefab = bulletHitEffectPrefab; bulletAttack.HitEffectNormal = bulletHitEffectNormal; bulletAttack.Fire(); } public override void FixedUpdate() { base.FixedUpdate(); fireTimer -= GetDeltaTime(); if (fireTimer <= 0f) { float num = baseFireInterval / attackSpeedStat; fireTimer += num; OnFireShared(); } if (base.isAuthority && !base.skillButtonState.down) { outer.SetNextState(new MinigunSpinDown()); } } } public class FireSonicBoom : EntityStates.Treebot.Weapon.FireSonicBoom { private static int WeaponIsReadyParamHash = Animator.StringToHash("WeaponIsReady"); public override void OnEnter() { base.OnEnter(); GetModelAnimator().SetBool(WeaponIsReadyParamHash, value: true); } protected override void AddDebuff(CharacterBody body) { body.AddTimedBuff(RoR2Content.Buffs.ClayGoo, slowDuration); } public override void OnExit() { if (!outer.destroying) { GetModelAnimator().SetBool(WeaponIsReadyParamHash, value: false); } base.OnExit(); } } } namespace EntityStates.ClayBruiserMonster { public class SpawnState : BaseState { public static float duration; public static string spawnSoundString; public static GameObject spawnEffectPrefab; public static string spawnEffectChildString; public static float startingPrintBias; public static float maxPrintBias; public static float printDuration; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectChildString, transmit: false); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); PrintController printController = GetModelTransform().gameObject.AddComponent(); printController.printTime = printDuration; printController.enabled = true; printController.startingPrintHeight = 0.3f; printController.maxPrintHeight = 0.3f; printController.startingPrintBias = startingPrintBias; printController.maxPrintBias = maxPrintBias; printController.disableWhenFinished = true; printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.ClayBoss { public class DeathState : GenericCharacterDeath { public static GameObject initialEffect; public static GameObject deathEffect; public static float duration = 2f; private float stopwatch; private Transform modelBaseTransform; private Transform centerTransform; private EffectData _effectData; private EffectManagerHelper _emh_initialEffect; private bool attemptedDeathBehavior; public override void Reset() { base.Reset(); stopwatch = 0f; modelBaseTransform = null; centerTransform = null; attemptedDeathBehavior = false; if (_effectData != null) { _effectData.Reset(); } _emh_initialEffect = null; } public override void OnEnter() { base.OnEnter(); if (!base.modelLocator) { return; } ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if ((bool)component) { centerTransform = component.FindChild("Center"); if ((bool)initialEffect) { if (!EffectManager.ShouldUsePooledEffect(initialEffect)) { GameObject obj = UnityEngine.Object.Instantiate(initialEffect, centerTransform.position, centerTransform.rotation); obj.GetComponent().newDuration = duration; obj.transform.parent = centerTransform; } else { _emh_initialEffect = EffectManager.GetAndActivatePooledEffect(initialEffect, centerTransform.position, centerTransform.rotation, centerTransform); _emh_initialEffect.gameObject.GetComponent().newDuration = duration; } } } modelBaseTransform = base.modelLocator.modelBaseTransform; } private void AttemptDeathBehavior() { if (attemptedDeathBehavior) { return; } attemptedDeathBehavior = true; CleanupInitialEffect(); if ((bool)deathEffect && NetworkServer.active) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.origin = centerTransform.position; EffectManager.SpawnEffect(deathEffect, _effectData, transmit: true); } if ((bool)modelBaseTransform) { EntityState.Destroy(modelBaseTransform.gameObject); modelBaseTransform = null; } if (NetworkServer.active) { EntityState.Destroy(base.gameObject); } } public override void FixedUpdate() { stopwatch += GetDeltaTime(); if (stopwatch >= duration) { AttemptDeathBehavior(); } } public override void OnExit() { if (!outer.destroying) { AttemptDeathBehavior(); } else { CleanupInitialEffect(); } base.OnExit(); } public void CleanupInitialEffect() { if (_emh_initialEffect != null && _emh_initialEffect.OwningPool != null) { _emh_initialEffect.OwningPool.ReturnObject(_emh_initialEffect); _emh_initialEffect = null; } } } public class FireTarball : BaseState { public static GameObject effectPrefab; public static GameObject projectilePrefab; public static int tarballCountMax = 3; public static float damageCoefficient; public static float baseTimeBetweenShots = 1f; public static float cooldownDuration = 2f; public static float recoilAmplitude = 1f; public static string attackSoundString; public static float spreadBloomValue = 0.3f; private int tarballCount; private Ray aimRay; private Transform modelTransform; private float duration; private float fireTimer; private float timeBetweenShots; private void FireSingleTarball(string targetMuzzle) { PlayCrossfade("Body", "FireTarBall", 0.1f); Util.PlaySound(attackSoundString, base.gameObject); aimRay = GetAimRay(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { aimRay.origin = transform.position; } } } AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: true); } if (base.isAuthority) { UnityEngine.Vector3 forward = UnityEngine.Vector3.ProjectOnPlane(aimRay.direction, UnityEngine.Vector3.up); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnEnter() { base.OnEnter(); timeBetweenShots = baseTimeBetweenShots / attackSpeedStat; duration = (baseTimeBetweenShots * (float)tarballCountMax + cooldownDuration) / attackSpeedStat; modelTransform = GetModelTransform(); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); fireTimer -= GetDeltaTime(); if (fireTimer <= 0f) { if (tarballCount < tarballCountMax) { fireTimer += timeBetweenShots; FireSingleTarball("BottomMuzzle"); tarballCount++; } else { fireTimer += 9999f; PlayCrossfade("Body", "ExitTarBall", "ExitTarBall.playbackRate", (cooldownDuration - baseTimeBetweenShots) / attackSpeedStat, 0.1f); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class PrepTarBall : BaseState { public static float baseDuration = 3f; public static string prepTarBallSoundString; private float duration; private float stopwatch; private Animator modelAnimator; public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayCrossfade("Body", "PrepTarBall", "PrepTarBall.playbackRate", duration, 0.5f); } if (!string.IsNullOrEmpty(prepTarBallSoundString)) { Util.PlayAttackSpeedSound(prepTarBallSoundString, base.gameObject, attackSpeedStat); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextState(new FireTarball()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Recover : BaseState { private enum SubState { Entry, Tethers } public static float duration = 15f; public static float maxTetherDistance = 40f; public static float tetherMulchDistance = 5f; public static float tetherMulchDamageScale = 2f; public static float tetherMulchTickIntervalScale = 0.5f; public static float damagePerSecond = 2f; public static float damageTickFrequency = 3f; public static float entryDuration = 1f; public static GameObject mulchEffectPrefab; public static string enterSoundString; public static string beginMulchSoundString; public static string stopMulchSoundString; private GameObject mulchEffect; private Transform muzzleTransform; private List tetherControllers; private List victimsList; private BullseyeSearch search; private float stopwatch; private uint soundID; private EffectManagerHelper _emh_mulchEffect; private SubState subState; private static int ChannelSiphonStateHash = Animator.StringToHash("ChannelSiphon"); public override void Reset() { base.Reset(); mulchEffect = null; muzzleTransform = null; if (tetherControllers != null) { tetherControllers.Clear(); } if (victimsList != null) { victimsList.Clear(); } if (search != null) { search.Reset(); } soundID = 0u; subState = SubState.Entry; _emh_mulchEffect = null; } public override void OnEnter() { base.OnEnter(); stopwatch = 0f; if (NetworkServer.active && (bool)base.characterBody) { base.characterBody.AddBuff(RoR2Content.Buffs.ArmorBoost); } if ((bool)base.modelLocator) { ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if ((bool)component) { muzzleTransform = component.FindChild("MuzzleMulch"); } } subState = SubState.Entry; PlayCrossfade("Body", "PrepSiphon", "PrepSiphon.playbackRate", entryDuration, 0.1f); soundID = Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); } private void FireTethers() { UnityEngine.Vector3 position = muzzleTransform.position; float breakDistanceSqr = maxTetherDistance * maxTetherDistance; if (victimsList == null) { victimsList = new List(); } tetherControllers = new List(); if (search == null) { search = new BullseyeSearch(); } search.searchOrigin = position; search.maxDistanceFilter = maxTetherDistance; search.teamMaskFilter = TeamMask.allButNeutral; search.sortMode = BullseyeSearch.SortMode.Distance; search.filterByLoS = true; search.searchDirection = UnityEngine.Vector3.up; search.RefreshCandidates(); search.FilterOutGameObject(base.gameObject); List list = search.GetResults().ToList(); for (int i = 0; i < list.Count; i++) { GameObject gameObject = list[i].healthComponent.gameObject; if ((bool)gameObject) { victimsList.Add(gameObject); } } float tickInterval = 1f / damageTickFrequency; float damageCoefficientPerTick = damagePerSecond / damageTickFrequency; float mulchDistanceSqr = tetherMulchDistance * tetherMulchDistance; GameObject original = LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/TarTether"); for (int j = 0; j < victimsList.Count; j++) { GameObject obj = UnityEngine.Object.Instantiate(original, position, UnityEngine.Quaternion.identity); TarTetherController component = obj.GetComponent(); component.NetworkownerRoot = base.gameObject; component.NetworktargetRoot = victimsList[j]; component.breakDistanceSqr = breakDistanceSqr; component.damageCoefficientPerTick = damageCoefficientPerTick; component.tickInterval = tickInterval; component.tickTimer = (float)j * 0.1f; component.mulchDistanceSqr = mulchDistanceSqr; component.mulchDamageScale = tetherMulchDamageScale; component.mulchTickIntervalScale = tetherMulchTickIntervalScale; tetherControllers.Add(component); NetworkServer.Spawn(obj); } } private void DestroyTethers() { if (tetherControllers == null) { return; } for (int num = tetherControllers.Count - 1; num >= 0; num--) { if ((bool)tetherControllers[num]) { EntityState.Destroy(tetherControllers[num].gameObject); } } } public override void OnExit() { DestroyTethers(); if ((bool)mulchEffect) { if ((bool)_emh_mulchEffect && _emh_mulchEffect.OwningPool != null) { _emh_mulchEffect.ReturnToPool(); _emh_mulchEffect = null; } else { EntityState.Destroy(mulchEffect); } } AkSoundEngine.StopPlayingID(soundID); Util.PlaySound(stopMulchSoundString, base.gameObject); if (NetworkServer.active && (bool)base.characterBody) { base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost); } base.OnExit(); } private static void RemoveDeadTethersFromList(List tethersList) { for (int num = tethersList.Count - 1; num >= 0; num--) { if (!tethersList[num]) { tethersList.RemoveAt(num); } } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (subState == SubState.Entry) { if (stopwatch >= entryDuration) { subState = SubState.Tethers; stopwatch = 0f; PlayAnimation("Body", ChannelSiphonStateHash); Util.PlaySound(beginMulchSoundString, base.gameObject); SpawnMulcherEffect(); if (NetworkServer.active) { FireTethers(); } } } else if (subState == SubState.Tethers && NetworkServer.active) { RemoveDeadTethersFromList(tetherControllers); if ((stopwatch >= duration || tetherControllers.Count == 0) && base.isAuthority) { outer.SetNextState(new RecoverExit()); } } } private void SpawnMulcherEffect() { if (!EffectManager.ShouldUsePooledEffect(mulchEffectPrefab)) { mulchEffect = UnityEngine.Object.Instantiate(mulchEffectPrefab, muzzleTransform.position, UnityEngine.Quaternion.identity); } else { _emh_mulchEffect = EffectManager.GetAndActivatePooledEffect(mulchEffectPrefab, muzzleTransform.position, UnityEngine.Quaternion.identity); mulchEffect = _emh_mulchEffect.gameObject; } ChildLocator component = mulchEffect.gameObject.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("AreaIndicator"); if ((bool)transform) { transform.localScale = new UnityEngine.Vector3(maxTetherDistance * 2f, maxTetherDistance * 2f, maxTetherDistance * 2f); } } mulchEffect.transform.parent = muzzleTransform; } } public class RecoverExit : BaseState { public static float exitDuration = 1f; private float stopwatch; private static int ExitSiphonStateHash = Animator.StringToHash("ExitSiphon"); private static int ExitSiphonParamHash = Animator.StringToHash("ExitSiphon.playbackRate"); public override void OnEnter() { base.OnEnter(); stopwatch = 0f; PlayAnimation("Body", ExitSiphonStateHash, ExitSiphonParamHash, exitDuration); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= exitDuration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class SpawnState : BaseState { public static float duration; public static string spawnSoundString; public static GameObject spawnEffectPrefab; public static string spawnEffectChildString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); ChildLocator component = GetModelTransform().GetComponent(); if ((bool)component) { Transform transform = component.FindChild(spawnEffectChildString); if ((bool)transform) { UnityEngine.Object.Instantiate(spawnEffectPrefab, transform.position, UnityEngine.Quaternion.identity); } } Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.ClayBoss.ClayBossWeapon { public class ChargeBombardment : BaseState { public static float baseTotalDuration; public static float baseMaxChargeTime; public static int maxCharges; public static GameObject chargeEffectPrefab; public static string chargeLoopStartSoundString; public static string chargeLoopStopSoundString; public static int minGrenadeCount; public static int maxGrenadeCount; public static float minBonusBloom; public static float maxBonusBloom; private float stopwatch; private GameObject chargeInstance; private int charge; private float totalDuration; private float maxChargeTime; private EffectManagerHelper _emh_chargeInstance; private static int ChargeBombardmentStateHash = Animator.StringToHash("ChargeBombardment"); private static int EmptyStateHash = Animator.StringToHash("Empty"); public override void Reset() { base.Reset(); stopwatch = 0f; chargeInstance = null; charge = 0; totalDuration = 0f; maxChargeTime = 0f; _emh_chargeInstance = null; } public override void OnEnter() { base.OnEnter(); totalDuration = baseTotalDuration / attackSpeedStat; maxChargeTime = baseMaxChargeTime / attackSpeedStat; Transform modelTransform = GetModelTransform(); PlayAnimation("Gesture, Additive", ChargeBombardmentStateHash); Util.PlaySound(chargeLoopStartSoundString, base.gameObject); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("Muzzle"); if ((bool)transform && (bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation); chargeInstance = _emh_chargeInstance.gameObject; } chargeInstance.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeInstance.GetComponent(); if ((bool)component2) { component2.newDuration = totalDuration; } } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(totalDuration); } } public override void OnExit() { base.OnExit(); PlayAnimation("Gesture, Additive", EmptyStateHash); Util.PlaySound(chargeLoopStopSoundString, base.gameObject); if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null) { _emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance); } else { EntityState.Destroy(chargeInstance); } _emh_chargeInstance = null; chargeInstance = null; } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); charge = Mathf.Min((int)(stopwatch / maxChargeTime * (float)maxCharges), maxCharges); float t = (float)charge / (float)maxCharges; float value = Mathf.Lerp(minBonusBloom, maxBonusBloom, t); base.characterBody.SetSpreadBloom(value); int grenadeCountMax = Mathf.FloorToInt(Mathf.Lerp(minGrenadeCount, maxGrenadeCount, t)); if ((stopwatch >= totalDuration || !base.inputBank || !base.inputBank.skill1.down) && base.isAuthority) { FireBombardment fireBombardment = new FireBombardment(); fireBombardment.grenadeCountMax = grenadeCountMax; outer.SetNextState(fireBombardment); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireBombardment : BaseState { public static GameObject effectPrefab; public static GameObject projectilePrefab; public int grenadeCountMax = 3; public static float damageCoefficient; public static float baseTimeBetweenShots = 1f; public static float cooldownDuration = 2f; public static float arcAngle = 5f; public static float recoilAmplitude = 1f; public static string shootSoundString; public static float spreadBloomValue = 0.3f; private Ray aimRay; private Transform modelTransform; private float duration; private float fireTimer; private int grenadeCount; private float timeBetweenShots; private void FireGrenade(string targetMuzzle) { PlayCrossfade("Gesture, Bombardment", "FireBombardment", 0.1f); Util.PlaySound(shootSoundString, base.gameObject); aimRay = GetAimRay(); UnityEngine.Vector3 vector = aimRay.origin; if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { vector = transform.position; } } } AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: true); } if (base.isAuthority) { float num = -1f; if (Util.CharacterRaycast(base.gameObject, aimRay, out var hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) { UnityEngine.Vector3 point = hitInfo.point; float velocity = projectilePrefab.GetComponent().velocity; UnityEngine.Vector3 vector2 = point - vector; UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z); float magnitude = vector3.magnitude; float y = Trajectory.CalculateInitialYSpeed(magnitude / velocity, vector2.y); UnityEngine.Vector3 vector4 = new UnityEngine.Vector3(vector3.x / magnitude * velocity, y, vector3.y / magnitude * velocity); num = vector4.magnitude; aimRay.direction = vector4 / num; } float x = UnityEngine.Random.Range(0f, base.characterBody.spreadBloomAngle); float z = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 up = UnityEngine.Vector3.up; UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction); UnityEngine.Vector3 vector5 = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward); float y2 = vector5.y; vector5.y = 0f; float angle = Mathf.Atan2(vector5.z, vector5.x) * 57.29578f - 90f; float angle2 = Mathf.Atan2(y2, vector5.magnitude) * 57.29578f; UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction); ProjectileManager.instance.FireProjectile(projectilePrefab, vector, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, num); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnEnter() { base.OnEnter(); timeBetweenShots = baseTimeBetweenShots / attackSpeedStat; duration = (baseTimeBetweenShots * (float)grenadeCount + cooldownDuration) / attackSpeedStat; PlayCrossfade("Gesture, Additive", "BeginBombardment", 0.1f); modelTransform = GetModelTransform(); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void OnExit() { PlayCrossfade("Gesture, Additive", "EndBombardment", 0.1f); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { fireTimer -= GetDeltaTime(); if (fireTimer <= 0f && grenadeCount < grenadeCountMax) { fireTimer += timeBetweenShots; FireGrenade("Muzzle"); grenadeCount++; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.ChildMonster { public class DeathState : GenericCharacterDeath { public static GameObject deathEffectPrefab; public float smallHopVelocity = 0.35f; private bool blewUp; public float duration = 0.2f; public static string deathSoundString; public override void OnEnter() { base.OnEnter(); SmallHop(base.characterMotor, smallHopVelocity); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && !blewUp && base.fixedAge > duration) { EffectManager.SpawnEffect(deathEffectPrefab, new EffectData { origin = base.characterBody.corePosition }, transmit: true); Util.PlaySound(deathSoundString, base.gameObject); blewUp = true; } if (base.fixedAge > duration * 2f) { DestroyBodyAsapServer(); } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class Frolic : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static GameObject tpEffectPrefab; public static float baseDuration = 2f; public static float damageCoefficient = 1.2f; public static float force = 20f; public static string attackString; public static float tpDuration = 0.5f; public static float fireFrolicDuration = 0.3f; public static float frolicCooldownDuration = 18f; private float duration; private bool frolicFireFired; private bool tpFired; private bool cantFrolic; public override void OnEnter() { base.OnEnter(); ChildMonsterController component = base.characterBody.GetComponent(); cantFrolic = !component.CheckTeleportAvailable(); if (!cantFrolic) { component.RegisterTeleport(); fireFrolicDuration += tpDuration; duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Override", "FrolicEnter", "FrolicEnter.playbackRate", 1f); Util.PlaySound(attackString, base.gameObject); } } public override void FixedUpdate() { base.FixedUpdate(); if (cantFrolic) { outer.SetNextStateToMain(); return; } if (base.fixedAge > tpDuration && !tpFired) { FireTPEffect(); tpFired = true; TeleportAroundPlayer(); } if (base.fixedAge > fireFrolicDuration && !frolicFireFired) { frolicFireFired = true; FireTPEffect(); Transform transform = base.characterBody.master.GetComponent().currentEnemy.characterBody.transform; base.characterBody.transform.LookAt(transform.position); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public void TeleportAroundPlayer() { GetComponent().modelTransform.GetComponent(); _ = base.characterBody.corePosition; NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); UnityEngine.Vector3 position = base.characterBody.master.GetComponent().currentEnemy.characterBody.coreTransform.position; List list = nodeGraph.FindNodesInRange(position, 25f, 37f, HullMask.Human); UnityEngine.Vector3 position2 = default(UnityEngine.Vector3); bool flag = false; int num = 35; while (!flag) { NodeGraph.NodeIndex nodeIndex = list.ElementAt(UnityEngine.Random.Range(1, list.Count)); nodeGraph.GetNodePosition(nodeIndex, out position2); float num2 = UnityEngine.Vector3.Distance(base.characterBody.coreTransform.position, position2); num--; if (num2 > 35f || num < 0) { flag = true; } } if (num < 0) { UnityEngine.Debug.LogWarning("Child.Frolic state entered a loop where it ran more than 35 times without getting out - check what it's doing"); } position2 += UnityEngine.Vector3.up * 1.5f; TeleportHelper.TeleportBody(base.characterBody, position2); } public void FireTPEffect() { UnityEngine.Vector3 position = FindModelChild("Chest").transform.position; EffectManager.SpawnEffect(tpEffectPrefab, new EffectData { origin = position, scale = 1f }, transmit: true); Util.PlaySound("Play_child_attack2_reappear", base.gameObject); } } public class FrolicAway : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static GameObject tpEffectPrefab; public static float baseDuration = 2f; public static float damageCoefficient = 1.2f; public static float force = 20f; public static string attackString; public static float tpDuration = 0.5f; public static float fireFrolicDuration = 0.3f; private float duration; private bool frolicFireFired; private bool tpFired; public override void OnEnter() { base.OnEnter(); fireFrolicDuration += tpDuration; base.characterBody.GetComponent()?.RegisterTeleport(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Override", "FrolicEnter", "FrolicEnter.playbackRate", 1f); Util.PlaySound(attackString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > tpDuration && !tpFired) { FireTPEffect(); tpFired = true; TeleportAway(); } if (base.fixedAge > fireFrolicDuration && !frolicFireFired) { frolicFireFired = true; FireTPEffect(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public void TeleportAway() { CharacterModel component = GetComponent().modelTransform.GetComponent(); _ = base.characterBody.corePosition; NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); List source = nodeGraph.FindNodesInRange(base.characterBody.corePosition, 100f, 200f, HullMask.Human); nodeGraph.GetNodePosition(source.First(), out var position); TeleportHelper.TeleportBody(base.characterBody, position); TeleportOutController.AddTPOutEffect(component, 1f, 0f, 1f); if ((bool)tpEffectPrefab) { FireTPEffect(); } } public void FireTPEffect() { UnityEngine.Vector3 position = FindModelChild("Chest").transform.position; EffectManager.SpawnEffect(tpEffectPrefab, new EffectData { origin = position, scale = 1f }, transmit: true); Util.PlaySound("Play_child_attack2_reappear", base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class SparkBallCharge : BaseState { public static float baseDuration = 3f; public static GameObject chargingEffectPrefab; public static string chargingSoundString; private float duration; private float stopwatch; private GameObject chargeEffectInstance; private uint soundID; public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); PlayCrossfade("Gesture, Override", "SparkEnter", "SparkEnter.playbackRate", duration, 0.3f); soundID = Util.PlayAttackSpeedSound(chargingSoundString, base.gameObject, attackSpeedStat); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("MuzzleFire"); if ((bool)transform && (bool)chargingEffectPrefab) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargingEffectPrefab, transform.position, transform.rotation); chargeEffectInstance.transform.parent = transform; chargeEffectInstance.GetComponent().newDuration = duration; } } } public override void OnExit() { base.OnExit(); AkSoundEngine.StopPlayingID(soundID); if ((bool)chargeEffectInstance) { EntityState.Destroy(chargeEffectInstance); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextState(new SparkBallFire()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class SparkBallFire : BaseState { public static float baseDuration = 3f; public static GameObject projectilePrefab; public static GameObject muzzleEffectPrefab; public static string fireBombSoundString; public static float bombDamageCoefficient; public static float bombForce; public float novaRadius; private float duration; private float stopwatch; public override void OnEnter() { base.OnEnter(); stopwatch = 0f; duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture, Override", "SparkLaunch", "SparkLaunch.playbackRate", duration); FireBomb(); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireBomb() { Ray aimRay = GetAimRay(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { aimRay.origin = component.FindChild("MuzzleFire").transform.position; } } EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "MuzzleFire", transmit: false); if (base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * bombDamageCoefficient, bombForce, Util.CheckRoll(critStat, base.characterBody.master)); } } } public class SpawnState : EntityState { public static float duration = 1f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private ParentEnergyFXController FXController; public override void OnEnter() { base.OnEnter(); GetModelAnimator(); PlayAnimation("Gesture, Override", "FrolicEnter", "FrolicEnter.playbackRate", duration); Util.PlaySound(spawnSoundString, base.gameObject); if ((bool)spawnEffectPrefab) { EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData { origin = base.gameObject.transform.position }, transmit: true); } PrintController component = base.modelLocator.modelTransform.gameObject.GetComponent(); component.enabled = false; component.printTime = duration; component.startingPrintHeight = 4f; component.maxPrintHeight = -1f; component.startingPrintBias = 2f; component.maxPrintBias = 0.95f; component.disableWhenFinished = true; component.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); component.enabled = true; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Chef { public class ChargeRolyPoly : BaseSkillState { [SerializeField] public float baseDuration; [SerializeField] public float baseChargeDuration = 1f; [SerializeField] public float minChargeForChargedAttack = 0.1f; [SerializeField] public float walkSpeedCoefficient; [SerializeField] public GameObject skiddingVFX1; [SerializeField] public string chargeLevelSFX1; [SerializeField] public string chargeLevelSFX2; [SerializeField] public string chargeLevelSFX3; [SerializeField] public float explosionDmgCoefficient; [SerializeField] public float dmgIncreasePercent; [SerializeField] public float explosionForce; [SerializeField] public UnityEngine.Vector3 extraExplosionForce; [SerializeField] public float explosionRadius; [SerializeField] public GameObject explosionPrefab1; [SerializeField] public GameObject explosionPrefab2; [SerializeField] public GameObject explosionPrefab3; [SerializeField] public float explodeRadiusVFX; private float duration; private GameObject explosionPrefab; private int gearShifLevel; private GameObject chargeLevelVFXBase; private bool chargeAnimPlayed; private float gearToChargeProgress = 0.3f; private bool obtainedGear1; private bool obtainedGear2; private bool obtainedGear3; private Transform modelTransform; private EffectManagerHelper rolyPolyChargeFXReference; private bool hasBoost; private bool useRootMotion; private bool hasCharacterMotor; private bool hasRailMotor; private bool hasCharacterDirection; private bool hasAimAnimator; private AimAnimator aimAnimator; private UnityEngine.Vector3 moveVector = UnityEngine.Vector3.zero; private UnityEngine.Vector3 aimDirection = UnityEngine.Vector3.forward; private ChefController chefController; protected float charge { get; private set; } protected float chargeDuration { get; private set; } public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { chefController = base.characterBody.GetComponent(); if (chefController != null) { chefController.blockOtherSkills = true; } EntityStateMachine.FindByCustomName(base.gameObject, "Weapon").SetNextState(new RolyPolyWeaponBlockingState()); } bool active = NetworkServer.active; chargeDuration = baseChargeDuration / attackSpeedStat; if (base.characterBody.HasBuff(DLC2Content.Buffs.Boosted)) { hasBoost = true; if (active) { base.characterBody.RemoveBuff(DLC2Content.Buffs.Boosted); } } if (active) { base.characterBody.AddBuff(RoR2Content.Buffs.ArmorBoost); } base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient; PlayAnimation("Body", "ChargeRolyPoly", "ChargeRolyPoly.playbackRate", 1f); new EffectData { origin = base.transform.position, scale = 1f }; modelTransform = GetModelTransform(); ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform inTransform = component.FindChild("Base"); rolyPolyChargeFXReference = EffectManager.GetAndActivatePooledEffect(skiddingVFX1, inTransform, inResetLocal: true); } useRootMotion = ((bool)base.characterBody && base.characterBody.rootMotionInMainState && base.isGrounded) || (bool)base.railMotor; hasCharacterMotor = base.characterMotor; hasRailMotor = base.railMotor; hasCharacterDirection = base.characterDirection; Util.PlaySound("Play_chef_skill3_charge_start", base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); charge = Mathf.Clamp01(base.fixedAge / chargeDuration); base.characterBody.SetSpreadBloom(charge); base.characterBody.SetAimTimer(3f); if (charge >= minChargeForChargedAttack && charge != 1f && charge >= gearToChargeProgress) { gearToChargeProgress += 0.3f; explosionDmgCoefficient += explosionDmgCoefficient * dmgIncreasePercent; GearShift(); } if (base.isAuthority) { AuthorityFixedUpdate(); } } private void GearShift() { switch (gearShifLevel) { case 0: explosionPrefab = explosionPrefab1; Util.PlaySound(chargeLevelSFX1, base.gameObject); break; case 1: explosionPrefab = explosionPrefab2; Util.PlaySound(chargeLevelSFX2, base.gameObject); break; case 2: explosionPrefab = explosionPrefab3; Util.PlaySound(chargeLevelSFX3, base.gameObject); break; } EffectManager.SpawnEffect(explosionPrefab, new EffectData { origin = base.characterBody.footPosition, scale = explosionRadius * explodeRadiusVFX }, transmit: true); gearShifLevel++; BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.characterBody.gameObject; blastAttack.baseDamage = explosionDmgCoefficient * base.characterBody.damage; blastAttack.baseForce = explosionForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = base.characterBody.RollCrit(); blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.damageType = DamageType.SlowOnHit; blastAttack.inflictor = base.gameObject; blastAttack.position = base.transform.position; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = 1f; blastAttack.radius = explosionRadius; blastAttack.teamIndex = base.characterBody.teamComponent.teamIndex; blastAttack.bonusForce = extraExplosionForce; blastAttack.Fire(); } private void AuthorityFixedUpdate() { if (base.inputBank.skill3.justReleased || charge > 0.9f) { if (charge >= 0.9f) { charge = 3f; } else if (charge >= 0.6f) { charge = 2f; } else if (charge >= 0.3f) { charge = 1f; } else { charge = 0f; } outer.SetNextState(GetNextStateAuthority()); } else { HandleRotation(); } } private void HandleRotation() { moveVector = base.inputBank.moveVector; aimDirection = base.inputBank.aimDirection; if (useRootMotion) { if (hasCharacterMotor) { base.characterMotor.moveDirection = UnityEngine.Vector3.zero; } if (hasRailMotor) { base.railMotor.inputMoveVector = moveVector; } } else { if (hasCharacterMotor) { base.characterMotor.moveDirection = moveVector; } if (hasRailMotor) { base.railMotor.inputMoveVector = moveVector; } } if (!hasRailMotor && hasCharacterDirection) { if (hasAimAnimator && aimAnimator.aimType == AimAnimator.AimType.Smart) { UnityEngine.Vector3 vector = ((moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : moveVector); float num = UnityEngine.Vector3.Angle(aimDirection, vector); float num2 = Mathf.Max(aimAnimator.pitchRangeMax + aimAnimator.pitchGiveupRange, aimAnimator.yawRangeMax + aimAnimator.yawGiveupRange); base.characterDirection.moveVector = (((bool)base.characterBody && base.characterBody.shouldAim && num > num2) ? aimDirection : vector); } else { base.characterDirection.moveVector = (((bool)base.characterBody && base.characterBody.shouldAim) ? aimDirection : moveVector); } } } public override void OnExit() { if (rolyPolyChargeFXReference != null) { rolyPolyChargeFXReference.ReturnToPool(); rolyPolyChargeFXReference = null; } if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost); } base.characterMotor.walkSpeedPenaltyCoefficient = 1f; if (base.isAuthority && chefController != null) { chefController.blockOtherSkills = hasBoost; } Util.PlaySound("Stop_chef_skill3_charge_loop", base.gameObject); base.OnExit(); } protected virtual EntityState GetNextStateAuthority() { return new RolyPoly { charge = charge, hasBoost = hasBoost }; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class RolyPolyWeaponBlockingState : BaseSkillState { private ChefController chefController; public override void OnEnter() { base.OnEnter(); chefController = base.characterBody.GetComponent(); } public override void Update() { base.Update(); if (base.isAuthority && !chefController.blockOtherSkills) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class ChefsKiss : BaseState { public override void OnEnter() { } } public class Dice : BaseState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject effectPrefab; [SerializeField] public GameObject projectileEnhancedPrefab; [SerializeField] public GameObject effectEnhancedPrefab; [SerializeField] public float baseDuration = 2f; [SerializeField] public float damageCoefficient = 1.2f; [SerializeField] public float boostedDamageCoefficient = 1.2f; [SerializeField] public float force = 20f; [SerializeField] public string attackString; [SerializeField] public string returnString; [SerializeField] public string yesChefAttackString; [SerializeField] public string yesChefReturnString; [SerializeField] public float recoilAmplitude; [SerializeField] public float bloom; [SerializeField] public float recallAnimationTransitionTime = 0.2f; [SerializeField] public float approximateCleaverDistance = 80f; private float duration; private ChefController chefController; private bool hasBoost; private bool recallInputPressed; private const float recallBackupCountdown_Duration = 3f; private float recallBackupCountdown = 3f; public override void OnEnter() { base.OnEnter(); recallBackupCountdown = 3f; if (!chefController) { chefController = GetComponent(); } chefController.characterBody = base.characterBody; chefController.spreadBloom = bloom; hasBoost = base.characterBody.HasBuff(DLC2Content.Buffs.Boosted); if (hasBoost) { damageCoefficient = boostedDamageCoefficient; if (NetworkServer.active) { base.characterBody.RemoveBuff(DLC2Content.Buffs.Boosted); } } chefController.NetworkcatchDirtied = false; chefController.recallCleaver = false; Ray ray = GetAimRay(); TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, approximateCleaverDistance, base.gameObject); duration = baseDuration; StartAimMode(duration + 2f); if (hasBoost) { PlayAnimation("Gesture, Override", "FireSliceAndDice", "FireSliceAndDice.playbackRate", duration); PlayAnimation("Gesture, Additive", "FireSliceAndDice", "FireSliceAndDice.playbackRate", duration); Util.PlaySound(yesChefAttackString, base.gameObject); } else { PlayAnimation("Gesture, Override", "FireDice", "FireDice.playbackRate", duration); PlayAnimation("Gesture, Additive", "FireDice", "FireDice.playbackRate", duration); Util.PlaySound(attackString, base.gameObject); } AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude); string muzzleName = "MouthMuzzle"; GameObject gameObject = (hasBoost ? effectEnhancedPrefab : effectPrefab); if ((bool)gameObject) { EffectManager.SimpleMuzzleFlash(gameObject, base.characterBody.aimOriginTransform.gameObject, muzzleName, transmit: false); } chefController.cleaverAway = true; if (!base.isAuthority) { return; } GameObject gameObject2 = (hasBoost ? projectileEnhancedPrefab : projectilePrefab); int[] array = ((!hasBoost) ? new int[1] { 1 } : new int[3] { 8, 4, 4 }); int num = array.Length; for (int i = 0; i < num; i++) { int num2 = array[i]; float num3 = (float)(i % 2) * (0.5f / (float)num2); for (int j = 0; j < num2; j++) { FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = gameObject2; fireProjectileInfo.position = ray.origin; float f = (num3 + (float)j / (float)num2) * MathF.PI * 2f; float f2 = Mathf.Acos(0.02f + (float)i / (float)num); float x = Mathf.Sin(f2) * Mathf.Sin(f); float y = Mathf.Cos(f2); float z = Mathf.Sin(f2) * Mathf.Cos(f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.LookRotation(new UnityEngine.Vector3(x, y, z)); fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction) * quaternion; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.damageTypeOverride = DamageType.Generic; fireProjectileInfo.force = force; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); if (!NetworkServer.active && (bool)chefController) { chefController.CacheCleaverProjectileFireInfo(fireProjectileInfo); } ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } } public override void OnExit() { chefController.SetYesChefHeatState(newYesChefHeatState: false); if (NetworkServer.active) { base.characterBody.RemoveBuff(DLC2Content.Buffs.boostedFireEffect); if (!hasBoost) { chefController.DestroyCleavers(); } } if (base.isAuthority) { chefController.ClearSkillOverrides(); } if (chefController.cleaverAway) { chefController.recallCleaver = true; } if (chefController.catchDirtied) { chefController.NetworkcatchDirtied = false; PlayAnimation("Gesture, Override", "DiceReturnCatch", "DiceReturnCatch.playbackRate", duration); PlayAnimation("Gesture, Additive", "DiceReturnCatch", "DiceReturnCatch.playbackRate", duration); } else { PlayAnimation("Gesture, Override", "BufferEmpty", null, duration); PlayAnimation("Gesture, Additive", "BufferEmpty", null, duration); } base.OnExit(); } public override void FixedUpdate() { bool flag = base.fixedAge > 0f; base.FixedUpdate(); bool flag2 = base.isAuthority; if (flag) { recallInputPressed = base.inputBank.skill1.justPressed; } if (recallInputPressed) { recallInputPressed = false; if (chefController.cleaverAway && flag) { if (chefController.recallCleaver) { chefController.recallCleaver = true; } else { chefController.recallCleaver = true; recallBackupCountdown = 3f; PlayAnimation("Gesture, Override", "DiceReturnHold", null, duration, recallAnimationTransitionTime); PlayAnimation("Gesture, Additive", "DiceReturnHold", null, duration, recallAnimationTransitionTime); } } } bool flag3 = false; if (flag2 && chefController.recallCleaver) { recallBackupCountdown -= Time.deltaTime; if (recallBackupCountdown <= 0f) { flag3 = true; } } if (chefController.catchDirtied) { if (hasBoost) { Util.PlaySound(yesChefReturnString, base.gameObject); } else { Util.PlaySound(returnString, base.gameObject); } if (flag2) { outer.SetNextStateToMain(); } } else if (flag3 || (!chefController.cleaverAway && flag)) { chefController.NetworkcatchDirtied = true; if (flag2) { outer.SetNextStateToMain(); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Glaze : BaseState { public static GameObject effectPrefab; public static GameObject projectilePrefab; public static int grenadeCountMax = 3; public static float damageCoefficient; public static float fireDuration = 3f; public static float baseDuration = 2f; public static float arcAngle = 7f; public static float recoilAmplitude = 1f; public static string attackSoundString; public static float spreadBloomValue = 0.3f; public static float minimumTimeBetweenShots = 0.025f; public static float maximumTimeBetweenShots = 0.1f; public static float xDeviationSpread = 1f; private Ray projectileRay; private Transform modelTransform; private float duration; private float fireTimer; private int grenadeCount; private int muzzleStringEndNum = 1; private void FireGrenade(string targetMuzzle) { Util.PlaySound(attackSoundString, base.gameObject); projectileRay = GetAimRay(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild(targetMuzzle); if ((bool)transform) { projectileRay.origin = transform.position; } } } AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { float x = UnityEngine.Random.Range(0f, base.characterBody.spreadBloomAngle + xDeviationSpread); float z = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 up = UnityEngine.Vector3.up; UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, projectileRay.direction); UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward); float y = vector.y; vector.y = 0f; float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle; UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * projectileRay.direction); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = projectileRay.origin; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(forward); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = 0f; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); fireProjectileInfo.damageTypeOverride = DamageType.WeakOnHit; ProjectileManager.instance.FireProjectile(fireProjectileInfo); } base.characterBody.AddSpreadBloom(spreadBloomValue); } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelTransform = GetModelTransform(); PlayAnimation("Gesture, Override", "ChefGlazeStart", "ChefGlazeStart.playbackRate", duration); StartAimMode(); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { fireTimer -= GetDeltaTime(); float num = UnityEngine.Random.Range(minimumTimeBetweenShots, maximumTimeBetweenShots) + fireDuration / attackSpeedStat / (float)grenadeCountMax; if (fireTimer <= 0f && grenadeCount < grenadeCountMax) { fireTimer += num; arcAngle = UnityEngine.Random.Range(-6, -12); PlayCrossfade("Gesture, Additive", "ChefGlazeRecoil", 0.2f); FireGrenade("MuzzleGlaze" + muzzleStringEndNum); muzzleStringEndNum++; if (muzzleStringEndNum > 5) { muzzleStringEndNum = 1; } grenadeCount++; } } if (base.isAuthority && grenadeCount >= grenadeCountMax) { PlayCrossfade("Gesture, Override", "ChefGlazeExit", 0.2f); PlayCrossfade("Gesture, Additive", "ChefGlazeExit", 0.2f); outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class RolyPoly : GenericCharacterMain { [SerializeField] public float baseDuration; [SerializeField] public float speedMultiplier; [SerializeField] public float speedMultiplierLvlUp; [SerializeField] public float baseDurationLvlUp; public static float chargeDamageCoefficient; public static float chargeDamageCoefficientLvlUp; public static float awayForceMagnitude; public static float upwardForceMagnitude; public static GameObject impactEffectPrefab; public static GameObject impactEffectBoostedPrefab; public static float hitPauseDuration; public static string impactSoundString; public static float recoilAmplitude; public static string startSoundString; public static string endSoundString; public static GameObject knockbackEffectPrefab; public static float knockbackDamageCoefficient; public static float massThresholdForKnockback; public static float knockbackForce; public static float knockbackForceLvlUp; [SerializeField] public GameObject startEffectPrefab; [SerializeField] public GameObject midEffectPrefab; [SerializeField] public GameObject endEffectPrefab; private uint soundID; private float duration; private float hitPauseTimer; private UnityEngine.Vector3 idealDirection; private OverlapAttack attack; private bool inHitPause; private int chestIndex = -1; private GameObject temporaryInstantiationTransform; private GameObject midEffectInstance; private float chargeDamageCoefficientTemp; private float speedMultiplierTemp; private float knockBackForceTemp; private float baseDurationTemp; private ChefController chefController; [SerializeField] public bool hasBoost; [SerializeField] public float charge; [SerializeField] public GameObject projectilePrefab; [SerializeField] public float whirlwindDamageCo; private int originalLayer; [SerializeField] public GameObject rollerSpikePrefab; private GameObject rollerSpikeInstance; public override void OnEnter() { base.OnEnter(); chefController = base.characterBody.GetComponent(); chefController.rolyPolyActive = true; originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal; base.characterMotor?.Motor.RebuildCollidableLayers(); chargeDamageCoefficientTemp = chargeDamageCoefficient; knockBackForceTemp = knockbackForce; speedMultiplierTemp = speedMultiplier; baseDurationTemp = baseDuration; float num = charge; if (num <= 1f) { if (num != 0f && num == 1f) { chargeDamageCoefficientTemp += chargeDamageCoefficientTemp * chargeDamageCoefficientLvlUp; speedMultiplierTemp += speedMultiplierTemp * speedMultiplierLvlUp; knockBackForceTemp += knockBackForceTemp * knockbackForceLvlUp; baseDurationTemp += baseDurationLvlUp; } } else if (num != 2f) { if (num == 3f) { chargeDamageCoefficientTemp += chargeDamageCoefficientTemp * (chargeDamageCoefficientLvlUp * 3f); speedMultiplierTemp += speedMultiplierTemp * (speedMultiplierLvlUp * 3f); knockBackForceTemp += knockBackForceTemp * (knockbackForceLvlUp * 3f); baseDurationTemp += baseDurationLvlUp * 3f; } } else { chargeDamageCoefficientTemp += chargeDamageCoefficientTemp * (chargeDamageCoefficientLvlUp * 2f); speedMultiplierTemp += speedMultiplierTemp * (speedMultiplierLvlUp * 2f); knockBackForceTemp += knockBackForceTemp * (knockbackForceLvlUp * 2f); baseDurationTemp += baseDurationLvlUp * 2f; } if (NetworkServer.active) { base.characterBody.AddBuff(DLC2Content.Buffs.CookingRolling); } if (hasBoost) { Util.PlaySound("Play_chef_skill3_start", base.gameObject); Util.PlaySound("Play_chef_skill3_boosted_active_loop", base.gameObject); ProjectileManager.instance.FireProjectile(projectilePrefab, base.gameObject.transform.position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * whirlwindDamageCo, 0f, Util.CheckRoll(critStat, base.characterBody.master)); PlayAnimation("Body", "BoostedRolyPoly", "BoostedRolyPoly.playbackRate", 1f); GetModelAnimator().SetBool("isInBoostedRolyPoly", value: true); } else { Util.PlaySound("Play_chef_skill3_start", base.gameObject); GetModelAnimator().SetBool("isInRolyPoly", value: true); PlayAnimation("Body", "FireRolyPoly", "FireRolyPoly.playbackRate", 1f); } duration = baseDurationTemp; if (base.isAuthority) { if ((bool)base.inputBank) { idealDirection = base.inputBank.aimDirection; idealDirection.y = 0f; } UpdateDirection(); } temporaryInstantiationTransform = GetModelTransform().gameObject; if ((bool)base.modelLocator) { base.modelLocator.normalizeToFloor = true; } if ((bool)base.characterBody) { if ((bool)startEffectPrefab) { EffectManager.SpawnEffect(startEffectPrefab, new EffectData { origin = base.characterBody.corePosition }, transmit: false); } if ((bool)midEffectPrefab && (bool)temporaryInstantiationTransform) { midEffectInstance = UnityEngine.Object.Instantiate(midEffectPrefab, temporaryInstantiationTransform.transform); } } if ((bool)base.characterDirection) { base.characterDirection.forward = idealDirection; } Util.PlaySound("Stop_chef_skill3_charge_loop", base.gameObject); HitBoxGroup hitBoxGroup = null; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Charge"); } attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = GetTeam(); attack.damage = chargeDamageCoefficientTemp * damageStat; attack.hitEffectPrefab = (hasBoost ? impactEffectBoostedPrefab : impactEffectPrefab); attack.forceVector = UnityEngine.Vector3.up * upwardForceMagnitude; attack.pushAwayForce = knockBackForceTemp; attack.hitBoxGroup = hitBoxGroup; attack.isCrit = RollCrit(); attack.damageType = DamageType.Stun1s; attack.retriggerTimeout = 0.5f; } private void HandleSpawnRollerspikes() { if (!rollerSpikePrefab) { return; } ChildLocator modelChildLocator = GetModelChildLocator(); if ((bool)modelChildLocator) { GameObject gameObject = modelChildLocator.FindChildGameObject("Wheel"); if ((bool)gameObject) { rollerSpikeInstance = UnityEngine.Object.Instantiate(rollerSpikePrefab, gameObject.transform); } } } private void HandleCleanupRollerSpikes() { if ((bool)rollerSpikeInstance) { EntityState.Destroy(rollerSpikeInstance); } } public override void OnExit() { chefController.rolyPolyActive = false; chefController.SetYesChefHeatState(newYesChefHeatState: false); chefController.blockOtherSkills = false; if (hasBoost) { if (NetworkServer.active && base.characterBody.HasBuff(DLC2Content.Buffs.boostedFireEffect)) { base.characterBody.RemoveBuff(DLC2Content.Buffs.boostedFireEffect); } if (base.isAuthority) { chefController.ClearSkillOverrides(); } } if (NetworkServer.active) { base.characterBody.RemoveBuff(DLC2Content.Buffs.CookingRolling); } base.gameObject.layer = originalLayer; base.characterMotor?.Motor.RebuildCollidableLayers(); HandleCleanupRollerSpikes(); if (!outer.destroying && (bool)base.characterBody) { if ((bool)endEffectPrefab) { EffectManager.SpawnEffect(endEffectPrefab, new EffectData { origin = base.characterBody.corePosition }, transmit: false); } if ((bool)midEffectInstance) { EntityState.Destroy(midEffectInstance); } base.characterBody.isSprinting = false; if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost); } } if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision) { base.characterMotor.velocity += GetIdealVelocity(); } if ((bool)base.modelLocator) { base.modelLocator.normalizeToFloor = false; } GetModelAnimator().SetBool("isInRolyPoly", value: false); GetModelAnimator().SetBool("isInBoostedRolyPoly", value: false); PlayCrossfade("Body", "ExitRolyPoly", 0.1f); AkSoundEngine.StopPlayingID(soundID); if (hasBoost) { Util.PlaySound("Stop_chef_skill3_boosted_active_loop", base.gameObject); } Util.PlaySound(endSoundString, base.gameObject); Util.PlaySound("Stop_chef_skill3_active_loop", base.gameObject); Util.PlaySound("Stop_chef_skill3_charge_loop", base.gameObject); base.OnExit(); } private float GetDamageBoostFromSpeed() { return Mathf.Max(1f, base.characterBody.moveSpeed / base.characterBody.baseMoveSpeed); } private void UpdateDirection() { if ((bool)base.inputBank) { UnityEngine.Vector3 vector = base.inputBank.moveVector; UnityEngine.Vector2 vector2 = ((!(vector == UnityEngine.Vector3.zero)) ? Util.Vector3XZToVector2XY(vector.normalized) : Util.Vector3XZToVector2XY(base.characterDirection.forward)); if (vector2 != UnityEngine.Vector2.zero) { vector2.Normalize(); idealDirection = new UnityEngine.Vector3(vector2.x, 0f, vector2.y).normalized; } } } private UnityEngine.Vector3 GetIdealVelocity() { return base.characterDirection.forward.normalized * base.characterBody.moveSpeed * speedMultiplier; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } else { if (!base.isAuthority) { return; } if ((bool)base.characterBody) { base.characterBody.isSprinting = true; } if ((bool)base.skillLocator.special && base.inputBank.skill4.down) { base.skillLocator.special.ExecuteIfReady(); } UpdateDirection(); if (!inHitPause) { if ((bool)base.characterDirection) { base.characterMotor.moveDirection = idealDirection; base.characterDirection.moveVector = idealDirection; if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision) { base.characterMotor.rootMotion += GetIdealVelocity() * GetDeltaTime(); } } if (attack.Fire()) { inHitPause = true; hitPauseTimer = hitPauseDuration; AddRecoil(-0.25f * recoilAmplitude, -0.25f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude); } } else { base.characterMotor.velocity = UnityEngine.Vector3.zero; hitPauseTimer -= GetDeltaTime(); if (hitPauseTimer < 0f) { inHitPause = false; } } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class Sear : BaseState { public static GameObject flamethrowerEffectPrefab; public static GameObject ovenBlueEffectPrefab; public static GameObject initialOvenBlueEffectPrefab; public static GameObject boostedSearProjectilePrefab; public static GameObject impactEffectPrefab; public static GameObject tracerEffectPrefab; public static float maxDistance; public static float radius; public static float baseEntryDuration = 1f; public static float baseExitDuration = 0.5f; public static float baseFlamethrowerDuration = 2f; public static float totalDamageCoefficient = 1.2f; public static float procCoefficientPerTick; public static float tickFrequency; public static float force = 20f; public static GameObject muzzleflashEffectPrefab; public static float boostedProjectileDmgCoefficient = 1f; public static float boostedProjectileCount = 1f; public static float boostedProjectileTimer; public static float boostedProjectileInBetweenShotTime; public static string startAttackSoundString; public static string endAttackSoundString; public static string endLoopSoundString; public static string boostedStartAttackSoundString; public static string boostedEndAttackSoundString; public static string boostedEndLoopSoundString; public static string boostedFireBallSoundString; public static float ignitePercentChance; public static float maxSpread; private float tickDamageCoefficient; private float primaryAttackStopwatch; private float stopwatch; private float entryDuration; private float exitDuration; private float flamethrowerDuration; private bool flamethrowerStarted; private bool flamethrowerEnded; private ChildLocator childLocator; private Transform flamethrowerEffectInstance; private Transform muzzleTransform; private bool isCrit; private bool hasBoost; private float boostedDamage; private int boostedProjectilesFired; private bool allBoostProjectilesFired; private ChefController chefController; private const float flamethrowerEffectBaseDistance = 16f; private float flamethrowerTimestamp; public override void OnEnter() { base.OnEnter(); chefController = GetComponent(); if (NetworkServer.active) { base.characterBody.AddBuff(DLC2Content.Buffs.CookingSearing); } if (base.characterBody.HasBuff(DLC2Content.Buffs.Boosted)) { hasBoost = true; base.characterBody.RemoveBuff(DLC2Content.Buffs.Boosted); } stopwatch = 0f; entryDuration = baseEntryDuration / attackSpeedStat; exitDuration = baseExitDuration / attackSpeedStat; flamethrowerDuration = baseFlamethrowerDuration + exitDuration; Transform modelTransform = GetModelTransform(); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(entryDuration + flamethrowerDuration + 1f); } if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); modelTransform.GetComponent().enabled = true; muzzleTransform = childLocator.FindChild("MuzzleCenter"); } float num = flamethrowerDuration * tickFrequency; if (hasBoost) { boostedDamage = 1.5f; } else { boostedDamage = 1f; } tickDamageCoefficient = totalDamageCoefficient * boostedDamage / num; if (base.isAuthority && (bool)base.characterBody) { isCrit = Util.CheckRoll(critStat, base.characterBody.master); } boostedProjectileTimer = boostedProjectileInBetweenShotTime; PlayAnimation("Gesture, Additive", "PrepSear", "PrepSear.playbackRate", entryDuration); PlayAnimation("Gesture, Override", "PrepSear", "PrepSear.playbackRate", entryDuration); } public override void Update() { base.Update(); float deltaTime = Time.deltaTime; stopwatch += deltaTime; if (stopwatch < entryDuration) { return; } if (hasBoost && !allBoostProjectilesFired) { HandleBoostProjectiles(deltaTime); return; } if (!flamethrowerStarted && stopwatch >= entryDuration) { StartPrimaryFlameVFX(); } else if (!flamethrowerEnded) { if (base.isAuthority) { HandlePrimaryAttack(deltaTime); } if (stopwatch >= entryDuration + flamethrowerDuration) { EndPrimaryFlameVFX(); } } if (flamethrowerEnded && stopwatch >= flamethrowerDuration + entryDuration + exitDuration && base.isAuthority) { outer.SetNextStateToMain(); } } private void HandleBoostProjectiles(float deltaTime) { boostedProjectileTimer += deltaTime; if (!(boostedProjectileTimer < boostedProjectileInBetweenShotTime)) { if ((float)boostedProjectilesFired < boostedProjectileCount) { boostedProjectileTimer = 0f; boostedProjectilesFired++; FireBoostedFireball("MuzzleCenter"); } else { allBoostProjectilesFired = true; stopwatch = entryDuration; } } } private void FirePrimaryAttack(string muzzleString) { GetAimRay(); if (base.isAuthority && (bool)muzzleTransform) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = muzzleTransform.position; bulletAttack.aimVector = muzzleTransform.forward; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = maxSpread; bulletAttack.damage = tickDamageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.muzzleName = muzzleString; bulletAttack.hitEffectPrefab = impactEffectPrefab; bulletAttack.isCrit = isCrit; bulletAttack.radius = radius; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.stopperMask = LayerIndex.world.mask; bulletAttack.procCoefficient = procCoefficientPerTick; bulletAttack.maxDistance = maxDistance; bulletAttack.smartCollision = true; bulletAttack.damageType = new DamageTypeCombo(DamageType.IgniteOnHit, DamageTypeExtended.ChefSearDamage); bulletAttack.Fire(); } } private void FireBoostedFireball(string muzzleString) { if (base.isAuthority && (bool)muzzleTransform) { if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true); } Ray aimRay = GetAimRay(); Util.PlaySound(boostedFireBallSoundString, base.gameObject); ProjectileManager.instance.FireProjectile(boostedSearProjectilePrefab, muzzleTransform.position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, base.characterBody.damage * boostedProjectileDmgCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master)); } } private void StartPrimaryFlameVFX() { flamethrowerStarted = true; PlayAnimation("Gesture, Override", "FireSear", "FireSear.playbackRate", flamethrowerDuration); PlayAnimation("Gesture, Additive", "FireSear", "FireSear.playbackRate", flamethrowerDuration); if (hasBoost) { flamethrowerEffectInstance = UnityEngine.Object.Instantiate(ovenBlueEffectPrefab, muzzleTransform).transform; Util.PlaySound(boostedStartAttackSoundString, base.gameObject); } else { flamethrowerEffectInstance = UnityEngine.Object.Instantiate(flamethrowerEffectPrefab, muzzleTransform).transform; Util.PlaySound(startAttackSoundString, base.gameObject); } flamethrowerTimestamp = Time.time; flamethrowerEffectInstance.transform.localPosition = UnityEngine.Vector3.zero; flamethrowerEffectInstance.GetComponent().newDuration = flamethrowerDuration; } private void EndPrimaryFlameVFX() { flamethrowerEnded = true; PlayCrossfade("Gesture, Override", "ExitSear", "ExitSear.playbackRate", exitDuration, 0.1f); PlayCrossfade("Gesture, Additive", "ExitSear", "ExitSear.playbackRate", exitDuration, 0.1f); if ((bool)flamethrowerEffectInstance) { if (hasBoost) { Util.PlaySound(boostedEndLoopSoundString, base.gameObject); Util.PlaySound(boostedEndAttackSoundString, base.gameObject); } else { Util.PlaySound(endLoopSoundString, base.gameObject); Util.PlaySound(endAttackSoundString, base.gameObject); } EntityState.Destroy(flamethrowerEffectInstance.gameObject); } } private void HandlePrimaryAttack(float deltaTime) { primaryAttackStopwatch += deltaTime; if (primaryAttackStopwatch > 1f / tickFrequency) { primaryAttackStopwatch -= 1f / tickFrequency; FirePrimaryAttack("MuzzleCenter"); } } public override void OnExit() { chefController.SetYesChefHeatState(newYesChefHeatState: false); if (NetworkServer.active) { base.characterBody.RemoveBuff(DLC2Content.Buffs.CookingSearing); if (base.characterBody.HasBuff(DLC2Content.Buffs.boostedFireEffect)) { base.characterBody.RemoveBuff(DLC2Content.Buffs.boostedFireEffect); } } if (base.isAuthority) { chefController.ClearSkillOverrides(); } PlayCrossfade("Gesture, Override", "BufferEmpty", 0.1f); PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.1f); if ((bool)flamethrowerEffectInstance) { if (hasBoost) { Util.PlaySound(boostedEndLoopSoundString, base.gameObject); Util.PlaySound(boostedEndAttackSoundString, base.gameObject); } else { Util.PlaySound(endLoopSoundString, base.gameObject); Util.PlaySound(endAttackSoundString, base.gameObject); } EntityState.Destroy(flamethrowerEffectInstance.gameObject); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class YesChef : BaseState { [SerializeField] public float duration = 1f; [SerializeField] public GameObject playerRespawnEffectPrefab; [SerializeField] public string startSoundString; [SerializeField] public int buffStockToAdd = 3; [SerializeField] public float heatDamageCo = 1f; [SerializeField] public GameObject projectilePrefab; [SerializeField] public GameObject blastEffectPrefab; [SerializeField] public float blastDamageCoefficient; [SerializeField] public float blastRadius; [SerializeField] public float blastProcCoefficient; [SerializeField] public float blastForce; [SerializeField] [Tooltip("Set This to the child transform you want the blast effect to parent to")] public string blastEffectTransformChild; [SerializeField] public float exitDelay; [SerializeField] public SkillDef primarySkillOverrideDef; [SerializeField] public SkillDef secondarySkillOverrideDef; [SerializeField] public SkillDef utilitySkillOverrideDef; [SerializeField] public SkillDef specialSkillOverrideDef; private bool alreadyRan; private ChildLocator childLocator; private ChefController chefController; private bool playedYesChefSFX; public override void OnEnter() { base.OnEnter(); chefController = base.characterBody.GetComponent(); if ((bool)chefController) { chefController.SetYesChefHeatState(newYesChefHeatState: true); } if (base.isAuthority && (bool)chefController) { chefController.ClearSkillOverrides(); SkillStateOverrideData skillStateOverrideData = new SkillStateOverrideData(base.characterBody, _duplicateStock: true); skillStateOverrideData.simulateRestockForOverridenSkills = false; skillStateOverrideData.primarySkillOverride = primarySkillOverrideDef; skillStateOverrideData.secondarySkillOverride = secondarySkillOverrideDef; skillStateOverrideData.utilitySkillOverride = utilitySkillOverrideDef; skillStateOverrideData.specialSkillOverride = specialSkillOverrideDef; skillStateOverrideData.OverrideSkills(base.skillLocator); EnsureMinStock(ref base.skillLocator.primary); EnsureMinStock(ref base.skillLocator.secondary); EnsureMinStock(ref base.skillLocator.utility); chefController.TransferSkillOverrides(skillStateOverrideData); } childLocator = GetModelChildLocator(); PlayAnimation("Gesture, Additive", "FireYesChef", "FireYesChef.playbackRate", duration); PlayAnimation("Gesture, Override", "FireYesChef", "FireYesChef.playbackRate", duration); EffectData effectData = new EffectData { origin = base.transform.position, scale = blastRadius }; if ((bool)childLocator) { int num = childLocator.FindChildIndex(blastEffectTransformChild); if (num != -1) { effectData.SetChildLocatorTransformReference(base.gameObject, num); } } EffectManager.SpawnEffect(blastEffectPrefab, effectData, transmit: true); chefController.ActivateServoStrainSfxForDuration(3f); static void EnsureMinStock(ref GenericSkill skill) { if (skill.stock < 1) { skill.stock = 1; skill.rechargeStopwatch = 0f; } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } public override void OnExit() { base.OnExit(); if (NetworkServer.active) { if (!base.characterBody.HasBuff(DLC2Content.Buffs.Boosted)) { base.characterBody.AddBuff(DLC2Content.Buffs.Boosted); } if (!base.characterBody.HasBuff(DLC2Content.Buffs.boostedFireEffect)) { base.characterBody.AddBuff(DLC2Content.Buffs.boostedFireEffect); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > 0.5f && !playedYesChefSFX) { Util.PlaySound(startSoundString, base.gameObject); playedYesChefSFX = true; } if ((bool)chefController && base.fixedAge > duration && base.isAuthority) { ProjectileManager.instance.FireProjectile(projectilePrefab, base.gameObject.transform.position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * heatDamageCo, 0f, Util.CheckRoll(critStat, base.characterBody.master)); Util.PlaySound("Play_chef_skill4_flame_aoe_on", base.gameObject); BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.characterBody.gameObject; blastAttack.baseDamage = blastDamageCoefficient * base.characterBody.damage; blastAttack.baseForce = blastForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = base.characterBody.RollCrit(); blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.inflictor = base.gameObject; blastAttack.position = base.characterBody.corePosition; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = blastProcCoefficient; blastAttack.radius = blastRadius; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.teamIndex = base.teamComponent.teamIndex; blastAttack.Fire(); outer.SetNextStateToMain(); } } } } namespace EntityStates.CaptainSupplyDrop { public class BaseCaptainSupplyDropState : BaseState { private ProxyInteraction interactionComponent; protected GenericEnergyComponent energyComponent; protected TeamFilter teamFilter; private UnityEngine.UI.Image energyIndicator; private GameObject energyIndicatorContainer; protected virtual bool shouldShowModel => true; protected virtual bool shouldShowEnergy => false; protected virtual string GetContextString(Interactor activator) { return null; } protected virtual Interactability GetInteractability(Interactor activator) { return Interactability.Disabled; } protected virtual void OnInteractionBegin(Interactor activator) { } protected virtual bool ShouldShowOnScanner() { return false; } protected virtual bool ShouldIgnoreSpherecastForInteractability(Interactor activator) { return false; } private string GetContextStringInternal(ProxyInteraction proxyInteraction, Interactor activator) { return GetContextString(activator); } private Interactability GetInteractabilityInternal(ProxyInteraction proxyInteraction, Interactor activator) { return GetInteractability(activator); } private void OnInteractionBeginInternal(ProxyInteraction proxyInteraction, Interactor activator) { OnInteractionBegin(activator); } private bool ShouldIgnoreSpherecastForInteractabilityInternal(ProxyInteraction proxyInteraction, Interactor activator) { return ShouldIgnoreSpherecastForInteractability(activator); } private bool ShouldShowOnScannerInternal(ProxyInteraction proxyInteraction) { return ShouldShowOnScanner(); } public override void OnEnter() { base.OnEnter(); energyComponent = GetComponent(); teamFilter = GetComponent(); interactionComponent = GetComponent(); interactionComponent.getContextString = GetContextStringInternal; interactionComponent.getInteractability = GetInteractabilityInternal; interactionComponent.onInteractionBegin = OnInteractionBeginInternal; interactionComponent.shouldShowOnScanner = ShouldShowOnScannerInternal; interactionComponent.shouldIgnoreSpherecastForInteractability = ShouldIgnoreSpherecastForInteractabilityInternal; GetModelTransform().gameObject.SetActive(shouldShowModel); energyIndicatorContainer = FindModelChild("EnergyIndicatorContainer").gameObject; energyIndicator = FindModelChild("EnergyIndicator").GetComponent(); } public override void OnExit() { interactionComponent.getContextString = null; interactionComponent.getInteractability = null; interactionComponent.onInteractionBegin = null; interactionComponent.shouldShowOnScanner = null; interactionComponent.shouldIgnoreSpherecastForInteractability = null; base.OnExit(); } public override void Update() { base.Update(); UpdateEnergyIndicator(); } private void UpdateEnergyIndicator() { energyIndicatorContainer.SetActive(shouldShowEnergy); energyIndicator.fillAmount = energyComponent.normalizedEnergy; } } public class EntryState : BaseCaptainSupplyDropState { public static float baseDuration; private float duration; protected override bool shouldShowModel => false; public override void OnEnter() { base.OnEnter(); duration = baseDuration; } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new HitGroundState()); } } } public class HitGroundState : BaseCaptainSupplyDropState { public static float baseDuration; public static GameObject effectPrefab; public static float impactBulletDistance; public static float impactBulletRadius; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration; if (NetworkServer.active) { GameObject ownerObject = GetComponent().ownerObject; ProjectileDamage component = GetComponent(); UnityEngine.Vector3 position = base.transform.position; UnityEngine.Vector3 vector = -base.transform.up; BulletAttack bulletAttack = new BulletAttack(); bulletAttack.origin = position - vector * impactBulletDistance; bulletAttack.aimVector = vector; bulletAttack.maxDistance = impactBulletDistance + 1f; bulletAttack.stopperMask = default(LayerMask); bulletAttack.hitMask = LayerIndex.CommonMasks.bullet; bulletAttack.damage = component.damage; bulletAttack.damageColorIndex = component.damageColorIndex; bulletAttack.damageType = component.damageType; bulletAttack.bulletCount = 1u; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = 0f; bulletAttack.owner = ownerObject; bulletAttack.weapon = base.gameObject; bulletAttack.procCoefficient = 0f; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.isCrit = RollCrit(); bulletAttack.smartCollision = false; bulletAttack.sniper = false; bulletAttack.force = component.force; bulletAttack.radius = impactBulletRadius; bulletAttack.hitEffectPrefab = effectPrefab; bulletAttack.Fire(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextState(new DeployState()); } } } public class DeployState : BaseCaptainSupplyDropState { public static float baseDuration; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration; } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } public abstract class BaseMainState : BaseCaptainSupplyDropState { } public class PreDepletionState : BaseCaptainSupplyDropState { } public class DepletionState : BaseCaptainSupplyDropState { } public class PlatingBuffMainState : BaseMainState { public static int maximumBuffStack; public static int buffCountToGrant; [SerializeField] public float activationCost; private static BuffIndex buff => JunkContent.Buffs.BodyArmor.buffIndex; protected override bool shouldShowEnergy => true; protected override string GetContextString(Interactor activator) { return Language.GetString("CAPTAIN_SUPPLY_DEFENSE_RESTOCK_INTERACTION"); } protected override Interactability GetInteractability(Interactor activator) { CharacterBody component = activator.GetComponent(); if (!component) { return Interactability.Disabled; } if (energyComponent.energy < activationCost) { return Interactability.ConditionsNotMet; } if (component.GetBuffCount(buff) >= maximumBuffStack) { return Interactability.ConditionsNotMet; } return Interactability.Available; } protected override void OnInteractionBegin(Interactor activator) { CharacterBody component = activator.GetComponent(); for (int i = 0; i < buffCountToGrant; i++) { if (component.GetBuffCount(buff) >= maximumBuffStack) { break; } if (!energyComponent.TakeEnergy(activationCost)) { break; } component.AddBuff(buff); } } } public class EquipmentRestockMainState : BaseMainState { [SerializeField] public float activationCost; protected override bool shouldShowEnergy => true; protected override string GetContextString(Interactor activator) { return Language.GetString("CAPTAIN_SUPPLY_EQUIPMENT_RESTOCK_INTERACTION"); } protected override Interactability GetInteractability(Interactor activator) { CharacterBody component = activator.GetComponent(); RoR2.Inventory inventory; if (!component || !(inventory = component.inventory)) { return Interactability.Disabled; } if (activationCost >= energyComponent.energy) { return Interactability.ConditionsNotMet; } if (inventory.GetEquipmentRestockableChargeCount(inventory.activeEquipmentSlot) <= 0) { return Interactability.ConditionsNotMet; } return Interactability.Available; } protected override void OnInteractionBegin(Interactor activator) { energyComponent.TakeEnergy(activationCost); RoR2.Inventory inventory = activator.GetComponent().inventory; inventory.RestockEquipmentCharges(inventory.activeEquipmentSlot, 1); } } public class HealZoneMainState : BaseMainState { public static GameObject healZonePrefab; private GameObject healZoneInstance; protected override Interactability GetInteractability(Interactor activator) { return Interactability.Disabled; } public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { healZoneInstance = UnityEngine.Object.Instantiate(healZonePrefab, base.transform.position, base.transform.rotation); healZoneInstance.GetComponent().teamIndex = teamFilter.teamIndex; NetworkServer.Spawn(healZoneInstance); } } public override void OnExit() { if ((bool)healZoneInstance) { EntityState.Destroy(healZoneInstance); } base.OnExit(); } } public class ShockZoneMainState : BaseMainState { public static GameObject shockEffectPrefab; public static float shockRadius; public static float shockDamageCoefficient; public static float shockFrequency; private float shockTimer; protected override Interactability GetInteractability(Interactor activator) { return Interactability.Disabled; } public override void OnEnter() { base.OnEnter(); } public override void FixedUpdate() { base.FixedUpdate(); shockTimer += GetDeltaTime(); if (shockTimer > 1f / shockFrequency) { shockTimer -= 1f / shockFrequency; Shock(); } } private void Shock() { BlastAttack blastAttack = new BlastAttack(); blastAttack.radius = shockRadius; blastAttack.baseDamage = 0f; blastAttack.damageType = DamageType.Silent | DamageType.Shock5s; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.attacker = null; blastAttack.teamIndex = teamFilter.teamIndex; blastAttack.position = base.transform.position; blastAttack.Fire(); if ((bool)shockEffectPrefab) { EffectManager.SpawnEffect(shockEffectPrefab, new EffectData { origin = base.transform.position, scale = shockRadius }, transmit: false); } } public override void OnExit() { base.OnExit(); } } public class HackingMainState : BaseMainState { public static float baseRadius = 7f; public static float scanInterval = 5f; private float radius; private float scanTimer; private SphereSearch sphereSearch; public override void OnEnter() { base.OnEnter(); radius = baseRadius; if (base.isAuthority) { sphereSearch = new SphereSearch(); sphereSearch.origin = base.transform.position; sphereSearch.mask = LayerIndex.CommonMasks.interactable; sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.Collide; sphereSearch.radius = radius; } } public override void OnExit() { base.OnExit(); } private PurchaseInteraction ScanForTarget() { List list = CollectionPool>.RentCollection(); sphereSearch.ClearCandidates(); sphereSearch.RefreshCandidates(); sphereSearch.FilterCandidatesByColliderEntities(); sphereSearch.OrderCandidatesByDistance(); sphereSearch.FilterCandidatesByDistinctColliderEntities(); sphereSearch.GetColliders(list); PurchaseInteraction result = null; int i = 0; for (int count = list.Count; i < count; i++) { PurchaseInteraction component = list[i].GetComponent().entity.GetComponent(); if (PurchaseInteractionIsValidTarget(component)) { result = component; break; } } CollectionPool>.ReturnCollection(list); return result; } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority) { return; } scanTimer -= GetDeltaTime(); if (scanTimer <= 0f) { scanTimer = scanInterval; PurchaseInteraction purchaseInteraction = ScanForTarget(); if ((bool)purchaseInteraction) { outer.SetNextState(new HackingInProgressState { target = purchaseInteraction }); } } } public static bool PurchaseInteractionIsValidTarget(PurchaseInteraction purchaseInteraction) { if ((bool)purchaseInteraction) { if (purchaseInteraction.costType == CostTypeIndex.Money && purchaseInteraction.cost > 0) { return purchaseInteraction.available; } return false; } return false; } } public class HackingInProgressState : BaseMainState { public static int baseGoldForBaseDuration = 25; public static float baseDuration = 15f; public static GameObject targetIndicatorVfxPrefab; public PurchaseInteraction target; private GameObject targetIndicatorVfxInstance; private Run.FixedTimeStamp startTime; private Run.FixedTimeStamp endTime; protected override bool shouldShowEnergy => true; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { int difficultyScaledCost = Run.instance.GetDifficultyScaledCost(baseGoldForBaseDuration, Stage.instance.entryDifficultyCoefficient); float num = (float)((double)target.cost / (double)difficultyScaledCost * (double)baseDuration); startTime = Run.FixedTimeStamp.now; endTime = startTime + num; } energyComponent.normalizedChargeRate = 1f / (endTime - startTime); if (NetworkServer.active) { energyComponent.energy = 0f; } if (!targetIndicatorVfxPrefab || !target) { return; } targetIndicatorVfxInstance = UnityEngine.Object.Instantiate(targetIndicatorVfxPrefab, target.transform.position, UnityEngine.Quaternion.identity); ChildLocator component = targetIndicatorVfxInstance.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("LineEnd"); if ((bool)transform) { transform.position = FindModelChild("ShaftTip").position; } } } public override void OnExit() { if ((bool)targetIndicatorVfxInstance) { EntityState.Destroy(targetIndicatorVfxInstance); targetIndicatorVfxInstance = null; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { if (energyComponent.normalizedEnergy >= 1f) { outer.SetNextState(new UnlockTargetState { target = target }); } else if (!HackingMainState.PurchaseInteractionIsValidTarget(target)) { outer.SetNextStateToMain(); } } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(target ? target.gameObject : null); writer.Write(startTime); writer.Write(endTime); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); GameObject gameObject = reader.ReadGameObject(); target = (gameObject ? gameObject.GetComponent() : null); startTime = reader.ReadFixedTimeStamp(); endTime = reader.ReadFixedTimeStamp(); } } public class UnlockTargetState : BaseMainState { public static GameObject unlockEffectPrefab; public static float baseDuration; public static string soundString; public PurchaseInteraction target; private float duration; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active && (bool)target && target.available) { target.Networkcost = 0; GameObject ownerObject = GetComponent().ownerObject; if ((bool)ownerObject) { Interactor component = ownerObject.GetComponent(); if ((bool)component) { component.AttemptInteraction(target.gameObject); } } EffectManager.SpawnEffect(unlockEffectPrefab, new EffectData { origin = target.transform.position }, transmit: true); } Util.PlaySound(soundString, base.gameObject); duration = baseDuration; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(target ? target.gameObject : null); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); GameObject gameObject = reader.ReadGameObject(); target = (gameObject ? gameObject.GetComponent() : null); } } } namespace EntityStates.Captain.Weapon { public class SetupAirstrike : BaseState { public static SkillDef primarySkillDef; public static GameObject crosshairOverridePrefab; public static string enterSoundString; public static string exitSoundString; public static GameObject effectMuzzlePrefab; public static string effectMuzzleString; public static float baseExitDuration; private GenericSkill primarySkillSlot; private GameObject effectMuzzleInstance; private Animator modelAnimator; private float timerSinceComplete; private bool beginExit; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private static int PrepAirstrikeHash = Animator.StringToHash("PrepAirstrike"); private float exitDuration => baseExitDuration / attackSpeedStat; public override void OnEnter() { base.OnEnter(); primarySkillSlot = (base.skillLocator ? base.skillLocator.primary : null); if ((bool)primarySkillSlot) { primarySkillSlot.SetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual); } modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetBool(PrepAirstrikeHash, value: true); } PlayCrossfade("Gesture, Override", PrepAirstrikeHash, 0.1f); PlayCrossfade("Gesture, Additive", PrepAirstrikeHash, 0.1f); Transform transform = FindModelChild(effectMuzzleString); if ((bool)transform) { effectMuzzleInstance = UnityEngine.Object.Instantiate(effectMuzzlePrefab, transform); } if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } Util.PlaySound(enterSoundString, base.gameObject); Util.PlaySound("Play_captain_shift_active_loop", base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } if (!primarySkillSlot || primarySkillSlot.stock == 0) { beginExit = true; } if (beginExit) { timerSinceComplete += GetDeltaTime(); if (timerSinceComplete > exitDuration) { outer.SetNextStateToMain(); } } } public override void OnExit() { if ((bool)primarySkillSlot) { primarySkillSlot.UnsetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual); } Util.PlaySound(exitSoundString, base.gameObject); Util.PlaySound("Stop_captain_shift_active_loop", base.gameObject); if ((bool)effectMuzzleInstance) { EntityState.Destroy(effectMuzzleInstance); } if ((bool)modelAnimator) { modelAnimator.SetBool(PrepAirstrikeHash, value: false); } crosshairOverrideRequest?.Dispose(); base.OnExit(); } } public class SetupAirstrikeAlt : BaseState { public static SkillDef primarySkillDef; public static GameObject crosshairOverridePrefab; public static string enterSoundString; public static string exitSoundString; public static GameObject effectMuzzlePrefab; public static string effectMuzzleString; public static float baseExitDuration; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private GenericSkill primarySkillSlot; private GameObject effectMuzzleInstance; private Animator modelAnimator; private float timerSinceComplete; private bool beginExit; private static int PrepAirstrikeHash = Animator.StringToHash("PrepAirstrike"); private float exitDuration => baseExitDuration / attackSpeedStat; public override void OnEnter() { base.OnEnter(); primarySkillSlot = (base.skillLocator ? base.skillLocator.primary : null); if ((bool)primarySkillSlot) { primarySkillSlot.SetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual); } modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.SetBool(PrepAirstrikeHash, value: true); } PlayCrossfade("Gesture, Override", PrepAirstrikeHash, 0.1f); PlayCrossfade("Gesture, Additive", PrepAirstrikeHash, 0.1f); Transform transform = FindModelChild(effectMuzzleString); if ((bool)transform) { effectMuzzleInstance = UnityEngine.Object.Instantiate(effectMuzzlePrefab, transform); } if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } Util.PlaySound(enterSoundString, base.gameObject); Util.PlaySound("Play_captain_shift_active_loop", base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } if (!primarySkillSlot || primarySkillSlot.stock == 0) { beginExit = true; } if (beginExit) { timerSinceComplete += GetDeltaTime(); if (timerSinceComplete > exitDuration) { outer.SetNextStateToMain(); } } } public override void OnExit() { if ((bool)primarySkillSlot) { primarySkillSlot.UnsetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual); } Util.PlaySound(exitSoundString, base.gameObject); Util.PlaySound("Stop_captain_shift_active_loop", base.gameObject); if ((bool)effectMuzzleInstance) { EntityState.Destroy(effectMuzzleInstance); } if ((bool)modelAnimator) { modelAnimator.SetBool(PrepAirstrikeHash, value: false); } crosshairOverrideRequest?.Dispose(); base.OnExit(); } } public class CallAirstrikeEnter : BaseSkillState { public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { switch (base.activatorSkillSlot.stock) { case 2: outer.SetNextState(new CallAirstrike1()); break; case 1: outer.SetNextState(new CallAirstrike2()); break; case 0: outer.SetNextState(new CallAirstrike3()); break; default: outer.SetNextState(new CallAirstrike1()); break; } } } } public class CallAirstrikeAltEnter : BaseSkillState { public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { outer.SetNextState(new CallAirstrikeAlt()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class CallAirstrike1 : CallAirstrikeBase { private static int CallAirstrike1StateHash = Animator.StringToHash("CallAirstrike1"); public override void OnEnter() { base.OnEnter(); } public override void OnExit() { PlayAnimation("Gesture, Override", CallAirstrike1StateHash); PlayAnimation("Gesture, Additive", CallAirstrike1StateHash); AddRecoil(0f, 0f, -1f, -1f); base.OnExit(); } } public class CallAirstrike2 : CallAirstrikeBase { private static int CallAirstrike2StateHash = Animator.StringToHash("CallAirstrike2"); public override void OnExit() { PlayAnimation("Gesture, Override", CallAirstrike2StateHash); PlayAnimation("Gesture, Additive", CallAirstrike2StateHash); AddRecoil(0f, 0f, 1f, 1f); base.OnExit(); } } public class CallAirstrike3 : CallAirstrikeBase { private static int CallAirstrike3StateHash = Animator.StringToHash("CallAirstrike3"); public override void OnExit() { PlayAnimation("Gesture, Override", CallAirstrike3StateHash); AddRecoil(-2f, -2f, -0.5f, 0.5f); base.OnExit(); } } public class CallAirstrikeAlt : CallAirstrikeBase { [SerializeField] public float projectileForce; private static int CallAirstrike3StateHash = Animator.StringToHash("CallAirstrike3"); public override void OnExit() { PlayAnimation("Gesture, Override", CallAirstrike3StateHash); PlayAnimation("Gesture, Additive", CallAirstrike3StateHash); AddRecoil(-2f, -2f, -0.5f, 0.5f); base.OnExit(); } protected override void ModifyProjectile(ref FireProjectileInfo fireProjectileInfo) { base.ModifyProjectile(ref fireProjectileInfo); fireProjectileInfo.force = projectileForce; } } public class CallAirstrikeBase : AimThrowableBase { [SerializeField] public float airstrikeRadius; [SerializeField] public float bloom; public static GameObject muzzleFlashEffect; public static string muzzleString; public static string fireAirstrikeSoundString; public override void OnEnter() { base.OnEnter(); base.characterBody.SetSpreadBloom(bloom); } public override void FixedUpdate() { base.FixedUpdate(); base.characterBody.SetAimTimer(4f); } public override void OnExit() { Util.PlaySound(fireAirstrikeSoundString, base.gameObject); base.OnExit(); } protected override void ModifyProjectile(ref FireProjectileInfo fireProjectileInfo) { base.ModifyProjectile(ref fireProjectileInfo); fireProjectileInfo.position = currentTrajectoryInfo.hitPoint; fireProjectileInfo.rotation = UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f); fireProjectileInfo.speedOverride = 0f; } protected override bool KeyIsDown() { return base.inputBank.skill1.down; } protected override EntityState PickNextState() { return new Idle(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SetupSupplyDrop : BaseState { public struct PlacementInfo { public bool ok; public UnityEngine.Vector3 position; public UnityEngine.Quaternion rotation; public void Serialize(NetworkWriter writer) { writer.Write(ok); writer.Write(position); writer.Write(rotation); } public void Deserialize(NetworkReader reader) { ok = reader.ReadBoolean(); position = reader.ReadVector3(); rotation = reader.ReadQuaternion(); } } public static GameObject crosshairOverridePrefab; public static string enterSoundString; public static string exitSoundString; public static GameObject effectMuzzlePrefab; public static string effectMuzzleString; public static float baseExitDuration; public static float maxPlacementDistance; public static GameObject blueprintPrefab; public static float normalYThreshold; private PlacementInfo currentPlacementInfo; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; private GenericSkill primarySkillSlot; private AimAnimator modelAimAnimator; private GameObject effectMuzzleInstance; private Animator modelAnimator; private float timerSinceComplete; private bool beginExit; private GenericSkill originalPrimarySkill; private GenericSkill originalSecondarySkill; private BlueprintController blueprints; private CameraTargetParams.AimRequest aimRequest; private static int PrepSupplyDropStateHash = Animator.StringToHash("PrepSupplyDrop"); private float exitDuration => baseExitDuration / attackSpeedStat; public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); PlayAnimation("Gesture, Override", PrepSupplyDropStateHash); if ((bool)modelAnimator) { modelAnimator.SetBool(PrepSupplyDropStateHash, value: true); } Transform transform = FindModelChild(effectMuzzleString); if ((bool)transform) { effectMuzzleInstance = UnityEngine.Object.Instantiate(effectMuzzlePrefab, transform); } if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } Util.PlaySound(enterSoundString, base.gameObject); blueprints = UnityEngine.Object.Instantiate(blueprintPrefab, currentPlacementInfo.position, currentPlacementInfo.rotation).GetComponent(); if ((bool)base.cameraTargetParams) { aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } originalPrimarySkill = base.skillLocator.primary; originalSecondarySkill = base.skillLocator.secondary; base.skillLocator.primary = base.skillLocator.FindSkill("SupplyDrop1"); base.skillLocator.secondary = base.skillLocator.FindSkill("SupplyDrop2"); } public override void Update() { base.Update(); currentPlacementInfo = GetPlacementInfo(GetAimRay(), base.gameObject); if ((bool)blueprints) { blueprints.PushState(currentPlacementInfo.position, currentPlacementInfo.rotation, currentPlacementInfo.ok); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } if (base.isAuthority && beginExit) { timerSinceComplete += GetDeltaTime(); if (timerSinceComplete > exitDuration) { outer.SetNextStateToMain(); } } } public override void OnExit() { if (!outer.destroying) { Util.PlaySound(exitSoundString, base.gameObject); } if ((bool)effectMuzzleInstance) { EntityState.Destroy(effectMuzzleInstance); } crosshairOverrideRequest?.Dispose(); base.skillLocator.primary = originalPrimarySkill; base.skillLocator.secondary = originalSecondarySkill; if ((bool)modelAnimator) { modelAnimator.SetBool(PrepSupplyDropStateHash, value: false); } if ((bool)blueprints) { EntityState.Destroy(blueprints.gameObject); blueprints = null; } aimRequest?.Dispose(); base.OnExit(); } public static PlacementInfo GetPlacementInfo(Ray aimRay, GameObject gameObject) { float extraRaycastDistance = 0f; CameraRigController.ModifyAimRayIfApplicable(aimRay, gameObject, out extraRaycastDistance); UnityEngine.Vector3 vector = -aimRay.direction; UnityEngine.Vector3 vector2 = UnityEngine.Vector3.up; UnityEngine.Vector3 lhs = UnityEngine.Vector3.Cross(vector2, vector); PlacementInfo result = default(PlacementInfo); result.ok = false; if (Physics.Raycast(aimRay, out var hitInfo, maxPlacementDistance, LayerIndex.world.mask) && hitInfo.normal.y > normalYThreshold) { vector2 = hitInfo.normal; vector = UnityEngine.Vector3.Cross(lhs, vector2); result.ok = true; } result.rotation = Util.QuaternionSafeLookRotation(vector, vector2); UnityEngine.Vector3 point = hitInfo.point; result.position = point; return result; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class CallSupplyDropBase : BaseSkillState { [SerializeField] public GameObject muzzleflashEffect; [SerializeField] public GameObject supplyDropPrefab; public static string muzzleString; public static float baseDuration; public static float impactDamageCoefficient; public static float impactDamageForce; public SetupSupplyDrop.PlacementInfo placementInfo; private static int CallSupplyDropStateHash = Animator.StringToHash("CallSupplyDrop"); private static int CallSupplyDropParamHash = Animator.StringToHash("CallSupplyDrop.playbackRate"); private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty"); private float duration => baseDuration / attackSpeedStat; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { placementInfo = SetupSupplyDrop.GetPlacementInfo(GetAimRay(), base.gameObject); if (placementInfo.ok) { base.activatorSkillSlot.DeductStock(1); } } if (placementInfo.ok) { EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, muzzleString, transmit: false); base.characterBody.SetAimTimer(3f); PlayAnimation("Gesture, Additive", CallSupplyDropStateHash, CallSupplyDropParamHash, duration); PlayAnimation("Gesture, Override", CallSupplyDropStateHash, CallSupplyDropParamHash, duration); if (NetworkServer.active) { GameObject obj = UnityEngine.Object.Instantiate(supplyDropPrefab, placementInfo.position, placementInfo.rotation); obj.GetComponent().teamIndex = base.teamComponent.teamIndex; obj.GetComponent().ownerObject = base.gameObject; Deployable component = obj.GetComponent(); if ((bool)component && (bool)base.characterBody.master) { base.characterBody.master.AddDeployable(component, DeployableSlot.CaptainSupplyDrop); } ProjectileDamage component2 = obj.GetComponent(); component2.crit = RollCrit(); component2.damage = damageStat * impactDamageCoefficient; component2.damageColorIndex = DamageColorIndex.Default; component2.force = impactDamageForce; component2.damageType = DamageType.Generic; NetworkServer.Spawn(obj); } } else { PlayCrossfade("Gesture, Additive", BufferEmptyStateHash, 0.1f); PlayCrossfade("Gesture, Additive", BufferEmptyStateHash, 0.1f); } EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Skillswap"); if ((bool)entityStateMachine) { entityStateMachine.SetNextStateToMain(); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); placementInfo.Serialize(writer); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); placementInfo.Deserialize(reader); } } public class CallSupplyDropHealing : CallSupplyDropBase { } public class CallSupplyDropPlating : CallSupplyDropBase { } public class CallSupplyDropEquipmentRestock : CallSupplyDropBase { } public class CallSupplyDropForce : CallSupplyDropBase { } public class CallSupplyDropHacking : CallSupplyDropBase { } public class CallSupplyDropShocking : CallSupplyDropBase { } public class ChargeCaptainShotgun : BaseState { public static float baseMinChargeDuration; public static float baseChargeDuration; public static string muzzleName; public static GameObject chargeupVfxPrefab; public static GameObject holdChargeVfxPrefab; public static string enterSoundString; public static string playChargeSoundString; public static string stopChargeSoundString; private float minChargeDuration; private float chargeDuration; private bool released; private GameObject chargeupVfxGameObject; private GameObject holdChargeVfxGameObject; private Transform muzzleTransform; private uint enterSoundID; public override void OnEnter() { base.OnEnter(); minChargeDuration = baseMinChargeDuration / attackSpeedStat; chargeDuration = baseChargeDuration / attackSpeedStat; PlayCrossfade("Gesture, Override", "ChargeCaptainShotgun", "ChargeCaptainShotgun.playbackRate", chargeDuration, 0.1f); PlayCrossfade("Gesture, Additive", "ChargeCaptainShotgun", "ChargeCaptainShotgun.playbackRate", chargeDuration, 0.1f); muzzleTransform = FindModelChild(muzzleName); if ((bool)muzzleTransform) { chargeupVfxGameObject = UnityEngine.Object.Instantiate(chargeupVfxPrefab, muzzleTransform); chargeupVfxGameObject.GetComponent().newDuration = chargeDuration; } enterSoundID = Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); Util.PlaySound(playChargeSoundString, base.gameObject); } public override void OnExit() { if ((bool)chargeupVfxGameObject) { EntityState.Destroy(chargeupVfxGameObject); chargeupVfxGameObject = null; } if ((bool)holdChargeVfxGameObject) { EntityState.Destroy(holdChargeVfxGameObject); holdChargeVfxGameObject = null; } AkSoundEngine.StopPlayingID(enterSoundID); Util.PlaySound(stopChargeSoundString, base.gameObject); base.OnExit(); } public override void Update() { base.Update(); base.characterBody.SetSpreadBloom(base.age / chargeDuration); } public override void FixedUpdate() { base.FixedUpdate(); base.characterBody.SetAimTimer(1f); Mathf.Clamp01(base.fixedAge / chargeDuration); if (base.fixedAge >= chargeDuration) { if ((bool)chargeupVfxGameObject) { EntityState.Destroy(chargeupVfxGameObject); chargeupVfxGameObject = null; } if (!holdChargeVfxGameObject && (bool)muzzleTransform) { holdChargeVfxGameObject = UnityEngine.Object.Instantiate(holdChargeVfxPrefab, muzzleTransform); } } if (base.isAuthority) { if (!released && (!base.inputBank || !base.inputBank.skill1.down)) { released = true; } if (released) { outer.SetNextState(new FireCaptainShotgun()); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireCaptainShotgun : GenericBulletBaseState { public static float tightSoundSwitchThreshold; public static string wideSoundString; public static string tightSoundString; private static int FireCaptainShotgunStateHash = Animator.StringToHash("FireCaptainShotgun"); public override void OnEnter() { fireSoundString = ((base.characterBody.spreadBloomAngle <= tightSoundSwitchThreshold) ? tightSoundString : wideSoundString); base.OnEnter(); PlayAnimation("Gesture, Additive", FireCaptainShotgunStateHash); PlayAnimation("Gesture, Override", FireCaptainShotgunStateHash); } protected override void ModifyBullet(BulletAttack bulletAttack) { base.ModifyBullet(bulletAttack); bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet; } public override void FixedUpdate() { base.FixedUpdate(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireTazer : BaseState { public static GameObject projectilePrefab; public static GameObject muzzleflashEffectPrefab; public static GameObject chargeEffectPrefab; public static float baseDelay = 0.1f; public static float baseDuration = 2f; public static float baseDurationUntilPriorityLowers = 1f; public static float damageCoefficient = 1.2f; public static float force = 20f; public static string enterSoundString; public static string attackString; public static float recoilAmplitude; public static float bloom; public static string targetMuzzle; private float duration; private float delay; private float durationUntilPriorityLowers; private static int FireTazerStateHash = Animator.StringToHash("FireTazer"); private static int FireTazerParamHash = Animator.StringToHash("FireTazer.playbackRate"); private bool hasFired; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; durationUntilPriorityLowers = baseDurationUntilPriorityLowers / attackSpeedStat; delay = baseDelay / attackSpeedStat; StartAimMode(duration + 2f); if ((bool)chargeEffectPrefab) { EffectManager.SimpleMuzzleFlash(chargeEffectPrefab, base.gameObject, targetMuzzle, transmit: false); } Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); PlayAnimation("Gesture, Additive", FireTazerStateHash, FireTazerParamHash, duration); PlayAnimation("Gesture, Override", FireTazerStateHash, FireTazerParamHash, duration); } private void Fire() { hasFired = true; Util.PlaySound(attackString, base.gameObject); AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude); base.characterBody.AddSpreadBloom(bloom); Ray ray = GetAimRay(); if ((bool)muzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, targetMuzzle, transmit: false); } if (base.isAuthority) { TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = ray.origin; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = force; fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master); ProjectileManager.instance.FireProjectile(fireProjectileInfo); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= delay && !hasFired) { Fire(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { if (!(base.fixedAge > durationUntilPriorityLowers)) { return InterruptPriority.PrioritySkill; } return InterruptPriority.Any; } } } namespace EntityStates.CaptainDefenseMatrixItem { public class DefenseMatrixOn : BaseBodyAttachmentState { public static float projectileEraserRadius; public static float minimumFireFrequency; public static float baseRechargeFrequency; public static GameObject tracerEffectPrefab; private float rechargeTimer; private float rechargeFrequency => baseRechargeFrequency * (base.attachedBody ? base.attachedBody.attackSpeed : 1f); private float fireFrequency => Mathf.Max(minimumFireFrequency, rechargeFrequency); private float timeBetweenFiring => 1f / fireFrequency; private bool isReadyToFire => rechargeTimer <= 0f; protected int GetItemStack() { if (!base.attachedBody || !base.attachedBody.inventory) { return 1; } return base.attachedBody.inventory.GetItemCount(RoR2Content.Items.CaptainDefenseMatrix); } public override void OnEnter() { base.OnEnter(); if (!base.attachedBody) { return; } PlayerCharacterMasterController component = base.attachedBody.master.GetComponent(); if ((bool)component) { NetworkUser networkUser = component.networkUser; if ((bool)networkUser) { PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(RoR2Content.Items.CaptainDefenseMatrix.itemIndex); networkUser.localUser?.userProfile.DiscoverPickup(pickupIndex); } } } public override void FixedUpdate() { base.FixedUpdate(); if (!NetworkServer.active) { return; } rechargeTimer -= GetDeltaTime(); if (base.fixedAge > timeBetweenFiring) { base.fixedAge -= timeBetweenFiring; if (isReadyToFire && DeleteNearbyProjectile()) { rechargeTimer = 1f / rechargeFrequency; } } } private bool DeleteNearbyProjectile() { UnityEngine.Vector3 vector = (base.attachedBody ? base.attachedBody.corePosition : UnityEngine.Vector3.zero); TeamIndex teamIndex = (base.attachedBody ? base.attachedBody.teamComponent.teamIndex : TeamIndex.None); float num = projectileEraserRadius * projectileEraserRadius; int num2 = 0; int itemStack = GetItemStack(); bool result = false; List instancesList = InstanceTracker.GetInstancesList(); List list = new List(); int i = 0; for (int count = instancesList.Count; i < count; i++) { if (num2 >= itemStack) { break; } ProjectileController projectileController = instancesList[i]; if (!projectileController.cannotBeDeleted && projectileController.teamFilter.teamIndex != teamIndex && (projectileController.transform.position - vector).sqrMagnitude < num) { list.Add(projectileController); num2++; } } int j = 0; for (int count2 = list.Count; j < count2; j++) { ProjectileController projectileController2 = list[j]; if ((bool)projectileController2) { result = true; UnityEngine.Vector3 position = projectileController2.transform.position; UnityEngine.Vector3 start = vector; if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = position, start = start }; EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } EntityState.Destroy(projectileController2.gameObject); } } return result; } } } namespace EntityStates.BrotherMonster { public class SkyLeapDeathState : GenericCharacterDeath { public static float baseDuration; private float duration; private static int SkyLeapStateHash = Animator.StringToHash("EnterSkyLeap"); private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty"); private static int SkyLeapParamHash = Animator.StringToHash("SkyLeap.playbackRate"); protected override bool shouldAutoDestroy => false; public override void OnEnter() { duration = baseDuration / attackSpeedStat; base.OnEnter(); } protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayAnimation("Body", SkyLeapStateHash, SkyLeapParamHash, duration); PlayAnimation("FullBody Override", BufferEmptyStateHash); base.characterDirection.moveVector = base.characterDirection.forward; AimAnimator aimAnimator = GetAimAnimator(); if ((bool)aimAnimator) { aimAnimator.enabled = true; } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { DestroyBodyAsapServer(); } } } public class InstantDeathState : GenericCharacterDeath { public static GameObject deathEffectPrefab; protected override bool shouldAutoDestroy => false; public override void OnEnter() { base.OnEnter(); DestroyModel(); if (NetworkServer.active) { DestroyBodyAsapServer(); } } protected override void CreateDeathEffects() { base.CreateDeathEffects(); EffectManager.SimpleMuzzleFlash(deathEffectPrefab, base.gameObject, "MuzzleCenter", transmit: false); } } public class TrueDeathState : GenericCharacterDeath { public static float durationBeforeDissolving; public static float dissolveDuration; public static GameObject deathEffectPrefab; private static int TrueDeathStateHash = Animator.StringToHash("TrueDeath"); private bool dissolving; protected override bool shouldAutoDestroy => base.fixedAge > durationBeforeDissolving + dissolveDuration + 1f; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { Util.CleanseBody(base.characterBody, removeDebuffs: true, removeBuffs: true, removeCooldownBuffs: true, removeDots: true, removeStun: false, removeNearbyProjectiles: false); ReturnStolenItemsOnGettingHit component = GetComponent(); if ((bool)component && (bool)component.itemStealController) { EntityState.Destroy(component.itemStealController.gameObject); } } } protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f) { PlayAnimation("FullBody Override", TrueDeathStateHash); base.characterDirection.moveVector = base.characterDirection.forward; EffectManager.SimpleMuzzleFlash(deathEffectPrefab, base.gameObject, "MuzzleCenter", transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= durationBeforeDissolving) { Dissolve(); } } private void Dissolve() { if (!dissolving) { dissolving = true; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { modelTransform.gameObject.GetComponent(); PrintController component = base.modelLocator.modelTransform.gameObject.GetComponent(); component.enabled = false; component.printTime = dissolveDuration; component.enabled = true; } Transform transform = FindModelChild("TrueDeathEffect"); if ((bool)transform) { transform.gameObject.SetActive(value: true); transform.GetComponent().newDuration = dissolveDuration; } } } } public class FistSlam : BaseState { public static float baseDuration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float upwardForce; public static float radius = 3f; public static string attackSoundString; public static string muzzleString; public static float healthCostFraction; public static GameObject chargeEffectPrefab; public static GameObject slamImpactEffect; public static GameObject waveProjectilePrefab; public static int waveProjectileCount; public static float waveProjectileDamageCoefficient; public static float waveProjectileForce; private BlastAttack attack; private Animator modelAnimator; private Transform modelTransform; private bool hasAttacked; private float duration; private GameObject chargeInstance; private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty"); public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); PlayCrossfade("FullBody Override", "FistSlam", "FistSlam.playbackRate", duration, 0.1f); if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if ((bool)modelTransform) { AimAnimator component = modelTransform.GetComponent(); if ((bool)component) { component.enabled = true; } } Transform transform = FindModelChild("MuzzleRight"); if ((bool)transform && (bool)chargeEffectPrefab) { chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); chargeInstance.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeInstance.GetComponent(); if ((bool)component2) { component2.newDuration = duration / 2.8f; } } } public override void OnExit() { if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } PlayAnimation("FullBody Override", BufferEmptyStateHash); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)modelAnimator && modelAnimator.GetFloat("fist.hitBoxActive") > 0.5f && !hasAttacked) { if ((bool)chargeInstance) { EntityState.Destroy(chargeInstance); } EffectManager.SimpleMuzzleFlash(slamImpactEffect, base.gameObject, muzzleString, transmit: false); if (NetworkServer.active && (bool)base.healthComponent) { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction; damageInfo.position = base.characterBody.corePosition; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.damageColorIndex = DamageColorIndex.Default; damageInfo.crit = false; damageInfo.attacker = null; damageInfo.inflictor = null; damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor; damageInfo.procCoefficient = 0f; damageInfo.procChainMask = default(ProcChainMask); base.healthComponent.TakeDamage(damageInfo); } if (base.isAuthority) { if ((bool)modelTransform) { Transform transform = FindModelChild(muzzleString); if ((bool)transform) { attack = new BlastAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); attack.baseDamage = damageStat * damageCoefficient; attack.baseForce = forceMagnitude; attack.position = transform.position; attack.radius = radius; attack.bonusForce = new UnityEngine.Vector3(0f, upwardForce, 0f); attack.Fire(); } } float num = 360f / (float)waveProjectileCount; UnityEngine.Vector3 vector = UnityEngine.Vector3.ProjectOnPlane(base.inputBank.aimDirection, UnityEngine.Vector3.up); UnityEngine.Vector3 footPosition = base.characterBody.footPosition; for (int i = 0; i < waveProjectileCount; i++) { UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num * (float)i, UnityEngine.Vector3.up) * vector; ProjectileManager.instance.FireProjectile(waveProjectilePrefab, footPosition, Util.QuaternionSafeLookRotation(forward), base.gameObject, base.characterBody.damage * waveProjectileDamageCoefficient, waveProjectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master)); } } hasAttacked = true; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } } public class EnterSkyLeap : BaseState { public static float baseDuration; public static string soundString; private float duration; private static int EnterSkyLeapStateHash = Animator.StringToHash("EnterSkyLeap"); private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty"); private static int SkyLeapParamHash = Animator.StringToHash("SkyLeap.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(soundString, base.gameObject); PlayAnimation("Body", EnterSkyLeapStateHash, SkyLeapParamHash, duration); PlayAnimation("FullBody Override", BufferEmptyStateHash); base.characterDirection.moveVector = base.characterDirection.forward; base.characterBody.AddTimedBuff(RoR2Content.Buffs.ArmorBoost, baseDuration); AimAnimator aimAnimator = GetAimAnimator(); if ((bool)aimAnimator) { aimAnimator.enabled = true; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { outer.SetNextState(new HoldSkyLeap()); } } } public class ExitSkyLeap : BaseState { public static float baseDuration; public static float baseDurationUntilRecastInterrupt; public static string soundString; public static GameObject waveProjectilePrefab; public static int waveProjectileCount; public static float waveProjectileDamageCoefficient; public static float waveProjectileForce; public static float recastChance; public static int cloneCount; public static int cloneDuration; public static SkillDef replacementSkillDef; private float duration; private float durationUntilRecastInterrupt; private bool recast; private static int ExitSkyLeapStateHash = Animator.StringToHash("ExitSkyLeap"); private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty"); private static int SkyLeapParamHash = Animator.StringToHash("SkyLeap.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Util.PlaySound(soundString, base.gameObject); PlayAnimation("Body", ExitSkyLeapStateHash, SkyLeapParamHash, duration); PlayAnimation("FullBody Override", BufferEmptyStateHash); base.characterBody.AddTimedBuff(RoR2Content.Buffs.ArmorBoost, baseDuration); AimAnimator aimAnimator = GetAimAnimator(); if ((bool)aimAnimator) { aimAnimator.enabled = true; } if (base.isAuthority) { FireRingAuthority(); } if (!PhaseCounter.instance || PhaseCounter.instance.phase != 3) { return; } if (UnityEngine.Random.value < recastChance) { recast = true; } for (int i = 0; i < cloneCount; i++) { DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load("SpawnCards/CharacterSpawnCards/cscBrotherGlass"), new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = 3f, maxDistance = 20f, spawnOnTarget = base.gameObject.transform }, RoR2Application.rng); directorSpawnRequest.summonerBodyObject = base.gameObject; directorSpawnRequest.onSpawnedServer = (Action)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action)delegate(SpawnCard.SpawnResult spawnResult) { spawnResult.spawnedInstance.GetComponent().GiveItem(RoR2Content.Items.HealthDecay, cloneDuration); }); DirectorCore.instance.TrySpawnObject(directorSpawnRequest); } GenericSkill genericSkill = (base.skillLocator ? base.skillLocator.special : null); if ((bool)genericSkill) { genericSkill.SetSkillOverride(outer, UltChannelState.replacementSkillDef, GenericSkill.SkillOverridePriority.Contextual); } } private void FireRingAuthority() { float num = 360f / (float)waveProjectileCount; UnityEngine.Vector3 vector = UnityEngine.Vector3.ProjectOnPlane(base.inputBank.aimDirection, UnityEngine.Vector3.up); UnityEngine.Vector3 footPosition = base.characterBody.footPosition; for (int i = 0; i < waveProjectileCount; i++) { UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num * (float)i, UnityEngine.Vector3.up) * vector; if (base.isAuthority) { ProjectileManager.instance.FireProjectile(waveProjectilePrefab, footPosition, Util.QuaternionSafeLookRotation(forward), base.gameObject, base.characterBody.damage * waveProjectileDamageCoefficient, waveProjectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master)); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { if (recast && base.fixedAge > baseDurationUntilRecastInterrupt) { outer.SetNextState(new EnterSkyLeap()); } if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } } } public class HoldSkyLeap : BaseState { public static float duration; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private int originalLayer; public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { characterModel = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); } if ((bool)characterModel) { characterModel.invisibilityCount++; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); Util.PlaySound("Play_moonBrother_phaseJump_land_preWhoosh", base.gameObject); originalLayer = base.gameObject.layer; base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal; base.characterMotor.Motor.RebuildCollidableLayers(); if (!SceneInfo.instance) { return; } ChildLocator component = SceneInfo.instance.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("CenterOfArena"); if ((bool)transform) { base.characterMotor.Motor.SetPositionAndRotation(transform.position, UnityEngine.Quaternion.identity); } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { outer.SetNextState(new ExitSkyLeap()); } } public override void OnExit() { if ((bool)characterModel) { characterModel.invisibilityCount--; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); base.gameObject.layer = originalLayer; base.characterMotor.Motor.RebuildCollidableLayers(); base.OnExit(); } } public class BaseSlideState : BaseState { public static float duration; public static AnimationCurve speedCoefficientCurve; public static AnimationCurve jumpforwardSpeedCoefficientCurve; public static string soundString; public static GameObject slideEffectPrefab; public static string slideEffectMuzzlestring; protected UnityEngine.Vector3 slideVector; protected UnityEngine.Quaternion slideRotation; public override void OnEnter() { base.OnEnter(); Util.PlaySound(soundString, base.gameObject); if ((bool)base.inputBank) { _ = (bool)base.characterDirection; } if (NetworkServer.active) { Util.CleanseBody(base.characterBody, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: false, removeDots: false, removeStun: false, removeNearbyProjectiles: false); } if ((bool)slideEffectPrefab && (bool)base.characterBody) { UnityEngine.Vector3 position = base.characterBody.corePosition; UnityEngine.Quaternion rotation = UnityEngine.Quaternion.identity; Transform transform = FindModelChild(slideEffectMuzzlestring); if ((bool)transform) { position = transform.position; } if ((bool)base.characterDirection) { rotation = Util.QuaternionSafeLookRotation(slideRotation * base.characterDirection.forward, UnityEngine.Vector3.up); } EffectManager.SimpleEffect(slideEffectPrefab, position, rotation, transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { UnityEngine.Vector3 vector = UnityEngine.Vector3.zero; if ((bool)base.inputBank && (bool)base.characterDirection) { vector = base.characterDirection.forward; } if ((bool)base.characterMotor) { float num = speedCoefficientCurve.Evaluate(base.fixedAge / duration); base.characterMotor.rootMotion += slideRotation * (num * moveSpeedStat * vector * GetDeltaTime()); } if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } public override void OnExit() { if (!outer.destroying) { PlayImpactAnimation(); } base.OnExit(); } private void PlayImpactAnimation() { } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SlideIntroState : BaseState { public override void OnEnter() { base.OnEnter(); bool flag = false; if ((bool)base.inputBank && base.isAuthority) { UnityEngine.Vector3 normalized = ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized; UnityEngine.Vector3 forward = base.characterDirection.forward; UnityEngine.Vector3 rhs = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, forward); float num = UnityEngine.Vector3.Dot(normalized, forward); float num2 = UnityEngine.Vector3.Dot(normalized, rhs); if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.inputBank.aimDirection; } if (Mathf.Abs(num2) > Mathf.Abs(num)) { if (num2 <= 0f) { flag = true; outer.SetNextState(new SlideLeftState()); } else { flag = true; outer.SetNextState(new SlideRightState()); } } else if (num <= 0f) { flag = true; outer.SetNextState(new SlideBackwardState()); } else { flag = true; outer.SetNextState(new SlideForwardState()); } } if (!flag) { outer.SetNextState(new SlideForwardState()); } } } public class SlideLeftState : BaseSlideState { public override void OnEnter() { slideRotation = UnityEngine.Quaternion.AngleAxis(-90f, UnityEngine.Vector3.up); base.OnEnter(); PlayCrossfade("FullBody Override", "SlideLeft", "Slide.playbackRate", BaseSlideState.duration, 0.05f); } } public class SlideRightState : BaseSlideState { public override void OnEnter() { slideRotation = UnityEngine.Quaternion.AngleAxis(90f, UnityEngine.Vector3.up); base.OnEnter(); PlayCrossfade("FullBody Override", "SlideRight", "Slide.playbackRate", BaseSlideState.duration, 0.05f); } } public class SlideForwardState : BaseSlideState { public override void OnEnter() { slideRotation = UnityEngine.Quaternion.identity; base.OnEnter(); PlayCrossfade("FullBody Override", "SlideForward", "Slide.playbackRate", BaseSlideState.duration, 0.05f); PlayCrossfade("Body", "Run", 0.05f); } public override void OnExit() { base.OnExit(); } } public class SlideBackwardState : BaseSlideState { public override void OnEnter() { slideRotation = UnityEngine.Quaternion.AngleAxis(-180f, UnityEngine.Vector3.up); base.OnEnter(); PlayCrossfade("FullBody Override", "SlideBackward", "Slide.playbackRate", BaseSlideState.duration, 0.05f); } } public class SkySpawnState : BaseState { public static float duration; public static string soundString; private static int ExitSkyLeapStateHash = Animator.StringToHash("ExitSkyLeap"); private static int BufferEmptyLeapStateHash = Animator.StringToHash("BufferEmpty"); private static int SkyLeapParamHash = Animator.StringToHash("SkyLeap.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", ExitSkyLeapStateHash, SkyLeapParamHash, duration); PlayAnimation("FullBody Override", BufferEmptyLeapStateHash); Util.PlaySound(soundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } } public class ThroneSpawnState : BaseState { public static GameObject spawnEffectPrefab; public static string muzzleString; public static float initialDelay; public static float duration; private bool hasPlayedAnimation; private static int ThroneStateHash = Animator.StringToHash("Throne"); private static int ThroneToIdleStateHash = Animator.StringToHash("ThroneToIdle"); private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty"); private static int ThroneToIdleParamHash = Animator.StringToHash("ThroneToIdle.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", ThroneStateHash); PlayAnimation("FullBody Override", BufferEmptyStateHash); EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, muzzleString, transmit: false); } private void PlayAnimation() { hasPlayedAnimation = true; PlayAnimation("Body", ThroneToIdleStateHash, ThroneToIdleParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > initialDelay && !hasPlayedAnimation) { PlayAnimation(); } if (base.fixedAge > initialDelay + duration) { outer.SetNextStateToMain(); } } } public class SpellBaseState : BaseState { protected ItemStealController itemStealController; protected GameObject hammerRendererObject; protected virtual bool DisplayWeapon => false; public override void OnEnter() { base.OnEnter(); FindItemStealer(); if (NetworkServer.active && !itemStealController) { InitItemStealer(); } hammerRendererObject = FindModelChild("HammerRenderer").gameObject; if ((bool)hammerRendererObject) { hammerRendererObject.SetActive(DisplayWeapon); } } public override void OnExit() { if ((bool)hammerRendererObject) { hammerRendererObject.SetActive(value: false); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); FindItemStealer(); } private void FindItemStealer() { if ((bool)itemStealController) { return; } List list = new List(); NetworkedBodyAttachment.FindBodyAttachments(base.characterBody, list); foreach (NetworkedBodyAttachment item in list) { itemStealController = item.GetComponent(); if ((bool)itemStealController) { break; } } } private void InitItemStealer() { if (NetworkServer.active && itemStealController == null) { GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/ItemStealController"), base.transform.position, UnityEngine.Quaternion.identity); itemStealController = gameObject.GetComponent(); itemStealController.itemLendFilter = ItemStealController.BrotherItemFilter; gameObject.GetComponent().AttachToGameObjectAndSpawn(base.gameObject); base.gameObject.GetComponent().itemStealController = itemStealController; NetworkServer.Spawn(gameObject); } } } public class SpellChannelEnterState : SpellBaseState { public static GameObject channelBeginEffectPrefab; public static float duration; private Transform trueDeathEffect; private static int SpellChannerEnterStateHash = Animator.StringToHash("SpellChannelEnter"); private static int SpellChannelEnterParamHash = Animator.StringToHash("SpellChannelEnter.playbackRate"); protected override bool DisplayWeapon => false; public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpellChannerEnterStateHash, SpellChannelEnterParamHash, duration); Util.PlaySound("Play_moonBrother_phase4_transition", base.gameObject); trueDeathEffect = FindModelChild("TrueDeathEffect"); if ((bool)trueDeathEffect) { trueDeathEffect.gameObject.SetActive(value: true); trueDeathEffect.GetComponent().newDuration = 10f; } HurtBoxGroup component = GetModelTransform().GetComponent(); if ((bool)component) { int hurtBoxesDeactivatorCounter = component.hurtBoxesDeactivatorCounter + 1; component.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { outer.SetNextState(new SpellChannelState()); } } public override void OnExit() { HurtBoxGroup component = GetModelTransform().GetComponent(); if ((bool)component) { int hurtBoxesDeactivatorCounter = component.hurtBoxesDeactivatorCounter - 1; component.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)channelBeginEffectPrefab) { EffectManager.SimpleMuzzleFlash(channelBeginEffectPrefab, base.gameObject, "SpellChannel", transmit: false); } if ((bool)trueDeathEffect) { trueDeathEffect.gameObject.SetActive(value: false); } base.OnExit(); } } public class SpellChannelState : SpellBaseState { public static float stealInterval; public static float delayBeforeBeginningSteal; public static float maxDuration; public static GameObject channelEffectPrefab; private bool hasBegunSteal; private GameObject channelEffectInstance; private Transform spellChannelChildTransform; private bool hasSubscribedToStealFinish; private static int SpellChannelStateHash = Animator.StringToHash("SpellChannel"); protected override bool DisplayWeapon => false; public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpellChannelStateHash); Util.PlaySound("Play_moonBrother_phase4_itemSuck_start", base.gameObject); spellChannelChildTransform = FindModelChild("SpellChannel"); if ((bool)spellChannelChildTransform) { channelEffectInstance = UnityEngine.Object.Instantiate(channelEffectPrefab, spellChannelChildTransform.position, UnityEngine.Quaternion.identity, spellChannelChildTransform); } base.characterBody.AddBuff(RoR2Content.Buffs.Immune); } public override void FixedUpdate() { base.FixedUpdate(); if (!itemStealController) { return; } if (!hasSubscribedToStealFinish && base.isAuthority) { hasSubscribedToStealFinish = true; if (NetworkServer.active) { itemStealController.onStealFinishServer.AddListener(OnStealEndAuthority); } else { itemStealController.onStealFinishClient += OnStealEndAuthority; } } if (NetworkServer.active && base.fixedAge > delayBeforeBeginningSteal && !hasBegunSteal) { hasBegunSteal = true; itemStealController.stealInterval = stealInterval; TeamIndex teamIndex = GetTeam(); itemStealController.StartSteal((CharacterMaster characterMaster) => characterMaster.teamIndex != teamIndex && characterMaster.hasBody); } if (base.isAuthority && base.fixedAge > delayBeforeBeginningSteal + maxDuration) { outer.SetNextState(new SpellChannelExitState()); } if ((bool)spellChannelChildTransform) { itemStealController.transform.position = spellChannelChildTransform.position; } } public override void OnExit() { if ((bool)itemStealController && hasSubscribedToStealFinish) { itemStealController.onStealFinishServer.RemoveListener(OnStealEndAuthority); itemStealController.onStealFinishClient -= OnStealEndAuthority; } if ((bool)channelEffectInstance) { EntityState.Destroy(channelEffectInstance); } Util.PlaySound("Play_moonBrother_phase4_itemSuck_end", base.gameObject); base.characterBody.RemoveBuff(RoR2Content.Buffs.Immune); base.OnExit(); } private void OnStealEndAuthority() { outer.SetNextState(new SpellChannelExitState()); } } public class SpellChannelExitState : SpellBaseState { public static float lendInterval; public static float duration; public static GameObject channelFinishEffectPrefab; private static int SpellChannelExitStateHash = Animator.StringToHash("SpellChannelExit"); private static int SpellChannelExitParamHash = Animator.StringToHash("SpellChannelExit.playbackRate"); protected override bool DisplayWeapon => false; public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpellChannelExitStateHash, SpellChannelExitParamHash, duration); if (NetworkServer.active && (bool)itemStealController) { itemStealController.stealInterval = lendInterval; itemStealController.LendImmediately(base.characterBody.inventory); } if ((bool)channelFinishEffectPrefab) { EffectManager.SimpleMuzzleFlash(channelFinishEffectPrefab, base.gameObject, "SpellChannel", transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } public override void OnExit() { SetStateOnHurt component = GetComponent(); if ((bool)component) { component.canBeFrozen = true; } base.OnExit(); } } public class SprintBash : BasicMeleeAttack { public static float durationBeforePriorityReduces; protected override void PlayAnimation() { PlayCrossfade("FullBody Override", "SprintBash", "SprintBash.playbackRate", duration, 0.05f); } public override void OnEnter() { base.OnEnter(); AimAnimator aimAnimator = GetAimAnimator(); if ((bool)aimAnimator) { aimAnimator.enabled = true; } if ((bool)base.characterDirection) { base.characterDirection.forward = base.inputBank.aimDirection; } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && (bool)base.inputBank && (bool)base.skillLocator && base.skillLocator.utility.IsReady() && base.inputBank.skill3.justPressed) { base.skillLocator.utility.ExecuteIfReady(); } } public override void OnExit() { Transform transform = FindModelChild("SpinnyFX"); if ((bool)transform) { transform.gameObject.SetActive(value: false); } PlayCrossfade("FullBody Override", "BufferEmpty", 0.1f); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { if (!(base.fixedAge > durationBeforePriorityReduces)) { return InterruptPriority.PrioritySkill; } return InterruptPriority.Skill; } } public class StaggerBaseState : BaseState { [SerializeField] public float duration; public virtual EntityState nextState => null; public override void OnEnter() { base.OnEnter(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class StaggerEnter : StaggerBaseState { public static GameObject effectPrefab; public static string effectMuzzleString; private static int StaggerEnterStateHash = Animator.StringToHash("StaggerEnter"); private static int StaggerParamHash = Animator.StringToHash("Stagger.playbackRate"); public override EntityState nextState => new StaggerLoop(); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", StaggerEnterStateHash, StaggerParamHash, duration); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, effectMuzzleString, transmit: false); } } } public class StaggerLoop : StaggerBaseState { private static int StaggerLoopStateHash = Animator.StringToHash("StaggerLoop"); public override EntityState nextState => new StaggerExit(); public override void OnEnter() { base.OnEnter(); PlayCrossfade("Body", "StaggerLoop", 0.2f); PlayCrossfade("Body", StaggerLoopStateHash, 0.2f); } } public class StaggerExit : StaggerBaseState { private static int StaggerExitStateHash = Animator.StringToHash("StaggerExit"); private static int StaggerParamHash = Animator.StringToHash("Stagger.playbackRate"); public override EntityState nextState => new GenericCharacterMain(); public override void OnEnter() { base.OnEnter(); PlayCrossfade("Body", StaggerExitStateHash, StaggerParamHash, duration, 0.1f); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } public class UltEnterState : BaseState { public static string soundString; public static float duration; public override void OnEnter() { base.OnEnter(); PlayCrossfade("Body", "UltEnter", "Ult.playbackRate", duration, 0.1f); Util.PlaySound(soundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { outer.SetNextState(new UltChannelState()); } } } public class UltChannelState : BaseState { public static GameObject waveProjectileLeftPrefab; public static GameObject waveProjectileRightPrefab; public static int waveProjectileCount; public static float waveProjectileDamageCoefficient; public static float waveProjectileForce; public static int totalWaves; public static float maxDuration; public static GameObject channelBeginMuzzleflashEffectPrefab; public static GameObject channelEffectPrefab; public static string enterSoundString; public static string exitSoundString; private GameObject channelEffectInstance; public static SkillDef replacementSkillDef; private int wavesFired; public override void OnEnter() { base.OnEnter(); Util.PlaySound(enterSoundString, base.gameObject); Transform transform = FindModelChild("MuzzleUlt"); if ((bool)transform && (bool)channelEffectPrefab) { channelEffectInstance = UnityEngine.Object.Instantiate(channelEffectPrefab, transform.position, UnityEngine.Quaternion.identity, transform); } if ((bool)channelBeginMuzzleflashEffectPrefab) { EffectManager.SimpleMuzzleFlash(channelBeginMuzzleflashEffectPrefab, base.gameObject, "MuzzleUlt", transmit: false); } } private void FireWave() { wavesFired++; float num = 360f / (float)waveProjectileCount; UnityEngine.Vector3 normalized = UnityEngine.Vector3.ProjectOnPlane(UnityEngine.Random.onUnitSphere, UnityEngine.Vector3.up).normalized; UnityEngine.Vector3 footPosition = base.characterBody.footPosition; GameObject prefab = waveProjectileLeftPrefab; if (UnityEngine.Random.value <= 0.5f) { prefab = waveProjectileRightPrefab; } for (int i = 0; i < waveProjectileCount; i++) { UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num * (float)i, UnityEngine.Vector3.up) * normalized; ProjectileManager.instance.FireProjectile(prefab, footPosition, Util.QuaternionSafeLookRotation(forward), base.gameObject, base.characterBody.damage * waveProjectileDamageCoefficient, waveProjectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master)); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { if (Mathf.CeilToInt(base.fixedAge / maxDuration * (float)totalWaves) > wavesFired) { FireWave(); } if (base.fixedAge > maxDuration) { outer.SetNextState(new UltExitState()); } } } public override void OnExit() { Util.PlaySound(exitSoundString, base.gameObject); if ((bool)channelEffectInstance) { EntityState.Destroy(channelEffectInstance); } base.OnExit(); } } public class UltExitState : BaseState { public static float lendInterval; public static float duration; public static string soundString; public static GameObject channelFinishEffectPrefab; private static int UltExitStateHash = Animator.StringToHash("UltExit"); private static int UltParamHash = Animator.StringToHash("Ult.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", UltExitStateHash, UltParamHash, duration); Util.PlaySound(soundString, base.gameObject); if ((bool)channelFinishEffectPrefab) { EffectManager.SimpleMuzzleFlash(channelFinishEffectPrefab, base.gameObject, "MuzzleUlt", transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } public override void OnExit() { GenericSkill genericSkill = (base.skillLocator ? base.skillLocator.special : null); if ((bool)genericSkill) { genericSkill.UnsetSkillOverride(outer, UltChannelState.replacementSkillDef, GenericSkill.SkillOverridePriority.Contextual); } base.OnExit(); } } public class WeaponSlam : BaseState { public static float duration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float upwardForce; public static float radius = 3f; public static string attackSoundString; public static string muzzleString; public static GameObject slamImpactEffect; public static float durationBeforePriorityReduces; public static GameObject waveProjectilePrefab; public static float waveProjectileArc; public static int waveProjectileCount; public static float waveProjectileDamageCoefficient; public static float waveProjectileForce; public static float weaponDamageCoefficient; public static float weaponForce; public static GameObject pillarProjectilePrefab; public static float pillarDamageCoefficient; public static GameObject weaponHitEffectPrefab; public static NetworkSoundEventDef weaponImpactSound; private BlastAttack blastAttack; private OverlapAttack weaponAttack; private Animator modelAnimator; private Transform modelTransform; private bool hasDoneBlastAttack; public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); PlayCrossfade("FullBody Override", "WeaponSlam", "WeaponSlam.playbackRate", duration, 0.1f); if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } if ((bool)modelTransform) { AimAnimator component = modelTransform.GetComponent(); if ((bool)component) { component.enabled = true; } } if (base.isAuthority) { weaponAttack = new OverlapAttack { attacker = base.gameObject, damage = damageCoefficient * damageStat, damageColorIndex = DamageColorIndex.Default, damageType = DamageType.Generic, hitEffectPrefab = weaponHitEffectPrefab, hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "WeaponBig"), impactSound = weaponImpactSound.index, inflictor = base.gameObject, procChainMask = default(ProcChainMask), pushAwayForce = weaponForce, procCoefficient = 1f, teamIndex = GetTeam() }; } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && (bool)base.inputBank && (bool)base.skillLocator && base.skillLocator.utility.IsReady() && base.inputBank.skill3.justPressed) { base.skillLocator.utility.ExecuteIfReady(); return; } if ((bool)modelAnimator) { if (base.isAuthority && modelAnimator.GetFloat("weapon.hitBoxActive") > 0.5f) { weaponAttack.Fire(); } if (modelAnimator.GetFloat("blast.hitBoxActive") > 0.5f && !hasDoneBlastAttack) { hasDoneBlastAttack = true; EffectManager.SimpleMuzzleFlash(slamImpactEffect, base.gameObject, muzzleString, transmit: false); if (base.isAuthority) { if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if ((bool)modelTransform) { Transform transform = FindModelChild(muzzleString); if ((bool)transform) { blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); blastAttack.baseDamage = damageStat * damageCoefficient; blastAttack.baseForce = forceMagnitude; blastAttack.position = transform.position; blastAttack.radius = radius; blastAttack.bonusForce = new UnityEngine.Vector3(0f, upwardForce, 0f); blastAttack.Fire(); } } if ((bool)PhaseCounter.instance && PhaseCounter.instance.phase == 3) { Transform transform2 = FindModelChild(muzzleString); float num = waveProjectileArc / (float)waveProjectileCount; UnityEngine.Vector3 vector = UnityEngine.Vector3.ProjectOnPlane(base.characterDirection.forward, UnityEngine.Vector3.up); UnityEngine.Vector3 position = base.characterBody.footPosition; if ((bool)transform2) { position = transform2.position; } for (int i = 0; i < waveProjectileCount; i++) { UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num * ((float)i - (float)waveProjectileCount / 2f), UnityEngine.Vector3.up) * vector; ProjectileManager.instance.FireProjectile(waveProjectilePrefab, position, Util.QuaternionSafeLookRotation(forward), base.gameObject, base.characterBody.damage * waveProjectileDamageCoefficient, waveProjectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master)); } ProjectileManager.instance.FireProjectile(pillarProjectilePrefab, position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * pillarDamageCoefficient, 0f, Util.CheckRoll(base.characterBody.crit, base.characterBody.master)); } } } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { if (!(base.fixedAge > durationBeforePriorityReduces)) { return InterruptPriority.PrioritySkill; } return InterruptPriority.Skill; } } } namespace EntityStates.BrotherMonster.Weapon { public class FireLunarShards : BaseSkillState { public static float baseDuration; [SerializeField] public float damageCoefficient; public static GameObject projectilePrefab; public static float recoilAmplitude; public static float spreadBloomValue; public static string muzzleString; public static GameObject muzzleFlashEffectPrefab; public static string fireSound; [SerializeField] public float maxSpread; [SerializeField] public float spreadYawScale; [SerializeField] public float spreadPitchScale; private float duration; private static int FireLunarShardsStateHash = Animator.StringToHash("FireLunarShards"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; if (base.isAuthority) { Ray aimRay = GetAimRay(); Transform transform = FindModelChild(muzzleString); if ((bool)transform) { aimRay.origin = transform.position; } aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, maxSpread, spreadYawScale, spreadPitchScale); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.position = aimRay.origin; fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction); fireProjectileInfo.crit = base.characterBody.RollCrit(); fireProjectileInfo.damage = base.characterBody.damage * damageCoefficient; fireProjectileInfo.damageColorIndex = DamageColorIndex.Default; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.procChainMask = default(ProcChainMask); fireProjectileInfo.force = 0f; fireProjectileInfo.useFuseOverride = false; fireProjectileInfo.useSpeedOverride = false; fireProjectileInfo.target = null; fireProjectileInfo.projectilePrefab = projectilePrefab; ProjectileManager.instance.FireProjectile(fireProjectileInfo); } PlayAnimation("Gesture, Additive", FireLunarShardsStateHash); PlayAnimation("Gesture, Override", FireLunarShardsStateHash); AddRecoil(-0.4f * recoilAmplitude, -0.8f * recoilAmplitude, -0.3f * recoilAmplitude, 0.3f * recoilAmplitude); base.characterBody.AddSpreadBloom(spreadBloomValue); EffectManager.SimpleMuzzleFlash(muzzleFlashEffectPrefab, base.gameObject, muzzleString, transmit: false); Util.PlaySound(fireSound, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge >= duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireLunarShardsHurt : FireLunarShards { } } namespace EntityStates.Bison { public class Charge : BaseState { public static float chargeDuration; public static float chargeMovementSpeedCoefficient; public static float turnSpeed; public static float turnSmoothTime; public static float impactDamageCoefficient; public static float impactForce; public static float damageCoefficient; public static float upwardForceMagnitude; public static float awayForceMagnitude; public static GameObject hitEffectPrefab; public static float overlapResetFrequency; public static float overlapSphereRadius; public static float selfStunDuration; public static float selfStunForce; public static string startSoundString; public static string endSoundString; public static string footstepOverrideSoundString; public static string headbuttImpactSound; private float stopwatch; private float overlapResetStopwatch; private Animator animator; private UnityEngine.Vector3 targetMoveVector; private UnityEngine.Vector3 targetMoveVectorVelocity; private ContactDamage contactDamage; private OverlapAttack attack; private HitBoxGroup hitboxGroup; private ChildLocator childLocator; private Transform sphereCheckTransform; private string baseFootstepString; private static int forwardSpeedParamHash = Animator.StringToHash("forwardSpeed"); public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); childLocator = animator.GetComponent(); FootstepHandler component = animator.GetComponent(); if ((bool)component) { baseFootstepString = component.baseFootstepString; component.baseFootstepString = footstepOverrideSoundString; } Util.PlaySound(startSoundString, base.gameObject); PlayCrossfade("Body", "ChargeForward", 0.2f); ResetOverlapAttack(); SetSprintEffectActive(active: true); if ((bool)childLocator) { sphereCheckTransform = childLocator.FindChild("SphereCheckTransform"); } if (!sphereCheckTransform && (bool)base.characterBody) { sphereCheckTransform = base.characterBody.coreTransform; } if (!sphereCheckTransform) { sphereCheckTransform = base.transform; } } private void SetSprintEffectActive(bool active) { if ((bool)childLocator) { childLocator.FindChild("SprintEffect")?.gameObject.SetActive(active); } } public override void OnExit() { base.OnExit(); base.characterMotor.moveDirection = UnityEngine.Vector3.zero; Util.PlaySound(endSoundString, base.gameObject); Util.PlaySound("stop_bison_charge_attack_loop", base.gameObject); SetSprintEffectActive(active: false); FootstepHandler component = animator.GetComponent(); if ((bool)component) { component.baseFootstepString = baseFootstepString; } } public override void FixedUpdate() { targetMoveVector = UnityEngine.Vector3.ProjectOnPlane(UnityEngine.Vector3.SmoothDamp(targetMoveVector, base.inputBank.aimDirection, ref targetMoveVectorVelocity, turnSmoothTime, turnSpeed), UnityEngine.Vector3.up).normalized; base.characterDirection.moveVector = targetMoveVector; UnityEngine.Vector3 forward = base.characterDirection.forward; float value = moveSpeedStat * chargeMovementSpeedCoefficient; base.characterMotor.moveDirection = forward * chargeMovementSpeedCoefficient; animator.SetFloat(forwardSpeedParamHash, value); if (base.isAuthority && attack.Fire()) { Util.PlaySound(headbuttImpactSound, base.gameObject); } if (overlapResetStopwatch >= 1f / overlapResetFrequency) { overlapResetStopwatch -= 1f / overlapResetFrequency; } if (base.isAuthority && HGPhysics.DoesOverlapSphere(sphereCheckTransform.position, overlapSphereRadius, LayerIndex.world.mask)) { Util.PlaySound(headbuttImpactSound, base.gameObject); EffectManager.SimpleMuzzleFlash(hitEffectPrefab, base.gameObject, "SphereCheckTransform", transmit: true); base.healthComponent.TakeDamageForce(forward * selfStunForce, alwaysApply: true); StunState stunState = new StunState(); stunState.stunDuration = selfStunDuration; outer.SetNextState(stunState); return; } float deltaTime = GetDeltaTime(); stopwatch += deltaTime; overlapResetStopwatch += deltaTime; if (stopwatch > chargeDuration) { outer.SetNextStateToMain(); } base.FixedUpdate(); } private void ResetOverlapAttack() { if (!hitboxGroup) { Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { hitboxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Charge"); } } attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.forceVector = UnityEngine.Vector3.up * upwardForceMagnitude; attack.pushAwayForce = awayForceMagnitude; attack.hitBoxGroup = hitboxGroup; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Headbutt : BaseState { public static float baseHeadbuttDuration; public static float damageCoefficient; public static string attackSoundString; public static GameObject hitEffectPrefab; public static float upwardForceMagnitude; public static float awayForceMagnitude; private float headbuttDuration; private float stopwatch; private OverlapAttack attack; private Animator animator; private bool hasAttacked; public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); animator = modelTransform.GetComponent(); headbuttDuration = baseHeadbuttDuration / attackSpeedStat; Util.PlaySound(attackSoundString, base.gameObject); PlayCrossfade("Body", "Headbutt", "Headbutt.playbackRate", headbuttDuration, 0.2f); base.characterMotor.moveDirection = UnityEngine.Vector3.zero; base.characterDirection.moveVector = base.characterDirection.forward; attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.forceVector = UnityEngine.Vector3.up * upwardForceMagnitude; attack.pushAwayForce = awayForceMagnitude; if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Headbutt"); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)animator && animator.GetFloat("Headbutt.hitBoxActive") > 0.5f) { if (NetworkServer.active) { attack.Fire(); } if (base.isAuthority && !hasAttacked) { hasAttacked = true; } } stopwatch += GetDeltaTime(); if (stopwatch > headbuttDuration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class PrepCharge : BaseState { public static float basePrepDuration; public static string enterSoundString; public static GameObject chargeEffectPrefab; private float stopwatch; private float prepDuration; private GameObject chargeEffectInstance; private EffectManagerHelper _emh_chargeEffectInstance; public override void Reset() { base.Reset(); prepDuration = 0f; chargeEffectInstance = null; _emh_chargeEffectInstance = null; } public override void OnEnter() { base.OnEnter(); prepDuration = basePrepDuration / attackSpeedStat; base.characterBody.SetAimTimer(prepDuration); PlayCrossfade("Body", "PrepCharge", "PrepCharge.playbackRate", prepDuration, 0.2f); Util.PlaySound(enterSoundString, base.gameObject); Transform modelTransform = GetModelTransform(); AimAnimator component = modelTransform.GetComponent(); if ((bool)component) { component.enabled = true; } if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } if (!modelTransform) { return; } ChildLocator component2 = modelTransform.GetComponent(); if (!component2) { return; } Transform transform = component2.FindChild("ChargeIndicator"); if ((bool)transform && (bool)chargeEffectPrefab) { if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab)) { chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation); chargeEffectInstance = _emh_chargeEffectInstance.gameObject; } chargeEffectInstance.transform.parent = transform; ScaleParticleSystemDuration component3 = chargeEffectInstance.GetComponent(); if ((bool)component3) { component3.newDuration = prepDuration; } } } public override void OnExit() { base.OnExit(); if ((bool)chargeEffectInstance) { if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null) { _emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance); } else { EntityState.Destroy(chargeEffectInstance); } chargeEffectInstance = null; _emh_chargeEffectInstance = null; } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch > prepDuration && base.isAuthority) { outer.SetNextState(new Charge()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : BaseState { public static GameObject spawnEffectPrefab; public static string spawnEffectMuzzle; public static float duration; public static float snowyOverlayDuration; public static Material snowyMaterial; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectMuzzle, transmit: false); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound("Play_bison_idle_graze", base.gameObject); Util.PlaySound("Play_bison_charge_attack_collide", base.gameObject); if ((bool)modelTransform) { CharacterModel component = modelTransform.GetComponent(); if ((bool)component && (bool)snowyMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(component.gameObject); temporaryOverlayInstance.duration = snowyOverlayDuration; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = snowyMaterial; temporaryOverlayInstance.inspectorCharacterModel = component; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } } } namespace EntityStates.Bell { public class DeathState : GenericCharacterDeath { public static GameObject initialEffect; public static float initialEffectScale; public static float velocityMagnitude; public static float explosionForce; protected override bool shouldAutoDestroy => false; public override void OnEnter() { base.OnEnter(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { if ((bool)modelTransform.GetComponent() && (bool)initialEffect) { EffectManager.SpawnEffect(initialEffect, new EffectData { origin = base.transform.position, scale = initialEffectScale }, transmit: false); } RagdollController component = modelTransform.GetComponent(); Rigidbody component2 = GetComponent(); if ((bool)component && (bool)component2) { component.BeginRagdoll(component2.velocity * velocityMagnitude); } ExplodeRigidbodiesOnStart component3 = modelTransform.GetComponent(); if ((bool)component3) { component3.force = explosionForce; component3.enabled = true; } } if ((bool)base.modelLocator) { base.modelLocator.autoUpdateModelTransform = false; } DestroyBodyAsapServer(); } } public class SpawnState : BaseState { public static float duration = 4f; public static string spawnSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); Util.PlaySound(spawnSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Bell.BellWeapon { public class BuffBeam : BaseState { public static float duration; public static GameObject buffBeamPrefab; public static AnimationCurve beamWidthCurve; public static string playBeamSoundString; public static string stopBeamSoundString; public HurtBox target; private float healTimer; private float healInterval; private float healChunk; private CharacterBody targetBody; private GameObject buffBeamInstance; private BezierCurveLine healBeamCurve; private Transform muzzleTransform; private Transform beamTipTransform; public override void OnEnter() { base.OnEnter(); Util.PlaySound(playBeamSoundString, base.gameObject); Ray aimRay = GetAimRay(); BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.teamMaskFilter = TeamMask.none; if ((bool)base.teamComponent) { bullseyeSearch.teamMaskFilter.AddTeam(base.teamComponent.teamIndex); } bullseyeSearch.filterByLoS = false; bullseyeSearch.maxDistanceFilter = 50f; bullseyeSearch.maxAngleFilter = 180f; bullseyeSearch.searchOrigin = aimRay.origin; bullseyeSearch.searchDirection = aimRay.direction; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle; bullseyeSearch.RefreshCandidates(); bullseyeSearch.FilterOutGameObject(base.gameObject); target = bullseyeSearch.GetResults().FirstOrDefault(); UnityEngine.Debug.LogFormat("Buffing target {0}", target); if ((bool)target) { targetBody = target.healthComponent.body; targetBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); } string childName = "Muzzle"; Transform modelTransform = GetModelTransform(); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { muzzleTransform = component.FindChild(childName); buffBeamInstance = UnityEngine.Object.Instantiate(buffBeamPrefab); ChildLocator component2 = buffBeamInstance.GetComponent(); if ((bool)component2) { beamTipTransform = component2.FindChild("BeamTip"); } healBeamCurve = buffBeamInstance.GetComponentInChildren(); } } private void UpdateHealBeamVisuals() { float widthMultiplier = beamWidthCurve.Evaluate(base.age / duration); healBeamCurve.lineRenderer.widthMultiplier = widthMultiplier; healBeamCurve.v0 = muzzleTransform.forward * 3f; healBeamCurve.transform.position = muzzleTransform.position; if ((bool)target) { beamTipTransform.position = targetBody.mainHurtBox.transform.position; } } public override void Update() { base.Update(); UpdateHealBeamVisuals(); } public override void FixedUpdate() { base.FixedUpdate(); if ((base.fixedAge >= duration || target == null) && base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { Util.PlaySound(stopBeamSoundString, base.gameObject); EntityState.Destroy(buffBeamInstance); if ((bool)targetBody) { targetBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); HurtBoxReference.FromHurtBox(target).Write(writer); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); HurtBoxReference hurtBoxReference = default(HurtBoxReference); hurtBoxReference.Read(reader); target = hurtBoxReference.ResolveGameObject()?.GetComponent(); } } public class ChargeTrioBomb : BaseState { public static float basePrepDuration; public static float baseTimeBetweenPreps; public static GameObject preppedBombPrefab; public static float baseBarrageDuration; public static float baseTimeBetweenBarrages; public static GameObject bombProjectilePrefab; public static GameObject muzzleflashPrefab; public static float damageCoefficient; public static float force; public static float selfForce; private float prepDuration; private float timeBetweenPreps; private float barrageDuration; private float timeBetweenBarrages; private ChildLocator childLocator; private List preppedBombInstances = new List(); private int currentBombIndex; private float perProjectileStopwatch; public override void OnEnter() { base.OnEnter(); prepDuration = basePrepDuration / attackSpeedStat; timeBetweenPreps = baseTimeBetweenPreps / attackSpeedStat; barrageDuration = baseBarrageDuration / attackSpeedStat; timeBetweenBarrages = baseTimeBetweenBarrages / attackSpeedStat; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { childLocator = modelTransform.GetComponent(); } } private string FindTargetChildStringFromBombIndex() { return string.Format(CultureInfo.InvariantCulture, "ProjectilePosition{0}", currentBombIndex); } private Transform FindTargetChildTransformFromBombIndex() { string childName = FindTargetChildStringFromBombIndex(); return childLocator.FindChild(childName); } public override void FixedUpdate() { base.FixedUpdate(); perProjectileStopwatch += GetDeltaTime(); if (base.fixedAge < prepDuration) { if (perProjectileStopwatch > timeBetweenPreps && currentBombIndex < 3) { currentBombIndex++; perProjectileStopwatch = 0f; Transform transform = FindTargetChildTransformFromBombIndex(); if ((bool)transform) { GameObject item = UnityEngine.Object.Instantiate(preppedBombPrefab, transform); preppedBombInstances.Add(item); } } } else if (base.fixedAge < prepDuration + barrageDuration) { if (!(perProjectileStopwatch > timeBetweenBarrages) || currentBombIndex <= 0) { return; } perProjectileStopwatch = 0f; Ray aimRay = GetAimRay(); Transform transform2 = FindTargetChildTransformFromBombIndex(); if ((bool)transform2) { if (base.isAuthority) { float damage = damageStat * damageCoefficient; BaseAI component = outer.commonComponents.characterBody.master.GetComponent(); if ((object)component != null && component.shouldMissFirstOffScreenShot && component.currentEnemy.characterBody.teamComponent.teamIndex == TeamIndex.Player) { aimRay.direction = OffScreenMissHelper.ApplyRandomTrajectoryOffset(aimRay.direction); damage = 0f; if (currentBombIndex <= 1) { component.shouldMissFirstOffScreenShot = false; } } ProjectileManager.instance.FireProjectile(bombProjectilePrefab, transform2.position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damage, force, Util.CheckRoll(critStat, base.characterBody.master)); Rigidbody component2 = GetComponent(); if ((bool)component2) { component2.AddForceAtPosition((0f - selfForce) * transform2.forward, transform2.position); } } EffectManager.SimpleMuzzleFlash(muzzleflashPrefab, base.gameObject, FindTargetChildStringFromBombIndex(), transmit: false); } currentBombIndex--; EntityState.Destroy(preppedBombInstances[currentBombIndex]); } else if (base.isAuthority) { outer.SetNextStateToMain(); } } public override void OnExit() { base.OnExit(); foreach (GameObject preppedBombInstance in preppedBombInstances) { EntityState.Destroy(preppedBombInstance); } } } } namespace EntityStates.BeetleMonster { public class HeadbuttState : BaseState { public static float baseDuration = 3.5f; public static float damageCoefficient; public static float forceMagnitude = 16f; public static GameObject hitEffectPrefab; public static string attackSoundString; private OverlapAttack attack; private Animator modelAnimator; private RootMotionAccumulator rootMotionAccumulator; private float duration; public override void OnEnter() { base.OnEnter(); rootMotionAccumulator = GetModelRootMotionAccumulator(); modelAnimator = GetModelAnimator(); duration = baseDuration / attackSpeedStat; attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Headbutt"); } Util.PlaySound(attackSoundString, base.gameObject); PlayCrossfade("Body", "Headbutt", "Headbutt.playbackRate", duration, 0.1f); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)rootMotionAccumulator) { UnityEngine.Vector3 vector = rootMotionAccumulator.ExtractRootMotion(); if (vector != UnityEngine.Vector3.zero && base.isAuthority && (bool)base.characterMotor) { base.characterMotor.rootMotion += vector; } } if (base.isAuthority) { attack.forceVector = (base.characterDirection ? (base.characterDirection.forward * forceMagnitude) : UnityEngine.Vector3.zero); if ((bool)base.characterDirection && (bool)base.inputBank) { base.characterDirection.moveVector = base.inputBank.aimDirection; } if ((bool)modelAnimator && modelAnimator.GetFloat("Headbutt.hitBoxActive") > 0.5f) { attack.Fire(); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class MainState : EntityState { private Animator modelAnimator; private static int walkToRunBlendParamHash = Animator.StringToHash("walkToRunBlend"); public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { modelAnimator.CrossFadeInFixedTime("Walk", 0.1f); } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)modelAnimator) { modelAnimator.SetFloat(walkToRunBlendParamHash, 1f); } } } public class MeleeState : EntityState { public static float duration = 3.5f; public static float damage = 10f; public static float forceMagnitude = 10f; private OverlapAttack attack; private Animator modelAnimator; public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = 10f; Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "Melee1"); } PlayCrossfade("Body", "Melee1", "Melee1.playbackRate", duration, 0.1f); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { attack.forceVector = (base.characterDirection ? (base.characterDirection.forward * forceMagnitude) : UnityEngine.Vector3.zero); if ((bool)modelAnimator && modelAnimator.GetFloat("Melee1.hitBoxActive") > 0.5f) { attack.Fire(); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : GenericCharacterSpawnState { } } namespace EntityStates.BeetleQueenMonster { public class BeetleWardDeath : BaseState { public static GameObject initialExplosion; public static string deathString; public override void OnEnter() { base.OnEnter(); Util.PlaySound(deathString, base.gameObject); if ((bool)base.modelLocator) { if ((bool)base.modelLocator.modelBaseTransform) { EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject); } if ((bool)base.modelLocator.modelTransform) { EntityState.Destroy(base.modelLocator.modelTransform.gameObject); } } if ((bool)initialExplosion && NetworkServer.active) { EffectManager.SimpleImpactEffect(initialExplosion, base.transform.position, UnityEngine.Vector3.up, transmit: true); } EntityState.Destroy(base.gameObject); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class BeginBurrow : BaseState { public static GameObject burrowPrefab; public static float duration; private bool isBurrowing; private Animator animator; private Transform modelTransform; private ChildLocator childLocator; public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); PlayCrossfade("Body", "BeginBurrow", "BeginBurrow.playbackRate", duration, 0.5f); modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); bool flag = animator.GetFloat("BeginBurrow.active") > 0.9f; if (flag && !isBurrowing) { string childName = "BurrowCenter"; Transform transform = childLocator.FindChild(childName); if ((bool)transform) { UnityEngine.Object.Instantiate(burrowPrefab, transform.position, UnityEngine.Quaternion.identity); } } isBurrowing = flag; if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ChargeSpit : BaseState { public static float baseDuration = 3f; public static GameObject effectPrefab; public static string attackSoundString; private float duration; private GameObject chargeEffect; private EffectManagerHelper _emh_chargeEffect; public override void Reset() { base.Reset(); duration = 0f; chargeEffect = null; _emh_chargeEffect = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); PlayCrossfade("Gesture", "ChargeSpit", "ChargeSpit.playbackRate", duration, 0.2f); Util.PlaySound(attackSoundString, base.gameObject); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component || !effectPrefab) { return; } Transform transform = component.FindChild("Mouth"); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(effectPrefab)) { chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation); chargeEffect = _emh_chargeEffect.gameObject; } chargeEffect.transform.parent = transform; ScaleParticleSystemDuration component2 = chargeEffect.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } } public override void OnExit() { base.OnExit(); if (chargeEffect != null) { if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null) { _emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect); } else { EntityState.Destroy(chargeEffect); } chargeEffect = null; _emh_chargeEffect = null; } } public override void Update() { base.Update(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } if (base.fixedAge >= duration && base.isAuthority) { FireSpit nextState = new FireSpit(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class FireSpit : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static float baseDuration = 2f; public static float damageCoefficient = 1.2f; public static float force = 20f; public static int projectileCount = 3; public static float yawSpread = 5f; public static float minSpread = 0f; public static float maxSpread = 5f; public static float arcAngle = 5f; public static float projectileHSpeed = 50f; private Ray aimRay; private float duration; public override void OnEnter() { base.OnEnter(); string muzzleName = "Mouth"; duration = baseDuration / attackSpeedStat; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } PlayCrossfade("Gesture", "FireSpit", "FireSpit.playbackRate", duration, 0.1f); aimRay = GetAimRay(); float magnitude = projectileHSpeed; Ray ray = aimRay; ray.origin = aimRay.GetPoint(6f); if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) { float num = magnitude; UnityEngine.Vector3 vector = hitInfo.point - aimRay.origin; UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z); float magnitude2 = vector2.magnitude; float y = Trajectory.CalculateInitialYSpeed(magnitude2 / num, vector.y); UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(vector2.x / magnitude2 * num, y, vector2.y / magnitude2 * num); magnitude = vector3.magnitude; aimRay.direction = vector3 / magnitude; } EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); if (base.isAuthority) { for (int i = 0; i < projectileCount; i++) { FireBlob(aimRay, 0f, ((float)projectileCount / 2f - (float)i) * yawSpread, magnitude); } } } private void FireBlob(Ray aimRay, float bonusPitch, float bonusYaw, float speed) { UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, bonusYaw, bonusPitch); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speed); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class SpawnState : BaseState { public static float duration = 4f; public static GameObject burrowPrefab; public static string spawnSoundString; private static int SpawnStateHash = Animator.StringToHash("Spawn"); private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(spawnSoundString, base.gameObject); GetModelTransform().GetComponent(); PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration); string muzzleName = "BurrowCenter"; EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, muzzleName, transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class SpawnWards : BaseState { public static string muzzleString; public static string attackSoundString; public static GameObject muzzleflashEffectPrefab; public static float baseDuration = 0.9f; public static float orbRange; public static float orbTravelSpeed; public static int orbCountMax; private float stopwatch; private int orbCount; private float duration; private bool hasFiredOrbs; private Animator animator; private ChildLocator childLocator; public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); childLocator = animator.GetComponent(); duration = baseDuration / attackSpeedStat; Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat); PlayCrossfade("Gesture", "SpawnWards", "SpawnWards.playbackRate", duration, 0.5f); } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (!hasFiredOrbs && animator.GetFloat("SpawnWards.active") > 0.5f) { hasFiredOrbs = true; FireOrbs(); } if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireOrbs() { if (NetworkServer.active) { Transform transform = childLocator.FindChild(muzzleString).transform; BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.searchOrigin = transform.position; bullseyeSearch.searchDirection = transform.forward; bullseyeSearch.maxDistanceFilter = orbRange; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; bullseyeSearch.teamMaskFilter.RemoveTeam(TeamComponent.GetObjectTeam(base.gameObject)); bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.RefreshCandidates(); EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true); List list = bullseyeSearch.GetResults().ToList(); for (int i = 0; i < list.Count; i++) { HurtBox target = list[i]; BeetleWardOrb beetleWardOrb = new BeetleWardOrb(); beetleWardOrb.origin = transform.position; beetleWardOrb.target = target; beetleWardOrb.speed = orbTravelSpeed; OrbManager.instance.AddOrb(beetleWardOrb); } } } public override void OnExit() { base.OnExit(); if ((bool)base.cameraTargetParams) { base.cameraTargetParams.fovOverride = -1f; } int layerIndex = animator.GetLayerIndex("Impact"); if (layerIndex >= 0) { animator.SetLayerWeight(layerIndex, 1.5f); animator.PlayInFixedTime("LightImpact", layerIndex, 0f); } } } public class SummonEggs : BaseState { public static float baseDuration = 3.5f; public static string attackSoundString; public static float randomRadius = 8f; public static GameObject spitPrefab; public static int maxSummonCount = 5; public static float summonInterval = 1f; private static float summonDuration = 3.26f; public static SpawnCard spawnCard; private Animator animator; private Transform modelTransform; private ChildLocator childLocator; private float duration; private float summonTimer; private int summonCount; private bool isSummoning; private BullseyeSearch enemySearch; public override void Reset() { base.Reset(); animator = null; modelTransform = null; childLocator = null; duration = 0f; summonInterval = 0f; summonTimer = 0f; summonCount = 0; isSummoning = false; } public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); modelTransform = GetModelTransform(); childLocator = modelTransform.GetComponent(); duration = baseDuration; PlayCrossfade("Gesture", "SummonEggs", 0.5f); Util.PlaySound(attackSoundString, base.gameObject); if (NetworkServer.active) { enemySearch = new BullseyeSearch(); enemySearch.filterByDistinctEntity = false; enemySearch.filterByLoS = false; enemySearch.maxDistanceFilter = float.PositiveInfinity; enemySearch.minDistanceFilter = 0f; enemySearch.minAngleFilter = 0f; enemySearch.maxAngleFilter = 180f; enemySearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam()); enemySearch.sortMode = BullseyeSearch.SortMode.Distance; enemySearch.viewer = base.characterBody; } } private void SummonEgg() { UnityEngine.Vector3 searchOrigin = GetAimRay().origin; if ((bool)base.inputBank && base.inputBank.GetAimRaycast(float.PositiveInfinity, out var hitInfo)) { searchOrigin = hitInfo.point; } if (enemySearch == null) { return; } enemySearch.searchOrigin = searchOrigin; enemySearch.RefreshCandidates(); HurtBox hurtBox = enemySearch.GetResults().FirstOrDefault(); Transform transform = (((bool)hurtBox && (bool)hurtBox.healthComponent) ? hurtBox.healthComponent.body.coreTransform : base.characterBody.coreTransform); if (!transform) { return; } DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = 3f, maxDistance = 20f, spawnOnTarget = transform }, RoR2Application.rng); directorSpawnRequest.summonerBodyObject = base.gameObject; directorSpawnRequest.onSpawnedServer = (Action)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action)delegate(SpawnCard.SpawnResult spawnResult) { if (spawnResult.success && (bool)spawnResult.spawnedInstance && (bool)base.characterBody) { RoR2.Inventory component = spawnResult.spawnedInstance.GetComponent(); if ((bool)component) { component.CopyEquipmentFrom(base.characterBody.inventory); if (base.characterBody.inventory.GetItemCount(RoR2Content.Items.Ghost) > 0) { component.GiveItem(RoR2Content.Items.Ghost); component.GiveItem(RoR2Content.Items.HealthDecay, 30); component.GiveItem(RoR2Content.Items.BoostDamage, 150); } } } }); DirectorCore.instance?.TrySpawnObject(directorSpawnRequest); } public override void FixedUpdate() { base.FixedUpdate(); bool flag = animator.GetFloat("SummonEggs.active") > 0.9f; if (flag && !isSummoning) { string childName = "Mouth"; Transform transform = childLocator.FindChild(childName); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(spitPrefab)) { UnityEngine.Object.Instantiate(spitPrefab, transform); } else { EffectManager.GetAndActivatePooledEffect(spitPrefab, transform, inResetLocal: true); } } } if (isSummoning) { summonTimer += GetDeltaTime(); if (NetworkServer.active && summonTimer > 0f && summonCount < maxSummonCount) { summonCount++; summonTimer -= summonInterval; SummonEgg(); } } isSummoning = flag; if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class WeakState : BaseState { private float stopwatch; private float grubStopwatch; public static float weakDuration; public static float weakToIdleTransitionDuration; public static string weakPointChildString; public static int maxGrubCount; public static float grubSpawnFrequency; public static float grubSpawnDelay; private int grubCount; private bool beginExitTransition; private ChildLocator childLocator; private static int WeakEnterStateHash = Animator.StringToHash("WeakEnter"); public override void OnEnter() { base.OnEnter(); grubStopwatch -= grubSpawnDelay; if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "") { Util.PlaySound(base.sfxLocator.barkSound, base.gameObject); } PlayAnimation("Body", WeakEnterStateHash); Transform modelTransform = GetModelTransform(); if (!modelTransform) { return; } childLocator = modelTransform.GetComponent(); if ((bool)childLocator) { Transform transform = childLocator.FindChild(weakPointChildString); if ((bool)transform) { UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/Effects/WeakPointProcEffect"), transform.position, transform.rotation); } } } public override void FixedUpdate() { base.FixedUpdate(); float deltaTime = GetDeltaTime(); stopwatch += deltaTime; grubStopwatch += deltaTime; if (grubStopwatch >= 1f / grubSpawnFrequency && grubCount < maxGrubCount) { grubCount++; grubStopwatch -= 1f / grubSpawnFrequency; if (NetworkServer.active) { Transform transform = childLocator.FindChild("GrubSpawnPoint" + UnityEngine.Random.Range(1, 10)); if ((bool)transform) { NetworkServer.Spawn(UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/GrubPack"), transform.transform.position, UnityEngine.Random.rotation)); transform.gameObject.SetActive(value: false); } } } if (stopwatch >= weakDuration - weakToIdleTransitionDuration && !beginExitTransition) { beginExitTransition = true; PlayCrossfade("Body", "WeakExit", "WeakExit.playbackRate", weakToIdleTransitionDuration, 0.5f); } if (stopwatch >= weakDuration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Pain; } } } namespace EntityStates.BeetleGuardMonster { public class DefenseUp : BaseState { public static float baseDuration = 3.5f; public static float buffDuration = 8f; public static GameObject defenseUpPrefab; private Animator modelAnimator; private float duration; private bool hasCastBuff; private EffectManagerHelper _emh_defenseUp; public override void Reset() { base.Reset(); modelAnimator = null; duration = 0f; hasCastBuff = false; _emh_defenseUp = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayCrossfade("Body", "DefenseUp", "DefenseUp.playbackRate", duration, 0.2f); } } public override void OnExit() { if (_emh_defenseUp != null && _emh_defenseUp.OwningPool != null) { _emh_defenseUp.OwningPool.ReturnObject(_emh_defenseUp); _emh_defenseUp = null; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)modelAnimator && modelAnimator.GetFloat("DefenseUp.activate") > 0.5f && !hasCastBuff) { GameObject gameObject = null; if (!EffectManager.ShouldUsePooledEffect(defenseUpPrefab)) { gameObject = UnityEngine.Object.Instantiate(defenseUpPrefab, base.transform.position, UnityEngine.Quaternion.identity, base.transform); } else { _emh_defenseUp = EffectManager.GetAndActivatePooledEffect(defenseUpPrefab, base.transform.position, UnityEngine.Quaternion.identity, base.transform); gameObject = _emh_defenseUp.gameObject; } ScaleParticleSystemDuration component = gameObject.GetComponent(); if ((bool)component) { component.newDuration = buffDuration; } hasCastBuff = true; if (NetworkServer.active) { base.characterBody.AddTimedBuff(JunkContent.Buffs.EnrageAncientWisp, buffDuration); } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireSunder : BaseState { public static float baseDuration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static string initialAttackSoundString; public static GameObject chargeEffectPrefab; public static GameObject projectilePrefab; public static GameObject hitEffectPrefab; private Animator modelAnimator; private Transform modelTransform; private bool hasAttacked; private float duration; private GameObject rightHandChargeEffect; private ChildLocator modelChildLocator; private Transform handRTransform; private EffectManagerHelper _emh_rightHandChargeEffect; public override void Reset() { base.Reset(); modelAnimator = null; modelTransform = null; hasAttacked = false; duration = 0f; rightHandChargeEffect = null; modelChildLocator = null; handRTransform = null; _emh_rightHandChargeEffect = null; } public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); Util.PlaySound(initialAttackSoundString, base.gameObject); duration = baseDuration / attackSpeedStat; PlayCrossfade("Body", "FireSunder", "FireSunder.playbackRate", duration, 0.2f); if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration + 2f); } if (!modelTransform) { return; } AimAnimator component = modelTransform.GetComponent(); if ((bool)component) { component.enabled = true; } modelChildLocator = modelTransform.GetComponent(); if (!modelChildLocator) { return; } GameObject gameObject = chargeEffectPrefab; handRTransform = modelChildLocator.FindChild("HandR"); if ((bool)handRTransform) { if (!EffectManager.ShouldUsePooledEffect(gameObject)) { rightHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, handRTransform); return; } _emh_rightHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, handRTransform, inResetLocal: true); rightHandChargeEffect = _emh_rightHandChargeEffect.gameObject; } } public override void OnExit() { DestroyRightHandCharge(); if ((bool)modelTransform) { AimAnimator component = modelTransform.GetComponent(); if ((bool)component) { component.enabled = true; } } base.OnExit(); } public void DestroyRightHandCharge() { if (_emh_rightHandChargeEffect != null && _emh_rightHandChargeEffect.OwningPool != null) { _emh_rightHandChargeEffect.OwningPool.ReturnObject(_emh_rightHandChargeEffect); } else { EntityState.Destroy(rightHandChargeEffect); } rightHandChargeEffect = null; _emh_rightHandChargeEffect = null; } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)modelAnimator && modelAnimator.GetFloat("FireSunder.activate") > 0.5f && !hasAttacked) { if (base.isAuthority && (bool)modelTransform) { Ray aimRay = GetAimRay(); aimRay.origin = handRTransform.position; ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, forceMagnitude, Util.CheckRoll(critStat, base.characterBody.master)); } hasAttacked = true; DestroyRightHandCharge(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class GroundSlam : BaseState { public static float baseDuration = 3.5f; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; private OverlapAttack attack; public static string initialAttackSoundString; public static GameObject chargeEffectPrefab; public static GameObject slamEffectPrefab; public static GameObject hitEffectPrefab; private Animator modelAnimator; private Transform modelTransform; private bool hasAttacked; private float duration; private GameObject leftHandChargeEffect; private GameObject rightHandChargeEffect; private ChildLocator modelChildLocator; private EffectManagerHelper _emh_leftHandChargeEffect; private EffectManagerHelper _emh_rightHandChargeEffect; private Transform groundSlamIndicatorInstance; public override void Reset() { base.Reset(); if (attack != null) { attack.Reset(); } modelAnimator = null; modelTransform = null; hasAttacked = false; duration = 0f; leftHandChargeEffect = null; rightHandChargeEffect = null; modelChildLocator = null; _emh_leftHandChargeEffect = null; _emh_rightHandChargeEffect = null; groundSlamIndicatorInstance = null; } private void EnableIndicator(Transform indicator) { if ((bool)indicator) { indicator.gameObject.SetActive(value: true); ObjectScaleCurve component = indicator.gameObject.GetComponent(); if ((bool)component) { component.time = 0f; } } } private void DisableIndicator(Transform indicator) { if ((bool)indicator) { indicator.gameObject.SetActive(value: false); } } public override void OnEnter() { base.OnEnter(); modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); Util.PlaySound(initialAttackSoundString, base.gameObject); _ = (bool)base.characterDirection; attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.forceVector = UnityEngine.Vector3.up * forceMagnitude; if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == "GroundSlam"); } duration = baseDuration / attackSpeedStat; PlayCrossfade("Body", "GroundSlam", "GroundSlam.playbackRate", duration, 0.2f); if (!modelTransform) { return; } modelChildLocator = modelTransform.GetComponent(); if (!modelChildLocator) { return; } GameObject gameObject = chargeEffectPrefab; Transform transform = modelChildLocator.FindChild("HandL"); Transform transform2 = modelChildLocator.FindChild("HandR"); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(gameObject)) { leftHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, transform); } else { _emh_leftHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, transform, inResetLocal: true); leftHandChargeEffect = _emh_leftHandChargeEffect.gameObject; } } if ((bool)transform2) { if (!EffectManager.ShouldUsePooledEffect(gameObject)) { rightHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, transform2); } else { _emh_rightHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, transform2, inResetLocal: true); rightHandChargeEffect = _emh_rightHandChargeEffect.gameObject; } } groundSlamIndicatorInstance = modelChildLocator.FindChild("GroundSlamIndicator"); EnableIndicator(groundSlamIndicatorInstance); } protected void DestroyChargeEffects() { if (_emh_leftHandChargeEffect != null && _emh_leftHandChargeEffect.OwningPool != null) { _emh_leftHandChargeEffect.OwningPool.ReturnObject(_emh_leftHandChargeEffect); } else { EntityState.Destroy(leftHandChargeEffect); } leftHandChargeEffect = null; _emh_leftHandChargeEffect = null; if (_emh_rightHandChargeEffect != null && _emh_rightHandChargeEffect.OwningPool != null) { _emh_rightHandChargeEffect.OwningPool.ReturnObject(_emh_rightHandChargeEffect); } else { EntityState.Destroy(rightHandChargeEffect); } rightHandChargeEffect = null; _emh_rightHandChargeEffect = null; } public override void OnExit() { DestroyChargeEffects(); DisableIndicator(groundSlamIndicatorInstance); _ = (bool)base.characterDirection; base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)modelAnimator && modelAnimator.GetFloat("GroundSlam.hitBoxActive") > 0.5f && !hasAttacked) { if (NetworkServer.active) { attack.Fire(); } if (base.isAuthority && (bool)modelTransform) { DisableIndicator(groundSlamIndicatorInstance); EffectManager.SimpleMuzzleFlash(slamEffectPrefab, base.gameObject, "SlamZone", transmit: true); } hasAttacked = true; DestroyChargeEffects(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : BaseState { public static float duration = 4f; public static string spawnSoundString; private static int Spawn1StateHash = Animator.StringToHash("Spawn1"); private static int Spawn1ParamHash = Animator.StringToHash("Spawn1.playbackRate"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(spawnSoundString, base.gameObject); PlayAnimation("Body", Spawn1StateHash, Spawn1ParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.Barrel { public class ActivateFan : EntityState { private static int IdleToActiveStateHash = Animator.StringToHash("IdleToActive"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Base", IdleToActiveStateHash); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { component.FindChild("JumpVolume").gameObject.SetActive(value: true); component.FindChild("LightBack").gameObject.SetActive(value: true); component.FindChild("LightFront").gameObject.SetActive(value: true); } } if ((bool)base.sfxLocator) { Util.PlaySound(base.sfxLocator.openSound, base.gameObject); } } } public class Closed : EntityState { public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", "Closed"); } } public class Closing : EntityState { public static float duration = 1f; public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", "Closing", "Closing.playbackRate", duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new Closed()); } } } public class Opened : EntityState { private static int OpenedStateHash = Animator.StringToHash("Opened"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", OpenedStateHash); SetPingable(value: false); } } public class Opening : EntityState { public static float duration = 1f; private static int OpeningStateHash = Animator.StringToHash("Opening"); private static int OpeningParamHash = Animator.StringToHash("Opening.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", OpeningStateHash, OpeningParamHash, duration); if ((bool)base.sfxLocator) { Util.PlaySound(base.sfxLocator.openSound, base.gameObject); } } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new Opened()); } } } public class OpeningLunar : BaseState { public static float duration = 1f; private static int OpeningStateHash = Animator.StringToHash("Opening"); private static int OpeningParamHash = Animator.StringToHash("Opening.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", OpeningStateHash, OpeningParamHash, duration); if ((bool)base.sfxLocator) { Util.PlaySound(base.sfxLocator.openSound, base.gameObject); } StopSteamEffect(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration) { outer.SetNextState(new Opened()); } } private void StopSteamEffect() { Transform modelTransform = GetModelTransform(); if (!modelTransform) { return; } ChildLocator component = modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild("SteamEffect"); if ((bool)transform) { ParticleSystem component2 = transform.GetComponent(); if ((bool)component2) { ParticleSystem.MainModule main = component2.main; main.loop = false; } } } } } namespace EntityStates.Bandit2 { public class ThrowSmokebomb : BaseState { public static float duration; private static int throwSmokeBombStateHash = Animator.StringToHash("ThrowSmokebomb"); private static int throwSmokeBombParamHash = Animator.StringToHash("ThrowSmokebomb.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Gesture, Additive", throwSmokeBombStateHash, throwSmokeBombParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new StealthMode()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class StealthMode : BaseState { public static float duration; public static string enterStealthSound; public static string exitStealthSound; public static float blastAttackRadius; public static float blastAttackDamageCoefficient; public static float blastAttackProcCoefficient; public static float blastAttackForce; public static GameObject smokeBombEffectPrefab; public static string smokeBombMuzzleString; public static float shortHopVelocity; private Animator animator; public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); _ = (bool)animator; if ((bool)base.characterBody) { if (NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.Cloak); base.characterBody.AddBuff(RoR2Content.Buffs.CloakSpeed); } base.characterBody.onSkillActivatedAuthority += OnSkillActivatedAuthority; } FireSmokebomb(); Util.PlaySound(enterStealthSound, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } public override void OnExit() { if (!outer.destroying) { FireSmokebomb(); } Util.PlaySound(exitStealthSound, base.gameObject); if ((bool)base.characterBody) { base.characterBody.onSkillActivatedAuthority -= OnSkillActivatedAuthority; if (NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.CloakSpeed); base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak); } } if ((bool)animator) { animator.SetLayerWeight(animator.GetLayerIndex("Body, StealthWeapon"), 0f); } base.OnExit(); } private void OnSkillActivatedAuthority(GenericSkill skill) { if (skill.skillDef.isCombatSkill) { outer.SetNextStateToMain(); } } private void FireSmokebomb() { if (base.isAuthority) { BlastAttack obj = new BlastAttack { radius = blastAttackRadius, procCoefficient = blastAttackProcCoefficient, position = base.transform.position, attacker = base.gameObject, crit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master), baseDamage = base.characterBody.damage * blastAttackDamageCoefficient, falloffModel = BlastAttack.FalloffModel.None, damageType = DamageType.Stun1s, baseForce = blastAttackForce }; obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker); obj.attackerFiltering = AttackerFiltering.NeverHitSelf; obj.Fire(); } if ((bool)smokeBombEffectPrefab) { EffectManager.SimpleMuzzleFlash(smokeBombEffectPrefab, base.gameObject, smokeBombMuzzleString, transmit: false); } if ((bool)base.characterMotor) { base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, shortHopVelocity, base.characterMotor.velocity.z); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.Bandit2.Weapon { public abstract class Bandit2FirePrimaryBase : GenericBulletBaseState { [SerializeField] public float minimumBaseDuration; protected float minimumDuration; private static int FireMainWeaponStateHash = Animator.StringToHash("FireMainWeapon"); private static int FireMainWeaponParamHash = Animator.StringToHash("FireMainWeapon.playbackRate"); public override void OnEnter() { minimumDuration = minimumBaseDuration / attackSpeedStat; base.OnEnter(); PlayAnimation("Gesture, Additive", FireMainWeaponStateHash, FireMainWeaponParamHash, duration); } protected override void ModifyBullet(BulletAttack bulletAttack) { base.ModifyBullet(bulletAttack); bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet; } public override InterruptPriority GetMinimumInterruptPriority() { if (!(base.fixedAge > minimumDuration)) { return InterruptPriority.Skill; } return InterruptPriority.Any; } } public class Bandit2FireRifle : Bandit2FirePrimaryBase { protected override void ModifyBullet(BulletAttack bulletAttack) { base.ModifyBullet(bulletAttack); bulletAttack.falloffModel = BulletAttack.FalloffModel.None; } } public class Bandit2FireShiv : BaseSkillState { [SerializeField] public GameObject projectilePrefab; [SerializeField] public float baseDuration; [SerializeField] public float damageCoefficient; [SerializeField] public float force; [SerializeField] public int maxShivCount; public static float baseDelayBetweenShivs; public static float shortHopVelocity; public static GameObject muzzleEffectPrefab; public static string muzzleString; private float duration; private float delayBetweenShivs; private float countdownSinceLastShiv; private int shivCount; private static int SlashBladeStateHash = Animator.StringToHash("SlashBlade"); private static int SlashBladeParamHash = Animator.StringToHash("SlashBlade.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; delayBetweenShivs = baseDelayBetweenShivs / attackSpeedStat; PlayAnimation("Gesture, Additive", SlashBladeStateHash, SlashBladeParamHash, duration); StartAimMode(); if ((bool)base.characterMotor) { base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, Mathf.Max(base.characterMotor.velocity.y, shortHopVelocity), base.characterMotor.velocity.z); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); countdownSinceLastShiv -= GetDeltaTime(); if (shivCount < maxShivCount && countdownSinceLastShiv <= 0f) { shivCount++; countdownSinceLastShiv += delayBetweenShivs; FireShiv(); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } private void FireShiv() { if ((bool)muzzleEffectPrefab) { EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleString, transmit: false); } if (base.isAuthority) { Ray ray = GetAimRay(); if (projectilePrefab != null) { TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.position = ray.origin; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = damageStat * damageCoefficient; fireProjectileInfo.force = force; fireProjectileInfo.crit = RollCrit(); fireProjectileInfo.damageTypeOverride = DamageType.SuperBleedOnCrit; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class FireShotgun2 : Bandit2FirePrimaryBase { [SerializeField] public float minFixedSpreadYaw; [SerializeField] public float maxFixedSpreadYaw; protected override void ModifyBullet(BulletAttack bulletAttack) { base.ModifyBullet(bulletAttack); bulletAttack.bulletCount = 1u; bulletAttack.allowTrajectoryAimAssist = false; } protected override void FireBullet(Ray aimRay) { StartAimMode(aimRay, 3f); DoFireEffects(); PlayFireAnimation(); AddRecoil(-1f * recoilAmplitudeY, -1.5f * recoilAmplitudeY, -1f * recoilAmplitudeX, 1f * recoilAmplitudeX); if (base.isAuthority) { UnityEngine.Vector3 rhs = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, aimRay.direction); UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(aimRay.direction, rhs); float num = 0f; if ((bool)base.characterBody) { num = base.characterBody.spreadBloomAngle; } float angle = 0f; float num2 = 0f; if (bulletCount > 1) { num2 = UnityEngine.Random.Range(minFixedSpreadYaw + num, maxFixedSpreadYaw + num) * 2f; angle = num2 / (float)(bulletCount - 1); } TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, maxDistance, base.gameObject); UnityEngine.Vector3 direction = UnityEngine.Quaternion.AngleAxis((0f - num2) * 0.5f, axis) * aimRay.direction; UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, axis); Ray aimRay2 = new Ray(aimRay.origin, direction); for (int i = 0; i < bulletCount; i++) { BulletAttack bulletAttack = GenerateBulletAttack(aimRay2); ModifyBullet(bulletAttack); bulletAttack.Fire(); aimRay2.direction = quaternion * aimRay2.direction; } } } } public class EnterReload : BaseState { public static string enterSoundString; public static float baseDuration; private float duration => baseDuration / attackSpeedStat; public override void OnEnter() { base.OnEnter(); PlayCrossfade("Gesture, Additive", "EnterReload", "Reload.playbackRate", duration, 0.1f); Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.fixedAge > duration) { outer.SetNextState(new Reload()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Reload : BaseState { public static float enterSoundPitch; public static float exitSoundPitch; public static string enterSoundString; public static string exitSoundString; public static GameObject reloadEffectPrefab; public static string reloadEffectMuzzleString; public static float baseDuration; private bool hasGivenStock; private static int ReloadSimpleStateHash = Animator.StringToHash("ReloadSimple"); private static int ReloadStateHash = Animator.StringToHash("Reload"); private static int ReloadParamHash = Animator.StringToHash("Reload.playbackRate"); private float duration => baseDuration / attackSpeedStat; public override void OnEnter() { base.OnEnter(); PlayAnimation("Gesture, Additive", (base.characterBody.isSprinting && (bool)base.characterMotor && base.characterMotor.isGrounded) ? ReloadSimpleStateHash : ReloadStateHash, ReloadParamHash, duration); Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, enterSoundPitch); EffectManager.SimpleMuzzleFlash(reloadEffectPrefab, base.gameObject, reloadEffectMuzzleString, transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration / 2f) { GiveStock(); } if (base.isAuthority && base.fixedAge >= duration) { if (base.skillLocator.primary.stock < base.skillLocator.primary.maxStock) { outer.SetNextState(new Reload()); return; } Util.PlayAttackSpeedSound(exitSoundString, base.gameObject, exitSoundPitch); outer.SetNextStateToMain(); } } public override void OnExit() { base.OnExit(); } private void GiveStock() { if (!hasGivenStock) { base.skillLocator.primary.AddOneStock(); hasGivenStock = true; } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class BaseSidearmState : BaseState { [SerializeField] public float baseDuration; [SerializeField] public GameObject crosshairOverridePrefab; protected float duration; private Animator animator; private int bodySideWeaponLayerIndex; private CrosshairUtils.OverrideRequest crosshairOverrideRequest; public virtual string exitAnimationStateName => "BufferEmpty"; public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); duration = baseDuration / attackSpeedStat; if ((bool)animator) { bodySideWeaponLayerIndex = animator.GetLayerIndex("Body, SideWeapon"); animator.SetLayerWeight(bodySideWeaponLayerIndex, 1f); } if ((bool)crosshairOverridePrefab) { crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill); } base.characterBody.SetAimTimer(3f); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority && base.characterBody.isSprinting) { outer.SetNextStateToMain(); } } public override void OnExit() { if ((bool)animator) { animator.SetLayerWeight(bodySideWeaponLayerIndex, 0f); } PlayAnimation("Gesture, Additive", exitAnimationStateName); crosshairOverrideRequest?.Dispose(); Transform transform = FindModelChild("SpinningPistolFX"); if ((bool)transform) { transform.gameObject.SetActive(value: false); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public abstract class BasePrepSidearmRevolverState : BaseSidearmState { [SerializeField] public string enterSoundString; private Animator animator; private static int MainToSideStateHash = Animator.StringToHash("MainToSide"); private static int MainToSideParamHash = Animator.StringToHash("MainToSide.playbackRate"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Gesture, Additive", MainToSideStateHash, MainToSideParamHash, duration); Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(GetNextState()); } } public override void OnExit() { base.OnExit(); } protected abstract EntityState GetNextState(); } public class ExitSidearmRevolver : BaseSidearmState { public override string exitAnimationStateName => "SideToMain"; public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } } public abstract class BaseFireSidearmRevolverState : BaseSidearmState { [SerializeField] public GameObject effectPrefab; [SerializeField] public GameObject hitEffectPrefab; [SerializeField] public GameObject tracerEffectPrefab; [SerializeField] public float damageCoefficient; [SerializeField] public float force; [SerializeField] public float minSpread; [SerializeField] public float maxSpread; [SerializeField] public string attackSoundString; [SerializeField] public float recoilAmplitude; [SerializeField] public float bulletRadius; [SerializeField] public float trajectoryAimAssistMultiplier = 0.75f; private static int FireSideWeaponStateHash = Animator.StringToHash("FireSideWeapon"); private static int FireSideWeaponParamHash = Animator.StringToHash("FireSideWeapon.playbackRate"); public override void OnEnter() { base.OnEnter(); AddRecoil(-3f * recoilAmplitude, -4f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude); Ray aimRay = GetAimRay(); StartAimMode(aimRay); string muzzleName = "MuzzlePistol"; Util.PlaySound(attackSoundString, base.gameObject); PlayAnimation("Gesture, Additive", FireSideWeaponStateHash, FireSideWeaponParamHash, duration); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false); } if (base.isAuthority) { BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = base.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = aimRay.origin; bulletAttack.aimVector = aimRay.direction; bulletAttack.minSpread = minSpread; bulletAttack.maxSpread = maxSpread; bulletAttack.bulletCount = 1u; bulletAttack.damage = damageCoefficient * damageStat; bulletAttack.force = force; bulletAttack.falloffModel = BulletAttack.FalloffModel.None; bulletAttack.tracerEffectPrefab = tracerEffectPrefab; bulletAttack.muzzleName = muzzleName; bulletAttack.hitEffectPrefab = hitEffectPrefab; bulletAttack.isCrit = RollCrit(); bulletAttack.HitEffectNormal = false; bulletAttack.radius = bulletRadius; bulletAttack.damageType |= (DamageTypeCombo)DamageType.BonusToLowHealth; bulletAttack.smartCollision = true; bulletAttack.trajectoryAimAssistMultiplier = trajectoryAimAssistMultiplier; ModifyBullet(bulletAttack); bulletAttack.Fire(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new ExitSidearmRevolver()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Any; } protected virtual void ModifyBullet(BulletAttack bulletAttack) { } } public class PrepSidearmResetRevolver : BasePrepSidearmRevolverState { protected override EntityState GetNextState() { return new FireSidearmResetRevolver(); } } public class FireSidearmResetRevolver : BaseFireSidearmRevolverState { protected override void ModifyBullet(BulletAttack bulletAttack) { base.ModifyBullet(bulletAttack); bulletAttack.damageType |= (DamageTypeCombo)DamageType.ResetCooldownsOnKill; } } public class PrepSidearmSkullRevolver : BasePrepSidearmRevolverState { protected override EntityState GetNextState() { return new FireSidearmSkullRevolver(); } } public class FireSidearmSkullRevolver : BaseFireSidearmRevolverState { protected override void ModifyBullet(BulletAttack bulletAttack) { base.ModifyBullet(bulletAttack); int num = 0; if ((bool)base.characterBody) { num = base.characterBody.GetBuffCount(RoR2Content.Buffs.BanditSkull); } bulletAttack.damage *= 1f + 0.1f * (float)num; bulletAttack.damageType |= (DamageTypeCombo)DamageType.GiveSkullOnKill; } } public class SlashBlade : BasicMeleeAttack { public static float shortHopVelocity; public static float selfForceStrength; public static float minimumBaseDuration; public static AnimationCurve bloomCurve; private GameObject bladeMeshObject; private static int SlashBladeStateHash = Animator.StringToHash("SlashBlade"); private static int SlashBladeParamHash = Animator.StringToHash("SlashBlade.playbackRate"); private float minimumDuration => minimumBaseDuration / attackSpeedStat; public override void OnEnter() { base.OnEnter(); PlayAnimation("Gesture, Additive", SlashBladeStateHash, SlashBladeParamHash, duration); bladeMeshObject = FindModelChild("BladeMesh").gameObject; if ((bool)bladeMeshObject) { bladeMeshObject.SetActive(value: true); } base.characterMotor.ApplyForce(base.inputBank.moveVector * selfForceStrength, alwaysApply: true); if ((bool)base.characterMotor) { base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, Mathf.Max(base.characterMotor.velocity.y, shortHopVelocity), base.characterMotor.velocity.z); } } protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack) { base.AuthorityModifyOverlapAttack(overlapAttack); overlapAttack.damageType = DamageType.SuperBleedOnCrit; } public override void Update() { base.Update(); base.characterBody.SetSpreadBloom(bloomCurve.Evaluate(base.age / duration), canOnlyIncreaseBloom: false); } public override void OnExit() { if ((bool)bladeMeshObject) { bladeMeshObject.SetActive(value: false); } base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { if ((bool)base.inputBank) { if (!(base.fixedAge > minimumDuration)) { return InterruptPriority.PrioritySkill; } return InterruptPriority.Skill; } return InterruptPriority.Skill; } } } namespace EntityStates.AurelioniteHeart { public class AurelioniteHeartEntityState : EntityState { protected AurelioniteHeartController heartController; protected Animator animator; protected Xoroshiro128Plus rng; protected UnityEngine.Vector3 inertPosition; protected float heartMovementTimer; public static event Action falseSonUnlockEvent; public override void OnEnter() { base.OnEnter(); heartController = base.gameObject.GetComponent(); animator = heartController.heartAnimator; rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); inertPosition = new UnityEngine.Vector3(base.gameObject.transform.position.x, base.gameObject.transform.position.y - 1f, base.gameObject.transform.position.z); } public void FalseSonUnlocked() { AurelioniteHeartEntityState.falseSonUnlockEvent?.Invoke(); } } public class AurelioniteHeartIdleState : AurelioniteHeartEntityState { public override void OnEnter() { base.OnEnter(); } } public class AurelioniteHeartActivationState : AurelioniteHeartEntityState { public static float expGrantingDuration = 3f; [SerializeField] public static float itemGrantingDuration = 10f; [SerializeField] public ItemTier rewardDisplayTier; [SerializeField] [Tooltip("The prefab to use for the reward pickup.")] public GameObject rewardPickupPrefab; [SerializeField] public UnityEngine.Vector3 rewardOffset; [SerializeField] public string falseSonSurvivorAchievement; [SerializeField] public ItemDef halcyonSeed; [SerializeField] public int rewardOptionCount = 1; [SerializeField] public PickupDropTable rewardDropTable; public bool rewardGiven; public override void OnEnter() { base.OnEnter(); rewardGiven = false; } public override void FixedUpdate() { base.FixedUpdate(); if (!heartController.activated || !(base.fixedAge >= expGrantingDuration)) { return; } int participatingPlayerCount = Run.instance.participatingPlayerCount; if (base.gameObject == null || rewardDropTable == null || participatingPlayerCount == 0) { return; } if (participatingPlayerCount > 0 && (bool)base.gameObject && (bool)rewardDropTable && !rewardGiven) { rewardGiven = true; int num = participatingPlayerCount; float angle = 360f / (float)num; UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); UnityEngine.Vector3 position = base.gameObject.transform.position + rewardOffset; int num2 = 0; while (num2 < num) { GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo); pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier); pickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(rewardOptionCount, rewardDropTable, rng); pickupInfo.rotation = UnityEngine.Quaternion.identity; pickupInfo.prefabOverride = rewardPickupPrefab; PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector); num2++; vector = quaternion * vector; } } if (base.fixedAge >= itemGrantingDuration) { if (FalseSonUnlockStateMet()) { outer.SetNextState(new AurelioniteHeartFalseSonSurvivorUnlockState()); } else { outer.SetNextState(new AurelioniteHeartInertState()); } } } private bool FalseSonUnlockStateMet() { bool result = false; int num = 0; foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (!instance.networkUser.localUser.userProfile.HasAchievement("UnlockFalseSon")) { num++; } } if (num > 0) { foreach (PlayerCharacterMasterController instance2 in PlayerCharacterMasterController.instances) { if (instance2.master.inventory.GetItemCount(RoR2Content.Items.TitanGoldDuringTP) > 0 && num > 0) { result = true; GameObject effectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/DelusionItemDissolveVFX"); EffectData effectData = new EffectData { origin = instance2.master.GetBody().transform.position, genericFloat = 1.5f, genericUInt = (uint)(halcyonSeed.itemIndex + 1) }; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true); instance2.master.inventory.RemoveItem(halcyonSeed); FalseSonUnlocked(); } } } return result; } } public class AurelioniteHeartFalseSonSurvivorUnlockState : AurelioniteHeartEntityState { [SerializeField] public float animationDuration = 4f; [SerializeField] public float initialDelay = 2f; [SerializeField] public string falseSonUnlockAnimationState; [SerializeField] public float upwardMovement = 0.2f; public override void OnEnter() { base.OnEnter(); } public override void FixedUpdate() { base.FixedUpdate(); if (!(base.fixedAge >= initialDelay)) { return; } heartMovementTimer -= GetDeltaTime(); base.gameObject.transform.position += new UnityEngine.Vector3(0f, upwardMovement, 0f); if (heartMovementTimer <= 0f) { heartMovementTimer += 0.02f; upwardMovement += upwardMovement / 10f; if (base.fixedAge >= animationDuration) { heartController.rebirthShrine.SetActive(value: true); EntityState.Destroy(base.gameObject); } } } } public class AurelioniteHeartInertState : AurelioniteHeartEntityState { [SerializeField] private float animationDuration = 1f; [SerializeField] private string heartInertAnimationState; public override void OnEnter() { base.OnEnter(); } public override void FixedUpdate() { base.FixedUpdate(); heartMovementTimer -= GetDeltaTime(); if (heartMovementTimer <= 0f) { heartMovementTimer += 0.02f; if (base.gameObject.transform.position != inertPosition) { base.gameObject.transform.position += new UnityEngine.Vector3(0f, -0.25f, 0f); return; } animator.StopPlayback(); heartController.rebirthShrine.SetActive(value: true); outer.SetNextState(new AurelioniteHeartIdleState()); } } } } namespace EntityStates.Assassin2 { public class ChargeDash : BaseState { public static float baseDuration = 1.5f; public static string enterSoundString; private Animator modelAnimator; private float duration; private int slashCount; private Transform modelTransform; private UnityEngine.Vector3 oldVelocity; private bool dashComplete; private static int PreAttackStateHash = Animator.StringToHash("PreAttack"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(enterSoundString, base.gameObject); modelTransform = GetModelTransform(); AimAnimator component = modelTransform.GetComponent(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); if ((bool)component) { component.enabled = true; } if ((bool)base.characterDirection) { base.characterDirection.moveVector = GetAimRay().direction; } if ((bool)modelAnimator) { PlayAnimation("Gesture", PreAttackStateHash); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration && base.isAuthority) { outer.SetNextState(new DashStrike()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class DashStrike : BaseState { public static float dashDuration = 1f; public static float slashDuration = 1.667f; public static float damageCoefficient = 4f; public static float procCoefficient; public static float selfForce; public static float forceMagnitude = 16f; public static float maxDashSpeedCoefficient = 4f; public static float maxSlashDistance = 20f; public static GameObject hitEffectPrefab; public static GameObject swipeEffectPrefab; public static string enterSoundString; public static string slashSoundString; private UnityEngine.Vector3 targetMoveVector; private UnityEngine.Vector3 targetMoveVectorVelocity; private OverlapAttack attack; private Animator modelAnimator; private float duration; private int slashCount; private Transform modelTransform; private bool dashComplete; private int handParamHash; private int swordParamHash; private float calculatedDashSpeed; private bool startedSlash; private static int DashStateHash = Animator.StringToHash("Dash"); private static int SwordStrikeStateHash = Animator.StringToHash("SwordStrike"); private static int forwardSpeedParamHash = Animator.StringToHash("forwardSpeed"); public override void OnEnter() { base.OnEnter(); duration = (dashDuration + slashDuration) / attackSpeedStat; modelAnimator = GetModelAnimator(); modelTransform = GetModelTransform(); base.characterMotor.velocity = UnityEngine.Vector3.zero; float sqrMagnitude = (base.characterBody.master.GetComponent().currentEnemy.characterBody.corePosition - base.characterBody.corePosition).sqrMagnitude; calculatedDashSpeed = Util.Remap(sqrMagnitude, 0f, maxSlashDistance * maxSlashDistance, 0f, maxDashSpeedCoefficient); attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); attack.procCoefficient = procCoefficient; attack.damageType = DamageType.Generic; Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat); if ((bool)modelAnimator) { PlayAnimation("Gesture", DashStateHash); handParamHash = Animator.StringToHash("HandStrike"); swordParamHash = Animator.StringToHash("SwordStrike"); } } public override void OnExit() { base.characterMotor.walkSpeedPenaltyCoefficient = 1f; base.OnExit(); } private void HandleSlash(int animatorParamHash, string muzzleName, string hitBoxGroupName) { bool flag = false; if (modelAnimator.GetFloat(animatorParamHash) > 0.1f) { if (!startedSlash) { Util.PlaySound(slashSoundString, base.gameObject); EffectManager.SimpleMuzzleFlash(swipeEffectPrefab, base.gameObject, muzzleName, transmit: true); startedSlash = true; } if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == hitBoxGroupName); } if ((bool)base.healthComponent) { base.healthComponent.TakeDamageForce(base.characterDirection.forward * selfForce, alwaysApply: true); } attack.ResetIgnoredHealthComponents(); if ((bool)base.characterDirection) { attack.forceVector = base.characterDirection.forward * forceMagnitude; } flag = attack.Fire(); } else if (startedSlash || flag) { slashCount++; startedSlash = false; } } public override void FixedUpdate() { base.FixedUpdate(); if (!dashComplete) { targetMoveVector = UnityEngine.Vector3.ProjectOnPlane(UnityEngine.Vector3.SmoothDamp(targetMoveVector, base.inputBank.aimDirection, ref targetMoveVectorVelocity, 0f, 0f), UnityEngine.Vector3.up).normalized; base.characterDirection.moveVector = targetMoveVector; UnityEngine.Vector3 forward = base.characterDirection.forward; float value = moveSpeedStat * calculatedDashSpeed; base.characterMotor.moveDirection = forward * calculatedDashSpeed; modelAnimator.SetFloat(forwardSpeedParamHash, value); } if (NetworkServer.active) { if (base.fixedAge > dashDuration && !dashComplete) { PlayAnimation("Gesture", SwordStrikeStateHash); dashComplete = true; } if ((bool)modelAnimator) { switch (slashCount) { case 0: HandleSlash(handParamHash, "ShurikenTag", "ShurikenHitbox"); break; case 1: HandleSlash(swordParamHash, "Sword", "SwordHitbox"); break; } } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class DeathState : GenericCharacterDeath { public static GameObject deathEffectPrefab; public static float duration = 1.333f; private float stopwatch; private Animator animator; private bool hasPlayedDeathEffect; public override void OnEnter() { base.OnEnter(); animator = GetModelAnimator(); if ((bool)base.characterMotor) { base.characterMotor.enabled = false; } } public override void FixedUpdate() { base.FixedUpdate(); if ((bool)animator) { stopwatch += GetDeltaTime(); if (!hasPlayedDeathEffect && animator.GetFloat("DeathEffect") > 0.5f) { hasPlayedDeathEffect = true; EffectData effectData = new EffectData(); effectData.origin = base.transform.position; EffectManager.SpawnEffect(deathEffectPrefab, effectData, transmit: false); } if (stopwatch >= duration) { DestroyModel(); EntityState.Destroy(base.gameObject); } } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class Hide : BaseState { private Transform modelTransform; public static GameObject hideEfffectPrefab; public static GameObject smokeEffectPrefab; public static Material destealthMaterial; private float stopwatch; private UnityEngine.Vector3 blinkDestination = UnityEngine.Vector3.zero; private UnityEngine.Vector3 blinkStart = UnityEngine.Vector3.zero; [Tooltip("the length of time to stay hidden")] public static float hiddenDuration = 5f; [Tooltip("the entire duration of the hidden state (hidden time + time after)")] public static float fullDuration = 10f; public static string beginSoundString; public static string endSoundString; private Animator animator; private CharacterModel characterModel; private HurtBoxGroup hurtboxGroup; private bool hidden; private GameObject smokeEffectInstance; private static int DisappearStateHash = Animator.StringToHash("Disappear"); private static int AppearStateHash = Animator.StringToHash("Appear"); public override void OnEnter() { base.OnEnter(); Util.PlaySound(beginSoundString, base.gameObject); modelTransform = GetModelTransform(); if ((bool)modelTransform) { animator = modelTransform.GetComponent(); characterModel = modelTransform.GetComponent(); hurtboxGroup = modelTransform.GetComponent(); if ((bool)smokeEffectPrefab) { Transform transform = modelTransform; if ((bool)transform) { smokeEffectInstance = UnityEngine.Object.Instantiate(smokeEffectPrefab, transform); ScaleParticleSystemDuration component = smokeEffectInstance.GetComponent(); if ((bool)component) { component.newDuration = component.initialDuration; } } } } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } PlayAnimation("Gesture", DisappearStateHash); if ((bool)base.characterBody && NetworkServer.active) { base.characterBody.AddBuff(RoR2Content.Buffs.Cloak); } CreateHiddenEffect(Util.GetCorePosition(base.gameObject)); if ((bool)base.healthComponent) { base.healthComponent.dontShowHealthbar = true; } hidden = true; } private void CreateHiddenEffect(UnityEngine.Vector3 origin) { EffectData effectData = new EffectData(); effectData.origin = origin; EffectManager.SpawnEffect(hideEfffectPrefab, effectData, transmit: false); } private void SetPosition(UnityEngine.Vector3 newPosition) { if ((bool)base.characterMotor) { base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= hiddenDuration && hidden) { Reveal(); } if (base.isAuthority && stopwatch > fullDuration) { outer.SetNextStateToMain(); } } private void Reveal() { Util.PlaySound(endSoundString, base.gameObject); CreateHiddenEffect(Util.GetCorePosition(base.gameObject)); if ((bool)modelTransform && (bool)destealthMaterial) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(animator.gameObject); temporaryOverlayInstance.duration = 1f; temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = destealthMaterial; temporaryOverlayInstance.inspectorCharacterModel = animator.gameObject.GetComponent(); temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.animateShaderAlpha = true; } if ((bool)hurtboxGroup) { HurtBoxGroup hurtBoxGroup = hurtboxGroup; int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1; hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } if ((bool)base.characterMotor) { base.characterMotor.enabled = true; } PlayAnimation("Gesture", AppearStateHash); if ((bool)base.characterBody && NetworkServer.active) { base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak); } if ((bool)base.healthComponent) { base.healthComponent.dontShowHealthbar = false; } if ((bool)smokeEffectInstance) { EntityState.Destroy(smokeEffectInstance); } hidden = false; } public override void OnExit() { base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : BaseState { private float stopwatch; public static float animDuration = 1.5f; public static float duration = 4f; public static string spawnSoundString; public static GameObject spawnEffectPrefab; private static int SpawnStateHash = Animator.StringToHash("Spawn"); public override void OnEnter() { base.OnEnter(); PlayAnimation("Body", SpawnStateHash); Util.PlaySound(spawnSoundString, base.gameObject); if ((bool)spawnEffectPrefab) { EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "Base", transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); stopwatch += GetDeltaTime(); if (stopwatch >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } public class ThrowShuriken : GenericProjectileBaseState { public static string attackString; private Transform muzzleTransform; private static int ThrowShurikenStateHash = Animator.StringToHash("ThrowShuriken"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture", ThrowShurikenStateHash); Util.PlaySound(attackString, base.gameObject); GetAimRay(); string text = "ShurikenTag"; muzzleTransform = FindModelChild(text); if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false); } if (base.isAuthority) { FireProjectile(); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } } namespace EntityStates.Assassin.Weapon { public class SlashCombo : BaseState { public enum SlashComboPermutation { Slash1, Slash2, Final } public static float baseDuration = 3.5f; public static float mecanimDurationCoefficient; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float selfForceMagnitude; public static float radius = 3f; public static GameObject hitEffectPrefab; public static GameObject swingEffectPrefab; public static string attackString; private OverlapAttack attack; private Animator modelAnimator; private float duration; private bool hasSlashed; public SlashComboPermutation slashComboPermutation; private static int SlashP1Hash = Animator.StringToHash("SlashP1"); private static int SlashP2Hash = Animator.StringToHash("SlashP2"); private static int SlashP3Hash = Animator.StringToHash("SlashP3"); private static int SlashComboParamHash = Animator.StringToHash("SlashCombo.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); attack = new OverlapAttack(); attack.attacker = base.gameObject; attack.inflictor = base.gameObject; attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker); attack.damage = damageCoefficient * damageStat; attack.hitEffectPrefab = hitEffectPrefab; attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master); Util.PlaySound(attackString, base.gameObject); string hitboxGroupName = ""; int animationStateHash = -1; switch (slashComboPermutation) { case SlashComboPermutation.Slash1: hitboxGroupName = "DaggerLeft"; animationStateHash = SlashP1Hash; break; case SlashComboPermutation.Slash2: hitboxGroupName = "DaggerLeft"; animationStateHash = SlashP2Hash; break; case SlashComboPermutation.Final: hitboxGroupName = "DaggerLeft"; animationStateHash = SlashP3Hash; break; } if ((bool)modelTransform) { attack.hitBoxGroup = Array.Find(modelTransform.GetComponents(), (HitBoxGroup element) => element.groupName == hitboxGroupName); } if ((bool)modelAnimator) { PlayAnimation("Gesture, Override", animationStateHash, SlashComboParamHash, duration * mecanimDurationCoefficient); PlayAnimation("Gesture, Additive", animationStateHash, SlashComboParamHash, duration * mecanimDurationCoefficient); } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("SlashCombo.hitBoxActive") > 0.1f) { if (!hasSlashed) { EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "SwingCenter", transmit: true); HealthComponent healthComponent = base.characterBody.healthComponent; CharacterDirection component = base.characterBody.GetComponent(); if ((bool)healthComponent) { healthComponent.TakeDamageForce(selfForceMagnitude * component.forward, alwaysApply: true); } hasSlashed = true; } attack.forceVector = base.transform.forward * forceMagnitude; attack.Fire(); } if (!(base.fixedAge >= duration) || !base.isAuthority) { return; } if ((bool)base.inputBank && base.inputBank.skill1.down) { SlashCombo slashCombo = new SlashCombo(); switch (slashComboPermutation) { case SlashComboPermutation.Slash1: slashCombo.slashComboPermutation = SlashComboPermutation.Slash2; break; case SlashComboPermutation.Slash2: slashCombo.slashComboPermutation = SlashComboPermutation.Slash1; break; } outer.SetNextState(slashCombo); } else { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } } namespace EntityStates.ArtifactShell { public class ArtifactShellBaseState : BaseState { protected Light light; private string stopLoopSound; protected PurchaseInteraction purchaseInteraction { get; private set; } protected virtual CostTypeIndex interactionCostType => CostTypeIndex.None; protected virtual bool interactionAvailable => false; protected virtual int interactionCost => 0; protected ParticleSystem rayParticleSystem { get; private set; } protected PostProcessVolume postProcessVolume { get; private set; } public override void OnEnter() { base.OnEnter(); purchaseInteraction = GetComponent(); if ((object)purchaseInteraction != null) { purchaseInteraction.costType = interactionCostType; purchaseInteraction.Networkcost = interactionCost; purchaseInteraction.Networkavailable = interactionAvailable; purchaseInteraction.onPurchase.AddListener(DoOnPurchase); } rayParticleSystem = FindModelChild("RayParticles")?.GetComponent(); postProcessVolume = FindModelChild("PP")?.GetComponent(); light = FindModelChild("Light").GetComponent(); CalcLoopSounds(base.healthComponent.combinedHealthFraction, out var startLoopSound, out stopLoopSound); Util.PlaySound(startLoopSound, base.gameObject); } private static void CalcLoopSounds(float currentHealthFraction, out string startLoopSound, out string stopLoopSound) { startLoopSound = null; stopLoopSound = null; float num = 0.05f; if (currentHealthFraction > 0.75f + num) { startLoopSound = "Play_artifactBoss_loop_level1"; stopLoopSound = "Stop_artifactBoss_loop_level1"; } else if (currentHealthFraction > 0.25f + num) { startLoopSound = "Play_artifactBoss_loop_level2"; stopLoopSound = "Stop_artifactBoss_loop_level2"; } else if (currentHealthFraction > 0f + num) { startLoopSound = "Play_artifactBoss_loop_level2"; stopLoopSound = "Stop_artifactBoss_loop_level2"; } } public override void OnExit() { Util.PlaySound(stopLoopSound, base.gameObject); if ((object)purchaseInteraction != null) { purchaseInteraction.onPurchase.RemoveListener(DoOnPurchase); purchaseInteraction = null; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); UpdateVisuals(); } private void DoOnPurchase(Interactor activator) { OnPurchase(activator); } protected virtual void OnPurchase(Interactor activator) { } protected void UpdateVisuals() { float num = 1f - base.healthComponent.combinedHealthFraction; if ((bool)rayParticleSystem) { ParticleSystem.EmissionModule emission = rayParticleSystem.emission; emission.rateOverTime = Util.Remap(num, 0f, 1f, 0f, 10f); ParticleSystem.MainModule main = rayParticleSystem.main; main.simulationSpeed = Util.Remap(num, 0f, 1f, 1f, 5f); } if ((bool)postProcessVolume) { if (!Mathf.Approximately(postProcessVolume.weight, num)) { PostProcessVolume.DispatchVolumeSettingsChangedEvent(); } postProcessVolume.weight = num; } if ((bool)light) { light.range = 10f + num * 150f; } } } public class StartHurt : ArtifactShellBaseState { public static float baseDuration = 0.25f; public static string firstHurtSound; public override void OnEnter() { base.OnEnter(); if (base.healthComponent.combinedHealthFraction >= 1f) { Util.PlaySound(firstHurtSound, base.gameObject); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= baseDuration) { outer.SetNextState(new Hurt()); } } } public class Hurt : ArtifactShellBaseState { public static float baseDuration = 2f; public static float blastRadius = 50f; public static float knockbackForce = 5000f; public static float knockbackLiftForce = 2000f; public static float blastOriginOffset = -10f; public static GameObject novaEffectPrefab; private float duration; public override void OnEnter() { base.OnEnter(); duration = baseDuration; UnityEngine.Vector3 position = base.transform.position; if (NetworkServer.active) { DamageInfo damageInfo = new DamageInfo(); damageInfo.position = position; damageInfo.attacker = null; damageInfo.inflictor = null; damageInfo.damage = Mathf.Ceil(base.healthComponent.fullCombinedHealth * 0.25f); damageInfo.damageType = DamageType.BypassArmor | DamageType.Silent; damageInfo.procCoefficient = 0f; base.healthComponent.TakeDamage(damageInfo); BlastAttack blastAttack = new BlastAttack(); blastAttack.position = position + blastOriginOffset * UnityEngine.Vector3.up; blastAttack.attacker = base.gameObject; blastAttack.inflictor = base.gameObject; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.baseDamage = 0f; blastAttack.baseForce = knockbackForce; blastAttack.bonusForce = UnityEngine.Vector3.up * knockbackLiftForce; blastAttack.falloffModel = BlastAttack.FalloffModel.Linear; blastAttack.radius = blastRadius; blastAttack.procCoefficient = 0f; blastAttack.teamIndex = TeamIndex.None; blastAttack.Fire(); ArtifactTrialMissionController.RemoveAllMissionKeys(); } EffectData effectData = new EffectData { origin = position, scale = blastRadius }; EffectManager.SpawnEffect(novaEffectPrefab, effectData, transmit: false); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { outer.SetNextState(new WaitForKey()); } } } public class WaitForIntro : ArtifactShellBaseState { public static float baseDuration = 10f; private float duration; protected override bool interactionAvailable => false; public override void OnEnter() { base.OnEnter(); duration = baseDuration; } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { outer.SetNextState(new WaitForKey()); } } } public class WaitForKey : ArtifactShellBaseState { protected override CostTypeIndex interactionCostType => CostTypeIndex.ArtifactShellKillerItem; protected override int interactionCost => 1; protected override bool interactionAvailable => true; public override void OnEnter() { base.OnEnter(); } protected override void OnPurchase(Interactor activator) { base.OnPurchase(activator); outer.SetInterruptState(new StartHurt(), InterruptPriority.Pain); } } public class FireSolarFlares : BaseState { public static GameObject projectilePrefab; public static int minimumProjectileCount; public static int maximumProjectileCount; public static float arc; public static float baseDuration; public static float radius; public static float projectileDamageCoefficient; public static float projectileForce; public static float projectileFuse; public static float projectileSpeed; private float duration; private int projectileCount; private int projectilesFired; private UnityEngine.Quaternion currentRotation; private UnityEngine.Quaternion deltaRotation; public override void OnEnter() { base.OnEnter(); if ((bool)base.healthComponent) { projectileCount = (int)Util.Remap(base.healthComponent.combinedHealthFraction, 0f, 1f, maximumProjectileCount, minimumProjectileCount); } if (NetworkServer.active) { UnityEngine.Vector3 aimDirection = base.inputBank.aimDirection; currentRotation = UnityEngine.Quaternion.LookRotation(aimDirection); _ = Run.FixedTimeStamp.now.t * 2f % 1f; UnityEngine.Vector3 rhs = currentRotation * UnityEngine.Vector3.forward; UnityEngine.Vector3 lhs = currentRotation * UnityEngine.Vector3.right; _ = currentRotation * UnityEngine.Vector3.up; deltaRotation = UnityEngine.Quaternion.AngleAxis(arc / (float)projectileCount, UnityEngine.Vector3.Cross(lhs, rhs)); } duration = baseDuration / attackSpeedStat; } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { float num = duration / (float)projectileCount; if (base.fixedAge >= (float)projectilesFired * num) { projectilesFired++; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.position = base.transform.position + currentRotation * UnityEngine.Vector3.forward * radius; fireProjectileInfo.rotation = currentRotation; fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.fuseOverride = projectileFuse; fireProjectileInfo.useFuseOverride = true; fireProjectileInfo.speedOverride = projectileSpeed; fireProjectileInfo.useSpeedOverride = true; fireProjectileInfo.damage = damageStat * projectileDamageCoefficient; fireProjectileInfo.force = projectileForce; ProjectileManager.instance.FireProjectile(fireProjectileInfo); currentRotation *= deltaRotation; } if (base.fixedAge >= duration) { outer.SetNextStateToMain(); } } } } public class Death : ArtifactShellBaseState { public static float duration; protected override bool interactionAvailable => false; public override void OnEnter() { base.OnEnter(); Util.PlaySound(GetComponent().deathSound, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { EntityState.Destroy(base.gameObject); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Death; } } } namespace EntityStates.AncientWispMonster { public class ChannelRain : BaseState { private float castTimer; public static float baseDuration = 4f; public static float explosionDelay = 2f; public static int explosionCount = 10; public static float damageCoefficient; public static float randomRadius; public static float radius; public static GameObject delayPrefab; private float duration; private float durationBetweenCast; public override void OnEnter() { base.OnEnter(); duration = baseDuration; durationBetweenCast = baseDuration / (float)explosionCount / attackSpeedStat; PlayCrossfade("Body", "ChannelRain", 0.3f); } private void PlaceRain() { UnityEngine.Vector3 vector = UnityEngine.Vector3.zero; Ray aimRay = GetAimRay(); aimRay.origin += UnityEngine.Random.insideUnitSphere * randomRadius; if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask)) { vector = hitInfo.point; } if (!(vector != UnityEngine.Vector3.zero)) { return; } Transform transform = FindTargetClosest(vector, base.characterBody.GetComponent().teamIndex switch { TeamIndex.Monster => TeamIndex.Player, TeamIndex.Player => TeamIndex.Monster, _ => TeamIndex.Neutral, }); UnityEngine.Vector3 vector2 = vector; if ((bool)transform) { vector2 = transform.transform.position; } vector2 += UnityEngine.Random.insideUnitSphere * randomRadius; Ray ray = default(Ray); ray.origin = vector2 + UnityEngine.Vector3.up * randomRadius; ray.direction = UnityEngine.Vector3.down; if (Physics.Raycast(ray, out hitInfo, 500f, LayerIndex.world.mask)) { UnityEngine.Vector3 point = hitInfo.point; UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(hitInfo.normal); GameObject obj = UnityEngine.Object.Instantiate(delayPrefab, point, rotation); DelayBlast component = obj.GetComponent(); component.position = point; component.baseDamage = base.characterBody.damage * damageCoefficient; component.baseForce = 2000f; component.bonusForce = UnityEngine.Vector3.up * 1000f; component.radius = radius; component.attacker = base.gameObject; component.inflictor = null; component.crit = Util.CheckRoll(critStat, base.characterBody.master); component.maxTimer = explosionDelay; obj.GetComponent().teamIndex = TeamComponent.GetObjectTeam(component.attacker); obj.transform.localScale = new UnityEngine.Vector3(radius, radius, 1f); ScaleParticleSystemDuration component2 = obj.GetComponent(); if ((bool)component2) { component2.newDuration = explosionDelay; } } } public override void FixedUpdate() { base.FixedUpdate(); castTimer += GetDeltaTime(); if (castTimer >= durationBetweenCast) { PlaceRain(); castTimer -= durationBetweenCast; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new EndRain()); } } private Transform FindTargetClosest(UnityEngine.Vector3 point, TeamIndex enemyTeam) { ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(enemyTeam); float num = 99999f; Transform result = null; for (int i = 0; i < teamMembers.Count; i++) { float num2 = UnityEngine.Vector3.SqrMagnitude(teamMembers[i].transform.position - point); if (num2 < num) { num = num2; result = teamMembers[i].transform; } } return result; } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class ChargeBomb : BaseState { public static float baseDuration = 3f; public static GameObject effectPrefab; public static GameObject delayPrefab; public static float radius = 10f; public static float damageCoefficient = 1f; private float duration; private GameObject chargeEffectLeft; private GameObject chargeEffectRight; private UnityEngine.Vector3 startLine = UnityEngine.Vector3.zero; private UnityEngine.Vector3 endLine = UnityEngine.Vector3.zero; private bool hasFired; private EffectManagerHelper _emh_chargeEffectLeft; private EffectManagerHelper _emh_chargeEffectRight; private static int chargeBombAnimStateHash = Animator.StringToHash("ChargeBomb"); private static int chargeBombParamHas = Animator.StringToHash("ChargeBomb.playbackRate"); public override void Reset() { base.Reset(); duration = 0f; chargeEffectLeft = null; chargeEffectRight = null; startLine = UnityEngine.Vector3.zero; endLine = UnityEngine.Vector3.zero; hasFired = false; _emh_chargeEffectLeft = null; _emh_chargeEffectRight = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture", chargeBombAnimStateHash, chargeBombParamHas, duration); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component && (bool)effectPrefab) { Transform transform = component.FindChild("MuzzleLeft"); Transform transform2 = component.FindChild("MuzzleRight"); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(effectPrefab)) { chargeEffectLeft = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffectLeft = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation); chargeEffectLeft = _emh_chargeEffectLeft.gameObject; } chargeEffectLeft.transform.parent = transform; } if ((bool)transform2) { if (!EffectManager.ShouldUsePooledEffect(effectPrefab)) { chargeEffectRight = UnityEngine.Object.Instantiate(effectPrefab, transform2.position, transform2.rotation); } else { _emh_chargeEffectRight = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform2.position, transform2.rotation); chargeEffectRight = _emh_chargeEffectRight.gameObject; } chargeEffectRight.transform.parent = transform2; } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } if (Physics.Raycast(GetAimRay(), out var hitInfo, (int)LayerIndex.world.mask)) { startLine = hitInfo.point; } } public override void OnExit() { base.OnExit(); if (_emh_chargeEffectLeft != null && _emh_chargeEffectLeft.OwningPool != null) { _emh_chargeEffectLeft.OwningPool.ReturnObject(_emh_chargeEffectLeft); } else { EntityState.Destroy(chargeEffectLeft); } chargeEffectLeft = null; _emh_chargeEffectLeft = null; if (_emh_chargeEffectRight != null && _emh_chargeEffectRight.OwningPool != null) { _emh_chargeEffectRight.OwningPool.ReturnObject(_emh_chargeEffectRight); } else { EntityState.Destroy(chargeEffectRight); } chargeEffectRight = null; _emh_chargeEffectRight = null; } public override void Update() { base.Update(); } public override void FixedUpdate() { base.FixedUpdate(); float num = 0f; if (base.fixedAge >= num && !hasFired) { hasFired = true; Ray aimRay = GetAimRay(); if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask)) { endLine = hitInfo.point; } UnityEngine.Vector3 normalized = (endLine - startLine).normalized; normalized.y = 0f; normalized.Normalize(); for (int i = 0; i < 1; i++) { UnityEngine.Vector3 vector = endLine; Ray ray = default(Ray); ray.origin = aimRay.origin; ray.direction = vector - aimRay.origin; UnityEngine.Debug.DrawLine(ray.origin, vector, UnityEngine.Color.red, 5f); if (Physics.Raycast(ray, out hitInfo, 500f, LayerIndex.world.mask)) { UnityEngine.Vector3 point = hitInfo.point; UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(hitInfo.normal); GameObject obj = UnityEngine.Object.Instantiate(delayPrefab, point, rotation); DelayBlast component = obj.GetComponent(); component.position = point; component.baseDamage = base.characterBody.damage * damageCoefficient; component.baseForce = 2000f; component.bonusForce = UnityEngine.Vector3.up * 1000f; component.radius = radius; component.attacker = base.gameObject; component.inflictor = null; component.crit = Util.CheckRoll(critStat, base.characterBody.master); component.maxTimer = duration; obj.GetComponent().teamIndex = TeamComponent.GetObjectTeam(component.attacker); obj.transform.localScale = new UnityEngine.Vector3(radius, radius, 1f); ScaleParticleSystemDuration component2 = obj.GetComponent(); if ((bool)component2) { component2.newDuration = duration; } } } } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new FireBomb()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ChargeRain : BaseState { public static float baseDuration = 3f; public static GameObject effectPrefab; public static GameObject delayPrefab; private float duration; private static int chargeRainStateHash = Animator.StringToHash("ChargeRain"); private static int chargeRainplaybackRateParamHash = Animator.StringToHash("ChargeRain.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } PlayAnimation("Body", chargeRainStateHash, chargeRainplaybackRateParamHash, duration); if (Physics.Raycast(base.transform.position, UnityEngine.Vector3.down, out var hitInfo, 999f, LayerIndex.world.mask)) { NodeGraph groundNodes = SceneInfo.instance.groundNodes; NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(hitInfo.point, HullClassification.BeetleQueen); groundNodes.GetNodePosition(nodeIndex, out var position); base.transform.position = position + UnityEngine.Vector3.up * 2f; } } public override void OnExit() { base.OnExit(); } public override void Update() { base.Update(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextState(new ChannelRain()); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class ChargeRHCannon : BaseState { public static float baseDuration = 3f; public static GameObject effectPrefab; private float duration; private GameObject chargeEffectLeft; private GameObject chargeEffectRight; private EffectManagerHelper _emh_chargeEffectRight; private static int chargeRHCannonHash = Animator.StringToHash("ChargeRHCannon"); private static int chargeRHCannonPlaybackHash = Animator.StringToHash("ChargeRHCannon.playbackRate"); public override void Reset() { base.Reset(); duration = 0f; chargeEffectLeft = null; chargeEffectRight = null; _emh_chargeEffectRight = null; } public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; Transform modelTransform = GetModelTransform(); PlayAnimation("Gesture", chargeRHCannonHash, chargeRHCannonPlaybackHash, duration); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component && (bool)effectPrefab) { Transform transform = component.FindChild("MuzzleRight"); if ((bool)transform) { if (!EffectManager.ShouldUsePooledEffect(effectPrefab)) { chargeEffectRight = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation); } else { _emh_chargeEffectRight = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation); chargeEffectRight = _emh_chargeEffectRight.gameObject; } chargeEffectRight.transform.parent = transform; } } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(duration); } } public override void OnExit() { base.OnExit(); if (_emh_chargeEffectRight != null && _emh_chargeEffectRight.OwningPool != null) { _emh_chargeEffectRight.OwningPool.ReturnObject(_emh_chargeEffectRight); } else { EntityState.Destroy(chargeEffectRight); } chargeEffectRight = null; _emh_chargeEffectRight = null; } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { FireRHCannon nextState = new FireRHCannon(); outer.SetNextState(nextState); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class EndRain : BaseState { public static float baseDuration = 3f; public static GameObject effectPrefab; public static GameObject delayPrefab; private float duration; private static int endRainHash = Animator.StringToHash("EndRain"); private static int endRainParamHash = Animator.StringToHash("EndRain.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } PlayAnimation("Body", endRainHash, endRainParamHash, duration); NodeGraph airNodes = SceneInfo.instance.airNodes; NodeGraph.NodeIndex nodeIndex = airNodes.FindClosestNode(base.transform.position, base.characterBody.hullClassification); airNodes.GetNodePosition(nodeIndex, out var position); base.transform.position = position; } public override void OnExit() { base.OnExit(); } public override void Update() { base.Update(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Enrage : BaseState { public static float baseDuration = 3.5f; public static GameObject enragePrefab; private Animator modelAnimator; private float duration; private bool hasCastBuff; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayCrossfade("Gesture", "Enrage", "Enrage.playbackRate", duration, 0.2f); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Enrage.activate") > 0.5f && !hasCastBuff) { EffectData effectData = new EffectData(); effectData.origin = base.transform.position; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(enragePrefab, effectData, transmit: true); hasCastBuff = true; base.characterBody.AddBuff(JunkContent.Buffs.EnrageAncientWisp); } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } private static void PullEnemies(UnityEngine.Vector3 position, UnityEngine.Vector3 direction, float coneAngle, float maxDistance, float force, TeamIndex excludedTeam) { float num = Mathf.Cos(coneAngle * 0.5f * (MathF.PI / 180f)); HGPhysics.OverlapSphere(out var colliders, position, maxDistance); foreach (Collider collider in colliders) { UnityEngine.Vector3 position2 = collider.transform.position; UnityEngine.Vector3 normalized = (position - position2).normalized; if (!(UnityEngine.Vector3.Dot(-normalized, direction) >= num)) { continue; } TeamIndex teamIndex = TeamIndex.Neutral; TeamComponent component = collider.GetComponent(); if (!component) { continue; } teamIndex = component.teamIndex; if (teamIndex != excludedTeam) { CharacterMotor component2 = collider.GetComponent(); if ((bool)component2) { component2.ApplyForce(normalized * force); } Rigidbody component3 = collider.GetComponent(); if ((bool)component3) { component3.AddForce(normalized * force, ForceMode.Impulse); } } } HGPhysics.ReturnResults(colliders); } } public class FireBomb : BaseState { public static float baseDuration = 4f; private float duration; private static int fireBombHash = Animator.StringToHash("FireBomb"); private static int fireBombParamHash = Animator.StringToHash("FireBomb.playbackRate"); public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; PlayAnimation("Gesture", fireBombHash, fireBombParamHash, duration); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Frozen; } } public class FireRHCannon : BaseState { public static GameObject projectilePrefab; public static GameObject effectPrefab; public static float baseDuration = 2f; public static float baseDurationBetweenShots = 0.5f; public static float damageCoefficient = 1.2f; public static float force = 20f; public static int bulletCount; private float duration; private float durationBetweenShots; public int bulletCountCurrent = 1; private static int fireRHCannonHash = Animator.StringToHash("FireRHCannon"); private static int fireRHCannonParamHash = Animator.StringToHash("FireRHCannon.playbackRate"); public override void OnEnter() { base.OnEnter(); Ray aimRay = GetAimRay(); string text = "MuzzleRight"; duration = baseDuration / attackSpeedStat; durationBetweenShots = baseDurationBetweenShots / attackSpeedStat; if ((bool)effectPrefab) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false); } PlayAnimation("Gesture", fireRHCannonHash, fireRHCannonParamHash, duration); if (!base.isAuthority || !base.modelLocator || !base.modelLocator.modelTransform) { return; } ChildLocator component = base.modelLocator.modelTransform.GetComponent(); if (!component) { return; } Transform transform = component.FindChild(text); if ((bool)transform) { UnityEngine.Vector3 forward = aimRay.direction; if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask)) { forward = hitInfo.point - transform.position; } ProjectileManager.instance.FireProjectile(projectilePrefab, transform.position, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master)); } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (base.isAuthority) { if (bulletCountCurrent == bulletCount && base.fixedAge >= duration) { outer.SetNextStateToMain(); } else if (bulletCountCurrent < bulletCount && base.fixedAge >= durationBetweenShots) { FireRHCannon fireRHCannon = new FireRHCannon(); fireRHCannon.bulletCountCurrent = bulletCountCurrent + 1; outer.SetNextState(fireRHCannon); } } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.Skill; } } public class Throw : BaseState { public static float baseDuration = 3.5f; public static float returnToIdlePercentage; public static float damageCoefficient = 4f; public static float forceMagnitude = 16f; public static float radius = 3f; public static GameObject projectilePrefab; public static GameObject swingEffectPrefab; private Transform rightMuzzleTransform; private Animator modelAnimator; private float duration; private bool hasSwung; public override void OnEnter() { base.OnEnter(); duration = baseDuration / attackSpeedStat; modelAnimator = GetModelAnimator(); Transform modelTransform = GetModelTransform(); if ((bool)modelTransform) { ChildLocator component = modelTransform.GetComponent(); if ((bool)component) { rightMuzzleTransform = component.FindChild("MuzzleRight"); } } if ((bool)modelAnimator) { int layerIndex = modelAnimator.GetLayerIndex("Gesture"); if (modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("Throw1")) { PlayCrossfade("Gesture", "Throw2", "Throw.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f); } else { PlayCrossfade("Gesture", "Throw1", "Throw.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f); } } if ((bool)base.characterBody) { base.characterBody.SetAimTimer(2f); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Throw.activate") > 0f && !hasSwung) { Ray aimRay = GetAimRay(); UnityEngine.Vector3 forward = aimRay.direction; if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask)) { forward = hitInfo.point - rightMuzzleTransform.position; } ProjectileManager.instance.FireProjectile(projectilePrefab, rightMuzzleTransform.position, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, forceMagnitude, Util.CheckRoll(critStat, base.characterBody.master)); EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "RightSwingCenter", transmit: true); hasSwung = true; } if (base.fixedAge >= duration && base.isAuthority) { outer.SetNextStateToMain(); } } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } private static void PullEnemies(UnityEngine.Vector3 position, UnityEngine.Vector3 direction, float coneAngle, float maxDistance, float force, TeamIndex excludedTeam) { float num = Mathf.Cos(coneAngle * 0.5f * (MathF.PI / 180f)); Collider[] colliders; int num2 = HGPhysics.OverlapSphere(out colliders, position, maxDistance); for (int i = 0; i < num2; i++) { Collider collider = colliders[i]; UnityEngine.Vector3 position2 = collider.transform.position; UnityEngine.Vector3 normalized = (position - position2).normalized; if (!(UnityEngine.Vector3.Dot(-normalized, direction) >= num)) { continue; } TeamIndex teamIndex = TeamIndex.Neutral; TeamComponent component = collider.GetComponent(); if (!component) { continue; } teamIndex = component.teamIndex; if (teamIndex != excludedTeam) { CharacterMotor component2 = collider.GetComponent(); if ((bool)component2) { component2.ApplyForce(normalized * force); } Rigidbody component3 = collider.GetComponent(); if ((bool)component3) { component3.AddForce(normalized * force, ForceMode.Impulse); } } } HGPhysics.ReturnResults(colliders); } } } namespace EntityStates.AI { public abstract class BaseAIState : EntityState { protected static FloatConVar cvAIUpdateInterval = new FloatConVar("ai_update_interval", ConVarFlags.Cheat, "0.2", "Frequency that the local navigator refreshes."); protected BaseAI.BodyInputs bodyInputs; protected bool isInJump; protected UnityEngine.Vector3? jumpLockedMoveVector; protected CharacterMaster characterMaster { get; private set; } protected BaseAI ai { get; private set; } protected CharacterBody body { get; private set; } protected Transform bodyTransform { get; private set; } protected InputBankTest bodyInputBank { get; private set; } protected CharacterMotor bodyCharacterMotor { get; private set; } protected SkillLocator bodySkillLocator { get; private set; } public override void OnEnter() { base.OnEnter(); characterMaster = GetComponent(); ai = GetComponent(); if ((bool)ai) { body = ai.body; bodyTransform = ai.bodyTransform; bodyInputBank = ai.bodyInputBank; bodyCharacterMotor = ai.bodyCharacterMotor; bodySkillLocator = ai.bodySkillLocator; } bodyInputs = default(BaseAI.BodyInputs); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); } public virtual BaseAI.BodyInputs GenerateBodyInputs(in BaseAI.BodyInputs previousBodyInputs) { return bodyInputs; } protected void ModifyInputsForJumpIfNeccessary(ref BaseAI.BodyInputs bodyInputs) { if (!ai) { return; } BroadNavigationSystem.AgentOutput output = ai.broadNavigationAgent.output; bodyInputs.pressJump = false; if (!bodyCharacterMotor) { return; } bool isGrounded = bodyCharacterMotor.isGrounded; bool flag = isGrounded || bodyCharacterMotor.isFlying || !bodyCharacterMotor.useGravity; if (isInJump && flag) { isInJump = false; jumpLockedMoveVector = null; } if (isGrounded) { float num = Mathf.Max(output.desiredJumpVelocity, ai.localNavigator.jumpSpeed); if (num > 0f && body.jumpPower > 0f) { bool num2 = output.desiredJumpVelocity >= ai.localNavigator.jumpSpeed; num = body.jumpPower; bodyInputs.pressJump = true; if (num2 && output.nextPosition.HasValue) { UnityEngine.Vector3 vector = output.nextPosition.Value - bodyTransform.position; UnityEngine.Vector3 vector2 = vector; vector2.y = 0f; float num3 = Trajectory.CalculateFlightDuration(0f, vector.y, num); float walkSpeed = bodyCharacterMotor.walkSpeed; if (num3 > 0f && walkSpeed > 0f) { float magnitude = vector2.magnitude; float num4 = Mathf.Max(magnitude / num3 / bodyCharacterMotor.walkSpeed, 0f); jumpLockedMoveVector = vector2 * (num4 / magnitude); bodyCharacterMotor.moveDirection = jumpLockedMoveVector.Value; } } isInJump = true; } } if (jumpLockedMoveVector.HasValue) { bodyInputs.moveVector = jumpLockedMoveVector.Value; } } protected UnityEngine.Vector3? PickRandomNearbyReachablePosition() { if (!ai || !body) { return null; } NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(body.isFlying ? MapNodeGroup.GraphType.Air : MapNodeGroup.GraphType.Ground); NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(nodeGraph, (HullMask)(1 << (int)body.hullClassification)); NodeGraph.NodeIndex nodeIndex = nodeGraph.FindClosestNode(bodyTransform.position, body.hullClassification, 50f); nodeGraphSpider.AddNodeForNextStep(nodeIndex); nodeGraphSpider.PerformStep(); nodeGraphSpider.PerformStep(); List collectedSteps = nodeGraphSpider.collectedSteps; if (collectedSteps.Count == 0) { return null; } int index = UnityEngine.Random.Range(0, collectedSteps.Count); NodeGraph.NodeIndex node = collectedSteps[index].node; if (nodeGraph.GetNodePosition(node, out var position)) { return position; } return null; } protected void AimAt(ref BaseAI.BodyInputs dest, BaseAI.Target aimTarget) { if (aimTarget != null && aimTarget.GetBullseyePosition(out var position)) { dest.desiredAimDirection = (position - bodyInputBank.aimOrigin).normalized; } } protected void AimInDirection(ref BaseAI.BodyInputs dest, UnityEngine.Vector3 aimDirection) { if (aimDirection != UnityEngine.Vector3.zero) { dest.desiredAimDirection = aimDirection; } } } } namespace EntityStates.AI.Walker { public class Combat : BaseAIState { private float strafeDirection; private const float strafeDuration = 0.25f; private float strafeTimer; private float activeSoundTimer; private float aiUpdateTimer; public float timeChasing; private const float minUpdateInterval = 1f / 6f; private const float maxUpdateInterval = 0.2f; private AISkillDriver dominantSkillDriver; protected bool currentSkillMeetsActivationConditions; protected SkillSlot currentSkillSlot = SkillSlot.None; protected UnityEngine.Vector3 myBodyFootPosition; private float lastPathUpdate; private float fallbackNodeStartAge; private readonly float fallbackNodeDuration = 4f; public override void OnEnter() { base.OnEnter(); activeSoundTimer = UnityEngine.Random.Range(3f, 8f); if ((bool)base.ai) { lastPathUpdate = base.ai.broadNavigationAgent.output.lastPathUpdate; base.ai.broadNavigationAgent.InvalidatePath(); } fallbackNodeStartAge = float.NegativeInfinity; } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!base.ai || !base.body) { return; } float deltaTime = GetDeltaTime(); aiUpdateTimer -= deltaTime; strafeTimer -= deltaTime; UpdateFootPosition(); if (aiUpdateTimer <= 0f) { aiUpdateTimer = BaseAIState.cvAIUpdateInterval.value; UpdateAI(BaseAIState.cvAIUpdateInterval.value); if (!dominantSkillDriver) { outer.SetNextState(new LookBusy()); } } UpdateBark(); } protected void UpdateFootPosition() { myBodyFootPosition = base.body.footPosition; BroadNavigationSystem.Agent broadNavigationAgent = base.ai.broadNavigationAgent; broadNavigationAgent.currentPosition = myBodyFootPosition; } protected void UpdateAI(float deltaTime) { BaseAI.SkillDriverEvaluation skillDriverEvaluation = base.ai.skillDriverEvaluation; dominantSkillDriver = skillDriverEvaluation.dominantSkillDriver; currentSkillSlot = SkillSlot.None; currentSkillMeetsActivationConditions = false; bodyInputs.moveVector = UnityEngine.Vector3.zero; AISkillDriver.MovementType movementType = AISkillDriver.MovementType.Stop; float num = 1f; bool flag = false; bool flag2 = false; bool flag3 = false; if (!base.body || !base.bodyInputBank) { return; } if ((bool)dominantSkillDriver) { movementType = dominantSkillDriver.movementType; currentSkillSlot = dominantSkillDriver.skillSlot; flag = dominantSkillDriver.activationRequiresTargetLoS; flag2 = dominantSkillDriver.activationRequiresAimTargetLoS; flag3 = dominantSkillDriver.activationRequiresAimConfirmation; num = dominantSkillDriver.moveInputScale; } UnityEngine.Vector3 position = base.bodyTransform.position; _ = base.bodyInputBank.aimOrigin; BroadNavigationSystem.Agent broadNavigationAgent = base.ai.broadNavigationAgent; BroadNavigationSystem.AgentOutput output = broadNavigationAgent.output; BaseAI.Target target = skillDriverEvaluation.target; if ((bool)target?.gameObject) { target.GetBullseyePosition(out var position2); UnityEngine.Vector3 vector = position2; if (fallbackNodeStartAge + fallbackNodeDuration < base.fixedAge) { base.ai.SetGoalPosition(target); } UnityEngine.Vector3 targetPosition = position; bool allowWalkOffCliff = true; UnityEngine.Vector3 vector2 = ((!dominantSkillDriver || !dominantSkillDriver.ignoreNodeGraph) ? (output.nextPosition ?? myBodyFootPosition) : ((!base.body.isFlying) ? vector : position2)); UnityEngine.Vector3 vector3 = (vector2 - myBodyFootPosition).normalized * 10f; UnityEngine.Vector3 vector4 = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, vector3); switch (movementType) { case AISkillDriver.MovementType.ChaseMoveTarget: targetPosition = vector2 + (position - myBodyFootPosition); break; case AISkillDriver.MovementType.FleeMoveTarget: targetPosition -= vector3; break; case AISkillDriver.MovementType.StrafeMovetarget: if (strafeTimer <= 0f) { if (strafeDirection == 0f) { strafeDirection = ((UnityEngine.Random.Range(0, 1) == 0) ? (-1f) : 1f); } strafeTimer = 0.25f; } targetPosition += vector4 * strafeDirection; allowWalkOffCliff = false; break; } base.ai.localNavigator.targetPosition = targetPosition; base.ai.localNavigator.allowWalkOffCliff = allowWalkOffCliff; base.ai.localNavigator.Update(deltaTime); if (base.ai.localNavigator.wasObstructedLastUpdate) { strafeDirection *= -1f; } bodyInputs.moveVector = base.ai.localNavigator.moveVector; bodyInputs.moveVector *= num; if (!flag3 || base.ai.hasAimConfirmation) { bool flag4 = true; if (skillDriverEvaluation.target == skillDriverEvaluation.aimTarget && flag && flag2) { flag2 = false; } if (flag4 && flag) { flag4 = skillDriverEvaluation.target.TestLOSNow(); } if (flag4 && flag2) { flag4 = skillDriverEvaluation.aimTarget.TestLOSNow(); } if (flag4) { currentSkillMeetsActivationConditions = true; } } } if (output.lastPathUpdate > lastPathUpdate && !output.targetReachable && fallbackNodeStartAge + fallbackNodeDuration < base.fixedAge) { broadNavigationAgent.goalPosition = PickRandomNearbyReachablePosition(); broadNavigationAgent.InvalidatePath(); } lastPathUpdate = output.lastPathUpdate; } public override BaseAI.BodyInputs GenerateBodyInputs(in BaseAI.BodyInputs previousBodyInputs) { bool pressSkill = false; bool pressSkill2 = false; bool pressSkill3 = false; bool pressSkill4 = false; if ((bool)base.bodyInputBank) { AISkillDriver.ButtonPressType buttonPressType = AISkillDriver.ButtonPressType.Abstain; if ((bool)dominantSkillDriver) { buttonPressType = dominantSkillDriver.buttonPressType; } bool flag = false; switch (currentSkillSlot) { case SkillSlot.Primary: flag = previousBodyInputs.pressSkill1; break; case SkillSlot.Secondary: flag = previousBodyInputs.pressSkill2; break; case SkillSlot.Utility: flag = previousBodyInputs.pressSkill3; break; case SkillSlot.Special: flag = previousBodyInputs.pressSkill4; break; } bool flag2 = currentSkillMeetsActivationConditions; switch (buttonPressType) { case AISkillDriver.ButtonPressType.Abstain: flag2 = false; break; case AISkillDriver.ButtonPressType.TapContinuous: flag2 = flag2 && !flag; break; } switch (currentSkillSlot) { case SkillSlot.Primary: pressSkill = flag2; break; case SkillSlot.Secondary: pressSkill2 = flag2; break; case SkillSlot.Utility: pressSkill3 = flag2; break; case SkillSlot.Special: pressSkill4 = flag2; break; } } bodyInputs.pressSkill1 = pressSkill; bodyInputs.pressSkill2 = pressSkill2; bodyInputs.pressSkill3 = pressSkill3; bodyInputs.pressSkill4 = pressSkill4; bodyInputs.pressSprint = false; bodyInputs.pressActivateEquipment = false; bodyInputs.desiredAimDirection = UnityEngine.Vector3.zero; if ((bool)dominantSkillDriver) { bodyInputs.pressSprint = dominantSkillDriver.shouldSprint; bodyInputs.pressActivateEquipment = dominantSkillDriver.shouldFireEquipment && !previousBodyInputs.pressActivateEquipment; AISkillDriver.AimType aimType = dominantSkillDriver.aimType; BaseAI.Target aimTarget = base.ai.skillDriverEvaluation.aimTarget; if (aimType == AISkillDriver.AimType.MoveDirection) { AimInDirection(ref bodyInputs, bodyInputs.moveVector); } if (aimTarget != null) { AimAt(ref bodyInputs, aimTarget); } } ModifyInputsForJumpIfNeccessary(ref bodyInputs); return bodyInputs; } protected void UpdateBark() { activeSoundTimer -= GetDeltaTime(); if (activeSoundTimer <= 0f) { activeSoundTimer = UnityEngine.Random.Range(3f, 8f); base.body.CallRpcBark(); } } } public class LookBusy : BaseAIState { private const float minDuration = 2f; private const float maxDuration = 7f; private UnityEngine.Vector3 targetPosition; private float duration; private float lookTimer; private const float minLookDuration = 0.5f; private const float maxLookDuration = 4f; private const int lookTries = 4; private const float lookRaycastLength = 25f; protected virtual void PickNewTargetLookDirection() { if ((bool)base.bodyInputBank) { float num = 0f; UnityEngine.Vector3 aimOrigin = base.bodyInputBank.aimOrigin; for (int i = 0; i < 4; i++) { UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere; float num2 = 25f; if (Physics.Raycast(new Ray(aimOrigin, onUnitSphere), out var hitInfo, 25f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { num2 = hitInfo.distance; } if (num2 > num) { num = num2; bodyInputs.desiredAimDirection = onUnitSphere; } } } lookTimer = UnityEngine.Random.Range(0.5f, 4f); } public override void OnEnter() { base.OnEnter(); duration = UnityEngine.Random.Range(2f, 7f); base.bodyInputBank.moveVector = UnityEngine.Vector3.zero; base.bodyInputBank.jump.PushState(newState: false); PickNewTargetLookDirection(); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!base.ai || !base.body) { return; } if ((bool)base.ai.skillDriverEvaluation.dominantSkillDriver) { outer.SetNextState(new Combat()); } if (base.ai.hasAimConfirmation) { lookTimer -= GetDeltaTime(); if (lookTimer <= 0f) { PickNewTargetLookDirection(); } } if (base.fixedAge >= duration) { outer.SetNextState(new Wander()); } } public override BaseAI.BodyInputs GenerateBodyInputs(in BaseAI.BodyInputs previousBodyInputs) { return bodyInputs; } } public class Guard : LookBusy { public override void FixedUpdate() { base.FixedUpdate(); base.fixedAge = 0f; } protected override void PickNewTargetLookDirection() { } } public class Wander : BaseAIState { private UnityEngine.Vector3? targetPosition; private float lookTimer; private const float minLookDuration = 0.5f; private const float maxLookDuration = 4f; private const int lookTries = 1; private const float lookRaycastLength = 25f; private UnityEngine.Vector3 targetLookPosition; private float aiUpdateTimer; public override void Reset() { base.Reset(); targetPosition = UnityEngine.Vector3.zero; lookTimer = 0f; targetLookPosition = UnityEngine.Vector3.zero; } private void PickNewTargetLookPosition() { if ((bool)base.bodyInputBank) { float num = 0f; UnityEngine.Vector3 aimOrigin = base.bodyInputBank.aimOrigin; UnityEngine.Vector3 vector = base.bodyInputBank.moveVector; if (vector == UnityEngine.Vector3.zero) { vector = UnityEngine.Random.onUnitSphere; } for (int i = 0; i < 1; i++) { UnityEngine.Vector3 direction = Util.ApplySpread(vector, 0f, 60f, 0f, 0f); float num2 = 25f; Ray ray = new Ray(aimOrigin, direction); if (Physics.Raycast(ray, out var hitInfo, 25f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { num2 = hitInfo.distance; } if (num2 > num) { num = num2; targetLookPosition = ray.GetPoint(num2); } } } lookTimer = UnityEngine.Random.Range(0.5f, 4f); } public override void OnEnter() { base.OnEnter(); if ((bool)base.ai && (bool)base.body) { BroadNavigationSystem.Agent broadNavigationAgent = base.ai.broadNavigationAgent; targetPosition = PickRandomNearbyReachablePosition(); if (targetPosition.HasValue) { broadNavigationAgent.goalPosition = targetPosition.Value; broadNavigationAgent.InvalidatePath(); } PickNewTargetLookPosition(); aiUpdateTimer = 0.5f; } } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); aiUpdateTimer -= GetDeltaTime(); if (!base.ai || !base.body) { return; } if ((bool)base.ai.skillDriverEvaluation.dominantSkillDriver) { outer.SetNextState(new Combat()); } base.ai.SetGoalPosition(targetPosition); _ = base.bodyTransform.position; BroadNavigationSystem.Agent broadNavigationAgent = base.ai.broadNavigationAgent; if (aiUpdateTimer <= 0f) { aiUpdateTimer = BaseAIState.cvAIUpdateInterval.value; base.ai.localNavigator.targetPosition = broadNavigationAgent.output.nextPosition ?? base.ai.localNavigator.targetPosition; base.ai.localNavigator.Update(BaseAIState.cvAIUpdateInterval.value); if ((bool)base.bodyInputBank) { bodyInputs.moveVector = base.ai.localNavigator.moveVector * 0.25f; bodyInputs.desiredAimDirection = (targetLookPosition - base.bodyInputBank.aimOrigin).normalized; } lookTimer -= GetDeltaTime(); if (lookTimer <= 0f) { PickNewTargetLookPosition(); } bool flag = false; if (targetPosition.HasValue) { float sqrMagnitude = (base.body.footPosition - targetPosition.Value).sqrMagnitude; float num = base.body.radius * base.body.radius * 4f; flag = sqrMagnitude > num; } if (!flag) { outer.SetNextState(new LookBusy()); } } } public override BaseAI.BodyInputs GenerateBodyInputs(in BaseAI.BodyInputs previousBodyInputs) { ModifyInputsForJumpIfNeccessary(ref bodyInputs); return bodyInputs; } } } namespace EntityStates.AffixVoid { public class SelfDestruct : BaseState { [SerializeField] public float duration; [SerializeField] public string animationLayerName; [SerializeField] public string animationStateName; [SerializeField] public string enterSoundString; public override void OnEnter() { base.OnEnter(); PlayCrossfade(animationLayerName, animationStateName, duration); if ((bool)base.characterBody) { base.characterBody.isSprinting = false; } if ((bool)base.characterDirection) { base.characterDirection.moveVector = base.characterDirection.forward; } if ((bool)base.rigidbodyMotor) { base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero; } Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= duration) { EntityState.Destroy(base.gameObject); } } } } namespace EntityStates.AffixEarthHealer { public class Chargeup : BaseState { private static int chargeUpAnimationStateHash = Animator.StringToHash("ChargeUp"); private static int chargeUpParamHash = Animator.StringToHash("ChargeUp.playbackRate"); public static float duration; public static string enterSoundString; public override void OnEnter() { base.OnEnter(); FindModelChild("ChargeUpFX").gameObject.SetActive(value: true); PlayAnimation("Base", chargeUpAnimationStateHash, chargeUpParamHash, duration); Util.PlaySound(enterSoundString, base.gameObject); } public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > duration) { outer.SetNextState(new Heal()); } } public override void OnExit() { FindModelChild("ChargeUpFX").gameObject.SetActive(value: false); base.OnExit(); } } public class Heal : BaseState { public static float radius; public static float healCoefficient; public static float healOrbTravelDuration; public static GameObject effectPrefab; public override void OnEnter() { base.OnEnter(); float healValue = base.characterBody.damage * healCoefficient; if (!NetworkServer.active) { return; } List list = new List(); SphereSearch sphereSearch = new SphereSearch(); sphereSearch.radius = radius; sphereSearch.origin = base.transform.position; sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.Ignore; sphereSearch.mask = LayerIndex.entityPrecise.mask; sphereSearch.RefreshCandidates(); sphereSearch.FilterCandidatesByDistinctHurtBoxEntities(); HurtBox[] hurtBoxes = sphereSearch.GetHurtBoxes(); for (int i = 0; i < hurtBoxes.Length; i++) { HealthComponent item = hurtBoxes[i].healthComponent; if (!list.Contains(item)) { list.Add(item); } } foreach (HealthComponent item2 in list) { HealOrb healOrb = new HealOrb(); healOrb.origin = base.transform.position; healOrb.target = item2.body.mainHurtBox; healOrb.healValue = healValue; healOrb.overrideDuration = healOrbTravelDuration; OrbManager.instance.AddOrb(healOrb); } EffectManager.SimpleEffect(effectPrefab, base.transform.position, UnityEngine.Quaternion.identity, transmit: true); base.characterBody.healthComponent.Suicide(); } } public class DeathState : GenericCharacterDeath { public static GameObject initialExplosion; public static float duration; public static string enterSoundString; public override void OnEnter() { base.OnEnter(); if ((bool)initialExplosion) { EffectManager.SimpleEffect(initialExplosion, base.transform.position, base.transform.rotation, transmit: false); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge > duration) { EntityState.Destroy(base.gameObject); } } } } namespace EntityStates.AcidLarva { public class Death : GenericCharacterDeath { public static float deathDelay; public static GameObject deathEffectPrefab; private bool hasDied; public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > deathDelay && !hasDied) { hasDied = true; DestroyModel(); EffectManager.SimpleImpactEffect(deathEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: false); if (NetworkServer.active) { DestroyBodyAsapServer(); } } } public override void OnExit() { DestroyModel(); base.OnExit(); } } public class LarvaLeap : BaseCharacterMain { [SerializeField] public float minimumDuration; [SerializeField] public float blastRadius; [SerializeField] public float blastProcCoefficient; [SerializeField] public float blastDamageCoefficient; [SerializeField] public float blastForce; [SerializeField] public string leapSoundString; [SerializeField] public GameObject projectilePrefab; [SerializeField] public UnityEngine.Vector3 blastBonusForce; [SerializeField] public GameObject blastImpactEffectPrefab; [SerializeField] public GameObject blastEffectPrefab; [SerializeField] public float airControl; [SerializeField] public float aimVelocity; [SerializeField] public float upwardVelocity; [SerializeField] public float forwardVelocity; [SerializeField] public float minimumY; [SerializeField] public float minYVelocityForAnim; [SerializeField] public float maxYVelocityForAnim; [SerializeField] public float knockbackForce; [SerializeField] public float maxRadiusToConfirmDetonate; [SerializeField] public bool confirmDetonate; [SerializeField] public GameObject spinEffectPrefab; [SerializeField] public string spinEffectMuzzleString; [SerializeField] public string soundLoopStartEvent; [SerializeField] public string soundLoopStopEvent; [SerializeField] public NetworkSoundEventDef landingSound; [SerializeField] public float detonateSelfDamageFraction; private float previousAirControl; private GameObject spinEffectInstance; protected bool isCritAuthority; protected CrocoDamageTypeController crocoDamageTypeController; private bool detonateNextFrame; private static int EmptyStateHash = Animator.StringToHash("Empty"); protected virtual DamageTypeCombo GetBlastDamageType() { return DamageType.Generic; } public override void OnEnter() { base.OnEnter(); previousAirControl = base.characterMotor.airControl; base.characterMotor.airControl = airControl; UnityEngine.Vector3 direction = GetAimRay().direction; if (base.isAuthority) { base.characterBody.isSprinting = true; direction.y = Mathf.Max(direction.y, minimumY); UnityEngine.Vector3 vector = direction.normalized * aimVelocity * moveSpeedStat; UnityEngine.Vector3 vector2 = UnityEngine.Vector3.up * upwardVelocity; UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(direction.x, 0f, direction.z).normalized * forwardVelocity; base.characterMotor.Motor.ForceUnground(); base.characterMotor.velocity = vector + vector2 + vector3; isCritAuthority = RollCrit(); } PlayCrossfade("Gesture, Override", "LarvaLeap", 0.1f); Util.PlaySound(leapSoundString, base.gameObject); base.characterDirection.moveVector = direction; spinEffectInstance = UnityEngine.Object.Instantiate(spinEffectPrefab, FindModelChild(spinEffectMuzzleString)); if (base.isAuthority) { base.characterMotor.onMovementHit += OnMovementHit; } Util.PlaySound(soundLoopStartEvent, base.gameObject); } private void OnMovementHit(ref CharacterMotor.MovementHitInfo movementHitInfo) { detonateNextFrame = true; } protected override void UpdateAnimationParameters() { base.UpdateAnimationParameters(); } public override void FixedUpdate() { base.FixedUpdate(); if (!base.isAuthority || !base.characterMotor) { return; } base.characterMotor.moveDirection = base.inputBank.moveVector; base.characterDirection.moveVector = base.characterMotor.velocity; base.characterMotor.disableAirControlUntilCollision = base.characterMotor.velocity.y < 0f; if (base.fixedAge >= minimumDuration && (detonateNextFrame || (base.characterMotor.Motor.GroundingStatus.IsStableOnGround && !base.characterMotor.Motor.LastGroundingStatus.IsStableOnGround))) { bool flag = true; if (confirmDetonate) { BullseyeSearch bullseyeSearch = new BullseyeSearch(); bullseyeSearch.viewer = base.characterBody; bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral; bullseyeSearch.teamMaskFilter.RemoveTeam(base.characterBody.teamComponent.teamIndex); bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.minDistanceFilter = 0f; bullseyeSearch.maxDistanceFilter = maxRadiusToConfirmDetonate; bullseyeSearch.searchOrigin = base.inputBank.aimOrigin; bullseyeSearch.searchDirection = base.inputBank.aimDirection; bullseyeSearch.maxAngleFilter = 180f; bullseyeSearch.filterByLoS = false; bullseyeSearch.RefreshCandidates(); flag = bullseyeSearch.GetResults().FirstOrDefault(); } if (flag) { DoImpactAuthority(); } outer.SetNextStateToMain(); } } protected virtual void DoImpactAuthority() { DetonateAuthority(); if ((bool)landingSound) { EffectManager.SimpleSoundEffect(landingSound.index, base.characterBody.footPosition, transmit: true); } base.healthComponent.TakeDamage(new DamageInfo { damage = base.healthComponent.fullCombinedHealth * detonateSelfDamageFraction, attacker = base.characterBody.gameObject, position = base.characterBody.corePosition, damageType = DamageType.Generic }); } protected BlastAttack.Result DetonateAuthority() { UnityEngine.Vector3 footPosition = base.characterBody.footPosition; EffectManager.SpawnEffect(blastEffectPrefab, new EffectData { origin = footPosition, scale = blastRadius }, transmit: true); return new BlastAttack { attacker = base.gameObject, baseDamage = damageStat * blastDamageCoefficient, baseForce = blastForce, bonusForce = blastBonusForce, crit = isCritAuthority, damageType = GetBlastDamageType(), falloffModel = BlastAttack.FalloffModel.None, procCoefficient = blastProcCoefficient, radius = blastRadius, position = footPosition, attackerFiltering = AttackerFiltering.NeverHitSelf, impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab), teamIndex = base.teamComponent.teamIndex }.Fire(); } protected void FireProjectile() { UnityEngine.Vector3 footPosition = base.characterBody.footPosition; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.crit = isCritAuthority; fireProjectileInfo.force = 0f; fireProjectileInfo.damage = damageStat; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; fireProjectileInfo.position = footPosition; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } public override void OnExit() { Util.PlaySound(soundLoopStopEvent, base.gameObject); if (base.isAuthority) { base.characterMotor.onMovementHit -= OnMovementHit; } base.characterMotor.airControl = previousAirControl; base.characterBody.isSprinting = false; if ((bool)spinEffectInstance) { EntityState.Destroy(spinEffectInstance); } PlayAnimation("Gesture, Override", EmptyStateHash); base.OnExit(); } public override InterruptPriority GetMinimumInterruptPriority() { return InterruptPriority.PrioritySkill; } } public class SpawnState : GenericCharacterSpawnState { } } namespace EntityStates.LightningStorm { public class LightningStormState : BaseState { [SerializeField] public GameObject lightningInstancePrefab; public static int strikesPerSurvivor = 4; public static float minDistanceBetweenStrikes = 3f; public static float maxStrikeDistanceFromPlayer = 5f; public static float frequencyOfLightningStrikes = 8f; public static float timeBetweenIndividualStrikes = 0.2f; private List possibleNodesToTarget = new List(); private List possibleNodePositions = new List(); private float stormStopwatch; private float strikeStopwatch; private Queue positionsToStrike = new Queue(); private GameObject startPostProcessingObject; private PostProcessDuration startPostProcessDuration; private GameObject endPostProcessingObject; private PostProcessDuration endPostProcessDuration; private Action ExecuteNextStep; public override void OnEnter() { base.OnEnter(); LightningStormController component = GetComponent(); if ((bool)component) { startPostProcessingObject = component.startPostProcessingObject; startPostProcessDuration = component.startPostProcessDuration; endPostProcessingObject = component.endPostProcessingObject; endPostProcessDuration = component.endPostProcessDuration; } HandleStartStorm(); } public override void OnExit() { base.OnExit(); HandleStopStorm(); } private void HandleStartStorm() { ToggleStormVFX(b: true); ExecuteNextStep = GenerateTargetPositions; stormStopwatch = -1f; } private void ToggleStormVFX(bool b) { if ((bool)startPostProcessingObject) { startPostProcessingObject.SetActive(b); startPostProcessDuration.enabled = b; } if ((bool)endPostProcessingObject) { endPostProcessingObject.SetActive(!b); endPostProcessDuration.enabled = !b; } } private void GenerateTargetPositions() { if (stormStopwatch > 0f) { return; } positionsToStrike.Clear(); _ = minDistanceBetweenStrikes; _ = minDistanceBetweenStrikes; LightningStrikePattern lightningPattern = LightningStormController.lightningPattern; if (lightningPattern == null) { UnityEngine.Debug.LogWarning("No Lightning Storm pattern set up in the LightningStormController!"); return; } if (!SceneInfo.instance || !SceneInfo.instance.groundNodes) { UnityEngine.Debug.LogWarning("No ground nodes available, disabling lightning storm"); HandleStopStorm(); return; } NodeGraph groundNodes = SceneInfo.instance.groundNodes; possibleNodesToTarget.Clear(); float num = 0f; foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (!(instance == null) && !(instance.master == null) && instance.master.GetBody() != null) { num += 1f; } } num -= 1f; foreach (PlayerCharacterMasterController instance2 in PlayerCharacterMasterController.instances) { CharacterBody body = instance2.master.GetBody(); if (body == null || !body.hasAuthority) { continue; } Transform coreTransform = body.coreTransform; UnityEngine.Vector3 velocity = body.characterMotor.velocity; float magnitude = new UnityEngine.Vector3(velocity.x, 0f, velocity.z).magnitude; velocity = velocity.normalized; float num2 = magnitude; foreach (LightningStormController.LightningStrikePoint lightningStrikePoint in lightningPattern.lightningStrikePoints) { float maxDistance = LightningStormController.GetMaxDistance(velocity, magnitude, lightningStrikePoint); if (maxDistance > num2) { num2 = maxDistance; } } num2 = Mathf.Max(num2, lightningPattern.maxAcceptableDistanceFromPredictedPoint * 2f); possibleNodesToTarget = groundNodes.FindNodesInRange(coreTransform.position, 0f, num2, HullMask.Human); possibleNodePositions.Clear(); int count = possibleNodesToTarget.Count; for (int i = 0; i < count; i++) { if (groundNodes.GetNodePosition(possibleNodesToTarget[i], out var position2)) { possibleNodePositions.Add(position2); } } int count2 = lightningPattern.lightningStrikePoints.Count; count2 -= (int)(num * lightningPattern.forEachAdditionalPlayerReduceStrikeTotalBy); count2 = Mathf.Max(count2, 1); foreach (LightningStormController.LightningStrikePoint lightningStrikePoint2 in lightningPattern.lightningStrikePoints) { if (positionsToStrike.Count >= count2) { break; } UnityEngine.Vector3 position3 = LightningStormController.PredictPosition(coreTransform.position, coreTransform.forward, magnitude, lightningStrikePoint2); if (TryPickBestNodePosition(position3, lightningPattern.maxAcceptableDistanceFromPredictedPoint, out var bestPosition2)) { positionsToStrike.Enqueue(bestPosition2); } } } ExecuteNextStep = FireNextStrike; bool TryPickBestNodePosition(UnityEngine.Vector3 position, float range, out UnityEngine.Vector3 bestPosition) { int num3 = -1; range *= range; float num4 = float.MaxValue; bestPosition = UnityEngine.Vector3.zero; int count3 = possibleNodePositions.Count; UnityEngine.Vector2 vector = new UnityEngine.Vector2(position.x, position.z); for (int j = 0; j < count3; j++) { float sqrMagnitude = (new UnityEngine.Vector2(possibleNodePositions[j].x, possibleNodePositions[j].z) - vector).sqrMagnitude; if (sqrMagnitude <= range && sqrMagnitude < num4) { num3 = j; num4 = sqrMagnitude; } } if (num3 != -1) { bestPosition = possibleNodePositions[num3]; possibleNodePositions.RemoveAt(num3); return true; } return false; } } private void FireNextStrike() { if (positionsToStrike.Count < 1) { stormStopwatch = LightningStormController.lightningPattern.frequencyOfLightningStrikes; ExecuteNextStep = GenerateTargetPositions; } else if (!(strikeStopwatch > 0f)) { strikeStopwatch = LightningStormController.lightningPattern.timeBetweenIndividualStrikes; LightningStormController.FireLightningBolt(positionsToStrike.Dequeue(), lightningInstancePrefab); } } private void WaitForNextStrike() { if (stormStopwatch <= 0f) { ExecuteNextStep = GenerateTargetPositions; } } private void HandleStopStorm() { ToggleStormVFX(b: false); ExecuteNextStep = null; } public override void Update() { float deltaTime = Time.deltaTime; stormStopwatch -= deltaTime; strikeStopwatch -= deltaTime; ExecuteNextStep?.Invoke(); } private void LightningStrikeAtPosition(UnityEngine.Vector3 position) { GameObject gameObject = UnityEngine.Object.Instantiate(lightningInstancePrefab); LightningStrikeInstance component = gameObject.GetComponent(); if (!component) { UnityEngine.Debug.Log("GameObject doesn't have a lightninginstance component!", gameObject); } else { component.Initialize(position, null); } } } } namespace RoR2 { public class TriggerIntroMusicStart : MonoBehaviour { private void OnEnable() { MusicController.Instance.StartIntroMusic(); UnityEngine.Debug.Log("Triggered MusicController"); } } public class DevotionInventoryController : NetworkBehaviour { private static NetworkSoundEventDef activationSoundEventDef; public static GameObject s_effectPrefab; public SfxLocator sfxLocator; private static List InstanceList = new List(); private static List lowLevelEliteBuffs = new List(); private static List highLevelEliteBuffs = new List(); private bool _isRespawning; private CharacterMaster _summonerMaster; private Inventory _devotionMinionInventory; public CharacterMaster SummonerMaster { get { return _summonerMaster; } set { _summonerMaster = value; } } public static bool isDevotionEnable => RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Devotion); private Interactor _summonerInteractor => _summonerMaster.GetBody().GetComponent(); [SystemInitializer(new Type[] { typeof(ArtifactCatalog) })] private static void Init() { RunArtifactManager.onArtifactEnabledGlobal += OnDevotionArtifactEnabled; RunArtifactManager.onArtifactDisabledGlobal += OnDevotionArtifactDisabled; LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseNullifiedBuffApplied", delegate(NetworkSoundEventDef asset) { activationSoundEventDef = asset; }); } private static void OnDevotionArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef) { if (!(artifactDef != CU8Content.Artifacts.Devotion)) { lowLevelEliteBuffs.Add(RoR2Content.Equipment.AffixRed.equipmentIndex); lowLevelEliteBuffs.Add(RoR2Content.Equipment.AffixWhite.equipmentIndex); lowLevelEliteBuffs.Add(RoR2Content.Equipment.AffixBlue.equipmentIndex); highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixRed.equipmentIndex); highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixWhite.equipmentIndex); highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixBlue.equipmentIndex); highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixPoison.equipmentIndex); highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixLunar.equipmentIndex); highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixHaunted.equipmentIndex); if (DLC1Content.Elites.Earth.IsAvailable()) { lowLevelEliteBuffs.Add(DLC1Content.Elites.Earth.eliteEquipmentDef.equipmentIndex); highLevelEliteBuffs.Add(DLC1Content.Elites.Earth.eliteEquipmentDef.equipmentIndex); } Run.onRunDestroyGlobal += OnRunDestroy; s_effectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/OrbEffects/ItemTakenOrbEffect"); BossGroup.onBossGroupDefeatedServer += OnBossGroupDefeatedServer; } } private static void OnDevotionArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef) { if (!(artifactDef != CU8Content.Artifacts.Devotion)) { lowLevelEliteBuffs.Clear(); highLevelEliteBuffs.Clear(); Run.onRunDestroyGlobal -= OnRunDestroy; s_effectPrefab = null; BossGroup.onBossGroupDefeatedServer -= OnBossGroupDefeatedServer; } } private static void OnRunDestroy(Run run) { for (int i = 0; i < InstanceList.Count; i++) { UnityEngine.Object.Destroy(InstanceList[i].gameObject); } InstanceList.Clear(); } public static void StartRespawnAllLemurians() { foreach (DevotionInventoryController instance in InstanceList) { if (!instance._isRespawning) { instance.StartCoroutine(instance.TryRespawnLemurians()); } } } public static DevotionInventoryController GetOrCreateDevotionInventoryController(Interactor summoner) { DevotionInventoryController devotionInventoryController = null; foreach (DevotionInventoryController instance in InstanceList) { if (instance._summonerInteractor == summoner) { devotionInventoryController = instance; break; } } if (!devotionInventoryController) { GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/DevotionMinionInventory")); devotionInventoryController = obj.GetComponent(); devotionInventoryController.GetComponent().teamIndex = TeamIndex.Player; devotionInventoryController._summonerMaster = summoner.GetComponent().master; NetworkServer.Spawn(obj); } return devotionInventoryController; } [Server] public static void ActivateAllDevotedEvolution() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::ActivateAllDevotedEvolution()' called on client"); return; } foreach (DevotionInventoryController instance in InstanceList) { instance.UpdateAllMinions(shouldEvolve: true); } } [Server] public void ActivateDevotedEvolution() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::ActivateDevotedEvolution()' called on client"); } else { UpdateAllMinions(shouldEvolve: true); } } [Server] public void UpdateAllMinions(bool shouldEvolve = false) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::UpdateAllMinions(System.Boolean)' called on client"); } else { if (!_summonerMaster) { return; } MinionOwnership.MinionGroup minionGroup = MinionOwnership.MinionGroup.FindGroup(_summonerMaster.netId); if (minionGroup == null) { return; } MinionOwnership[] members = minionGroup.members; foreach (MinionOwnership minionOwnership in members) { if ((bool)minionOwnership && minionOwnership.GetComponent().TryGetComponent(out var component)) { UpdateMinionInventory(component, shouldEvolve); } } } } public override int GetNetworkChannel() { return QosChannelIndex.defaultReliable.intVal; } public void GiveItem(ItemIndex itemIndex, int count = 1) { _devotionMinionInventory.GiveItem(itemIndex, count); } public void RemoveItem(ItemIndex itedmIndex, int count = 1) { _devotionMinionInventory.RemoveItem(itedmIndex, count); } public bool HasItem(ItemDef item) { return _devotionMinionInventory.GetItemCount(item) > 0; } public void DropScrapOnDeath(ItemIndex devotionItem, CharacterBody minionBody) { PickupIndex pickupIndex = PickupIndex.none; ItemDef itemDef = ItemCatalog.GetItemDef(devotionItem); if (itemDef != null) { switch (itemDef.tier) { case ItemTier.Tier1: pickupIndex = PickupCatalog.FindPickupIndex("ItemIndex.ScrapWhite"); break; case ItemTier.Tier2: pickupIndex = PickupCatalog.FindPickupIndex("ItemIndex.ScrapGreen"); break; case ItemTier.Tier3: pickupIndex = PickupCatalog.FindPickupIndex("ItemIndex.ScrapRed"); break; case ItemTier.Boss: pickupIndex = PickupCatalog.FindPickupIndex("ItemIndex.ScrapYellow"); break; } } if (pickupIndex != PickupIndex.none) { PickupDropletController.CreatePickupDroplet(pickupIndex, minionBody.corePosition, UnityEngine.Vector3.down * 15f); } } [Server] private void UpdateMinionInventory(DevotedLemurianController devotedLemurianController, bool shouldEvolve) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::UpdateMinionInventory(DevotedLemurianController,System.Boolean)' called on client"); return; } CharacterBody lemurianBody = devotedLemurianController.LemurianBody; Inventory lemurianInventory = devotedLemurianController.LemurianInventory; lemurianInventory.CleanInventory(); if (shouldEvolve) { if ((bool)activationSoundEventDef) { UnityEngine.Debug.Log("playing sound effect"); EffectManager.SimpleSoundEffect(activationSoundEventDef.index, lemurianBody.gameObject.transform.position, transmit: true); } devotedLemurianController.DevotedEvolutionLevel++; _devotionMinionInventory.GiveItem(devotedLemurianController.DevotionItem); EvolveDevotedLumerian(devotedLemurianController); } int num = 0; num = ((devotedLemurianController.DevotedEvolutionLevel != 0 && devotedLemurianController.DevotedEvolutionLevel != 2) ? ((devotedLemurianController.DevotedEvolutionLevel != 1 && devotedLemurianController.DevotedEvolutionLevel != 3) ? (20 + devotedLemurianController.DevotedEvolutionLevel - 3) : 20) : 10); lemurianInventory.GiveItem(RoR2Content.Items.BoostHp, num); lemurianInventory.GiveItem(RoR2Content.Items.BoostDamage, num); lemurianInventory.AddItemsFrom(_devotionMinionInventory); } [Server] private void EvolveDevotedLumerian(DevotedLemurianController devotedLemurianController) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::EvolveDevotedLumerian(DevotedLemurianController)' called on client"); return; } CharacterBody lemurianBody = devotedLemurianController.LemurianBody; switch (devotedLemurianController.DevotedEvolutionLevel) { case 1: GenerateEliteBuff(lemurianBody, devotedLemurianController, isLowLevel: true); break; case 2: lemurianBody.inventory.SetEquipmentIndex(EquipmentIndex.None); lemurianBody.master.TransformBody("DevotedLemurianBruiserBody"); break; case 3: GenerateEliteBuff(lemurianBody, devotedLemurianController, isLowLevel: false); break; default: UnityEngine.Debug.LogError("shouldn't evolve!"); break; } } [Server] private void GenerateEliteBuff(CharacterBody body, DevotedLemurianController devotedCntroller, bool isLowLevel) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::GenerateEliteBuff(RoR2.CharacterBody,DevotedLemurianController,System.Boolean)' called on client"); return; } List list = (isLowLevel ? lowLevelEliteBuffs : highLevelEliteBuffs); int index = UnityEngine.Random.Range(0, list.Count); body.inventory.SetEquipmentIndex(list[index]); } private void Awake() { _devotionMinionInventory = base.gameObject.GetComponent(); _devotionMinionInventory.GiveItem(CU8Content.Items.LemurianHarness); } public static void OnBossGroupDefeatedServer(BossGroup group) { UnityEngine.Debug.Log("on boss group defeated server in devotion"); if (!SceneCatalog.GetSceneDefForCurrentScene().needSkipDevotionRespawn) { ActivateAllDevotedEvolution(); } } private void OnEnable() { InstanceList.Add(this); } private void OnDisable() { InstanceList.Remove(this); } private IEnumerator TryRespawnLemurians() { _isRespawning = true; while (!_summonerMaster.GetBody()) { yield return new WaitForSeconds(1f); } NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); List list = nodeGraph.FindNodesInRangeWithFlagConditions(_summonerInteractor.transform.position, 3f, 40f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false); while (list.Count == 0) { yield return new WaitForSeconds(1f); list = nodeGraph.FindNodesInRangeWithFlagConditions(_summonerInteractor.transform.position, 3f, 40f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false); } while (list.Count > 0) { int index = UnityEngine.Random.Range(0, list.Count); NodeGraph.NodeIndex nodeIndex = list[index]; if (!nodeGraph.GetNodePosition(nodeIndex, out var position)) { continue; } MinionOwnership.MinionGroup minionGroup = MinionOwnership.MinionGroup.FindGroup(_summonerMaster.netId); if (minionGroup == null) { break; } MinionOwnership[] members = minionGroup.members; foreach (MinionOwnership minionOwnership in members) { if ((bool)minionOwnership) { CharacterMaster component = minionOwnership.GetComponent(); if (component.TryGetComponent(out var _)) { component.Respawn(position, UnityEngine.Quaternion.identity); } } } break; } _isRespawning = false; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public static class BenchmarkCommandProcessor { private static string targetScene; [ConCommand(commandName = "benchmark", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "Load first argument as scene, disables baddies, and spawns test prefab for baddies.")] public static void CCBenchmark(ConCommandArgs args) { } } public class RoRGraphyControl { private static RoRGraphyControl instance; private bool specsActive; private bool fpsActive; [ConCommand(commandName = "graphy_specs", flags = ConVarFlags.None, helpText = "Graphy testing.")] public static void graphySpecs(ConCommandArgs args) { if (instance.specsActive) { G_Singleton.Instance.SetModuleMode(GraphyManager.ModuleType.ADVANCED, GraphyManager.ModuleState.OFF); instance.specsActive = false; } else { G_Singleton.Instance.SetModuleMode(GraphyManager.ModuleType.ADVANCED, GraphyManager.ModuleState.FULL); instance.specsActive = true; } G_Singleton.Instance.SetModuleMode(GraphyManager.ModuleType.AUDIO, GraphyManager.ModuleState.OFF); } [ConCommand(commandName = "graphy_init", flags = ConVarFlags.None, helpText = "Graphy testing.")] public static void verifyInst(ConCommandArgs args) { if (instance == null) { instance = new RoRGraphyControl(); UnityEngine.Object.DontDestroyOnLoad(UnityEngine.Object.Instantiate(Resources.Load("ror2Graphy") as GameObject)); instance.specsActive = false; instance.fpsActive = false; } } [ConCommand(commandName = "graphy_fps", flags = ConVarFlags.None, helpText = "Graphy testing.")] public static void graphyFPS(ConCommandArgs args) { if (instance.fpsActive) { G_Singleton.Instance.SetModuleMode(GraphyManager.ModuleType.FPS, GraphyManager.ModuleState.OFF); G_Singleton.Instance.SetModuleMode(GraphyManager.ModuleType.RAM, GraphyManager.ModuleState.OFF); instance.fpsActive = false; } else { G_Singleton.Instance.SetModuleMode(GraphyManager.ModuleType.FPS, GraphyManager.ModuleState.FULL); G_Singleton.Instance.SetModuleMode(GraphyManager.ModuleType.RAM, GraphyManager.ModuleState.FULL); instance.fpsActive = true; } G_Singleton.Instance.SetModuleMode(GraphyManager.ModuleType.AUDIO, GraphyManager.ModuleState.OFF); } } public class SoulSpiralGhost : MonoBehaviour { [Tooltip("Triggered at beginning, to make sure the ghost is cleaned up.")] [SerializeField] private UnityEvent OnEnableAction; [SerializeField] [Tooltip("Triggered when the orbs are 'boosted'.")] private UnityEvent OnOrbBoost; [SerializeField] [Tooltip("Triggered when the orbs' boost ends.")] private UnityEvent OnOrbBoostEnd; [Tooltip("Triggered when a given orb has only one hit left.")] [SerializeField] private UnityEvent OnOrbLastHit; public void OnEnable() { OnEnableAction?.Invoke(); } public void Boost() { OnOrbBoost?.Invoke(); } public void EndBoost() { OnOrbBoostEnd?.Invoke(); } public void OnLastHit() { OnOrbLastHit?.Invoke(); } } public class SproutOfLifeHealOrbSpawn : NetworkBehaviour { private float seedOfLifeOrbsLeft = 10f; private float seedOfLifeOrbsTimer; private void Start() { Util.PlaySound("Play_item_use_healAndRevive_healPlantGrow", base.gameObject); } private void FixedUpdate() { if (seedOfLifeOrbsLeft > 0f) { seedOfLifeOrbsTimer -= Time.fixedDeltaTime; if (seedOfLifeOrbsTimer <= 0f && NetworkServer.active) { SproutSpawnHealOrb(); } } else { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/SproutOfLifeBurst"), new EffectData { origin = base.gameObject.transform.position }, transmit: true); UnityEngine.Object.Destroy(base.gameObject); } } [Server] private void SproutSpawnHealOrb() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SproutOfLifeHealOrbSpawn::SproutSpawnHealOrb()' called on client"); return; } seedOfLifeOrbsTimer += 0.5f; float num = Mathf.Pow(4f, 0.25f); GameObject original = LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/HealPack"); UnityEngine.Vector3 vector = default(UnityEngine.Vector3); vector = base.transform.position + new UnityEngine.Vector3(UnityEngine.Random.Range(-1.5f, 1.5f), 0f, UnityEngine.Random.Range(-1.5f, 1.5f)); GameObject obj = UnityEngine.Object.Instantiate(original, vector, UnityEngine.Random.rotation); TeamIndex teamIndex = TeamIndex.Player; TeamFilter component = obj.GetComponent(); if ((bool)component) { component.teamIndex = teamIndex; } HealthPickup componentInChildren = obj.GetComponentInChildren(); if ((bool)componentInChildren) { componentInChildren.flatHealing = 0f; componentInChildren.fractionalHealing = 0.02f; } obj.transform.localScale = new UnityEngine.Vector3(num, num, num); NetworkServer.Spawn(obj); Util.PlaySound("Play_item_use_healAndRevive_healOrb_gather", base.gameObject); seedOfLifeOrbsLeft -= 1f; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class GoldSiphonNearbyBodyController : NetworkBehaviour { protected class TetheredPlayers { public GameObject tetheredPlayer; public bool isTethered; } public GameObject shrineGameObject; private TeamComponent parentTeamComponent; public TetherVfxOrigin tetherVfxOrigin; public bool automaticallyScaleCostWithDifficulty = true; private uint appliedDrain; protected SphereSearch sphereSearch; protected float timer; protected new Transform transform; private bool isTetheredToAtLeastOneObject; private int tetheredPlayers; private HalcyoniteShrineInteractable parentShrineReference; protected PurchaseInteraction purchaseInteraction; private int goldDrainValue = 1; private EntityStateMachine stateMachine; public SerializableEntityStateType lowQualityState = new SerializableEntityStateType(typeof(ShrineHalcyoniteLowQuality)); public SerializableEntityStateType midQualityState = new SerializableEntityStateType(typeof(ShrineHalcyoniteMidQuality)); public SerializableEntityStateType maxQualityState = new SerializableEntityStateType(typeof(ShrineHalcyoniteMaxQuality)); private int shrineLowGoldCost = 75; private int shrineMidGoldCost = 150; private int shrineMaxGoldCost = 300; private float tickRate = 5f; private int maxTargets = 4; private List tetheredGameObjects; private bool isReady; private int tierTracker; public static event Action onHalcyonShrineGoldDrain; protected void Awake() { parentShrineReference = GetComponentInParent(); shrineLowGoldCost = parentShrineReference.lowGoldCost; shrineMidGoldCost = parentShrineReference.midGoldCost; shrineMaxGoldCost = parentShrineReference.maxGoldCost; tickRate = parentShrineReference.tickRate; maxTargets = parentShrineReference.maxTargets; goldDrainValue = parentShrineReference.goldDrainValue; purchaseInteraction = GetComponentInParent(); appliedDrain = (uint)(goldDrainValue * -1); stateMachine = GetComponentInParent(); sphereSearch = new SphereSearch(); transform = base.transform; } protected void FixedUpdate() { if (parentShrineReference.interactions > 1) { timer -= Time.fixedDeltaTime; if (timer <= 0f) { timer += 1f / tickRate; DrainGold(); } } } protected void DrainGold() { if (sphereSearch == null || parentShrineReference == null || stateMachine == null || this.transform == null || purchaseInteraction == null) { return; } if (!isReady) { isReady = true; GrabPlayerReferences(); } List list = CollectionPool>.RentCollection(); SearchForPlayers(list); List list2 = CollectionPool>.RentCollection(); for (int i = 0; i < list.Count; i++) { HurtBox hurtBox = list[i]; bool isPlayerControlled = hurtBox.healthComponent.body.isPlayerControlled; if ((bool)hurtBox && (bool)hurtBox.healthComponent && hurtBox.healthComponent.alive && hurtBox.healthComponent.body.master.money > goldDrainValue && isPlayerControlled) { Transform transform = hurtBox.healthComponent.body?.coreTransform ?? hurtBox.transform; list2.Add(transform); for (int j = 0; j < tetheredGameObjects.Count; j++) { if (tetheredGameObjects[j].tetheredPlayer != null && transform.gameObject == tetheredGameObjects[j].tetheredPlayer) { tetheredGameObjects[j].tetheredPlayer = transform.gameObject; tetheredGameObjects[j].isTethered = true; } } if (NetworkServer.active) { appliedDrain = (uint)parentShrineReference.goldDrainValue; CharacterMaster master = hurtBox.healthComponent.body.master; _ = master.money; master.money = (uint)Mathf.Max(0f, (float)master.money - (float)appliedDrain); _ = master.money; EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/CoinImpact"), transform.position, UnityEngine.Vector3.up, transmit: true); Util.PlaySound("Play_obj_shrineHalcyonite_goldSiphon", transform.gameObject); parentShrineReference.StoreDrainValue(parentShrineReference.goldDrainValue); GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain(); if (parentShrineReference.goldDrained < parentShrineReference.lowGoldCost && tierTracker == 0) { tierTracker++; purchaseInteraction.SetAvailable(newAvailable: false); } if (parentShrineReference.goldDrained > parentShrineReference.lowGoldCost && parentShrineReference.goldDrained < parentShrineReference.midGoldCost && tierTracker == 1) { tierTracker++; purchaseInteraction.SetAvailable(newAvailable: true); stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref lowQualityState)); } if (parentShrineReference.goldDrained > parentShrineReference.midGoldCost && parentShrineReference.goldDrained < parentShrineReference.maxGoldCost && tierTracker == 2) { tierTracker++; stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref midQualityState)); } if (parentShrineReference.goldDrained >= parentShrineReference.maxGoldCost && tierTracker == 3) { tierTracker++; stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref maxQualityState)); } } } if (list2.Count >= maxTargets) { break; } } isTetheredToAtLeastOneObject = (float)list2.Count > 0f; if ((bool)tetherVfxOrigin) { tetherVfxOrigin.SetTetheredTransforms(list2); } for (int k = 0; k < tetheredGameObjects.Count; k++) { int num = 0; for (int l = 0; l < list2.Count; l++) { if (tetheredGameObjects[k].tetheredPlayer != list2[l]) { num++; } } if (num == list2.Count) { tetheredGameObjects[k].isTethered = false; } } if (isTetheredToAtLeastOneObject) { parentShrineReference.IsDraining(drainingActive: true); } else { parentShrineReference.IsDraining(drainingActive: false); } CollectionPool>.ReturnCollection(list2); CollectionPool>.ReturnCollection(list); } protected void SearchForPlayers(List dest) { TeamMask mask = default(TeamMask); mask.AddTeam(TeamIndex.Player); sphereSearch.mask = LayerIndex.entityPrecise.mask; sphereSearch.origin = base.gameObject.transform.position; sphereSearch.radius = parentShrineReference.radius; sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal; sphereSearch.RefreshCandidates(); sphereSearch.FilterCandidatesByHurtBoxTeam(mask); sphereSearch.OrderCandidatesByDistance(); sphereSearch.FilterCandidatesByDistinctHurtBoxEntities(); sphereSearch.GetHurtBoxes(dest); sphereSearch.ClearCandidates(); } private void GrabPlayerReferences() { tetheredGameObjects = CollectionPool>.RentCollection(); for (int i = 0; i < PlayerCharacterMasterController.instances.Count; i++) { PlayerCharacterMasterController playerCharacterMasterController = PlayerCharacterMasterController.instances[i]; if ((bool)playerCharacterMasterController) { CharacterBody body = playerCharacterMasterController.master.GetBody(); if ((bool)body) { TetheredPlayers tetheredPlayers = new TetheredPlayers(); tetheredPlayers.tetheredPlayer = body.gameObject; tetheredGameObjects.Add(tetheredPlayers); } } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class HalcyoniteShrineInteractable : NetworkBehaviour { [Header("Shrine Core Variables")] public bool HalcyoniteShrineActive = true; [Tooltip("Flat max gold cost for accessing top quality. *Note, without difficulty cost scaling.")] public int maxGoldCost = 300; [Tooltip("Flat mid gold cost for accessing top quality. *Note, without difficulty cost scaling.")] public int midGoldCost = 150; [Tooltip("Minimum amount of gold required to activate boss fight and end drain. *Note, without difficulty cost scaling.")] public int lowGoldCost = 75; [Tooltip("True if shrine gold mechanic should increase with difficulty. False if it should not.")] [SerializeField] private bool automaticallyScaleCostWithDifficulty = true; [SerializeField] private GameObject shrineCollisionObject; [Tooltip("Detection radius for picking up the players within range of the Halcyonite Shrine.")] [Header("Draining Gold Variables")] public float radius = 30f; [Tooltip("Amount drained per tick.")] public int goldDrainValue = 1; [Tooltip("Total amount of gold stored in Shrine.")] public int goldDrained; [UnityEngine.Min(float.Epsilon)] [Tooltip("How many ticks per second.")] public float tickRate = 5f; [SyncVar] [Tooltip("Maximum amount of player targets allowed.")] public int maxTargets = 4; [Tooltip("Game Object for the network game object responsible for draining the player's gold.")] public GameObject siphonObject; [SyncVar] [HideInInspector] public int interactions; [SerializeField] [Tooltip("Renderer reference for when changing target renderers for the highlight script.")] private Renderer shrineRenderer; [SyncVar] public bool isDraining; [SerializeField] [Tooltip("Reference to the crystal object for changing its materials.")] [Header("Gauge Mechanic")] public GameObject crystalObject; [SerializeField] [SyncVar] public GameObject shrineGoldBottom; [SyncVar] [SerializeField] public GameObject shrineGoldMid; [SerializeField] [SyncVar] public GameObject shrineGoldTop; [SerializeField] public Material goldMaterialController; [Tooltip("Color of VFX and Crystal once the encounter is finished and reward has been dispersed.")] [SerializeField] public GameObject shrineBaseObject; [Tooltip("Halcyonite Shrine bubble Game Object reference.")] [SerializeField] public GameObject shrineHalcyoniteBubble; [Tooltip("Entity State Machine reference for handling changes to gauge mechanics for the network.")] [SerializeField] public EntityStateMachine stateMachine; public SerializableEntityStateType noQualityState = new SerializableEntityStateType(typeof(ShrineHalcyoniteNoQuality)); public SerializableEntityStateType finishedState = new SerializableEntityStateType(typeof(ShrineHalcyoniteFinished)); public SfxLocator sfxLocator; [SerializeField] private PurchaseInteraction purchaseInteraction; [SerializeField] [Header("Shrine Encounter and Rewards")] private DirectorCard chosenDirectCard; [SerializeField] [Tooltip("Drop table dictating what rewards are available at minimum gold value.")] private BasicPickupDropTable halcyoniteDropTableTier1; [SerializeField] [Tooltip("Drop table dictating what rewards are available at middling gold value.")] private BasicPickupDropTable halcyoniteDropTableTier2; [SerializeField] [Tooltip("Drop table dictating what rewards are available at maximum gold value.")] private BasicPickupDropTable halcyoniteDropTableTier3; [Tooltip("Use this tier to get a pickup index for the reward. The droplet's visuals will correspond to this.")] [SerializeField] private ItemTier rewardDisplayTier; [SerializeField] [Tooltip("The number of options to display when the player interacts with the reward pickup.")] private int rewardOptionCount; [SerializeField] [Tooltip("The prefab to use for the reward pickup.")] private GameObject rewardPickupPrefab; [SerializeField] [Tooltip("Where to spawn the reward droplets relative to the spawn target (the center of the safe ward).")] private UnityEngine.Vector3 rewardOffset; [SerializeField] [Header("Colossus Portal")] public ChildLocator modelChildLocator; public PortalSpawner[] portalSpawners; [Tooltip("Combat Director managing the monster wave that spawns on Halcyon Shrine's gold drain behavior activation.")] public CombatDirector activationDirector; [Tooltip("Monster credits given to combat director to determine how many monsters to spawn.")] public float monsterCredit; [SerializeField] private bool scaleMonsterCreditWithDifficultyCoefficient = true; [SerializeField] private CombatDirector combatDirector; private int quantityIncreaseFromBuyIn = 1; private BasicPickupDropTable rewardDropTable; private Xoroshiro128Plus rng; [SyncVar] public float goldMaterialModifier = -2.2f; [SyncVar] private bool visualsDone; private NetworkInstanceId ___shrineGoldBottomNetId; private NetworkInstanceId ___shrineGoldMidNetId; private NetworkInstanceId ___shrineGoldTopNetId; public static bool isCommandEnabled => RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.Command); public int NetworkmaxTargets { get { return maxTargets; } [param: In] set { SetSyncVar(value, ref maxTargets, 1u); } } public int Networkinteractions { get { return interactions; } [param: In] set { SetSyncVar(value, ref interactions, 2u); } } public bool NetworkisDraining { get { return isDraining; } [param: In] set { SetSyncVar(value, ref isDraining, 4u); } } public GameObject NetworkshrineGoldBottom { get { return shrineGoldBottom; } [param: In] set { SetSyncVarGameObject(value, ref shrineGoldBottom, 8u, ref ___shrineGoldBottomNetId); } } public GameObject NetworkshrineGoldMid { get { return shrineGoldMid; } [param: In] set { SetSyncVarGameObject(value, ref shrineGoldMid, 16u, ref ___shrineGoldMidNetId); } } public GameObject NetworkshrineGoldTop { get { return shrineGoldTop; } [param: In] set { SetSyncVarGameObject(value, ref shrineGoldTop, 32u, ref ___shrineGoldTopNetId); } } public float NetworkgoldMaterialModifier { get { return goldMaterialModifier; } [param: In] set { SetSyncVar(value, ref goldMaterialModifier, 64u); } } public bool NetworkvisualsDone { get { return visualsDone; } [param: In] set { SetSyncVar(value, ref visualsDone, 128u); } } protected void Awake() { if (NetworkServer.active) { if (automaticallyScaleCostWithDifficulty) { lowGoldCost = Run.instance.GetDifficultyScaledCost(lowGoldCost); midGoldCost = Run.instance.GetDifficultyScaledCost(midGoldCost); maxGoldCost = Run.instance.GetDifficultyScaledCost(maxGoldCost); goldDrainValue = Run.instance.GetDifficultyScaledCost(goldDrainValue); } CalculateCredits(); HalcyoniteShrineActive = true; goldMaterialController.EnableKeyword("_SLICEHEIGHT"); combatDirector = GetComponent(); } } private void Start() { HalcyoniteShrineActive = true; shrineCollisionObject.layer = LayerIndex.world.intVal; } private void CalculateCredits() { if (scaleMonsterCreditWithDifficultyCoefficient) { monsterCredit = Mathf.CeilToInt(monsterCredit * Run.instance.difficultyCoefficient); } } [Server] public void TrackInteractions() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HalcyoniteShrineInteractable::TrackInteractions()' called on client"); return; } if (interactions == 0) { GetComponent().targetRenderer = shrineRenderer; stateMachine.SetNextStateToMain(); } Networkinteractions = interactions + 1; if (interactions >= 3) { stateMachine.SetNextState(new ShrineHalcyoniteMaxQuality()); } } [Server] public void IsDraining(bool drainingActive) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HalcyoniteShrineInteractable::IsDraining(System.Boolean)' called on client"); } else { NetworkisDraining = drainingActive; } } public void DestroyDrainVFX() { if ((bool)siphonObject) { NetworkServer.Destroy(siphonObject); } if ((bool)shrineHalcyoniteBubble && shrineHalcyoniteBubble.activeInHierarchy) { shrineHalcyoniteBubble.SetActive(value: false); } IsDraining(drainingActive: false); } public void DrainConditionMet() { DestroyDrainVFX(); if ((bool)purchaseInteraction && purchaseInteraction.available) { purchaseInteraction.SetAvailable(newAvailable: false); } if (goldDrained > lowGoldCost && goldDrained < midGoldCost) { quantityIncreaseFromBuyIn = 1; rewardDropTable = halcyoniteDropTableTier1; rewardOptionCount = 3; rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); } if (goldDrained > midGoldCost && goldDrained < maxGoldCost) { quantityIncreaseFromBuyIn = 1; rewardDropTable = halcyoniteDropTableTier2; rewardOptionCount = 4; rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); } if (goldDrained >= maxGoldCost) { quantityIncreaseFromBuyIn = 1; rewardDropTable = halcyoniteDropTableTier3; rewardOptionCount = 5; rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); } Transform transform = modelChildLocator.FindChild("ModelBase"); if (transform != null) { UnityEngine.Vector3 origin = transform.position + new UnityEngine.Vector3(0f, 16f, 0f); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/HalcyonShrineTierReachVFX"), new EffectData { origin = origin }, transmit: false); } int difficultyLevel = (int)((float)goldDrained / 100f); combatDirector.HalcyoniteShrineActivation(chosenDirectCard.cost, chosenDirectCard, difficultyLevel, base.gameObject.transform); } public void StoreDrainValue(int value) { goldDrained += value; } [Server] public void AttemptSpawnPortal() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HalcyoniteShrineInteractable::AttemptSpawnPortal()' called on client"); return; } PortalSpawner[] array = portalSpawners; for (int i = 0; i < array.Length; i++) { array[i].AttemptSpawnPortalServer(); } } [Server] public void DropRewards() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HalcyoniteShrineInteractable::DropRewards()' called on client"); return; } stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref finishedState)); int participatingPlayerCount = Run.instance.participatingPlayerCount; if (participatingPlayerCount <= 0 || !base.gameObject || !rewardDropTable) { return; } int num = participatingPlayerCount * quantityIncreaseFromBuyIn; float angle = 360f / (float)num; UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); UnityEngine.Vector3 position = base.gameObject.transform.position + rewardOffset; int num2 = 0; while (num2 < num) { if (isCommandEnabled) { int num3 = rewardOptionCount - 2; for (int i = 0; i < num3; i++) { PickupIndex pickupIndex = rewardDropTable.GenerateDrop(rng); GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo); createPickupInfo.pickupIndex = pickupIndex; createPickupInfo.rotation = UnityEngine.Quaternion.identity; createPickupInfo.position = position; GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo; PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, vector); } } else { GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo); createPickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier); createPickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTablePlusForcedStorm(rewardOptionCount, halcyoniteDropTableTier3, halcyoniteDropTableTier2, rng); createPickupInfo.rotation = UnityEngine.Quaternion.identity; createPickupInfo.prefabOverride = rewardPickupPrefab; GenericPickupController.CreatePickupInfo pickupInfo2 = createPickupInfo; pickupInfo2.position = position; PickupDropletController.CreatePickupDroplet(pickupInfo2, position, vector); } num2++; vector = quaternion * vector; } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt32((uint)maxTargets); writer.WritePackedUInt32((uint)interactions); writer.Write(isDraining); writer.Write(shrineGoldBottom); writer.Write(shrineGoldMid); writer.Write(shrineGoldTop); writer.Write(goldMaterialModifier); writer.Write(visualsDone); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)maxTargets); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)interactions); } if ((base.syncVarDirtyBits & 4u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(isDraining); } if ((base.syncVarDirtyBits & 8u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(shrineGoldBottom); } if ((base.syncVarDirtyBits & 0x10u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(shrineGoldMid); } if ((base.syncVarDirtyBits & 0x20u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(shrineGoldTop); } if ((base.syncVarDirtyBits & 0x40u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(goldMaterialModifier); } if ((base.syncVarDirtyBits & 0x80u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(visualsDone); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { maxTargets = (int)reader.ReadPackedUInt32(); interactions = (int)reader.ReadPackedUInt32(); isDraining = reader.ReadBoolean(); ___shrineGoldBottomNetId = reader.ReadNetworkId(); ___shrineGoldMidNetId = reader.ReadNetworkId(); ___shrineGoldTopNetId = reader.ReadNetworkId(); goldMaterialModifier = reader.ReadSingle(); visualsDone = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { maxTargets = (int)reader.ReadPackedUInt32(); } if (((uint)num & 2u) != 0) { interactions = (int)reader.ReadPackedUInt32(); } if (((uint)num & 4u) != 0) { isDraining = reader.ReadBoolean(); } if (((uint)num & 8u) != 0) { shrineGoldBottom = reader.ReadGameObject(); } if (((uint)num & 0x10u) != 0) { shrineGoldMid = reader.ReadGameObject(); } if (((uint)num & 0x20u) != 0) { shrineGoldTop = reader.ReadGameObject(); } if (((uint)num & 0x40u) != 0) { goldMaterialModifier = reader.ReadSingle(); } if (((uint)num & 0x80u) != 0) { visualsDone = reader.ReadBoolean(); } } public override void PreStartClient() { if (!___shrineGoldBottomNetId.IsEmpty()) { NetworkshrineGoldBottom = ClientScene.FindLocalObject(___shrineGoldBottomNetId); } if (!___shrineGoldMidNetId.IsEmpty()) { NetworkshrineGoldMid = ClientScene.FindLocalObject(___shrineGoldMidNetId); } if (!___shrineGoldTopNetId.IsEmpty()) { NetworkshrineGoldTop = ClientScene.FindLocalObject(___shrineGoldTopNetId); } } } public class MultiOptionPickerPanel : MonoBehaviour { private int numberOfPickUpsSelected; public int numberOfPickUpsAvailable = 1; private EventFunctions eventFunctions; private void Start() { eventFunctions = base.gameObject.GetComponent(); } public void AddPickupSelected() { numberOfPickUpsSelected++; if (numberOfPickUpsSelected >= numberOfPickUpsAvailable) { KillPanel(); } } private void KillPanel() { eventFunctions.DestroySelf(); } } public class DelayedDamageEffectUpdater : MonoBehaviour { private CharacterBody body; private void OnEnable() { body = GetComponentInParent().body; CharacterBody characterBody = body; characterBody.OnNetworkItemBehaviorUpdate = (Action)Delegate.Combine(characterBody.OnNetworkItemBehaviorUpdate, new Action(HandleNetworkItemUpdate)); } private void OnDisable() { if ((bool)body) { CharacterBody characterBody = body; characterBody.OnNetworkItemBehaviorUpdate = (Action)Delegate.Remove(characterBody.OnNetworkItemBehaviorUpdate, new Action(HandleNetworkItemUpdate)); } } private void HandleNetworkItemUpdate(CharacterBody.NetworkItemBehaviorData itemBehaviorData) { if (itemBehaviorData.itemIndex == DLC2Content.Items.DelayedDamage.itemIndex) { SpawnDelayedDamageEffect(); } } public void SpawnDelayedDamageEffect() { UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/Effects/DelayedDamageIndicator"), body.mainHurtBox ? body.mainHurtBox.transform.position : body.transform.position, UnityEngine.Quaternion.identity, body.mainHurtBox ? body.mainHurtBox.transform : body.transform); } } public class GoldOnStageStartBehaviour : MonoBehaviour { private CharacterBody body; private void OnEnable() { body = GetComponentInParent().body; CharacterBody characterBody = body; characterBody.OnNetworkItemBehaviorUpdate = (Action)Delegate.Combine(characterBody.OnNetworkItemBehaviorUpdate, new Action(HandleNetworkItemUpdate)); } private void OnDisable() { if ((bool)body) { CharacterBody characterBody = body; characterBody.OnNetworkItemBehaviorUpdate = (Action)Delegate.Remove(characterBody.OnNetworkItemBehaviorUpdate, new Action(HandleNetworkItemUpdate)); } } private void HandleNetworkItemUpdate(CharacterBody.NetworkItemBehaviorData itemBehaviorData) { if (itemBehaviorData.itemIndex == DLC2Content.Items.GoldOnStageStart.itemIndex) { GiveWarBondsGold(itemBehaviorData.floatValue); } } private void GiveWarBondsGold(float na) { if (((body.inventory != null && body.inventory.GetItemCount(DLC2Content.Items.GoldOnStageStart) != 0) ? 1 : 0) > (false ? 1 : 0)) { Util.PlaySound("Play_item_proc_goldOnStageStart", body.gameObject); EffectManager.SpawnEffect(CharacterBody.CommonAssets.goldOnStageStartEffect, new EffectData { origin = base.transform.position }, transmit: false); } } } public class LowerHealthHigherDamageEffectUpdater : MonoBehaviour { private CharacterBody body; public GameObject rageCrystalEffect; private void OnEnable() { body = GetComponentInParent().body; CharacterBody characterBody = body; characterBody.OnNetworkItemBehaviorUpdate = (Action)Delegate.Combine(characterBody.OnNetworkItemBehaviorUpdate, new Action(HandleNetworkItemUpdate)); } private void OnDisable() { if ((bool)body) { CharacterBody characterBody = body; characterBody.OnNetworkItemBehaviorUpdate = (Action)Delegate.Remove(characterBody.OnNetworkItemBehaviorUpdate, new Action(HandleNetworkItemUpdate)); } } private void HandleNetworkItemUpdate(CharacterBody.NetworkItemBehaviorData itemBehaviorData) { if (itemBehaviorData.itemIndex == DLC2Content.Items.LowerHealthHigherDamage.itemIndex) { UpdateLanternFlameEffect((int)itemBehaviorData.floatValue); } } public void UpdateLanternFlameEffect(int on) { if (on != 0) { rageCrystalEffect.SetActive(value: true); Util.PlaySound("Play_item_proc_lowerHealthHigherDamage_active_loop", base.gameObject); } else { rageCrystalEffect.SetActive(value: false); Util.PlaySound("Stop_item_proc_lowerHealthHigherDamage_active_loop", base.gameObject); } } } public class JunkContent : IContentPackProvider { public static class Items { public static ItemDef AACannon; public static ItemDef PlasmaCore; public static ItemDef CooldownOnCrit; public static ItemDef TempestOnKill; public static ItemDef WarCryOnCombat; public static ItemDef PlantOnHit; public static ItemDef MageAttunement; public static ItemDef BurnNearby; public static ItemDef CritHeal; public static ItemDef Incubator; public static ItemDef SkullCounter; } public static class Equipment { public static EquipmentDef SoulJar; public static EquipmentDef EliteYellowEquipment; public static EquipmentDef EliteGoldEquipment; public static EquipmentDef GhostGun; public static EquipmentDef OrbitalLaser; public static EquipmentDef Enigma; public static EquipmentDef SoulCorruptor; } public static class Buffs { public static BuffDef EnrageAncientWisp; public static BuffDef LightningShield; public static BuffDef Slow30; public static BuffDef EngiTeamShield; public static BuffDef GoldEmpowered; public static BuffDef LoaderOvercharged; public static BuffDef LoaderPylonPowered; public static BuffDef Deafened; public static BuffDef MeatRegenBoost; public static BuffDef BodyArmor; } public static class Elites { public static EliteDef Gold; } private ContentPack contentPack = new ContentPack(); public string identifier => "RoR2.Junk"; public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args) { contentPack.identifier = identifier; AddressablesLoadHelper loadHelper = AddressablesLoadHelper.CreateUsingDefaultResourceLocator("ContentPack:RoR2.Junk"); yield return loadHelper.AddContentPackLoadOperationWithYields(contentPack); loadHelper.AddGenericOperation(delegate { ContentLoadHelper.PopulateTypeFields(typeof(Items), contentPack.itemDefs); ContentLoadHelper.PopulateTypeFields(typeof(Equipment), contentPack.equipmentDefs); ContentLoadHelper.PopulateTypeFields(typeof(Buffs), contentPack.buffDefs, (string fieldName) => "bd" + fieldName); ContentLoadHelper.PopulateTypeFields(typeof(Elites), contentPack.eliteDefs, (string fieldName) => "ed" + fieldName); }, 0.05f); while (loadHelper.coroutine.MoveNext()) { args.ReportProgress(loadHelper.progress.value); yield return loadHelper.coroutine.Current; } } public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args) { ContentPack.Copy(contentPack, args.output); yield break; } public IEnumerator FinalizeAsync(FinalizeAsyncArgs args) { yield break; } } public struct AchievementIndex { [SerializeField] public int intValue; public static AchievementIndex operator ++(AchievementIndex achievementIndex) { achievementIndex.intValue++; return achievementIndex; } } public struct ServerAchievementIndex : IEquatable { [SerializeField] public int intValue; public bool Equals(ServerAchievementIndex other) { return intValue == other.intValue; } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is ServerAchievementIndex) { return Equals((ServerAchievementIndex)obj); } return false; } public override int GetHashCode() { return intValue.GetHashCode(); } public static ServerAchievementIndex operator ++(ServerAchievementIndex achievementIndex) { achievementIndex.intValue++; return achievementIndex; } public static bool operator ==(ServerAchievementIndex a, ServerAchievementIndex b) { return a.intValue == b.intValue; } public static bool operator !=(ServerAchievementIndex a, ServerAchievementIndex b) { return a.intValue != b.intValue; } } public static class NetworkExtensions { private static int itemMaskBitCount; private static int itemMaskByteCount; private static byte[] itemMaskByteBuffer; public static void WriteAchievementIndex(this NetworkWriter writer, AchievementIndex value) { writer.WritePackedUInt32((uint)value.intValue); } public static AchievementIndex ReadAchievementIndex(this NetworkReader reader) { AchievementIndex result = default(AchievementIndex); result.intValue = (int)reader.ReadPackedUInt32(); return result; } public static void WriteBodyIndex(this NetworkWriter writer, BodyIndex bodyIndex) { writer.WritePackedIndex32((int)bodyIndex); } public static BodyIndex ReadBodyIndex(this NetworkReader reader) { return (BodyIndex)reader.ReadPackedIndex32(); } public static void WriteBuffIndex(this NetworkWriter writer, BuffIndex buffIndex) { writer.WritePackedIndex32((int)buffIndex); } public static BuffIndex ReadBuffIndex(this NetworkReader reader) { return (BuffIndex)reader.ReadPackedIndex32(); } public static DamageTypeCombo ReadDamageType(this NetworkReader reader) { return reader.ReadPackedUInt64(); } public static void WriteDamageType(this NetworkWriter writer, DamageTypeCombo damageType) { writer.WritePackedUInt64(damageType.damageTypeCombined); } public static DamageColorIndex ReadDamageColorIndex(this NetworkReader reader) { return (DamageColorIndex)reader.ReadByte(); } public static void Write(this NetworkWriter writer, DamageColorIndex damageColorIndex) { writer.Write((byte)damageColorIndex); } public static void Write(this NetworkWriter writer, DamageInfo damageInfo) { writer.Write(damageInfo.damage); writer.Write(damageInfo.crit); writer.Write(damageInfo.attacker); writer.Write(damageInfo.inflictor); writer.Write(damageInfo.position); writer.Write(damageInfo.force); writer.Write(damageInfo.procChainMask); writer.Write(damageInfo.procCoefficient); writer.WritePackedUInt32((uint)(ulong)damageInfo.damageType); writer.Write((byte)damageInfo.damageColorIndex); writer.Write((byte)(damageInfo.dotIndex + 1)); writer.Write(damageInfo.canRejectForce); } public static DamageInfo ReadDamageInfo(this NetworkReader reader) { return new DamageInfo { damage = reader.ReadSingle(), crit = reader.ReadBoolean(), attacker = reader.ReadGameObject(), inflictor = reader.ReadGameObject(), position = reader.ReadVector3(), force = reader.ReadVector3(), procChainMask = reader.ReadProcChainMask(), procCoefficient = reader.ReadSingle(), damageType = reader.ReadPackedUInt64(), damageColorIndex = (DamageColorIndex)reader.ReadByte(), dotIndex = (DotController.DotIndex)(reader.ReadByte() - 1), canRejectForce = reader.ReadBoolean() }; } public static void WriteEffectIndex(this NetworkWriter writer, EffectIndex effectIndex) { writer.WritePackedUInt32((uint)(effectIndex + 1)); } public static EffectIndex ReadEffectIndex(this NetworkReader reader) { return (EffectIndex)(reader.ReadPackedUInt32() - 1); } public static void Write(this NetworkWriter writer, EffectData effectData) { effectData.Serialize(writer); } public static EffectData ReadEffectData(this NetworkReader reader) { EffectData effectData = new EffectData(); effectData.Deserialize(reader); return effectData; } public static void ReadEffectData(this NetworkReader reader, EffectData effectData) { effectData.Deserialize(reader); } public static void Write(this NetworkWriter writer, EntityStateIndex entityStateIndex) { writer.WritePackedIndex32((int)entityStateIndex); } public static EntityStateIndex ReadEntityStateIndex(this NetworkReader reader) { return (EntityStateIndex)reader.ReadPackedIndex32(); } public static void Write(this NetworkWriter writer, EquipmentIndex equipmentIndex) { writer.WritePackedUInt32((uint)(equipmentIndex + 1)); } public static EquipmentIndex ReadEquipmentIndex(this NetworkReader reader) { return (EquipmentIndex)(reader.ReadPackedUInt32() - 1); } public static void Write(this NetworkWriter writer, Run.TimeStamp timeStamp) { Run.TimeStamp.Serialize(writer, timeStamp); } public static Run.TimeStamp ReadTimeStamp(this NetworkReader reader) { return Run.TimeStamp.Deserialize(reader); } public static void Write(this NetworkWriter writer, Run.FixedTimeStamp timeStamp) { Run.FixedTimeStamp.Serialize(writer, timeStamp); } public static Run.FixedTimeStamp ReadFixedTimeStamp(this NetworkReader reader) { return Run.FixedTimeStamp.Deserialize(reader); } public static void Write(this NetworkWriter writer, HurtBoxReference hurtBoxReference) { hurtBoxReference.Write(writer); } public static HurtBoxReference ReadHurtBoxReference(this NetworkReader reader) { HurtBoxReference result = default(HurtBoxReference); result.Read(reader); return result; } public static void Write(this NetworkWriter writer, ItemIndex itemIndex) { writer.WritePackedUInt32((uint)(itemIndex + 1)); } public static ItemIndex ReadItemIndex(this NetworkReader reader) { return (ItemIndex)(reader.ReadPackedUInt32() - 1); } [SystemInitializer(new Type[] { typeof(ItemCatalog) })] private static void Init() { itemMaskBitCount = ItemCatalog.itemCount; itemMaskByteCount = itemMaskBitCount + 7 >> 3; itemMaskByteBuffer = new byte[itemMaskByteCount]; } public static void WriteItemStacks(this NetworkWriter writer, int[] srcItemStacks) { int num = 0; for (int i = 0; i < itemMaskByteCount; i++) { byte b = 0; int num2 = 0; while (num2 < 8 && num < itemMaskBitCount && num < srcItemStacks.Length) { if (srcItemStacks[num] > 0) { b |= (byte)(1 << num2); } num2++; num++; } itemMaskByteBuffer[i] = b; } for (int j = 0; j < itemMaskByteCount && j < itemMaskByteBuffer.Length; j++) { writer.Write(itemMaskByteBuffer[j]); } ItemIndex itemIndex = ItemIndex.Count; for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount && (int)itemIndex < srcItemStacks.Length; itemIndex++) { int num3 = srcItemStacks[(int)itemIndex]; if (num3 > 0) { writer.WritePackedUInt32((uint)num3); } } } public static void ReadItemStacks(this NetworkReader reader, int[] destItemStacks) { for (int i = 0; i < itemMaskByteCount; i++) { itemMaskByteBuffer[i] = reader.ReadByte(); } int num = 0; for (int j = 0; j < itemMaskByteCount; j++) { byte b = itemMaskByteBuffer[j]; int num2 = 0; while (num2 < 8 && num < itemMaskBitCount) { destItemStacks[num] = (int)(((b & (byte)(1 << num2)) != 0) ? reader.ReadPackedUInt32() : 0); num2++; num++; } } } public static void WriteBitArray(this NetworkWriter writer, [NotNull] bool[] values) { writer.WriteBitArray(values, values.Length); } public static void WriteBitArray(this NetworkWriter writer, [NotNull] bool[] values, int bufferLength) { int num = bufferLength + 7 >> 3; int num2 = num - 1; int num3 = bufferLength - (num2 << 3); int num4 = 0; for (int i = 0; i < num; i++) { byte b = 0; int num5 = ((i < num2) ? 8 : num3); int num6 = 0; while (num6 < num5) { if (values[num4]) { b |= (byte)(1 << num6); } num6++; num4++; } writer.Write(b); } } public static void ReadBitArray(this NetworkReader reader, [NotNull] bool[] values) { reader.ReadBitArray(values, values.Length); } public static void ReadBitArray(this NetworkReader reader, [NotNull] bool[] values, int bufferLength) { int num = bufferLength + 7 >> 3; int num2 = num - 1; int num3 = bufferLength - (num2 << 3); int num4 = 0; for (int i = 0; i < num; i++) { int num5 = ((i < num2) ? 8 : num3); byte b = reader.ReadByte(); int num6 = 0; while (num6 < num5) { values[num4] = (b & (byte)(1 << num6)) != 0; num6++; num4++; } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WritePackedIndex32(this NetworkWriter writer, int index) { writer.WritePackedUInt32((uint)(index + 1)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ReadPackedIndex32(this NetworkReader reader) { return (int)(reader.ReadPackedUInt32() - 1); } public static void Write(this NetworkWriter writer, NetworkPlayerName networkPlayerName) { networkPlayerName.Serialize(writer); } public static NetworkPlayerName ReadNetworkPlayerName(this NetworkReader reader) { NetworkPlayerName result = default(NetworkPlayerName); result.Deserialize(reader); return result; } public static void Write(this NetworkWriter writer, PackedUnitVector3 value) { writer.Write(value.value); } public static PackedUnitVector3 ReadPackedUnitVector3(this NetworkReader reader) { return new PackedUnitVector3(reader.ReadUInt16()); } public static void Write(this NetworkWriter writer, PickupIndex value) { PickupIndex.WriteToNetworkWriter(writer, value); } public static PickupIndex ReadPickupIndex(this NetworkReader reader) { return PickupIndex.ReadFromNetworkReader(reader); } public static void Write(this NetworkWriter writer, PitchYawPair pitchYawPair) { writer.Write(pitchYawPair.pitch); writer.Write(pitchYawPair.yaw); } public static PitchYawPair ReadPitchYawPair(this NetworkReader reader) { float pitch = reader.ReadSingle(); float yaw = reader.ReadSingle(); return new PitchYawPair(pitch, yaw); } public static void Write(this NetworkWriter writer, ProcChainMask procChainMask) { writer.WritePackedUInt32(procChainMask.mask); } public static ProcChainMask ReadProcChainMask(this NetworkReader reader) { ProcChainMask result = default(ProcChainMask); result.mask = reader.ReadPackedUInt32(); return result; } public static void Write(this NetworkWriter writer, RuleBook src) { src.Serialize(writer); } public static void ReadRuleBook(this NetworkReader reader, RuleBook dest) { dest.Deserialize(reader); } public static void Write(this NetworkWriter writer, RuleMask src) { src.Serialize(writer); } public static void ReadRuleMask(this NetworkReader reader, RuleMask dest) { dest.Deserialize(reader); } public static void Write(this NetworkWriter writer, RuleChoiceMask src) { src.Serialize(writer); } public static void ReadRuleChoiceMask(this NetworkReader reader, RuleChoiceMask dest) { dest.Deserialize(reader); } public static void Write(this NetworkWriter writer, TeamIndex teamIndex) { byte value = (byte)(teamIndex + 1); writer.Write(value); } public static TeamIndex ReadTeamIndex(this NetworkReader reader) { return (TeamIndex)(reader.ReadByte() - 1); } public static void Write(this NetworkWriter writer, UnlockableIndex index) { writer.WritePackedIndex32((int)index); } public static UnlockableIndex ReadUnlockableIndex(this NetworkReader reader) { return (UnlockableIndex)reader.ReadPackedIndex32(); } } public static class AchievementManager { private struct AchievementSortPair { public int score; public AchievementDef achievementDef; } public struct Enumerator : IEnumerator, IEnumerator, IDisposable { private int position; public AchievementDef Current => achievementDefs[position]; object IEnumerator.Current => Current; public bool MoveNext() { position++; return position < achievementDefs.Length; } public void Reset() { position = -1; } void IDisposable.Dispose() { } } private static readonly Dictionary userToManagerMap = new Dictionary(); public static ResourceAvailability availability; private static readonly Queue taskQueue = new Queue(); private static readonly Dictionary achievementNamesToDefs = new Dictionary(); private static readonly List achievementIdentifiers = new List(); public static readonly ReadOnlyCollection readOnlyAchievementIdentifiers = achievementIdentifiers.AsReadOnly(); private static AchievementDef[] achievementDefs; private static AchievementDef[] serverAchievementDefs; public static readonly GenericStaticEnumerable allAchievementDefs; public static int achievementCount => achievementDefs.Length; public static int serverAchievementCount => serverAchievementDefs.Length; public static event Action onAchievementsRegistered; public static UserAchievementManager GetUserAchievementManager([NotNull] LocalUser user) { userToManagerMap.TryGetValue(user, out var value); return value; } public static IEnumerator DoInit() { yield return CollectAchievementDefs(achievementNamesToDefs); LocalUserManager.onUserSignIn += delegate(LocalUser localUser) { if (localUser.userProfile.canSave) { UserAchievementManager userAchievementManager = new UserAchievementManager(); userAchievementManager.OnInstall(localUser); userToManagerMap[localUser] = userAchievementManager; } }; LocalUserManager.onUserSignOut += delegate(LocalUser localUser) { if (userToManagerMap.TryGetValue(localUser, out var value)) { value.OnUninstall(); userToManagerMap.Remove(localUser); } }; RoR2Application.onUpdate += delegate { foreach (KeyValuePair item in userToManagerMap) { item.Value.Update(); } }; availability.MakeAvailable(); } public static void AddTask(Action action) { taskQueue.Enqueue(action); } public static void ProcessTasks() { while (taskQueue.Count > 0) { taskQueue.Dequeue()(); } } public static AchievementDef GetAchievementDef(string achievementIdentifier) { if (achievementNamesToDefs.TryGetValue(achievementIdentifier, out var value)) { return value; } return null; } public static AchievementDef GetAchievementDef(AchievementIndex index) { if (index.intValue >= 0 && index.intValue < achievementDefs.Length) { return achievementDefs[index.intValue]; } return null; } public static AchievementDef GetAchievementDef(ServerAchievementIndex index) { if (index.intValue >= 0 && index.intValue < serverAchievementDefs.Length) { return serverAchievementDefs[index.intValue]; } return null; } public static AchievementDef GetAchievementDefFromUnlockable(string unlockableRewardIdentifier) { for (int i = 0; i < achievementDefs.Length; i++) { if (achievementDefs[i].unlockableRewardIdentifier == unlockableRewardIdentifier) { return achievementDefs[i]; } } return null; } public static IEnumerator CollectAchievementDefs(Dictionary map) { List achievementDefsList = new List(); map.Clear(); List list = new List(); if (RoR2Application.isModded) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly item in assemblies) { list.Add(item); } } else { list.Add(typeof(BaseAchievement).Assembly); } foreach (Assembly item2 in list) { Type[] types; try { types = item2.GetTypes(); } catch (ReflectionTypeLoadException ex) { UnityEngine.Debug.LogError($"CollectAchievementDefs: {ex}"); types = ex.Types; if (types == null) { continue; } } catch (Exception arg) { UnityEngine.Debug.LogError($"CollectAchievementDefs: {arg}"); continue; } foreach (Type item3 in from type in types where type != null && type.IsSubclassOf(typeof(BaseAchievement)) orderby type.Name select type) { RegisterAchievementAttribute registerAchievementAttribute = (RegisterAchievementAttribute)item3.GetCustomAttributes(inherit: false).FirstOrDefault((object v) => v is RegisterAchievementAttribute); if (registerAchievementAttribute != null) { if (map.ContainsKey(registerAchievementAttribute.identifier)) { UnityEngine.Debug.LogErrorFormat("Class {0} attempted to register as achievement {1}, but class {2} has already registered as that achievement.", item3.FullName, registerAchievementAttribute.identifier, achievementNamesToDefs[registerAchievementAttribute.identifier].type.FullName); continue; } UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(registerAchievementAttribute.unlockableRewardIdentifier); AchievementDef achievementDef2 = new AchievementDef { identifier = registerAchievementAttribute.identifier, unlockableRewardIdentifier = registerAchievementAttribute.unlockableRewardIdentifier, prerequisiteAchievementIdentifier = registerAchievementAttribute.prerequisiteAchievementIdentifier, nameToken = "ACHIEVEMENT_" + registerAchievementAttribute.identifier.ToUpper(CultureInfo.InvariantCulture) + "_NAME", descriptionToken = "ACHIEVEMENT_" + registerAchievementAttribute.identifier.ToUpper(CultureInfo.InvariantCulture) + "_DESCRIPTION", type = item3, serverTrackerType = registerAchievementAttribute.serverTrackerType, lunarCoinReward = registerAchievementAttribute.lunarCoinReward }; if ((bool)unlockableDef && (bool)unlockableDef.achievementIcon) { achievementDef2.SetAchievedIcon(unlockableDef.achievementIcon); } else { achievementDef2.iconPath = "Textures/AchievementIcons/tex" + registerAchievementAttribute.identifier + "Icon"; achievementDef2.PreloadIcon(); } achievementIdentifiers.Add(registerAchievementAttribute.identifier); map.Add(registerAchievementAttribute.identifier, achievementDef2); achievementDefsList.Add(achievementDef2); if (unlockableDef != null) { unlockableDef.getHowToUnlockString = () => Language.GetStringFormatted("UNLOCK_VIA_ACHIEVEMENT_FORMAT", Language.GetString(achievementDef2.nameToken), Language.GetString(achievementDef2.descriptionToken)); unlockableDef.getUnlockedString = () => Language.GetStringFormatted("UNLOCKED_FORMAT", Language.GetString(achievementDef2.nameToken), Language.GetString(achievementDef2.descriptionToken)); } } yield return null; } } achievementDefs = achievementDefsList.ToArray(); SortAchievements(achievementDefs); serverAchievementDefs = achievementDefs.Where((AchievementDef achievementDef) => achievementDef.serverTrackerType != null).ToArray(); for (int j = 0; j < achievementDefs.Length; j++) { achievementDefs[j].index = new AchievementIndex { intValue = j }; } for (int k = 0; k < serverAchievementDefs.Length; k++) { serverAchievementDefs[k].serverIndex = new ServerAchievementIndex { intValue = k }; } for (int l = 0; l < achievementIdentifiers.Count; l++) { string currentAchievementIdentifier = achievementIdentifiers[l]; map[currentAchievementIdentifier].childAchievementIdentifiers = achievementIdentifiers.Where((string v) => map[v].prerequisiteAchievementIdentifier == currentAchievementIdentifier).ToArray(); } AchievementManager.onAchievementsRegistered?.Invoke(); yield return null; } private static void SortAchievements(AchievementDef[] achievementDefsArray) { AchievementSortPair[] array = new AchievementSortPair[achievementDefsArray.Length]; for (int i = 0; i < array.Length; i++) { array[i] = new AchievementSortPair { score = UnlockableCatalog.GetUnlockableSortScore(achievementDefsArray[i].unlockableRewardIdentifier), achievementDef = achievementDefsArray[i] }; } Array.Sort(array, (AchievementSortPair a, AchievementSortPair b) => a.score - b.score); for (int j = 0; j < array.Length; j++) { achievementDefsArray[j] = array[j].achievementDef; } } public static Enumerator GetEnumerator() { return default(Enumerator); } } public class AchievementDef { public AchievementIndex index; public ServerAchievementIndex serverIndex = new ServerAchievementIndex { intValue = -1 }; public string identifier; public string unlockableRewardIdentifier; public string prerequisiteAchievementIdentifier; public string nameToken; public string descriptionToken; public string iconPath; public uint lunarCoinReward; public Type type; public Type serverTrackerType; private static readonly string[] emptyStringArray = Array.Empty(); public string[] childAchievementIdentifiers = emptyStringArray; private Sprite achievedIcon; private Sprite unachievedIcon; public void SetAchievedIcon(Sprite icon) { achievedIcon = icon; } public void PreloadIcon() { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync(iconPath); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { achievedIcon = x.Result; if (!achievedIcon) { AsyncOperationHandle asyncOperationHandle2 = LegacyResourcesAPI.LoadAsync("Textures/AchievementIcons/texPlaceholderAchievement"); asyncOperationHandle2.Completed += delegate(AsyncOperationHandle handle) { achievedIcon = handle.Result; }; } }; } public string GetReward() { return lunarCoinReward.ToString(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sprite GetAchievedIcon() { if (!achievedIcon) { achievedIcon = LegacyResourcesAPI.Load(iconPath); if (!achievedIcon) { achievedIcon = LegacyResourcesAPI.Load("Textures/AchievementIcons/texPlaceholderAchievement"); } } return achievedIcon; } public Sprite GetUnachievedIcon() { return LegacyResourcesAPI.Load("Textures/MiscIcons/texUnlockIcon"); } public string GetAchievementSoundString() { if (unlockableRewardIdentifier.Contains("Characters.")) { return "Play_UI_achievementUnlock_enhanced"; } if (unlockableRewardIdentifier.Contains("Skills.") || unlockableRewardIdentifier.Contains("Skins.")) { return "Play_UI_skill_unlock"; } return "Play_UI_achievementUnlock"; } } [MeansImplicitUse] public class RegisterAchievementAttribute : System.Attribute { public readonly string identifier; public readonly string unlockableRewardIdentifier; public readonly string prerequisiteAchievementIdentifier; public readonly uint lunarCoinReward; public readonly Type serverTrackerType; public RegisterAchievementAttribute([NotNull] string identifier, string unlockableRewardIdentifier, string prerequisiteAchievementIdentifier, uint lunarCoinReward, Type serverTrackerType = null) { this.identifier = identifier; this.unlockableRewardIdentifier = unlockableRewardIdentifier; this.prerequisiteAchievementIdentifier = prerequisiteAchievementIdentifier; this.lunarCoinReward = lunarCoinReward; this.serverTrackerType = serverTrackerType; } } public class UserAchievementManager { private readonly List achievementsList = new List(); public LocalUser localUser; public UserProfile userProfile; public int dirtyGrantsCount; public int dirtyUpdatesCount; private readonly bool[] serverAchievementTrackingMask = new bool[AchievementManager.serverAchievementCount]; private bool serverAchievementTrackingMaskDirty; public event Action onUserProfileStatsUpdated; public event Action onRunStatsUpdated; private void OnUserProfileStatsUpdated() { StatSheet statSheet = userProfile.statSheet; if (statSheet != null) { OnUserProfileStatsUpdated(statSheet); } PlayerStatsComponent cachedStatsComponent = localUser.cachedStatsComponent; if ((bool)cachedStatsComponent) { StatSheet currentStats = cachedStatsComponent.currentStats; if (currentStats != null) { OnRunStatsUpdated(currentStats); } } } private void OnUserProfileStatsUpdated([NotNull] StatSheet statSheet) { this.onUserProfileStatsUpdated?.Invoke(statSheet); } private void OnRunStatsUpdated([NotNull] StatSheet statSheet) { this.onRunStatsUpdated?.Invoke(statSheet); } public void SetServerAchievementTracked(ServerAchievementIndex serverAchievementIndex, bool shouldTrack) { if (serverAchievementTrackingMask[serverAchievementIndex.intValue] != shouldTrack) { serverAchievementTrackingMask[serverAchievementIndex.intValue] = shouldTrack; serverAchievementTrackingMaskDirty = true; } } public void TransmitAchievementRequestsToServer() { if ((bool)localUser.currentNetworkUser) { localUser.currentNetworkUser.GetComponent().SendAchievementTrackerRequestsMaskToServer(serverAchievementTrackingMask); } } public void Update() { if (serverAchievementTrackingMaskDirty) { serverAchievementTrackingMaskDirty = false; TransmitAchievementRequestsToServer(); } int num = achievementsList.Count - 1; while (num >= 0 && dirtyGrantsCount > 0) { BaseAchievement baseAchievement = achievementsList[num]; if (baseAchievement.shouldGrant) { dirtyGrantsCount--; achievementsList.RemoveAt(num); userProfile.AddAchievement(baseAchievement.achievementDef.identifier, isExternal: true); baseAchievement.OnGranted(); baseAchievement.OnUninstall(); NetworkUser currentNetworkUser = localUser.currentNetworkUser; if (currentNetworkUser != null) { currentNetworkUser.CallCmdReportAchievement(baseAchievement.achievementDef.nameToken); } } num--; } } public void GrantAchievement(AchievementDef achievementDef) { for (int i = 0; i < achievementsList.Count; i++) { if (achievementsList[i].achievementDef == achievementDef) { achievementsList[i].Grant(); } } } public void HandleServerAchievementCompleted(ServerAchievementIndex serverAchievementIndex) { achievementsList.FirstOrDefault((BaseAchievement a) => a.achievementDef.serverIndex == serverAchievementIndex)?.Grant(); } public void HandleServerTryToCompleteActivity(ServerAchievementIndex serverAchievementIndex) { achievementsList.FirstOrDefault((BaseAchievement a) => a.achievementDef.serverIndex == serverAchievementIndex)?.TryToCompleteActivity(); } public float GetAchievementProgress(AchievementDef achievementDef) { return achievementsList.FirstOrDefault((BaseAchievement a) => a.achievementDef == achievementDef)?.ProgressForAchievement() ?? 1f; } public void OnInstall(LocalUser localUser) { this.localUser = localUser; userProfile = localUser.userProfile; UserProfile obj = userProfile; obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(OnUserProfileStatsUpdated)); foreach (string readOnlyAchievementIdentifier in AchievementManager.readOnlyAchievementIdentifiers) { AchievementDef achievementDef = AchievementManager.GetAchievementDef(readOnlyAchievementIdentifier); if (userProfile.HasAchievement(readOnlyAchievementIdentifier)) { if (!userProfile.HasUnlockable(achievementDef.unlockableRewardIdentifier)) { UnityEngine.Debug.LogFormat("UserProfile {0} has achievement {1} but not its unlockable {2}. Granting.", userProfile.name, achievementDef.nameToken, achievementDef.unlockableRewardIdentifier); userProfile.AddUnlockToken(achievementDef.unlockableRewardIdentifier); } } else { BaseAchievement baseAchievement = (BaseAchievement)Activator.CreateInstance(achievementDef.type); baseAchievement.achievementDef = achievementDef; baseAchievement.owner = this; achievementsList.Add(baseAchievement); baseAchievement.OnInstall(); } } } public void OnUninstall() { for (int num = achievementsList.Count - 1; num >= 0; num--) { achievementsList[num].OnUninstall(); } achievementsList.Clear(); UserProfile obj = userProfile; obj.onStatsReceived = (Action)Delegate.Remove(obj.onStatsReceived, new Action(OnUserProfileStatsUpdated)); userProfile = null; localUser = null; } } public static class AnimationParameters { public static readonly int isMoving = Animator.StringToHash("isMoving"); public static readonly int turnAngle = Animator.StringToHash("turnAngle"); public static readonly int isGrounded = Animator.StringToHash("isGrounded"); public static readonly int mainRootPlaybackRate = Animator.StringToHash("mainRootPlaybackRate"); public static readonly int forwardSpeed = Animator.StringToHash("forwardSpeed"); public static readonly int rightSpeed = Animator.StringToHash("rightSpeed"); public static readonly int upSpeed = Animator.StringToHash("upSpeed"); public static readonly int walkSpeed = Animator.StringToHash("walkSpeed"); public static readonly int isSprinting = Animator.StringToHash("isSprinting"); public static readonly int aimWeight = Animator.StringToHash("aimWeight"); } [CreateAssetMenu(menuName = "RoR2/DropTables/ArenaMonsterItemDropTable")] public class ArenaMonsterItemDropTable : PickupDropTable { public ItemTag[] requiredItemTags; public ItemTag[] bannedItemTags; public float tier1Weight = 0.8f; public float tier2Weight = 0.2f; public float tier3Weight = 0.01f; public float bossWeight; public float lunarItemWeight; public float voidTier1Weight; public float voidTier2Weight; public float voidTier3Weight; public float voidBossWeight; private readonly WeightedSelection selector = new WeightedSelection(); private bool PassesFilter(PickupIndex pickupIndex) { PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef.itemIndex != ItemIndex.None) { ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex); if (ArenaMissionController.instance.inventory.GetItemCount(itemDef.itemIndex) > 0) { return false; } ItemTag[] array = requiredItemTags; foreach (ItemTag value in array) { if (Array.IndexOf(itemDef.tags, value) == -1) { return false; } } array = bannedItemTags; foreach (ItemTag value2 in array) { if (Array.IndexOf(itemDef.tags, value2) != -1) { return false; } } } return true; } private void Add(List sourceDropList, float chance) { if (chance <= 0f || sourceDropList.Count == 0) { return; } foreach (PickupIndex sourceDrop in sourceDropList) { if (PassesFilter(sourceDrop)) { selector.AddChoice(sourceDrop, chance); } } } private void GenerateWeightedSelection(Run run) { selector.Clear(); Add(run.availableTier1DropList, tier1Weight); Add(run.availableTier2DropList, tier2Weight); Add(run.availableTier3DropList, tier3Weight); Add(run.availableBossDropList, bossWeight); Add(run.availableLunarItemDropList, lunarItemWeight); Add(run.availableVoidTier1DropList, voidTier1Weight); Add(run.availableVoidTier2DropList, voidTier2Weight); Add(run.availableVoidTier3DropList, voidTier3Weight); Add(run.availableVoidBossDropList, voidBossWeight); } protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng) { GenerateWeightedSelection(Run.instance); return PickupDropTable.GenerateDropFromWeightedSelection(rng, selector); } public override int GetPickupCount() { return selector.Count; } protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng) { return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, selector); } } public enum ArtifactIndex { None = -1 } [Serializable] public struct ArtifactMask { [SerializeField] public ushort a; public static readonly ArtifactMask none; public static ArtifactMask all; public bool HasArtifact(ArtifactIndex artifactIndex) { if (artifactIndex < (ArtifactIndex)0 || (int)artifactIndex >= ArtifactCatalog.artifactCount) { return false; } return (a & (1 << (int)artifactIndex)) != 0; } public void AddArtifact(ArtifactIndex artifactIndex) { if (artifactIndex >= (ArtifactIndex)0 && (int)artifactIndex < ArtifactCatalog.artifactCount) { a |= (ushort)(1 << (int)artifactIndex); } } public void ToggleArtifact(ArtifactIndex artifactIndex) { if (artifactIndex >= (ArtifactIndex)0 && (int)artifactIndex < ArtifactCatalog.artifactCount) { a ^= (ushort)(1 << (int)artifactIndex); } } public void RemoveArtifact(ArtifactIndex artifactIndex) { if (artifactIndex >= (ArtifactIndex)0 && (int)artifactIndex < ArtifactCatalog.artifactCount) { a &= (ushort)(~(1 << (int)artifactIndex)); } } public static ArtifactMask operator &(ArtifactMask mask1, ArtifactMask mask2) { ArtifactMask result = default(ArtifactMask); result.a = (ushort)(mask1.a & mask2.a); return result; } [SystemInitializer(new Type[] { typeof(ArtifactCatalog) })] private static void Init() { all = default(ArtifactMask); for (ArtifactIndex artifactIndex = (ArtifactIndex)0; (int)artifactIndex < ArtifactCatalog.artifactCount; artifactIndex++) { all.AddArtifact(artifactIndex); } } } public static class ArtifactCatalog { private static ArtifactDef[] artifactDefs = Array.Empty(); public static ResourceAvailability availability; public static int artifactCount => artifactDefs.Length; [Obsolete("Use IContentPackProvider instead.")] public static event Action> getAdditionalEntries { add { LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.ArtifactCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.artifactDefs); } remove { } } private static void RegisterArtifact(ArtifactIndex artifactIndex, ArtifactDef artifactDef) { artifactDefs[(int)artifactIndex] = artifactDef; } [SystemInitializer(new Type[] { })] private static void Init() { SetArtifactDefs(ContentManager.artifactDefs); availability.MakeAvailable(); } private static void SetArtifactDefs([NotNull] ArtifactDef[] newArtifactDefs) { artifactDefs = ArrayUtils.Clone(newArtifactDefs); Array.Sort(artifactDefs, (ArtifactDef a, ArtifactDef b) => string.CompareOrdinal(a.cachedName, b.cachedName)); for (int i = 0; i < artifactDefs.Length; i++) { artifactDefs[i].artifactIndex = (ArtifactIndex)i; } } public static ArtifactIndex FindArtifactIndex(string artifactName) { for (int i = 0; i < artifactDefs.Length; i++) { if (string.CompareOrdinal(artifactName, artifactDefs[i].cachedName) == 0) { return (ArtifactIndex)i; } } return ArtifactIndex.None; } public static ArtifactDef FindArtifactDef(string artifactName) { return GetArtifactDef(FindArtifactIndex(artifactName)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ArtifactDef GetArtifactDef(ArtifactIndex artifactIndex) { ArtifactDef[] array = artifactDefs; ArtifactDef defaultValue = null; return ArrayUtils.GetSafe(array, (int)artifactIndex, in defaultValue); } } [CreateAssetMenu(menuName = "RoR2/ArtifactCompoundDef")] public class ArtifactCompoundDef : ScriptableObject { public int value; public Material decalMaterial; public GameObject modelPrefab; } [CreateAssetMenu(menuName = "RoR2/ArtifactDef")] public class ArtifactDef : ScriptableObject { public string nameToken; public string descriptionToken; public UnlockableDef unlockableDef; public ExpansionDef requiredExpansion; public Sprite smallIconSelectedSprite; public Sprite smallIconDeselectedSprite; public GameObject extraUIDisplayPrefab; [FormerlySerializedAs("worldModelPrefab")] public GameObject pickupModelPrefab; private string _cachedName; public ArtifactIndex artifactIndex { get; set; } [Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)] public new string name { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public string cachedName { get { return _cachedName; } set { base.name = value; _cachedName = value; } } public static void AttemptGrant(ref PickupDef.GrantContext context) { ArtifactDef artifactDef = ArtifactCatalog.GetArtifactDef(PickupCatalog.GetPickupDef(context.controller.pickupIndex).artifactIndex); Run.instance.GrantUnlockToAllParticipatingPlayers(artifactDef.unlockableDef); context.shouldNotify = true; context.shouldDestroy = true; } public virtual PickupDef CreatePickupDef() { PickupDef obj = new PickupDef { internalName = "ArtifactIndex." + cachedName, artifactIndex = artifactIndex, displayPrefab = pickupModelPrefab, nameToken = nameToken, baseColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Artifact) }; obj.darkColor = obj.baseColor; obj.unlockableDef = unlockableDef; obj.interactContextToken = "ITEM_PICKUP_CONTEXT"; obj.iconTexture = (smallIconSelectedSprite ? smallIconSelectedSprite.texture : null); obj.iconSprite = (smallIconSelectedSprite ? smallIconSelectedSprite : null); obj.attemptGrant = AttemptGrant; return obj; } private void Awake() { _cachedName = base.name; } private void OnValidate() { _cachedName = base.name; } } public enum AttackerFiltering { Default, AlwaysHit, NeverHitSelf, AlwaysHitSelf } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] public class ConditionalHideAttribute : PropertyAttribute { public enum DisablingType { ReadOnly = 2, DontDraw } public string comparedPropertyName { get; private set; } public object comparedValue { get; private set; } public DisablingType disablingType { get; private set; } public ConditionalHideAttribute(string comparedPropertyName, object comparedValue, DisablingType disablingType = DisablingType.DontDraw) { this.comparedPropertyName = comparedPropertyName; this.comparedValue = comparedValue; this.disablingType = disablingType; } } public static class BackstabManager { private class BackstabVisualizer { private class IndicatorInfo { public GameObject gameObject; public Transform transform; public ParticleSystem particleSystem; public ParticleSystemRenderer renderer; public float lastDisplayTime; } private CameraRigController camera; public CharacterBody targetBody; private readonly Dictionary bodyToIndicator = new Dictionary(); private static readonly Dictionary buffer = new Dictionary(); private readonly Stack indicatorPool = new Stack(); private static GameObject indicatorPrefab; public void Install(CameraRigController newCamera) { camera = newCamera; RoR2Application.onLateUpdate += UpdateIndicators; } public void Uninstall() { RoR2Application.onLateUpdate -= UpdateIndicators; camera = null; foreach (KeyValuePair item in bodyToIndicator) { UnityEngine.Object.Destroy(item.Value.gameObject); } bodyToIndicator.Clear(); foreach (IndicatorInfo item2 in indicatorPool) { UnityEngine.Object.Destroy(item2.gameObject); } indicatorPool.Clear(); } [InitDuringStartup] private static void OnLoad() { LegacyResourcesAPI.LoadAsyncCallback("Prefabs/VFX/BackstabIndicator", delegate(GameObject operationResult) { indicatorPrefab = operationResult; }); } private void UpdateIndicators() { UnityEngine.Vector3 corePosition = targetBody.corePosition; TeamIndex teamIndex = targetBody.teamComponent.teamIndex; buffer.Clear(); float unscaledTime = Time.unscaledTime; foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { bool num = TeamManager.IsTeamEnemy(teamIndex, readOnlyInstances.teamComponent.teamIndex); bool flag = false; if (num) { flag = IsBackstab(readOnlyInstances.corePosition - corePosition, readOnlyInstances); } if (num && flag) { IndicatorInfo value = null; if (!bodyToIndicator.TryGetValue(readOnlyInstances, out value)) { value = AddIndicator(readOnlyInstances); } value.lastDisplayTime = unscaledTime; } } List list = CollectionPool>.RentCollection(); foreach (KeyValuePair item in bodyToIndicator) { if (item.Value.lastDisplayTime != unscaledTime) { list.Add(item.Key); } } foreach (CharacterBody item2 in list) { RemoveIndicator(item2); } list = CollectionPool>.ReturnCollection(list); } private IndicatorInfo AddIndicator(CharacterBody victimBody) { IndicatorInfo indicatorInfo = null; if (indicatorPool.Count > 0) { indicatorInfo = indicatorPool.Pop(); } else { indicatorInfo = new IndicatorInfo(); indicatorInfo.gameObject = UnityEngine.Object.Instantiate(indicatorPrefab); indicatorInfo.transform = indicatorInfo.gameObject.transform; indicatorInfo.particleSystem = indicatorInfo.gameObject.GetComponent(); indicatorInfo.renderer = indicatorInfo.gameObject.GetComponent(); indicatorInfo.renderer.enabled = false; } indicatorInfo.gameObject.SetActive(value: true); indicatorInfo.particleSystem.Play(); bodyToIndicator[victimBody] = indicatorInfo; return indicatorInfo; } private void RemoveIndicator(CharacterBody victimBody) { IndicatorInfo indicatorInfo = bodyToIndicator[victimBody]; if ((bool)indicatorInfo.gameObject) { indicatorInfo.particleSystem.Stop(); indicatorInfo.gameObject.SetActive(value: false); } bodyToIndicator.Remove(victimBody); indicatorPool.Push(indicatorInfo); } public void OnPreCull() { foreach (KeyValuePair item in bodyToIndicator) { CharacterBody key = item.Key; Transform transform = item.Value.transform; if ((bool)key) { UnityEngine.Vector3? bodyForward = GetBodyForward(key); if (bodyForward.HasValue) { transform.forward = -bodyForward.Value; } transform.position = key.corePosition - transform.forward * key.radius; item.Value.renderer.enabled = true; } } } public void OnPostRender() { foreach (KeyValuePair item in bodyToIndicator) { item.Value.renderer.enabled = false; } } private void Update() { UpdateIndicators(); } } public static GameObject backstabImpactEffectPrefab = null; private static readonly bool enableVisualizerSystem = false; private static readonly float showBackstabThreshold = Mathf.Cos(MathF.PI / 4f); private static readonly Dictionary camToVisualizer = new Dictionary(); public static bool IsBackstab(UnityEngine.Vector3 attackerCorePositionToHitPosition, CharacterBody victimBody) { if (!victimBody.canReceiveBackstab) { return false; } UnityEngine.Vector3? bodyForward = GetBodyForward(victimBody); if (bodyForward.HasValue) { return UnityEngine.Vector3.Dot(attackerCorePositionToHitPosition, bodyForward.Value) > 0f; } return false; } private static UnityEngine.Vector3? GetBodyForward(CharacterBody characterBody) { UnityEngine.Vector3? vector = null; return (!characterBody.characterDirection) ? new UnityEngine.Vector3?(characterBody.transform.forward) : new UnityEngine.Vector3?(characterBody.characterDirection.forward); } [InitDuringStartup] private static void Init() { if (enableVisualizerSystem) { InitVisualizerSystem(); } LegacyResourcesAPI.LoadAsyncCallback("Effects/ImpactEffects/BackstabSpark", delegate(GameObject operationResult) { backstabImpactEffectPrefab = operationResult; }); } private static bool ShouldShowBackstab(UnityEngine.Vector3 attackerCorePosition, CharacterBody victimBody) { if (!victimBody.canReceiveBackstab) { return false; } UnityEngine.Vector3? bodyForward = GetBodyForward(victimBody); if (bodyForward.HasValue) { return UnityEngine.Vector3.Dot((attackerCorePosition - victimBody.corePosition).normalized, bodyForward.Value) > showBackstabThreshold; } return false; } private static void InitVisualizerSystem() { CameraRigController.onCameraTargetChanged += OnCameraTargetChanged; CameraRigController.onCameraEnableGlobal += OnCameraDiscovered; CameraRigController.onCameraDisableGlobal += OnCameraLost; SceneCamera.onSceneCameraPreCull += OnSceneCameraPreCull; SceneCamera.onSceneCameraPostRender += OnSceneCameraPostRender; } private static void OnCameraTargetChanged(CameraRigController camera, GameObject target) { RefreshCamera(camera); } private static void OnCameraDiscovered(CameraRigController camera) { RefreshCamera(camera); } private static void OnCameraLost(CameraRigController camera) { RefreshCamera(camera); } private static void OnSceneCameraPreCull(SceneCamera sceneCam) { if (camToVisualizer.TryGetValue(sceneCam.cameraRigController, out var value)) { value.OnPreCull(); } } private static void OnSceneCameraPostRender(SceneCamera sceneCam) { if (camToVisualizer.TryGetValue(sceneCam.cameraRigController, out var value)) { value.OnPostRender(); } } private static void RefreshCamera(CameraRigController camera) { BackstabVisualizer value; bool num = camToVisualizer.TryGetValue(camera, out value); GameObject gameObject = (camera.isActiveAndEnabled ? camera.target : null); CharacterBody characterBody = (gameObject ? gameObject.GetComponent() : null); bool flag = (bool)characterBody && characterBody.canPerformBackstab; if (num != flag) { if (flag) { value = new BackstabVisualizer(); camToVisualizer.Add(camera, value); value.Install(camera); } else { value.Uninstall(); camToVisualizer.Remove(camera); value = null; } } if (value != null) { value.targetBody = characterBody; } } } public static class BadClientEntityStateMachineFix { private class Watcher { public LocalUser localUser; private TimerQueue.TimerHandle? currentTimerHandle; public void OnInstall() { localUser.onBodyChanged += OnBodyChanged; } public void OnUninstall() { localUser.onBodyChanged -= OnBodyChanged; if (currentTimerHandle.HasValue) { RoR2Application.fixedTimeTimers.RemoveTimer(currentTimerHandle.Value); currentTimerHandle = null; } } private void OnBodyChanged() { if (currentTimerHandle.HasValue) { RoR2Application.fixedTimeTimers.RemoveTimer(currentTimerHandle.Value); currentTimerHandle = null; } if ((bool)localUser.cachedBody) { currentTimerHandle = RoR2Application.fixedTimeTimers.CreateTimer(1f, OnTimer); } } private void OnTimer() { currentTimerHandle = null; ForceInitializeEntityStateMachines(localUser.cachedBody); } private static void ForceInitializeEntityStateMachines(CharacterBody characterBody) { if (!characterBody) { return; } EntityStateMachine[] components = characterBody.GetComponents(); for (int i = 0; i < components.Length; i++) { EntityStateMachine entityStateMachine = components[i]; if (!entityStateMachine.HasPendingState() && entityStateMachine.state is Uninitialized) { EntityState entityState = EntityStateCatalog.InstantiateState(ref entityStateMachine.mainStateType); if (entityState != null) { UnityEngine.Debug.LogFormat("Setting {0} uninitialized state machine [{1}] next state to {2}", characterBody.name, i, entityState.GetType().Name); entityStateMachine.SetInterruptState(entityState, InterruptPriority.Any); } } } } } private static readonly Dictionary watchers = new Dictionary(); [SystemInitializer(new Type[] { })] private static void Init() { LocalUserManager.onUserSignIn += OnUserSignIn; LocalUserManager.onUserSignOut += OnUserSignOut; } private static void OnUserSignIn(LocalUser localUser) { Watcher watcher = new Watcher { localUser = localUser }; watchers[localUser] = watcher; watcher.OnInstall(); } private static void OnUserSignOut(LocalUser localUser) { Watcher watcher = watchers[localUser]; watcher.OnUninstall(); watcher.localUser = null; watchers.Remove(localUser); } } [CreateAssetMenu(menuName = "RoR2/DropTables/BasicPickupDropTable")] public class BasicPickupDropTable : PickupDropTable { public ItemTag[] requiredItemTags = Array.Empty(); public ItemTag[] bannedItemTags = Array.Empty(); public float tier1Weight = 0.8f; public float tier2Weight = 0.2f; public float tier3Weight = 0.01f; public float bossWeight; public float lunarEquipmentWeight; public float lunarItemWeight; public float lunarCombinedWeight; public float equipmentWeight; public float voidTier1Weight; public float voidTier2Weight; public float voidTier3Weight; public float voidBossWeight; private readonly WeightedSelection selector = new WeightedSelection(); protected override void Regenerate(Run run) { GenerateWeightedSelection(run); } public void RegenerateDropTable(Run run) { GenerateWeightedSelection(run); } public bool IsFilterRequired() { if (requiredItemTags.Length == 0) { return bannedItemTags.Length != 0; } return true; } public bool PassesFilter(PickupIndex pickupIndex) { PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef.itemIndex != ItemIndex.None) { ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex); ItemTag[] array = requiredItemTags; foreach (ItemTag value in array) { if (Array.IndexOf(itemDef.tags, value) == -1) { return false; } } array = bannedItemTags; foreach (ItemTag value2 in array) { if (Array.IndexOf(itemDef.tags, value2) != -1) { return false; } } } return true; } private void Add(List sourceDropList, float chance) { if (chance <= 0f || sourceDropList.Count == 0) { return; } foreach (PickupIndex sourceDrop in sourceDropList) { if (!IsFilterRequired() || PassesFilter(sourceDrop)) { selector.AddChoice(sourceDrop, chance); } } } private void GenerateWeightedSelection(Run run) { selector.Clear(); Add(run.availableTier1DropList, tier1Weight); Add(run.availableTier2DropList, tier2Weight); Add(run.availableTier3DropList, tier3Weight); Add(run.availableBossDropList, bossWeight); Add(run.availableLunarItemDropList, lunarItemWeight); Add(run.availableLunarEquipmentDropList, lunarEquipmentWeight); Add(run.availableLunarCombinedDropList, lunarCombinedWeight); Add(run.availableEquipmentDropList, equipmentWeight); Add(run.availableVoidTier1DropList, voidTier1Weight); Add(run.availableVoidTier2DropList, voidTier2Weight); Add(run.availableVoidTier3DropList, voidTier3Weight); Add(run.availableVoidBossDropList, voidBossWeight); } protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng) { return PickupDropTable.GenerateDropFromWeightedSelection(rng, selector); } public override int GetPickupCount() { return selector.Count; } protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng) { return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, selector); } } public class BlastAttack { public enum FalloffModel { None, Linear, SweetSpot } public enum LoSType { None, NearestHit } public struct HitPoint { public HurtBox hurtBox; public UnityEngine.Vector3 hitPosition; public UnityEngine.Vector3 hitNormal; public float distanceSqr; } public struct Result { public int hitCount; public HitPoint[] hitPoints; } private struct BlastAttackDamageInfo { public GameObject attacker; public GameObject inflictor; public bool crit; public float damage; public DamageColorIndex damageColorIndex; public HurtBox.DamageModifier damageModifier; public DamageTypeCombo damageType; public UnityEngine.Vector3 force; public UnityEngine.Vector3 position; public ProcChainMask procChainMask; public float procCoefficient; public HealthComponent hitHealthComponent; public bool canRejectForce; public void Write(NetworkWriter writer) { writer.Write(attacker); writer.Write(inflictor); writer.Write(crit); writer.Write(damage); writer.Write(damageColorIndex); writer.Write((byte)damageModifier); writer.WriteDamageType(damageType); writer.Write(force); writer.Write(position); writer.Write(procChainMask); writer.Write(procCoefficient); writer.Write(hitHealthComponent.netId); writer.Write(canRejectForce); } public void Read(NetworkReader reader) { attacker = reader.ReadGameObject(); inflictor = reader.ReadGameObject(); crit = reader.ReadBoolean(); damage = reader.ReadSingle(); damageColorIndex = reader.ReadDamageColorIndex(); damageModifier = (HurtBox.DamageModifier)reader.ReadByte(); damageType = reader.ReadDamageType(); force = reader.ReadVector3(); position = reader.ReadVector3(); procChainMask = reader.ReadProcChainMask(); procCoefficient = reader.ReadSingle(); GameObject gameObject = reader.ReadGameObject(); hitHealthComponent = (gameObject ? gameObject.GetComponent() : null); canRejectForce = reader.ReadBoolean(); } } public GameObject attacker; public GameObject inflictor; public TeamIndex teamIndex; public AttackerFiltering attackerFiltering; public UnityEngine.Vector3 position; public float radius; public FalloffModel falloffModel = FalloffModel.Linear; public float baseDamage; public float baseForce; public UnityEngine.Vector3 bonusForce; public bool crit; public DamageTypeCombo damageType = DamageType.Generic; public DamageColorIndex damageColorIndex; public LoSType losType; public EffectIndex impactEffect = EffectIndex.Invalid; public bool canRejectForce = true; public ProcChainMask procChainMask; public float procCoefficient = 1f; private static readonly int initialBufferSize = 256; private static HitPoint[] hitPointsBuffer = new HitPoint[initialBufferSize]; private static int[] hitOrderBuffer = new int[initialBufferSize]; private static HealthComponent[] encounteredHealthComponentsBuffer = new HealthComponent[initialBufferSize]; public static event Action BlastAttackMultiHit; public Result Fire() { HitPoint[] array = CollectHits(); HandleHits(array); Result result = default(Result); result.hitCount = array.Length; result.hitPoints = array; return result; } [NetworkMessageHandler(msgType = 75, client = false, server = true)] private static void HandleReportBlastAttackDamage(NetworkMessage netMsg) { NetworkReader reader = netMsg.reader; BlastAttackDamageInfo blastAttackDamageInfo = default(BlastAttackDamageInfo); blastAttackDamageInfo.Read(reader); PerformDamageServer(in blastAttackDamageInfo); } public void Reset() { attacker = null; inflictor = null; teamIndex = TeamIndex.Neutral; position = UnityEngine.Vector3.zero; radius = 0f; falloffModel = FalloffModel.Linear; baseDamage = 0f; baseForce = 0f; bonusForce = UnityEngine.Vector3.zero; crit = false; damageType = DamageType.Generic; damageColorIndex = DamageColorIndex.Default; procChainMask.mask = 0u; procCoefficient = 1f; canRejectForce = true; } private HitPoint[] CollectHits() { UnityEngine.Vector3 vector = position; Collider[] array = Physics.OverlapSphere(vector, radius, LayerIndex.entityPrecise.mask); int num = array.Length; int count = 0; int encounteredHealthComponentsLength = 0; int hitOrderBufferLength = 0; ArrayUtils.EnsureCapacity(ref hitPointsBuffer, num); ArrayUtils.EnsureCapacity(ref hitOrderBuffer, num); ArrayUtils.EnsureCapacity(ref encounteredHealthComponentsBuffer, num); for (int i = 0; i < num; i++) { Collider collider = array[i]; HurtBox component = collider.GetComponent(); if (!component) { continue; } HealthComponent healthComponent2 = component.healthComponent; if (!healthComponent2) { continue; } bool flag = true; switch (attackerFiltering) { case AttackerFiltering.Default: flag = true; break; case AttackerFiltering.AlwaysHitSelf: flag = true; if (healthComponent2.gameObject == attacker) { flag = false; } break; case AttackerFiltering.AlwaysHit: flag = false; break; case AttackerFiltering.NeverHitSelf: flag = true; if (healthComponent2.gameObject == attacker) { continue; } break; } if (!flag || FriendlyFireManager.ShouldSplashHitProceed(healthComponent2, teamIndex)) { UnityEngine.Vector3 vector2 = collider.transform.position; UnityEngine.Vector3 hitNormal = vector - vector2; float sqrMagnitude = hitNormal.sqrMagnitude; hitPointsBuffer[count++] = new HitPoint { hurtBox = component, hitPosition = vector2, hitNormal = hitNormal, distanceSqr = sqrMagnitude }; } } if (true) { for (int j = 0; j < count; j++) { ref HitPoint reference = ref hitPointsBuffer[j]; if ((object)reference.hurtBox != null && reference.distanceSqr > 0f && reference.hurtBox.collider.Raycast(new Ray(vector, -reference.hitNormal), out var hitInfo, radius)) { reference.distanceSqr = (vector - hitInfo.point).sqrMagnitude; reference.hitPosition = hitInfo.point; reference.hitNormal = hitInfo.normal; } } } hitOrderBufferLength = count; for (int k = 0; k < count; k++) { hitOrderBuffer[k] = k; } for (int l = 1; l < count; l++) { int num2 = l; while (num2 > 0 && hitPointsBuffer[hitOrderBuffer[num2 - 1]].distanceSqr > hitPointsBuffer[hitOrderBuffer[num2]].distanceSqr) { int num3 = hitOrderBuffer[num2 - 1]; hitOrderBuffer[num2 - 1] = hitOrderBuffer[num2]; hitOrderBuffer[num2] = num3; num2--; } } bool flag2 = losType == LoSType.None || losType == LoSType.NearestHit; for (int m = 0; m < hitOrderBufferLength; m++) { int num4 = hitOrderBuffer[m]; ref HitPoint reference2 = ref hitPointsBuffer[num4]; HealthComponent healthComponent3 = reference2.hurtBox.healthComponent; if (!EntityIsMarkedEncountered(healthComponent3)) { MarkEntityAsEncountered(healthComponent3); } else if (flag2) { reference2.hurtBox = null; } } ClearEncounteredEntities(); CondenseHitOrderBuffer(); LoSType loSType = losType; if (loSType != 0 && loSType == LoSType.NearestHit) { NativeArray commands = new NativeArray(hitOrderBufferLength, Allocator.TempJob); NativeArray results = new NativeArray(hitOrderBufferLength, Allocator.TempJob); int n = 0; int num5 = 0; for (; n < hitOrderBufferLength; n++) { int num6 = hitOrderBuffer[n]; ref HitPoint reference3 = ref hitPointsBuffer[num6]; commands[num5++] = new RaycastCommand(vector, reference3.hitPosition - vector, Mathf.Sqrt(reference3.distanceSqr), LayerIndex.world.mask); } bool queriesHitTriggers = Physics.queriesHitTriggers; Physics.queriesHitTriggers = true; RaycastCommand.ScheduleBatch(commands, results, 1).Complete(); Physics.queriesHitTriggers = queriesHitTriggers; int num7 = 0; int num8 = 0; for (; num7 < hitOrderBufferLength; num7++) { int num9 = hitOrderBuffer[num7]; ref HitPoint reference4 = ref hitPointsBuffer[num9]; if ((object)reference4.hurtBox != null && (bool)results[num8++].collider) { reference4.hurtBox = null; } } results.Dispose(); commands.Dispose(); CondenseHitOrderBuffer(); } HitPoint[] array2 = new HitPoint[hitOrderBufferLength]; for (int num10 = 0; num10 < hitOrderBufferLength; num10++) { int num11 = hitOrderBuffer[num10]; array2[num10] = hitPointsBuffer[num11]; } ArrayUtils.Clear(hitPointsBuffer, ref count); ClearEncounteredEntities(); return array2; void ClearEncounteredEntities() { Array.Clear(encounteredHealthComponentsBuffer, 0, encounteredHealthComponentsLength); encounteredHealthComponentsLength = 0; } void CondenseHitOrderBuffer() { for (int num12 = 0; num12 < hitOrderBufferLength; num12++) { int num13 = 0; for (int num14 = num12; num14 < hitOrderBufferLength; num14++) { int num15 = hitOrderBuffer[num14]; if ((object)hitPointsBuffer[num15].hurtBox != null) { break; } num13++; } if (num13 > 0) { ArrayUtils.ArrayRemoveAt(hitOrderBuffer, ref hitOrderBufferLength, num12, num13); } } } bool EntityIsMarkedEncountered(HealthComponent healthComponent) { for (int num16 = 0; num16 < encounteredHealthComponentsLength; num16++) { if ((object)encounteredHealthComponentsBuffer[num16] == healthComponent) { return true; } } return false; } void MarkEntityAsEncountered(HealthComponent healthComponent) { encounteredHealthComponentsBuffer[encounteredHealthComponentsLength++] = healthComponent; } } private void HandleHits(HitPoint[] hitPoints) { UnityEngine.Vector3 vector = position; for (int i = 0; i < hitPoints.Length; i++) { HitPoint hitPoint = hitPoints[i]; float num = Mathf.Sqrt(hitPoint.distanceSqr); float num2 = 0f; UnityEngine.Vector3 vector2 = ((num > 0f) ? ((hitPoint.hitPosition - vector) / num) : UnityEngine.Vector3.zero); HealthComponent healthComponent = (hitPoint.hurtBox ? hitPoint.hurtBox.healthComponent : null); if ((bool)healthComponent) { switch (falloffModel) { case FalloffModel.None: num2 = 1f; break; case FalloffModel.Linear: num2 = 1f - Mathf.Clamp01(num / radius); break; case FalloffModel.SweetSpot: num2 = 1f - ((num > radius / 2f) ? 0.75f : 0f); break; } BlastAttackDamageInfo blastAttackDamageInfo = default(BlastAttackDamageInfo); blastAttackDamageInfo.attacker = attacker; blastAttackDamageInfo.inflictor = inflictor; blastAttackDamageInfo.crit = crit; blastAttackDamageInfo.damage = baseDamage * num2; blastAttackDamageInfo.damageColorIndex = damageColorIndex; blastAttackDamageInfo.damageModifier = hitPoint.hurtBox.damageModifier; blastAttackDamageInfo.damageType = damageType | DamageType.AOE; blastAttackDamageInfo.force = bonusForce * num2 + baseForce * num2 * vector2; blastAttackDamageInfo.position = hitPoint.hitPosition; blastAttackDamageInfo.procChainMask = procChainMask; blastAttackDamageInfo.procCoefficient = procCoefficient; blastAttackDamageInfo.hitHealthComponent = healthComponent; blastAttackDamageInfo.canRejectForce = canRejectForce; BlastAttackDamageInfo blastAttackDamageInfo2 = blastAttackDamageInfo; if (NetworkServer.active) { PerformDamageServer(in blastAttackDamageInfo2); } else { ClientReportDamage(in blastAttackDamageInfo2); } if (impactEffect != EffectIndex.Invalid) { EffectData effectData = new EffectData(); effectData.origin = hitPoint.hitPosition; effectData.rotation = UnityEngine.Quaternion.LookRotation(-vector2); EffectManager.SpawnEffect(impactEffect, effectData, transmit: true); } } } BlastAttack.BlastAttackMultiHit?.Invoke(hitPoints, attacker); } private static void ClientReportDamage(in BlastAttackDamageInfo blastAttackDamageInfo) { NetworkWriter networkWriter = new NetworkWriter(); networkWriter.StartMessage(75); blastAttackDamageInfo.Write(networkWriter); networkWriter.FinishMessage(); PlatformSystems.networkManager.client.connection.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal); } private static void PerformDamageServer(in BlastAttackDamageInfo blastAttackDamageInfo) { if ((bool)blastAttackDamageInfo.hitHealthComponent) { DamageInfo damageInfo = new DamageInfo(); damageInfo.attacker = blastAttackDamageInfo.attacker; damageInfo.inflictor = blastAttackDamageInfo.inflictor; damageInfo.damage = blastAttackDamageInfo.damage; damageInfo.crit = blastAttackDamageInfo.crit; damageInfo.force = blastAttackDamageInfo.force; damageInfo.procChainMask = blastAttackDamageInfo.procChainMask; damageInfo.procCoefficient = blastAttackDamageInfo.procCoefficient; damageInfo.damageType = blastAttackDamageInfo.damageType; damageInfo.damageColorIndex = blastAttackDamageInfo.damageColorIndex; damageInfo.position = blastAttackDamageInfo.position; damageInfo.canRejectForce = blastAttackDamageInfo.canRejectForce; damageInfo.ModifyDamageInfo(blastAttackDamageInfo.damageModifier); blastAttackDamageInfo.hitHealthComponent.TakeDamage(damageInfo); GlobalEventManager.instance.OnHitEnemy(damageInfo, blastAttackDamageInfo.hitHealthComponent.gameObject); GlobalEventManager.instance.OnHitAll(damageInfo, blastAttackDamageInfo.hitHealthComponent.gameObject); } } } public class DustStreakManager : MonoBehaviour { public GameObject dustStreakPrefab; public float timeBetweenStreaksMin; public float timeBetweenStreaksMax; private float streakTimer; public List dustStreakLocations = new List(); private int streakNum; private bool startDustStreaks; private void Start() { streakTimer = UnityEngine.Random.Range(timeBetweenStreaksMin, timeBetweenStreaksMax); startDustStreaks = true; } private void FixedUpdate() { if (startDustStreaks) { streakTimer -= Time.deltaTime; if (streakTimer <= 0f) { streakTimer = UnityEngine.Random.Range(timeBetweenStreaksMin, timeBetweenStreaksMax); streakNum = UnityEngine.Random.Range(0, dustStreakLocations.Count); EffectManager.SimpleEffect(dustStreakPrefab, dustStreakLocations[streakNum].position, dustStreakPrefab.transform.rotation, transmit: true); } } } } public class NoGravZone : MonoBehaviour { public void OnTriggerEnter(Collider other) { ICharacterGravityParameterProvider component = other.GetComponent(); if (component != null) { CharacterGravityParameters gravityParameters = component.gravityParameters; gravityParameters.environmentalAntiGravityGranterCount++; component.gravityParameters = gravityParameters; } ICharacterFlightParameterProvider component2 = other.GetComponent(); if (component2 != null) { CharacterFlightParameters flightParameters = component2.flightParameters; flightParameters.channeledFlightGranterCount++; component2.flightParameters = flightParameters; } } public void OnTriggerExit(Collider other) { ICharacterFlightParameterProvider component = other.GetComponent(); if (component != null) { CharacterFlightParameters flightParameters = component.flightParameters; flightParameters.channeledFlightGranterCount--; component.flightParameters = flightParameters; } ICharacterGravityParameterProvider component2 = other.GetComponent(); if (component2 != null) { CharacterGravityParameters gravityParameters = component2.gravityParameters; gravityParameters.environmentalAntiGravityGranterCount--; component2.gravityParameters = gravityParameters; } } } public enum BodyIndex { None = -1 } public static class BodyCatalog { public static class SpecialCases { private static BodyIndex chief = BodyIndex.None; private static BodyIndex railgunner = BodyIndex.None; private static BodyIndex heretic = BodyIndex.None; public static BodyIndex Chief() { if (chief == BodyIndex.None) { chief = FindBodyIndex("ChefBody"); } return chief; } public static BodyIndex RailGunner() { if (railgunner == BodyIndex.None) { railgunner = FindBodyIndex("RailgunnerBody"); } return railgunner; } public static BodyIndex HereticBody() { if (heretic == BodyIndex.None) { heretic = FindBodyIndex("HereticBody"); } return heretic; } } public static ResourceAvailability availability = default(ResourceAvailability); private static string[] bodyNames; private static GameObject[] bodyPrefabs; private static CharacterBody[] bodyPrefabBodyComponents; private static Component[][] bodyComponents; private static GenericSkill[][] skillSlots; private static SkinDef[][] skins; private static readonly Dictionary nameToIndexMap = new Dictionary(); private static Texture2D defaultPortraitIcon; public static int bodyCount { get; private set; } public static IEnumerable allBodyPrefabs => bodyPrefabs; public static IEnumerable allBodyPrefabBodyBodyComponents => bodyPrefabBodyComponents; [Obsolete("Use IContentPackProvider instead.")] public static event Action> getAdditionalEntries { add { LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.BodyCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.bodyPrefabs); } remove { } } public static GameObject GetBodyPrefab(BodyIndex bodyIndex) { return ArrayUtils.GetSafe(bodyPrefabs, (int)bodyIndex); } [CanBeNull] public static CharacterBody GetBodyPrefabBodyComponent(BodyIndex bodyIndex) { return ArrayUtils.GetSafe(bodyPrefabBodyComponents, (int)bodyIndex); } public static string GetBodyName(BodyIndex bodyIndex) { return ArrayUtils.GetSafe(bodyNames, (int)bodyIndex); } public static BodyIndex FindBodyIndex([NotNull] string bodyName) { if (nameToIndexMap.TryGetValue(bodyName, out var value)) { return value; } return BodyIndex.None; } public static BodyIndex FindBodyIndexCaseInsensitive([NotNull] string bodyName) { for (BodyIndex bodyIndex = (BodyIndex)0; (int)bodyIndex < bodyPrefabs.Length; bodyIndex++) { if (string.Compare(bodyPrefabs[(int)bodyIndex].name, bodyName, StringComparison.OrdinalIgnoreCase) == 0) { return bodyIndex; } } return BodyIndex.None; } public static BodyIndex FindBodyIndex(GameObject bodyObject) { return FindBodyIndex(bodyObject ? bodyObject.GetComponent() : null); } public static BodyIndex FindBodyIndex(CharacterBody characterBody) { return characterBody?.bodyIndex ?? BodyIndex.None; } [CanBeNull] public static GameObject FindBodyPrefab([NotNull] string bodyName) { BodyIndex bodyIndex = FindBodyIndex(bodyName); if (bodyIndex != BodyIndex.None) { return GetBodyPrefab(bodyIndex); } return null; } [CanBeNull] public static GameObject FindBodyPrefab(CharacterBody characterBody) { return GetBodyPrefab(FindBodyIndex(characterBody)); } [CanBeNull] public static GameObject FindBodyPrefab(GameObject characterBodyObject) { return GetBodyPrefab(FindBodyIndex(characterBodyObject)); } [CanBeNull] public static GenericSkill[] GetBodyPrefabSkillSlots(BodyIndex bodyIndex) { return ArrayUtils.GetSafe(skillSlots, (int)bodyIndex); } public static SkinDef[] GetBodySkins(BodyIndex bodyIndex) { SkinDef[][] array = skins; SkinDef[] defaultValue = Array.Empty(); return ArrayUtils.GetSafe(array, (int)bodyIndex, in defaultValue); } [SystemInitializer(new Type[] { })] public static IEnumerator Init() { AsyncOperationHandle mysteryIconHandler = LegacyResourcesAPI.LoadAsync("Textures/MiscIcons/texMysteryIcon"); while (!mysteryIconHandler.IsDone) { yield return null; } defaultPortraitIcon = mysteryIconHandler.Result; SetBodyPrefabs(ContentManager.bodyPrefabs); availability.MakeAvailable(); } private static void SetBodyPrefabs([NotNull] GameObject[] newBodyPrefabs) { bodyPrefabs = ArrayUtils.Clone(newBodyPrefabs); Array.Sort(bodyPrefabs, (GameObject a, GameObject b) => string.CompareOrdinal(a.name, b.name)); bodyPrefabBodyComponents = new CharacterBody[bodyPrefabs.Length]; bodyNames = new string[bodyPrefabs.Length]; bodyComponents = new Component[bodyPrefabs.Length][]; skillSlots = new GenericSkill[bodyPrefabs.Length][]; skins = new SkinDef[bodyPrefabs.Length][]; nameToIndexMap.Clear(); for (BodyIndex bodyIndex = (BodyIndex)0; (int)bodyIndex < bodyPrefabs.Length; bodyIndex++) { GameObject gameObject = bodyPrefabs[(int)bodyIndex]; string name = gameObject.name; bodyNames[(int)bodyIndex] = name; bodyComponents[(int)bodyIndex] = gameObject.GetComponents(); skillSlots[(int)bodyIndex] = gameObject.GetComponents(); nameToIndexMap.Add(name, bodyIndex); nameToIndexMap.Add(name + "(Clone)", bodyIndex); CharacterBody characterBody = (bodyPrefabBodyComponents[(int)bodyIndex] = gameObject.GetComponent()); characterBody.bodyIndex = bodyIndex; BodyIndex _temporaryBodyIndex = bodyIndex; AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Textures/BodyIcons/" + name); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { FinishAsyncLoads(_temporaryBodyIndex, x.Result); }; skins[(int)bodyIndex] = gameObject.GetComponent()?.modelTransform?.GetComponent()?.skins ?? Array.Empty(); if (string.IsNullOrEmpty(characterBody.baseNameToken)) { characterBody.baseNameToken = "UNIDENTIFIED"; } } bodyCount = bodyPrefabs.Length; } private static void FinishAsyncLoads(BodyIndex _bodyIndex, Texture2D tex) { CharacterBody characterBody = bodyPrefabBodyComponents[(int)_bodyIndex]; if ((bool)tex) { characterBody.portraitIcon = tex; } else if (characterBody.portraitIcon == null) { characterBody.portraitIcon = defaultPortraitIcon; } } private static IEnumerator GeneratePortraits(bool forceRegeneration) { UnityEngine.Debug.LogError("Starting portrait generation."); UnityEngine.Debug.Break(); ModelPanel modelPanel = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/UI/IconGenerator")).GetComponentInChildren(); yield return new WaitForEndOfFrame(); int i = 0; while (i < bodyPrefabs.Length) { CharacterBody characterBody = bodyPrefabBodyComponents[i]; if ((bool)characterBody && (forceRegeneration || IconIsNotSuitable(characterBody.portraitIcon))) { float num = 1f; try { UnityEngine.Debug.LogFormat("Generating portrait for {0}", bodyPrefabs[i].name); modelPanel.modelPrefab = bodyPrefabs[i].GetComponent()?.modelTransform.gameObject; modelPanel.SetAnglesForCharacterThumbnail(setZoom: true); PrintController printController = modelPanel.modelPrefab?.GetComponentInChildren(); if ((object)printController != null) { num = Mathf.Max(num, printController.printTime + 1f); } TemporaryOverlay temporaryOverlay = modelPanel.modelPrefab?.GetComponentInChildren(); if ((object)temporaryOverlay != null) { num = Mathf.Max(num, temporaryOverlay.durationInstance + 1f); } } catch (Exception) { } RoR2Application.onLateUpdate += UpdateCamera; yield return new WaitForSeconds(num); modelPanel.SetAnglesForCharacterThumbnail(setZoom: true); yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame(); try { Texture2D texture2D = new Texture2D(modelPanel.renderTexture.width, modelPanel.renderTexture.height, TextureFormat.ARGB32, mipChain: false, linear: false); RenderTexture active = RenderTexture.active; RenderTexture.active = modelPanel.renderTexture; texture2D.ReadPixels(new UnityEngine.Rect(0f, 0f, modelPanel.renderTexture.width, modelPanel.renderTexture.height), 0, 0, recalculateMipMaps: false); RenderTexture.active = active; byte[] array = texture2D.EncodeToPNG(); using FileStream fileStream = new FileStream("Assets/RoR2/GeneratedPortraits/" + bodyPrefabs[i].name + ".png", FileMode.Create, FileAccess.Write); fileStream.Write(array, 0, array.Length); } catch (Exception) { } RoR2Application.onLateUpdate -= UpdateCamera; yield return new WaitForEndOfFrame(); } int num2 = i + 1; i = num2; } UnityEngine.Object.Destroy(modelPanel.transform.root.gameObject); static bool IconIsNotSuitable(Texture texture) { if (!texture) { return true; } string name = texture.name; if (name == "texMysteryIcon" || name == "texNullIcon") { return true; } return false; } void UpdateCamera() { modelPanel.SetAnglesForCharacterThumbnail(setZoom: true); } } [ConCommand(commandName = "body_generate_portraits", flags = ConVarFlags.None, helpText = "Generates portraits for all bodies that are currently using the default.")] private static void CCBodyGeneratePortraits(ConCommandArgs args) { RoR2Application.instance.StartCoroutine(GeneratePortraits(args.TryGetArgBool(0).GetValueOrDefault())); } [ConCommand(commandName = "body_list", flags = ConVarFlags.None, helpText = "Prints a list of all character bodies in the game.")] private static void CCBodyList(ConCommandArgs args) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < bodyComponents.Length; i++) { stringBuilder.Append("[").Append(i).Append("]=") .Append(bodyNames[i]) .AppendLine(); } } [ConCommand(commandName = "body_reload_all", flags = ConVarFlags.Cheat, helpText = "Reloads all bodies and repopulates the BodyCatalog.")] private static void CCBodyReloadAll(ConCommandArgs args) { SetBodyPrefabs(Resources.LoadAll("Prefabs/CharacterBodies/")); } } public static class ConCommandArgExtensions { public abstract class BaseCharacterBodyInstanceSearchHandler { public abstract bool ShouldHandle(ConCommandArgs args, string argString); public abstract void GetResults(ConCommandArgs args, string argString, List dest); } public class NearestCharacterBodyInstanceSearchHandler : BaseCharacterBodyInstanceSearchHandler { public override bool ShouldHandle(ConCommandArgs args, string argString) { return argString.Equals("nearest", StringComparison.OrdinalIgnoreCase); } public override void GetResults(ConCommandArgs args, string argString, List dest) { CharacterBody senderBody = args.TryGetSenderBody(); if (!senderBody) { throw new ConCommandException($"Sender must have a valid body to use \"{argString}\"."); } UnityEngine.Vector3 myPosition = senderBody.corePosition; ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; dest.AddRange(from candidateBody in readOnlyInstancesList where (object)senderBody != candidateBody orderby (candidateBody.corePosition - myPosition).sqrMagnitude select candidateBody); } } public class SenderCharacterBodyInstanceSearchHandler : BaseCharacterBodyInstanceSearchHandler { public override bool ShouldHandle(ConCommandArgs args, string argString) { return argString.Equals("me", StringComparison.OrdinalIgnoreCase); } public override void GetResults(ConCommandArgs args, string argString, List dest) { CharacterBody characterBody = args.TryGetSenderBody(); if (!characterBody) { throw new ConCommandException($"Sender must have a valid body to use \"{argString}\"."); } dest.Add(characterBody); } } private static readonly BaseCharacterBodyInstanceSearchHandler[] finders = new BaseCharacterBodyInstanceSearchHandler[2] { new SenderCharacterBodyInstanceSearchHandler(), new NearestCharacterBodyInstanceSearchHandler() }; public static BodyIndex? TryGetArgBodyIndex(this ConCommandArgs args, int index) { if (index < args.userArgs.Count) { BodyIndex bodyIndex = BodyCatalog.FindBodyIndexCaseInsensitive(args[index]); if (bodyIndex != BodyIndex.None) { return bodyIndex; } } return null; } public static BodyIndex GetArgBodyIndex(this ConCommandArgs args, int index) { return args.TryGetArgBodyIndex(index) ?? throw new ConCommandException($"Argument {index} is not a valid body name."); } public static EquipmentIndex? TryGetArgEquipmentIndex(this ConCommandArgs args, int index) { string text = args.TryGetArgString(index); if (text != null) { EquipmentIndex equipmentIndex = EquipmentCatalog.FindEquipmentIndex(text); if (equipmentIndex != EquipmentIndex.None || text.Equals("None", StringComparison.Ordinal)) { return equipmentIndex; } } return null; } public static EquipmentIndex GetArgEquipmentIndex(this ConCommandArgs args, int index) { return args.TryGetArgEquipmentIndex(index) ?? throw new ConCommandException("No EquipmentIndex is defined for an equipment named '" + args.TryGetArgString(index) + "'. Use the \"equipment_list\" command to get a list of all valid equipment."); } public static void GetArgCharacterBodyInstances(this ConCommandArgs args, int argIndex, List dest) { if (argIndex >= args.userArgs.Count) { return; } string argString = args[argIndex]; args.TryGetSenderBody(); List list = CollectionPool>.RentCollection(); try { for (int i = 0; i < finders.Length; i++) { BaseCharacterBodyInstanceSearchHandler baseCharacterBodyInstanceSearchHandler = finders[i]; if (baseCharacterBodyInstanceSearchHandler.ShouldHandle(args, argString)) { baseCharacterBodyInstanceSearchHandler.GetResults(args, argString, list); dest.AddRange(list); break; } } } catch (ConCommandException ex) { throw new ConCommandException($"Argument {argIndex}: {ex.Message}"); } finally { list = CollectionPool>.ReturnCollection(list); } } public static void TryGetArgCharacterBodyInstances(this ConCommandArgs args, int argIndex, List dest) { try { args.GetArgCharacterBodyInstances(argIndex, dest); } catch (ConCommandException) { } } public static CharacterBody GetArgCharacterBodyInstance(this ConCommandArgs args, int argIndex) { List list = CollectionPool>.RentCollection(); try { args.GetArgCharacterBodyInstances(argIndex, list); return (list.Count > 0) ? list[0] : null; } finally { list = CollectionPool>.ReturnCollection(list); } } public static CharacterBody TryGetArgCharacterBodyInstance(this ConCommandArgs args, int argIndex) { try { return args.GetArgCharacterBodyInstance(argIndex); } catch (ConCommandException) { return null; } } public static CharacterMaster GetArgCharacterMasterInstance(this ConCommandArgs args, int argIndex) { CharacterBody argCharacterBodyInstance = args.GetArgCharacterBodyInstance(argIndex); if ((bool)argCharacterBodyInstance) { return argCharacterBodyInstance.master; } return null; } public static CharacterMaster TryGetArgCharacterMasterInstance(this ConCommandArgs args, int argIndex) { try { return args.GetArgCharacterMasterInstance(argIndex); } catch (ConCommandException) { return null; } } public static ItemIndex? TryGetArgItemIndex(this ConCommandArgs args, int index) { string text = args.TryGetArgString(index); if (text != null) { ItemIndex itemIndex = ItemCatalog.FindItemIndex(text); if (itemIndex != ItemIndex.None || text.Equals("None", StringComparison.Ordinal)) { return itemIndex; } } return null; } public static ItemIndex GetArgItemIndex(this ConCommandArgs args, int index) { return args.TryGetArgItemIndex(index) ?? throw new ConCommandException("No ItemIndex is defined for an item named '" + args.TryGetArgString(index) + "'. Use the \"item_list\" command to get a list of all valid items."); } public static MasterCatalog.MasterIndex? TryGetArgMasterIndex(this ConCommandArgs args, int argIndex) { if (argIndex < args.userArgs.Count) { string text = args[argIndex]; MasterCatalog.MasterIndex masterIndex = MasterCatalog.FindMasterIndex(text); if (masterIndex != MasterCatalog.MasterIndex.none || text.Equals("None", StringComparison.OrdinalIgnoreCase)) { return masterIndex; } } return null; } public static MasterCatalog.MasterIndex GetArgMasterIndex(this ConCommandArgs args, int index) { return args.TryGetArgMasterIndex(index) ?? throw new ConCommandException($"Argument {index} is not a valid character master prefab name."); } } public class BodySplitter { public CharacterBody body; public float moneyMultiplier; private int _count = 1; public readonly MasterSummon masterSummon; private Dictionary spawnedBodyVelocity = new Dictionary(); public int count { get { return _count; } set { if (value <= 0) { throw new ArgumentException("'value' cannot be non-positive.", "value"); } _count = value; } } public UnityEngine.Vector3 splinterInitialVelocityLocal { get; set; } = UnityEngine.Vector3.zero; public float minSpawnCircleRadius { get; set; } public BodySplitter() { masterSummon = new MasterSummon { masterPrefab = null, ignoreTeamMemberLimit = false, useAmbientLevel = null, teamIndexOverride = null }; } public void Perform() { PerformInternal(masterSummon); } private void PerformInternal(MasterSummon masterSummon) { if ((object)body == null) { throw new InvalidOperationException("'body' is null."); } if (!body) { throw new InvalidOperationException("'body' is an invalid object."); } GameObject masterPrefab = masterSummon.masterPrefab; CharacterMaster obj = masterPrefab.GetComponent() ?? throw new InvalidOperationException("'splinterMasterPrefab' does not have a CharacterMaster component."); if (!obj.masterIndex.isValid) { throw new InvalidOperationException("'splinterMasterPrefab' is not registered with MasterCatalog."); } if ((object)MasterCatalog.GetMasterPrefab(obj.masterIndex) != masterPrefab) { throw new InvalidOperationException("'splinterMasterPrefab' is not a prefab."); } UnityEngine.Vector3 position = body.transform.position; float y = UnityEngine.Quaternion.LookRotation(body.inputBank.aimDirection).eulerAngles.y; GameObject bodyPrefab = obj.bodyPrefab; bodyPrefab.GetComponent(); float num = CalcBodyXZRadius(bodyPrefab); float a = 0f; if (count > 1) { a = num / Mathf.Sin(MathF.PI / (float)count); } a = Mathf.Max(a, minSpawnCircleRadius); masterSummon.summonerBodyObject = body.gameObject; masterSummon.inventoryToCopy = body.inventory; masterSummon.loadout = (body.master ? body.master.loadout : null); masterSummon.inventoryItemCopyFilter = CopyItemFilter; foreach (float item in new DegreeSlices(count, 0.5f)) { UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(0f, y + item + 180f, 0f); UnityEngine.Vector3 vector = quaternion * UnityEngine.Vector3.forward; float num2 = a; if (Physics.Raycast(new Ray(position, vector), out var hitInfo, a + num, LayerIndex.world.intVal, QueryTriggerInteraction.Ignore)) { num2 = hitInfo.distance - num; } UnityEngine.Vector3 position2 = position + vector * num2; masterSummon.position = position2; masterSummon.rotation = quaternion; try { CharacterMaster characterMaster = masterSummon.Perform(); if ((bool)characterMaster) { CharacterBody characterBody = characterMaster.GetBody(); if ((bool)characterBody) { spawnedBodyVelocity.Add(characterBody, quaternion * splinterInitialVelocityLocal); characterMaster.money = (uint)Mathf.FloorToInt((float)body.master.money * moneyMultiplier); characterBody.characterMotor.onMotorStart += OnCharacterMotorStart; } } } catch (Exception message) { UnityEngine.Debug.LogError(message); } } } private void OnCharacterMotorStart(CharacterBody characterBody) { if (spawnedBodyVelocity.TryGetValue(characterBody, out var value)) { AddBodyVelocity(characterBody, value); } else { UnityEngine.Debug.LogError("Split characterBody has not stored split velocity"); } } private static float CalcBodyXZRadius(GameObject bodyPrefab) { Collider component = bodyPrefab.GetComponent(); if (!component) { return 0f; } UnityEngine.Vector3 position = bodyPrefab.transform.position; Bounds bounds = component.bounds; UnityEngine.Vector3 min = bounds.min; UnityEngine.Vector3 max = bounds.max; return Mathf.Max(Mathf.Max(Mathf.Max(Mathf.Max(0f, position.x - min.x), position.z - min.z), max.x - position.x), max.z - position.z); } private static void AddBodyVelocity(CharacterBody body, UnityEngine.Vector3 additionalVelocity) { IPhysMotor component = body.GetComponent(); if (component != null) { PhysForceInfo physForceInfo = PhysForceInfo.Create(); physForceInfo.force = additionalVelocity; physForceInfo.massIsOne = true; physForceInfo.ignoreGroundStick = true; physForceInfo.disableAirControlUntilCollision = false; component.ApplyForceImpulse(in physForceInfo); } } private static bool CopyItemFilter(ItemIndex itemIndex) { ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); if ((bool)itemDef) { return itemDef.tier == ItemTier.NoTier; } return false; } } public enum BuffIndex { None = -1 } public static class BuffCatalog { private static BuffDef[] buffDefs; public static BuffIndex[] eliteBuffIndices; public static BuffIndex[] debuffBuffIndices; public static BuffIndex[] nonHiddenBuffIndices; public static BuffIndex[] ignoreGrowthNectarIndices; private static readonly Dictionary nameToBuffIndex = new Dictionary(); [Obsolete("Use IContentPackProvider instead.")] public static readonly CatalogModHelperProxy modHelper = new CatalogModHelperProxy("RoR2.BuffCatalog.modHelper", LegacyModContentPackProvider.instance.registrationContentPack.buffDefs); public static int buffCount => buffDefs.Length; private static void RegisterBuff(BuffIndex buffIndex, BuffDef buffDef) { buffDef.buffIndex = buffIndex; nameToBuffIndex[buffDef.name] = buffIndex; } public static BuffDef GetBuffDef(BuffIndex buffIndex) { return ArrayUtils.GetSafe(buffDefs, (int)buffIndex); } public static BuffIndex FindBuffIndex(string buffName) { if (nameToBuffIndex.TryGetValue(buffName, out var value)) { return value; } return BuffIndex.None; } public static T[] GetPerBuffBuffer() { return new T[buffCount]; } [SystemInitializer(new Type[] { })] private static void Init() { SetBuffDefs(ContentManager.buffDefs); } private static void SetBuffDefs(BuffDef[] newBuffDefs) { nameToBuffIndex.Clear(); buffDefs = ArrayUtils.Clone(newBuffDefs); for (BuffIndex buffIndex = (BuffIndex)0; (int)buffIndex < buffDefs.Length; buffIndex++) { RegisterBuff(buffIndex, buffDefs[(int)buffIndex]); } eliteBuffIndices = (from buffDef in buffDefs where buffDef.isElite select buffDef.buffIndex).ToArray(); debuffBuffIndices = (from buffDef in buffDefs where buffDef.isDebuff select buffDef.buffIndex).ToArray(); nonHiddenBuffIndices = (from buffDef in buffDefs where !buffDef.isHidden select buffDef.buffIndex).ToArray(); ignoreGrowthNectarIndices = (from buffDef in buffDefs where buffDef.ignoreGrowthNectar select buffDef.buffIndex).ToArray(); } } public class BulletAttack { public enum FalloffModel { None, DefaultBullet, Buckshot } public delegate bool HitCallback(BulletAttack bulletAttack, ref BulletHit hitInfo); public delegate void ModifyOutgoingDamageCallback(BulletAttack bulletAttack, ref BulletHit hitInfo, DamageInfo damageInfo); public delegate bool FilterCallback(BulletAttack bulletAttack, ref BulletHit hitInfo); public class BulletHit { public UnityEngine.Vector3 direction; public UnityEngine.Vector3 point; public UnityEngine.Vector3 surfaceNormal; public float distance; public Collider collider; public HurtBox hitHurtBox; public GameObject entityObject; public HurtBox.DamageModifier damageModifier; public bool isSniperHit; public HurtBox hurtBox; public void Reset() { direction = UnityEngine.Vector3.zero; point = UnityEngine.Vector3.zero; surfaceNormal = UnityEngine.Vector3.zero; distance = 0f; collider = null; entityObject = null; damageModifier = HurtBox.DamageModifier.Normal; isSniperHit = false; hurtBox = null; } } public class BulletHitPool : GenericPool { protected override BulletHit CreateNewObject(bool inPoolEntry = true) { return new BulletHit(); } public void ReturnAllInUse() { if (_InUse != null) { for (int num = _InUse.Count - 1; num >= 0; num--) { ReturnObject(_InUse[num]); } } } } private static GameObject sniperTargetHitEffect; public GameObject owner; public GameObject weapon; public float damage = 1f; public bool isCrit; public float force = 1f; public ProcChainMask procChainMask; public float procCoefficient = 1f; public DamageTypeCombo damageType = DamageType.Generic; public DamageColorIndex damageColorIndex; public bool sniper; public FalloffModel falloffModel = FalloffModel.DefaultBullet; public GameObject tracerEffectPrefab; public GameObject hitEffectPrefab; public string muzzleName = ""; public bool HitEffectNormal = true; public UnityEngine.Vector3 origin; private UnityEngine.Vector3 _aimVector; private float _maxDistance = 200f; public float radius; public uint bulletCount = 1u; public float minSpread; public float maxSpread; public float spreadPitchScale = 1f; public float spreadYawScale = 1f; public QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.Ignore; private static readonly LayerMask defaultHitMask = (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask; public LayerMask hitMask = defaultHitMask; private static readonly LayerMask defaultStopperMask = defaultHitMask; public LayerMask stopperMask = defaultStopperMask; public bool smartCollision; public bool cheapMultiBullet; public float multiBulletOdds = 0.4f; public bool allowTrajectoryAimAssist = true; public float trajectoryAimAssistMultiplier = 1f; public HitCallback hitCallback; protected DamageInfo _dmgInfo; public static readonly HitCallback defaultHitCallback = DefaultHitCallbackImplementation; public ModifyOutgoingDamageCallback modifyOutgoingDamageCallback; private static NetworkWriter messageWriter = new NetworkWriter(); public FilterCallback filterCallback; public static readonly FilterCallback defaultFilterCallback = DefaultFilterCallbackImplementation; protected static BulletHitPool __BulletHitPool = null; protected static List _BulletHits = new List(); protected static List _IgnoreList = new List(); protected static HashSet _EncounteredEntityObjects = new HashSet(); protected static bool _UsePools = true; protected static EffectData _effectData = null; public UnityEngine.Vector3 aimVector { get { return _aimVector; } set { _aimVector = value; _aimVector.Normalize(); } } public float maxDistance { get { return _maxDistance; } set { if (!float.IsInfinity(value) && !float.IsNaN(value)) { _maxDistance = value; return; } UnityEngine.Debug.LogFormat("BulletAttack.maxDistance was assigned a value other than a finite number. value={0}", value); } } [Obsolete("Use .defaultHitCallback instead.", false)] public static HitCallback DefaultHitCallback => defaultHitCallback; [Obsolete("Use .defaultFilterCallback instead.", false)] public static FilterCallback DefaultFilterCallback => defaultFilterCallback; protected static BulletHitPool _BulletHitPool { get { if (__BulletHitPool == null) { __BulletHitPool = new BulletHitPool(); __BulletHitPool.AlwaysGrowable = true; __BulletHitPool.Initialize(20, 10); } return __BulletHitPool; } } public static bool UsePools => _UsePools; public BulletAttack() { filterCallback = defaultFilterCallback; hitCallback = defaultHitCallback; } [InitDuringStartup] private static void Init() { LegacyResourcesAPI.LoadAsyncCallback("Prefabs/Effects/ImpactEffects/SniperTargetHitEffect", delegate(GameObject operationResult) { sniperTargetHitEffect = operationResult; }); } public void Reset() { owner = null; weapon = null; damage = 1f; isCrit = false; force = 1f; procChainMask.mask = 0u; procCoefficient = 1f; damageType = DamageType.Generic; damageColorIndex = DamageColorIndex.Default; sniper = false; falloffModel = FalloffModel.DefaultBullet; tracerEffectPrefab = null; hitEffectPrefab = null; muzzleName = ""; HitEffectNormal = true; origin = UnityEngine.Vector3.zero; _aimVector = UnityEngine.Vector3.zero; _maxDistance = 200f; radius = 0f; bulletCount = 1u; minSpread = 0f; maxSpread = 0f; spreadPitchScale = 1f; spreadYawScale = 1f; queryTriggerInteraction = QueryTriggerInteraction.Ignore; hitMask = defaultHitMask; stopperMask = defaultStopperMask; smartCollision = false; cheapMultiBullet = false; filterCallback = defaultFilterCallback; hitCallback = defaultHitCallback; } private static void PlayHitEffect(BulletAttack bulletAttack, ref BulletHit hitInfo) { if ((bool)bulletAttack.hitEffectPrefab) { EffectManager.SimpleImpactEffect(bulletAttack.hitEffectPrefab, hitInfo.point, bulletAttack.HitEffectNormal ? hitInfo.surfaceNormal : (-hitInfo.direction), transmit: true); } if (hitInfo.isSniperHit && (object)sniperTargetHitEffect != null) { EffectData effectData = new EffectData { origin = hitInfo.point, rotation = UnityEngine.Quaternion.LookRotation(-hitInfo.direction) }; effectData.SetHurtBoxReference(hitInfo.hitHurtBox); EffectManager.SpawnEffect(sniperTargetHitEffect, effectData, transmit: true); } if ((bool)hitInfo.collider) { SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitInfo.collider, hitInfo.point); if ((bool)objectSurfaceDef && (bool)objectSurfaceDef.impactEffectPrefab) { EffectData effectData2 = new EffectData { origin = hitInfo.point, rotation = UnityEngine.Quaternion.LookRotation(hitInfo.surfaceNormal), color = objectSurfaceDef.approximateColor, surfaceDefIndex = objectSurfaceDef.surfaceDefIndex }; EffectManager.SpawnEffect(objectSurfaceDef.impactEffectPrefab, effectData2, transmit: true); } } } private static bool DefaultHitCallbackImplementation(BulletAttack bulletAttack, ref BulletHit hitInfo) { bool result = false; if ((bool)hitInfo.collider) { result = ((1 << hitInfo.collider.gameObject.layer) & (int)bulletAttack.stopperMask) == 0; } PlayHitEffect(bulletAttack, ref hitInfo); GameObject entityObject = hitInfo.entityObject; if ((bool)entityObject) { float num = CalcFalloffFactor(bulletAttack.falloffModel, hitInfo.distance); DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = bulletAttack.damage * num; damageInfo.crit = bulletAttack.isCrit; damageInfo.attacker = bulletAttack.owner; damageInfo.inflictor = bulletAttack.weapon; damageInfo.position = hitInfo.point; damageInfo.force = hitInfo.direction * (bulletAttack.force * num); damageInfo.procChainMask = bulletAttack.procChainMask; damageInfo.procCoefficient = bulletAttack.procCoefficient; damageInfo.damageType = bulletAttack.damageType; damageInfo.damageColorIndex = bulletAttack.damageColorIndex; damageInfo.ModifyDamageInfo(hitInfo.damageModifier); if (hitInfo.isSniperHit) { damageInfo.crit = true; damageInfo.damageColorIndex = DamageColorIndex.Sniper; } bulletAttack.modifyOutgoingDamageCallback?.Invoke(bulletAttack, ref hitInfo, damageInfo); TeamIndex attackerTeamIndex = TeamIndex.None; if ((bool)bulletAttack.owner) { TeamComponent component = bulletAttack.owner.GetComponent(); if ((bool)component) { attackerTeamIndex = component.teamIndex; } } HealthComponent healthComponent = null; if ((bool)hitInfo.hitHurtBox) { healthComponent = hitInfo.hitHurtBox.healthComponent; } bool flag = (bool)healthComponent && FriendlyFireManager.ShouldDirectHitProceed(healthComponent, attackerTeamIndex); if (NetworkServer.active) { if (flag) { healthComponent.TakeDamage(damageInfo); GlobalEventManager.instance.OnHitEnemy(damageInfo, hitInfo.entityObject); } GlobalEventManager.instance.OnHitAll(damageInfo, hitInfo.entityObject); } else if (ClientScene.ready) { messageWriter.StartMessage(53); int currentLogLevel = LogFilter.currentLogLevel; LogFilter.currentLogLevel = 4; messageWriter.Write(entityObject); LogFilter.currentLogLevel = currentLogLevel; messageWriter.Write(damageInfo); messageWriter.Write(flag); messageWriter.FinishMessage(); ClientScene.readyConnection.SendWriter(messageWriter, QosChannelIndex.defaultReliable.intVal); } } return result; } private static float CalcFalloffFactor(FalloffModel falloffModel, float distance) { return falloffModel switch { FalloffModel.DefaultBullet => 0.5f + Mathf.Clamp01(Mathf.InverseLerp(60f, 25f, distance)) * 0.5f, FalloffModel.Buckshot => 0.25f + Mathf.Clamp01(Mathf.InverseLerp(25f, 7f, distance)) * 0.75f, _ => 1f, }; } private static bool DefaultFilterCallbackImplementation(BulletAttack bulletAttack, ref BulletHit hitInfo) { HurtBox component = hitInfo.collider.GetComponent(); if ((bool)component && (bool)component.healthComponent && component.healthComponent.gameObject == bulletAttack.weapon) { return false; } return hitInfo.entityObject != bulletAttack.weapon; } private void InitBulletHitFromOriginHit(ref BulletHit bulletHit, UnityEngine.Vector3 direction, Collider hitCollider) { bulletHit.direction = direction; bulletHit.point = origin; bulletHit.surfaceNormal = -direction; bulletHit.distance = 0f; bulletHit.collider = hitCollider; HurtBox component = bulletHit.collider.GetComponent(); bulletHit.hitHurtBox = component; bulletHit.entityObject = (((bool)component && (bool)component.healthComponent) ? component.healthComponent.gameObject : bulletHit.collider.gameObject); bulletHit.damageModifier = (component ? component.damageModifier : HurtBox.DamageModifier.Normal); } private void InitBulletHitFromRaycastHit(ref BulletHit bulletHit, UnityEngine.Vector3 origin, UnityEngine.Vector3 direction, ref RaycastHit raycastHit) { bulletHit.direction = direction; bulletHit.surfaceNormal = raycastHit.normal; bulletHit.distance = raycastHit.distance; bulletHit.collider = raycastHit.collider; bulletHit.point = ((bulletHit.distance == 0f) ? origin : raycastHit.point); HurtBox component = bulletHit.collider.GetComponent(); bulletHit.hitHurtBox = component; bulletHit.entityObject = (((bool)component && (bool)component.healthComponent) ? component.healthComponent.gameObject : bulletHit.collider.gameObject); bulletHit.damageModifier = (component ? component.damageModifier : HurtBox.DamageModifier.Normal); } private bool ProcessHit(ref BulletHit hitInfo) { if (!filterCallback(this, ref hitInfo)) { return true; } if (sniper) { hitInfo.isSniperHit = IsSniperTargetHit(in hitInfo); } return hitCallback(this, ref hitInfo); } private static bool IsSniperTargetHit(in BulletHit hitInfo) { if ((bool)hitInfo.hitHurtBox && (bool)hitInfo.hitHurtBox.hurtBoxGroup) { HurtBox[] hurtBoxes = hitInfo.hitHurtBox.hurtBoxGroup.hurtBoxes; foreach (HurtBox hurtBox in hurtBoxes) { if ((bool)hurtBox && hurtBox.isSniperTarget && UnityEngine.Vector3.ProjectOnPlane(hitInfo.point - hurtBox.transform.position, hitInfo.direction).sqrMagnitude <= HurtBox.sniperTargetRadiusSqr) { return true; } } } return false; } private GameObject ProcessHitList(List hits, ref UnityEngine.Vector3 endPosition, List ignoreList) { int count = hits.Count; int[] array = new int[count]; for (int i = 0; i < count; i++) { array[i] = i; } for (int j = 0; j < count; j++) { float distance = maxDistance; int num = j; for (int k = j; k < count; k++) { int index = array[k]; if (hits[index].distance < distance) { distance = hits[index].distance; num = k; } } GameObject entityObject = hits[array[num]].entityObject; if (!ignoreList.Contains(entityObject)) { ignoreList.Add(entityObject); BulletHit hitInfo = hits[array[num]]; if (!ProcessHit(ref hitInfo)) { endPosition = hits[array[num]].point; return entityObject; } } array[num] = array[j]; } return null; } private static GameObject LookUpColliderEntityObject(Collider collider) { HurtBox component = collider.GetComponent(); if (!component || !component.healthComponent) { return collider.gameObject; } return component.healthComponent.gameObject; } private static Collider[] PhysicsOverlapPoint(UnityEngine.Vector3 point, int layerMask = -1, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.Ignore) { return Physics.OverlapBox(point, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity, layerMask, queryTriggerInteraction); } public void Fire() { if (allowTrajectoryAimAssist) { aimVector = TrajectoryAimAssist.ApplyTrajectoryAimAssist(aimVector, origin, maxDistance, owner, weapon, trajectoryAimAssistMultiplier); } UnityEngine.Vector3[] array = new UnityEngine.Vector3[bulletCount]; UnityEngine.Vector3 up = UnityEngine.Vector3.up; UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimVector); for (int i = 0; i < bulletCount; i++) { float x = UnityEngine.Random.Range(minSpread, maxSpread); float z = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward); float y = vector.y; vector.y = 0f; float angle = (Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f) * spreadYawScale; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f * spreadPitchScale; array[i] = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimVector); } int muzzleIndex = -1; if (!weapon) { weapon = owner; } if ((bool)weapon) { ModelLocator component = weapon.GetComponent(); if ((bool)component && (bool)component.modelTransform) { ChildLocator component2 = component.modelTransform.GetComponent(); if ((bool)component2) { muzzleIndex = component2.FindChildIndex(muzzleName); } } } UnityEngine.Vector3 axis2 = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, aimVector); UnityEngine.Vector3 forward = UnityEngine.Vector3.forward; if (cheapMultiBullet) { float x2 = UnityEngine.Random.Range(minSpread, maxSpread); float z2 = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 vector2 = UnityEngine.Quaternion.Euler(0f, 0f, z2) * (UnityEngine.Quaternion.Euler(x2, 0f, 0f) * UnityEngine.Vector3.forward); float y2 = vector2.y; vector2.y = 0f; float angle3 = (Mathf.Atan2(vector2.z, vector2.x) * 57.29578f - 90f) * spreadYawScale; float angle4 = Mathf.Atan2(y2, vector2.magnitude) * 57.29578f * spreadPitchScale; forward = UnityEngine.Quaternion.AngleAxis(angle3, UnityEngine.Vector3.up) * (UnityEngine.Quaternion.AngleAxis(angle4, axis2) * aimVector); FireMulti(forward, muzzleIndex); return; } for (int j = 0; j < bulletCount; j++) { float x3 = UnityEngine.Random.Range(minSpread, maxSpread); float z3 = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 vector3 = UnityEngine.Quaternion.Euler(0f, 0f, z3) * (UnityEngine.Quaternion.Euler(x3, 0f, 0f) * UnityEngine.Vector3.forward); float y3 = vector3.y; vector3.y = 0f; float angle5 = (Mathf.Atan2(vector3.z, vector3.x) * 57.29578f - 90f) * spreadYawScale; float angle6 = Mathf.Atan2(y3, vector3.magnitude) * 57.29578f * spreadPitchScale; forward = UnityEngine.Quaternion.AngleAxis(angle5, UnityEngine.Vector3.up) * (UnityEngine.Quaternion.AngleAxis(angle6, axis2) * aimVector); FireSingle(forward, muzzleIndex); } } public UnityEngine.Vector3 Fire_ReturnHit() { int muzzleIndex = -1; _ = origin; if (!weapon) { weapon = owner; } if ((bool)weapon) { ModelLocator component = weapon.GetComponent(); if ((bool)component && (bool)component.modelTransform) { ChildLocator component2 = component.modelTransform.GetComponent(); if ((bool)component2) { muzzleIndex = component2.FindChildIndex(muzzleName); } } } UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, aimVector); UnityEngine.Vector3 forward = UnityEngine.Vector3.forward; UnityEngine.Vector3 result = UnityEngine.Vector3.zero; for (int i = 0; i < bulletCount; i++) { float x = UnityEngine.Random.Range(minSpread, maxSpread); float z = UnityEngine.Random.Range(0f, 360f); UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward); float y = vector.y; vector.y = 0f; float angle = (Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f) * spreadYawScale; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f * spreadPitchScale; forward = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimVector); result = FireSingle_ReturnHit(forward, muzzleIndex); } return result; } public static void TogglePooling() { _UsePools = !_UsePools; UnityEngine.Debug.LogFormat("BulletAttack pooling {0}", _UsePools ? "ENABLED" : "DISABLED"); } public static void DumpPools() { UnityEngine.Debug.LogFormat("BulletAttack Pool: Pooled {0}, InUse {1}", _BulletHitPool.PoolCount(), _BulletHitPool.InUseCount()); } protected static BulletHit GetBulletHit() { BulletHit @object = _BulletHitPool.GetObject(); @object.Reset(); return @object; } private void FireSingle(UnityEngine.Vector3 normal, int muzzleIndex) { if (_UsePools) { float distance = maxDistance; UnityEngine.Vector3 endPosition = origin + normal * maxDistance; _BulletHits.Clear(); bool num = radius == 0f || smartCollision; bool flag = radius != 0f; if (smartCollision) { _EncounteredEntityObjects.Clear(); } if (num) { int num2 = 0; num2 = HGPhysics.RaycastAll(out var hits, origin, normal, distance, hitMask, queryTriggerInteraction); for (int i = 0; i < num2; i++) { BulletHit bulletHit = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit, origin, normal, ref hits[i]); _BulletHits.Add(bulletHit); if (smartCollision) { _EncounteredEntityObjects.Add(bulletHit.entityObject); } if (bulletHit.distance < distance) { distance = bulletHit.distance; } } HGPhysics.ReturnResults(hits); } if (flag) { LayerMask layerMask = hitMask; if (smartCollision) { layerMask = (int)layerMask & ~(int)LayerIndex.world.mask; } int num3 = 0; num3 = HGPhysics.SphereCastAll(out var hits2, origin, radius, normal, distance, layerMask, queryTriggerInteraction); for (int j = 0; j < num3; j++) { BulletHit bulletHit2 = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit2, origin, normal, ref hits2[j]); if (!smartCollision || !_EncounteredEntityObjects.Contains(bulletHit2.entityObject)) { _BulletHits.Add(bulletHit2); } } HGPhysics.ReturnResults(hits2); } _IgnoreList.Clear(); ProcessHitList(_BulletHits, ref endPosition, _IgnoreList); if ((bool)tracerEffectPrefab) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.Reset(); _effectData.origin = endPosition; _effectData.start = origin; _effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, _effectData, transmit: true); } _BulletHitPool.ReturnAllInUse(); _EncounteredEntityObjects.Clear(); return; } float distance2 = maxDistance; UnityEngine.Vector3 endPosition2 = origin + normal * maxDistance; List list = new List(); bool num4 = radius == 0f || smartCollision; bool flag2 = radius != 0f; HashSet hashSet = null; if (smartCollision) { hashSet = new HashSet(); } if (num4) { int num5 = 0; num5 = HGPhysics.RaycastAll(out var hits3, origin, normal, distance2, hitMask, queryTriggerInteraction); for (int k = 0; k < num5; k++) { BulletHit bulletHit3 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit3, origin, normal, ref hits3[k]); list.Add(bulletHit3); if (smartCollision) { hashSet.Add(bulletHit3.entityObject); } if (bulletHit3.distance < distance2) { distance2 = bulletHit3.distance; } } HGPhysics.ReturnResults(hits3); } if (flag2) { LayerMask layerMask2 = hitMask; if (smartCollision) { layerMask2 = (int)layerMask2 & ~(int)LayerIndex.world.mask; } int num6 = 0; num6 = HGPhysics.SphereCastAll(out var hits4, origin, radius, normal, distance2, layerMask2, queryTriggerInteraction); for (int l = 0; l < num6; l++) { BulletHit bulletHit4 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit4, origin, normal, ref hits4[l]); if (!smartCollision || !hashSet.Contains(bulletHit4.entityObject)) { list.Add(bulletHit4); } } HGPhysics.ReturnResults(hits4); } ProcessHitList(list, ref endPosition2, new List()); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = endPosition2, start = origin }; effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } } private void FireMulti(UnityEngine.Vector3 normal, int muzzleIndex) { if (_UsePools) { float distance = maxDistance; UnityEngine.Vector3 endPosition = origin + normal * maxDistance; _BulletHits.Clear(); bool num = radius == 0f || smartCollision; bool flag = radius != 0f; if (smartCollision) { _EncounteredEntityObjects.Clear(); } if (num) { int num2 = 0; num2 = HGPhysics.RaycastAll(out var hits, origin, normal, distance, hitMask, queryTriggerInteraction); for (int i = 0; i < num2; i++) { BulletHit bulletHit = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit, origin, normal, ref hits[i]); _BulletHits.Add(bulletHit); if (smartCollision) { _EncounteredEntityObjects.Add(bulletHit.entityObject); } if (bulletHit.distance < distance) { distance = bulletHit.distance; } } HGPhysics.ReturnResults(hits); } if (flag) { LayerMask layerMask = hitMask; if (smartCollision) { layerMask = (int)layerMask & ~(int)LayerIndex.world.mask; } int num3 = 0; num3 = HGPhysics.SphereCastAll(out var hits2, origin, radius, normal, distance, layerMask, queryTriggerInteraction); for (int j = 0; j < num3; j++) { BulletHit bulletHit2 = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit2, origin, normal, ref hits2[j]); if (!smartCollision || !_EncounteredEntityObjects.Contains(bulletHit2.entityObject)) { _BulletHits.Add(bulletHit2); } } HGPhysics.ReturnResults(hits2); } _IgnoreList.Clear(); ProcessHitList(_BulletHits, ref endPosition, _IgnoreList); if ((bool)tracerEffectPrefab) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.Reset(); _effectData.origin = endPosition; _effectData.start = origin; _effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, _effectData, transmit: true); } _BulletHitPool.ReturnAllInUse(); _EncounteredEntityObjects.Clear(); return; } float distance2 = maxDistance; UnityEngine.Vector3 endPosition2 = origin + normal * maxDistance; List list = new List(); bool num4 = radius == 0f || smartCollision; bool flag2 = radius != 0f; HashSet hashSet = null; if (smartCollision) { hashSet = new HashSet(); } if (num4) { int num5 = 0; num5 = HGPhysics.RaycastAll(out var hits3, origin, normal, distance2, hitMask, queryTriggerInteraction); for (int k = 0; k < num5; k++) { BulletHit bulletHit3 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit3, origin, normal, ref hits3[k]); list.Add(bulletHit3); if (smartCollision) { hashSet.Add(bulletHit3.entityObject); } if (bulletHit3.distance < distance2) { distance2 = bulletHit3.distance; } } HGPhysics.ReturnResults(hits3); } if (flag2) { LayerMask layerMask2 = hitMask; if (smartCollision) { layerMask2 = (int)layerMask2 & ~(int)LayerIndex.world.mask; } int num6 = 0; num6 = HGPhysics.SphereCastAll(out var hits4, origin, radius, normal, distance2, layerMask2, queryTriggerInteraction); for (int l = 0; l < num6; l++) { BulletHit bulletHit4 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit4, origin, normal, ref hits4[l]); if (!smartCollision || !hashSet.Contains(bulletHit4.entityObject)) { list.Add(bulletHit4); } } HGPhysics.ReturnResults(hits4); } ProcessHitList(list, ref endPosition2, new List()); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = endPosition2, start = origin }; effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } } private UnityEngine.Vector3 FireSingle_ReturnHit(UnityEngine.Vector3 normal, int muzzleIndex) { UnityEngine.Vector3 endPosition; if (_UsePools) { float distance = maxDistance; endPosition = origin + normal * maxDistance; _BulletHits.Clear(); bool num = radius == 0f || smartCollision; bool flag = radius != 0f; if (smartCollision) { _EncounteredEntityObjects.Clear(); } if (num) { int num2 = 0; num2 = HGPhysics.RaycastAll(out var hits, origin, normal, distance, hitMask, queryTriggerInteraction); for (int i = 0; i < num2; i++) { BulletHit bulletHit = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit, origin, normal, ref hits[i]); _BulletHits.Add(bulletHit); if (smartCollision) { _EncounteredEntityObjects.Add(bulletHit.entityObject); } if (bulletHit.distance < distance) { distance = bulletHit.distance; } } HGPhysics.ReturnResults(hits); } if (flag) { LayerMask layerMask = hitMask; if (smartCollision) { layerMask = (int)layerMask & ~(int)LayerIndex.world.mask; } int num3 = 0; num3 = HGPhysics.SphereCastAll(out var hits2, origin, radius, normal, distance, layerMask, queryTriggerInteraction); for (int j = 0; j < num3; j++) { BulletHit bulletHit2 = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit2, origin, normal, ref hits2[j]); if (!smartCollision || !_EncounteredEntityObjects.Contains(bulletHit2.entityObject)) { _BulletHits.Add(bulletHit2); } } HGPhysics.ReturnResults(hits2); } _IgnoreList.Clear(); ProcessHitList(_BulletHits, ref endPosition, _IgnoreList); if ((bool)tracerEffectPrefab) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.Reset(); _effectData.origin = endPosition; _effectData.start = origin; _effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, _effectData, transmit: true); } _BulletHitPool.ReturnAllInUse(); _EncounteredEntityObjects.Clear(); } else { float distance2 = maxDistance; endPosition = origin + normal * maxDistance; List list = new List(); bool num4 = radius == 0f || smartCollision; bool flag2 = radius != 0f; HashSet hashSet = null; if (smartCollision) { hashSet = new HashSet(); } if (num4) { int num5 = 0; num5 = HGPhysics.RaycastAll(out var hits3, origin, normal, distance2, hitMask, queryTriggerInteraction); for (int k = 0; k < num5; k++) { BulletHit bulletHit3 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit3, origin, normal, ref hits3[k]); list.Add(bulletHit3); if (smartCollision) { hashSet.Add(bulletHit3.entityObject); } if (bulletHit3.distance < distance2) { distance2 = bulletHit3.distance; } } HGPhysics.ReturnResults(hits3); } if (flag2) { LayerMask layerMask2 = hitMask; if (smartCollision) { layerMask2 = (int)layerMask2 & ~(int)LayerIndex.world.mask; } int num6 = 0; num6 = HGPhysics.SphereCastAll(out var hits4, origin, radius, normal, distance2, layerMask2, queryTriggerInteraction); for (int l = 0; l < num6; l++) { BulletHit bulletHit4 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit4, origin, normal, ref hits4[l]); if (!smartCollision || !hashSet.Contains(bulletHit4.entityObject)) { list.Add(bulletHit4); } } HGPhysics.ReturnResults(hits4); } ProcessHitList(list, ref endPosition, new List()); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = endPosition, start = origin }; effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } } return endPosition; } [NetworkMessageHandler(msgType = 53, server = true)] private static void HandleBulletDamage(NetworkMessage netMsg) { NetworkReader reader = netMsg.reader; GameObject gameObject = reader.ReadGameObject(); DamageInfo damageInfo = reader.ReadDamageInfo(); if (reader.ReadBoolean() && (bool)gameObject) { HealthComponent component = gameObject.GetComponent(); if ((bool)component) { component.TakeDamage(damageInfo); } GlobalEventManager.instance.OnHitEnemy(damageInfo, gameObject); } GlobalEventManager.instance.OnHitAll(damageInfo, gameObject); } } public class CallbackCheck where TResult : struct { public delegate void CallbackDelegate(TArg arg, ref TResult? resultOverride); private CallbackDelegate[] callbacks = Array.Empty(); private int callbackCount; public void AddCallback([NotNull] CallbackDelegate callback) { if (callbacks.Length <= callbackCount + 1) { Array.Resize(ref callbacks, callbackCount + 1); } callbacks[callbackCount++] = callback; } public void RemoveCallback([NotNull] CallbackDelegate callback) { for (int i = 0; i < callbackCount; i++) { if ((object)callbacks[i] == callback) { for (int num = callbackCount - 1; i < num; i++) { callbacks[i] = callbacks[i + 1]; } callbacks[--callbackCount] = null; break; } } } public void Clear() { Array.Clear(callbacks, 0, callbackCount); callbackCount = 0; } public TResult? Evaluate(TArg arg) { TResult? resultOverride = null; for (int i = 0; i < callbackCount; i++) { callbacks[i](arg, ref resultOverride); if (resultOverride.HasValue) { break; } } return resultOverride; } } public class CatalogModHelper { private readonly Action registrationDelegate; private readonly Func nameGetter; public event Action> getAdditionalEntries; public CatalogModHelper(Action registrationDelegate, Func nameGetter) { this.registrationDelegate = registrationDelegate; this.nameGetter = nameGetter; } public void CollectAndRegisterAdditionalEntries(ref TEntry[] entries) { int num = entries.Length; List list = new List(); this.getAdditionalEntries?.Invoke(list); list.Sort((TEntry a, TEntry b) => StringComparer.Ordinal.Compare(nameGetter(a), nameGetter(b))); Array.Resize(ref entries, entries.Length + list.Count); int i = 0; for (int count = list.Count; i < count; i++) { entries[num + i] = list[i]; registrationDelegate?.Invoke(num + i, list[i]); } } } public class CatalogModHelperProxy { private string name; private NamedAssetCollection dest; [Obsolete("Use IContentPackProvider instead.")] public event Action> getAdditionalEntries { add { LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries(name, value, dest); } remove { } } public CatalogModHelperProxy(string name, NamedAssetCollection dest) { this.name = name; this.dest = dest; } } public struct CharacterAnimatorWalkParamCalculator { private float animatorReferenceMagnitudeVelocity; private float animatorReferenceAngleVelocity; public UnityEngine.Vector2 animatorWalkSpeed { get; private set; } public float remainingTurnAngle { get; private set; } public void Update(UnityEngine.Vector3 worldMoveVector, UnityEngine.Vector3 animatorForward, in BodyAnimatorSmoothingParameters.SmoothingParameters smoothingParameters, float deltaTime) { UnityEngine.Vector3 rhs = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, animatorForward); float x = UnityEngine.Vector3.Dot(worldMoveVector, animatorForward); float y = UnityEngine.Vector3.Dot(worldMoveVector, rhs); UnityEngine.Vector2 to = new UnityEngine.Vector2(x, y); float magnitude = to.magnitude; float num = ((magnitude > 0f) ? UnityEngine.Vector2.SignedAngle(UnityEngine.Vector2.right, to) : 0f); float magnitude2 = animatorWalkSpeed.magnitude; float current = ((magnitude2 > 0f) ? UnityEngine.Vector2.SignedAngle(UnityEngine.Vector2.right, animatorWalkSpeed) : 0f); float num2 = Mathf.SmoothDamp(magnitude2, magnitude, ref animatorReferenceMagnitudeVelocity, smoothingParameters.walkMagnitudeSmoothDamp, float.PositiveInfinity, deltaTime); float num3 = Mathf.SmoothDampAngle(current, num, ref animatorReferenceAngleVelocity, smoothingParameters.walkAngleSmoothDamp, float.PositiveInfinity, deltaTime); remainingTurnAngle = num3 - num; animatorWalkSpeed = new UnityEngine.Vector2(Mathf.Cos(num3 * (MathF.PI / 180f)), Mathf.Sin(num3 * (MathF.PI / 180f))) * num2; } } public struct CharacterAnimParamAvailability { public bool isMoving; public bool turnAngle; public bool isGrounded; public bool mainRootPlaybackRate; public bool forwardSpeed; public bool rightSpeed; public bool upSpeed; public bool walkSpeed; public bool isSprinting; public static CharacterAnimParamAvailability FromAnimator(Animator animator) { AnimatorControllerParameter[] parameters = animator.parameters; CharacterAnimParamAvailability result = default(CharacterAnimParamAvailability); result.isMoving = Util.HasAnimationParameter(AnimationParameters.isMoving, parameters); result.turnAngle = Util.HasAnimationParameter(AnimationParameters.turnAngle, parameters); result.isGrounded = Util.HasAnimationParameter(AnimationParameters.isGrounded, parameters); result.mainRootPlaybackRate = Util.HasAnimationParameter(AnimationParameters.mainRootPlaybackRate, parameters); result.forwardSpeed = Util.HasAnimationParameter(AnimationParameters.forwardSpeed, parameters); result.rightSpeed = Util.HasAnimationParameter(AnimationParameters.rightSpeed, parameters); result.upSpeed = Util.HasAnimationParameter(AnimationParameters.upSpeed, parameters); result.walkSpeed = Util.HasAnimationParameter(AnimationParameters.walkSpeed, parameters); result.isSprinting = Util.HasAnimationParameter(AnimationParameters.isSprinting, parameters); return result; } } public class CharacterLosTracker : IDisposable { private struct BodyInfo { public bool hasLos; public Run.FixedTimeStamp lastChecked; } public UnityEngine.Vector3 origin; public int maxRaycastsPerStep = 4; private Dictionary bodyToBodyInfo = new Dictionary(); private bool _enabled; private int currentCheckedBodyIndex; public bool enabled { get { return _enabled; } set { if (_enabled != value) { _enabled = value; if (_enabled) { OnEnable(); } else { OnDisable(); } } } } public event Action onBodyDiscovered; public event Action onBodyLost; private void OnEnable() { CharacterBody.onBodyAwakeGlobal += OnBodyAwakeGlobal; CharacterBody.onBodyDestroyGlobal += OnBodyDestroyGlobal; ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { OnBodyDiscovered(readOnlyInstancesList[i]); } } private void OnDisable() { ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { OnBodyLost(readOnlyInstancesList[i]); } CharacterBody.onBodyDestroyGlobal -= OnBodyDestroyGlobal; CharacterBody.onBodyAwakeGlobal -= OnBodyAwakeGlobal; } private void OnBodyAwakeGlobal(CharacterBody characterBody) { OnBodyDiscovered(characterBody); } private void OnBodyDestroyGlobal(CharacterBody characterBody) { OnBodyLost(characterBody); } public void Step() { ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; if (readOnlyInstancesList.Count == 0) { return; } for (int i = 0; i < maxRaycastsPerStep; i++) { if (++currentCheckedBodyIndex >= readOnlyInstancesList.Count) { currentCheckedBodyIndex = 0; } CharacterBody characterBody = readOnlyInstancesList[currentCheckedBodyIndex]; if ((bool)characterBody.mainHurtBox) { UnityEngine.Vector3 position = characterBody.mainHurtBox.transform.position; BodyInfo value = bodyToBodyInfo[characterBody]; RaycastHit hitInfo; bool flag = Physics.Linecast(origin, position, out hitInfo, LayerIndex.world.mask, QueryTriggerInteraction.Ignore); value.hasLos = !flag; bodyToBodyInfo[characterBody] = value; } } } public bool CheckBodyHasLos(CharacterBody characterBody) { if (bodyToBodyInfo.TryGetValue(characterBody, out var value)) { return value.hasLos; } return false; } public void Dispose() { enabled = false; bodyToBodyInfo.Clear(); } private void OnBodyDiscovered(CharacterBody characterBody) { bodyToBodyInfo.Add(characterBody, new BodyInfo { hasLos = false, lastChecked = Run.FixedTimeStamp.now }); try { this.onBodyDiscovered?.Invoke(characterBody); } catch (Exception exception) { UnityEngine.Debug.LogException(exception); } } private void OnBodyLost(CharacterBody characterBody) { bodyToBodyInfo.Remove(characterBody); try { this.onBodyLost?.Invoke(characterBody); } catch (Exception exception) { UnityEngine.Debug.LogException(exception); } } } public static class Chat { public class UserChatMessage : ChatMessageBase { public GameObject sender; public string text; public override string ConstructChatString() { if ((bool)sender) { NetworkUser component = sender.GetComponent(); if ((bool)component) { return string.Format(CultureInfo.InvariantCulture, "{0}: {1}", Util.EscapeRichTextForTextMeshPro(component.userName), Util.EscapeRichTextForTextMeshPro(text)); } } return null; } public override void OnProcessed() { base.OnProcessed(); Util.PlaySound("Play_UI_chatMessage", RoR2Application.instance.gameObject); } public override void Serialize(NetworkWriter writer) { writer.Write(sender); writer.Write(text); } public override void Deserialize(NetworkReader reader) { sender = reader.ReadGameObject(); text = reader.ReadString(); } } public class NpcChatMessage : ChatMessageBase { public GameObject sender; public string baseToken; public string sound; public string formatStringToken; public override string ConstructChatString() { return Language.GetStringFormatted(formatStringToken, Language.GetString(baseToken)); } public override void OnProcessed() { base.OnProcessed(); if ((bool)sender) { Util.PlaySound(sound, sender); } } public override void Serialize(NetworkWriter writer) { writer.Write(sender); writer.Write(baseToken); writer.Write(sound); writer.Write(formatStringToken); } public override void Deserialize(NetworkReader reader) { sender = reader.ReadGameObject(); baseToken = reader.ReadString(); sound = reader.ReadString(); formatStringToken = reader.ReadString(); } } public class SimpleChatMessage : ChatMessageBase { public string baseToken; public string[] paramTokens; public override string ConstructChatString() { string text = Language.GetString(baseToken); if (paramTokens != null && paramTokens.Length != 0) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; string format = text; object[] args = paramTokens; text = string.Format(invariantCulture, format, args); } return text; } public override void Serialize(NetworkWriter writer) { writer.Write(baseToken); GeneratedNetworkCode._WriteArrayString_None(writer, paramTokens); } public override void Deserialize(NetworkReader reader) { baseToken = reader.ReadString(); paramTokens = GeneratedNetworkCode._ReadArrayString_None(reader); } } public class BodyChatMessage : ChatMessageBase { public GameObject bodyObject; public string token; public override string ConstructChatString() { CharacterBody characterBody = bodyObject?.GetComponent(); if ((bool)characterBody) { string bestBodyName = Util.GetBestBodyName(characterBody.gameObject); return string.Format(CultureInfo.InvariantCulture, "{0}: {1}", Util.EscapeRichTextForTextMeshPro(bestBodyName), Language.GetString(token)); } return null; } public override void OnProcessed() { base.OnProcessed(); Util.PlaySound("Play_UI_chatMessage", RoR2Application.instance.gameObject); } public override void Serialize(NetworkWriter writer) { writer.Write(bodyObject); writer.Write(token); } public override void Deserialize(NetworkReader reader) { bodyObject = reader.ReadGameObject(); token = reader.ReadString(); } } public class SubjectFormatChatMessage : SubjectChatMessage { private static readonly string[] empty = new string[0]; public string[] paramTokens = empty; public override string ConstructChatString() { string @string = Language.GetString(GetResolvedToken()); string subjectName = GetSubjectName(); string[] array = new string[1 + paramTokens.Length]; array[0] = subjectName; Array.Copy(paramTokens, 0, array, 1, paramTokens.Length); for (int i = 1; i < array.Length; i++) { array[i] = Language.GetString(array[i]); } object[] args = array; return string.Format(@string, args); } public override void Serialize(NetworkWriter writer) { base.Serialize(writer); writer.Write((byte)paramTokens.Length); for (int i = 0; i < paramTokens.Length; i++) { writer.Write(paramTokens[i]); } } public override void Deserialize(NetworkReader reader) { base.Deserialize(reader); paramTokens = new string[reader.ReadByte()]; for (int i = 0; i < paramTokens.Length; i++) { paramTokens[i] = reader.ReadString(); } } } public class PlayerPickupChatMessage : SubjectChatMessage { public string pickupToken; public Color32 pickupColor; public uint pickupQuantity; public override string ConstructChatString() { string subjectName = GetSubjectName(); string @string = Language.GetString(GetResolvedToken()); string arg = ""; if (pickupQuantity != 1) { arg = "(" + pickupQuantity + ")"; } string str = Language.GetString(pickupToken) ?? "???"; str = Util.GenerateColoredString(str, pickupColor); try { return string.Format(@string, subjectName, str, arg); } catch (Exception message) { UnityEngine.Debug.LogError(message); } return ""; } public override void Serialize(NetworkWriter writer) { base.Serialize(writer); writer.Write(pickupToken); writer.Write(pickupColor); writer.WritePackedUInt32(pickupQuantity); } public override void Deserialize(NetworkReader reader) { base.Deserialize(reader); pickupToken = reader.ReadString(); pickupColor = reader.ReadColor32(); pickupQuantity = reader.ReadPackedUInt32(); } } public class PlayerDeathChatMessage : SubjectFormatChatMessage { public override string ConstructChatString() { string text = base.ConstructChatString(); if (text != null) { return " " + text + " "; } return text; } public override void Serialize(NetworkWriter writer) { base.Serialize(writer); } public override void Deserialize(NetworkReader reader) { base.Deserialize(reader); } } public class NamedObjectChatMessage : ChatMessageBase { public GameObject namedObject; public string baseToken; public string[] paramTokens; public override string ConstructChatString() { return string.Format(Language.GetString(baseToken), GetObjectName(namedObject)); } public override void Serialize(NetworkWriter writer) { writer.Write(namedObject); writer.Write(baseToken); GeneratedNetworkCode._WriteArrayString_None(writer, paramTokens); } public override void Deserialize(NetworkReader reader) { namedObject = reader.ReadGameObject(); baseToken = reader.ReadString(); paramTokens = GeneratedNetworkCode._ReadArrayString_None(reader); } } public class PlayerChatMessage : ChatMessageBase { public NetworkPlayerName networkPlayerName; public string baseToken; public override string ConstructChatString() { return string.Format(Language.GetString(baseToken), networkPlayerName.GetResolvedName()); } public override void Serialize(NetworkWriter writer) { ((MessageBase)this).Serialize(writer); writer.Write(networkPlayerName); writer.Write(baseToken); } public override void Deserialize(NetworkReader reader) { ((MessageBase)this).Deserialize(reader); networkPlayerName = reader.ReadNetworkPlayerName(); baseToken = reader.ReadString(); } } public class PlayerPauseChatMessage : ChatMessageBase { public string playerName; public string baseToken; public override string ConstructChatString() { return string.Format(Language.GetString(baseToken), playerName); } public override void Serialize(NetworkWriter writer) { ((MessageBase)this).Serialize(writer); writer.Write(playerName); writer.Write(baseToken); } public override void Deserialize(NetworkReader reader) { ((MessageBase)this).Deserialize(reader); playerName = reader.ReadString(); baseToken = reader.ReadString(); } } private static List log = new List(); private static ReadOnlyCollection _readOnlyLog = log.AsReadOnly(); private static IntConVar cvChatMaxMessages = new IntConVar("chat_max_messages", ConVarFlags.None, "30", "Maximum number of chat messages to store."); public static ReadOnlyCollection readOnlyLog => _readOnlyLog; public static event Action onChatChanged; public static void AddMessage(string message) { int num = Mathf.Max(cvChatMaxMessages.value, 1); while (log.Count > num) { log.RemoveAt(0); } log.Add(message); if (Chat.onChatChanged != null) { Chat.onChatChanged(); } } public static void Clear() { log.Clear(); Chat.onChatChanged?.Invoke(); } public static void SendBroadcastChat(ChatMessageBase message) { SendBroadcastChat(message, QosChannelIndex.chat.intVal); } public static void SendBroadcastChat(ChatMessageBase message, int channelIndex) { NetworkWriter networkWriter = new NetworkWriter(); networkWriter.StartMessage(59); networkWriter.Write(message.GetTypeIndex()); networkWriter.Write(message); networkWriter.FinishMessage(); foreach (NetworkConnection connection in NetworkServer.connections) { connection?.SendWriter(networkWriter, channelIndex); } } public static void SendPlayerConnectedMessage(NetworkUser user) { SendBroadcastChat(new PlayerChatMessage { networkPlayerName = user.GetNetworkPlayerName(), baseToken = "PLAYER_CONNECTED" }); } public static void SendPlayerDisconnectedMessage(NetworkUser user) { SendBroadcastChat(new PlayerChatMessage { networkPlayerName = user.GetNetworkPlayerName(), baseToken = "PLAYER_DISCONNECTED" }); } public static void SendPlayerPausedMessage(string playerName) { SendBroadcastChat(new PlayerPauseChatMessage { playerName = playerName, baseToken = "PLAYER_PAUSED" }); } public static void SendPlayerResumedMessage(string playerName) { SendBroadcastChat(new PlayerPauseChatMessage { playerName = playerName, baseToken = "PLAYER_RESUMED" }); } public static void AddPickupMessage(CharacterBody body, string pickupToken, Color32 pickupColor, uint pickupQuantity) { AddMessage(new PlayerPickupChatMessage { subjectAsCharacterBody = body, baseToken = "PLAYER_PICKUP", pickupToken = pickupToken, pickupColor = pickupColor, pickupQuantity = pickupQuantity }); } [NetworkMessageHandler(msgType = 59, client = true)] private static void HandleBroadcastChat(NetworkMessage netMsg) { ChatMessageBase chatMessageBase = ChatMessageBase.Instantiate(netMsg.reader.ReadByte()); if (chatMessageBase != null) { chatMessageBase.Deserialize(netMsg.reader); if (!PlatformSystems.userManager.CurrentUserHasRestriction(UserManager.PlatformRestriction.TextChat)) { AddMessage(chatMessageBase); } } } private static void AddMessage(ChatMessageBase message) { string text = message.ConstructChatString(); if (text != null) { AddMessage(text); message.OnProcessed(); } } [ConCommand(commandName = "say", flags = ConVarFlags.ExecuteOnServer, helpText = "Sends a chat message.")] private static void CCSay(ConCommandArgs args) { args.CheckArgumentCount(1); if ((bool)args.sender) { SendBroadcastChat(new UserChatMessage { sender = args.sender.gameObject, text = args[0] }); } } } public abstract class ChatMessageBase : MessageBase { private static readonly BoolConVar cvChatDebug; private static readonly Dictionary chatMessageTypeToIndex; private static readonly List chatMessageIndexToType; static ChatMessageBase() { cvChatDebug = new BoolConVar("chat_debug", ConVarFlags.None, "0", "Enables logging of chat network messages."); chatMessageTypeToIndex = new Dictionary(); chatMessageIndexToType = new List(); BuildMessageTypeNetMap(); } public abstract string ConstructChatString(); public virtual void OnProcessed() { } private static void BuildMessageTypeNetMap() { Type[] types = typeof(ChatMessageBase).Assembly.GetTypes(); foreach (Type type in types) { if (type.IsSubclassOf(typeof(ChatMessageBase))) { chatMessageTypeToIndex.Add(type, (byte)chatMessageIndexToType.Count); chatMessageIndexToType.Add(type); } } } protected string GetObjectName(GameObject namedObject) { string result = "???"; if ((bool)namedObject) { result = namedObject.name; NetworkUser networkUser = namedObject.GetComponent(); if (!networkUser) { networkUser = Util.LookUpBodyNetworkUser(namedObject); } if ((bool)networkUser) { result = Util.EscapeRichTextForTextMeshPro(networkUser.userName); } } return result; } public byte GetTypeIndex() { return chatMessageTypeToIndex[GetType()]; } public static ChatMessageBase Instantiate(byte typeIndex) { Type type = chatMessageIndexToType[typeIndex]; if (cvChatDebug.value) { UnityEngine.Debug.LogFormat("Received chat message typeIndex={0} type={1}", typeIndex, type?.Name); } if (type != null) { return (ChatMessageBase)Activator.CreateInstance(type); } return null; } public override void Serialize(NetworkWriter writer) { } public override void Deserialize(NetworkReader reader) { } } public class ColoredTokenChatMessage : SubjectChatMessage { private static readonly string[] empty = new string[0]; public string[] paramTokens = empty; public Color32[] paramColors = new Color32[0]; public override string ConstructChatString() { string @string = Language.GetString(GetResolvedToken()); string subjectName = GetSubjectName(); string[] array = new string[1 + paramTokens.Length]; array[0] = subjectName; Array.Copy(paramTokens, 0, array, 1, paramTokens.Length); for (int i = 1; i < array.Length; i++) { int num = i - 1; if (num < paramColors.Length) { array[i] = Util.GenerateColoredString(Language.GetString(array[i]), paramColors[num]); } else { array[i] = Language.GetString(array[i]); } } object[] args = array; return string.Format(@string, args); } public override void Serialize(NetworkWriter writer) { base.Serialize(writer); writer.Write((byte)paramTokens.Length); for (int i = 0; i < paramTokens.Length; i++) { writer.Write(paramTokens[i]); } writer.Write((byte)paramColors.Length); for (int j = 0; j < paramColors.Length; j++) { writer.Write(paramColors[j]); } } public override void Deserialize(NetworkReader reader) { base.Deserialize(reader); paramTokens = new string[reader.ReadByte()]; for (int i = 0; i < paramTokens.Length; i++) { paramTokens[i] = reader.ReadString(); } paramColors = new Color32[reader.ReadByte()]; for (int j = 0; j < paramColors.Length; j++) { paramColors[j] = reader.ReadColor32(); } } } public class SubjectChatMessage : ChatMessageBase { private GameObject subjectNetworkUserObject; private GameObject subjectCharacterBodyGameObject; public string baseToken; private MemoizedGetComponent subjectNetworkUserGetComponent; private MemoizedGetComponent subjectCharacterBodyGetComponent; public NetworkUser subjectAsNetworkUser { get { return subjectNetworkUserGetComponent.Get(subjectNetworkUserObject); } set { subjectNetworkUserObject = (value ? value.gameObject : null); CharacterBody characterBody = null; if ((bool)value) { characterBody = value.GetCurrentBody(); } subjectCharacterBodyGameObject = (characterBody ? characterBody.gameObject : null); } } public CharacterBody subjectAsCharacterBody { get { return subjectCharacterBodyGetComponent.Get(subjectCharacterBodyGameObject); } set { subjectCharacterBodyGameObject = (value ? value.gameObject : null); subjectNetworkUserObject = Util.LookUpBodyNetworkUser(value)?.gameObject; } } protected string GetSubjectName() { if ((bool)subjectAsNetworkUser) { return Util.EscapeRichTextForTextMeshPro(subjectAsNetworkUser.userName); } if ((bool)subjectAsCharacterBody) { return subjectAsCharacterBody.GetDisplayName(); } return "???"; } protected bool IsSecondPerson() { if (LocalUserManager.readOnlyLocalUsersList.Count == 1 && (bool)subjectAsNetworkUser && subjectAsNetworkUser.localUser != null) { return true; } return false; } protected string GetResolvedToken() { if (!IsSecondPerson()) { return baseToken; } return baseToken + "_2P"; } public override string ConstructChatString() { return string.Format(Language.GetString(GetResolvedToken()), GetSubjectName()); } public override void Serialize(NetworkWriter writer) { ((MessageBase)this).Serialize(writer); writer.Write(subjectNetworkUserObject); writer.Write(subjectCharacterBodyGameObject); writer.Write(baseToken); } public override void Deserialize(NetworkReader reader) { ((MessageBase)this).Deserialize(reader); subjectNetworkUserObject = reader.ReadGameObject(); subjectCharacterBodyGameObject = reader.ReadGameObject(); baseToken = reader.ReadString(); } } public class ColorCatalog { public enum ColorIndex { None, Tier1Item, Tier2Item, Tier3Item, LunarItem, Equipment, Interactable, Teleporter, Money, Blood, Unaffordable, Unlockable, LunarCoin, BossItem, Error, EasyDifficulty, NormalDifficulty, HardDifficulty, Tier1ItemDark, Tier2ItemDark, Tier3ItemDark, LunarItemDark, BossItemDark, WIP, Artifact, VoidItem, VoidItemDark, VoidCoin, Count } private static readonly Color32[] indexToColor32; private static readonly string[] indexToHexString; private static readonly UnityEngine.Color[] multiplayerColors; static ColorCatalog() { indexToColor32 = new Color32[28]; indexToHexString = new string[28]; multiplayerColors = new UnityEngine.Color[4] { new Color32(252, 62, 62, byte.MaxValue), new Color32(62, 109, 252, byte.MaxValue), new Color32(129, 252, 62, byte.MaxValue), new Color32(252, 241, 62, byte.MaxValue) }; indexToColor32[1] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); indexToColor32[2] = new Color32(119, byte.MaxValue, 23, byte.MaxValue); indexToColor32[3] = new Color32(231, 84, 58, byte.MaxValue); indexToColor32[4] = new Color32(48, 127, byte.MaxValue, byte.MaxValue); indexToColor32[5] = new Color32(byte.MaxValue, 128, 0, byte.MaxValue); indexToColor32[6] = new Color32(235, 232, 122, byte.MaxValue); indexToColor32[7] = new Color32(231, 84, 58, byte.MaxValue); indexToColor32[8] = new Color32(239, 235, 26, byte.MaxValue); indexToColor32[9] = new Color32(206, 41, 41, byte.MaxValue); indexToColor32[10] = new Color32(100, 100, 100, byte.MaxValue); indexToColor32[11] = Color32.Lerp(new Color32(142, 56, 206, byte.MaxValue), new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue), 0.575f); indexToColor32[12] = new Color32(173, 189, 250, byte.MaxValue); indexToColor32[13] = UnityEngine.Color.yellow; indexToColor32[14] = new Color32(byte.MaxValue, 0, byte.MaxValue, byte.MaxValue); indexToColor32[15] = new Color32(106, 170, 95, byte.MaxValue); indexToColor32[16] = new Color32(173, 117, 80, byte.MaxValue); indexToColor32[17] = new Color32(142, 49, 49, byte.MaxValue); indexToColor32[18] = new Color32(193, 193, 193, byte.MaxValue); indexToColor32[19] = new Color32(88, 149, 88, byte.MaxValue); indexToColor32[20] = new Color32(142, 49, 49, byte.MaxValue); indexToColor32[21] = new Color32(76, 84, 144, byte.MaxValue); indexToColor32[22] = new Color32(189, 180, 60, byte.MaxValue); indexToColor32[23] = new Color32(200, 80, 0, byte.MaxValue); indexToColor32[24] = new Color32(140, 114, 219, byte.MaxValue); indexToColor32[25] = new Color32(237, 127, 205, byte.MaxValue); indexToColor32[26] = new Color32(163, 77, 132, byte.MaxValue); indexToColor32[27] = new Color32(244, 173, 250, byte.MaxValue); for (ColorIndex colorIndex = ColorIndex.None; colorIndex < ColorIndex.Count; colorIndex++) { indexToHexString[(int)colorIndex] = Util.RGBToHex(indexToColor32[(int)colorIndex]); } } public static Color32 GetColor(ColorIndex colorIndex) { if (colorIndex < ColorIndex.None || colorIndex >= ColorIndex.Count) { colorIndex = ColorIndex.Error; } return indexToColor32[(int)colorIndex]; } public static string GetColorHexString(ColorIndex colorIndex) { if (colorIndex < ColorIndex.None || colorIndex >= ColorIndex.Count) { colorIndex = ColorIndex.Error; } return indexToHexString[(int)colorIndex]; } public static UnityEngine.Color GetMultiplayerColor(int playerSlot) { if (playerSlot >= 0 && playerSlot < multiplayerColors.Length) { return multiplayerColors[playerSlot]; } return UnityEngine.Color.black; } } public static class CommonLanguageTokens { public static string ok = "OK"; public static string cancel = "CANCEL"; public static string optionRebindDialogTitle = "OPTION_REBIND_DIALOG_TITLE"; public static string optionRebindDialogDescription = "OPTION_REBIND_DIALOG_DESCRIPTION"; } public static class CommonShaderProperties { public static readonly int _FlashColor = Shader.PropertyToID("_FlashColor"); public static readonly int _Fade = Shader.PropertyToID("_Fade"); public static readonly int _EliteIndex = Shader.PropertyToID("_EliteIndex"); public static readonly int _LimbPrimeMask = Shader.PropertyToID("_LimbPrimeMask"); public static readonly int _ExternalAlpha = Shader.PropertyToID("_ExternalAlpha"); } public enum CostTypeIndex { None, Money, PercentHealth, LunarCoin, WhiteItem, GreenItem, RedItem, Equipment, VolatileBattery, LunarItemOrEquipment, BossItem, ArtifactShellKillerItem, TreasureCacheItem, TreasureCacheVoidItem, VoidCoin, SoulCost, Count } public class CostTypeDef { public delegate void BuildCostStringDelegate(CostTypeDef costTypeDef, BuildCostStringContext context); public struct BuildCostStringContext { public StringBuilder stringBuilder; public int cost; } public delegate Color32 GetCostColorDelegate(CostTypeDef costTypeDef, GetCostColorContext context); public struct GetCostColorContext { public bool forWorldDisplay; } public delegate void BuildCostStringStyledDelegate(CostTypeDef costTypeDef, BuildCostStringStyledContext context); public struct BuildCostStringStyledContext { public StringBuilder stringBuilder; public int cost; public bool forWorldDisplay; public bool includeColor; } public delegate bool IsAffordableDelegate(CostTypeDef costTypeDef, IsAffordableContext context); public struct IsAffordableContext { public int cost; public Interactor activator; } public delegate void PayCostDelegate(CostTypeDef costTypeDef, PayCostContext context); public struct PayCostContext { public int cost; public Interactor activator; public CharacterBody activatorBody; public CharacterMaster activatorMaster; public GameObject purchasedObject; public PayCostResults results; public Xoroshiro128Plus rng; public ItemIndex avoidedItemIndex; } public class PayCostResults { public List itemsTaken = new List(); public List equipmentTaken = new List(); } public string name; public ItemTier itemTier = ItemTier.NoTier; public ColorCatalog.ColorIndex colorIndex = ColorCatalog.ColorIndex.Error; public string costStringFormatToken; public string costStringStyle; public bool saturateWorldStyledCostString = true; public bool darkenWorldStyledCostString = true; public BuildCostStringDelegate buildCostString { private get; set; } = BuildCostStringDefault; public GetCostColorDelegate getCostColor { private get; set; } = GetCostColorDefault; public BuildCostStringStyledDelegate buildCostStringStyled { private get; set; } = BuildCostStringStyledDefault; public IsAffordableDelegate isAffordable { private get; set; } public PayCostDelegate payCost { private get; set; } public void BuildCostString(int cost, [NotNull] StringBuilder stringBuilder) { buildCostString(this, new BuildCostStringContext { cost = cost, stringBuilder = stringBuilder }); } public static void BuildCostStringDefault(CostTypeDef costTypeDef, BuildCostStringContext context) { context.stringBuilder.Append(Language.GetStringFormatted(costTypeDef.costStringFormatToken, context.cost)); } public Color32 GetCostColor(bool forWorldDisplay) { return getCostColor(this, new GetCostColorContext { forWorldDisplay = forWorldDisplay }); } public static Color32 GetCostColorDefault(CostTypeDef costTypeDef, GetCostColorContext context) { Color32 color = ColorCatalog.GetColor(costTypeDef.colorIndex); if (context.forWorldDisplay) { UnityEngine.Color.RGBToHSV(color, out var H, out var S, out var V); if (costTypeDef.saturateWorldStyledCostString && S > 0f) { S = 1f; } if (costTypeDef.darkenWorldStyledCostString) { V *= 0.5f; } color = UnityEngine.Color.HSVToRGB(H, S, V); } return color; } public void BuildCostStringStyled(int cost, [NotNull] StringBuilder stringBuilder, bool forWorldDisplay, bool includeColor = true) { buildCostStringStyled(this, new BuildCostStringStyledContext { cost = cost, forWorldDisplay = forWorldDisplay, stringBuilder = stringBuilder, includeColor = includeColor }); } public static void BuildCostStringStyledDefault(CostTypeDef costTypeDef, BuildCostStringStyledContext context) { StringBuilder stringBuilder = context.stringBuilder; stringBuilder.Append(""); if (costTypeDef.costStringStyle != null) { stringBuilder.Append(""); } if (context.includeColor) { Color32 costColor = costTypeDef.GetCostColor(context.forWorldDisplay); stringBuilder.Append(""); } costTypeDef.BuildCostString(context.cost, context.stringBuilder); if (context.includeColor) { stringBuilder.Append(""); } if (costTypeDef.costStringStyle != null) { stringBuilder.Append(""); } stringBuilder.Append(""); } public bool IsAffordable(int cost, Interactor activator) { return isAffordable(this, new IsAffordableContext { cost = cost, activator = activator }); } public PayCostResults PayCost(int cost, Interactor activator, GameObject purchasedObject, Xoroshiro128Plus rng, ItemIndex avoidedItemIndex) { PayCostResults payCostResults = new PayCostResults(); CharacterBody component = activator.GetComponent(); payCost(this, new PayCostContext { cost = cost, activator = activator, activatorBody = component, activatorMaster = (component ? component.master : null), purchasedObject = purchasedObject, results = payCostResults, rng = rng, avoidedItemIndex = avoidedItemIndex }); return payCostResults; } } public static class CostTypeCatalog { private static class LunarItemOrEquipmentCostTypeHelper { private static ItemIndex[] lunarItemIndices = Array.Empty(); private static EquipmentIndex[] lunarEquipmentIndices = Array.Empty(); public static bool IsAffordable(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { CharacterBody component = context.activator.GetComponent(); if (!component) { return false; } Inventory inventory = component.inventory; if (!inventory) { return false; } int cost = context.cost; int num = 0; for (int i = 0; i < lunarItemIndices.Length; i++) { int itemCount = inventory.GetItemCount(lunarItemIndices[i]); num += itemCount; if (num >= cost) { return true; } } int j = 0; for (int equipmentSlotCount = inventory.GetEquipmentSlotCount(); j < equipmentSlotCount; j++) { EquipmentState equipment = inventory.GetEquipment((uint)j); for (int k = 0; k < lunarEquipmentIndices.Length; k++) { if (equipment.equipmentIndex == lunarEquipmentIndices[k]) { num++; if (num >= cost) { return true; } } } } return false; } public static void PayCost(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { Inventory inventory = context.activator.GetComponent().inventory; int cost = context.cost; int itemWeight = 0; int equipmentWeight = 0; for (int i = 0; i < lunarItemIndices.Length; i++) { ItemIndex itemIndex = lunarItemIndices[i]; int itemCount = inventory.GetItemCount(itemIndex); itemWeight += itemCount; } int j = 0; for (int equipmentSlotCount = inventory.GetEquipmentSlotCount(); j < equipmentSlotCount; j++) { EquipmentState equipment = inventory.GetEquipment((uint)j); if (Array.IndexOf(lunarEquipmentIndices, equipment.equipmentIndex) != -1) { int num = equipmentWeight + 1; equipmentWeight = num; } } int totalWeight = itemWeight + equipmentWeight; for (int k = 0; k < cost; k++) { TakeOne(); } MultiShopCardUtils.OnNonMoneyPurchase(context); void TakeOne() { float nextNormalizedFloat = context.rng.nextNormalizedFloat; float num2 = (float)itemWeight / (float)totalWeight; if (nextNormalizedFloat < num2) { int num3 = Mathf.FloorToInt(Util.Remap(Util.Remap(nextNormalizedFloat, 0f, num2, 0f, 1f), 0f, 1f, 0f, itemWeight)); int num4 = 0; for (int l = 0; l < lunarItemIndices.Length; l++) { ItemIndex itemIndex2 = lunarItemIndices[l]; int itemCount2 = inventory.GetItemCount(itemIndex2); num4 += itemCount2; if (num3 < num4) { inventory.RemoveItem(itemIndex2); context.results.itemsTaken.Add(itemIndex2); break; } } } else { int num5 = Mathf.FloorToInt(Util.Remap(Util.Remap(nextNormalizedFloat, num2, 1f, 0f, 1f), 0f, 1f, 0f, equipmentWeight)); int num6 = 0; for (int m = 0; m < inventory.GetEquipmentSlotCount(); m++) { EquipmentIndex equipmentIndex = inventory.GetEquipment((uint)m).equipmentIndex; if (Array.IndexOf(lunarEquipmentIndices, equipmentIndex) != -1) { num6++; if (num5 < num6) { inventory.SetEquipment(EquipmentState.empty, (uint)m); context.results.equipmentTaken.Add(equipmentIndex); } } } } } } private static void PayOne(Inventory inventory) { new WeightedSelection(lunarItemIndices.Length); new WeightedSelection(inventory.GetEquipmentSlotCount()); int num = 0; int num2 = 0; for (int i = 0; i < lunarItemIndices.Length; i++) { ItemIndex itemIndex = lunarItemIndices[i]; int itemCount = inventory.GetItemCount(itemIndex); num += itemCount; } int j = 0; for (int equipmentSlotCount = inventory.GetEquipmentSlotCount(); j < equipmentSlotCount; j++) { EquipmentState equipment = inventory.GetEquipment((uint)j); if (Array.IndexOf(lunarEquipmentIndices, equipment.equipmentIndex) != -1) { num2++; } } } [SystemInitializer(new Type[] { typeof(ItemCatalog), typeof(EquipmentCatalog) })] private static void Init() { lunarItemIndices = ItemCatalog.lunarItemList.ToArray(); lunarEquipmentIndices = EquipmentCatalog.equipmentList.Where((EquipmentIndex v) => EquipmentCatalog.GetEquipmentDef(v).isLunar).ToArray(); } } private static CostTypeDef[] costTypeDefs; public static readonly CatalogModHelper modHelper = new CatalogModHelper(delegate(int i, CostTypeDef def) { Register((CostTypeIndex)i, def); }, (CostTypeDef v) => v.name); public static int costTypeCount => costTypeDefs.Length; private static void Register(CostTypeIndex costType, CostTypeDef costTypeDef) { if (costType < CostTypeIndex.Count) { costTypeDef.name = costType.ToString(); } costTypeDefs[(int)costType] = costTypeDef; } [SystemInitializer(new Type[] { })] private static void Init() { costTypeDefs = new CostTypeDef[16]; Register(CostTypeIndex.None, new CostTypeDef { buildCostString = delegate(CostTypeDef costTypeDef, CostTypeDef.BuildCostStringContext context) { context.stringBuilder.Append(""); }, isAffordable = (CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) => true, payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { MultiShopCardUtils.OnNonMoneyPurchase(context); } }); Register(CostTypeIndex.Money, new CostTypeDef { costStringFormatToken = "COST_MONEY_FORMAT", isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { CharacterBody component14 = context.activator.GetComponent(); if ((bool)component14) { CharacterMaster master2 = component14.master; if ((bool)master2) { return master2.money >= context.cost; } } return false; }, payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { if ((bool)context.activatorMaster) { context.activatorMaster.money -= (uint)context.cost; MultiShopCardUtils.OnMoneyPurchase(context); } }, colorIndex = ColorCatalog.ColorIndex.Money }); Register(CostTypeIndex.PercentHealth, new CostTypeDef { costStringFormatToken = "COST_PERCENTHEALTH_FORMAT", saturateWorldStyledCostString = false, darkenWorldStyledCostString = true, isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { HealthComponent component13 = context.activator.GetComponent(); return (bool)component13 && component13.combinedHealth / component13.fullCombinedHealth * 100f >= (float)context.cost; }, payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { HealthComponent component12 = context.activator.GetComponent(); if ((bool)component12) { float combinedHealth2 = component12.combinedHealth; float num3 = component12.fullCombinedHealth * (float)context.cost / 100f; if (combinedHealth2 > num3) { component12.TakeDamage(new DamageInfo { damage = num3, attacker = context.purchasedObject, position = context.purchasedObject.transform.position, damageType = (DamageType.NonLethal | DamageType.BypassArmor) }); MultiShopCardUtils.OnNonMoneyPurchase(context); } } }, colorIndex = ColorCatalog.ColorIndex.Blood }); Register(CostTypeIndex.LunarCoin, new CostTypeDef { costStringFormatToken = "COST_LUNARCOIN_FORMAT", saturateWorldStyledCostString = false, darkenWorldStyledCostString = true, isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { NetworkUser networkUser2 = Util.LookUpBodyNetworkUser(context.activator.gameObject); return (bool)networkUser2 && networkUser2.lunarCoins >= context.cost; }, payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { NetworkUser networkUser = Util.LookUpBodyNetworkUser(context.activator.gameObject); if ((bool)networkUser) { networkUser.DeductLunarCoins((uint)context.cost); MultiShopCardUtils.OnNonMoneyPurchase(context); } }, colorIndex = ColorCatalog.ColorIndex.LunarCoin }); Register(CostTypeIndex.VoidCoin, new CostTypeDef { costStringFormatToken = "COST_VOIDCOIN_FORMAT", isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { CharacterBody component11 = context.activator.GetComponent(); if ((bool)component11) { CharacterMaster master = component11.master; if ((bool)master) { return master.voidCoins >= context.cost; } } return false; }, payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { if ((bool)context.activatorMaster) { context.activatorMaster.voidCoins -= (uint)context.cost; MultiShopCardUtils.OnNonMoneyPurchase(context); } }, saturateWorldStyledCostString = false, darkenWorldStyledCostString = true, colorIndex = ColorCatalog.ColorIndex.VoidCoin }); Register(CostTypeIndex.SoulCost, new CostTypeDef { costStringFormatToken = "COST_SOULCOST_FORMAT", saturateWorldStyledCostString = false, darkenWorldStyledCostString = true, isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { HealthComponent component10 = context.activator.GetComponent(); return (bool)component10 && component10.combinedHealth / component10.fullCombinedHealth * 100f >= (float)context.cost; }, payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { HealthComponent component9 = context.activator.GetComponent(); if ((bool)component9) { float combinedHealth = component9.combinedHealth; float num2 = component9.fullCombinedHealth * (float)context.cost / 100f; int newCount = context.cost / 10; if (combinedHealth > num2) { component9.body.SetBuffCount(DLC2Content.Buffs.SoulCost.buffIndex, newCount); MultiShopCardUtils.OnNonMoneyPurchase(context); } } }, colorIndex = ColorCatalog.ColorIndex.BossItem }); Register(CostTypeIndex.WhiteItem, new CostTypeDef { costStringFormatToken = "COST_ITEM_FORMAT", isAffordable = IsAffordableItem, payCost = PayCostItems, colorIndex = ColorCatalog.ColorIndex.Tier1Item, itemTier = ItemTier.Tier1 }); Register(CostTypeIndex.GreenItem, new CostTypeDef { costStringFormatToken = "COST_ITEM_FORMAT", saturateWorldStyledCostString = true, isAffordable = IsAffordableItem, payCost = PayCostItems, colorIndex = ColorCatalog.ColorIndex.Tier2Item, itemTier = ItemTier.Tier2 }); Register(CostTypeIndex.RedItem, new CostTypeDef { costStringFormatToken = "COST_ITEM_FORMAT", saturateWorldStyledCostString = false, darkenWorldStyledCostString = true, isAffordable = IsAffordableItem, payCost = PayCostItems, colorIndex = ColorCatalog.ColorIndex.Tier3Item, itemTier = ItemTier.Tier3 }); Register(CostTypeIndex.BossItem, new CostTypeDef { costStringFormatToken = "COST_ITEM_FORMAT", darkenWorldStyledCostString = true, isAffordable = IsAffordableItem, payCost = PayCostItems, colorIndex = ColorCatalog.ColorIndex.BossItem, itemTier = ItemTier.Boss }); Register(CostTypeIndex.Equipment, new CostTypeDef { costStringFormatToken = "COST_EQUIPMENT_FORMAT", isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { CharacterBody component8 = context.activator.gameObject.GetComponent(); if ((bool)component8) { Inventory inventory8 = component8.inventory; if ((bool)inventory8) { return inventory8.currentEquipmentIndex != EquipmentIndex.None; } } return false; }, payCost = PayEquipment, colorIndex = ColorCatalog.ColorIndex.Equipment }); Register(CostTypeIndex.VolatileBattery, new CostTypeDef { costStringFormatToken = "COST_VOLATILEBATTERY_FORMAT", isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { CharacterBody component7 = context.activator.gameObject.GetComponent(); if ((bool)component7) { Inventory inventory7 = component7.inventory; if ((bool)inventory7) { return inventory7.currentEquipmentIndex == RoR2Content.Equipment.QuestVolatileBattery.equipmentIndex; } } return false; }, payCost = PayEquipment, colorIndex = ColorCatalog.ColorIndex.Equipment }); Register(CostTypeIndex.LunarItemOrEquipment, new CostTypeDef { costStringFormatToken = "COST_LUNAR_FORMAT", isAffordable = LunarItemOrEquipmentCostTypeHelper.IsAffordable, payCost = LunarItemOrEquipmentCostTypeHelper.PayCost, colorIndex = ColorCatalog.ColorIndex.LunarItem }); Register(CostTypeIndex.ArtifactShellKillerItem, new CostTypeDef { costStringFormatToken = "COST_ARTIFACTSHELLKILLERITEM_FORMAT", isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { CharacterBody component6 = context.activator.gameObject.GetComponent(); if ((bool)component6) { Inventory inventory6 = component6.inventory; if ((bool)inventory6) { return inventory6.GetItemCount(RoR2Content.Items.ArtifactKey) >= context.cost; } } return false; }, payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { context.activatorBody.inventory.RemoveItem(RoR2Content.Items.ArtifactKey, context.cost); MultiShopCardUtils.OnNonMoneyPurchase(context); }, colorIndex = ColorCatalog.ColorIndex.Artifact }); Register(CostTypeIndex.TreasureCacheItem, new CostTypeDef { costStringFormatToken = "COST_TREASURECACHEITEM_FORMAT", isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { CharacterBody component5 = context.activator.gameObject.GetComponent(); if ((bool)component5) { Inventory inventory5 = component5.inventory; if ((bool)inventory5) { return inventory5.GetItemCount(RoR2Content.Items.TreasureCache) >= context.cost; } } return false; }, payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { context.activatorBody.inventory.RemoveItem(RoR2Content.Items.TreasureCache, context.cost); MultiShopCardUtils.OnNonMoneyPurchase(context); }, colorIndex = ColorCatalog.ColorIndex.Tier1Item }); Register(CostTypeIndex.TreasureCacheVoidItem, new CostTypeDef { costStringFormatToken = "COST_TREASURECACHEVOIDITEM_FORMAT", isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { CharacterBody component4 = context.activator.gameObject.GetComponent(); if ((bool)component4) { Inventory inventory4 = component4.inventory; if ((bool)inventory4) { return inventory4.GetItemCount(DLC1Content.Items.TreasureCacheVoid) >= context.cost; } } return false; }, payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { context.activatorBody.inventory.RemoveItem(DLC1Content.Items.TreasureCacheVoid, context.cost); MultiShopCardUtils.OnNonMoneyPurchase(context); }, colorIndex = ColorCatalog.ColorIndex.VoidItem }); modHelper.CollectAndRegisterAdditionalEntries(ref costTypeDefs); static bool IsAffordableItem(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) { CharacterBody component3 = context.activator.GetComponent(); if ((bool)component3) { Inventory inventory3 = component3.inventory; if ((bool)inventory3) { return inventory3.HasAtLeastXTotalItemsOfTier(costTypeDef.itemTier, context.cost); } } return false; } static void PayCostItems(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { List itemsToTake; if ((bool)context.activatorBody) { Inventory inventory2 = context.activatorBody.inventory; if ((bool)inventory2) { itemsToTake = CollectionPool>.RentCollection(); WeightedSelection weightedSelection2 = new WeightedSelection(); WeightedSelection weightedSelection3 = new WeightedSelection(); WeightedSelection weightedSelection4 = new WeightedSelection(); foreach (ItemIndex allItem in ItemCatalog.allItems) { if (allItem != context.avoidedItemIndex) { int itemCount = inventory2.GetItemCount(allItem); if (itemCount > 0) { ItemDef itemDef = ItemCatalog.GetItemDef(allItem); if (itemDef.tier == costTypeDef.itemTier) { (itemDef.ContainsTag(ItemTag.PriorityScrap) ? weightedSelection4 : (itemDef.ContainsTag(ItemTag.Scrap) ? weightedSelection3 : weightedSelection2)).AddChoice(allItem, itemCount); } } } } TakeItemsFromWeightedSelection(weightedSelection4); TakeItemsFromWeightedSelection(weightedSelection3); TakeItemsFromWeightedSelection(weightedSelection2); for (int i = itemsToTake.Count; i < context.cost; i++) { itemsToTake.Add(context.avoidedItemIndex); } bool flag = false; for (int j = 0; j < itemsToTake.Count; j++) { ItemIndex itemIndex = itemsToTake[j]; context.results.itemsTaken.Add(itemIndex); if (itemIndex == DLC1Content.Items.RegeneratingScrap.itemIndex) { flag = true; inventory2.GiveItem(DLC1Content.Items.RegeneratingScrapConsumed); EntitySoundManager.EmitSoundServer(NetworkSoundEventCatalog.FindNetworkSoundEventIndex("Play_item_proc_regenScrap_consume"), context.activatorBody.gameObject); ModelLocator component = context.activatorBody.GetComponent(); if ((bool)component) { Transform modelTransform = component.modelTransform; if ((bool)modelTransform) { CharacterModel component2 = modelTransform.GetComponent(); if ((bool)component2) { List itemDisplayObjects = component2.GetItemDisplayObjects(DLC1Content.Items.RegeneratingScrap.itemIndex); if (itemDisplayObjects.Count > 0) { GameObject gameObject = itemDisplayObjects[0]; GameObject effectPrefab = Addressables.LoadAssetAsync("RoR2/DLC1/RegeneratingScrap/RegeneratingScrapExplosionDisplay.prefab").WaitForCompletion(); EffectData effectData = new EffectData { origin = gameObject.transform.position, rotation = gameObject.transform.rotation }; EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true); } } } } EffectManager.SimpleMuzzleFlash(Addressables.LoadAssetAsync("RoR2/DLC1/RegeneratingScrap/RegeneratingScrapExplosionInPrinter.prefab").WaitForCompletion(), context.purchasedObject, "DropPivot", transmit: true); } inventory2.RemoveItem(itemIndex); } if (flag) { CharacterMasterNotificationQueue.SendTransformNotification(context.activatorBody.master, DLC1Content.Items.RegeneratingScrap.itemIndex, DLC1Content.Items.RegeneratingScrapConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); } CollectionPool>.ReturnCollection(itemsToTake); } } MultiShopCardUtils.OnNonMoneyPurchase(context); void TakeItemsFromWeightedSelection(WeightedSelection weightedSelection) { while (weightedSelection.Count > 0 && itemsToTake.Count < context.cost) { int choiceIndex2 = weightedSelection.EvaluateToChoiceIndex(context.rng.nextNormalizedFloat); TakeItemFromWeightedSelection(weightedSelection, choiceIndex2); } } } static void PayEquipment(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context) { Inventory inventory = context.activatorBody.inventory; EquipmentIndex equipmentIndex = inventory.GetEquipmentIndex(); if ((bool)inventory) { inventory.SetEquipmentIndex(EquipmentIndex.None); } context.results.equipmentTaken.Add(equipmentIndex); MultiShopCardUtils.OnNonMoneyPurchase(context); } void TakeItemFromWeightedSelection(WeightedSelection weightedSelection, int choiceIndex) { WeightedSelection.ChoiceInfo choice = weightedSelection.GetChoice(choiceIndex); ItemIndex value = choice.value; int num = (int)choice.weight; num--; if (num <= 0) { weightedSelection.RemoveChoice(choiceIndex); } else { weightedSelection.ModifyChoiceWeight(choiceIndex, num); } P_2.itemsToTake.Add(value); } } public static CostTypeDef GetCostTypeDef(CostTypeIndex costTypeIndex) { return ArrayUtils.GetSafe(costTypeDefs, (int)costTypeIndex); } } public class CU8Content : IContentPackProvider { public static class Artifacts { public static ArtifactDef Devotion; public static ArtifactDef Delusion; } public static class Items { public static ItemDef LemurianHarness; } public static class ItemRelationshipTypes { } public static class Equipment { } public static class Buffs { } public static class Elites { } public static class GameEndings { } public static class Survivors { } public static class MiscPickups { } private ContentPack contentPack = new ContentPack(); private static readonly string addressablesLabel = "ContentPack:RoR2.CU8"; public string identifier => "RoR2.CU8"; public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args) { contentPack.identifier = identifier; AddressablesLoadHelper loadHelper = AddressablesLoadHelper.CreateUsingDefaultResourceLocator(addressablesLabel); yield return loadHelper.AddContentPackLoadOperationWithYields(contentPack); loadHelper.AddGenericOperation(delegate { ContentLoadHelper.PopulateTypeFields(typeof(Artifacts), contentPack.artifactDefs); ContentLoadHelper.PopulateTypeFields(typeof(Items), contentPack.itemDefs); }, 0.05f); while (loadHelper.coroutine.MoveNext()) { args.ReportProgress(loadHelper.progress.value); yield return loadHelper.coroutine.Current; } } public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args) { ContentPack.Copy(contentPack, args.output); yield break; } public IEnumerator FinalizeAsync(FinalizeAsyncArgs args) { yield break; } } [CreateAssetMenu(menuName = "RoR2/Animation Curve Asset")] public class AnimationCurveAsset : ScriptableObject { public AnimationCurve value; } [CreateAssetMenu(menuName = "RoR2/AssetCollection")] public class AssetCollection : ScriptableObject { public UnityEngine.Object[] assets = Array.Empty(); [ContextMenu("Add selected assets.")] private void AddSelectedAssets() { UnityEngine.Object[] additionalAssets = Array.Empty(); AddAssets(additionalAssets); } public void AddAssets(UnityEngine.Object[] additionalAssets) { int num = assets.Length; Array.Resize(ref assets, assets.Length + additionalAssets.Length); for (int i = 0; i < additionalAssets.Length; i++) { assets[num + i] = additionalAssets[i]; } } } [Serializable] public class AssetReferenceScene : AssetReference { public AssetReferenceScene(string guid) : base(guid) { } public override bool ValidateAsset(string path) { if (base.ValidateAsset(path)) { return path.EndsWith(".unity", StringComparison.OrdinalIgnoreCase); } return false; } public override bool ValidateAsset(UnityEngine.Object obj) { bool num = base.ValidateAsset(obj); bool flag = false; return num && flag; } } [CreateAssetMenu(menuName = "RoR2/SpawnCards/BodySpawnCard")] public class BodySpawnCard : SpawnCard { protected override void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest directorSpawnRequest, ref SpawnResult result) { UnityEngine.Vector3 position2 = position; position2.y += Util.GetBodyPrefabFootOffset(prefab); GameObject gameObject = UnityEngine.Object.Instantiate(prefab, position2, rotation); NetworkServer.Spawn(gameObject); result.spawnedInstance = gameObject; result.success = true; } } [CreateAssetMenu(menuName = "RoR2/BuffDef")] public class BuffDef : ScriptableObject { [Obsolete("BuffDef.iconPath is deprecated and no longer functions. Use .iconSprite instead.", false)] public string iconPath = "Textures/ItemIcons/texNullIcon"; public Sprite iconSprite; public UnityEngine.Color buffColor = UnityEngine.Color.white; public bool canStack; public EliteDef eliteDef; public bool isDebuff; public bool ignoreGrowthNectar; public bool isCooldown; public bool isHidden; public NetworkSoundEventDef startSfx; public BuffIndex buffIndex { get; set; } = BuffIndex.None; public bool isElite => (object)eliteDef != null; protected void OnValidate() { ReplaceIconFromPathWithDirectReference(); } [ContextMenu("Update iconPath to iconSprite")] private void ReplaceIconFromPathWithDirectReference() { string text = iconPath; if (!string.IsNullOrEmpty(text)) { Sprite sprite = LegacyResourcesAPI.Load(text); if ((bool)sprite) { iconSprite = sprite; iconPath = string.Empty; EditorUtil.SetDirty(this); } } } } [CreateAssetMenu(menuName = "RoR2/CharacterCameraParams")] public class CharacterCameraParams : ScriptableObject { [SerializeField] [HideInInspector] private int version; public CharacterCameraParamsData data; private static readonly float minPitchDefault = -70f; private static readonly float maxPitchDefault = 70f; private static readonly float wallCushionDefault = 0.1f; private static readonly float pivotVerticalOffsetDefault = 1.6f; private static readonly UnityEngine.Vector3 standardLocalCameraPosDefault = new UnityEngine.Vector3(0f, 0f, -5f); [Obsolete("Use data.minPitch instead.", false)] [ShowFieldObsolete] public float minPitch = minPitchDefault; [Obsolete("Use data.maxPitch instead.", false)] [ShowFieldObsolete] public float maxPitch = maxPitchDefault; [ShowFieldObsolete] [Obsolete("Use data.wallCushion instead.", false)] public float wallCushion = wallCushionDefault; [Obsolete("Use data.pivotVerticalOffset instead.", false)] [ShowFieldObsolete] public float pivotVerticalOffset = pivotVerticalOffsetDefault; [ShowFieldObsolete] [Obsolete("Use data.standardLocalCameraPos instead.", false)] public UnityEngine.Vector3 standardLocalCameraPos = standardLocalCameraPosDefault; private void Awake() { UpdateVersion(); } private void UpdateVersion() { if (version < 1) { SetBlendableFromValue(out data.minPitch, minPitch, minPitchDefault); SetBlendableFromValue(out data.maxPitch, maxPitch, maxPitchDefault); SetBlendableFromValue(out data.wallCushion, wallCushion, wallCushionDefault); SetBlendableFromValue(out data.pivotVerticalOffset, pivotVerticalOffset, pivotVerticalOffsetDefault); SetBlendableFromValue(out data.idealLocalCameraPos, standardLocalCameraPos, standardLocalCameraPosDefault); version = 1; } else { minPitch = data.minPitch.value; maxPitch = data.maxPitch.value; wallCushion = data.wallCushion.value; pivotVerticalOffset = data.pivotVerticalOffset.value; standardLocalCameraPos = data.idealLocalCameraPos.value; } } private static void SetBlendableFromValue(out BlendableFloat dest, float src, float defaultValue) { dest.value = src; dest.alpha = (src.Equals(defaultValue) ? 0f : 1f); } private static void SetBlendableFromValue(out BlendableVector3 dest, UnityEngine.Vector3 src, UnityEngine.Vector3 defaultValue) { dest.value = src; dest.alpha = (src.Equals(defaultValue) ? 0f : 1f); } private static void SetBlendableFromValue(out BlendableBool dest, bool src, bool defaultValue) { dest.value = src; dest.alpha = (src.Equals(defaultValue) ? 0f : 1f); } } [Serializable] public struct CharacterCameraParamsData { public BlendableFloat minPitch; public BlendableFloat maxPitch; public BlendableFloat wallCushion; public BlendableFloat pivotVerticalOffset; public BlendableVector3 idealLocalCameraPos; public BlendableFloat fov; public BlendableBool isFirstPerson; public float overrideFirstPersonFadeDuration; public static readonly CharacterCameraParamsData basic = new CharacterCameraParamsData { minPitch = -70f, maxPitch = 70f, wallCushion = 0.1f, pivotVerticalOffset = 1.6f, idealLocalCameraPos = new UnityEngine.Vector3(0f, 0f, -5f), fov = new BlendableFloat { value = 60f, alpha = 0f }, overrideFirstPersonFadeDuration = 0f }; public static void Blend(in CharacterCameraParamsData src, ref CharacterCameraParamsData dest, float alpha) { BlendableFloat.Blend(in src.minPitch, ref dest.minPitch, alpha); BlendableFloat.Blend(in src.maxPitch, ref dest.maxPitch, alpha); BlendableFloat.Blend(in src.wallCushion, ref dest.wallCushion, alpha); BlendableFloat.Blend(in src.pivotVerticalOffset, ref dest.pivotVerticalOffset, alpha); BlendableVector3.Blend(in src.idealLocalCameraPos, ref dest.idealLocalCameraPos, alpha); BlendableFloat.Blend(in src.fov, ref dest.fov, alpha); BlendableBool.Blend(in src.isFirstPerson, ref dest.isFirstPerson, alpha); } } [CreateAssetMenu(menuName = "RoR2/SpawnCards/CharacterSpawnCard")] public class CharacterSpawnCard : SpawnCard, MasterSummon.IInventorySetupCallback { public bool noElites; public bool forbiddenAsBoss; [CanBeNull] [Tooltip("The loadout for any summoned character to use.")] [FormerlySerializedAs("loadout")] [SerializeField] private SerializableLoadout _loadout; [CanBeNull] [Tooltip("The inventory from which to initially paste into any summoned character's inventory. Will skip certain non-bequeathable items. This is usually not a good idea to set up in the editor, and is more reserved for runtime.")] public Inventory inventoryToCopy; [CanBeNull] public Func inventoryItemCopyFilter; [Tooltip("The set of equipment to grant to any summoned character, after inventory copy.")] [NotNull] public EquipmentDef[] equipmentToGrant = Array.Empty(); [Tooltip("The set of items to grant to any summoned character, after inventory copy.")] [NotNull] public ItemCountPair[] itemsToGrant = Array.Empty(); [CanBeNull] protected Loadout runtimeLoadout; private static ResourceAvailability loadoutAvailability; [CanBeNull] public SerializableLoadout loadout { get { return _loadout; } set { if (_loadout != value) { _loadout = value; if (loadoutAvailability.available) { SetLoadoutFromSerializedLoadout(); } else { loadoutAvailability.CallWhenAvailable(SetLoadoutFromSerializedLoadout); } } } } public void Awake() { if (!loadoutAvailability.available) { loadoutAvailability.CallWhenAvailable(SetLoadoutFromSerializedLoadout); } else { SetLoadoutFromSerializedLoadout(); } } private void SetLoadoutFromSerializedLoadout() { SetLoadout(loadout); } private void SetLoadout([CanBeNull] SerializableLoadout serializableLoadout) { if (Application.isPlaying) { runtimeLoadout = ((serializableLoadout != null && !serializableLoadout.isEmpty) ? new Loadout() : null); if (runtimeLoadout != null) { serializableLoadout.Apply(runtimeLoadout); } } } [CanBeNull] protected virtual Loadout GetRuntimeLoadout() { return runtimeLoadout; } [CanBeNull] protected virtual Action GetPreSpawnSetupCallback() { return null; } protected override void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest directorSpawnRequest, ref SpawnResult result) { MasterSummon masterSummon = new MasterSummon { masterPrefab = prefab, position = position, rotation = rotation, summonerBodyObject = directorSpawnRequest.summonerBodyObject, teamIndexOverride = directorSpawnRequest.teamIndexOverride, ignoreTeamMemberLimit = directorSpawnRequest.ignoreTeamMemberLimit, loadout = GetRuntimeLoadout(), inventoryToCopy = inventoryToCopy, inventoryItemCopyFilter = inventoryItemCopyFilter, inventorySetupCallback = this, preSpawnSetupCallback = GetPreSpawnSetupCallback(), useAmbientLevel = true }; result.spawnedInstance = masterSummon.Perform()?.gameObject; result.success = result.spawnedInstance; } [SystemInitializer(new Type[] { typeof(Loadout) })] private static void Init() { loadoutAvailability.MakeAvailable(); } void MasterSummon.IInventorySetupCallback.SetupSummonedInventory(MasterSummon masterSummon, Inventory summonedInventory) { SetupSummonedInventory(masterSummon, summonedInventory); } protected virtual void SetupSummonedInventory(MasterSummon masterSummon, Inventory summonedInventory) { for (int i = 0; i < equipmentToGrant.Length; i++) { EquipmentState equipment = summonedInventory.GetEquipment((uint)i); summonedInventory.SetEquipment(new EquipmentState(equipmentToGrant[i]?.equipmentIndex ?? EquipmentIndex.None, equipment.chargeFinishTime, equipment.charges), (uint)i); } for (int j = 0; j < itemsToGrant.Length; j++) { ItemCountPair itemCountPair = itemsToGrant[j]; summonedInventory.GiveItem(itemCountPair.itemDef, itemCountPair.count); } } public void OnValidate() { if (occupyPosition) { UnityEngine.Debug.LogErrorFormat("{0} OccupyPosition=1.This is only intended for limited spawns, and will prevent spawning on this node in the future! Are ya sure? ", this); } } } [CreateAssetMenu(menuName = "RoR2/DCCS/DccsPool")] public class DccsPool : ScriptableObject { [Serializable] public class PoolEntry : ISerializationCallbackReceiver { public DirectorCardCategorySelection dccs; [Tooltip("The weight of this entry relative to its siblings")] public float weight; [HideInInspector] [SerializeField] protected bool hasBeenSerialized; public void OnBeforeSerialize() { hasBeenSerialized = true; } public virtual void OnAfterDeserialize() { if (!hasBeenSerialized) { weight = 1f; } } } [Serializable] public class ConditionalPoolEntry : PoolEntry { [Tooltip("ALL expansions in this list must be enabled for this run for this entry to be considered.")] public ExpansionDef[] requiredExpansions; } [Serializable] public class Category : ISerializationCallbackReceiver { [Tooltip("A name to help identify this category")] public string name; [Tooltip("The weight of all entries in this category relative to the sibling categories.")] public float categoryWeight = 1f; [Tooltip("These entries are always considered.")] public PoolEntry[] alwaysIncluded; [Tooltip("These entries are only considered if their individual conditions are met.")] public ConditionalPoolEntry[] includedIfConditionsMet; [Tooltip("These entries are considered only if no entries from 'includedIfConditionsMet' have been included.")] public PoolEntry[] includedIfNoConditionsMet; [HideInInspector] [SerializeField] protected bool hasBeenSerialized; public void OnBeforeSerialize() { hasBeenSerialized = true; } public void OnAfterDeserialize() { if (!hasBeenSerialized) { categoryWeight = 1f; } } } [SerializeField] private Category[] poolCategories; internal DirectorCardCategorySelection TrySelectPool(string selectionName) { return poolCategories.FirstOrDefault((Category category) => category.includedIfConditionsMet.Any((ConditionalPoolEntry entry) => entry.dccs.name == selectionName))?.includedIfConditionsMet.First().dccs; } public WeightedSelection GenerateWeightedSelection() { WeightedSelection weightedSelection = new WeightedSelection(); Category[] array = poolCategories; foreach (Category category in array) { float num = SumAllWeightsInCategory(category); if (!(num > 0f)) { continue; } float num2 = category.categoryWeight / num; PoolEntry[] alwaysIncluded = category.alwaysIncluded; foreach (PoolEntry poolEntry in alwaysIncluded) { if (poolEntry.dccs.IsAvailable()) { weightedSelection.AddChoice(poolEntry.dccs, poolEntry.weight * num2); } } bool flag = false; ConditionalPoolEntry[] includedIfConditionsMet = category.includedIfConditionsMet; foreach (ConditionalPoolEntry conditionalPoolEntry in includedIfConditionsMet) { if (conditionalPoolEntry.dccs.IsAvailable() && AreConditionsMet(conditionalPoolEntry)) { weightedSelection.AddChoice(conditionalPoolEntry.dccs, conditionalPoolEntry.weight * num2); flag = true; } } if (flag) { continue; } alwaysIncluded = category.includedIfNoConditionsMet; foreach (PoolEntry poolEntry2 in alwaysIncluded) { if (poolEntry2.dccs.IsAvailable()) { weightedSelection.AddChoice(poolEntry2.dccs, poolEntry2.weight * num2); } } } return weightedSelection; } private float SumAllWeightsInCategory(Category category) { float num = 0f; PoolEntry[] alwaysIncluded = category.alwaysIncluded; foreach (PoolEntry poolEntry in alwaysIncluded) { if (poolEntry.dccs.IsAvailable()) { num += poolEntry.weight; } } bool flag = false; ConditionalPoolEntry[] includedIfConditionsMet = category.includedIfConditionsMet; foreach (ConditionalPoolEntry conditionalPoolEntry in includedIfConditionsMet) { if (conditionalPoolEntry.dccs.IsAvailable() && AreConditionsMet(conditionalPoolEntry)) { num += conditionalPoolEntry.weight; flag = true; } } if (!flag) { alwaysIncluded = category.includedIfNoConditionsMet; foreach (PoolEntry poolEntry2 in alwaysIncluded) { if (poolEntry2.dccs.IsAvailable()) { num += poolEntry2.weight; } } } return num; } private bool AreConditionsMet(ConditionalPoolEntry entry) { if (Run.instance != null) { ExpansionDef[] requiredExpansions = entry.requiredExpansions; foreach (ExpansionDef expansionDef in requiredExpansions) { if (!Run.instance.IsExpansionEnabled(expansionDef)) { return false; } } return true; } return false; } } [CreateAssetMenu(menuName = "RoR2/DCCS/DirectorCardCategorySelection")] public class DirectorCardCategorySelection : ScriptableObject { public delegate void CalcCardWeight(DirectorCard card, ref float weight); [Serializable] public struct Category { [Tooltip("A name to help identify this category")] public string name; public DirectorCard[] cards; public float selectionWeight; } public Category[] categories = Array.Empty(); public static event CalcCardWeight calcCardWeight; public float SumAllWeightsInCategory(Category category) { float num = 0f; for (int i = 0; i < category.cards.Length; i++) { if (category.cards[i].IsAvailable()) { num += (float)category.cards[i].selectionWeight; } } return num; } public int FindCategoryIndexByName(string categoryName) { for (int i = 0; i < categories.Length; i++) { if (string.CompareOrdinal(categories[i].name, categoryName) == 0) { return i; } } return -1; } public void CopyFrom([NotNull] DirectorCardCategorySelection src) { Category[] array = src.categories; Array.Resize(ref categories, src.categories.Length); for (int i = 0; i < categories.Length; i++) { ref Category reference = ref categories[i]; reference = array[i]; reference.cards = ArrayUtils.Clone(reference.cards); } } public WeightedSelection GenerateDirectorCardWeightedSelection() { WeightedSelection weightedSelection = new WeightedSelection(); for (int i = 0; i < categories.Length; i++) { ref Category reference = ref categories[i]; float num = SumAllWeightsInCategory(reference); float num2 = reference.selectionWeight / num; if (!(num > 0f)) { continue; } DirectorCard[] cards = reference.cards; foreach (DirectorCard directorCard in cards) { if (directorCard.IsAvailable()) { float weight = (float)directorCard.selectionWeight * num2; DirectorCardCategorySelection.calcCardWeight?.Invoke(directorCard, ref weight); weightedSelection.AddChoice(directorCard, weight); } } } return weightedSelection; } public void Clear() { categories = Array.Empty(); } public int AddCategory(string name, float selectionWeight) { Category category = default(Category); category.name = name; category.cards = Array.Empty(); category.selectionWeight = selectionWeight; Category value = category; ArrayUtils.ArrayAppend(ref categories, in value); return categories.Length - 1; } public int AddCard(int categoryIndex, DirectorCard card) { if ((uint)categoryIndex >= categories.Length) { throw new ArgumentOutOfRangeException("categoryIndex"); } ref DirectorCard[] cards = ref categories[categoryIndex].cards; ArrayUtils.ArrayAppend(ref cards, in card); return cards.Length - 1; } public void RemoveCardsThatFailFilter(Predicate predicate) { for (int i = 0; i < categories.Length; i++) { ref Category reference = ref categories[i]; for (int num = reference.cards.Length - 1; num >= 0; num--) { DirectorCard obj = reference.cards[num]; if (!predicate(obj)) { ArrayUtils.ArrayRemoveAtAndResize(ref reference.cards, num); } } } } public virtual bool IsAvailable() { return true; } public virtual void OnSelected(ClassicStageInfo stageInfo) { } public void OnValidate() { for (int i = 0; i < categories.Length; i++) { Category category = categories[i]; if (category.selectionWeight <= 0f) { UnityEngine.Debug.LogErrorFormat("'{0}' in '{1}' has no weight!", category.name, this); } for (int j = 0; j < category.cards.Length; j++) { DirectorCard directorCard = category.cards[j]; if ((float)directorCard.selectionWeight <= 0f) { UnityEngine.Debug.LogErrorFormat("'{0}' in '{1}' has no weight!", directorCard.spawnCard.name, this); } } } } } [CreateAssetMenu(menuName = "RoR2/EliteDef")] public class EliteDef : ScriptableObject { public string modifierToken; public EquipmentDef eliteEquipmentDef; public Color32 color; public int shaderEliteRampIndex = -1; public float healthBoostCoefficient = 1f; public float damageBoostCoefficient = 1f; public EliteIndex eliteIndex { get; set; } = EliteIndex.None; public bool IsAvailable() { if ((bool)eliteEquipmentDef) { if ((bool)Run.instance) { return !Run.instance.IsEquipmentExpansionLocked(eliteEquipmentDef.equipmentIndex); } return false; } return true; } [ConCommand(commandName = "elites_migrate", flags = ConVarFlags.None, helpText = "Generates EliteDef assets from the existing catalog entries.")] private static void CCElitesMigrate(ConCommandArgs args) { for (EliteIndex eliteIndex = (EliteIndex)0; (int)eliteIndex < EliteCatalog.eliteList.Count; eliteIndex++) { EditorUtil.CopyToScriptableObject(EliteCatalog.GetEliteDef(eliteIndex), "Assets/RoR2/Resources/EliteDefs/"); } } } [CreateAssetMenu(menuName = "RoR2/EntityStateConfiguration")] public class EntityStateConfiguration : ScriptableObject { [SerializableSystemType.RequiredBaseType(typeof(EntityState))] public SerializableSystemType targetType; public SerializedFieldCollection serializedFieldsCollection; public static event Action onEditorUpdatedConfigurationGlobal; [ContextMenu("Set Name from Target Type")] public void SetNameFromTargetType() { Type type = (Type)targetType; if (!(type == null)) { base.name = type.FullName; } } public void ApplyStatic() { Type type = (Type)targetType; if (type == null) { return; } SerializedField[] serializedFields = serializedFieldsCollection.serializedFields; for (int i = 0; i < serializedFields.Length; i++) { SerializedField serializedField = serializedFields[i]; try { FieldInfo field = type.GetField(serializedField.fieldName, BindingFlags.Static | BindingFlags.Public); if ((object)field != null) { SerializedValue fieldValue = serializedField.fieldValue; field.SetValue(null, fieldValue.GetValue(field)); } } catch (Exception message) { UnityEngine.Debug.LogError(message); } } } [CanBeNull] public Action BuildInstanceInitializer() { Type type = (Type)targetType; if (type == null) { return null; } SerializedField[] serializedFields = serializedFieldsCollection.serializedFields; List<(FieldInfo, object)> list = CollectionPool<(FieldInfo, object), List<(FieldInfo, object)>>.RentCollection(); for (int i = 0; i < serializedFields.Length; i++) { ref SerializedField reference = ref serializedFields[i]; try { FieldInfo field = type.GetField(reference.fieldName); if (!(field == null) && FieldPassesFilter(field)) { list.Add((field, reference.fieldValue.GetValue(field))); } } catch (Exception message) { UnityEngine.Debug.LogError(message); } } if (list.Count == 0) { list = CollectionPool<(FieldInfo, object), List<(FieldInfo, object)>>.ReturnCollection(list); return null; } (FieldInfo, object)[] fieldValuesArray = list.ToArray(); list = CollectionPool<(FieldInfo, object), List<(FieldInfo, object)>>.ReturnCollection(list); return InitializeObject; static bool FieldPassesFilter(FieldInfo fieldInfo) { return CustomAttributeExtensions.GetCustomAttribute(fieldInfo) != null; } void InitializeObject(object obj) { for (int j = 0; j < fieldValuesArray.Length; j++) { var (fieldInfo2, value) = fieldValuesArray[j]; fieldInfo2.SetValue(obj, value); } } } private void Awake() { serializedFieldsCollection.PurgeUnityPsuedoNullFields(); } private void OnValidate() { if (Application.isPlaying) { RoR2Application.onNextUpdate += delegate { EntityStateConfiguration.onEditorUpdatedConfigurationGlobal?.Invoke(this); }; } } } [CreateAssetMenu(menuName = "RoR2/EquipmentDef")] public class EquipmentDef : ScriptableObject { private EquipmentIndex _equipmentIndex = EquipmentIndex.None; public GameObject pickupModelPrefab; public float cooldown; public string nameToken; public string pickupToken; public string descriptionToken; public string loreToken; public bool isConsumed; public Sprite pickupIconSprite; public UnlockableDef unlockableDef; public ColorCatalog.ColorIndex colorIndex = ColorCatalog.ColorIndex.Equipment; public bool canDrop; [Range(0f, 1f)] public float dropOnDeathChance; public bool canBeRandomlyTriggered = true; public bool enigmaCompatible; public bool isLunar; public bool isBoss; public BuffDef passiveBuffDef; public bool appearsInSinglePlayer = true; public bool appearsInMultiPlayer = true; public ExpansionDef requiredExpansion; public static GameObject dropletDisplayPrefab; [HideInInspector] [Obsolete] public MageElement mageElement; public EquipmentIndex equipmentIndex { get { if (_equipmentIndex == EquipmentIndex.None) { UnityEngine.Debug.LogError("EquipmentDef '" + base.name + "' has an equipment index of 'None'. Attempting to fix..."); _equipmentIndex = EquipmentCatalog.FindEquipmentIndex(base.name); if (_equipmentIndex != EquipmentIndex.None) { UnityEngine.Debug.LogError($"Able to fix EquipmentDef '{base.name}' (equipment index = {_equipmentIndex}). This is probably because the asset is being duplicated across bundles."); } } return _equipmentIndex; } set { _equipmentIndex = value; } } public Texture pickupIconTexture { get { if (!pickupIconSprite) { return null; } return pickupIconSprite.texture; } } public Texture bgIconTexture { get { if (isLunar) { return LegacyResourcesAPI.Load("Textures/ItemIcons/BG/texLunarBGIcon"); } return LegacyResourcesAPI.Load("Textures/ItemIcons/BG/texEquipmentBGIcon"); } } public static void AttemptGrant(ref PickupDef.GrantContext context) { context.controller.StartWaitTime(); Inventory inventory = context.body.inventory; EquipmentIndex currentEquipmentIndex = inventory.currentEquipmentIndex; EquipmentIndex equipmentIndex = PickupCatalog.GetPickupDef(context.controller.pickupIndex)?.equipmentIndex ?? EquipmentIndex.None; inventory.SetEquipmentIndex(equipmentIndex); context.controller.NetworkpickupIndex = PickupCatalog.FindPickupIndex(currentEquipmentIndex); context.shouldDestroy = false; context.shouldNotify = true; if (context.controller.pickupIndex == PickupIndex.none) { context.shouldDestroy = true; } if (context.controller.selfDestructIfPickupIndexIsNotIdeal && context.controller.pickupIndex != PickupCatalog.FindPickupIndex(context.controller.idealPickupIndex.pickupName)) { PickupDropletController.CreatePickupDroplet(context.controller.pickupIndex, context.controller.transform.position, new UnityEngine.Vector3(UnityEngine.Random.Range(-4f, 4f), 20f, UnityEngine.Random.Range(-4f, 4f))); context.shouldDestroy = true; } } [ContextMenu("Auto Populate Tokens")] public void AutoPopulateTokens() { string arg = base.name.ToUpperInvariant(); nameToken = $"EQUIPMENT_{arg}_NAME"; pickupToken = $"EQUIPMENT_{arg}_PICKUP"; descriptionToken = $"EQUIPMENT_{arg}_DESC"; loreToken = $"EQUIPMENT_{arg}_LORE"; } public static void SetDropletDisplayPrefab(GameObject gameObj) { dropletDisplayPrefab = gameObj; } public virtual PickupDef CreatePickupDef() { PickupDef obj = new PickupDef { internalName = "EquipmentIndex." + base.name, equipmentIndex = equipmentIndex, displayPrefab = pickupModelPrefab, dropletDisplayPrefab = dropletDisplayPrefab, nameToken = nameToken, baseColor = ColorCatalog.GetColor(colorIndex) }; obj.darkColor = obj.baseColor; obj.unlockableDef = unlockableDef; obj.interactContextToken = "EQUIPMENT_PICKUP_CONTEXT"; obj.isLunar = isLunar; obj.isBoss = isBoss; obj.iconTexture = pickupIconTexture; obj.iconSprite = pickupIconSprite; obj.attemptGrant = AttemptGrant; return obj; } [ConCommand(commandName = "equipment_migrate", flags = ConVarFlags.None, helpText = "Generates EquipmentDef assets from the existing catalog entries.")] private static void CCEquipmentMigrate(ConCommandArgs args) { for (EquipmentIndex equipmentIndex = (EquipmentIndex)0; (int)equipmentIndex < EquipmentCatalog.equipmentCount; equipmentIndex++) { EditorUtil.CopyToScriptableObject(EquipmentCatalog.GetEquipmentDef(equipmentIndex), "Assets/RoR2/Resources/EquipmentDefs/"); } } } [CreateAssetMenu(menuName = "RoR2/DCCS/FamilyDirectorCardCategorySelection")] public class FamilyDirectorCardCategorySelection : DirectorCardCategorySelection { private const float chatMessageDelaySeconds = 1f; [SerializeField] private string selectionChatString; [SerializeField] [Tooltip("The minimum (inclusive) number of stages COMPLETED (not reached) before this family event becomes available.")] private int minimumStageCompletion = 1; [Tooltip("The maximum (exclusive) number of stages COMPLETED (not reached) before this family event becomes unavailable.")] [SerializeField] private int maximumStageCompletion = int.MaxValue; public override bool IsAvailable() { if ((bool)Run.instance && Run.instance.canFamilyEventTrigger && minimumStageCompletion <= Run.instance.stageClearCount) { return maximumStageCompletion > Run.instance.stageClearCount; } return false; } public override void OnSelected(ClassicStageInfo stageInfo) { if (!string.IsNullOrEmpty(selectionChatString)) { stageInfo.StartCoroutine(stageInfo.BroadcastFamilySelection(selectionChatString)); } } } [CreateAssetMenu(menuName = "RoR2/GameEndingDef")] public class GameEndingDef : ScriptableObject { public string endingTextToken; public UnityEngine.Color backgroundColor; public UnityEngine.Color foregroundColor; public Sprite icon; public Material material; [Tooltip("The body prefab to use as the killer when this ending is triggered while players are still alive.")] public GameObject defaultKillerOverride; public bool isWin; public bool showCredits; public SerializableEntityStateType gameOverControllerState; public uint lunarCoinReward; private string _cachedName; public GameEndingIndex gameEndingIndex { get; set; } [Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)] public new string name { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public string cachedName { get { return _cachedName; } set { base.name = value; _cachedName = value; } } private void Awake() { _cachedName = base.name; } private void OnValidate() { _cachedName = base.name; } } public enum GameEndingIndex { Invalid = -1 } public static class GameEndingCatalog { private static GameEndingDef[] gameEndingDefs = Array.Empty(); public static int endingCount => gameEndingDefs.Length; [Obsolete("Use IContentPackProvider instead.")] public static event Action> collectEntries { add { LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.GameEndingCatalog.collectEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.gameEndingDefs); } remove { } } [SystemInitializer(new Type[] { })] private static void Init() { HGXml.Register(delegate(XElement element, GameEndingDef contents) { element.Value = contents?.cachedName ?? ""; }, delegate(XElement element, ref GameEndingDef contents) { contents = FindGameEndingDef(element.Value); return true; }); SetGameEndingDefs(ContentManager.gameEndingDefs); } private static void SetGameEndingDefs(GameEndingDef[] newGameEndingDefs) { GameEndingDef[] array = gameEndingDefs; for (int i = 0; i < array.Length; i++) { array[i].gameEndingIndex = GameEndingIndex.Invalid; } ArrayUtils.CloneTo(newGameEndingDefs, ref gameEndingDefs); Array.Sort(gameEndingDefs, (GameEndingDef a, GameEndingDef b) => string.CompareOrdinal(a.cachedName, b.cachedName)); for (int j = 0; j < gameEndingDefs.Length; j++) { gameEndingDefs[j].gameEndingIndex = (GameEndingIndex)j; } } public static GameEndingDef GetGameEndingDef(GameEndingIndex gameEndingIndex) { return ArrayUtils.GetSafe(gameEndingDefs, (int)gameEndingIndex); } public static GameEndingIndex FindGameEndingIndex(string gameEndingName) { for (int i = 0; i < gameEndingDefs.Length; i++) { if (string.CompareOrdinal(gameEndingName, gameEndingDefs[i].cachedName) == 0) { return (GameEndingIndex)i; } } return GameEndingIndex.Invalid; } public static GameEndingDef FindGameEndingDef(string gameEndingName) { return GetGameEndingDef(FindGameEndingIndex(gameEndingName)); } public static GameEndingIndex GetGameEndingIndex([CanBeNull] GameEndingDef gameEndingDef) { if (!gameEndingDef) { return GameEndingIndex.Invalid; } return gameEndingDef.gameEndingIndex; } } [CreateAssetMenu(menuName = "RoR2/GameObjectFactory")] public class GameObjectFactory : ScriptableObject { public bool clearOnPerformInstantiate = true; private GameObject prefab; private UnityEngine.Vector3 spawnPosition; private UnityEngine.Quaternion spawnRotation; private bool isNetworkPrefab; private AnimationClip spawnModificationsClip; public void Reset() { Clear(); clearOnPerformInstantiate = true; } public void Clear() { prefab = null; spawnPosition = UnityEngine.Vector3.zero; spawnRotation = UnityEngine.Quaternion.identity; isNetworkPrefab = false; spawnModificationsClip = null; } public void SetPrefab(GameObject newPrefab) { prefab = newPrefab; isNetworkPrefab = prefab?.GetComponent(); } public void SetSpawnLocation(Transform newSpawnLocation) { spawnPosition = newSpawnLocation.position; spawnRotation = newSpawnLocation.rotation; } public void SetSpawnModificationsClip(AnimationClip newSpawnModificationsClip) { spawnModificationsClip = newSpawnModificationsClip; } public void PerformInstantiate() { if ((bool)prefab) { GameObject gameObject = UnityEngine.Object.Instantiate(prefab, spawnPosition, spawnRotation); if ((bool)spawnModificationsClip) { Animator obj = gameObject.AddComponent(); spawnModificationsClip.SampleAnimation(gameObject, 0f); UnityEngine.Object.Destroy(obj); } gameObject.SetActive(value: true); if (isNetworkPrefab && NetworkServer.active) { NetworkServer.Spawn(gameObject); } if (clearOnPerformInstantiate) { Clear(); } } } } [CreateAssetMenu(menuName = "RoR2/Singletons/GlobalEventMethodLibrary")] public class GlobalEventMethodLibrary : ScriptableObject { public void RunAdvanceStageServer(SceneDef nextScene) { if (NetworkServer.active && (bool)Run.instance) { Run.instance.AdvanceStage(nextScene); } } public void RunBeginGameOverServer(GameEndingDef endingDef) { if (NetworkServer.active && (bool)Run.instance) { Run.instance.BeginGameOver(endingDef); } } public void LogMessage(string message) { } public void ForcePlayableDirectorFinish(PlayableDirector playableDirector) { playableDirector.time = playableDirector.duration; } public new void DestroyObject(UnityEngine.Object obj) { UnityEngine.Object.Destroy(obj); } public void DisableAllSiblings(Transform transform) { if (!transform) { return; } Transform parent = transform.parent; if (!parent) { return; } int i = 0; for (int childCount = parent.childCount; i < childCount; i++) { Transform child = parent.GetChild(i); if ((bool)child && child != transform) { child.gameObject.SetActive(value: false); } } } public void DisableAllSiblings(GameObject gameObject) { if ((bool)gameObject) { DisableAllSiblings(gameObject.transform); } } public void ActivateGameObjectIfServer(GameObject gameObject) { if ((bool)gameObject && NetworkServer.active) { gameObject.SetActive(value: true); } } public void DeactivateGameObjectIfServer(GameObject gameObject) { if ((bool)gameObject && NetworkServer.active) { gameObject.SetActive(value: false); } } } [CreateAssetMenu(menuName = "RoR2/Infinite Tower/Infinite Tower Wave Artifact Prerequisites")] public class InfiniteTowerWaveArtifactPrerequisites : InfiniteTowerWavePrerequisites { [SerializeField] [Tooltip("This wave cannot be selected while this artifact is enabled.")] private ArtifactDef bannedArtifact; public override bool AreMet(InfiniteTowerRun run) { return !RunArtifactManager.instance.IsArtifactEnabled(bannedArtifact); } } [CreateAssetMenu(menuName = "RoR2/Infinite Tower/Infinite Tower Wave Category")] public class InfiniteTowerWaveCategory : ScriptableObject { [Serializable] public struct WeightedWave { public GameObject wavePrefab; public InfiniteTowerWavePrerequisites prerequisites; public float weight; } private readonly WeightedSelection weightedSelection = new WeightedSelection(); [SerializeField] [Tooltip("The weighted selection for which wave prefab to use")] private WeightedWave[] wavePrefabs; [Tooltip("The period of how often this category is available, e.g.\"every N waves\".")] [SerializeField] private int availabilityPeriod; [Tooltip("The minimum wave index where this category is available (inclusive)")] [SerializeField] private int minWaveIndex; public bool IsAvailable(InfiniteTowerRun run) { bool num = availabilityPeriod > 0 && run.waveIndex % availabilityPeriod == 0; bool flag = run.waveIndex >= minWaveIndex; bool flag2 = wavePrefabs.Length != 0; if (num && flag && flag2) { WeightedWave[] array = wavePrefabs; for (int i = 0; i < array.Length; i++) { WeightedWave weightedWave = array[i]; if (!weightedWave.prerequisites || weightedWave.prerequisites.AreMet(run)) { return true; } } } return false; } public GameObject SelectWavePrefab(InfiniteTowerRun run, Xoroshiro128Plus rng) { if (weightedSelection.Count < wavePrefabs.Length) { GenerateWeightedSelection(); } WeightedWave[] array = wavePrefabs; for (int i = 0; i < array.Length; i++) { WeightedWave weightedWave = array[i]; if (!weightedWave.prerequisites || weightedWave.prerequisites.AreMet(run)) { continue; } for (int j = 0; j < weightedSelection.Count; j++) { if ((object)weightedSelection.choices[j].value == weightedWave.wavePrefab) { weightedSelection.RemoveChoice(j); break; } } } return weightedSelection.Evaluate(rng.nextNormalizedFloat); } private void GenerateWeightedSelection() { weightedSelection.Clear(); WeightedWave[] array = wavePrefabs; for (int i = 0; i < array.Length; i++) { WeightedWave weightedWave = array[i]; weightedSelection.AddChoice(weightedWave.wavePrefab, weightedWave.weight); } } } [CreateAssetMenu(menuName = "RoR2/Infinite Tower/Infinite Tower Wave Count Prerequisites")] public class InfiniteTowerWaveCountPrerequisites : InfiniteTowerWavePrerequisites { [SerializeField] private int minimumWaveCount; public override bool AreMet(InfiniteTowerRun run) { return run.waveIndex >= minimumWaveCount; } } public abstract class InfiniteTowerWavePrerequisites : ScriptableObject { public abstract bool AreMet(InfiniteTowerRun run); } [CreateAssetMenu(menuName = "RoR2/InspectableDef")] public class InspectDef : ScriptableObject { public InspectInfo Info; } [CreateAssetMenu(menuName = "RoR2/SpawnCards/InteractableSpawnCard")] public class InteractableSpawnCard : SpawnCard { [Tooltip("Whether or not to orient the object to the normal of the ground it spawns on.")] public bool orientToFloor; [Tooltip("Slightly tweaks the rotation for things like chests and barrels so it looks more natural.")] public bool slightlyRandomizeOrientation; public bool skipSpawnWhenSacrificeArtifactEnabled; [Tooltip("When Sacrifice is enabled, this is multiplied by the card's weight")] public float weightScalarWhenSacrificeArtifactEnabled = 1f; public bool skipSpawnWhenDevotionArtifactEnabled; [Tooltip("Won't spawn more than this many per stage. If it's negative, there's no cap")] public int maxSpawnsPerStage = -1; [Range(0f, 1f)] [SerializeField] [Tooltip("When playing Primatic Trials, this interactable will have a required check to see if it is supposed to spawn. 0 is will not spawn, 1 will 100% spawn and will be default.")] public float prismaticTrialSpawnChance = 1f; private static readonly float floorOffset = 3f; private static readonly float raycastLength = 6f; private static readonly Xoroshiro128Plus rng = new Xoroshiro128Plus(0uL); protected override void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest directorSpawnRequest, ref SpawnResult result) { ulong nextUlong = directorSpawnRequest.rng.nextUlong; rng.ResetSeed(nextUlong); if (skipSpawnWhenSacrificeArtifactEnabled && RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.sacrificeArtifactDef)) { return; } GameObject gameObject = UnityEngine.Object.Instantiate(prefab, position, rotation); Transform transform = gameObject.transform; if (orientToFloor) { UnityEngine.Vector3 up = gameObject.transform.up; if (Physics.Raycast(new Ray(position + up * floorOffset, -up), out var hitInfo, raycastLength + floorOffset, LayerIndex.world.mask)) { transform.up = hitInfo.normal; } } transform.Rotate(UnityEngine.Vector3.up, rng.RangeFloat(0f, 360f), Space.Self); if (slightlyRandomizeOrientation) { transform.Translate(UnityEngine.Vector3.down * 0.3f, Space.Self); transform.rotation *= UnityEngine.Quaternion.Euler(rng.RangeFloat(-30f, 30f), rng.RangeFloat(-30f, 30f), rng.RangeFloat(-30f, 30f)); } NetworkServer.Spawn(gameObject); result.spawnedInstance = gameObject; result.success = true; } } [CreateAssetMenu(menuName = "RoR2/ItemDef")] public class ItemDef : ScriptableObject { [Serializable] public struct Pair : IEquatable { public ItemDef itemDef1; public ItemDef itemDef2; public override int GetHashCode() { return itemDef1.GetHashCode() ^ ~itemDef2.GetHashCode(); } public override bool Equals(object obj) { if (obj is Pair) { return Equals((Pair)obj); } return false; } public bool Equals(Pair other) { if (other.itemDef1 == itemDef1) { return other.itemDef2 == itemDef2; } return false; } } private ItemIndex _itemIndex = ItemIndex.None; [FormerlySerializedAs("tier")] [Obsolete("Replaced by itemTierDef field", false)] [Tooltip("Deprecated. Use itemTierDef instead.")] [SerializeField] private ItemTier deprecatedTier; [SerializeField] private ItemTierDef _itemTierDef; public string nameToken; public string pickupToken; public string descriptionToken; public string loreToken; public UnlockableDef unlockableDef; public GameObject pickupModelPrefab; public Sprite pickupIconSprite; public bool isConsumed; public bool hidden; public bool canRemove = true; public ItemTag[] tags = Array.Empty(); public ExpansionDef requiredExpansion; public ItemIndex itemIndex { get { if (_itemIndex == ItemIndex.None) { UnityEngine.Debug.LogError("ItemDef '" + base.name + "' has an item index of 'None'. Attempting to fix..."); _itemIndex = ItemCatalog.FindItemIndex(base.name); if (_itemIndex != ItemIndex.None) { UnityEngine.Debug.LogError($"Able to fix ItemDef '{base.name}' (item index = {_itemIndex}). This is probably because the asset is being duplicated across bundles."); } } return _itemIndex; } set { _itemIndex = value; } } public ItemTier tier { get { if ((bool)_itemTierDef) { return _itemTierDef.tier; } return deprecatedTier; } set { _itemTierDef = ItemTierCatalog.GetItemTierDef(value); } } [Obsolete("Get isDroppable from the ItemTierDef instead")] public bool inDroppableTier { get { ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(tier); if ((bool)itemTierDef) { return itemTierDef.isDroppable; } return false; } } public Texture pickupIconTexture { get { if (!pickupIconSprite) { return null; } return pickupIconSprite.texture; } } [Obsolete("Get bgIconTexture from the ItemTierDef instead")] public Texture bgIconTexture => ItemTierCatalog.GetItemTierDef(tier)?.bgIconTexture; [Obsolete("Get colorIndex from the ItemTierDef instead")] public ColorCatalog.ColorIndex colorIndex => ItemTierCatalog.GetItemTierDef(tier)?.colorIndex ?? ColorCatalog.ColorIndex.Unaffordable; [Obsolete("Get darkColorIndex from the ItemTierDef instead")] public ColorCatalog.ColorIndex darkColorIndex => ItemTierCatalog.GetItemTierDef(tier)?.darkColorIndex ?? ColorCatalog.ColorIndex.Unaffordable; public static void AttemptGrant(ref PickupDef.GrantContext context) { context.body.inventory.GiveItem(PickupCatalog.GetPickupDef(context.controller.pickupIndex)?.itemIndex ?? ItemIndex.None); context.body.inventory.GetItemCount(PickupCatalog.GetPickupDef(context.controller.pickupIndex).itemIndex); context.shouldDestroy = true; context.shouldNotify = true; } public bool ContainsTag(ItemTag tag) { if (tag == ItemTag.Any) { return true; } return Array.IndexOf(tags, tag) != -1; } public bool DoesNotContainTag(ItemTag tag) { return Array.IndexOf(tags, tag) == -1; } public virtual PickupDef CreatePickupDef() { ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(tier); return new PickupDef { internalName = "ItemIndex." + base.name, itemIndex = itemIndex, itemTier = tier, displayPrefab = pickupModelPrefab, dropletDisplayPrefab = itemTierDef?.dropletDisplayPrefab, nameToken = nameToken, baseColor = ColorCatalog.GetColor(colorIndex), darkColor = ColorCatalog.GetColor(darkColorIndex), unlockableDef = unlockableDef, interactContextToken = "ITEM_PICKUP_CONTEXT", isLunar = (tier == ItemTier.Lunar), isBoss = (tier == ItemTier.Boss), iconTexture = pickupIconTexture, iconSprite = pickupIconSprite, attemptGrant = AttemptGrant }; } [ContextMenu("Auto Populate Tokens")] public void AutoPopulateTokens() { string arg = base.name.ToUpperInvariant(); nameToken = $"ITEM_{arg}_NAME"; pickupToken = $"ITEM_{arg}_PICKUP"; descriptionToken = $"ITEM_{arg}_DESC"; loreToken = $"ITEM_{arg}_LORE"; } [ConCommand(commandName = "items_migrate", flags = ConVarFlags.None, helpText = "Generates ItemDef assets from the existing catalog entries.")] private static void CCItemsMigrate(ConCommandArgs args) { for (ItemIndex itemIndex = ItemIndex.Count; (int)itemIndex < ItemCatalog.itemCount; itemIndex++) { EditorUtil.CopyToScriptableObject(ItemCatalog.GetItemDef(itemIndex), "Assets/RoR2/Resources/ItemDefs/"); } } } [CreateAssetMenu(menuName = "RoR2/ItemDisplayRuleSet")] public class ItemDisplayRuleSet : ScriptableObject { [Serializable] [Obsolete] public struct NamedRuleGroup { public string name; public DisplayRuleGroup displayRuleGroup; } [Serializable] public struct KeyAssetRuleGroup { public UnityEngine.Object keyAsset; public DisplayRuleGroup displayRuleGroup; } [SerializeField] [Obsolete("Use .assetRuleGroups instead.")] private NamedRuleGroup[] namedItemRuleGroups = Array.Empty(); [Obsolete("Use .assetRuleGroups instead.")] [SerializeField] private NamedRuleGroup[] namedEquipmentRuleGroups = Array.Empty(); public KeyAssetRuleGroup[] keyAssetRuleGroups = Array.Empty(); private DisplayRuleGroup[] runtimeItemRuleGroups; private DisplayRuleGroup[] runtimeEquipmentRuleGroups; private static readonly List instancesList = new List(); private static bool runtimeDependenciesReady = false; private bool hasObsoleteNamedRuleGroups { get { if (namedItemRuleGroups.Length == 0) { return namedEquipmentRuleGroups.Length != 0; } return true; } } public bool isEmpty => keyAssetRuleGroups.Length == 0; [SystemInitializer(new Type[] { typeof(ItemCatalog), typeof(EquipmentCatalog) })] private static void Init() { runtimeDependenciesReady = true; for (int i = 0; i < instancesList.Count; i++) { instancesList[i].GenerateRuntimeValues(); } } private void OnEnable() { instancesList.Add(this); if (runtimeDependenciesReady) { GenerateRuntimeValues(); } } private void OnDisable() { instancesList.Remove(this); } private void OnValidate() { if (hasObsoleteNamedRuleGroups) { UnityEngine.Debug.LogWarningFormat(this, "ItemDisplayRuleSet \"{0}\" still defines one or more entries in an obsolete format. Run the upgrade from the inspector context menu.", this); } } public void GenerateRuntimeValues() { runtimeItemRuleGroups = ItemCatalog.GetPerItemBuffer(); runtimeEquipmentRuleGroups = EquipmentCatalog.GetPerEquipmentBuffer(); ArrayUtils.SetAll(runtimeItemRuleGroups, in DisplayRuleGroup.empty); ArrayUtils.SetAll(runtimeEquipmentRuleGroups, in DisplayRuleGroup.empty); for (int i = 0; i < keyAssetRuleGroups.Length; i++) { ref KeyAssetRuleGroup reference = ref keyAssetRuleGroups[i]; UnityEngine.Object keyAsset = reference.keyAsset; if (!(keyAsset is ItemDef itemDef)) { if (keyAsset is EquipmentDef { equipmentIndex: not EquipmentIndex.None } equipmentDef) { runtimeEquipmentRuleGroups[(int)equipmentDef.equipmentIndex] = reference.displayRuleGroup; } } else if (itemDef.itemIndex != ItemIndex.None) { runtimeItemRuleGroups[(int)itemDef.itemIndex] = reference.displayRuleGroup; } } } public DisplayRuleGroup FindDisplayRuleGroup(UnityEngine.Object keyAsset) { if ((bool)keyAsset) { for (int i = 0; i < keyAssetRuleGroups.Length; i++) { ref KeyAssetRuleGroup reference = ref keyAssetRuleGroups[i]; if ((object)reference.keyAsset == keyAsset) { return reference.displayRuleGroup; } } } return DisplayRuleGroup.empty; } public void SetDisplayRuleGroup(UnityEngine.Object keyAsset, DisplayRuleGroup displayRuleGroup) { if (!keyAsset) { return; } for (int i = 0; i < keyAssetRuleGroups.Length; i++) { ref KeyAssetRuleGroup reference = ref keyAssetRuleGroups[i]; if ((object)reference.keyAsset == keyAsset) { reference.displayRuleGroup = displayRuleGroup; return; } } ref KeyAssetRuleGroup[] array = ref keyAssetRuleGroups; KeyAssetRuleGroup value = new KeyAssetRuleGroup { keyAsset = keyAsset, displayRuleGroup = displayRuleGroup }; ArrayUtils.ArrayAppend(ref array, in value); } public DisplayRuleGroup GetItemDisplayRuleGroup(ItemIndex itemIndex) { return ArrayUtils.GetSafe(runtimeItemRuleGroups, (int)itemIndex, in DisplayRuleGroup.empty); } public DisplayRuleGroup GetEquipmentDisplayRuleGroup(EquipmentIndex equipmentIndex) { return ArrayUtils.GetSafe(runtimeEquipmentRuleGroups, (int)equipmentIndex, in DisplayRuleGroup.empty); } public void Reset() { keyAssetRuleGroups = Array.Empty(); runtimeItemRuleGroups = Array.Empty(); runtimeEquipmentRuleGroups = Array.Empty(); } [ContextMenu("Upgrade to keying by asset")] public void UpdgradeToAssetKeying() { _ = Application.isPlaying; if (hasObsoleteNamedRuleGroups) { List list = new List(); UpgradeNamedRuleGroups(ref namedItemRuleGroups, "ItemDef", (string assetName) => ItemCatalog.GetItemDef(ItemCatalog.FindItemIndex(assetName)), list); UpgradeNamedRuleGroups(ref namedEquipmentRuleGroups, "EquipmentDef", (string assetName) => EquipmentCatalog.GetEquipmentDef(EquipmentCatalog.FindEquipmentIndex(assetName)), list); if (list.Count > 0) { UnityEngine.Debug.LogWarningFormat("Encountered {0} errors attempting to upgrade ItemDisplayRuleSet \"{1}\":\n{2}", list.Count, base.name, string.Join("\n", list)); } EditorUtil.SetDirty(this); } } private void UpgradeNamedRuleGroups(ref NamedRuleGroup[] namedRuleGroups, string assetTypeName, Func assetLookupMethod, List failureMessagesList) { int arraySize = namedRuleGroups.Length; for (int i = 0; i < arraySize; i++) { NamedRuleGroup namedRuleGroup = namedRuleGroups[i]; UnityEngine.Object @object = assetLookupMethod(namedRuleGroup.name); string text = null; if (!namedRuleGroup.displayRuleGroup.isEmpty) { if ((bool)@object) { if (FindDisplayRuleGroup(@object).isEmpty) { SetDisplayRuleGroup(@object, namedRuleGroup.displayRuleGroup); } else { text = "Conflicts with existing rule group."; } } else { text = "Named asset not found."; } } if (text != null) { failureMessagesList.Add(assetTypeName + " \"" + namedRuleGroup.name + "\": " + text); } else { ArrayUtils.ArrayRemoveAt(namedRuleGroups, ref arraySize, i); i--; } } Array.Resize(ref namedRuleGroups, arraySize); } } public enum ItemDisplayRuleType { ParentedPrefab, LimbMask } [Flags] public enum LimbFlags { None = 0, Head = 1, RightArm = 2, LeftArm = 4, RightCalf = 8, LeftLeg = 0x10, Count = 5 } [Serializable] public struct ItemDisplayRule : IEquatable { public ItemDisplayRuleType ruleType; public GameObject followerPrefab; public string childName; public UnityEngine.Vector3 localPos; public UnityEngine.Vector3 localAngles; public UnityEngine.Vector3 localScale; public LimbFlags limbMask; public bool Equals(ItemDisplayRule other) { if (ruleType == other.ruleType && object.Equals(followerPrefab, other.followerPrefab) && string.Equals(childName, other.childName) && localPos.Equals(other.localPos) && localAngles.Equals(other.localAngles) && localScale.Equals(other.localScale)) { return limbMask == other.limbMask; } return false; } public override bool Equals(object obj) { if (obj is ItemDisplayRule other) { return Equals(other); } return false; } public override int GetHashCode() { return ((((((((((((int)ruleType * 397) ^ ((followerPrefab != null) ? followerPrefab.GetHashCode() : 0)) * 397) ^ ((childName != null) ? childName.GetHashCode() : 0)) * 397) ^ localPos.GetHashCode()) * 397) ^ localAngles.GetHashCode()) * 397) ^ localScale.GetHashCode()) * 397) ^ (int)limbMask; } } [Serializable] public struct DisplayRuleGroup : IEquatable { public static readonly DisplayRuleGroup empty = new DisplayRuleGroup { rules = null }; public ItemDisplayRule[] rules; public bool isEmpty { get { if (rules != null) { return rules.Length == 0; } return true; } } public void AddDisplayRule(ItemDisplayRule itemDisplayRule) { if (rules == null) { rules = Array.Empty(); } ArrayUtils.ArrayAppend(ref rules, in itemDisplayRule); } public bool Equals(DisplayRuleGroup other) { return ArrayUtils.SequenceEquals(rules, other.rules); } public override bool Equals(object obj) { if (obj is DisplayRuleGroup other) { return Equals(other); } return false; } public override int GetHashCode() { if (rules == null) { return 0; } return rules.GetHashCode(); } } [CreateAssetMenu(menuName = "RoR2/ItemRelationshipProvider")] public class ItemRelationshipProvider : ScriptableObject { public ItemRelationshipType relationshipType; public ItemDef.Pair[] relationships; } [CreateAssetMenu(menuName = "RoR2/ItemRelationshipType")] public class ItemRelationshipType : ScriptableObject { } [CreateAssetMenu(menuName = "RoR2/ItemTierDef")] public class ItemTierDef : ScriptableObject { public enum PickupRules { Default, ConfirmFirst, ConfirmAll } [SerializeField] [FormerlySerializedAs("tier")] private ItemTier _tier; public Texture bgIconTexture; public ColorCatalog.ColorIndex colorIndex; public ColorCatalog.ColorIndex darkColorIndex; public bool isDroppable; public bool canScrap; public bool canRestack; public PickupRules pickupRules; public GameObject highlightPrefab; public GameObject dropletDisplayPrefab; public ItemTier tier { get { if (_tier == ItemTier.AssignedAtRuntime) { UnityEngine.Debug.LogError("ItemTierDef '" + base.name + "' has a tier of 'AssignedAtRuntime'. Attempting to fix..."); _tier = ItemTierCatalog.FindTierDef(base.name)?._tier ?? _tier; if (_tier != ItemTier.AssignedAtRuntime) { UnityEngine.Debug.LogError($"Able to fix ItemTierDef '{base.name}' (_tier = {_tier}). This is probably because the asset is being duplicated across bundles."); } } return _tier; } set { _tier = value; } } } [CreateAssetMenu(menuName = "RoR2/MiscPickupDefs/LunarCoinDef")] public class LunarCoinDef : MiscPickupDef { [SerializeField] public string internalNameOverride; public override string GetInternalName() { if (!string.IsNullOrEmpty(internalNameOverride)) { return internalNameOverride; } return "MiscPickupIndex." + base.name; } public override void GrantPickup(ref PickupDef.GrantContext context) { NetworkUser networkUser = Util.LookUpBodyNetworkUser(context.body); if ((bool)networkUser) { networkUser.AwardLunarCoins(coinValue); context.shouldDestroy = true; context.shouldNotify = true; } else { context.shouldNotify = false; context.shouldDestroy = false; } } } public class MasterCopySpawnCard : CharacterSpawnCard { protected CharacterMaster srcCharacterMaster; protected int[] srcItemStacks; protected EquipmentIndex[] srcEquipment; protected Action onPreSpawnSetup; public static MasterCopySpawnCard FromMaster(CharacterMaster srcCharacterMaster, bool copyItems, bool copyEquipment, Action onPreSpawnSetup = null) { if (!srcCharacterMaster || !srcCharacterMaster.GetBody()) { return null; } MasterCopySpawnCard masterCopySpawnCard = ScriptableObject.CreateInstance(); masterCopySpawnCard.onPreSpawnSetup = onPreSpawnSetup; CopyDataFromMaster(masterCopySpawnCard, srcCharacterMaster, copyItems, copyEquipment); return masterCopySpawnCard; } protected static void CopyDataFromMaster(MasterCopySpawnCard spawnCard, CharacterMaster srcCharacterMaster, bool copyItems, bool copyEquipment) { spawnCard.srcItemStacks = ItemCatalog.RequestItemStackArray(); spawnCard.srcEquipment = Array.Empty(); if (!srcCharacterMaster) { return; } spawnCard.sendOverNetwork = true; spawnCard.runtimeLoadout = new Loadout(); spawnCard.srcCharacterMaster = srcCharacterMaster; spawnCard.srcCharacterMaster.loadout.Copy(spawnCard.runtimeLoadout); if (copyItems) { srcCharacterMaster.inventory.WriteItemStacks(spawnCard.srcItemStacks); } if (copyEquipment) { spawnCard.srcEquipment = new EquipmentIndex[srcCharacterMaster.inventory.GetEquipmentSlotCount()]; for (uint num = 0u; num < spawnCard.srcEquipment.Length; num++) { spawnCard.srcEquipment[num] = srcCharacterMaster.inventory.GetEquipment(num).equipmentIndex; } } CharacterBody body = srcCharacterMaster.GetBody(); if ((bool)body) { spawnCard.hullSize = body.hullClassification; spawnCard.nodeGraphType = (body.isFlying ? MapNodeGroup.GraphType.Air : MapNodeGroup.GraphType.Ground); spawnCard.prefab = MasterCatalog.GetMasterPrefab(MasterCatalog.FindAiMasterIndexForBody(body.bodyIndex)); } } public void GiveItem(ItemIndex itemIndex, int count = 1) { srcItemStacks[(int)itemIndex] += count; } public void GiveItem(ItemDef itemDef, int count = 1) { GiveItem(itemDef?.itemIndex ?? ItemIndex.None, count); } protected override Loadout GetRuntimeLoadout() { return srcCharacterMaster.loadout; } protected override Action GetPreSpawnSetupCallback() { Action baseCallback = base.GetPreSpawnSetupCallback(); return Callback; void Callback(CharacterMaster spawnedMaster) { if (srcItemStacks != null) { spawnedMaster.inventory.AddItemsFrom(srcItemStacks, (ItemIndex _) => true); } if (srcEquipment != null) { for (uint num = 0u; num < srcEquipment.Length; num++) { spawnedMaster.inventory.SetEquipmentIndexForSlot(srcEquipment[num], num); } } baseCallback?.Invoke(spawnedMaster); onPreSpawnSetup?.Invoke(spawnedMaster); if (srcItemStacks != null) { ItemCatalog.ReturnItemStackArray(srcItemStacks); } } } } public abstract class MiscPickupDef : ScriptableObject { [SerializeField] public uint coinValue; [SerializeField] public string nameToken; [SerializeField] public GameObject displayPrefab; [SerializeField] public GameObject dropletDisplayPrefab; [SerializeField] public ColorCatalog.ColorIndex baseColor; [SerializeField] public ColorCatalog.ColorIndex darkColor; [SerializeField] public string interactContextToken; [SerializeField] public string descriptionToken; [SerializeField] public Sprite visual; [NonSerialized] public MiscPickupIndex miscPickupIndex; public abstract void GrantPickup(ref PickupDef.GrantContext context); public virtual string GetInternalName() { return "MiscPickupIndex." + base.name; } public virtual PickupDef CreatePickupDef() { return new PickupDef { internalName = GetInternalName(), coinValue = coinValue, nameToken = nameToken, displayPrefab = displayPrefab, dropletDisplayPrefab = dropletDisplayPrefab, baseColor = ColorCatalog.GetColor(baseColor), darkColor = ColorCatalog.GetColor(darkColor), interactContextToken = interactContextToken, attemptGrant = GrantPickup, miscPickupIndex = miscPickupIndex }; } } [CreateAssetMenu(menuName = "RoR2/SpawnCards/MultiCharacterSpawnCard")] public class MultiCharacterSpawnCard : CharacterSpawnCard { public GameObject[] masterPrefabs; protected override void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest directorSpawnRequest, ref SpawnResult result) { prefab = masterPrefabs[(int)(directorSpawnRequest.rng.nextNormalizedFloat * (float)masterPrefabs.Length)]; base.Spawn(position, rotation, directorSpawnRequest, ref result); } } [CreateAssetMenu(menuName = "RoR2/NetworkSoundEventDef")] public class NetworkSoundEventDef : ScriptableObject { public string eventName; public NetworkSoundEventIndex index { get; set; } public uint akId { get; set; } } [CreateAssetMenu(menuName = "RoR2/RoachParams")] public class RoachParams : ScriptableObject { public float reorientTimerMin = 0.2f; public float reorientTimerMax = 0.5f; public float turnSpeed = 72f; public float acceleration = 400f; public float maxSpeed = 100f; public float backupDuration = 0.1f; public float wiggle = 720f; public float stepSize = 0.1f; public float minSimulationDuration = 3f; public float maxSimulationDuration = 7f; public float chanceToFinishOnBump = 0.5f; public float keyframeInterval = 1f / 15f; public float minReactionTime; public float maxReactionTime = 0.2f; public GameObject roachPrefab; } [CreateAssetMenu(menuName = "RoR2/SceneCollection")] public class SceneCollection : ScriptableObject { [Serializable] public struct SceneEntry { public SceneDef sceneDef; [SerializeField] private float weightMinusOne; public float weight { get { return weightMinusOne + 1f; } set { weightMinusOne = value - 1f; } } } [FormerlySerializedAs("sceneReferences")] [SerializeField] private SceneEntry[] _sceneEntries = Array.Empty(); public ReadOnlyArray sceneEntries => _sceneEntries; public bool isEmpty => _sceneEntries.Length == 0; public void SetSceneEntries(IReadOnlyList newSceneReferences) { Array.Resize(ref _sceneEntries, newSceneReferences.Count); for (int i = 0; i < 0; i++) { _sceneEntries[i] = newSceneReferences[i]; } } public void AddToWeightedSelection(WeightedSelection dest, Func canAdd = null) { foreach (SceneEntry sceneEntry in sceneEntries) { SceneDef sceneDef = sceneEntry.sceneDef; if ((bool)sceneDef && (canAdd == null || canAdd(sceneDef))) { dest.AddChoice(sceneDef, sceneEntry.weight); } } } } public enum SceneType { Invalid = -1, Menu, Stage, Intermission, Cutscene, TimedIntermission, UntimedStage } [CreateAssetMenu(menuName = "RoR2/SceneDef")] public class SceneDef : ScriptableObject { [Tooltip("The address of the associated scene. There is a name-based fallback systems for mods to use if the address isn't provided, but all official scenes must provide this.")] [Header("Scene")] public AssetReferenceScene sceneAddress; [Tooltip("The \"base\" name used for things like unlockables and stat tracking associated with this scene. If empty, the name of this asset will be used instead.")] public string baseSceneNameOverride; [Header("Classification")] public SceneType sceneType; public bool isOfflineScene; public int stageOrder; public ExpansionDef requiredExpansion; [Header("User-Facing Name")] public string nameToken; public string subtitleToken; public Texture previewTexture; [Header("Bazaar")] public Material portalMaterial; public string portalSelectionMessageString; [Header("Logbook")] public bool shouldIncludeInLogbook = true; [Tooltip("The logbook text for this scene. If empty, this scene will not be represented in the logbook.")] public string loreToken; public GameObject dioramaPrefab; [Header("Music")] [FormerlySerializedAs("song")] public MusicTrackDef mainTrack; [FormerlySerializedAs("bossSong")] public MusicTrackDef bossTrack; [Header("Color")] [Tooltip("Representative color of the environment, to be used for things such as hardware lights.")] public UnityEngine.Color environmentColor; [Tooltip("scene has safe start or not.")] [Header("Combat Message")] public bool hasSafeStart; [Tooltip("Prevents players from spawning into the scene. This is usually for cutscenes.")] [Header("Behavior")] public bool suppressPlayerEntry; [Tooltip("Prevents persistent NPCs (like drones) from spawning into the scene. This is usually for cutscenes, or areas that get them killed them due to hazards they're not smart enough to avoid.")] public bool suppressNpcEntry; [Tooltip("Prevents Captain from using orbital skills.")] public bool blockOrbitalSkills; [Tooltip("Is this stage allowed to be selected when using a random stage order (e.g., in Prismatic Trials?)")] public bool validForRandomSelection = true; [Tooltip("Allow objects from items to spawn in this level. Overrides the need to have the SceneType = Stage.")] public bool allowItemsToSpawnObjects; [Tooltip("Devotion lemurians should respawn later when find a valid node graph")] [Header("Artifact")] public bool needSkipDevotionRespawn; [Tooltip("A collection of stages that can be destinations of the teleporter.")] [Header("Destinations")] public SceneCollection destinationsGroup; [Tooltip("A collection of stages that can be destinations of the teleporter after looping.")] public SceneCollection loopedDestinationsGroup; [Tooltip("A collection of stages that can be destinations of the teleporter after looping.")] [SerializeField] private bool shouldUpdateSceneCollectionAfterLooping; [Tooltip("A bool that tracks if this stage is available before looping.")] public bool isLockedBeforeLooping; [Tooltip("For specific portal transitions that references the original and needs the looped version.")] public SceneDef loopedSceneDef; [ShowFieldObsolete] [Obsolete("Use destinationsGroup instead.")] [Tooltip("Stages that can be destinations of the teleporter.")] public SceneDef[] destinations = Array.Empty(); [Header("Portal Appearance")] public GameObject preferredPortalPrefab; private string _cachedName; [NonSerialized] [HideInInspector] [Obsolete] public List sceneNameOverrides; public SceneIndex sceneDefIndex { get; set; } public string baseSceneName { get { if (string.IsNullOrEmpty(baseSceneNameOverride)) { return cachedName; } return baseSceneNameOverride; } } public bool isFinalStage { get { if (sceneType == SceneType.Stage) { return !hasAnyDestinations; } return false; } } public bool hasAnyDestinations { get { if (destinations.Length == 0) { if ((bool)destinationsGroup) { return !destinationsGroup.isEmpty; } return false; } return true; } } [Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)] public new string name { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public string cachedName { get { return _cachedName; } set { base.name = value; _cachedName = value; } } private void Awake() { _cachedName = base.name; } private void OnValidate() { _cachedName = base.name; if (string.IsNullOrEmpty(sceneAddress?.AssetGUID)) { AutoAssignSceneAddress(); } } [ContextMenu("Auto-assign scene address")] private void AutoAssignSceneAddress() { } public void AddDestinationsToWeightedSelection(WeightedSelection dest, Func canAdd = null) { if ((bool)destinationsGroup) { if (Run.instance.stageClearCount >= 4 && shouldUpdateSceneCollectionAfterLooping) { if ((bool)loopedDestinationsGroup) { loopedDestinationsGroup.AddToWeightedSelection(dest, canAdd); } else { UnityEngine.Debug.LogError("Should be looping but looped scene collection is missing."); } } else { destinationsGroup.AddToWeightedSelection(dest, canAdd); } } SceneDef[] array = destinations; foreach (SceneDef value in array) { dest.AddChoice(value, 1f); } } } [Serializable] public class AssetReferenceSceneDef : AssetReferenceT { public AssetReferenceSceneDef(string guid) : base(guid) { } } [CreateAssetMenu(menuName = "RoR2/Sha256 Hash")] public class Sha256HashAsset : ScriptableObject { public Sha256Hash value; } [CreateAssetMenu(menuName = "RoR2/SimpleSpriteAnimation")] public class SimpleSpriteAnimation : ScriptableObject { [Serializable] public struct Frame { public Sprite sprite; public int duration; } public float frameRate = 60f; public Frame[] frames = Array.Empty(); } [CreateAssetMenu(menuName = "RoR2/SpawnCards/SpawnCard")] public class SpawnCard : ScriptableObject { public struct SpawnResult { public GameObject spawnedInstance; public DirectorSpawnRequest spawnRequest; public UnityEngine.Vector3 position; public UnityEngine.Quaternion rotation; public bool success; } public enum EliteRules { Default, ArtifactOnly, Lunar } public GameObject prefab; public bool sendOverNetwork; public HullClassification hullSize; public MapNodeGroup.GraphType nodeGraphType; [EnumMask(typeof(NodeFlags))] public NodeFlags requiredFlags; [EnumMask(typeof(NodeFlags))] public NodeFlags forbiddenFlags; public int directorCreditCost; public bool occupyPosition; [Tooltip("Default = default rules, ArtifactOnly = only elite when forced by the elite-only artifact, Lunar = special lunar elites only (+ regular w/ elite-only artifact)")] public EliteRules eliteRules; public static event Action onSpawnedServerGlobal; protected virtual void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest spawnRequest, ref SpawnResult spawnResult) { GameObject gameObject = UnityEngine.Object.Instantiate(prefab, position, rotation); if (sendOverNetwork) { NetworkServer.Spawn(gameObject); } spawnResult.spawnedInstance = gameObject; spawnResult.success = true; } public SpawnResult DoSpawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest spawnRequest) { SpawnResult spawnResult = default(SpawnResult); spawnResult.spawnRequest = spawnRequest; spawnResult.position = position; spawnResult.rotation = rotation; SpawnResult spawnResult2 = spawnResult; Spawn(position, rotation, spawnRequest, ref spawnResult2); spawnRequest.onSpawnedServer?.Invoke(spawnResult2); SpawnCard.onSpawnedServerGlobal?.Invoke(spawnResult2); return spawnResult2; } } [CreateAssetMenu(menuName = "RoR2/SurfaceDef")] public class SurfaceDef : ScriptableObject { [HideInInspector] public SurfaceDefIndex surfaceDefIndex = SurfaceDefIndex.Invalid; public UnityEngine.Color approximateColor; public GameObject impactEffectPrefab; public GameObject footstepEffectPrefab; public string impactSoundString; public string materialSwitchString; public bool isSlippery; public bool isLava; public float damage; public float speedBoost; private void OnValidate() { if (!Application.isPlaying && surfaceDefIndex != SurfaceDefIndex.Invalid) { surfaceDefIndex = SurfaceDefIndex.Invalid; } } } [CreateAssetMenu(menuName = "RoR2/SurvivorDef")] public class SurvivorDef : ScriptableObject { private string _cachedName; public GameObject bodyPrefab; public GameObject displayPrefab; [Obsolete("Use 'unlockableDef' instead.")] public string unlockableName = ""; public UnlockableDef unlockableDef; public string displayNameToken; public string descriptionToken; public string outroFlavorToken; public string mainEndingEscapeFailureFlavorToken; public UnityEngine.Color primaryColor; public float desiredSortPosition; public bool hidden; public SurvivorIndex survivorIndex { get; set; } = SurvivorIndex.None; [Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)] public new string name { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public string cachedName { get { return _cachedName; } set { base.name = value; _cachedName = value; } } private void Awake() { _cachedName = base.name; } private void OnValidate() { _cachedName = base.name; } [ContextMenu("Auto Populate Tokens")] public void AutoPopulateTokens() { string arg = base.name.ToUpperInvariant(); displayNameToken = displayPrefab.GetComponent().baseNameToken; descriptionToken = $"{arg}_DESCRIPTION"; outroFlavorToken = $"{arg}_OUTRO_FLAVOR"; } [ContextMenu("Upgrade unlockableName to unlockableDef")] public void UpgradeUnlockableNameToUnlockableDef() { if (!string.IsNullOrEmpty(unlockableName) && !this.unlockableDef) { UnlockableDef unlockableDef = LegacyResourcesAPI.Load("UnlockableDefs/" + unlockableName); if ((bool)unlockableDef) { this.unlockableDef = unlockableDef; unlockableName = null; } } EditorUtil.SetDirty(this); } public ExpansionDef GetRequiredExpansion() { ExpansionRequirementComponent component = bodyPrefab.GetComponent(); if (!component) { return null; } return component.requiredExpansion; } public EntitlementDef GetRequiredEntitlement() { ExpansionDef requiredExpansion = GetRequiredExpansion(); if (!requiredExpansion) { return null; } return requiredExpansion.requiredEntitlement; } public bool CheckUserHasRequiredEntitlement(NetworkUser networkUser) { EntitlementDef requiredEntitlement = GetRequiredEntitlement(); if (!requiredEntitlement) { return true; } return EntitlementManager.networkUserEntitlementTracker.UserHasEntitlement(networkUser, requiredEntitlement); } public bool CheckUserHasRequiredEntitlement(LocalUser localUser) { EntitlementDef requiredEntitlement = GetRequiredEntitlement(); if (!requiredEntitlement) { return true; } return EntitlementManager.localUserEntitlementTracker.UserHasEntitlement(localUser, requiredEntitlement); } public bool CheckLocalUserHasRequiredEntitlement() { foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList) { if (CheckUserHasRequiredEntitlement(readOnlyLocalUsers)) { return true; } } return false; } public bool CheckRequiredExpansionEnabled(NetworkUser networkUser = null) { ExpansionDef requiredExpansion = GetRequiredExpansion(); if (!requiredExpansion) { return true; } if (requiredExpansion.enabledChoice == null) { return false; } if ((bool)networkUser && !EntitlementManager.networkUserEntitlementTracker.UserHasEntitlement(networkUser, requiredExpansion.requiredEntitlement)) { return false; } return (PreGameController.instance ? PreGameController.instance.readOnlyRuleBook : (Run.instance ? Run.instance.ruleBook : null))?.IsChoiceActive(requiredExpansion.enabledChoice) ?? true; } } [CreateAssetMenu(menuName = "RoR2/Timer String Formatter")] public class TimerStringFormatter : ScriptableObject { [Serializable] public struct Format { [Serializable] public struct Unit { [CanBeNull] public string name; public double conversionRate; public uint minDigits; public uint maxDigits; [CanBeNull] public string prefix; [CanBeNull] public string suffix; } [CanBeNull] public Unit[] units; public string prefix; public string suffix; public static Format Clone(in Format src) { Format result = default(Format); result.prefix = src.prefix; result.suffix = src.suffix; result.units = ((src.units != null) ? ArrayUtils.Clone(src.units) : null); return result; } } public Format format = defaultFormat; private const double hoursPerDay = 24.0; private const double minutesPerDay = 1440.0; private const double secondsPerDay = 86400.0; private const double minutesPerHour = 60.0; private const double secondsPerMinute = 60.0; private const double secondsPerSecond = 1.0; private const double secondsPerCentisecond = 0.01; private const double secondsPerHour = 3600.0; private static readonly Format defaultFormat = new Format { prefix = "", suffix = "", units = new Format.Unit[5] { new Format.Unit { name = "days", conversionRate = 86400.0, maxDigits = 2147483647u, minDigits = 2u, prefix = string.Empty, suffix = string.Empty }, new Format.Unit { name = "hours", conversionRate = 3600.0, maxDigits = 2u, minDigits = 2u, prefix = ":", suffix = string.Empty }, new Format.Unit { name = "minutes", conversionRate = 60.0, maxDigits = 2u, minDigits = 2u, prefix = ":", suffix = string.Empty }, new Format.Unit { name = "seconds", conversionRate = 1.0, maxDigits = 2u, minDigits = 2u, prefix = ":", suffix = string.Empty }, new Format.Unit { name = "centiseconds", conversionRate = 0.01, maxDigits = 2u, minDigits = 2u, prefix = ".", suffix = "" } } }; public void AppendToStringBuilder(double seconds, [NotNull] StringBuilder dest) { double num = seconds; if (!string.IsNullOrEmpty(format.prefix)) { dest.Append(format.prefix); } if (num < 0.0) { num = 0.0 - num; dest.Append("-"); } Format.Unit[] units = format.units; for (int i = 0; i < units.Length; i++) { Format.Unit unit = units[i]; double num2 = Math.Floor(num / unit.conversionRate); num -= num2 * unit.conversionRate; int num3 = (int)num2; uint minDigits = unit.minDigits; uint num4 = unit.maxDigits; if (num4 < minDigits) { num4 = minDigits; } if (num4 != 0 && (minDigits != 0 || num3 >= 10)) { if (!string.IsNullOrEmpty(unit.prefix)) { dest.Append(unit.prefix); } dest.AppendInt(num3, minDigits, num4); if (!string.IsNullOrEmpty(unit.suffix)) { dest.Append(unit.suffix); } } } if (!string.IsNullOrEmpty(format.suffix)) { dest.Append(format.suffix); } } private void Reset() { format = Format.Clone(in defaultFormat); } } [CreateAssetMenu(menuName = "RoR2/UI Layer")] public class UILayer : ScriptableObject { public int priority; } [CreateAssetMenu(menuName = "RoR2/UnlockableDef")] public class UnlockableDef : ScriptableObject { private string _cachedName; public string nameToken = "???"; [Obsolete("UnlockableDef.displayModelPath is obsolete. Use .displayModel instead.", false)] public string displayModelPath = "Prefabs/NullModel"; public GameObject displayModelPrefab; public bool hidden; public Sprite achievementIcon; [Tooltip("Set this to override Unlockable Catalog automatic Expansion linking")] public ExpansionDef requiredExpansion; public UnlockableIndex index { get; set; } = UnlockableIndex.None; [Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)] public new string name { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public string cachedName { get { return _cachedName; } set { base.name = value; _cachedName = value; } } [NotNull] public Func getHowToUnlockString { get; set; } = () => "???"; [NotNull] public Func getUnlockedString { get; set; } = () => "???"; public int sortScore { get; set; } private void Awake() { _cachedName = base.name; } private void OnValidate() { _cachedName = base.name; } [ContextMenu("Update displayModelPath to displayModelPrefab")] private void ReplaceDisplayModelPrefabPathWithDirectReference() { string text = displayModelPath; if (!string.IsNullOrEmpty(text)) { GameObject gameObject = LegacyResourcesAPI.Load(text); if ((bool)gameObject) { displayModelPrefab = gameObject; displayModelPath = string.Empty; EditorUtil.SetDirty(this); } } } [ConCommand(commandName = "unlockable_migrate", flags = ConVarFlags.None, helpText = "Generates UnlockableDef assets from the existing catalog entries.")] private static void CCUnlockableMigrate(ConCommandArgs args) { for (UnlockableIndex unlockableIndex = (UnlockableIndex)0; (int)unlockableIndex < UnlockableCatalog.unlockableCount; unlockableIndex++) { EditorUtil.CopyToScriptableObject(UnlockableCatalog.GetUnlockableDef(unlockableIndex), "Assets/RoR2/Resources/UnlockableDefs/"); } } } [CreateAssetMenu(menuName = "RoR2/MiscPickupDefs/VoidCoinDef")] public class VoidCoinDef : MiscPickupDef { public override void GrantPickup(ref PickupDef.GrantContext context) { if ((bool)context.body.master) { context.body.master.GiveVoidCoins(coinValue); context.shouldDestroy = true; context.shouldNotify = true; } else { context.shouldNotify = false; context.shouldDestroy = false; } } } [RequireComponent(typeof(Camera))] public class BlurOptimized : MonoBehaviour { public enum BlurType { StandardGauss, SgxGauss } [Range(0f, 2f)] public int downsample = 1; [Range(0f, 10f)] public float blurSize = 3f; [Range(1f, 4f)] public int blurIterations = 2; public BlurType blurType; [HideInInspector] public Material blurMaterial; public void Start() { blurMaterial = new Material(LegacyShaderAPI.Find("Hidden/FastBlur")); base.enabled = false; } public void OnRenderImage(RenderTexture source, RenderTexture destination) { float num = 1f / (1f * (float)(1 << downsample)); blurMaterial.SetVector("_Parameter", new UnityEngine.Vector4(blurSize * num, (0f - blurSize) * num, 0f, 0f)); source.filterMode = FilterMode.Bilinear; int width = source.width >> downsample; int height = source.height >> downsample; RenderTexture renderTexture = RenderTexture.GetTemporary(width, height, 0, source.format); renderTexture.filterMode = FilterMode.Bilinear; Graphics.Blit(source, renderTexture, blurMaterial, 0); int num2 = ((blurType != 0) ? 2 : 0); for (int i = 0; i < blurIterations; i++) { float num3 = (float)i * 1f; blurMaterial.SetVector("_Parameter", new UnityEngine.Vector4(blurSize * num + num3, (0f - blurSize) * num - num3, 0f, 0f)); RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, source.format); temporary.filterMode = FilterMode.Bilinear; Graphics.Blit(renderTexture, temporary, blurMaterial, 1 + num2); RenderTexture.ReleaseTemporary(renderTexture); renderTexture = temporary; temporary = RenderTexture.GetTemporary(width, height, 0, source.format); temporary.filterMode = FilterMode.Bilinear; Graphics.Blit(renderTexture, temporary, blurMaterial, 2 + num2); RenderTexture.ReleaseTemporary(renderTexture); renderTexture = temporary; } Graphics.Blit(renderTexture, destination); RenderTexture.ReleaseTemporary(renderTexture); } } [Flags] public enum DamageType : uint { Generic = 0u, NonLethal = 1u, BypassArmor = 2u, ResetCooldownsOnKill = 4u, SlowOnHit = 8u, WeakPointHit = 0x10u, Stun1s = 0x20u, BypassBlock = 0x40u, IgniteOnHit = 0x80u, Freeze2s = 0x100u, ClayGoo = 0x200u, BleedOnHit = 0x400u, Silent = 0x800u, PoisonOnHit = 0x1000u, PercentIgniteOnHit = 0x2000u, WeakOnHit = 0x4000u, Nullify = 0x8000u, VoidDeath = 0x10000u, AOE = 0x20000u, BypassOneShotProtection = 0x40000u, BonusToLowHealth = 0x80000u, BlightOnHit = 0x100000u, FallDamage = 0x200000u, CrippleOnHit = 0x400000u, ApplyMercExpose = 0x800000u, Shock5s = 0x1000000u, LunarSecondaryRootOnHit = 0x2000000u, DoT = 0x4000000u, SuperBleedOnCrit = 0x8000000u, GiveSkullOnKill = 0x10000000u, FruitOnHit = 0x20000000u, LunarRuin = 0x40000000u, OutOfBounds = 0x80000000u } [Flags] public enum DamageTypeExtended : uint { Generic = 0u, ChefSearDamage = 0x4000000u, SojournVehicleDamage = 0x8000000u, DamagePercentOfMaxHealth = 0x10000000u, ApplyBuffPermanently = 0x20000000u, DisableAllSkills = 0x40000000u, OutOfBounds = 0x80000000u } [Serializable] [StructLayout(LayoutKind.Explicit)] public struct DamageTypeCombo { internal static readonly DamageTypeCombo Generic = new DamageTypeCombo { damageType = DamageType.Generic, damageTypeExtended = DamageTypeExtended.Generic }; [FieldOffset(0)] [NonSerialized] public ulong damageTypeCombined; [FieldOffset(0)] public DamageType damageType; [FieldOffset(4)] public DamageTypeExtended damageTypeExtended; public DamageTypeCombo(DamageTypeCombo damageType, DamageTypeExtended damageTypeExtended) { this = default(DamageTypeCombo); this.damageType = damageType; this.damageTypeExtended = damageTypeExtended; } public static implicit operator DamageTypeCombo(DamageType damage) { DamageTypeCombo result = default(DamageTypeCombo); result.damageType = damage; return result; } public static implicit operator DamageTypeCombo(DamageTypeExtended damage) { DamageTypeCombo result = default(DamageTypeCombo); result.damageTypeExtended = damage; return result; } public static implicit operator DamageTypeCombo(ulong damage) { DamageTypeCombo result = default(DamageTypeCombo); result.damageTypeCombined = damage; return result; } public static implicit operator DamageType(DamageTypeCombo combo) { return combo.damageType; } public static implicit operator DamageTypeExtended(DamageTypeCombo combo) { return combo.damageTypeExtended; } public static implicit operator ulong(DamageTypeCombo combo) { return combo.damageTypeCombined; } public static DamageTypeCombo operator &(DamageTypeCombo operand1, DamageTypeCombo operand2) { return new DamageTypeCombo(operand1.damageType & operand2.damageType, operand1.damageTypeExtended & operand2.damageTypeExtended); } public static DamageTypeCombo operator |(DamageTypeCombo operand1, DamageTypeCombo operand2) { return new DamageTypeCombo(operand1.damageType | operand2.damageType, operand1.damageTypeExtended | operand2.damageTypeExtended); } public static DamageTypeCombo operator ^(DamageTypeCombo operand1, DamageTypeCombo operand2) { return new DamageTypeCombo(operand1.damageType ^ operand2.damageType, operand1.damageTypeExtended ^ operand2.damageTypeExtended); } public static DamageTypeCombo operator ~(DamageTypeCombo operand) { return new DamageTypeCombo(~operand.damageType, ~operand.damageTypeExtended); } public override string ToString() { return $"DamageType: {damageType}, DamageTypeExtended: {damageTypeExtended}"; } } public enum DamageColorIndex : byte { Default, Heal, Bleed, Item, Poison, WeakPoint, CritHeal, DeathMark, SuperBleed, Void, Nearby, Fragile, Sniper, Luminous, Count } public static class DamageColor { private static UnityEngine.Color[] colors; static DamageColor() { colors = new UnityEngine.Color[14]; colors[0] = UnityEngine.Color.white; colors[1] = new UnityEngine.Color(28f / 85f, 84f / 85f, 0.1764706f); colors[2] = new UnityEngine.Color(0.79607844f, 16f / 85f, 16f / 85f); colors[8] = new UnityEngine.Color(0.9372549f, 8f / 85f, 8f / 85f); colors[9] = new Color32(237, 127, 205, byte.MaxValue); colors[3] = new UnityEngine.Color(0.827451f, 0.7490196f, 16f / 51f); colors[4] = new UnityEngine.Color(0.76862746f, 0.96862745f, 0.34901962f); colors[5] = new UnityEngine.Color(0.9372549f, 44f / 85f, 0.20392157f); colors[7] = new UnityEngine.Color(0.6392157f, 0.2f, 0.20784314f); colors[10] = new UnityEngine.Color(47f / 51f, 23f / 51f, 0.827451f); colors[11] = new UnityEngine.Color(1f, 47f / 51f, 32f / 51f); colors[12] = new UnityEngine.Color(1f, 8f / 15f, 0.54509807f); colors[13] = UnityEngine.Color.yellow; } public static UnityEngine.Color FindColor(DamageColorIndex colorIndex) { if ((int)colorIndex < 0 || (int)colorIndex >= 14) { return UnityEngine.Color.white; } return colors[(uint)colorIndex]; } } public class DamageInfo { public float damage; public bool crit; public GameObject inflictor; public GameObject attacker; public UnityEngine.Vector3 position; public UnityEngine.Vector3 force; public bool rejected; public bool delayedDamageSecondHalf; public ProcChainMask procChainMask; public float procCoefficient = 1f; public DamageTypeCombo damageType = DamageType.Generic; public DamageColorIndex damageColorIndex; public DotController.DotIndex dotIndex = DotController.DotIndex.None; public bool canRejectForce = true; public void ModifyDamageInfo(HurtBox.DamageModifier damageModifier) { switch (damageModifier) { case HurtBox.DamageModifier.Weak: damageType |= (DamageTypeCombo)DamageType.WeakPointHit; break; case HurtBox.DamageModifier.Normal: case HurtBox.DamageModifier.SniperTarget: break; } } } public class DamageReport { public readonly HealthComponent victim; public readonly CharacterBody victimBody; public readonly BodyIndex victimBodyIndex; public readonly TeamIndex victimTeamIndex; public readonly CharacterMaster victimMaster; public readonly bool victimIsElite; public readonly bool victimIsBoss; public readonly bool victimIsChampion; public readonly DamageInfo damageInfo; public readonly GameObject attacker; public readonly CharacterBody attackerBody; public readonly BodyIndex attackerBodyIndex; public readonly TeamIndex attackerTeamIndex; public readonly CharacterMaster attackerMaster; public readonly CharacterMaster attackerOwnerMaster; public readonly BodyIndex attackerOwnerBodyIndex; public readonly DotController.DotIndex dotType; public readonly float damageDealt; public readonly float combinedHealthBeforeDamage; public readonly bool hitLowHealth; public bool isFriendlyFire { get { if (attackerTeamIndex == victimTeamIndex) { return attackerTeamIndex != TeamIndex.None; } return false; } } public bool isFallDamage => (ulong)(damageInfo.damageType & DamageType.FallDamage) != 0; public DamageReport(DamageInfo damageInfo, HealthComponent victim, float damageDealt, float combinedHealthBeforeDamage) { this.damageInfo = damageInfo; this.victim = victim; victimBody = (victim ? victim.body : null); if ((bool)victimBody) { victimBodyIndex = victimBody.bodyIndex; victimMaster = victimBody.master; victimIsElite = victimBody.isElite; victimIsBoss = victimBody.isBoss; victimIsChampion = victimBody.isChampion; if ((bool)victimBody.teamComponent) { victimTeamIndex = victimBody.teamComponent.teamIndex; } else { victimTeamIndex = TeamIndex.None; } } else { victimBodyIndex = BodyIndex.None; victimTeamIndex = TeamIndex.None; victimIsElite = false; victimIsBoss = false; victimIsChampion = false; } attacker = damageInfo.attacker; attackerBody = (attacker ? attacker.GetComponent() : null); if ((bool)attackerBody) { attackerBodyIndex = attackerBody.bodyIndex; if ((bool)attackerBody.teamComponent) { attackerTeamIndex = attackerBody.teamComponent.teamIndex; } else { attackerTeamIndex = TeamIndex.None; } attackerOwnerBodyIndex = BodyIndex.None; attackerMaster = attackerBody.master; if ((bool)attackerMaster && (bool)attackerMaster.minionOwnership) { attackerOwnerMaster = attackerMaster.minionOwnership.ownerMaster; if ((bool)attackerOwnerMaster) { CharacterBody body = attackerOwnerMaster.GetBody(); if ((bool)body) { attackerOwnerBodyIndex = body.bodyIndex; } } } } else { attackerBodyIndex = BodyIndex.None; attackerTeamIndex = TeamIndex.None; attackerOwnerBodyIndex = BodyIndex.None; } if ((bool)victim) { hitLowHealth = victim.isHealthLow; } else { hitLowHealth = false; } if (damageInfo != null) { dotType = damageInfo.dotIndex; } this.damageDealt = damageDealt; this.combinedHealthBeforeDamage = combinedHealthBeforeDamage; } public StringBuilder AppendToStringBuilderMultiline(StringBuilder stringBuilder) { stringBuilder.Append("VictimBody=").AppendLine(ObjToString(victimBody)); stringBuilder.Append("VictimTeamIndex=").AppendLine(victimTeamIndex.ToString()); stringBuilder.Append("VictimMaster=").AppendLine(ObjToString(victimMaster)); stringBuilder.Append("AttackerBody=").AppendLine(ObjToString(attackerBody)); stringBuilder.Append("AttackerTeamIndex=").AppendLine(attackerTeamIndex.ToString()); stringBuilder.Append("AttackerMaster=").AppendLine(ObjToString(attackerMaster)); stringBuilder.Append("Inflictor=").AppendLine(ObjToString(damageInfo.inflictor)); stringBuilder.Append("Damage=").AppendLine(damageInfo.damage.ToString()); stringBuilder.Append("Crit=").AppendLine(damageInfo.crit.ToString()); stringBuilder.Append("ProcChainMask=").AppendLine(damageInfo.procChainMask.ToString()); stringBuilder.Append("ProcCoefficient=").AppendLine(damageInfo.procCoefficient.ToString()); stringBuilder.Append("DamageType=").AppendLine(damageInfo.damageType.ToString()); stringBuilder.Append("DotIndex=").AppendLine(damageInfo.dotIndex.ToString()); stringBuilder.Append("DamageColorIndex=").AppendLine(damageInfo.damageColorIndex.ToString()); stringBuilder.Append("Position=").AppendLine(damageInfo.position.ToString()); stringBuilder.Append("Force=").AppendLine(damageInfo.force.ToString()); stringBuilder.Append("Rejected=").AppendLine(damageInfo.rejected.ToString()); return stringBuilder; static string ObjToString(object obj) { if (obj == null) { return "null"; } return obj.ToString(); } } public override string ToString() { return AppendToStringBuilderMultiline(new StringBuilder()).ToString(); } } [Serializable] public class DamageReportUnityEvent : UnityEvent { } public static class DefaultControllerMaps { public delegate void LogFormatFunction(string inFormat, params object[] inParams); public const string defaultKeyboardMapString = "00000000000-0000-0000-0000-000000000000false001-10false0100000true001-10false197000true011-10false0119000true011-10false1115000true041-10false032000true0181-10false0306000true051-10false0101000true061-10false0113000true091-10false0304000true0101-10false0114000true0191-10false09000true"; public const string defaultMouseMapString = "00000000000-0000-0000-0000-000000000000false07130false00000true08140false00000true028150false00000true02000false00000true03010false00000true"; public static readonly Guid gamepadTemplateGuid = new Guid("83b427e4-086f-47f3-bb06-be266abd1ca5"); public static readonly Guid xboneControllerGuid = new Guid("19002688-7406-4f4a-8340-8d25335406c8"); public static readonly Guid xbox360ControllerGuid = new Guid("d74a350e-fe8b-4e9e-bbcd-efff16d34115"); public static readonly Guid switchDualGuid = new Guid("521b808c-0248-4526-bc10-f1d16ee76bf1"); public static readonly Guid switchHandheldGuid = new Guid("1fbdd13b-0795-4173-8a95-a2a75de9d204"); public static readonly Guid switchProGuid = new Guid("7bf3154b-9db8-4d52-950f-cd0eed8a5819"); public static readonly Guid PS4Guid = new Guid("cd9718bf-a87a-44bc-8716-60a0def28a9f"); public static readonly Guid PS5Guid = new Guid("5286706d-19b4-4a45-b635-207ce78d8394"); public static readonly string xbox360ControllerName = "Xbox 360 Controller"; public static readonly string xboxOneControllerName = "Xbox One Controller"; public static readonly string dualshock4ControllerName = "Sony DualShock 4"; public static readonly string dualshock4ControllerNameAlt = "PlayStation Controller"; public static readonly string dualSenseController = "Sony DualSense"; public static readonly string switchControllerName = "Nintendo Controller"; public static readonly string switchProControllerName = "Nintendo Switch Pro Controller"; public static readonly string switchProControllerNameAlt = "Pro Controller"; public static readonly string stadiaControllerName = "Stadia Controller"; public static readonly KeyboardMap defaultKeyboardMap = (KeyboardMap)ControllerMap.CreateFromXml(ControllerType.Keyboard, "00000000000-0000-0000-0000-000000000000false001-10false0100000true001-10false197000true011-10false0119000true011-10false1115000true041-10false032000true0181-10false0306000true051-10false0101000true061-10false0113000true091-10false0304000true0101-10false0114000true0191-10false09000true"); public static readonly MouseMap defaultMouseMap = (MouseMap)ControllerMap.CreateFromXml(ControllerType.Mouse, "00000000000-0000-0000-0000-000000000000false07130false00000true08140false00000true028150false00000true02000false00000true03010false00000true"); private static Dictionary _DefaultJoystickMaps_Xml = new Dictionary(); private static bool _FilledDefaultJoystickMaps = false; public static JoystickMap DefaultJoystickMap { get { FillDefaultJoystickMaps(); if (_DefaultJoystickMaps_Xml.ContainsKey(PlatformManager.DefaultControllerGuid)) { string xmlString = _DefaultJoystickMaps_Xml[PlatformManager.DefaultControllerGuid]; return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString) as JoystickMap; } return null; } } public static bool RewiredLoggingEnabled() { return false; } public static void RewiredLogLineForce(LogFormatFunction inLogFcn, string inFormat, params object[] inParams) { if (inParams != null && inParams.Length != 0) { inLogFcn(inFormat, inParams); } else { inLogFcn(inFormat); } } public static void RewiredLogLine(LogFormatFunction inLogFcn, string inFormat, params object[] inParams) { } public static void RewiredDebugLog(string inFormat, params object[] inParams) { RewiredLogLine(UnityEngine.Debug.LogFormat, inFormat, inParams); } public static void RewiredDebugWarn(string inFormat, params object[] inParams) { RewiredLogLine(UnityEngine.Debug.LogWarningFormat, inFormat, inParams); } public static void RewiredDebugError(string inFormat, params object[] inParams) { RewiredLogLineForce(UnityEngine.Debug.LogErrorFormat, inFormat, inParams); } public static void RewiredDebugLogForce(string inFormat, params object[] inParams) { RewiredLogLineForce(UnityEngine.Debug.LogFormat, inFormat, inParams); } public static void RewiredDebugWarnForce(string inFormat, params object[] inParams) { RewiredLogLineForce(UnityEngine.Debug.LogWarningFormat, inFormat, inParams); } private static void FillDefaultJoystickMaps() { if (_FilledDefaultJoystickMaps) { return; } RewiredDebugLog("FillDefaultJoysticksMap"); if (ReInput.mapping != null) { JoystickMap joystickMapInstance = ReInput.mapping.GetJoystickMapInstance(gamepadTemplateGuid, 0, 0); JoystickMap joystickMapInstance2 = ReInput.mapping.GetJoystickMapInstance(xboneControllerGuid, 0, 0); JoystickMap joystickMapInstance3 = ReInput.mapping.GetJoystickMapInstance(xbox360ControllerGuid, 0, 0); JoystickMap joystickMapInstance4 = ReInput.mapping.GetJoystickMapInstance(PS4Guid, 0, 0); JoystickMap joystickMapInstance5 = ReInput.mapping.GetJoystickMapInstance(PS5Guid, 0, 0); JoystickMap joystickMapInstance6 = ReInput.mapping.GetJoystickMapInstance(switchProGuid, 0, 0); JoystickMap joystickMapInstance7 = ReInput.mapping.GetJoystickMapInstance(switchDualGuid, 0, 0); JoystickMap joystickMapInstance8 = ReInput.mapping.GetJoystickMapInstance(switchHandheldGuid, 0, 0); string value = joystickMapInstance.ToXmlString(); string value2 = joystickMapInstance2.ToXmlString(); string value3 = joystickMapInstance3.ToXmlString(); string value4 = joystickMapInstance4.ToXmlString(); string value5 = joystickMapInstance5.ToXmlString(); string value6 = joystickMapInstance6.ToXmlString(); string value7 = joystickMapInstance7.ToXmlString(); string value8 = joystickMapInstance8.ToXmlString(); _DefaultJoystickMaps_Xml.Add(gamepadTemplateGuid, value); if (joystickMapInstance2.buttonMapCount > 0) { _DefaultJoystickMaps_Xml.Add(xboneControllerGuid, value2); } _DefaultJoystickMaps_Xml.Add(xbox360ControllerGuid, value3); _DefaultJoystickMaps_Xml.Add(PS4Guid, value4); _DefaultJoystickMaps_Xml.Add(PS5Guid, value5); _DefaultJoystickMaps_Xml.Add(switchProGuid, value6); _DefaultJoystickMaps_Xml.Add(switchDualGuid, value7); _DefaultJoystickMaps_Xml.Add(switchHandheldGuid, value8); _FilledDefaultJoystickMaps = true; } } public static Dictionary GetDefaultJoystickMaps() { FillDefaultJoystickMaps(); Dictionary dictionary = new Dictionary(); foreach (KeyValuePair item in _DefaultJoystickMaps_Xml) { JoystickMap value = ControllerMap.CreateFromXml(ControllerType.Joystick, item.Value) as JoystickMap; dictionary.Add(item.Key, value); } return dictionary; } public static KeyboardMap GetDefaultKeyboardMap() { return ControllerMap.CreateFromXml(ControllerType.Keyboard, "00000000000-0000-0000-0000-000000000000false001-10false0100000true001-10false197000true011-10false0119000true011-10false1115000true041-10false032000true0181-10false0306000true051-10false0101000true061-10false0113000true091-10false0304000true0101-10false0114000true0191-10false09000true") as KeyboardMap; } public static MouseMap GetDefaultMoustMap() { return ControllerMap.CreateFromXml(ControllerType.Mouse, "00000000000-0000-0000-0000-000000000000false07130false00000true08140false00000true028150false00000true02000false00000true03010false00000true") as MouseMap; } public static JoystickMap GetDefaultJoystickMap(Guid inControllerGuid) { FillDefaultJoystickMaps(); if (_DefaultJoystickMaps_Xml.ContainsKey(inControllerGuid)) { string xmlString = _DefaultJoystickMaps_Xml[inControllerGuid]; return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString) as JoystickMap; } RewiredDebugWarn($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}..."); if (inControllerGuid == xboneControllerGuid && _DefaultJoystickMaps_Xml.ContainsKey(xbox360ControllerGuid)) { RewiredDebugWarn($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}... returning Xbox360 mapping (XInput detected)"); string xmlString2 = _DefaultJoystickMaps_Xml[xbox360ControllerGuid]; return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString2) as JoystickMap; } if (inControllerGuid == xbox360ControllerGuid && _DefaultJoystickMaps_Xml.ContainsKey(xboneControllerGuid)) { RewiredDebugWarn($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}... returning Xbone mapping (XInput detected)"); string xmlString3 = _DefaultJoystickMaps_Xml[xboneControllerGuid]; return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString3) as JoystickMap; } if (_DefaultJoystickMaps_Xml.ContainsKey(PlatformManager.DefaultControllerGuid)) { RewiredDebugWarn($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}... returning default"); string xmlString4 = _DefaultJoystickMaps_Xml[PlatformManager.DefaultControllerGuid]; return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString4) as JoystickMap; } RewiredDebugError($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}... nor default {PlatformManager.DefaultControllerGuid}. Returning null"); return null; } public static bool HardwareGuidsMatch(Guid inA, Guid inB) { if (inA == inB) { RewiredDebugLog("HardwareGuidsMatch: TRUE, direct match: {0} --> {1}", inA.ToString(), inB.ToString()); return true; } RewiredDebugLog("HardwareGuidsMatch: FALSE, no match: {0} --> {1}", inA.ToString(), inB.ToString()); return false; } public static Guid LocalHardwareGuidRemap(Guid inHardwareGuid) { Guid result = inHardwareGuid; RewiredDebugLog("LocalHardwareGuidRemap: {0} --> {1}", inHardwareGuid.ToString(), result.ToString()); return result; } [ConCommand(commandName = "export_default_controller_maps", flags = ConVarFlags.None, helpText = "Prints all default Rewired ControllerMaps.")] public static void CCExportDefaultControllerMaps(ConCommandArgs args) { } } public struct DegreeSlices : IEnumerable, IEnumerable { public struct Enumerator : IEnumerator, IEnumerator, IDisposable { public readonly float sliceSize; public readonly float offset; public int i; public int iEnd; public float Current => (float)i * sliceSize + offset; object IEnumerator.Current => Current; public Enumerator(int sliceCount, float sliceOffset) { sliceSize = 360f / (float)sliceCount; offset = sliceOffset * sliceSize; i = -1; iEnd = sliceCount; } public void Dispose() { } public bool MoveNext() { i++; return i < iEnd; } public void Reset() { i = -1; } } public readonly int sliceCount; public readonly float sliceOffset; public DegreeSlices(int sliceCount, float sliceOffset) { this.sliceCount = sliceCount; this.sliceOffset = sliceOffset; } public Enumerator GetEnumerator() { return new Enumerator(sliceCount, sliceOffset); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public class DeployableMinionSpawner : IDisposable { public float respawnInterval = 30f; [CanBeNull] public SpawnCard spawnCard; public float minSpawnDistance = 3f; public float maxSpawnDistance = 40f; [NotNull] private Xoroshiro128Plus rng; private float respawnStopwatch = float.PositiveInfinity; [CanBeNull] public CharacterMaster ownerMaster { get; } public DeployableSlot deployableSlot { get; } public event Action onMinionSpawnedServer; public DeployableMinionSpawner([CanBeNull] CharacterMaster ownerMaster, DeployableSlot deployableSlot, [NotNull] Xoroshiro128Plus rng) { this.ownerMaster = ownerMaster; this.deployableSlot = deployableSlot; this.rng = rng; RoR2Application.onFixedUpdate += FixedUpdate; } public void Dispose() { RoR2Application.onFixedUpdate -= FixedUpdate; } private void FixedUpdate() { if (!ownerMaster) { return; } float fixedDeltaTime = Time.fixedDeltaTime; int deployableCount = ownerMaster.GetDeployableCount(deployableSlot); int deployableSameSlotLimit = ownerMaster.GetDeployableSameSlotLimit(deployableSlot); if (deployableCount >= deployableSameSlotLimit) { return; } respawnStopwatch += fixedDeltaTime; if (!(respawnStopwatch >= respawnInterval)) { return; } CharacterBody body = ownerMaster.GetBody(); if ((bool)body && (bool)spawnCard) { try { SpawnMinion(spawnCard, body); } catch (Exception message) { UnityEngine.Debug.LogError(message); } respawnStopwatch = 0f; } } private void SpawnMinion([NotNull] SpawnCard spawnCard, [NotNull] CharacterBody spawnTarget) { DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = minSpawnDistance, maxDistance = maxSpawnDistance, spawnOnTarget = spawnTarget.transform }, RoR2Application.rng); directorSpawnRequest.summonerBodyObject = ownerMaster.GetBodyObject(); directorSpawnRequest.onSpawnedServer = OnMinionSpawnedServerInternal; DirectorCore.instance.TrySpawnObject(directorSpawnRequest); } private void OnMinionSpawnedServerInternal([NotNull] SpawnCard.SpawnResult spawnResult) { GameObject spawnedInstance = spawnResult.spawnedInstance; if ((bool)spawnedInstance) { CharacterMaster component = spawnedInstance.GetComponent(); Deployable deployable = spawnedInstance.AddComponent(); deployable.onUndeploy = deployable.onUndeploy ?? new UnityEvent(); if ((bool)component) { deployable.onUndeploy.AddListener(component.TrueKill); } else { deployable.onUndeploy.AddListener(delegate { UnityEngine.Object.Destroy(spawnedInstance); }); } ownerMaster.AddDeployable(deployable, deployableSlot); } this.onMinionSpawnedServer?.Invoke(spawnResult); } } public static class DevCommands { private class CvSvNetLogObjectIds : ToggleVirtualConVar { private static readonly CvSvNetLogObjectIds instance = new CvSvNetLogObjectIds("sv_net_log_object_ids", ConVarFlags.None, "0", "Logs objects associated with each network id to net_id_log.txt as encountered by the server."); private uint highestObservedId; private FieldInfo monitoredField; private TextWriter writer; public CvSvNetLogObjectIds(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { monitoredField = typeof(NetworkIdentity).GetField("s_NextNetworkId", BindingFlags.Static | BindingFlags.NonPublic); } protected override void OnEnable() { RoR2Application.onFixedUpdate += Update; RoR2Application.onUpdate += Update; writer = new StreamWriter("net_id_log.txt", append: false); highestObservedId = GetCurrentHighestID(); } protected override void OnDisable() { writer.Dispose(); writer = null; RoR2Application.onUpdate -= Update; RoR2Application.onFixedUpdate -= Update; } private uint GetCurrentHighestID() { return (uint)monitoredField.GetValue(null); } private void Update() { if (NetworkServer.active) { uint currentHighestID = GetCurrentHighestID(); while (highestObservedId < currentHighestID) { GameObject gameObject = NetworkServer.FindLocalObject(new NetworkInstanceId(highestObservedId)); writer.WriteLine(string.Format("[{0, 0:D10}]={1}", highestObservedId, gameObject ? gameObject.name : "null")); highestObservedId++; } } } } private static void AddTokenIfDefault(List lines, string token) { if (!string.IsNullOrEmpty(token) && (object)Language.GetString(token) == token) { lines.Add(string.Format("\t\t\"{0}\": \"{0}\",", token)); } } [ConCommand(commandName = "language_generate_tokens", flags = ConVarFlags.None, helpText = "Generates default token definitions to be inserted into a JSON language file.")] private static void CCLanguageGenerateTokens(ConCommandArgs args) { List list = new List(); foreach (ItemDef item in ItemCatalog.allItems.Select(ItemCatalog.GetItemDef)) { AddTokenIfDefault(list, item.nameToken); AddTokenIfDefault(list, item.pickupToken); AddTokenIfDefault(list, item.descriptionToken); } list.Add("\r\n"); foreach (EquipmentDef item2 in EquipmentCatalog.allEquipment.Select(EquipmentCatalog.GetEquipmentDef)) { AddTokenIfDefault(list, item2.nameToken); AddTokenIfDefault(list, item2.pickupToken); AddTokenIfDefault(list, item2.descriptionToken); } } [ConCommand(commandName = "rng_test_roll", flags = ConVarFlags.None, helpText = "Tests the RNG. First argument is a percent chance, second argument is a number of rolls to perform. Result is the average number of rolls that passed.")] private static void CCTestRng(ConCommandArgs args) { float argFloat = args.GetArgFloat(0); ulong argULong = args.GetArgULong(1); ulong num = 0uL; for (ulong num2 = 0uL; num2 < argULong; num2++) { if (RoR2Application.rng.RangeFloat(0f, 100f) < argFloat) { num++; } } } [ConCommand(commandName = "getpos", flags = ConVarFlags.None, helpText = "Prints the current position of the sender's body.")] private static void CCGetPos(ConCommandArgs args) { UnityEngine.Vector3 position = args.GetSenderBody().transform.position; UnityEngine.Debug.LogFormat("{0} {1} {2}", position.x, position.y, position.z); } [ConCommand(commandName = "setpos", flags = ConVarFlags.Cheat, helpText = "Teleports the sender's body to the specified position.")] private static void CCSetPos(ConCommandArgs args) { CharacterBody senderBody = args.GetSenderBody(); TeleportHelper.TeleportGameObject(newPosition: new UnityEngine.Vector3(args.GetArgFloat(0), args.GetArgFloat(1), args.GetArgFloat(2)), gameObject: senderBody.gameObject); } [ConCommand(commandName = "create_object_from_resources", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "Instantiates an object from the Resources folder where the sender is looking.")] private static void CreateObjectFromResources(ConCommandArgs args) { CharacterBody senderBody = args.GetSenderBody(); GameObject gameObject = LegacyResourcesAPI.Load(args.GetArgString(0)); if (!gameObject) { throw new ConCommandException("Prefab could not be found at the specified path. Argument must be a Resources/-relative path to a prefab."); } if (senderBody.GetComponent().GetAimRaycast(float.PositiveInfinity, out var hitInfo)) { UnityEngine.Vector3 point = hitInfo.point; UnityEngine.Quaternion identity = UnityEngine.Quaternion.identity; NetworkServer.Spawn(UnityEngine.Object.Instantiate(gameObject, point, identity)); } } [ConCommand(commandName = "resources_load_async_test", flags = ConVarFlags.None, helpText = "Tests Resources.LoadAsync. Loads the asset at the specified path and prints out the results of the operation.")] private static void CCResourcesLoadAsyncTest(ConCommandArgs args) { Resources.LoadAsync(args.GetArgString(0)).completed += Check; static void Check(AsyncOperation asyncOperation) { } } private static UnityEngine.Object FindObjectFromInstanceID(int instanceId) { return (UnityEngine.Object)typeof(UnityEngine.Object).GetMethod("FindObjectFromInstanceID", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[1] { instanceId }); } [ConCommand(commandName = "dump_object_info", flags = ConVarFlags.None, helpText = "Prints debug info about the object with the provided instance ID.")] private static void CCDumpObjectInfo(ConCommandArgs args) { int argInt = args.GetArgInt(0); UnityEngine.Object @object = FindObjectFromInstanceID(argInt); if (!@object) { throw new Exception($"Object is not valid. objectInstanceId={argInt}"); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(@object.name); stringBuilder.AppendLine($" instanceId={@object.GetInstanceID()}"); stringBuilder.AppendLine(" type=" + @object.GetType().FullName); GameObject gameObject = null; if (@object is GameObject gameObject2) { gameObject = gameObject2; } else if (@object is Component component) { gameObject = component.gameObject; } if ((bool)gameObject) { stringBuilder.Append(" scene=\"" + gameObject.scene.name + "\""); stringBuilder.Append(" transformPath=" + Util.BuildPrefabTransformPath(gameObject.transform.root, gameObject.transform, appendCloneSuffix: false, includeRoot: true)); } args.Log(stringBuilder.ToString()); } } public enum DifficultyIndex { Invalid = -1, Easy, Normal, Hard, Eclipse1, Eclipse2, Eclipse3, Eclipse4, Eclipse5, Eclipse6, Eclipse7, Eclipse8, Count } public class DifficultyDef { public readonly float scalingValue; public readonly string descriptionToken; public readonly string nameToken; public readonly string iconPath; public readonly UnityEngine.Color color; public readonly string serverTag; private Sprite iconSprite; private bool foundIconSprite; public bool countsAsHardMode { get; private set; } public DifficultyDef(float scalingValue, string nameToken, string iconPath, string descriptionToken, UnityEngine.Color color, string serverTag, bool countsAsHardMode) { this.scalingValue = scalingValue; this.descriptionToken = descriptionToken; this.nameToken = nameToken; this.iconPath = iconPath; this.color = color; this.serverTag = serverTag; this.countsAsHardMode = countsAsHardMode; } public Sprite GetIconSprite() { if (!foundIconSprite) { iconSprite = LegacyResourcesAPI.Load(iconPath); foundIconSprite = iconSprite; } return iconSprite; } } public static class DifficultyCatalog { private static readonly DifficultyDef[] difficultyDefs; public static int standardDifficultyCount; static DifficultyCatalog() { standardDifficultyCount = 3; difficultyDefs = new DifficultyDef[11]; difficultyDefs[0] = new DifficultyDef(1f, "DIFFICULTY_EASY_NAME", "Textures/DifficultyIcons/texDifficultyEasyIcon", "DIFFICULTY_EASY_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.EasyDifficulty), "dz", countsAsHardMode: false); difficultyDefs[1] = new DifficultyDef(2f, "DIFFICULTY_NORMAL_NAME", "Textures/DifficultyIcons/texDifficultyNormalIcon", "DIFFICULTY_NORMAL_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.NormalDifficulty), "rs", countsAsHardMode: false); difficultyDefs[2] = new DifficultyDef(3f, "DIFFICULTY_HARD_NAME", "Textures/DifficultyIcons/texDifficultyHardIcon", "DIFFICULTY_HARD_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true); difficultyDefs[3] = new DifficultyDef(3f, "ECLIPSE_1_NAME", "Textures/DifficultyIcons/texDifficultyEclipse1Icon", "ECLIPSE_1_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true); difficultyDefs[4] = new DifficultyDef(3f, "ECLIPSE_2_NAME", "Textures/DifficultyIcons/texDifficultyEclipse2Icon", "ECLIPSE_2_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true); difficultyDefs[5] = new DifficultyDef(3f, "ECLIPSE_3_NAME", "Textures/DifficultyIcons/texDifficultyEclipse3Icon", "ECLIPSE_3_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true); difficultyDefs[6] = new DifficultyDef(3f, "ECLIPSE_4_NAME", "Textures/DifficultyIcons/texDifficultyEclipse4Icon", "ECLIPSE_4_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true); difficultyDefs[7] = new DifficultyDef(3f, "ECLIPSE_5_NAME", "Textures/DifficultyIcons/texDifficultyEclipse5Icon", "ECLIPSE_5_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true); difficultyDefs[8] = new DifficultyDef(3f, "ECLIPSE_6_NAME", "Textures/DifficultyIcons/texDifficultyEclipse6Icon", "ECLIPSE_6_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true); difficultyDefs[9] = new DifficultyDef(3f, "ECLIPSE_7_NAME", "Textures/DifficultyIcons/texDifficultyEclipse7Icon", "ECLIPSE_7_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true); difficultyDefs[10] = new DifficultyDef(3f, "ECLIPSE_8_NAME", "Textures/DifficultyIcons/texDifficultyEclipse8Icon", "ECLIPSE_8_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true); } public static DifficultyDef GetDifficultyDef(DifficultyIndex difficultyIndex) { return ArrayUtils.GetSafe(difficultyDefs, (int)difficultyIndex); } } public class DLC1Content : IContentPackProvider { public static class Items { public static ItemDef MoveSpeedOnKill; public static ItemDef HealingPotion; public static ItemDef HealingPotionConsumed; public static ItemDef PermanentDebuffOnHit; public static ItemDef AttackSpeedAndMoveSpeed; public static ItemDef CritDamage; public static ItemDef BearVoid; public static ItemDef MushroomVoid; public static ItemDef CloverVoid; public static ItemDef StrengthenBurn; public static ItemDef GummyCloneIdentifier; public static ItemDef RegeneratingScrap; public static ItemDef RegeneratingScrapConsumed; public static ItemDef BleedOnHitVoid; public static ItemDef CritGlassesVoid; public static ItemDef TreasureCacheVoid; public static ItemDef SlowOnHitVoid; public static ItemDef MissileVoid; public static ItemDef ChainLightningVoid; public static ItemDef ExtraLifeVoid; public static ItemDef ExtraLifeVoidConsumed; public static ItemDef EquipmentMagazineVoid; public static ItemDef ExplodeOnDeathVoid; public static ItemDef FragileDamageBonus; public static ItemDef FragileDamageBonusConsumed; public static ItemDef OutOfCombatArmor; public static ItemDef ScrapWhiteSuppressed; public static ItemDef ScrapGreenSuppressed; public static ItemDef ScrapRedSuppressed; public static ItemDef MoreMissile; public static ItemDef ImmuneToDebuff; public static ItemDef RandomEquipmentTrigger; public static ItemDef PrimarySkillShuriken; public static ItemDef RandomlyLunar; public static ItemDef GoldOnHurt; public static ItemDef HalfAttackSpeedHalfCooldowns; public static ItemDef HalfSpeedDoubleHealth; public static ItemDef FreeChest; public static ItemDef ConvertCritChanceToCritDamage; public static ItemDef ElementalRingVoid; public static ItemDef LunarSun; public static ItemDef DroneWeapons; public static ItemDef DroneWeaponsBoost; public static ItemDef DroneWeaponsDisplay1; public static ItemDef DroneWeaponsDisplay2; public static ItemDef VoidmanPassiveItem; public static ItemDef MinorConstructOnKill; public static ItemDef VoidMegaCrabItem; } public static class ItemRelationshipTypes { public static ItemRelationshipType ContagiousItem; } public static class Equipment { public static EquipmentDef Molotov; public static EquipmentDef VendingMachine; public static EquipmentDef BossHunter; public static EquipmentDef BossHunterConsumed; public static EquipmentDef GummyClone; public static EquipmentDef MultiShopCard; public static EquipmentDef LunarPortalOnUse; public static EquipmentDef EliteVoidEquipment; } public static class Buffs { public static BuffDef ElementalRingVoidReady; public static BuffDef ElementalRingVoidCooldown; public static BuffDef BearVoidReady; public static BuffDef BearVoidCooldown; public static BuffDef KillMoveSpeed; public static BuffDef PermanentDebuff; public static BuffDef MushroomVoidActive; public static BuffDef StrongerBurn; public static BuffDef Fracture; public static BuffDef OutOfCombatArmorBuff; public static BuffDef PrimarySkillShurikenBuff; public static BuffDef Blinded; public static BuffDef EliteEarth; public static BuffDef EliteVoid; public static BuffDef JailerTether; public static BuffDef JailerSlow; public static BuffDef VoidRaidCrabWardWipeFog; public static BuffDef VoidSurvivorCorruptMode; public static BuffDef ImmuneToDebuffReady; public static BuffDef ImmuneToDebuffCooldown; } public static class Elites { public static EliteDef Earth; public static EliteDef EarthHonor; public static EliteDef Void; } public static class GameEndings { public static GameEndingDef VoidEnding; } public static class Survivors { public static SurvivorDef Railgunner; } public static class MiscPickups { public static MiscPickupDef VoidCoin; } private ContentPack contentPack = new ContentPack(); private static readonly string addressablesLabel = "ContentPack:RoR2.DLC1"; public string identifier => "RoR2.DLC1"; public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args) { contentPack.identifier = identifier; AddressablesLoadHelper loadHelper = AddressablesLoadHelper.CreateUsingDefaultResourceLocator(addressablesLabel); yield return loadHelper.AddContentPackLoadOperationWithYields(contentPack); loadHelper.AddGenericOperation(delegate { ContentLoadHelper.PopulateTypeFields(typeof(Items), contentPack.itemDefs); ContentLoadHelper.PopulateTypeFields(typeof(ItemRelationshipTypes), contentPack.itemRelationshipTypes); ContentLoadHelper.PopulateTypeFields(typeof(Equipment), contentPack.equipmentDefs); ContentLoadHelper.PopulateTypeFields(typeof(Buffs), contentPack.buffDefs, (string fieldName) => "bd" + fieldName); ContentLoadHelper.PopulateTypeFields(typeof(Elites), contentPack.eliteDefs, (string fieldName) => "ed" + fieldName); ContentLoadHelper.PopulateTypeFields(typeof(Survivors), contentPack.survivorDefs); ContentLoadHelper.PopulateTypeFields(typeof(GameEndings), contentPack.gameEndingDefs); ContentLoadHelper.PopulateTypeFields(typeof(MiscPickups), contentPack.miscPickupDefs); }, 0.05f); while (loadHelper.coroutine.MoveNext()) { args.ReportProgress(loadHelper.progress.value); yield return loadHelper.coroutine.Current; } } public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args) { ContentPack.Copy(contentPack, args.output); yield break; } public IEnumerator FinalizeAsync(FinalizeAsyncArgs args) { yield break; } } public class DLC2Content : IContentPackProvider { public static class Artifacts { public static ArtifactDef Rebirth; } public static class Items { public static ItemDef LowerHealthHigherDamage; public static ItemDef NegateAttack; public static ItemDef ExtraShrineItem; public static ItemDef StunAndPierce; public static ItemDef BoostAllStats; public static ItemDef KnockBackHitEnemies; public static ItemDef TriggerEnemyDebuffs; public static ItemDef LowerPricedChests; public static ItemDef LowerPricedChestsConsumed; public static ItemDef ResetChests; public static ItemDef IncreaseDamageOnMultiKill; public static ItemDef GoldOnStageStart; public static ItemDef IncreasePrimaryDamage; public static ItemDef DelayedDamage; public static ItemDef TeleportOnLowHealth; public static ItemDef TeleportOnLowHealthConsumed; public static ItemDef ExtraStatsOnLevelUp; public static ItemDef MeteorAttackOnHighDamage; public static ItemDef OnLevelUpFreeUnlock; public static ItemDef LemurianHarness; } public static class ItemRelationshipTypes { } public static class Equipment { public static EquipmentDef HealAndRevive; public static EquipmentDef HealAndReviveConsumed; public static EquipmentDef EliteBeadEquipment; public static EquipmentDef EliteAurelioniteEquipment; } public static class Buffs { public static BuffDef KnockUpHitEnemies; public static BuffDef KnockDownHitEnemies; public static BuffDef BoostAllStatsBuff; public static BuffDef LowerHealthHigherDamageBuff; public static BuffDef IncreaseDamageBuff; public static BuffDef IncreasePrimaryDamageBuff; public static BuffDef DelayedDamageBuff; public static BuffDef DelayedDamageDebuff; public static BuffDef ExtraStatsOnLevelUpBuff; public static BuffDef lunarruin; public static BuffDef TamperedHeart; public static BuffDef CorruptionFesters; public static BuffDef WeakenedBeating; public static BuffDef StunAndPierceBuff; public static BuffDef ChakraBuff; public static BuffDef RevitalizeBuff; public static BuffDef FreeChest; public static BuffDef Boosted; public static BuffDef boostedFireEffect; public static BuffDef CookingChopped; public static BuffDef CookingOiled; public static BuffDef CookingRoasted; public static BuffDef CookingRolled; public static BuffDef CookingFlambe; public static BuffDef CookingSearing; public static BuffDef CookingRolling; public static BuffDef FreeUnlocks; public static BuffDef GeodeBuff; public static BuffDef DisableAllSkills; public static BuffDef SoulCost; public static BuffDef ExtraLifeBuff; public static BuffDef EliteBead; public static BuffDef EliteBeadCorruption; public static BuffDef EliteBeadThorns; public static BuffDef EliteAurelionite; public static BuffDef AurelioniteBlessing; public static BuffDef HealAndReviveRegenBuff; public static BuffDef ChildFrolicCooldown; public static BuffDef TeleportOnLowHealth; public static BuffDef TeleportOnLowHealthCooldown; public static BuffDef SojournVehicle; public static BuffDef SojournHealing; public static BuffDef HiddenRejectAllDamage; } public static class Elites { public static EliteDef Aurelionite; public static EliteDef Bead; } public static class GameEndings { public static GameEndingDef RebirthEndingDef; } public static class Survivors { public static SurvivorDef Seeker; public static SurvivorDef FalseSon; public static SurvivorDef Chef; } public static class MiscPickups { } private ContentPack contentPack = new ContentPack(); private static readonly string addressablesLabel = "ContentPack:RoR2.DLC2"; public string identifier => "RoR2.DLC2"; public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args) { contentPack.identifier = identifier; AddressablesLoadHelper loadHelper = AddressablesLoadHelper.CreateUsingDefaultResourceLocator(addressablesLabel); yield return loadHelper.AddContentPackLoadOperationWithYields(contentPack); loadHelper.AddGenericOperation(delegate { ContentLoadHelper.PopulateTypeFields(typeof(Artifacts), contentPack.artifactDefs); ContentLoadHelper.PopulateTypeFields(typeof(Items), contentPack.itemDefs); ContentLoadHelper.PopulateTypeFields(typeof(ItemRelationshipTypes), contentPack.itemRelationshipTypes); ContentLoadHelper.PopulateTypeFields(typeof(Equipment), contentPack.equipmentDefs); ContentLoadHelper.PopulateTypeFields(typeof(Buffs), contentPack.buffDefs, (string fieldName) => "bd" + fieldName); ContentLoadHelper.PopulateTypeFields(typeof(Elites), contentPack.eliteDefs, (string fieldName) => "ed" + fieldName); ContentLoadHelper.PopulateTypeFields(typeof(Survivors), contentPack.survivorDefs); ContentLoadHelper.PopulateTypeFields(typeof(GameEndings), contentPack.gameEndingDefs); ContentLoadHelper.PopulateTypeFields(typeof(MiscPickups), contentPack.miscPickupDefs); }, 0.05f); while (loadHelper.coroutine.MoveNext()) { args.ReportProgress(loadHelper.progress.value); yield return loadHelper.coroutine.Current; } } public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args) { ContentPack.Copy(contentPack, args.output); yield break; } public IEnumerator FinalizeAsync(FinalizeAsyncArgs args) { yield break; } } [CreateAssetMenu(menuName = "RoR2/DropTables/DoppelgangerDropTable")] public class DoppelgangerDropTable : PickupDropTable { public ItemTag[] requiredItemTags = Array.Empty(); public ItemTag[] bannedItemTags = Array.Empty(); public float tier1Weight = 0.8f; public float tier2Weight = 0.2f; public float tier3Weight = 0.01f; public float bossWeight; public float lunarItemWeight; public float voidTier1Weight; public float voidTier2Weight; public float voidTier3Weight; public float voidBossWeight; private readonly WeightedSelection selector = new WeightedSelection(); private Inventory doppelgangerInventory; protected override void OnEnable() { base.OnEnable(); DoppelgangerInvasionManager.onDoppelgangerDeath += OnDoppelgangerDeath; } protected override void OnDisable() { DoppelgangerInvasionManager.onDoppelgangerDeath -= OnDoppelgangerDeath; base.OnDisable(); } protected override void Regenerate(Run run) { GenerateWeightedSelection(); } private bool CanSelectItem(ItemDef itemDef) { ItemTag[] array = requiredItemTags; foreach (ItemTag value in array) { if (Array.IndexOf(itemDef.tags, value) == -1) { return false; } } array = bannedItemTags; foreach (ItemTag value2 in array) { if (Array.IndexOf(itemDef.tags, value2) != -1) { return false; } } return itemDef.canRemove; } private void GenerateWeightedSelection() { selector.Clear(); if (!doppelgangerInventory) { return; } foreach (ItemIndex item in doppelgangerInventory.itemAcquisitionOrder) { ItemDef itemDef = ItemCatalog.GetItemDef(item); PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(item); if (!CanSelectItem(itemDef)) { continue; } float num = 0f; switch (itemDef.tier) { case ItemTier.Tier1: if (Run.instance.availableTier1DropList.Contains(pickupIndex)) { num = tier1Weight; } break; case ItemTier.Tier2: if (Run.instance.availableTier2DropList.Contains(pickupIndex)) { num = tier2Weight; } break; case ItemTier.Tier3: if (Run.instance.availableTier3DropList.Contains(pickupIndex)) { num = tier3Weight; } break; case ItemTier.Boss: if (Run.instance.availableBossDropList.Contains(pickupIndex)) { num = bossWeight; } break; case ItemTier.Lunar: if (Run.instance.availableLunarItemDropList.Contains(pickupIndex)) { num = lunarItemWeight; } break; case ItemTier.VoidTier1: if (Run.instance.availableVoidTier1DropList.Contains(pickupIndex)) { num = voidTier1Weight; } break; case ItemTier.VoidTier2: if (Run.instance.availableVoidTier2DropList.Contains(pickupIndex)) { num = voidTier2Weight; } break; case ItemTier.VoidTier3: if (Run.instance.availableVoidTier3DropList.Contains(pickupIndex)) { num = voidTier3Weight; } break; case ItemTier.VoidBoss: if (Run.instance.availableVoidTier3DropList.Contains(pickupIndex)) { num = voidBossWeight; } break; } if (num > 0f) { selector.AddChoice(pickupIndex, num); } } } protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng) { return PickupDropTable.GenerateDropFromWeightedSelection(rng, selector); } private void OnDoppelgangerDeath(DamageReport damageReport) { doppelgangerInventory = damageReport.victimMaster?.inventory; GenerateWeightedSelection(); } public override int GetPickupCount() { return selector.Count; } protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng) { return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, selector); } } public static class EditorUtil { private static int recursionLimit; private static int recursionStep; private static readonly char[] directorySeparators; private static event Action _onNextUpdate; public static event Action onNextUpdate { add { } remove { } } static EditorUtil() { recursionLimit = 3; recursionStep = 0; directorySeparators = new char[2] { '/', '\\' }; } private static void StaticUpdate() { Action action = EditorUtil._onNextUpdate; EditorUtil._onNextUpdate = null; action?.Invoke(); } public static bool IsPrefabVariant(UnityEngine.Object obj) { return false; } public static void SetDirty(UnityEngine.Object obj) { } public static void NonSerializedObjectGUI(ref T obj) { } [UsedImplicitly] private static void SetFieldGeneric(FieldInfo fieldInfo, object instance, T value) { if (fieldInfo.FieldType.IsAssignableFrom(typeof(T))) { fieldInfo.SetValue(instance, value); return; } UnityEngine.Debug.LogErrorFormat("Cannot assign value {0} of type {1} to field {2} of type {3}", value, value.GetType().Name, fieldInfo.Name, fieldInfo.FieldType.Name); } public static UnityEngine.Object PrefabUtilityGetNearestPrefabInstanceRoot(UnityEngine.Object obj) { throw new NotImplementedException(); } public static UnityEngine.Object PrefabUtilityInstantiatePrefab(UnityEngine.Object prefab, Transform parent) { throw new NotImplementedException(); } public static void CopyToScriptableObject(TSrc src, string folder) where TDest : ScriptableObject { TDest val = ScriptableObject.CreateInstance(); Dictionary)> dictionary = new Dictionary)>(); Dictionary)> dictionary2 = new Dictionary)>(); FieldInfo[] fields = typeof(TSrc).GetFields(); foreach (FieldInfo srcField in fields) { dictionary[srcField.Name] = (srcField.FieldType, (TSrc s) => srcField.GetValue(s)); } PropertyInfo[] properties = typeof(TSrc).GetProperties(); foreach (PropertyInfo srcProperty in properties) { if (!(srcProperty.GetMethod == null)) { dictionary[srcProperty.Name] = (srcProperty.PropertyType, (TSrc s) => srcProperty.GetValue(s)); } } fields = typeof(TDest).GetFields(); foreach (FieldInfo destField in fields) { dictionary2[destField.Name] = (destField.FieldType, delegate(TDest d, object v) { destField.SetValue(d, v); }); } properties = typeof(TDest).GetProperties(); foreach (PropertyInfo destProperty in properties) { if (!(destProperty.SetMethod == null)) { dictionary2[destProperty.Name] = (destProperty.PropertyType, delegate(TDest d, object v) { destProperty.SetValue(d, v); }); } } foreach (KeyValuePair)> item in dictionary) { string key = item.Key; var (c, func) = item.Value; if (dictionary2.TryGetValue(key, out var value)) { var (type, action) = value; if (type.IsAssignableFrom(c)) { action(val, func(src)); } } } CreateAsset(val, folder + val.name + ".asset"); } private static void CreateAsset(UnityEngine.Object asset, string path) { } private static void AssetDatabaseSaveAssets() { } private static void AssetDatabaseRefresh() { } private static void AssetDatabaseMoveAsset(string oldPath, string newPath) { } private static void AssetDatabaseDeleteAsset(string path) { } private static void AssetDatabaseCreateFolder(string parentFolder, string newFolderName) { } public static void EnsureDirectoryExists(string directoryPath) { string[] array = directoryPath.Split(directorySeparators); string text = array[0].ToString(); int i = 1; for (int num = array.Length; i < num; i++) { string text2 = array[i].ToString(); string text3 = $"{text}{'/'}{text2}"; if (!Directory.Exists(text3)) { AssetDatabaseCreateFolder(text, text2); } text = text3; } if (!Directory.Exists(directoryPath)) { UnityEngine.Debug.LogWarning("Failed to ensure path \"" + directoryPath + "\""); } } public static void MoveAsset(string oldPath, string newPath, bool deleteEmpty = true) { string directoryName = System.IO.Path.GetDirectoryName(oldPath); EnsureDirectoryExists(System.IO.Path.GetDirectoryName(newPath)); AssetDatabaseMoveAsset(oldPath, newPath); if (deleteEmpty) { DeleteDirectoryEmptyChildren(directoryName); } } public static void DeleteDirectoryIfEmpty(string directory) { DeleteDirectoryEmptyChildren(directory); DeleteDirectoryEmptyParents(directory); } private static bool DeleteDirectoryEmptyChildren(string directory) { bool flag = true; try { string[] directories = Directory.GetDirectories(directory); for (int i = 0; i < directories.Length; i++) { string fileName = System.IO.Path.GetFileName(directories[i]); if (!DeleteDirectoryEmptyChildren(directory + "/" + fileName)) { flag = false; } } flag &= Directory.GetFiles(directory).Length == 0; if (flag) { AssetDatabaseDeleteAsset(directory); } } catch (Exception ex) { throw new Exception($"DeleteDirectoryEmptyChildren(\"{directory}\") error: {ex}", ex); } return flag; } private static void DeleteDirectoryEmptyParents(string directory) { string directoryName = System.IO.Path.GetDirectoryName(directory); bool flag = Directory.GetDirectories(directoryName).Length != 0; bool flag2 = Directory.GetFiles(directoryName).Length != 0; if (!flag && !flag2) { AssetDatabaseDeleteAsset(directory); DeleteDirectoryEmptyParents(directoryName); } } public static IEnumerable GetAllAssetsInDirectory(string directory, bool includeSubdirectories) { DirectoryInfo directoryInfo = new DirectoryInfo(directory); FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos(); for (int i = 0; i < fileSystemInfos.Length; i++) { string name = fileSystemInfos[i].Name; if (!name.EndsWith(".meta")) { yield return directory + "/" + name; } } if (!includeSubdirectories) { yield break; } DirectoryInfo[] directories = directoryInfo.GetDirectories(); foreach (DirectoryInfo directoryInfo2 in directories) { string directory2 = directory + "/" + directoryInfo2.Name; foreach (string item in GetAllAssetsInDirectory(directory2, includeSubdirectories)) { yield return item; } } } } public enum EffectIndex { Invalid = -1 } public class EffectDef { private GameObject _prefab; public Func cullMethod; public EffectIndex index { get; internal set; } = EffectIndex.Invalid; public GameObject prefab { get { return _prefab; } set { if (!value) { throw new ArgumentNullException("Prefab is invalid."); } if ((object)_prefab != value) { EffectComponent component = value.GetComponent(); if (!component) { throw new ArgumentException($"Prefab \"{value}\" does not have EffectComponent attached."); } _prefab = value; prefabEffectComponent = component; prefabVfxAttributes = _prefab.GetComponent(); prefabName = _prefab.name; spawnSoundEventName = prefabEffectComponent.soundName; } } } public EffectComponent prefabEffectComponent { get; private set; } public VFXAttributes prefabVfxAttributes { get; private set; } public string prefabName { get; private set; } public string spawnSoundEventName { get; private set; } public EffectDef() { } public EffectDef(GameObject effectPrefab) { prefab = effectPrefab; } } public static class EffectCatalog { private static EffectDef[] entries = Array.Empty(); public static int effectCount => entries.Length; [SystemInitializer(new Type[] { })] public static void Init() { SetEntries(ContentManager.effectDefs); } public static void SetEntries(EffectDef[] newEntries) { EffectDef[] array = entries; foreach (EffectDef obj in array) { obj.index = EffectIndex.Invalid; obj.prefabEffectComponent.effectIndex = EffectIndex.Invalid; } ArrayUtils.CloneTo(newEntries, ref entries); Array.Sort(entries, (EffectDef a, EffectDef b) => string.CompareOrdinal(a.prefabName, b.prefabName)); for (int j = 0; j < entries.Length; j++) { ref EffectDef reference = ref entries[j]; reference.index = (EffectIndex)j; reference.prefabEffectComponent.effectIndex = reference.index; } } public static EffectIndex FindEffectIndexFromPrefab(GameObject effectPrefab) { if ((bool)effectPrefab) { EffectComponent component = effectPrefab.GetComponent(); if ((bool)component) { return component.effectIndex; } } return EffectIndex.Invalid; } public static EffectDef GetEffectDef(EffectIndex effectIndex) { EffectDef[] array = entries; EffectDef defaultValue = null; return ArrayUtils.GetSafe(array, (int)effectIndex, in defaultValue); } [ConCommand(commandName = "effects_reload", flags = ConVarFlags.Cheat, helpText = "Reloads the effect catalog.")] private static void CCEffectsReload(ConCommandArgs args) { throw new ConCommandException("Command unavailable outside editor until asset reloading is implemented at the ContentPack level."); } } public class EffectData { private UnityEngine.Vector3 _origin; public UnityEngine.Quaternion rotation = defaultRotation; public float scale = defaultScale; public Color32 color = defaultColor; public UnityEngine.Vector3 start = defaultStart; public SurfaceDefIndex surfaceDefIndex = defaultSurfaceDefIndex; public uint genericUInt = defaultGenericUInt; public float genericFloat = defaultGenericFloat; public bool genericBool = defaultGenericBool; public NetworkSoundEventIndex networkSoundEventIndex = defaultNetworkSoundEventIndex; private static readonly uint useNonDefaultRotationFlag = 1u; private static readonly uint useNonDefaultRootObjectFlag = 2u; private static readonly uint useNonDefaultModelChildIndexFlag = 4u; private static readonly uint useNonDefaultScaleFlag = 8u; private static readonly uint useNonDefaultColorFlag = 16u; private static readonly uint useNonDefaultStartFlag = 32u; private static readonly uint useNonDefaultSurfaceDefIndexFlag = 64u; private static readonly uint useNonDefaultGenericUIntFlag = 128u; private static readonly uint useNonDefaultGenericFloatFlag = 256u; private static readonly uint useNonDefaultGenericBoolFlag = 512u; private static readonly uint useNonDefaultNetworkSoundEventIndexFlag = 1024u; private static readonly UnityEngine.Quaternion defaultRotation = UnityEngine.Quaternion.identity; private static readonly GameObject defaultRootObject = null; private static readonly short defaultModelChildIndex = -1; private static readonly float defaultScale = 1f; private static readonly Color32 defaultColor = UnityEngine.Color.white; private static readonly UnityEngine.Vector3 defaultStart = UnityEngine.Vector3.zero; private static readonly SurfaceDefIndex defaultSurfaceDefIndex = SurfaceDefIndex.Invalid; private static readonly uint defaultGenericUInt = 0u; private static readonly float defaultGenericFloat = 0f; private static readonly bool defaultGenericBool = false; public bool forceUnpooled; private static readonly NetworkSoundEventIndex defaultNetworkSoundEventIndex = NetworkSoundEventIndex.Invalid; public UnityEngine.Vector3 origin { get { return _origin; } set { if (!Util.PositionIsValid(value)) { UnityEngine.Debug.LogFormat("EffectData.origin assignment position is invalid! Position={0}", value); } else { _origin = value; } } } public GameObject rootObject { get; private set; } = defaultRootObject; public short modelChildIndex { get; private set; } = defaultModelChildIndex; public static void Copy([NotNull] EffectData src, [NotNull] EffectData dest) { dest.origin = src.origin; dest.rotation = src.rotation; dest.rootObject = src.rootObject; dest.modelChildIndex = src.modelChildIndex; dest.scale = src.scale; dest.color = src.color; dest.start = src.start; dest.surfaceDefIndex = src.surfaceDefIndex; dest.genericUInt = src.genericUInt; dest.genericFloat = src.genericFloat; dest.genericBool = src.genericBool; dest.networkSoundEventIndex = src.networkSoundEventIndex; dest.forceUnpooled = src.forceUnpooled; } public void Reset() { _origin = UnityEngine.Vector3.zero; rotation = UnityEngine.Quaternion.identity; rootObject = null; modelChildIndex = -1; scale = 1f; color = UnityEngine.Color.white; start = UnityEngine.Vector3.zero; genericUInt = 0u; genericFloat = 0f; genericBool = false; forceUnpooled = false; } public void SetNetworkedObjectReference(GameObject networkedObject) { rootObject = networkedObject; modelChildIndex = -1; } public GameObject ResolveNetworkedObjectReference() { return rootObject; } public void SetHurtBoxReference(HurtBox hurtBox) { if (!hurtBox || !hurtBox.healthComponent) { rootObject = null; modelChildIndex = -1; } else { rootObject = hurtBox.healthComponent.gameObject; modelChildIndex = hurtBox.indexInGroup; } } public void SetHurtBoxReference(GameObject gameObject) { HurtBox hurtBox = gameObject?.GetComponent(); if ((bool)hurtBox) { SetHurtBoxReference(hurtBox); return; } rootObject = gameObject; modelChildIndex = -1; } public GameObject ResolveHurtBoxReference() { if (modelChildIndex == -1) { return rootObject; } if (!rootObject) { return null; } ModelLocator component = rootObject.GetComponent(); if (!component) { return null; } Transform modelTransform = component.modelTransform; if (!modelTransform) { return null; } HurtBoxGroup component2 = modelTransform.GetComponent(); if (!component2) { return null; } HurtBox safe = ArrayUtils.GetSafe(component2.hurtBoxes, modelChildIndex); if (!safe) { return null; } return safe.gameObject; } public void SetChildLocatorTransformReference(GameObject rootObject, int childIndex) { this.rootObject = rootObject; modelChildIndex = (short)childIndex; } public Transform ResolveChildLocatorTransformReference() { if ((bool)rootObject) { if (modelChildIndex == -1) { return rootObject.transform; } ModelLocator component = rootObject.GetComponent(); if ((bool)component && (bool)component.modelTransform) { ChildLocator component2 = component.modelTransform.GetComponent(); if ((bool)component2) { return component2.FindChild(modelChildIndex); } } } return null; } public EffectData Clone() { EffectData effectData = new EffectData(); Copy(this, effectData); return effectData; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool ColorEquals(in Color32 x, in Color32 y) { if (x.r == y.r && x.g == y.g && x.b == y.b) { return x.a == y.a; } return false; } public void Serialize(NetworkWriter writer) { uint num = 0u; bool num2 = !rotation.Equals(defaultRotation); bool flag = rootObject != defaultRootObject; bool flag2 = modelChildIndex != defaultModelChildIndex; bool flag3 = scale != defaultScale; bool flag4 = !ColorEquals(in color, in defaultColor); bool flag5 = !start.Equals(defaultStart); bool flag6 = surfaceDefIndex != defaultSurfaceDefIndex; bool flag7 = genericUInt != defaultGenericUInt; bool flag8 = genericFloat != defaultGenericFloat; bool flag9 = genericBool != defaultGenericBool; bool flag10 = networkSoundEventIndex != defaultNetworkSoundEventIndex; if (num2) { num |= useNonDefaultRotationFlag; } if (flag) { num |= useNonDefaultRootObjectFlag; } if (flag2) { num |= useNonDefaultModelChildIndexFlag; } if (flag3) { num |= useNonDefaultScaleFlag; } if (flag4) { num |= useNonDefaultColorFlag; } if (flag5) { num |= useNonDefaultStartFlag; } if (flag6) { num |= useNonDefaultSurfaceDefIndexFlag; } if (flag7) { num |= useNonDefaultGenericUIntFlag; } if (flag8) { num |= useNonDefaultGenericFloatFlag; } if (flag9) { num |= useNonDefaultGenericBoolFlag; } if (flag10) { num |= useNonDefaultNetworkSoundEventIndexFlag; } writer.WritePackedUInt32(num); writer.Write(origin); if (num2) { writer.Write(rotation); } if (flag) { writer.Write(rootObject); } if (flag2) { writer.Write((byte)(modelChildIndex + 1)); } if (flag3) { writer.Write(scale); } if (flag4) { writer.Write(color); } if (flag5) { writer.Write(start); } if (flag6) { writer.WritePackedIndex32((int)surfaceDefIndex); } if (flag7) { writer.WritePackedUInt32(genericUInt); } if (flag8) { writer.Write(genericFloat); } if (flag9) { writer.Write(genericBool); } if (flag10) { writer.WriteNetworkSoundEventIndex(networkSoundEventIndex); } writer.Write(forceUnpooled); } public void Deserialize(NetworkReader reader) { uint flags = reader.ReadPackedUInt32(); bool flag = HasFlag(in useNonDefaultRotationFlag); bool flag2 = HasFlag(in useNonDefaultRootObjectFlag); bool flag3 = HasFlag(in useNonDefaultModelChildIndexFlag); bool flag4 = HasFlag(in useNonDefaultScaleFlag); bool flag5 = HasFlag(in useNonDefaultColorFlag); bool flag6 = HasFlag(in useNonDefaultStartFlag); bool flag7 = HasFlag(in useNonDefaultSurfaceDefIndexFlag); bool flag8 = HasFlag(in useNonDefaultGenericUIntFlag); bool flag9 = HasFlag(in useNonDefaultGenericFloatFlag); bool flag10 = HasFlag(in useNonDefaultGenericBoolFlag); bool flag11 = HasFlag(in useNonDefaultNetworkSoundEventIndexFlag); origin = reader.ReadVector3(); rotation = (flag ? reader.ReadQuaternion() : defaultRotation); rootObject = (flag2 ? reader.ReadGameObject() : defaultRootObject); modelChildIndex = (flag3 ? ((short)(reader.ReadByte() - 1)) : defaultModelChildIndex); scale = (flag4 ? reader.ReadSingle() : defaultScale); color = (flag5 ? reader.ReadColor32() : defaultColor); start = (flag6 ? reader.ReadVector3() : defaultStart); surfaceDefIndex = (flag7 ? ((SurfaceDefIndex)reader.ReadPackedIndex32()) : defaultSurfaceDefIndex); genericUInt = (flag8 ? reader.ReadPackedUInt32() : defaultGenericUInt); genericFloat = (flag9 ? reader.ReadSingle() : defaultGenericFloat); genericBool = (flag10 ? reader.ReadBoolean() : defaultGenericBool); networkSoundEventIndex = (flag11 ? reader.ReadNetworkSoundEventIndex() : defaultNetworkSoundEventIndex); forceUnpooled = reader.ReadBoolean(); bool HasFlag(in uint mask) { return (flags & mask) != 0; } } } public static class EffectManager { private class EffectMessage : MessageBase { public EffectIndex effectIndex; public readonly EffectData effectData = new EffectData(); public override void Serialize(NetworkWriter writer) { writer.WriteEffectIndex(effectIndex); writer.Write(effectData); } public override void Deserialize(NetworkReader reader) { effectIndex = reader.ReadEffectIndex(); reader.ReadEffectData(effectData); } } public static bool DisableAllEffectSpawning = false; private static bool _UsePools = true; private static Dictionary _EffectPrefabMap = new Dictionary(); private static Dictionary _ShouldUsePooledEffectMap = new Dictionary(); private static EffectManagerHelper _LastSpawnedEffect = null; private static EffectData _simpleEffectData = null; private const float POOL_EXPIRATION_TIME = 45f; private const int POOLS_UNLOADING_TIMESTEP = 5; private const int MINIMAL_POOLS_AMOUNT_BEFORE_UNLOADING = 5; private const int MAXIMUM_POOLS_AMOUNT_BEFORE_UNLOADING_IN_USE_POOLS = 30; private static readonly QosChannelIndex qosChannel = QosChannelIndex.effects; private static int frameCount = 0; private static readonly EffectMessage outgoingEffectMessage = new EffectMessage(); private static readonly EffectMessage incomingEffectMessage = new EffectMessage(); public static EffectManagerHelper LastSpawnedEffect { get { EffectManagerHelper lastSpawnedEffect = _LastSpawnedEffect; _LastSpawnedEffect = null; return lastSpawnedEffect; } } public static bool UsePools => _UsePools; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] private static void Init() { RoR2Application.onUpdate += Update; SceneManager.sceneUnloaded += OnSceneUnloaded; } private static void OnSceneUnloaded(Scene scene) { KillAllPools(); } public static void TogglePooling() { _UsePools = !_UsePools; UnityEngine.Debug.LogFormat("EffectManager pooling is {0}", _UsePools ? "ENABLED" : "DISABLED"); } public static bool ShouldUsePooledEffect(GameObject inPrefab) { if (inPrefab != null && UsePools) { if (!_ShouldUsePooledEffectMap.TryGetValue(inPrefab, out var value)) { VFXAttributes component = inPrefab.GetComponent(); if (component != null) { value = !component.DoNotPool; _ShouldUsePooledEffectMap.Add(inPrefab, value); } else { value = true; _ShouldUsePooledEffectMap.Add(inPrefab, value); } } return value; } return false; } private static void CreatePoolIfNotPresent(GameObject inPrefab) { if (!_EffectPrefabMap.ContainsKey(inPrefab)) { EffectPool effectPool = new EffectPool(); effectPool.PrefabObject = inPrefab; effectPool.AlwaysGrowable = true; effectPool.AddComponentIfMissing = true; effectPool.Initialize(1, 1); _EffectPrefabMap.Add(inPrefab, effectPool); } } public static EffectManagerHelper GetPooledEffect(GameObject inPrefab, UnityEngine.Vector3 inPosition, UnityEngine.Quaternion inRotation) { CreatePoolIfNotPresent(inPrefab); EffectPool effectPool = _EffectPrefabMap[inPrefab]; EffectManagerHelper @object = effectPool.GetObject(); if (@object != null) { @object.SetOwningPool(effectPool); @object.Initialize(); @object.gameObject.transform.position = inPosition; @object.gameObject.transform.rotation = inRotation; } return @object; } public static EffectManagerHelper GetAndActivatePooledEffect(GameObject inPrefab, UnityEngine.Vector3 inPosition, UnityEngine.Quaternion inRotation) { EffectManagerHelper pooledEffect = GetPooledEffect(inPrefab, inPosition, inRotation); pooledEffect.Reset(inActivate: true); pooledEffect.gameObject.SetActive(value: true); pooledEffect.ResetPostActivate(); return pooledEffect; } public static EffectManagerHelper GetPooledEffect(GameObject inPrefab, Transform inTransform) { CreatePoolIfNotPresent(inPrefab); EffectPool effectPool = _EffectPrefabMap[inPrefab]; EffectManagerHelper @object = effectPool.GetObject(); if (@object != null) { @object.SetOwningPool(effectPool); @object.Initialize(); @object.gameObject.transform.SetParent(inTransform); } return @object; } public static EffectManagerHelper GetAndActivatePooledEffect(GameObject inPrefab, Transform inTransform, bool inResetLocal = false) { EffectManagerHelper pooledEffect = GetPooledEffect(inPrefab, inTransform); if (inResetLocal) { pooledEffect.gameObject.transform.localPosition = UnityEngine.Vector3.zero; pooledEffect.gameObject.transform.localRotation = UnityEngine.Quaternion.identity; pooledEffect.gameObject.transform.localScale = UnityEngine.Vector3.one; } pooledEffect.Reset(inActivate: true); pooledEffect.gameObject.SetActive(value: true); pooledEffect.ResetPostActivate(); return pooledEffect; } public static EffectManagerHelper GetPooledEffect(GameObject inPrefab, UnityEngine.Vector3 inPosition, UnityEngine.Quaternion inRotation, Transform inTransform) { CreatePoolIfNotPresent(inPrefab); EffectPool effectPool = _EffectPrefabMap[inPrefab]; EffectManagerHelper @object = effectPool.GetObject(); if (@object != null) { @object.SetOwningPool(effectPool); @object.Initialize(); @object.gameObject.transform.localPosition = inPosition; @object.gameObject.transform.localRotation = inRotation; } return @object; } public static EffectManagerHelper GetAndActivatePooledEffect(GameObject inPrefab, UnityEngine.Vector3 inPosition, UnityEngine.Quaternion inRotation, Transform inTransform) { EffectManagerHelper pooledEffect = GetPooledEffect(inPrefab, inPosition, inRotation, inTransform); pooledEffect.Reset(inActivate: true); pooledEffect.gameObject.SetActive(value: true); pooledEffect.ResetPostActivate(); return pooledEffect; } public static void ClearPool(GameObject inPrefab) { if (_EffectPrefabMap.ContainsKey(inPrefab)) { _EffectPrefabMap[inPrefab].Reset(); _EffectPrefabMap.Remove(inPrefab); } } public static void KillAllPools() { UnityEngine.Debug.LogWarning("EffectManager: Killing all pools"); foreach (EffectPool value in _EffectPrefabMap.Values) { value.Kill(); } _EffectPrefabMap.Clear(); _ShouldUsePooledEffectMap.Clear(); GC.Collect(); } public static void ClearAllPools(bool inForceAllClear = false) { UnityEngine.Debug.LogWarning("EffectManager: Clearing all pools"); foreach (EffectPool value in _EffectPrefabMap.Values) { value.Reset(inForceAllClear); } _EffectPrefabMap.Clear(); _ShouldUsePooledEffectMap.Clear(); } public static void DumpPools() { } [NetworkMessageHandler(msgType = 52, server = true)] private static void HandleEffectServer(NetworkMessage netMsg) { HandleEffectServerInternal(netMsg); } [NetworkMessageHandler(msgType = 52, client = true)] private static void HandleEffectClient(NetworkMessage netMsg) { HandleEffectClientInternal(netMsg); } public static void SpawnEffect(GameObject effectPrefab, EffectData effectData, bool transmit) { if (DisableAllEffectSpawning) { return; } EffectIndex effectIndex = EffectCatalog.FindEffectIndexFromPrefab(effectPrefab); if (effectIndex == EffectIndex.Invalid) { if ((bool)effectPrefab && !string.IsNullOrEmpty(effectPrefab.name)) { UnityEngine.Debug.LogError("Unable to SpawnEffect from prefab named '" + effectPrefab?.name + "'"); } else { UnityEngine.Debug.LogError($"Unable to SpawnEffect. Is null? {effectPrefab == null}. Name = '{effectPrefab?.name}'.\n{new StackTrace()}"); } } else { SpawnEffect(effectIndex, effectData, transmit); } } public static void SpawnEffect(EffectIndex effectIndex, EffectData effectData, bool transmit) { if (DisableAllEffectSpawning) { return; } if (transmit) { TransmitEffect(effectIndex, effectData); if (NetworkServer.active) { return; } } if (!NetworkClient.active) { return; } if (effectData.networkSoundEventIndex != NetworkSoundEventIndex.Invalid) { PointSoundManager.EmitSoundLocal(NetworkSoundEventCatalog.GetAkIdFromNetworkSoundEventIndex(effectData.networkSoundEventIndex), effectData.origin); } EffectDef effectDef = EffectCatalog.GetEffectDef(effectIndex); if (effectDef == null) { return; } string spawnSoundEventName = effectDef.spawnSoundEventName; if (!string.IsNullOrEmpty(spawnSoundEventName)) { PointSoundManager.EmitSoundLocal((AkEventIdArg)spawnSoundEventName, effectData.origin); } SurfaceDef surfaceDef = SurfaceDefCatalog.GetSurfaceDef(effectData.surfaceDefIndex); if ((object)surfaceDef != null) { string impactSoundString = surfaceDef.impactSoundString; if (!string.IsNullOrEmpty(impactSoundString)) { PointSoundManager.EmitSoundLocal((AkEventIdArg)impactSoundString, effectData.origin); } } if (!VFXBudget.CanAffordSpawn(effectDef.prefabVfxAttributes) || (effectDef.cullMethod != null && !effectDef.cullMethod(effectData))) { return; } EffectData effectData2 = effectData.Clone(); EffectManagerHelper effectManagerHelper = null; if (!ShouldUsePooledEffect(effectDef.prefab)) { EffectComponent component = UnityEngine.Object.Instantiate(effectDef.prefab, effectData2.origin, effectData2.rotation).GetComponent(); if ((bool)component) { component.effectData = effectData2.Clone(); } return; } effectManagerHelper = GetPooledEffect(effectDef.prefab, effectData2.origin, effectData2.rotation); EffectComponent component2 = effectManagerHelper.gameObject.GetComponent(); if ((bool)component2) { component2.effectData = effectData2.Clone(); effectManagerHelper.Reset(inActivate: true); effectManagerHelper.gameObject.SetActive(value: true); effectManagerHelper.ResetPostActivate(); } } private static void Update() { frameCount++; if (frameCount >= 5) { frameCount = 0; _ = _EffectPrefabMap.Count; _ = 5; UnloadOutdatedPools(); } } private static void UnloadOutdatedPools() { float num = float.PositiveInfinity; PrefabComponentPool prefabComponentPool = null; bool flag = _EffectPrefabMap.Count > 30; foreach (EffectPool value in _EffectPrefabMap.Values) { if (!value.DoNotCull && value.timestamp < num && (value.InUseCount() < 1 || flag)) { num = value.timestamp; prefabComponentPool = value; } } if (Time.realtimeSinceStartup - num > 45f) { prefabComponentPool.Kill(); _EffectPrefabMap.Remove(prefabComponentPool.PrefabObject); } } private static void TransmitEffect(EffectIndex effectIndex, EffectData effectData, NetworkConnection netOrigin = null) { outgoingEffectMessage.effectIndex = effectIndex; EffectData.Copy(effectData, outgoingEffectMessage.effectData); if (NetworkServer.active) { foreach (NetworkConnection connection in NetworkServer.connections) { if (connection != null && connection != netOrigin) { connection.SendByChannel(52, outgoingEffectMessage, qosChannel.intVal); } } return; } if (ClientScene.readyConnection != null) { ClientScene.readyConnection.SendByChannel(52, outgoingEffectMessage, qosChannel.intVal); } } private static void HandleEffectClientInternal(NetworkMessage netMsg) { netMsg.ReadMessage(incomingEffectMessage); SpawnEffect(incomingEffectMessage.effectIndex, incomingEffectMessage.effectData, transmit: false); } private static void HandleEffectServerInternal(NetworkMessage netMsg) { netMsg.ReadMessage(incomingEffectMessage); TransmitEffect(incomingEffectMessage.effectIndex, incomingEffectMessage.effectData, netMsg.conn); } public static void SimpleMuzzleFlash(GameObject effectPrefab, GameObject obj, string muzzleName, bool transmit) { if (!obj) { return; } ModelLocator component = obj.GetComponent(); if (!component || !component.modelTransform) { return; } ChildLocator component2 = component.modelTransform.GetComponent(); if ((bool)component2) { int childIndex = component2.FindChildIndex(muzzleName); Transform transform = component2.FindChild(childIndex); if ((bool)transform) { EffectData effectData = new EffectData { origin = transform.position }; effectData.SetChildLocatorTransformReference(obj, childIndex); SpawnEffect(effectPrefab, effectData, transmit); } } } public static void SimpleImpactEffect(GameObject effectPrefab, UnityEngine.Vector3 hitPos, UnityEngine.Vector3 normal, bool transmit) { SpawnEffect(effectPrefab, new EffectData { origin = hitPos, rotation = ((normal == UnityEngine.Vector3.zero) ? UnityEngine.Quaternion.identity : Util.QuaternionSafeLookRotation(normal)) }, transmit); } public static void SimpleImpactEffect(GameObject effectPrefab, UnityEngine.Vector3 hitPos, UnityEngine.Vector3 normal, UnityEngine.Color color, bool transmit) { SpawnEffect(effectPrefab, new EffectData { origin = hitPos, rotation = Util.QuaternionSafeLookRotation(normal), color = color }, transmit); } public static void SimpleEffect(GameObject effectPrefab, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, bool transmit) { SpawnEffect(effectPrefab, new EffectData { origin = position, rotation = rotation }, transmit); } public static void SimpleSoundEffect(NetworkSoundEventIndex soundEventIndex, UnityEngine.Vector3 position, bool transmit) { SpawnEffect(EffectIndex.Invalid, new EffectData { origin = position, networkSoundEventIndex = soundEventIndex }, transmit); } public static void ReturnToPoolOrDestroyInstance(this EffectManagerHelper effectManagerHelper, ref GameObject instance) { if (UsePools) { if (effectManagerHelper != null && effectManagerHelper.OwningPool != null) { effectManagerHelper.OwningPool.ReturnObject(effectManagerHelper); } else { UnityEngine.Object.Destroy(instance); } effectManagerHelper = null; } else { UnityEngine.Object.Destroy(instance); } } } public enum EliteIndex { None = -1 } public static class EliteCatalog { public static List eliteList = new List(); private static EliteDef[] eliteDefs; [Obsolete("Use IContentPackProvider instead.")] public static readonly CatalogModHelperProxy modHelper = new CatalogModHelperProxy("RoR2.EliteCatalog.modHelper", LegacyModContentPackProvider.instance.registrationContentPack.eliteDefs); [SystemInitializer(new Type[] { })] private static void Init() { SetEliteDefs(ContentManager.eliteDefs); } private static void SetEliteDefs(EliteDef[] newEliteDefs) { eliteDefs = ArrayUtils.Clone(newEliteDefs); for (EliteIndex eliteIndex = (EliteIndex)0; (int)eliteIndex < eliteDefs.Length; eliteIndex++) { RegisterElite(eliteIndex, eliteDefs[(int)eliteIndex]); } } private static void RegisterElite(EliteIndex eliteIndex, EliteDef eliteDef) { eliteDef.eliteIndex = eliteIndex; eliteList.Add(eliteIndex); eliteDefs[(int)eliteIndex] = eliteDef; } public static EliteDef GetEliteDef(EliteIndex eliteIndex) { return ArrayUtils.GetSafe(eliteDefs, (int)eliteIndex); } } public static class EngineConVars { private class SyncPhysicsConVar : BaseConVar { public static SyncPhysicsConVar instance = new SyncPhysicsConVar("sync_physics", ConVarFlags.None, "0", "Enable/disables Physics 'autosyncing' between moves."); private SyncPhysicsConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { } public override void SetString(string newValue) { Physics.autoSyncTransforms = BaseConVar.ParseBoolInvariant(newValue); } public override string GetString() { if (!Physics.autoSyncTransforms) { return "0"; } return "1"; } } private class AutoSimulatePhysicsConVar : BaseConVar { public static AutoSimulatePhysicsConVar instance = new AutoSimulatePhysicsConVar("auto_simulate_physics", ConVarFlags.None, "1", "Enable/disables Physics autosimulate."); private AutoSimulatePhysicsConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { } public override void SetString(string newValue) { Physics.autoSimulation = BaseConVar.ParseBoolInvariant(newValue); } public override string GetString() { if (!Physics.autoSimulation) { return "0"; } return "1"; } } private class TimeScaleConVar : BaseConVar { private static readonly TimeScaleConVar instance = new TimeScaleConVar("timescale", ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat | ConVarFlags.Engine, null, "The timescale of the game."); public TimeScaleConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { } public override void SetString(string newValue) { Time.timeScale = BaseConVar.ParseFloatInvariant(newValue); } public override string GetString() { return TextSerialization.ToStringInvariant(Time.timeScale); } } private class TimeStepConVar : BaseConVar { private static readonly TimeStepConVar instance = new TimeStepConVar("timestep", ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat | ConVarFlags.Engine, null, "The timestep of the game."); public TimeStepConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { } public override void SetString(string newValue) { Time.fixedDeltaTime = BaseConVar.ParseFloatInvariant(newValue); } public override string GetString() { return TextSerialization.ToStringInvariant(Time.fixedDeltaTime); } } } public enum EntityStateIndex { Invalid = -1 } public static class EntityStateCatalog { private static readonly Dictionary stateTypeToIndex = new Dictionary(1000); private static Type[] stateIndexToType = Array.Empty(); private static readonly Dictionary> instanceFieldInitializers = new Dictionary>(); private static string[] stateIndexToTypeName = Array.Empty(); [Obsolete("This is only for use in legacy editors only until they're fully phased out.")] public static string[] baseGameStateTypeNames = new string[0]; private static void SetStateInstanceInitializer([NotNull] Type stateType, [NotNull] Action initializer) { if (typeof(EntityState).IsAssignableFrom(stateType)) { instanceFieldInitializers[stateType] = initializer; } } public static void InitializeStateFields([NotNull] EntityState entityState) { if (instanceFieldInitializers.TryGetValue(entityState.GetType(), out var value)) { value(entityState); } } private static IEnumerator SetElements(Type[] newEntityStateTypes, EntityStateConfiguration[] newEntityStateConfigurations) { ArrayUtils.CloneTo(newEntityStateTypes, ref stateIndexToType); int _length = stateIndexToType.Length; string[] typeNames = new string[_length]; for (int i = 0; i < _length; i++) { typeNames[i] = stateIndexToType[i].AssemblyQualifiedName; } yield return null; Array.Sort(typeNames, stateIndexToType, StringComparer.Ordinal); yield return null; stateTypeToIndex.Clear(); for (int j = 0; j < _length; j++) { Type key = stateIndexToType[j]; stateTypeToIndex[key] = (EntityStateIndex)j; } yield return null; Array.Resize(ref stateIndexToTypeName, stateIndexToType.Length); for (int k = 0; k < stateIndexToType.Length; k++) { stateIndexToTypeName[k] = stateIndexToType[k].Name; } yield return null; instanceFieldInitializers.Clear(); int limitForLoop = 10; int loopIndex = 0; for (_length = 0; _length < newEntityStateConfigurations.Length; _length++) { ApplyEntityStateConfiguration(newEntityStateConfigurations[_length]); if (loopIndex++ >= limitForLoop) { loopIndex = 0; yield return null; } } } private static void ApplyEntityStateConfiguration(EntityStateConfiguration entityStateConfiguration) { Type type = (Type)entityStateConfiguration.targetType; if (type == null) { UnityEngine.Debug.LogFormat("ApplyEntityStateConfiguration({0}) failed: state type is null.", entityStateConfiguration); return; } if (!stateTypeToIndex.ContainsKey(type)) { UnityEngine.Debug.LogFormat("ApplyEntityStateConfiguration({0}) failed: state type {1} is not registered.", entityStateConfiguration, type.FullName); return; } entityStateConfiguration.ApplyStatic(); Action action = entityStateConfiguration.BuildInstanceInitializer(); if (action == null) { instanceFieldInitializers.Remove(type); } else { instanceFieldInitializers[type] = action; } } private static void OnStateConfigurationUpdatedByEditor(EntityStateConfiguration entityStateConfiguration) { ApplyEntityStateConfiguration(entityStateConfiguration); } public static IEnumerator Init() { EntityStateConfiguration.onEditorUpdatedConfigurationGlobal += OnStateConfigurationUpdatedByEditor; yield return SetElements(ContentManager.entityStateTypes, ContentManager.entityStateConfigurations); } public static EntityStateIndex GetStateIndex(Type entityStateType) { if (stateTypeToIndex.TryGetValue(entityStateType, out var value)) { return value; } return EntityStateIndex.Invalid; } public static Type GetStateType(EntityStateIndex entityStateIndex) { Type[] array = stateIndexToType; Type defaultValue = null; return ArrayUtils.GetSafe(array, (int)entityStateIndex, in defaultValue); } [CanBeNull] public static string GetStateTypeName(Type entityStateType) { return GetStateTypeName(GetStateIndex(entityStateType)); } [CanBeNull] public static string GetStateTypeName(EntityStateIndex entityStateIndex) { return ArrayUtils.GetSafe(stateIndexToTypeName, (int)entityStateIndex); } public static EntityState InstantiateState(EntityStateIndex entityStateIndex) { Type stateType = GetStateType(entityStateIndex); if (stateType != null) { return Activator.CreateInstance(stateType) as EntityState; } UnityEngine.Debug.LogFormat("Bad stateTypeIndex {0}", entityStateIndex); return null; } public static EntityState InstantiateState(Type stateType) { if (stateType != null && stateType.IsSubclassOf(typeof(EntityState))) { return Activator.CreateInstance(stateType) as EntityState; } UnityEngine.Debug.LogFormat("Bad stateType {0}", (stateType == null) ? "null" : stateType.FullName); return null; } public static EntityState InstantiateState(ref SerializableEntityStateType serializableStateType) { return InstantiateState(serializableStateType.stateType); } } [RequireComponent(typeof(EntityStateMachine))] [RequireComponent(typeof(CharacterBody))] public class ChildMonsterController : MonoBehaviour { public CharacterBody characterBody; public EntityStateMachine stateMachine; public GameObject tpEffectPrefab; [Tooltip("If Child receives this much cumulative damage, they will start trying to teleport.")] [FormerlySerializedAs("frolicThreshold")] public float cumulativeDamageThresholdBeforeFrolic = 10f; [Tooltip("Does not apply to 'falling off cliffs!' teleporting.")] public float teleportCooldown = 20f; [Tooltip("Which skill slot is 'Frolic' (teleport) categorized as.")] public SkillSlot frolicSkillSlot; private float inAirTimer; public float amountToFallBeforeTp = 1.5f; private float cachedYPosition; private SkillLocator skillLocator; private float lastTeleportTimestamp = -1f; private float healthAtLastTeleport; private BaseState requestedTeleportState; private bool hasAuthority; private void Start() { skillLocator = characterBody.skillLocator; cachedYPosition = characterBody.corePosition.y; hasAuthority = Util.HasEffectiveAuthority(characterBody.networkIdentity); RegisterTeleport(addInvincibility: false); lastTeleportTimestamp = -1f; } private void Update() { if (characterBody == null || !characterBody.healthComponent.alive) { return; } TryRefreshTeleportAbility(); if (hasAuthority) { HandleFalling(); HandleCumulativeDamage(); if (requestedTeleportState != null) { SetNextStateToTeleport(); } } } private void SetNextStateToTeleport() { if (stateMachine.CanInterruptState(requestedTeleportState.GetMinimumInterruptPriority())) { stateMachine.SetNextState(requestedTeleportState); requestedTeleportState = null; } } private void HandleFalling() { if (!characterBody.characterMotor.isGrounded && characterBody.corePosition.y < cachedYPosition) { inAirTimer += Time.deltaTime; } else { inAirTimer = 0f; } cachedYPosition = characterBody.corePosition.y; if (inAirTimer > amountToFallBeforeTp) { inAirTimer = 0f; requestedTeleportState = new FrolicAway(); } } private void TryRefreshTeleportAbility() { if (lastTeleportTimestamp != -1f && CheckTeleportAvailable()) { lastTeleportTimestamp = -1f; } } private void HandleCumulativeDamage() { if (requestedTeleportState == null && CheckTeleportAvailable() && healthAtLastTeleport - characterBody.healthComponent.health >= cumulativeDamageThresholdBeforeFrolic) { requestedTeleportState = new Frolic(); } } public bool CheckTeleportAvailable() { if (lastTeleportTimestamp != -1f) { return Time.time - lastTeleportTimestamp >= teleportCooldown; } return true; } public void RegisterTeleport(bool addInvincibility = true) { lastTeleportTimestamp = Time.time; healthAtLastTeleport = characterBody.healthComponent.health; requestedTeleportState = null; skillLocator.GetSkill(frolicSkillSlot)?.DeductStock(100); if (addInvincibility && NetworkServer.active && !characterBody.HasBuff(RoR2Content.Buffs.HiddenInvincibility)) { characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 1.5f); } } } [RequireComponent(typeof(CharacterBody))] public class FalseSonController : NetworkBehaviour { public CharacterBody characterBody; public SkillDef falseSonBodyTheTamperedHeart; public SkillDef tempAltDefName; public GenericSkill passiveSkillSlot; [SerializeField] private float tamperedHeartRegen; [SerializeField] private float tamperedHeartMoveSpeed; [SerializeField] private float tamperedHeartArmor; [SerializeField] private float tamperedHeartAttackSpeed; private bool tamperedHeart; private SkillLocator skillLocator; private int maxSecondaryStock; private int oldMaxSecondaryStock; private int secondaryStock; private int oldSecondaryStock; private int extraShardFromHealth; private int oldExtraShardFromHealth; private float maxHealth; private float oldMaxHealth; private int bonusSecondarySkillCountFromItems; private int oldBonusSecondarySkillCountFromItems; private bool alreadyResetMaxSecondaryStockCount; private int lunarSpikeSkillIndex; private int laserBurstSkillIndex; private GenericSkill lunarSpikeSkill; private GenericSkill laserSpecialSkill; private bool cachedEffectiveAuthority; private NetworkIdentity networkIdentity; private float clubSwingAltSecondaryTimestamp; private static int kCmdCmdUpdateAmmoAmounts; private bool secondarySkillIsFalseSonDefault => lunarSpikeSkill.baseSkill.skillIndex == lunarSpikeSkillIndex; private bool sendAmmoUpdatesToServer { get { if (cachedEffectiveAuthority) { return !NetworkServer.active; } return false; } } private void OnEnable() { skillLocator = GetComponent(); networkIdentity = skillLocator.GetComponent(); lunarSpikeSkill = skillLocator.GetSkill(SkillSlot.Secondary); laserSpecialSkill = skillLocator.GetSkill(SkillSlot.Special); CacheEffectiveAuthority(); oldMaxSecondaryStock = GetMaxSecondaryStock(); oldSecondaryStock = maxSecondaryStock; lunarSpikeSkillIndex = SkillCatalog.FindSkillIndexByName("LunarSpikes"); laserBurstSkillIndex = SkillCatalog.FindSkillIndexByName("LaserBurst"); } private void Update() { bool flag = false; CacheEffectiveAuthority(); if (passiveSkillSlot.skillDef == falseSonBodyTheTamperedHeart) { if (!secondarySkillIsFalseSonDefault && !alreadyResetMaxSecondaryStockCount) { characterBody.extraSecondaryFromSkill = 0; oldExtraShardFromHealth = 0; UpdateStats(); alreadyResetMaxSecondaryStockCount = true; } maxHealth = characterBody.maxHealth; maxSecondaryStock = GetMaxSecondaryStock(); if ((maxHealth != oldMaxHealth && characterBody.maxBonusHealth > 0f) || oldMaxSecondaryStock != maxSecondaryStock || (!secondarySkillIsFalseSonDefault ^ alreadyResetMaxSecondaryStockCount)) { if (secondarySkillIsFalseSonDefault) { IncreaseStockCount(); flag = true; alreadyResetMaxSecondaryStockCount = false; } oldMaxHealth = maxHealth; oldMaxSecondaryStock = maxSecondaryStock; } secondaryStock = GetSecondaryStock(); if (secondaryStock != oldSecondaryStock || flag) { CalcTamperedHeartStats(); flag = true; } } if (sendAmmoUpdatesToServer && flag) { CallCmdUpdateAmmoAmounts(secondaryStock, maxSecondaryStock); } } [Command] public void CmdUpdateAmmoAmounts(int _secondaryStock, int _maxSecondaryStock) { maxSecondaryStock = _maxSecondaryStock; secondaryStock = _secondaryStock; CalcTamperedHeartStats(); } public int GetTotalSpikeCount() { int num = 0; float num2 = 15f; float num3 = 5f; float num4 = characterBody.maxBonusHealth - (characterBody.baseMaxHealth + characterBody.levelMaxHealth * (float)((int)characterBody.level - 1)); int num5 = 10; while (num4 > num2) { num4 -= num2; if (num4 < 0f) { break; } num++; if (num + 4 > num5) { num5 += 10; num3 = 5f + 5f * (float)(num / 10); } num2 = 15f + num3 * (float)num; } return num; } private int GetMaxSecondaryStock() { if (cachedEffectiveAuthority) { return lunarSpikeSkill.GetBaseMaxStock(); } return maxSecondaryStock; } private int GetSecondaryStock() { if (cachedEffectiveAuthority) { return lunarSpikeSkill.GetBaseStock(); } return secondaryStock; } private void UpdateStats() { characterBody.RecalculateStats(); } private void CalcTamperedHeartStats() { int num = maxSecondaryStock - secondaryStock; if (num < 0) { num = 0; } float heartRegen = tamperedHeartRegen * (float)num; float heartMSpeed = tamperedHeartMoveSpeed * (float)num; float attackSpeed = tamperedHeartAttackSpeed * (float)secondaryStock; float armor = tamperedHeartArmor * (float)secondaryStock; float heartDamage = 0f; characterBody.ApplyTamperedHeartPassive(heartRegen, heartMSpeed, heartDamage, armor, attackSpeed); UpdateStats(); oldSecondaryStock = secondaryStock; } private float CalculateHyperbolicStatBonuses(float statCalc, float spikesToCalculate) { float num = 0f; if (spikesToCalculate > 0f) { if (spikesToCalculate <= 4f) { num += spikesToCalculate * statCalc; } else if (spikesToCalculate > 4f) { num += statCalc * 4f + (1f - 1f / (statCalc * (spikesToCalculate - 4f) + 1f)); } } return num; } private float RegenAndMoveSpeedCalc(float statCalc) { if (secondaryStock < maxSecondaryStock) { return statCalc * (float)(maxSecondaryStock - secondaryStock); } return 0f; } private void IncreaseStockCount() { extraShardFromHealth = GetTotalSpikeCount(); if (extraShardFromHealth != oldExtraShardFromHealth) { if (extraShardFromHealth < 0) { extraShardFromHealth = 0; } characterBody.extraSecondaryFromSkill = extraShardFromHealth; int num = extraShardFromHealth / 4; if (laserSpecialSkill.skillDef.skillIndex == laserBurstSkillIndex && num > 0) { characterBody.extraSpecialFromSkill = num; } UpdateStats(); oldExtraShardFromHealth = extraShardFromHealth; } maxSecondaryStock = GetMaxSecondaryStock(); } public float GetClubSwingAltSecondaryTimestamp() { return clubSwingAltSecondaryTimestamp; } public void SetClubSwingAltSecondaryTimestamp() { clubSwingAltSecondaryTimestamp = Time.time; } private void CacheEffectiveAuthority() { cachedEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity); } private void UNetVersion() { } protected static void InvokeCmdCmdUpdateAmmoAmounts(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdUpdateAmmoAmounts called on client."); } else { ((FalseSonController)obj).CmdUpdateAmmoAmounts((int)reader.ReadPackedUInt32(), (int)reader.ReadPackedUInt32()); } } public void CallCmdUpdateAmmoAmounts(int _secondaryStock, int _maxSecondaryStock) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdUpdateAmmoAmounts called on server."); return; } if (base.isServer) { CmdUpdateAmmoAmounts(_secondaryStock, _maxSecondaryStock); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdUpdateAmmoAmounts); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32((uint)_secondaryStock); networkWriter.WritePackedUInt32((uint)_maxSecondaryStock); SendCommandInternal(networkWriter, 0, "CmdUpdateAmmoAmounts"); } static FalseSonController() { kCmdCmdUpdateAmmoAmounts = -634793383; NetworkBehaviour.RegisterCommandDelegate(typeof(FalseSonController), kCmdCmdUpdateAmmoAmounts, InvokeCmdCmdUpdateAmmoAmounts); NetworkCRC.RegisterBehaviour("FalseSonController", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } [RequireComponent(typeof(CharacterBody))] public class FalseSonBossController : MonoBehaviour { public CharacterBody characterBody; public Animator characterAnimator; public ModelLocator modelLocator; public GameObject lunarSpikePrefab; public ChildLocator childLocator; public HealthComponent healthComponent; public GameObject masterFSPrefab; public Transform lunarSpike; public Transform lunarSpikeLocation; private float maxHealth; private float currentHealth; private bool health75; public bool health50; public bool lunarSpikeActive; private float testTimeGate = 2f; private float spikeTimer; public int swingCounter; public bool firedLunarSpike; private void OnEnable() { lunarSpikeLocation = childLocator.FindChild("LunarSpike"); } private void Start() { maxHealth = healthComponent.health; } private void FixedUpdate() { if (healthComponent.health <= maxHealth * 0.5f && !health50) { PlayAnimation("FullBody, Override", "OverloadErruption", "OverloadErruption.playbackRate", 6f); spikeTimer += Time.deltaTime; if (spikeTimer > 2.8f) { SpawnLunarSpike(); } health50 = true; } if (!lunarSpikeActive) { return; } if (characterBody.GetBuffCount(RoR2Content.Buffs.HiddenInvincibility) < 1) { characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility); } if (!lunarSpike) { characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility); characterBody.RemoveBuff(DLC2Content.Buffs.CorruptionFesters); if (health50) { characterBody.AddTimedBuff(DLC2Content.Buffs.WeakenedBeating, 60f); } lunarSpikeActive = false; } } protected void PlayAnimation(string layerName, string animationStateName, string playbackRateParam, float duration) { if (duration <= 0f) { UnityEngine.Debug.LogWarningFormat("EntityState.PlayAnimation: Zero duration is not allowed. type={0}", GetType().Name); return; } Animator modelAnimator = GetModelAnimator(); if ((bool)modelAnimator) { PlayAnimationOnAnimator(modelAnimator, layerName, animationStateName, playbackRateParam, duration); } } protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, string animationStateName, string playbackRateParam, float duration) { modelAnimator.speed = 1f; modelAnimator.Update(0f); int layerIndex = modelAnimator.GetLayerIndex(layerName); if (layerIndex >= 0) { modelAnimator.SetFloat(playbackRateParam, 1f); modelAnimator.PlayInFixedTime(animationStateName, layerIndex, 0f); modelAnimator.Update(0f); float length = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length; modelAnimator.SetFloat(playbackRateParam, length / duration); } } protected Animator GetModelAnimator() { if ((bool)modelLocator && (bool)modelLocator.modelTransform) { return modelLocator.modelTransform.GetComponent(); } return null; } public void SpawnLunarSpike() { MasterSpawnSlotController component = GetComponent(); if (NetworkServer.active && (bool)component) { component.SpawnRandomOpen(1, Run.instance.stageRng, base.gameObject); } lunarSpike = lunarSpikeLocation.transform.GetChild(0); lunarSpike.transform.rotation = lunarSpikeLocation.rotation; lunarSpike.GetComponent().baseMaxHealth = maxHealth * 0.2f; DamageInfo damageInfo = new DamageInfo { damage = healthComponent.health * 0.1f }; healthComponent.TakeDamage(damageInfo); characterBody.AddBuff(DLC2Content.Buffs.CorruptionFesters); lunarSpikeActive = true; firedLunarSpike = true; } } public class FissureSlamCracksController : MonoBehaviour { private class Meteor { public UnityEngine.Vector3 impactPosition; public float startTime; public bool didTravelEffect; public bool valid = true; } private class MeteorWave { private readonly CharacterBody[] targets; private int currentStep; private float hitChance = 0.4f; private readonly UnityEngine.Vector3 center; public float timer; private NodeGraphSpider nodeGraphSpider; public MeteorWave(CharacterBody[] targets, UnityEngine.Vector3 center) { this.targets = new CharacterBody[targets.Length]; targets.CopyTo(this.targets, 0); Util.ShuffleArray(targets); this.center = center; nodeGraphSpider = new NodeGraphSpider(SceneInfo.instance.groundNodes, HullMask.Human); nodeGraphSpider.AddNodeForNextStep(SceneInfo.instance.groundNodes.FindClosestNode(center, HullClassification.Human)); int i = 0; for (int num = 10; i < num; i++) { if (!nodeGraphSpider.PerformStep()) { break; } } } public Meteor GetNextMeteor() { if (currentStep >= targets.Length) { return null; } CharacterBody characterBody = targets[currentStep]; Meteor meteor = new Meteor(); if ((bool)characterBody && UnityEngine.Random.value < hitChance) { meteor.impactPosition = characterBody.corePosition; UnityEngine.Vector3 origin = meteor.impactPosition + UnityEngine.Vector3.up * 6f; UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere; onUnitSphere.y = -1f; if (Physics.Raycast(origin, onUnitSphere, out var hitInfo, 12f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { meteor.impactPosition = hitInfo.point; } else if (Physics.Raycast(meteor.impactPosition, UnityEngine.Vector3.down, out hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { meteor.impactPosition = hitInfo.point; } } else if (nodeGraphSpider.collectedSteps.Count != 0) { int index = UnityEngine.Random.Range(0, nodeGraphSpider.collectedSteps.Count); SceneInfo.instance.groundNodes.GetNodePosition(nodeGraphSpider.collectedSteps[index].node, out meteor.impactPosition); } else { meteor.valid = false; } meteor.startTime = Run.instance.time; currentStep++; return meteor; } } public int waveCount; public float waveMinInterval; public float waveMaxInterval; public GameObject warningEffectPrefab; public GameObject travelEffectPrefab; public float travelEffectDuration; public GameObject impactEffectPrefab; public float impactDelay; public float blastDamageCoefficient; public float blastRadius; public float blastForce; [NonSerialized] public GameObject owner; [NonSerialized] public float ownerDamage; [NonSerialized] public bool isCrit; public UnityEvent onDestroyEvents; private List meteorList; private List waveList; private int wavesPerformed; private float waveTimer; private void Start() { if (NetworkServer.active) { meteorList = new List(); waveList = new List(); } } private void FixedUpdate() { if (!NetworkServer.active) { return; } waveTimer -= Time.fixedDeltaTime; if (waveTimer <= 0f && wavesPerformed < waveCount) { wavesPerformed++; waveTimer = UnityEngine.Random.Range(waveMinInterval, waveMaxInterval); MeteorWave item = new MeteorWave(CharacterBody.readOnlyInstancesList.ToArray(), base.transform.position); waveList.Add(item); } for (int num = waveList.Count - 1; num >= 0; num--) { MeteorWave meteorWave = waveList[num]; meteorWave.timer -= Time.fixedDeltaTime; if (meteorWave.timer <= 0f) { meteorWave.timer = UnityEngine.Random.Range(0.05f, 0.075f); Meteor nextMeteor = meteorWave.GetNextMeteor(); if (nextMeteor == null) { waveList.RemoveAt(num); } else if (nextMeteor.valid) { meteorList.Add(nextMeteor); EffectManager.SpawnEffect(warningEffectPrefab, new EffectData { origin = nextMeteor.impactPosition, scale = blastRadius }, transmit: true); } } } float num2 = Run.instance.time - impactDelay; float num3 = num2 - travelEffectDuration; for (int num4 = meteorList.Count - 1; num4 >= 0; num4--) { Meteor meteor = meteorList[num4]; if (meteor.startTime < num3 && !meteor.didTravelEffect) { DoMeteorEffect(meteor); } if (meteor.startTime < num2) { meteorList.RemoveAt(num4); DetonateMeteor(meteor); } } if (wavesPerformed == waveCount && meteorList.Count == 0) { UnityEngine.Object.Destroy(base.gameObject); } } private void OnDestroy() { onDestroyEvents.Invoke(); } private void DoMeteorEffect(Meteor meteor) { meteor.didTravelEffect = true; if ((bool)travelEffectPrefab) { EffectManager.SpawnEffect(travelEffectPrefab, new EffectData { origin = meteor.impactPosition, scale = blastRadius }, transmit: true); } } private void DetonateMeteor(Meteor meteor) { EffectData effectData = new EffectData { origin = meteor.impactPosition, scale = blastRadius }; EffectManager.SpawnEffect(impactEffectPrefab, effectData, transmit: true); BlastAttack blastAttack = new BlastAttack(); blastAttack.inflictor = base.gameObject; blastAttack.baseDamage = blastDamageCoefficient * ownerDamage; blastAttack.baseForce = blastForce; blastAttack.attackerFiltering = AttackerFiltering.AlwaysHit; blastAttack.crit = isCrit; blastAttack.falloffModel = BlastAttack.FalloffModel.Linear; blastAttack.attacker = owner; blastAttack.bonusForce = UnityEngine.Vector3.zero; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.position = meteor.impactPosition; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = 1f; blastAttack.radius = blastRadius; blastAttack.Fire(); } } public class MeridianReportBossFinalPosition : MonoBehaviour { private void Start() { MeridianEventTriggerInteraction.bossTransform = base.transform; } } [RequireComponent(typeof(CharacterBody))] public class SpawnerPodsController : MonoBehaviour { [FormerlySerializedAs("maxSpawnTimer")] public float incubationDuration; public GameObject spawnEffect; public GameObject hatchEffect; [FormerlySerializedAs("dissolveTime")] public float dissolveDuration; public string podSpawnSound = ""; public string podHatchSound = ""; private CharacterMaster ownerMaster; private CharacterBody characterBody; private void Awake() { characterBody = GetComponent(); } private void Start() { ownerMaster = characterBody.master.minionOwnership.ownerMaster; if (NetworkServer.active) { Deployable component = GetComponent(); if ((bool)ownerMaster) { ownerMaster.AddDeployable(component, DeployableSlot.ParentPodAlly); } } } public void UndeployKill() { characterBody.healthComponent.Suicide(); } public void Dissolve() { PrintController printController = characterBody.modelLocator.modelTransform.gameObject.AddComponent(); printController.printTime = dissolveDuration; printController.enabled = true; printController.startingPrintHeight = 99999f; printController.maxPrintHeight = 99999f; printController.startingPrintBias = 0.95f; printController.maxPrintBias = 1.95f; printController.animateFlowmapPower = true; printController.startingFlowmapPower = 1.14f; printController.maxFlowmapPower = 30f; printController.disableWhenFinished = false; printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); } } public class GeodeSecretMissionController : MonoBehaviour { public int numberOfGeodesNecessary = 1; public List geodeMissionObjects = new List(); public GameObject rewardSpawnLocation; public EntityStateMachine entityStateMachine; public GameObject rewardPrefab; public bool increaseRewardPerPlayer; public int numberOfRewardsSpawned = 1; public int numberOfRewardOptions = 3; public BasicPickupDropTable rewardDropTable; [Tooltip("Use this tier to get a pickup index for the reward. The droplet's visuals will correspond to this.")] public ItemTier rewardDisplayTier; [HideInInspector] public int geodeInteractionsTracker; public OnCollisionEventController onCollisionEventController; public void AdvanceGeodeSecretMission() { geodeInteractionsTracker++; CheckIfRewardShouldBeGranted(); } public void CheckIfRewardShouldBeGranted() { if (numberOfGeodesNecessary <= geodeInteractionsTracker) { onCollisionEventController.SetAvailable(setActive: true); } } } public class VoidRaidEncounterController : NetworkBehaviour { public GameObject VoidRaidBossPrefab; public Transform VoidRaidBossSpawnPosition; private void Start() { GameObject obj = UnityEngine.Object.Instantiate(VoidRaidBossPrefab, VoidRaidBossSpawnPosition.position, UnityEngine.Quaternion.identity); obj.GetComponent().teamIndex = TeamIndex.Monster; NetworkServer.Spawn(obj); obj.GetComponent().SpawnBodyHere(); } private void Update() { } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } [RequireComponent(typeof(CharacterBody))] public class SeekerController : NetworkBehaviour, IOnKilledServerReceiver { private byte currentChakraGate; public bool doesExitVehicle; [SerializeField] public GameObject healingExplosionPrefab; [SerializeField] public GameObject scopeOverlayPrefab; [SerializeField] public string overlayChild; private OverlayController overlayController; private List fillUiList = new List(); private ChildLocator overlayInstanceChildLocator; public Color32 chakraDefaultColor = new Color32(0, 0, 0, 128); public Color32 chakraGrantedColor = new Color32(byte.MaxValue, 233, 124, 200); public Color32 chakraFinishedColor = new Color32(0, byte.MaxValue, 0, 200); public Color32 chakraAfterReviveColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 125); public Color32 chakraAfterReviveCompleteColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 200); public Color32 chakraSplashDefaultColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 125); public Color32 chakraSplashGrantedColor = new Color32(116, 226, 203, 200); public Color32 chakraSplashBurnedColor = new Color32(0, 0, 0, 0); public Color32 chakraBurnedColor = new Color32(byte.MaxValue, 0, 0, 200); public string[] chakraOrder = new string[7] { "Pedal1", "Pedal7", "Pedal2", "Pedal6", "Pedal3", "Pedal5", "Pedal4" }; public string finalActivation = "Glow"; [Tooltip("If a new respawn point is needed from a dead player, how far from the Seeker can it be.")] public float newRespawnPointMaxDistanceFromSeeker = 10f; [Tooltip("In case we need a new respawn point, we may only get one. So we randomize positions around that point for safety. Not too high: they might spawn through a wall.")] public UnityEngine.Vector3 randomDistanceForPlayerRespawn = new UnityEngine.Vector3(2f, 1f, 2f); private SeekerSoulSpiralManager soulSpiralManager; private CharacterBody characterBody; [NonSerialized] public sbyte[] meditationStepAndSequence = new sbyte[6]; [NonSerialized] public bool meditationUIDirty; private List possibleNodesToTarget = new List(); private static int kCmdCmdUnlockGateEffects; private static int kCmdCmdUpdateMeditationInput; private static int kRpcRpcSetMeditation; private static int kRpcRpcSetPedalsValue; private static int kRpcRpcSpiralCommand; private static int kCmdCmdTriggerHealPulse; private static int kCmdCmdSpiralCommand; public sbyte meditationInputStep { get { return meditationStepAndSequence[0]; } set { meditationUIDirty = true; meditationStepAndSequence[0] = value; CallCmdUpdateMeditationInput(meditationStepAndSequence); } } public sbyte GetNextMeditationStep() { int num = meditationStepAndSequence[0] + 1; if (0 <= num && num >= meditationStepAndSequence.Length) { return -1; } return meditationStepAndSequence[num]; } private void OnEnable() { overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams { prefab = scopeOverlayPrefab, childLocatorEntry = overlayChild }); overlayController.onInstanceAdded += OnOverlayInstanceAdded; overlayController.onInstanceRemove += OnOverlayInstanceRemoved; if (soulSpiralManager == null) { soulSpiralManager = new SeekerSoulSpiralManager(this); } characterBody = GetComponent(); } private bool IsPositionWithinBounds(UnityEngine.Vector3 position) { List instancesList = InstanceTracker.GetInstancesList(); bool flag = false; int num = 0; foreach (MapZone item in instancesList) { if (item.gameObject.activeSelf && item.zoneType == MapZone.ZoneType.OutOfBounds && item.triggerType == MapZone.TriggerType.TriggerExit) { num++; flag |= item.IsPointInsideMapZone(position); } } if (num < 1) { return true; } return flag; } private UnityEngine.Vector3 FindNewSpawnPosition(UnityEngine.Vector3 spawnPosition) { UnityEngine.Vector3 footPosition = characterBody.footPosition; NodeGraph groundNodes = SceneInfo.instance.groundNodes; if (possibleNodesToTarget.Count < 1) { newRespawnPointMaxDistanceFromSeeker = Mathf.Max(newRespawnPointMaxDistanceFromSeeker, 1f); groundNodes.FindNodesInRange(footPosition, 1f, newRespawnPointMaxDistanceFromSeeker, HullMask.Human, possibleNodesToTarget); } if (possibleNodesToTarget.Count < 1) { return spawnPosition; } groundNodes.GetNodePosition(possibleNodesToTarget[^1], out var position); possibleNodesToTarget.RemoveAt(possibleNodesToTarget.Count - 1); return position; } [Command] private void CmdUnlockGateEffects(byte chakraGate) { currentChakraGate = chakraGate; CharacterBody characterBody = this.characterBody; if (chakraGate < 7) { characterBody.AddBuff(DLC2Content.Buffs.ChakraBuff.buffIndex); } else if (chakraGate == 7 && characterBody.master.getSeekerUsedRevive() == CharacterMaster.SEEKER_REVIVE_STATUS.UNUSED) { foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (instance == null) { continue; } CharacterMaster master = instance.master; if (instance.isConnected && master.IsDeadAndOutOfLivesServer()) { UnityEngine.Vector3 vector = master.deathFootPosition; if (!IsPositionWithinBounds(vector)) { vector = FindNewSpawnPosition(vector); vector.y += UnityEngine.Random.Range(0.5f, Mathf.Abs(randomDistanceForPlayerRespawn.y)); vector.x += UnityEngine.Random.Range(0f - randomDistanceForPlayerRespawn.x, randomDistanceForPlayerRespawn.x); vector.z += UnityEngine.Random.Range(0f - randomDistanceForPlayerRespawn.z, randomDistanceForPlayerRespawn.z); } master.Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true); CharacterBody body = master.GetBody(); if ((bool)body) { body.AddTimedBuff(RoR2Content.Buffs.Immune, 3f); EntityStateMachine[] components = body.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/TeleporterHealNovaPulse"); if ((bool)gameObject) { EffectManager.SpawnEffect(gameObject, new EffectData { origin = vector, rotation = body.transform.rotation }, transmit: true); } } } else if ((object)master == null || master.GetBody()?.HasBuff(DLC2Content.Buffs.RevitalizeBuff.buffIndex) != true) { master?.GetBody()?.AddBuff(DLC2Content.Buffs.RevitalizeBuff.buffIndex); } } GetComponent().master.CallRpcSetSeekerRevive(CharacterMaster.SEEKER_REVIVE_STATUS.USED); } CallRpcSetPedalsValue(chakraGate); } public void RandomizeMeditationInputs() { meditationStepAndSequence[0] = 0; for (int i = 1; i <= 5; i++) { meditationStepAndSequence[i] = (sbyte)UnityEngine.Random.Range(0, 4); } CallCmdUpdateMeditationInput(meditationStepAndSequence); } [Command] private void CmdUpdateMeditationInput(sbyte[] sequence) { meditationStepAndSequence = sequence; meditationUIDirty = true; CallRpcSetMeditation(sequence); } [ClientRpc] private void RpcSetMeditation(sbyte[] sequence) { meditationStepAndSequence = sequence; meditationUIDirty = true; } public void IncrementChakraGate() { MonoBehaviour.print("triggered unlock gate"); currentChakraGate++; CallCmdUnlockGateEffects(currentChakraGate); } [ClientRpc] public void RpcSetPedalsValue(byte value) { if (base.hasAuthority) { currentChakraGate = value; UpdatePetalsUI(); } } public void UpdatePetalsUI() { CharacterMaster.SEEKER_REVIVE_STATUS seekerUsedRevive = GetComponent().master.getSeekerUsedRevive(); UnityEngine.UI.Image component = overlayInstanceChildLocator.FindChild(finalActivation).GetComponent(); switch (seekerUsedRevive) { case CharacterMaster.SEEKER_REVIVE_STATUS.UNUSED: component.color = chakraSplashDefaultColor; setColors(chakraGrantedColor, chakraDefaultColor); break; case CharacterMaster.SEEKER_REVIVE_STATUS.USED: component.color = chakraSplashGrantedColor; setColors(chakraFinishedColor, chakraDefaultColor); break; case CharacterMaster.SEEKER_REVIVE_STATUS.BURNED: component.color = chakraSplashBurnedColor; if (currentChakraGate >= 7) { setColors(chakraAfterReviveCompleteColor, chakraDefaultColor); break; } currentChakraGate = (byte)((currentChakraGate < 1) ? 1 : currentChakraGate); setColors(chakraAfterReviveColor, chakraDefaultColor); break; } void setColors(Color32 active, Color32 inactive) { for (int i = 0; i < 7; i++) { if (i < currentChakraGate) { overlayInstanceChildLocator.FindChild(chakraOrder[i]).GetComponent().color = active; } else { overlayInstanceChildLocator.FindChild(chakraOrder[i]).GetComponent().color = inactive; } } } } private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance) { fillUiList.Add(instance.GetComponent()); overlayInstanceChildLocator = instance.GetComponent(); UpdatePetalsUI(); } private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance) { fillUiList.Remove(instance.GetComponent()); } public void FireSoulSpiral(FireProjectileInfo projectileInfo) { soulSpiralManager.FireSoulSpiral(projectileInfo); } public void SpiralSendCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg) { if (NetworkServer.active) { CallRpcSpiralCommand(msg); } else { CallCmdSpiralCommand(msg); } } [ClientRpc] public void RpcSpiralCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg) { if (!soulSpiralManager.hasAuthority && !NetworkServer.active) { soulSpiralManager.ReceiveSpiralCommand(msg); } } [Command] internal void CmdTriggerHealPulse(float value, UnityEngine.Vector3 corePosition, float blastRadius) { HealingPulse healingPulse = new HealingPulse(); healingPulse.healAmount = value; healingPulse.origin = corePosition; healingPulse.radius = blastRadius; healingPulse.effectPrefab = healingExplosionPrefab; healingPulse.teamIndex = TeamIndex.Player; healingPulse.overShield = 0f; healingPulse.Fire(); } [Command] public void CmdSpiralCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg) { if (!soulSpiralManager.hasAuthority) { soulSpiralManager.ReceiveSpiralCommand(msg); } CallRpcSpiralCommand(msg); } private void FixedUpdate() { if (soulSpiralManager.runFixedUpdate) { soulSpiralManager.MyFixedUpdate(); } } private void OnDestroy() { soulSpiralManager.ShutdownAndCleanupSpirals(); } public void OnKilledServer(DamageReport damageReport) { if (NetworkServer.active) { soulSpiralManager.ShutdownAndCleanupSpirals(); } } private void UNetVersion() { } protected static void InvokeCmdCmdUnlockGateEffects(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdUnlockGateEffects called on client."); } else { ((SeekerController)obj).CmdUnlockGateEffects((byte)reader.ReadPackedUInt32()); } } protected static void InvokeCmdCmdUpdateMeditationInput(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdUpdateMeditationInput called on client."); } else { ((SeekerController)obj).CmdUpdateMeditationInput(GeneratedNetworkCode._ReadArraySByte_None(reader)); } } protected static void InvokeCmdCmdTriggerHealPulse(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdTriggerHealPulse called on client."); } else { ((SeekerController)obj).CmdTriggerHealPulse(reader.ReadSingle(), reader.ReadVector3(), reader.ReadSingle()); } } protected static void InvokeCmdCmdSpiralCommand(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSpiralCommand called on client."); } else { ((SeekerController)obj).CmdSpiralCommand((SeekerSoulSpiralManager.SoulSpiralCommandType)reader.ReadInt32()); } } public void CallCmdUnlockGateEffects(byte chakraGate) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdUnlockGateEffects called on server."); return; } if (base.isServer) { CmdUnlockGateEffects(chakraGate); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdUnlockGateEffects); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32(chakraGate); SendCommandInternal(networkWriter, 0, "CmdUnlockGateEffects"); } public void CallCmdUpdateMeditationInput(sbyte[] sequence) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdUpdateMeditationInput called on server."); return; } if (base.isServer) { CmdUpdateMeditationInput(sequence); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdUpdateMeditationInput); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WriteArraySByte_None(networkWriter, sequence); SendCommandInternal(networkWriter, 0, "CmdUpdateMeditationInput"); } public void CallCmdTriggerHealPulse(float value, UnityEngine.Vector3 corePosition, float blastRadius) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdTriggerHealPulse called on server."); return; } if (base.isServer) { CmdTriggerHealPulse(value, corePosition, blastRadius); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdTriggerHealPulse); networkWriter.Write(GetComponent().netId); networkWriter.Write(value); networkWriter.Write(corePosition); networkWriter.Write(blastRadius); SendCommandInternal(networkWriter, 0, "CmdTriggerHealPulse"); } public void CallCmdSpiralCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSpiralCommand called on server."); return; } if (base.isServer) { CmdSpiralCommand(msg); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSpiralCommand); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)msg); SendCommandInternal(networkWriter, 0, "CmdSpiralCommand"); } protected static void InvokeRpcRpcSetMeditation(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcSetMeditation called on server."); } else { ((SeekerController)obj).RpcSetMeditation(GeneratedNetworkCode._ReadArraySByte_None(reader)); } } protected static void InvokeRpcRpcSetPedalsValue(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcSetPedalsValue called on server."); } else { ((SeekerController)obj).RpcSetPedalsValue((byte)reader.ReadPackedUInt32()); } } protected static void InvokeRpcRpcSpiralCommand(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcSpiralCommand called on server."); } else { ((SeekerController)obj).RpcSpiralCommand((SeekerSoulSpiralManager.SoulSpiralCommandType)reader.ReadInt32()); } } public void CallRpcSetMeditation(sbyte[] sequence) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcSetMeditation called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcSetMeditation); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WriteArraySByte_None(networkWriter, sequence); SendRPCInternal(networkWriter, 0, "RpcSetMeditation"); } public void CallRpcSetPedalsValue(byte value) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcSetPedalsValue called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcSetPedalsValue); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32(value); SendRPCInternal(networkWriter, 0, "RpcSetPedalsValue"); } public void CallRpcSpiralCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcSpiralCommand called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcSpiralCommand); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)msg); SendRPCInternal(networkWriter, 0, "RpcSpiralCommand"); } static SeekerController() { kCmdCmdUnlockGateEffects = -1757393198; NetworkBehaviour.RegisterCommandDelegate(typeof(SeekerController), kCmdCmdUnlockGateEffects, InvokeCmdCmdUnlockGateEffects); kCmdCmdUpdateMeditationInput = -1791025022; NetworkBehaviour.RegisterCommandDelegate(typeof(SeekerController), kCmdCmdUpdateMeditationInput, InvokeCmdCmdUpdateMeditationInput); kCmdCmdTriggerHealPulse = -416543526; NetworkBehaviour.RegisterCommandDelegate(typeof(SeekerController), kCmdCmdTriggerHealPulse, InvokeCmdCmdTriggerHealPulse); kCmdCmdSpiralCommand = -1428889191; NetworkBehaviour.RegisterCommandDelegate(typeof(SeekerController), kCmdCmdSpiralCommand, InvokeCmdCmdSpiralCommand); kRpcRpcSetMeditation = -72748599; NetworkBehaviour.RegisterRpcDelegate(typeof(SeekerController), kRpcRpcSetMeditation, InvokeRpcRpcSetMeditation); kRpcRpcSetPedalsValue = 1863576493; NetworkBehaviour.RegisterRpcDelegate(typeof(SeekerController), kRpcRpcSetPedalsValue, InvokeRpcRpcSetPedalsValue); kRpcRpcSpiralCommand = 1157507459; NetworkBehaviour.RegisterRpcDelegate(typeof(SeekerController), kRpcRpcSpiralCommand, InvokeRpcRpcSpiralCommand); NetworkCRC.RegisterBehaviour("SeekerController", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class SeekerSoulSpiralManager { public enum SoulSpiralCommandType { RegisterIncomingSpiral, Boost, EndBoost } public SeekerController seekerController; private NetworkIdentity seekerNetworkIdentity; public CharacterBody seekerBody; private SoulSpiralProjectile[] soulSpiralArray; private SoulSpiralOrbiter soulSpiralOrbiter; private static GameObject soulSpiralBoostVFXPrefab; private static string soulSpiralBoostVFXPrefabGuid = "085f424d57ade224388b2ec514439cd9"; private static string soulSpiralBoostVFXParentName = "Base"; private EffectManagerHelper boostFXInstance; private Transform boostFXParent; public bool runFixedUpdate; private int soulSpiralLimit = 6; private int spiralsRequested; private int nextIndex; public bool hasAuthority { get { if (seekerNetworkIdentity == null) { return false; } return Util.HasEffectiveAuthority(seekerNetworkIdentity); } } public SeekerSoulSpiralManager(SeekerController _seekerController) { seekerController = _seekerController; seekerNetworkIdentity = _seekerController.GetComponent(); seekerBody = _seekerController.GetComponent(); soulSpiralArray = new SoulSpiralProjectile[soulSpiralLimit * 2]; soulSpiralOrbiter = new SoulSpiralOrbiter(_seekerController, this); ChildLocator childLocator = seekerBody.modelLocator?.modelTransform.GetComponent(); if (childLocator != null) { int childIndex = childLocator.FindChildIndex(soulSpiralBoostVFXParentName); boostFXParent = childLocator.FindChild(childIndex)?.transform; } if (!(soulSpiralBoostVFXPrefab == null)) { return; } if (!Addressables.LoadAssetAsync(soulSpiralBoostVFXPrefabGuid).IsValid()) { UnityEngine.Debug.LogError("SeekerSoulSpiralManager failed to load " + soulSpiralBoostVFXPrefabGuid + ". Check the path and try again?"); return; } LegacyResourcesAPI.LoadAsyncCallback(soulSpiralBoostVFXPrefabGuid, delegate(GameObject result) { soulSpiralBoostVFXPrefab = result; }); } public void ReceiveSpiralCommand(SoulSpiralCommandType msg) { switch (msg) { case SoulSpiralCommandType.RegisterIncomingSpiral: RegisterIncomingSpiral(); break; case SoulSpiralCommandType.Boost: BoostSpirals(); break; case SoulSpiralCommandType.EndBoost: NonAuthorityEndBoost(); break; } } public void MyFixedUpdate() { soulSpiralOrbiter.UpdateSpirals(ref soulSpiralArray); } public void FireSoulSpiral(FireProjectileInfo projectileInfo) { runFixedUpdate = hasAuthority; if (!CheckOurSpiralBudget()) { BoostSpirals(); } else { FireSoulSpiralInternal(projectileInfo); } } public void BoostSpirals() { FireBoostFX(); if (hasAuthority) { soulSpiralOrbiter.BoostAuthority(); } } public void FireBoostFX() { if (!(boostFXParent == null)) { if (boostFXInstance != null && boostFXInstance.gameObject.activeSelf) { EndBoostFX(); } boostFXInstance = EffectManager.GetAndActivatePooledEffect(soulSpiralBoostVFXPrefab, boostFXParent, inResetLocal: true); boostFXInstance.transform.SetParent(boostFXParent, worldPositionStays: false); } } public void EndBoostFX() { if (!(boostFXInstance == null)) { boostFXInstance.ReturnToPool(); } } public void NonAuthorityEndBoost() { EndBoostFX(); int num = soulSpiralArray.Length; for (int i = 0; i < num; i++) { if (!(soulSpiralArray[i] == null)) { soulSpiralArray[i].EndBoost(); } } } private void FireSoulSpiralInternal(FireProjectileInfo projectileInfo) { RegisterIncomingSpiral(); ProjectileManager.instance.FireProjectile(projectileInfo); } public void RegisterIncomingSpiral() { if (spiralsRequested < 1) { RoR2Application.onUpdate += DiscoverUnassignedSpirals; } spiralsRequested++; } private void DiscoverUnassignedSpirals() { if (seekerController == null) { StopListeningForUnassignedSpirals(); return; } if (spiralsRequested > 0) { List unassignedSoulSpirals = SoulSpiralProjectile.unassignedSoulSpirals; int count = unassignedSoulSpirals.Count; bool flag = hasAuthority; for (int i = 0; i < count; i++) { SoulSpiralProjectile soulSpiralProjectile = unassignedSoulSpirals[i]; if (!(soulSpiralProjectile == null) && !(soulSpiralProjectile.projectileController.owner != seekerController.gameObject)) { if (!TryToCacheSoulSpiral(soulSpiralProjectile, out var spiralPosition)) { break; } soulSpiralProjectile.AssignSpiralOwner(this); if (flag) { SetSpiralOrbitPosition(soulSpiralProjectile, spiralPosition); } if (!soulSpiralProjectile.projectileController.isPrediction) { spiralsRequested--; } } } } if (spiralsRequested < 1) { RoR2Application.onUpdate -= DiscoverUnassignedSpirals; } } private bool TryToCacheSoulSpiral(SoulSpiralProjectile soulSpiral, out int spiralPosition) { spiralPosition = -1; for (int i = 0; i < soulSpiralLimit; i++) { if (soulSpiralArray[nextIndex] == null) { if (soulSpiral.projectileController.isPrediction) { soulSpiralArray[nextIndex * 2] = soulSpiral; } else { soulSpiralArray[nextIndex] = soulSpiral; } spiralPosition = nextIndex; if (!soulSpiral.projectileController.isPrediction) { nextIndex = (nextIndex + 1) % soulSpiralLimit; } soulSpiralOrbiter.ResetValues(soulSpiral); return true; } nextIndex = (nextIndex + 1) % soulSpiralLimit; } return false; } private bool CheckOurSpiralBudget() { int num = spiralsRequested; for (int i = 0; i < soulSpiralLimit; i++) { if (soulSpiralArray[i] != null) { num++; } } return num < soulSpiralLimit; } private float GetSoulSpiralOffsetDegreesByIndex(int index) { return index switch { 1 => 240f, 2 => 120f, 3 => 300f, 4 => 60f, 5 => 180f, _ => 0f, }; } private void SetSpiralOrbitPosition(SoulSpiralProjectile soulSpiral, int positionIndex) { soulSpiral.SetInitialDegreesFromOwnerForward(GetSoulSpiralOffsetDegreesByIndex(positionIndex), positionIndex); } public void ShutdownAndCleanupSpirals() { if (NetworkServer.active) { DestroyAllSpirals(); CatchAndDestroyUnassignedSpirals(); } StopListeningForUnassignedSpirals(); runFixedUpdate = false; } private void CatchAndDestroyUnassignedSpirals() { if (seekerController == null || seekerController.gameObject == null) { return; } List unassignedSoulSpirals = SoulSpiralProjectile.unassignedSoulSpirals; for (int num = unassignedSoulSpirals.Count - 1; num >= 0; num--) { SoulSpiralProjectile soulSpiralProjectile = unassignedSoulSpirals[num]; if (!(soulSpiralProjectile == null) && !(soulSpiralProjectile.projectileController.owner != seekerController.gameObject)) { soulSpiralProjectile.DestroySpiral(); } } } private void StopListeningForUnassignedSpirals() { if (spiralsRequested > 0) { RoR2Application.onUpdate -= DiscoverUnassignedSpirals; } spiralsRequested = 0; } public void DestroyAllSpirals() { if (!NetworkServer.active) { return; } runFixedUpdate = false; int num = soulSpiralArray.Length; for (int i = 0; i < num; i++) { if (soulSpiralArray[i] != null) { soulSpiralArray[i].DestroySpiral(); } } } } [RequireComponent(typeof(VehicleSeat))] public class SojournVehicle : NetworkBehaviour, ICameraStateProvider { [Header("Vehicle Parameters")] public float nonLinearSpeedRate = 0.15f; public float nonLinearSpeedInterval = 1f; private float currentSpeed; public float startingSpeedBoost = 25f; private float startingSpeed; public float endSpeedTarget; public float endSpeedBodyInfluance = 1f; private float trueEndSpeed; public float cameraLerpTime = 1f; public float cameraForward = 2f; [Header("Blast Parameters")] public bool detonateOnCollision; public GameObject explosionEffectPrefab; public float blastDamageCoefficient; public float blastForce; public BlastAttack.FalloffModel blastFalloffModel; public DamageTypeCombo blastDamageType; public UnityEngine.Vector3 blastBonusForce; public float blastProcCoefficient; public string explosionSoundString; public GameObject healingExplosionPrefab; public float dmgAddedPerSecond = 0.5f; [Header("Blast Growth Rate")] private float blastRadius; public float minBlastSize = 4f; public float baseMaxBlastSize = 10f; public float perChakraAddMax = 2f; public float perChakraAddMin = 0.5f; public float blastNonlinearGrowthRate = 1f; [Tooltip("These are the explosion size indicators. They will be scaled up by blast size.")] public GameObject[] blastRadiusIndicators = new GameObject[0]; [Tooltip("This is the scale of the visible size indicators.")] public float blastRadiusIndicatorScale = 0.125f; [Tooltip("This will be multiplied by the bast size before calculating collision. Larger will expand the collider.")] public float blastRadiusCollisionMult = 1f; public GameObject effectsToFlatten; [Header("Overlap Parameters")] public float overlapDamageCoefficient; public float overlapProcCoefficient; public float overlapForce; public float overlapFirePeriod; public float overlapVehicleDurationBonusPerHit; public GameObject overlapHitEffectPrefab; private float age; private VehicleSeat vehicleSeat; private Rigidbody vehicleRigidbody; [Header("Camera Parameters")] public PlayerCharacterMasterController playerCharacterMasterController; public GameObject sojournOverlayPrefab; private CameraTargetParams cameraTargetParams; private CharacterBody characterBody; [Header("Flight Parameters")] private SeekerController seekerController; private float increaseAgeCheck; public float agePerTenthSecondsCheck = 0.1f; public float incrementalFlightDamage = 0.075f; [FormerlySerializedAs("initialFlightDamageDelay")] public float initialFlightGracePeriod = 0.3f; public float afterGraceLerpDownTime = 1f; [Header("Healing Parameters")] private float healingOverShield; private float healingExplosionAmount; private bool skillKeyWasDown = true; private bool skillHeldDown = true; private OverlayController overlayController; private List fillUiList = new List(); private ChildLocator overlayInstanceChildLocator; private OverlapAttack overlapAttack; private float overlapFireAge; private float overlapResetAge; private float agePerSecond; private float totalHealth; public Sojourn sojournState; public float barrierPercentage; public GameObject effectGameObject; public GameObject hitBox; private LocalUser localUser; private static int kRpcRpcEndSojournState; private void CacheLocalUser() { localUser = null; foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList) { if (readOnlyLocalPlayers.master == characterBody.master) { localUser = readOnlyLocalPlayers.localUser; } } } private void Awake() { playerCharacterMasterController = GetComponent(); vehicleSeat = GetComponent(); vehicleSeat.onPassengerEnter += OnPassengerEnter; vehicleSeat.onPassengerExit += OnPassengerExit; vehicleRigidbody = GetComponent(); effectGameObject = base.transform.Find("Effect").gameObject; hitBox = base.transform.Find("HitBox").gameObject; increaseAgeCheck = agePerTenthSecondsCheck; } private void Start() { overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams { prefab = sojournOverlayPrefab, childLocatorEntry = "CrosshairExtras" }); totalHealth = characterBody.baseMaxHealth + characterBody.levelMaxHealth * (float)((int)characterBody.level - 1); UpdateBlastRadius(); } private void OnPassengerExit(GameObject passenger) { foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList) { if (readOnlyInstances.target == passenger) { readOnlyInstances.SetOverrideCam(this, 0f); readOnlyInstances.SetOverrideCam(null, cameraLerpTime); } } DetonateServer(); } [ClientRpc] private void RpcEndSojournState() { Util.PlaySound(explosionSoundString, base.gameObject); seekerController.doesExitVehicle = true; } private void OnPassengerEnter(GameObject passenger) { skillHeldDown = vehicleSeat.currentPassengerInputBank.skill3.down; vehicleSeat.currentPassengerBody.GetComponent().interactableOverride = null; UnityEngine.Vector3 aimDirection = vehicleSeat.currentPassengerInputBank.aimDirection; vehicleRigidbody.rotation = UnityEngine.Quaternion.LookRotation(aimDirection); characterBody = vehicleSeat.currentPassengerBody; seekerController = characterBody.transform.GetComponent(); CacheLocalUser(); overlapAttack = new OverlapAttack { attacker = characterBody.gameObject, damage = 0f, pushAwayForce = overlapForce, isCrit = characterBody.RollCrit(), damageColorIndex = DamageColorIndex.Item, inflictor = base.gameObject, procChainMask = default(ProcChainMask), procCoefficient = overlapProcCoefficient, teamIndex = characterBody.teamComponent.teamIndex, hitBoxGroup = base.gameObject.GetComponent(), hitEffectPrefab = overlapHitEffectPrefab, damageType = DamageType.Stun1s }; startingSpeed = characterBody.moveSpeed + startingSpeedBoost; trueEndSpeed = endSpeedBodyInfluance * characterBody.moveSpeed + endSpeedTarget; currentSpeed = startingSpeed; vehicleRigidbody.velocity = aimDirection * currentSpeed; } [Server] private void DetonateServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SojournVehicle::DetonateServer()' called on client"); return; } float num = blastRadius * blastRadiusCollisionMult; EffectData effectData = new EffectData { origin = base.transform.position, scale = num }; EffectManager.SpawnEffect(explosionEffectPrefab, effectData, transmit: true); BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = characterBody.gameObject; blastAttack.baseDamage = blastDamageCoefficient * characterBody.damage; blastAttack.baseForce = blastForce; blastAttack.bonusForce = blastBonusForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = characterBody.RollCrit(); blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.damageType = blastDamageType; blastAttack.falloffModel = blastFalloffModel; blastAttack.inflictor = base.gameObject; blastAttack.position = base.transform.position; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = blastProcCoefficient; blastAttack.radius = num; blastAttack.teamIndex = characterBody.teamComponent.teamIndex; blastAttack.Fire(); Util.PlaySound(explosionSoundString, base.gameObject); seekerController.doesExitVehicle = true; CallRpcEndSojournState(); UnityEngine.Object.Destroy(base.gameObject); } private void Update() { effectsToFlatten.transform.rotation = UnityEngine.Quaternion.identity; } private void FixedUpdate() { age += Time.fixedDeltaTime; if (NetworkServer.active) { FixedUpdateOverlayAttack(); if (age > agePerTenthSecondsCheck) { FixedUpdatePerTenthSecond(); agePerTenthSecondsCheck += increaseAgeCheck; } } FixedUpdateMovement(); if (age > agePerSecond) { if (age > initialFlightGracePeriod) { blastForce += 25f; characterBody.AddBuff(DLC2Content.Buffs.SojournHealing); blastDamageCoefficient += dmgAddedPerSecond; } agePerSecond += 1f; } if (age > initialFlightGracePeriod) { float normalizedHealth = characterBody.healthComponent.GetNormalizedHealth(); float b = Mathf.Lerp(trueEndSpeed, startingSpeed, normalizedHealth); float t = Mathf.Clamp01((age - initialFlightGracePeriod) / afterGraceLerpDownTime); currentSpeed = Mathf.LerpUnclamped(startingSpeed, b, t); } UpdateBlastRadius(); if (localUser != null && vehicleSeat != null) { bool flag = localUser?.userProfile.toggleSeekerSojourn ?? true; bool? flag2 = vehicleSeat.currentPassengerInputBank?.skill3.down; if ((!flag && !flag2.Value) || (flag && flag2.Value && !skillKeyWasDown)) { vehicleSeat.currentPassengerInputBank.skill3.hasPressBeenClaimed = true; vehicleSeat.CallCmdEjectPassenger(); } skillKeyWasDown = vehicleSeat.currentPassengerInputBank?.skill3.down ?? false; } _ = effectGameObject.transform.position != hitBox.transform.position; } private void UpdateBlastRadius() { int buffCount = characterBody.GetBuffCount(DLC2Content.Buffs.ChakraBuff); float t = Util.ConvertAmplificationPercentageIntoReductionNormalized(blastNonlinearGrowthRate * age); blastRadius = Mathf.Lerp(minBlastSize + perChakraAddMin * (float)buffCount, baseMaxBlastSize + perChakraAddMax * (float)buffCount, t); UnityEngine.Vector3 localScale = UnityEngine.Vector3.one * (blastRadius * blastRadiusIndicatorScale); GameObject[] array = blastRadiusIndicators; for (int i = 0; i < array.Length; i++) { array[i].transform.localScale = localScale; } } [Server] private void FixedUpdateOverlayAttack() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SojournVehicle::FixedUpdateOverlayAttack()' called on client"); return; } overlapFireAge += Time.fixedDeltaTime; overlapResetAge += Time.fixedDeltaTime; if (overlapFireAge > overlapFirePeriod) { overlapAttack.Fire(); overlapFireAge = 0f; } } private void FixedUpdateMovement() { if (vehicleSeat.currentPassengerInputBank != null) { Ray aimRay = vehicleSeat.currentPassengerInputBank.GetAimRay(); aimRay = CameraRigController.ModifyAimRayIfApplicable(aimRay, base.gameObject, out var _); vehicleRigidbody.MoveRotation(UnityEngine.Quaternion.LookRotation(aimRay.direction)); vehicleRigidbody.velocity = aimRay.direction * currentSpeed; } } [Server] private void FixedUpdatePerTenthSecond() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SojournVehicle::FixedUpdatePerTenthSecond()' called on client"); return; } float damage = totalHealth * incrementalFlightDamage; DamageInfo damageInfo = new DamageInfo { damageType = DamageTypeExtended.SojournVehicleDamage, damage = damage, position = base.gameObject.transform.position }; if (age > initialFlightGracePeriod) { if (characterBody.healthComponent.health < totalHealth * 0.15f) { vehicleSeat.CallCmdEjectPassenger(); } else { characterBody.healthComponent.TakeDamage(damageInfo); } } } private void OnCollisionEnter(Collision collision) { if (detonateOnCollision && NetworkServer.active) { vehicleSeat.CallCmdEjectPassenger(); } } public void GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState) { cameraState.position = base.transform.position + base.transform.forward * cameraForward; } public bool IsUserLookAllowed(CameraRigController cameraRigController) { return true; } public bool IsUserControlAllowed(CameraRigController cameraRigController) { return true; } public bool IsHudAllowed(CameraRigController cameraRigController) { return true; } private void UNetVersion() { } protected static void InvokeRpcRpcEndSojournState(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcEndSojournState called on server."); } else { ((SojournVehicle)obj).RpcEndSojournState(); } } public void CallRpcEndSojournState() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcEndSojournState called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcEndSojournState); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcEndSojournState"); } static SojournVehicle() { kRpcRpcEndSojournState = -1858892214; NetworkBehaviour.RegisterRpcDelegate(typeof(SojournVehicle), kRpcRpcEndSojournState, InvokeRpcRpcEndSojournState); NetworkCRC.RegisterBehaviour("SojournVehicle", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class SoulSpiralProjectile : MonoBehaviour { public static List unassignedSoulSpirals = new List(); [SerializeField] [Header("Basic setup")] public UnityEngine.Vector3 offset; [SerializeField] public float initialDegreesFromOwnerForward; [SerializeField] public float degreesPerSecond; [SerializeField] public float radius; [SerializeField] public UnityEngine.Vector3 planeNormal = UnityEngine.Vector3.up; [SerializeField] public int hitStackPerBuff = 1; [SerializeField] [Tooltip("How much from 'baseline' can we move up or down during our sine wave")] public float verticalSineWaveOffset = 0.25f; [SerializeField] public float sineWavesPerSecond = 1.5f; [Space(20f)] [Header("Easing speeds")] [Tooltip("How long it takes the projectile to ease into its orbit from starting position.")] [SerializeField] public float easeInDuration; [Tooltip("How long it takes the projectile to transition from base speed to boosted speed")] [SerializeField] public float boostEaseDuration; [SerializeField] [Space(20f)] [Header("Boost variables")] [Tooltip("On the last hit, the projectile does more damage.")] public float lastHitDamageMultiplier; [SerializeField] [Tooltip("How long will the spiral spin after being boosted")] public float boostDuration; [SerializeField] [Tooltip("Coefficient for calculating Speed boost - multiplied against the # of boosts we have.")] public float speedBoostCoefficient; [Tooltip("How much should baseDamage be multipled by, if the speed is 100% faster than base.")] [SerializeField] public float damageMultiplier; [Tooltip("Triggered when the orbs are 'boosted'.")] [SerializeField] private UnityEvent OnOrbBoost; private SeekerSoulSpiralManager spiralManager; [HideInInspector] public ProjectileController projectileController; [HideInInspector] public ProjectileDamage projectileDamage; [HideInInspector] public ProjectileOverlapLimitHits projectileOverlapLimitHits; private SoulSpiralGhost _soulSpiralGhost; private Rigidbody rigidBody; private Transform ownerTransform; private float initialStartTimeStamp; private UnityEngine.Vector3 initialRadialDirection; private float prevDamage; private float baseDamage; private int baseHitLimit; private const float twoPi = MathF.PI * 2f; private SoulSpiralGhost soulSpiralGhost { get { if (_soulSpiralGhost == null) { if (projectileController == null || projectileController.ghost == null) { return null; } _soulSpiralGhost = projectileController.ghost.GetComponent(); } return _soulSpiralGhost; } set { _soulSpiralGhost = value; } } private void OnEnable() { unassignedSoulSpirals.Add(this); spiralManager = null; projectileController = projectileController ?? GetComponent(); rigidBody = rigidBody ?? GetComponent(); projectileDamage = projectileDamage ?? GetComponent(); projectileOverlapLimitHits = projectileOverlapLimitHits ?? GetComponent(); baseHitLimit = (projectileOverlapLimitHits ? projectileOverlapLimitHits.hitLimit : 3); if (sineWavesPerSecond < 0f) { sineWavesPerSecond = Mathf.Abs(sineWavesPerSecond); } if (sineWavesPerSecond == 0f) { sineWavesPerSecond = 1f; } } private void OnDisable() { if (unassignedSoulSpirals.Contains(this)) { unassignedSoulSpirals.Remove(this); } } public void AssignSpiralOwner(SeekerSoulSpiralManager _spiralManager) { spiralManager = _spiralManager; if (unassignedSoulSpirals.Contains(this)) { unassignedSoulSpirals.Remove(this); } ownerTransform = _spiralManager.seekerBody.transform; SetDefaultVariables(); } private void SetDefaultVariables() { if (hitStackPerBuff < 1) { hitStackPerBuff = 1; } projectileOverlapLimitHits.hitLimit = baseHitLimit + spiralManager.seekerBody.GetBuffCount(DLC2Content.Buffs.ChakraBuff.buffIndex) * hitStackPerBuff; initialStartTimeStamp = Time.fixedTime; initialRadialDirection = UnityEngine.Quaternion.AngleAxis(initialDegreesFromOwnerForward, planeNormal) * ownerTransform.forward; baseDamage = projectileDamage.damage; soulSpiralGhost = projectileController.ghost?.GetComponent(); } public void OnLastHit() { soulSpiralGhost?.OnLastHit(); } public void Boost() { soulSpiralGhost?.Boost(); } public void EndBoost() { soulSpiralGhost?.EndBoost(); } public void UpdateProjectile(float currentTime, float degreesRotated, float damageMultiplier, bool doBoost = false, bool doEndBoost = false) { if (!(ownerTransform == null)) { if (doBoost) { OnOrbBoost?.Invoke(); soulSpiralGhost?.Boost(); } if (doEndBoost) { soulSpiralGhost?.EndBoost(); } UnityEngine.Vector3 vector = ownerTransform.position + offset + UnityEngine.Quaternion.AngleAxis(degreesRotated, planeNormal) * initialRadialDirection * radius; float num = verticalSineWaveOffset; float num2 = (degreesRotated + initialDegreesFromOwnerForward) / degreesPerSecond; float num3 = Mathf.Cos(MathF.PI * 2f * num2 * sineWavesPerSecond); vector.y += num3 * num; if (currentTime - initialStartTimeStamp <= easeInDuration) { float num4 = currentTime - initialStartTimeStamp; vector = UnityEngine.Vector3.Lerp(base.transform.position, vector, num4 / easeInDuration); } if ((bool)rigidBody) { rigidBody.MovePosition(vector); } else { base.transform.position = vector; } float num5 = baseDamage * damageMultiplier; if (projectileOverlapLimitHits.IsLastHit()) { num5 *= lastHitDamageMultiplier; } if (num5 != prevDamage) { projectileDamage.damage = num5; prevDamage = num5; } } } public void SetInitialDegreesFromOwnerForward(float degrees, int positionIndex) { initialDegreesFromOwnerForward = degrees; if ((bool)ownerTransform) { initialRadialDirection = UnityEngine.Quaternion.AngleAxis(initialDegreesFromOwnerForward, planeNormal) * ownerTransform.forward; } } public void DestroySpiral() { EffectManagerHelper component = GetComponent(); if ((bool)component && component.OwningPool != null) { component.OwningPool.ReturnObject(component); } else { UnityEngine.Object.Destroy(base.gameObject); } } } public class SoulSpiralOrbiter { private float degreesRotated; public float easeInDuration; public float boostEaseDuration; public float boostDuration; public float speedBoostCoefficient; public float damageMultiplier; private int boostCount; private bool doBoost; private bool endBoost; private float baseDegreesPerSecond; private float targetAdditionalDegreesPerSecond; private float currentAdditionalDegreesPerSecond; private float baseProjectileDamage; private float currentDamageMultiplier; private float prevTimeStamp; private float deltaTime; private float boostChangedTimeStamp; private int length; private SeekerController seekerController; private SeekerSoulSpiralManager soulSpiralManager; public SoulSpiralOrbiter(SeekerController seekerController, SeekerSoulSpiralManager soulSpiralManager) { this.seekerController = seekerController; this.soulSpiralManager = soulSpiralManager; prevTimeStamp = Time.fixedTime; degreesRotated = 0f; baseProjectileDamage = 1f; } public void ResetValues(SoulSpiralProjectile soulSpiralInstance) { baseDegreesPerSecond = soulSpiralInstance.degreesPerSecond; boostEaseDuration = soulSpiralInstance.boostEaseDuration; boostDuration = soulSpiralInstance.boostDuration; damageMultiplier = soulSpiralInstance.damageMultiplier; easeInDuration = soulSpiralInstance.easeInDuration; speedBoostCoefficient = soulSpiralInstance.speedBoostCoefficient; } public void UpdateSpirals(ref SoulSpiralProjectile[] array) { length = array.Length; UpdateCurrentSpeedAndDamage(Time.fixedTime); for (int i = 0; i < length; i++) { if (!(array[i] == null)) { array[i].UpdateProjectile(prevTimeStamp, degreesRotated, currentDamageMultiplier, doBoost, endBoost); } } doBoost = false; endBoost = false; } public void UpdateCurrentSpeedAndDamage(float _currentTime) { deltaTime = _currentTime - prevTimeStamp; float boostTime = _currentTime - boostChangedTimeStamp; HandleBoostExpiring(_currentTime, ref boostTime); float num = 1f; if (boostCount > 0) { targetAdditionalDegreesPerSecond = speedBoostCoefficient * (float)boostCount / (speedBoostCoefficient * (float)boostCount + 1f); targetAdditionalDegreesPerSecond *= baseDegreesPerSecond; num = (targetAdditionalDegreesPerSecond + baseDegreesPerSecond) / baseDegreesPerSecond; } else { targetAdditionalDegreesPerSecond = 0f; } currentAdditionalDegreesPerSecond = Mathf.Lerp(currentAdditionalDegreesPerSecond, targetAdditionalDegreesPerSecond, boostTime / boostEaseDuration); degreesRotated += deltaTime * (baseDegreesPerSecond + currentAdditionalDegreesPerSecond); currentDamageMultiplier = baseProjectileDamage + (num - 1f) * damageMultiplier * baseProjectileDamage; prevTimeStamp = _currentTime; } private void HandleBoostExpiring(float stopWatchTime, ref float boostTime) { if (boostCount != 0 && boostTime > boostDuration) { boostCount = 0; boostChangedTimeStamp = stopWatchTime; boostTime = 0f; endBoost = true; soulSpiralManager.EndBoostFX(); seekerController.SpiralSendCommand(SeekerSoulSpiralManager.SoulSpiralCommandType.EndBoost); } } public void BoostAuthority() { boostCount++; boostChangedTimeStamp = Time.fixedTime; doBoost = true; seekerController.SpiralSendCommand(SeekerSoulSpiralManager.SoulSpiralCommandType.Boost); } } [RequireComponent(typeof(BezierCurveLine))] public class JailerTetherController : NetworkBehaviour { [SyncVar] public GameObject targetRoot; [SyncVar] public GameObject ownerRoot; [SyncVar] public GameObject origin; [SyncVar] public float reelSpeed = 12f; [NonSerialized] public float breakDistanceSqr; [NonSerialized] public float damageCoefficientPerTick; [NonSerialized] public float tickInterval; [NonSerialized] public float tickTimer; public float attachTime; private float fixedAge; private float age; private bool beginSiphon; private BezierCurveLine bezierCurveLine; private HealthComponent targetHealthComponent; private CharacterBody ownerBody; private CharacterBody targetBody; private BuffDef tetheredBuff; private NetworkInstanceId ___targetRootNetId; private NetworkInstanceId ___ownerRootNetId; private NetworkInstanceId ___originNetId; public GameObject NetworktargetRoot { get { return targetRoot; } [param: In] set { SetSyncVarGameObject(value, ref targetRoot, 1u, ref ___targetRootNetId); } } public GameObject NetworkownerRoot { get { return ownerRoot; } [param: In] set { SetSyncVarGameObject(value, ref ownerRoot, 2u, ref ___ownerRootNetId); } } public GameObject Networkorigin { get { return origin; } [param: In] set { SetSyncVarGameObject(value, ref origin, 4u, ref ___originNetId); } } public float NetworkreelSpeed { get { return reelSpeed; } [param: In] set { SetSyncVar(value, ref reelSpeed, 8u); } } private void Awake() { bezierCurveLine = GetComponent(); } private void Start() { if (!targetHealthComponent) { targetHealthComponent = targetRoot.GetComponent(); } if (!ownerBody) { ownerBody = ownerRoot.GetComponent(); } Networkorigin = ((origin != null) ? origin : ownerRoot); } private void LateUpdate() { age += Time.deltaTime; UnityEngine.Vector3 position = origin.transform.position; if (!beginSiphon) { UnityEngine.Vector3 position2 = UnityEngine.Vector3.Lerp(position, GetTargetRootPosition(), age / attachTime); bezierCurveLine.endTransform.position = position2; } else if ((bool)targetRoot) { bezierCurveLine.endTransform.position = targetRoot.transform.position; } } private void FixedUpdate() { fixedAge += Time.fixedDeltaTime; if ((bool)targetRoot && (bool)ownerRoot) { UnityEngine.Vector3 targetRootPosition = GetTargetRootPosition(); if (!beginSiphon && fixedAge >= attachTime) { beginSiphon = true; return; } UnityEngine.Vector3 vector = origin.transform.position - targetRootPosition; if (NetworkServer.active) { float sqrMagnitude = vector.sqrMagnitude; tickTimer -= Time.fixedDeltaTime; if (tickTimer <= 0f) { tickTimer += tickInterval; DoDamageTick(); } if (sqrMagnitude > breakDistanceSqr) { UnityEngine.Object.Destroy(base.gameObject); return; } } if (!Util.HasEffectiveAuthority(targetRoot)) { return; } UnityEngine.Vector3 vector2 = reelSpeed * Time.fixedDeltaTime * vector.normalized; CharacterMotor component = targetRoot.GetComponent(); if ((bool)component) { component.rootMotion += vector2; return; } Rigidbody component2 = targetRoot.GetComponent(); if ((bool)component2) { component2.velocity += vector2; } } else if (NetworkServer.active) { UnityEngine.Object.Destroy(base.gameObject); } } private void DoDamageTick() { DamageInfo damageInfo = new DamageInfo { position = targetRoot.transform.position, attacker = null, inflictor = null, damage = damageCoefficientPerTick * ownerBody.damage, damageColorIndex = DamageColorIndex.Default, damageType = DamageType.Generic, crit = false, force = UnityEngine.Vector3.zero, procChainMask = default(ProcChainMask), procCoefficient = 0f }; targetHealthComponent.TakeDamage(damageInfo); if (!targetHealthComponent.alive) { NetworktargetRoot = null; } } public override void OnNetworkDestroy() { if (NetworkServer.active) { RemoveBuff(); } base.OnNetworkDestroy(); } private void RemoveBuff() { if ((bool)tetheredBuff && (bool)targetBody) { targetBody.RemoveBuff(tetheredBuff); } } public CharacterBody GetTargetBody() { if ((bool)targetBody) { return targetBody; } if ((bool)targetRoot) { targetBody = targetRoot.GetComponent(); return targetBody; } return null; } private UnityEngine.Vector3 GetTargetRootPosition() { if ((bool)targetRoot) { UnityEngine.Vector3 result = targetRoot.transform.position; if ((bool)targetHealthComponent) { result = targetHealthComponent.body.corePosition; } return result; } return base.transform.position; } public void SetTetheredBuff(BuffDef buffDef) { if (buffDef != null) { CharacterBody characterBody = GetTargetBody(); if ((bool)characterBody) { tetheredBuff = buffDef; characterBody.AddBuff(tetheredBuff); } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(targetRoot); writer.Write(ownerRoot); writer.Write(origin); writer.Write(reelSpeed); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(targetRoot); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(ownerRoot); } if ((base.syncVarDirtyBits & 4u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(origin); } if ((base.syncVarDirtyBits & 8u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(reelSpeed); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { ___targetRootNetId = reader.ReadNetworkId(); ___ownerRootNetId = reader.ReadNetworkId(); ___originNetId = reader.ReadNetworkId(); reelSpeed = reader.ReadSingle(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { targetRoot = reader.ReadGameObject(); } if (((uint)num & 2u) != 0) { ownerRoot = reader.ReadGameObject(); } if (((uint)num & 4u) != 0) { origin = reader.ReadGameObject(); } if (((uint)num & 8u) != 0) { reelSpeed = reader.ReadSingle(); } } public override void PreStartClient() { if (!___targetRootNetId.IsEmpty()) { NetworktargetRoot = ClientScene.FindLocalObject(___targetRootNetId); } if (!___ownerRootNetId.IsEmpty()) { NetworkownerRoot = ClientScene.FindLocalObject(___ownerRootNetId); } if (!___originNetId.IsEmpty()) { Networkorigin = ClientScene.FindLocalObject(___originNetId); } } } public class EnumMaskAttribute : PropertyAttribute { public Type enumType; public EnumMaskAttribute(Type enumType) { this.enumType = enumType; } } public static class EOSLobbyDataGenerator { private static class ToStringCache { public static MemoizedToString> serverId; public static MemoizedToString> serverAddress; public static MemoizedToString playerCount; public static MemoizedToString edition; public static MemoizedToString serverMaxPlayers; public static MemoizedToString serverPlayerCount; } private const int k_cubChatMetadataMax = 8192; private const int k_nMaxLobbyKeyLength = 255; private static string lobbyId; private static int edition; private static RuleBook cachedRuleBook; private static bool dirty = false; private static readonly string[] specialKeys = new string[9] { "joinable", "name", "appid", "lobbytype", "total_max_players", "v", "qp_cutoff_time", "qp", "starting" }; private static readonly List> ruleBookKeyValues = new List>(1); private static readonly KeyValueSplitter ruleBookKeyValueSplitter = new KeyValueSplitter("rulebook", 255, 8192, SetRuleBookKeyValue); public static event Action>> getAdditionalKeyValues; [SystemInitializer(new Type[] { typeof(RuleBook) })] private static void Init() { cachedRuleBook = new RuleBook(); if (PlatformSystems.EgsToggleConVar.value == 1) { LobbyManager lobbyManager = PlatformSystems.lobbyManager; lobbyManager.onLobbyOwnershipGained = (Action)Delegate.Combine(lobbyManager.onLobbyOwnershipGained, new Action(OnLobbyOwnershipGained)); LobbyManager lobbyManager2 = PlatformSystems.lobbyManager; lobbyManager2.onLobbyOwnershipLost = (Action)Delegate.Combine(lobbyManager2.onLobbyOwnershipLost, new Action(OnLobbyOwnershipLost)); } } private static void OnLobbyOwnershipGained() { EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager; lobbyId = obj.CurrentLobbyId; edition = 0; LobbyDetails currentLobbyDetails = obj.CurrentLobbyDetails; LobbyDetailsCopyAttributeByKeyOptions options = new LobbyDetailsCopyAttributeByKeyOptions { AttrKey = "v" }; if (currentLobbyDetails.CopyAttributeByKey(ref options, out var outAttribute) == Result.Success) { int.TryParse(outAttribute.Value.Data.ToString(), out edition); } LobbyManager lobbyManager = PlatformSystems.lobbyManager; lobbyManager.onLobbyMemberDataUpdated = (Action)Delegate.Combine(lobbyManager.onLobbyMemberDataUpdated, new Action(EOSLobbyManagerOnOnLobbyMemberDataUpdated)); LobbyManager lobbyManager2 = PlatformSystems.lobbyManager; lobbyManager2.onLobbyStateChanged = (Action)Delegate.Combine(lobbyManager2.onLobbyStateChanged, new Action(EOSLobbyManagerOnOnLobbyStateChanged)); NetworkManagerSystem.onStartClientGlobal += NetworkManagerSystemOnOnStartClientGlobal; NetworkManagerSystem.onStopClientGlobal += NetworkManagerSystemOnOnStopClientGlobal; SceneCatalog.onMostRecentSceneDefChanged += SceneCatalogOnOnMostRecentSceneDefChanged; NetworkUser.onNetworkUserDiscovered += NetworkUserOnOnNetworkUserDiscovered; NetworkUser.onNetworkUserLost += NetworkUserOnOnNetworkUserLost; PreGameController.onPreGameControllerSetRuleBookGlobal += OnPreGameControllerSetRuleBook; Run.onRunSetRuleBookGlobal += OnRunSetRuleBook; UpdateRuleBook(); RebuildLobbyData(); } private static void OnLobbyOwnershipLost() { lobbyId = string.Empty; edition = 0; Run.onRunSetRuleBookGlobal -= OnRunSetRuleBook; PreGameController.onPreGameControllerSetRuleBookGlobal -= OnPreGameControllerSetRuleBook; NetworkUser.onNetworkUserLost -= NetworkUserOnOnNetworkUserLost; NetworkUser.onNetworkUserDiscovered -= NetworkUserOnOnNetworkUserDiscovered; SceneCatalog.onMostRecentSceneDefChanged -= SceneCatalogOnOnMostRecentSceneDefChanged; NetworkManagerSystem.onStopClientGlobal -= NetworkManagerSystemOnOnStopClientGlobal; NetworkManagerSystem.onStartClientGlobal -= NetworkManagerSystemOnOnStartClientGlobal; LobbyManager lobbyManager = PlatformSystems.lobbyManager; lobbyManager.onLobbyMemberDataUpdated = (Action)Delegate.Remove(lobbyManager.onLobbyMemberDataUpdated, new Action(EOSLobbyManagerOnOnLobbyMemberDataUpdated)); LobbyManager lobbyManager2 = PlatformSystems.lobbyManager; lobbyManager2.onLobbyStateChanged = (Action)Delegate.Remove(lobbyManager2.onLobbyStateChanged, new Action(EOSLobbyManagerOnOnLobbyStateChanged)); } private static void OnPreGameControllerSetRuleBook(PreGameController run, RuleBook ruleBook) { UpdateRuleBook(); } private static void OnRunSetRuleBook(Run run, RuleBook ruleBook) { UpdateRuleBook(); } private static void EOSLobbyManagerOnOnLobbyMemberDataUpdated(PlatformID memberId) { SetDirty(); } private static void EOSLobbyManagerOnOnLobbyStateChanged() { SetDirty(); } private static void NetworkManagerSystemOnOnStartClientGlobal(NetworkClient networkClient) { SetDirty(); } private static void NetworkManagerSystemOnOnStopClientGlobal() { SetDirty(); } private static void SceneCatalogOnOnMostRecentSceneDefChanged(SceneDef sceneDef) { SetDirty(); } private static void NetworkUserOnOnNetworkUserDiscovered(NetworkUser networkUser) { SetDirty(); } private static void NetworkUserOnOnNetworkUserLost(NetworkUser networkUser) { SetDirty(); } public static void SetDirty() { if (!dirty) { dirty = true; RoR2Application.onNextUpdate += RebuildLobbyData; } } public static void RebuildLobbyData() { try { dirty = false; LobbyDetails currentLobbyDetails = (PlatformSystems.lobbyManager as EOSLobbyManager).CurrentLobbyDetails; if (currentLobbyDetails == null) { return; } LobbyDetails lobbyDetails = currentLobbyDetails; Dictionary KVPs = CollectionPool, Dictionary>.RentCollection(); EOSLobbyManager.GetAllCurrentLobbyKVPs(currentLobbyDetails, ref KVPs); if (!EOSLobbyManager.IsLobbyOwner(currentLobbyDetails) || KVPs == null || lobbyDetails == null) { CollectionPool, Dictionary>.ReturnCollection(KVPs); return; } LobbyModification currentLobbyModification = (PlatformSystems.lobbyManager as EOSLobbyManager).CurrentLobbyModification; string value2 = null; KVPs.TryGetValue("total_max_players", out value2); if (value2 == null || !int.TryParse(value2, out var result)) { result = LobbyManager.cvSteamLobbyMaxMembers.value; EOSLobbyManager.SetLobbyStringValue(currentLobbyModification, "total_max_players", result.ToString()); } int num = result - PlatformSystems.lobbyManager.calculatedExtraPlayersCount; LobbyDetailsGetMemberCountOptions options = default(LobbyDetailsGetMemberCountOptions); currentLobbyDetails.GetMemberCount(ref options); _ = num; Dictionary newData = CollectionPool, Dictionary>.RentCollection(); List> list = CollectionPool, List>>.RentCollection(); EOSLobbyDataGenerator.getAdditionalKeyValues?.Invoke(list); for (int i = 0; i < list.Count; i++) { KeyValuePair keyValuePair = list[i]; AddData(keyValuePair.Key, keyValuePair.Value); } CollectionPool, List>>.ReturnCollection(list); AddData("build_id", RoR2Application.GetBuildId()); AddData("_mh", NetworkModCompatibilityHelper.networkModHash); int input = PlatformSystems.lobbyManager.calculatedTotalPlayerCount; AddData("player_count", ToStringCache.playerCount.GetString(in input)); string value3 = SceneCatalog.GetSceneDefForCurrentScene()?.baseSceneName; if (!string.IsNullOrEmpty(value3)) { AddData("_map", value3); } GetServerInfo(out var serverId, out var serverAddress, out var isSelf); bool flag = false; bool num2 = KVPs?.ContainsKey("server_id") ?? false; bool flag2 = KVPs?.ContainsKey("server_address") ?? false; bool flag3 = num2 || flag2; bool flag4 = false; if ((bool)NetworkSession.instance) { flag = NetworkSession.instance.HasFlag(NetworkSession.Flags.HasPassword); AddData("_ds", NetworkSession.instance.HasFlag(NetworkSession.Flags.IsDedicatedServer) ? "1" : "0"); AddData("_pw", flag ? "1" : "0"); AddData("_svtags", (NetworkSession.instance.tagsString != null) ? NetworkSession.instance.tagsString : ""); input = (int)NetworkSession.instance.maxPlayers; AddData("_svmpl", ToStringCache.serverMaxPlayers.GetString(in input)); input = NetworkUser.readOnlyInstancesList.Count; AddData("_svplc", ToStringCache.serverPlayerCount.GetString(in input)); AddData("_svnm", NetworkSession.instance.serverName); if (serverId != null) { AddData("server_id", serverId.ToString()); flag4 = true; } if (serverAddress.isValid) { AddData("server_address", ToStringCache.serverAddress.GetString(in serverAddress)); flag4 = true; } } GameModeIndex gameModeIndex = GameModeIndex.Invalid; if ((bool)Run.instance) { gameModeIndex = Run.instance.gameModeIndex; } else if ((bool)PreGameController.instance) { gameModeIndex = PreGameController.instance.gameModeIndex; } if (gameModeIndex != GameModeIndex.Invalid) { string gameModeName = GameModeCatalog.GetGameModeName(gameModeIndex); AddData("_svgm", gameModeName); } if (flag4 && !flag3 && flag) { string value4 = (isSelf ? NetworkManagerSystem.SvPasswordConVar.instance.value : NetworkManagerSystem.cvClPassword.value); NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write(value4); (PlatformSystems.lobbyManager as EOSLobbyManager).SendLobbyMessage(LobbyManager.LobbyMessageType.Password, networkWriter); } for (int j = 0; j < ruleBookKeyValues.Count; j++) { KeyValuePair keyValuePair2 = ruleBookKeyValues[j]; AddData(keyValuePair2.Key, keyValuePair2.Value); } for (int k = 0; k < specialKeys.Length; k++) { KVPs.Remove(specialKeys[k]); } bool flag5 = false; List list2 = CollectionPool>.RentCollection(); if (KVPs != null) { foreach (KeyValuePair item in KVPs) { if (!newData.ContainsKey(item.Key)) { list2.Add(item.Key); } } } for (int l = 0; l < list2.Count; l++) { EOSLobbyManager.RemoveLobbyStringValue(currentLobbyModification, list2[l]); } if (list2.Count > 0) { flag5 = true; } CollectionPool>.ReturnCollection(list2); foreach (KeyValuePair item2 in newData) { string value5 = null; if (KVPs == null || !KVPs.TryGetValue(item2.Key, out value5) || !item2.Value.Equals(value5, StringComparison.Ordinal)) { EOSLobbyManager.SetLobbyStringValue(currentLobbyModification, item2.Key, item2.Value); flag5 = true; } } if (flag5) { edition++; } EOSLobbyManager.SetLobbyStringValue(currentLobbyModification, "v", ToStringCache.edition.GetString(in edition)); EOSLobbyManager.UpdateLobby(currentLobbyModification); CollectionPool, Dictionary>.ReturnCollection(newData); CollectionPool, Dictionary>.ReturnCollection(KVPs); void AddData(string key, string value) { newData.Add(key, (value != null) ? value : ""); } } catch (Exception message) { UnityEngine.Debug.LogError(message); } } private static void GetServerInfo(out ProductUserId serverId, out AddressPortPair serverAddress, out bool isSelf) { serverId = new ProductUserId(); serverAddress = default(AddressPortPair); isSelf = false; HostDescription desiredHost = NetworkManagerSystem.singleton.desiredHost; if (desiredHost.hostType == HostDescription.HostType.None) { return; } if (desiredHost.hostType == HostDescription.HostType.Self) { if (NetworkServer.active) { serverId = NetworkManagerSystem.singleton.serverP2PId.productUserID; isSelf = true; } } else if (desiredHost.hostType == HostDescription.HostType.Steam) { serverId = desiredHost.userID.productUserID; } else if (desiredHost.hostType == HostDescription.HostType.IPv4) { serverAddress = desiredHost.addressPortPair; } } private static void UpdateRuleBook() { RuleBook ruleBook = null; if ((bool)Run.instance) { ruleBook = Run.instance.ruleBook; } else if ((bool)PreGameController.instance) { ruleBook = PreGameController.instance.readOnlyRuleBook; } if (ruleBook != null && !ruleBook.Equals(cachedRuleBook)) { cachedRuleBook.Copy(ruleBook); StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder(); RuleBook.WriteBase64ToStringBuilder(cachedRuleBook, stringBuilder); ruleBookKeyValueSplitter.SetValue(stringBuilder); HG.StringBuilderPool.ReturnStringBuilder(stringBuilder); } else { cachedRuleBook.SetToDefaults(); } } private static void SetRuleBookKeyValue(string key, string value) { int num = -1; for (int i = 0; i < ruleBookKeyValues.Count; i++) { if (ruleBookKeyValues[i].Key.Equals(key, StringComparison.Ordinal)) { if (ruleBookKeyValues[i].Value.Equals(value, StringComparison.Ordinal)) { return; } num = i; break; } } if (value == null) { if (num != -1) { ruleBookKeyValues.RemoveAt(num); } } else { KeyValuePair keyValuePair = new KeyValuePair(key, value); if (num != -1) { ruleBookKeyValues[num] = keyValuePair; } else { ruleBookKeyValues.Add(keyValuePair); } } SetDirty(); } [ConCommand(commandName = "steam_lobby_data_regenerate", flags = ConVarFlags.None, helpText = "Forces the current lobby data to be regenerated.")] public static void CCSteamLobbyRegenerateData(ConCommandArgs args) { SetDirty(); } } public enum EquipmentIndex { None = -1 } [Serializable] public class EquipmentMask : ICollection, IEnumerable, IEnumerable { public struct Enumerator : IEnumerator, IEnumerator, IDisposable { private bool[] target; public EquipmentIndex Current { get; private set; } object IEnumerator.Current => Current; public Enumerator(bool[] array) { Current = EquipmentIndex.None; target = array; } public bool MoveNext() { EquipmentIndex equipmentCount = (EquipmentIndex)EquipmentCatalog.equipmentCount; while (Current < equipmentCount) { if (target[(int)Current]) { return true; } EquipmentIndex current = Current + 1; Current = current; } return false; } public void Reset() { Current = EquipmentIndex.None; } public void Dispose() { } } private readonly bool[] array; public int Count => array.Length; public bool IsReadOnly => false; public EquipmentMask() { array = new bool[EquipmentCatalog.equipmentCount]; } public static EquipmentMask Rent() { return CollectionPool.RentCollection(); } public static void Return(EquipmentMask equipmentMask) { if (equipmentMask.array.Length == EquipmentCatalog.equipmentCount) { CollectionPool.ReturnCollection(equipmentMask); } } public bool Contains(EquipmentIndex equipmentIndex) { bool[] obj = array; bool defaultValue = false; return ArrayUtils.GetSafe(obj, (int)equipmentIndex, in defaultValue); } public void Add(EquipmentIndex equipmentIndex) { if (ArrayUtils.IsInBounds(array, (int)equipmentIndex)) { array[(int)equipmentIndex] = true; } } public bool Remove(EquipmentIndex equipmentIndex) { if (ArrayUtils.IsInBounds(array, (int)equipmentIndex)) { ref bool reference = ref array[(int)equipmentIndex]; bool result = reference; reference = false; return result; } return false; } public void Clear() { bool[] obj = array; bool value = false; ArrayUtils.SetAll(obj, in value); } public void CopyTo(EquipmentIndex[] array, int arrayIndex) { for (int i = 0; i < this.array.Length; i++) { if (this.array[i]) { array[arrayIndex++] = (EquipmentIndex)i; } } } public Enumerator GetEnumerator() { return new Enumerator(array); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public static class EquipmentCatalog { public struct AllEquipmentEnumerator : IEnumerator, IEnumerator, IDisposable { private EquipmentIndex position; public EquipmentIndex Current => position; object IEnumerator.Current => Current; public bool MoveNext() { position++; return (int)position < equipmentCount; } public void Reset() { position = EquipmentIndex.None; } void IDisposable.Dispose() { } } private static EquipmentDef[] equipmentDefs = Array.Empty(); public static List equipmentList = new List(); public static List enigmaEquipmentList = new List(); public static List randomTriggerEquipmentList = new List(); private static readonly Dictionary equipmentNameToIndex = new Dictionary(); public static ResourceAvailability availability = default(ResourceAvailability); public static readonly GenericStaticEnumerable allEquipment; public static int equipmentCount => equipmentDefs.Length; [Obsolete("Use IContentPackProvider instead.")] public static event Action> getAdditionalEntries { add { LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.EquipmentCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.equipmentDefs); } remove { } } [SystemInitializer(new Type[] { })] private static void Init() { SetEquipmentDefs(ContentManager.equipmentDefs); availability.MakeAvailable(); } private static void SetEquipmentDefs(EquipmentDef[] newEquipmentDefs) { EquipmentDef[] array = equipmentDefs; for (int i = 0; i < array.Length; i++) { array[i].equipmentIndex = EquipmentIndex.None; } equipmentNameToIndex.Clear(); equipmentList.Clear(); enigmaEquipmentList.Clear(); randomTriggerEquipmentList.Clear(); ArrayUtils.CloneTo(newEquipmentDefs, ref equipmentDefs); Array.Sort(equipmentDefs, (EquipmentDef a, EquipmentDef b) => string.CompareOrdinal(a.name, b.name)); for (EquipmentIndex equipmentIndex = (EquipmentIndex)0; (int)equipmentIndex < equipmentDefs.Length; equipmentIndex++) { RegisterEquipment(equipmentIndex, equipmentDefs[(int)equipmentIndex]); } } private static void RegisterEquipment(EquipmentIndex equipmentIndex, EquipmentDef equipmentDef) { equipmentDef.equipmentIndex = equipmentIndex; if (equipmentDef.canDrop) { equipmentList.Add(equipmentIndex); if (equipmentDef.enigmaCompatible) { enigmaEquipmentList.Add(equipmentIndex); } if (equipmentDef.canBeRandomlyTriggered) { randomTriggerEquipmentList.Add(equipmentIndex); } } string name = equipmentDef.name; equipmentNameToIndex[name] = equipmentIndex; } public static EquipmentDef GetEquipmentDef(EquipmentIndex equipmentIndex) { return ArrayUtils.GetSafe(equipmentDefs, (int)equipmentIndex); } public static EquipmentIndex FindEquipmentIndex(string equipmentName) { if (equipmentNameToIndex.TryGetValue(equipmentName, out var value)) { return value; } return EquipmentIndex.None; } public static T[] GetPerEquipmentBuffer() { return new T[equipmentCount]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIndexValid(in EquipmentIndex equipmentIndex) { return (uint)equipmentIndex < (uint)equipmentCount; } [ConCommand(commandName = "equipment_list", flags = ConVarFlags.None, helpText = "Lists internal names of all equipment registered to the equipment catalog.")] private static void CCEquipmentList(ConCommandArgs args) { StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder(); EquipmentDef[] array = equipmentDefs; foreach (EquipmentDef equipmentDef in array) { stringBuilder.AppendLine(equipmentDef.name + " (" + Language.GetString(equipmentDef.nameToken) + ")"); } args.Log(stringBuilder.ToString()); HG.StringBuilderPool.ReturnStringBuilder(stringBuilder); } } [CreateAssetMenu(menuName = "RoR2/DropTables/ExplicitPickupDropTable")] public class ExplicitPickupDropTable : PickupDropTable { [Serializable] public struct StringEntry { public string pickupName; public float pickupWeight; } [Serializable] public struct PickupDefEntry { [TypeRestrictedReference(new Type[] { typeof(ItemDef), typeof(EquipmentDef), typeof(MiscPickupDef) })] public UnityEngine.Object pickupDef; public float pickupWeight; } public PickupDefEntry[] pickupEntries = Array.Empty(); [Header("Deprecated")] [Obsolete("Use pickupEntries instead.", false)] public StringEntry[] entries = Array.Empty(); private readonly WeightedSelection weightedSelection = new WeightedSelection(); protected override void Regenerate(Run run) { GenerateWeightedSelection(); } private void GenerateWeightedSelection() { weightedSelection.Clear(); StringEntry[] array = entries; for (int i = 0; i < array.Length; i++) { StringEntry stringEntry = array[i]; weightedSelection.AddChoice(PickupCatalog.FindPickupIndex(stringEntry.pickupName), stringEntry.pickupWeight); } PickupDefEntry[] array2 = pickupEntries; for (int i = 0; i < array2.Length; i++) { PickupDefEntry pickupDefEntry = array2[i]; PickupIndex pickupIndex = PickupIndex.none; UnityEngine.Object pickupDef = pickupDefEntry.pickupDef; if (!(pickupDef is ItemDef itemDef)) { if (pickupDef is EquipmentDef equipmentDef) { pickupIndex = PickupCatalog.FindPickupIndex(equipmentDef.equipmentIndex); } else { MiscPickupDef miscPickupDef = pickupDefEntry.pickupDef as MiscPickupDef; if (miscPickupDef != null) { pickupIndex = PickupCatalog.FindPickupIndex(miscPickupDef.miscPickupIndex); } } } else { pickupIndex = PickupCatalog.FindPickupIndex(itemDef.itemIndex); } if (pickupIndex != PickupIndex.none) { weightedSelection.AddChoice(pickupIndex, pickupDefEntry.pickupWeight); } } } protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng) { return PickupDropTable.GenerateDropFromWeightedSelection(rng, weightedSelection); } public override int GetPickupCount() { return weightedSelection.Count; } protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng) { return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, weightedSelection); } } public static class FadeToBlackManager { private static UnityEngine.UI.Image image; public static int fadeCount; private static float alpha; public static bool fadePaused; private const float fadeDuration = 0.25f; private const float inversefadeDuration = 4f; public static bool fullyFaded => alpha == 2f; [InitDuringStartup] private static void Init() { LegacyResourcesAPI.LoadAsyncCallback("Prefabs/UI/ScreenTintCanvas", InitCanvas); static void InitCanvas(GameObject prefab) { GameObject gameObject = UnityEngine.Object.Instantiate(prefab, RoR2Application.instance.mainCanvas.transform); alpha = 0f; image = gameObject.transform.GetChild(0).GetComponent(); UpdateImageAlpha(alpha); RoR2Application.onUpdate += Update; SceneManager.sceneUnloaded += OnSceneUnloaded; } } public static void OnSceneUnloaded(Scene scene) { ForceFullBlack(); } public static void ForceFullBlack() { alpha = 2f; } private static void Update() { if (!fadePaused) { float target = 2f; float num = 4f; if (fadeCount <= 0) { target = 0f; num *= 0.25f; } alpha = Mathf.MoveTowards(alpha, target, Time.unscaledDeltaTime * num); float num2 = 0f; List instancesList = InstanceTracker.GetInstancesList(); for (int i = 0; i < instancesList.Count; i++) { FadeToBlackOffset fadeToBlackOffset = instancesList[i]; num2 += fadeToBlackOffset.value; } UpdateImageAlpha(alpha + num2); } } private static void UpdateImageAlpha(float finalAlpha) { UnityEngine.Color color = image.color; UnityEngine.Color color2 = color; color2.a = finalAlpha; image.color = color2; image.raycastTarget = color2.a > color.a; } public static void ForceClear() { fadeCount = 0; alpha = 0f; TransitionCommand.ForceClearFadeToBlack(); } public static bool IsFading() { return alpha > 0f; } } public static class FileIoIndicatorManager { private static int activeWriteCount; private static volatile float saveIconAlpha; public static void IncrementActiveWriteCount() { Interlocked.Increment(ref activeWriteCount); saveIconAlpha = 2f; } public static void DecrementActiveWriteCount() { Interlocked.Decrement(ref activeWriteCount); } [SystemInitializer(new Type[] { })] private static void Init() { UnityEngine.UI.Image saveImage = RoR2Application.instance.saveIconImage; RoR2Application.onUpdate += delegate { UnityEngine.Color color = saveImage.color; if (activeWriteCount <= 0) { color.a = (saveIconAlpha = Mathf.Max(saveIconAlpha - 4f * Time.unscaledDeltaTime, 0f)); } saveImage.color = color; }; } } public class FixedSizeArrayPool { public enum ClearType { RESET, CLEAR, NONE } private int _lengthOfArrays; [NotNull] private T[][] pooledArrays; private int count; public int lengthOfArrays { get { return _lengthOfArrays; } set { if (_lengthOfArrays != value) { ArrayUtils.Clear(pooledArrays, ref count); _lengthOfArrays = value; } } } public FixedSizeArrayPool(int lengthOfArrays) { _lengthOfArrays = lengthOfArrays; pooledArrays = Array.Empty(); } [NotNull] public T[] Request() { if (count <= 0) { return new T[_lengthOfArrays]; } T[] result = pooledArrays[--count]; pooledArrays[count] = null; return result; } [MethodImpl(MethodImplOptions.NoInlining)] [NotNull] private static ArgumentException CreateArraySizeMismatchException(int incomingArrayLength, int arrayPoolSizeRequirement) { return new ArgumentException($"Array of length {incomingArrayLength} may not be returned to pool for arrays of length {arrayPoolSizeRequirement}", "array"); } public void Return([NotNull] T[] array, ClearType clearType = ClearType.RESET) { if (array.Length != _lengthOfArrays) { throw CreateArraySizeMismatchException(array.Length, _lengthOfArrays); } switch (clearType) { case ClearType.RESET: { T[] array2 = array; T value = default(T); ArrayUtils.SetAll(array2, in value); break; } case ClearType.CLEAR: Array.Clear(array, 0, array.Length); break; } ArrayUtils.ArrayAppend(ref pooledArrays, ref count, in array); } } public class ForcePingable : MonoBehaviour { public bool bypassEntityLocator = true; } [CreateAssetMenu(menuName = "RoR2/DropTables/FreeChestDropTable")] public class FreeChestDropTable : PickupDropTable { [SerializeField] private float tier1Weight = 0.79f; [SerializeField] private float tier2Weight = 0.2f; [SerializeField] private float tier3Weight = 0.01f; private readonly WeightedSelection selector = new WeightedSelection(); private void Add(List sourceDropList, float listWeight) { if (listWeight <= 0f || sourceDropList.Count == 0) { return; } float weight = listWeight / (float)sourceDropList.Count; foreach (PickupIndex sourceDrop in sourceDropList) { selector.AddChoice(sourceDrop, weight); } } protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng) { int num = 0; foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if ((bool)instance.master) { int itemCount = instance.master.inventory.GetItemCount(DLC1Content.Items.FreeChest); num += itemCount; } } if (num <= 0) { num = 1; } selector.Clear(); Add(Run.instance.availableTier1DropList, tier1Weight); Add(Run.instance.availableTier2DropList, tier2Weight * (float)num); Add(Run.instance.availableTier3DropList, tier3Weight * Mathf.Pow(num, 2f)); return PickupDropTable.GenerateDropFromWeightedSelection(rng, selector); } public override int GetPickupCount() { return selector.Count; } protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng) { return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, selector); } } public static class FriendlyFireManager { public enum FriendlyFireMode { Off, FriendlyFire, FreeForAll } public static FriendlyFireMode friendlyFireMode = FriendlyFireMode.Off; public static float friendlyFireDamageScale { get; private set; } = 0.5f; public static bool ShouldSplashHitProceed(HealthComponent victim, TeamIndex attackerTeamIndex) { if (victim.body.teamComponent.teamIndex == attackerTeamIndex && friendlyFireMode == FriendlyFireMode.Off) { return attackerTeamIndex == TeamIndex.None; } return true; } public static bool ShouldDirectHitProceed(HealthComponent victim, TeamIndex attackerTeamIndex) { if (victim.body.teamComponent.teamIndex == attackerTeamIndex && friendlyFireMode == FriendlyFireMode.Off) { return attackerTeamIndex == TeamIndex.None; } return true; } public static bool ShouldSeekingProceed(HealthComponent victim, TeamIndex attackerTeamIndex) { if (victim.body.teamComponent.teamIndex == attackerTeamIndex && friendlyFireMode != FriendlyFireMode.FreeForAll) { return attackerTeamIndex == TeamIndex.None; } return true; } } public class AchievementGranter : NetworkBehaviour { private static int kRpcRpcGrantAchievement; [ClientRpc] public void RpcGrantAchievement(string achievementName) { foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList) { AchievementManager.GetUserAchievementManager(readOnlyLocalUsers).GrantAchievement(AchievementManager.GetAchievementDef(achievementName)); } } private void UNetVersion() { } protected static void InvokeRpcRpcGrantAchievement(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcGrantAchievement called on server."); } else { ((AchievementGranter)obj).RpcGrantAchievement(reader.ReadString()); } } public void CallRpcGrantAchievement(string achievementName) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcGrantAchievement called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcGrantAchievement); networkWriter.Write(GetComponent().netId); networkWriter.Write(achievementName); SendRPCInternal(networkWriter, 0, "RpcGrantAchievement"); } static AchievementGranter() { kRpcRpcGrantAchievement = -180752285; NetworkBehaviour.RegisterRpcDelegate(typeof(AchievementGranter), kRpcRpcGrantAchievement, InvokeRpcRpcGrantAchievement); NetworkCRC.RegisterBehaviour("AchievementGranter", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class AddCurvedTorque : MonoBehaviour { public AnimationCurve torqueCurve; public UnityEngine.Vector3 localTorqueVector; public float lifetime; public Rigidbody[] rigidbodies; private float stopwatch; private void FixedUpdate() { stopwatch += Time.fixedDeltaTime; float num = torqueCurve.Evaluate(stopwatch / lifetime); Rigidbody[] array = rigidbodies; for (int i = 0; i < array.Length; i++) { array[i].AddRelativeTorque(localTorqueVector * num); } } } [RequireComponent(typeof(Animator))] public class AimAnimator : MonoBehaviour, ILifeBehavior { public enum AimType { Direct, Smart } public class DirectionOverrideRequest : IDisposable { public readonly Func directionGetter; private Action disposeCallback; public DirectionOverrideRequest(Func getter, Action onDispose) { disposeCallback = onDispose; directionGetter = getter; } public void Dispose() { disposeCallback?.Invoke(this); disposeCallback = null; } } private struct AimAngles { public float pitch; public float yaw; } [Tooltip("The input bank component of the character.")] public InputBankTest inputBank; [Tooltip("The direction component of the character.")] public CharacterDirection directionComponent; [Tooltip("The minimum pitch supplied by the aiming animation.")] public float pitchRangeMin; [Tooltip("The maximum pitch supplied by the aiming animation.")] public float pitchRangeMax; [Tooltip("The minimum yaw supplied by the aiming animation.")] public float yawRangeMin; [Tooltip("The maximum yaw supplied by the aiming animation.")] public float yawRangeMax; [Tooltip("If the pitch is this many degrees beyond the range the aiming animations support, the character will return to neutral pose after waiting the giveup duration.")] public float pitchGiveupRange; [Tooltip("If the yaw is this many degrees beyond the range the aiming animations support, the character will return to neutral pose after waiting the giveup duration.")] public float yawGiveupRange; [Tooltip("If the pitch or yaw exceed the range supported by the aiming animations, the character will return to neutral pose after waiting this long.")] public float giveupDuration; [Tooltip("The speed in degrees/second to approach the desired pitch/yaw by while the weapon should be raised.")] public float raisedApproachSpeed = 720f; [Tooltip("The speed in degrees/second to approach the desired pitch/yaw by while the weapon should be lowered.")] public float loweredApproachSpeed = 360f; [Tooltip("The smoothing time for the motion.")] public float smoothTime = 0.1f; [Tooltip("Whether or not the character can do full 360 yaw turns.")] public bool fullYaw; [Tooltip("Switches between Direct (point straight at target) or Smart (only turn when outside angle range).")] public AimType aimType; [Tooltip("Assigns the weight of the aim from the center as an animator value 'aimWeight' between 0-1.")] public bool enableAimWeight; public bool UseTransformedAimVector; private Animator animatorComponent; private float pitchClipCycleEnd; private float yawClipCycleEnd; private float giveupTimer; private AimAngles localAnglesToAimVector; private AimAngles overshootAngles; private AimAngles clampedLocalAnglesToAimVector; private AimAngles currentLocalAngles; private AimAngles smoothingVelocity; private List directionOverrideRequests = new List(); private static readonly int aimPitchCycleHash = Animator.StringToHash("aimPitchCycle"); private static readonly int aimYawCycleHash = Animator.StringToHash("aimYawCycle"); private static readonly int aimWeightHash = Animator.StringToHash("aimWeight"); public bool isOutsideOfRange { get; private set; } private bool shouldGiveup => giveupTimer <= 0f; public DirectionOverrideRequest RequestDirectionOverride(Func getter) { DirectionOverrideRequest directionOverrideRequest = new DirectionOverrideRequest(getter, RemoveRequest); directionOverrideRequests.Add(directionOverrideRequest); return directionOverrideRequest; } private void RemoveRequest(DirectionOverrideRequest request) { directionOverrideRequests.Remove(request); } private void Awake() { animatorComponent = GetComponent(); } private void Start() { int layerIndex = animatorComponent.GetLayerIndex("AimPitch"); int layerIndex2 = animatorComponent.GetLayerIndex("AimYaw"); animatorComponent.Play("PitchControl", layerIndex); animatorComponent.Play("YawControl", layerIndex2); animatorComponent.Update(0f); AnimatorClipInfo[] currentAnimatorClipInfo = animatorComponent.GetCurrentAnimatorClipInfo(layerIndex); AnimatorClipInfo[] currentAnimatorClipInfo2 = animatorComponent.GetCurrentAnimatorClipInfo(layerIndex2); if (currentAnimatorClipInfo.Length != 0) { AnimationClip clip = currentAnimatorClipInfo[0].clip; double num = clip.length * clip.frameRate; pitchClipCycleEnd = (float)((num - 1.0) / num); } if (currentAnimatorClipInfo2.Length != 0) { AnimationClip clip2 = currentAnimatorClipInfo2[0].clip; _ = clip2.length; _ = clip2.frameRate; yawClipCycleEnd = 0.999f; } } private void Update() { if (!(Time.deltaTime <= 0f)) { UpdateLocalAnglesToAimVector(); UpdateGiveup(); ApproachDesiredAngles(); UpdateAnimatorParameters(animatorComponent, pitchRangeMin, pitchRangeMax, yawRangeMin, yawRangeMax); } } public void OnDeathStart() { base.enabled = false; currentLocalAngles = new AimAngles { pitch = 0f, yaw = 0f }; UpdateAnimatorParameters(animatorComponent, pitchRangeMin, pitchRangeMax, yawRangeMin, yawRangeMax); } private static float Remap(float value, float inMin, float inMax, float outMin, float outMax) { return outMin + (value - inMin) / (inMax - inMin) * (outMax - outMin); } private static float NormalizeAngle(float angle) { return Mathf.Repeat(angle + 180f, 360f) - 180f; } private void UpdateLocalAnglesToAimVector() { UnityEngine.Vector3 vector = ((directionOverrideRequests.Count <= 0) ? (inputBank ? inputBank.aimDirection : base.transform.forward) : directionOverrideRequests[directionOverrideRequests.Count - 1].directionGetter()); if (UseTransformedAimVector) { UnityEngine.Vector3 eulerAngles = Util.QuaternionSafeLookRotation(base.transform.InverseTransformDirection(vector), base.transform.up).eulerAngles; localAnglesToAimVector = new AimAngles { pitch = NormalizeAngle(eulerAngles.x), yaw = NormalizeAngle(eulerAngles.y) }; } else { float y = (directionComponent ? directionComponent.yaw : base.transform.eulerAngles.y); float x = (directionComponent ? directionComponent.transform.eulerAngles.x : base.transform.eulerAngles.x); float z = (directionComponent ? directionComponent.transform.eulerAngles.z : base.transform.eulerAngles.z); UnityEngine.Vector3 eulerAngles2 = Util.QuaternionSafeLookRotation(vector, base.transform.up).eulerAngles; UnityEngine.Vector3 vector2 = vector; UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(x, y, z); vector2.y = 0f; localAnglesToAimVector = new AimAngles { pitch = (0f - Mathf.Atan2(vector.y, vector2.magnitude)) * 57.29578f, yaw = NormalizeAngle(eulerAngles2.y - vector3.y) }; } overshootAngles = new AimAngles { pitch = Mathf.Max(pitchRangeMin - localAnglesToAimVector.pitch, localAnglesToAimVector.pitch - pitchRangeMax), yaw = Mathf.Max(Mathf.DeltaAngle(localAnglesToAimVector.yaw, yawRangeMin), Mathf.DeltaAngle(yawRangeMax, localAnglesToAimVector.yaw)) }; clampedLocalAnglesToAimVector = new AimAngles { pitch = Mathf.Clamp(localAnglesToAimVector.pitch, pitchRangeMin, pitchRangeMax), yaw = Mathf.Clamp(localAnglesToAimVector.yaw, yawRangeMin, yawRangeMax) }; } private void ApproachDesiredAngles() { AimAngles aimAngles2; float maxSpeed; if (shouldGiveup) { AimAngles aimAngles = default(AimAngles); aimAngles.pitch = 0f; aimAngles.yaw = 0f; aimAngles2 = aimAngles; maxSpeed = loweredApproachSpeed; } else { aimAngles2 = clampedLocalAnglesToAimVector; maxSpeed = raisedApproachSpeed; } float yaw = ((!fullYaw) ? Mathf.SmoothDamp(currentLocalAngles.yaw, aimAngles2.yaw, ref smoothingVelocity.yaw, smoothTime, maxSpeed, Time.deltaTime) : NormalizeAngle(Mathf.SmoothDampAngle(currentLocalAngles.yaw, aimAngles2.yaw, ref smoothingVelocity.yaw, smoothTime, maxSpeed, Time.deltaTime))); currentLocalAngles = new AimAngles { pitch = Mathf.SmoothDampAngle(currentLocalAngles.pitch, aimAngles2.pitch, ref smoothingVelocity.pitch, smoothTime, maxSpeed, Time.deltaTime), yaw = yaw }; } private void ResetGiveup() { giveupTimer = giveupDuration; } private void UpdateGiveup() { if (overshootAngles.pitch > pitchGiveupRange || (!fullYaw && overshootAngles.yaw > yawGiveupRange)) { giveupTimer -= Time.deltaTime; isOutsideOfRange = true; } else { isOutsideOfRange = false; ResetGiveup(); } } public void AimImmediate() { UpdateLocalAnglesToAimVector(); ResetGiveup(); currentLocalAngles = clampedLocalAnglesToAimVector; smoothingVelocity = new AimAngles { pitch = 0f, yaw = 0f }; UpdateAnimatorParameters(animatorComponent, pitchRangeMin, pitchRangeMax, yawRangeMin, yawRangeMax); } public void UpdateAnimatorParameters(Animator animator, float pitchRangeMin, float pitchRangeMax, float yawRangeMin, float yawRangeMax) { float num = 1f; if (enableAimWeight) { num = animatorComponent.GetFloat(aimWeightHash); } animator.SetFloat(aimPitchCycleHash, Remap(currentLocalAngles.pitch * num, pitchRangeMin, pitchRangeMax, pitchClipCycleEnd, 0f)); animator.SetFloat(aimYawCycleHash, Remap(currentLocalAngles.yaw * num, yawRangeMin, yawRangeMax, 0f, yawClipCycleEnd)); } } public class AimAssistTarget : MonoBehaviour { public Transform point0; public Transform point1; public float assistScale = 1f; public HealthComponent healthComponent; public TeamComponent teamComponent; public static List instancesList = new List(); public static FloatConVar debugAimAssistVisualCoefficient = new FloatConVar("debug_aim_assist_visual_coefficient", ConVarFlags.None, "2", "Magic for debug visuals. Don't touch."); private void OnEnable() { instancesList.Add(this); } private void OnDisable() { instancesList.Remove(this); } private void FixedUpdate() { MyFixedUpdate(Time.fixedDeltaTime); } private void MyFixedUpdate(float deltaTime) { if ((bool)healthComponent && !healthComponent.alive) { UnityEngine.Object.Destroy(base.gameObject); } } private void OnDrawGizmos() { if ((bool)point0) { Gizmos.color = UnityEngine.Color.red; Gizmos.DrawWireSphere(point0.position, 1f * assistScale * CameraRigController.aimStickAssistMinSize.value * debugAimAssistVisualCoefficient.value); Gizmos.color = UnityEngine.Color.white; Gizmos.DrawWireSphere(point0.position, 1f * assistScale * CameraRigController.aimStickAssistMaxSize.value * CameraRigController.aimStickAssistMinSize.value * debugAimAssistVisualCoefficient.value); } if ((bool)point1) { Gizmos.color = UnityEngine.Color.red; Gizmos.DrawWireSphere(point1.position, 1f * assistScale * CameraRigController.aimStickAssistMinSize.value * debugAimAssistVisualCoefficient.value); Gizmos.color = UnityEngine.Color.white; Gizmos.DrawWireSphere(point1.position, 1f * assistScale * CameraRigController.aimStickAssistMaxSize.value * CameraRigController.aimStickAssistMinSize.value * debugAimAssistVisualCoefficient.value); } if ((bool)point0 && (bool)point1) { Gizmos.DrawLine(point0.position, point1.position); } } } public class AimTurnStateController : MonoBehaviour { [Tooltip("The component we use to determine the current orientation")] [SerializeField] private CharacterDirection characterDirection; [SerializeField] [Tooltip("The component we use to determine the current aim")] private InputBankTest inputBank; [SerializeField] [Tooltip("The state machine we should modify")] private EntityStateMachine targetStateMachine; [SerializeField] [Tooltip("The state we should push")] private SerializableEntityStateType turnStateType; [SerializeField] [Tooltip("The priority of the new state")] private InterruptPriority interruptPriority; [SerializeField] [Tooltip("The minimum difference between the current orientation and the aim before we should push the state")] private float minTriggerDegrees; [SerializeField] [Tooltip("The minimum time before we should push the state again")] private float retriggerDelaySeconds; [Tooltip("The aim/direction vectors are multiplied by this vector and normalized before comparison. This can be used to exclude a dimension from the calculation.")] [SerializeField] private UnityEngine.Vector3 aimScale = new UnityEngine.Vector3(1f, 1f, 1f); private float lastTriggerTime; private void FixedUpdate() { if (!(Run.instance.fixedTime - lastTriggerTime > retriggerDelaySeconds)) { return; } UnityEngine.Vector3 aimDirection = inputBank.aimDirection; aimDirection.Scale(aimScale); aimDirection.Normalize(); UnityEngine.Vector3 forward = characterDirection.forward; forward.Scale(aimScale); forward.Normalize(); if (UnityEngine.Vector3.Angle(aimDirection, forward) > minTriggerDegrees) { lastTriggerTime = Run.instance.fixedTime; if ((bool)targetStateMachine) { EntityState newNextState = EntityStateCatalog.InstantiateState(ref turnStateType); targetStateMachine.SetInterruptState(newNextState, interruptPriority); } } } } public class AlignToNormal : MonoBehaviour { [Tooltip("The amount to raycast down from.")] public float maxDistance; [Tooltip("The amount to pull the object out of the ground initially to test.")] public float offsetDistance; [Tooltip("Send to floor only - don't change normals.")] public bool changePositionOnly; private void Start() { if (Physics.Raycast(base.transform.position + base.transform.up * offsetDistance, -base.transform.up, out var hitInfo, maxDistance, LayerIndex.world.mask)) { base.transform.position = hitInfo.point; if (!changePositionOnly) { base.transform.up = hitInfo.normal; } } } } [RequireComponent(typeof(Rigidbody))] public class AllPlayersTrigger : MonoBehaviour { public UnityEvent onTriggerStart; public UnityEvent onTriggerEnd; private Queue collisionQueueServer; private bool triggerActiveServer; private void Awake() { if (NetworkServer.active) { collisionQueueServer = new Queue(); triggerActiveServer = false; } } private void OnEnable() { if (!NetworkServer.active) { base.enabled = false; } } private void OnTriggerStay(Collider other) { if (base.enabled) { collisionQueueServer.Enqueue(other); } } private void FixedUpdate() { if (!Run.instance) { return; } int num = 0; List list = CollectionPool>.RentCollection(); while (collisionQueueServer.Count > 0) { Collider collider = collisionQueueServer.Dequeue(); if ((bool)collider) { CharacterBody component = collider.GetComponent(); if ((bool)component && component.isPlayerControlled && !list.Contains(component)) { list.Add(component); num++; } } } CollectionPool>.ReturnCollection(list); bool flag = num == Run.instance.livingPlayerCount && num != 0; if (triggerActiveServer != flag) { triggerActiveServer = flag; (triggerActiveServer ? onTriggerStart : onTriggerEnd)?.Invoke(); } } } public class AmmoPickup : MonoBehaviour { [Tooltip("The base object to destroy when this pickup is consumed.")] public GameObject baseObject; [Tooltip("The team filter object which determines who can pick up this pack.")] public TeamFilter teamFilter; public GameObject pickupEffect; private bool alive = true; private void OnTriggerStay(Collider other) { if (NetworkServer.active && alive && TeamComponent.GetObjectTeam(other.gameObject) == teamFilter.teamIndex) { SkillLocator component = other.GetComponent(); if ((bool)component) { alive = false; component.ApplyAmmoPack(); EffectManager.SimpleEffect(pickupEffect, base.transform.position, UnityEngine.Quaternion.identity, transmit: true); UnityEngine.Object.Destroy(baseObject); } } } } [RequireComponent(typeof(CharacterModel))] public class AncientWispFireController : MonoBehaviour { public ParticleSystem normalParticles; public Light normalLight; public ParticleSystem rageParticles; public Light rageLight; private CharacterModel characterModel; private void Awake() { characterModel = GetComponent(); } private void Update() { bool flag = false; CharacterBody body = characterModel.body; if ((bool)body) { flag = body.HasBuff(JunkContent.Buffs.EnrageAncientWisp); } if ((bool)normalParticles) { ParticleSystem.EmissionModule emission = normalParticles.emission; if (emission.enabled == flag) { emission.enabled = !flag; if (!flag) { normalParticles.Play(); } } } if ((bool)rageParticles) { ParticleSystem.EmissionModule emission2 = rageParticles.emission; if (emission2.enabled != flag) { emission2.enabled = flag; if (flag) { rageParticles.Play(); } } } if ((bool)normalLight) { normalLight.enabled = !flag; } if ((bool)rageLight) { rageLight.enabled = flag; } } } public class AnimateImageAlpha : MonoBehaviour { public AnimationCurve alphaCurve; public UnityEngine.UI.Image[] images; public float timeMax = 5f; public float delayBetweenElements; [HideInInspector] public float stopwatch; private void OnEnable() { stopwatch = 0f; } public void ResetStopwatch() { stopwatch = 0f; } private void LateUpdate() { stopwatch += Time.unscaledDeltaTime; int num = 0; UnityEngine.UI.Image[] array = images; foreach (UnityEngine.UI.Image obj in array) { num++; float a = alphaCurve.Evaluate((stopwatch + delayBetweenElements * (float)num) / timeMax); UnityEngine.Color color = obj.color; obj.color = new UnityEngine.Color(color.r, color.g, color.b, a); } } } public class AnimateShaderAlpha : MonoBehaviour { public AnimationCurve alphaCurve; private Renderer targetRenderer; private MaterialPropertyBlock _propBlock; private Material[] materials; public float timeMax = 5f; [Tooltip("Optional field if you want to animate Decal 'Fade' rather than renderer _ExternalAlpha.")] public Decal decal; public bool pauseTime; public bool destroyOnEnd; public bool disableOnEnd; [HideInInspector] public float time; private float initialFade; [HideInInspector] public bool initialyEnabled; [HideInInspector] public UnityEvent OnFinished; public bool continueExistingAfterTimeMaxIsReached; private bool initialised; private void Start() { Initialise(); } private void Initialise() { if (!initialised) { targetRenderer = GetComponent(); if ((bool)targetRenderer) { materials = targetRenderer.materials; } if ((bool)decal) { initialFade = decal.Fade; } initialised = true; } } public void Reset() { Initialise(); time = 0f; if ((bool)decal) { decal.Fade = initialFade; } else { Material[] array = materials; for (int i = 0; i < array.Length; i++) { _ = array[i]; _propBlock = new MaterialPropertyBlock(); targetRenderer.GetPropertyBlock(_propBlock); _propBlock.SetFloat("_ExternalAlpha", 1f); targetRenderer.SetPropertyBlock(_propBlock); } } base.enabled = initialyEnabled; } private void OnDestroy() { OnFinished.RemoveAllListeners(); } private void Update() { if (!pauseTime) { time = Mathf.Min(timeMax, time + Time.deltaTime); } float num = alphaCurve.Evaluate(time / timeMax); if ((bool)decal) { decal.Fade = num * initialFade; } else { Material[] array = materials; for (int i = 0; i < array.Length; i++) { _ = array[i]; _propBlock = new MaterialPropertyBlock(); targetRenderer.GetPropertyBlock(_propBlock); _propBlock.SetFloat("_ExternalAlpha", num); targetRenderer.SetPropertyBlock(_propBlock); } } if (time >= timeMax) { OnFinished?.Invoke(); if (disableOnEnd) { base.enabled = false; } if (destroyOnEnd) { UnityEngine.Object.Destroy(base.gameObject); } } } } public class AnimationEvents : MonoBehaviour { public GameObject soundCenter; private GameObject bodyObject; private CharacterModel characterModel; private ChildLocator childLocator; private EntityLocator entityLocator; private Renderer meshRenderer; private ModelLocator modelLocator; private float printHeight; private float printTime; private void Start() { childLocator = GetComponent(); entityLocator = GetComponent(); meshRenderer = GetComponentInChildren(); characterModel = GetComponent(); if ((bool)characterModel && (bool)characterModel.body) { bodyObject = characterModel.body.gameObject; modelLocator = bodyObject.GetComponent(); } } public void UpdateIKState(AnimationEvent animationEvent) { childLocator.FindChild(animationEvent.stringParameter).GetComponent()?.UpdateIKState(animationEvent.intParameter); } public void PlaySound(string soundString) { Util.PlaySound(soundString, soundCenter ? soundCenter : bodyObject); } public void NormalizeToFloor() { if ((bool)modelLocator) { modelLocator.normalizeToFloor = true; } } public void SetIK(AnimationEvent animationEvent) { if ((bool)modelLocator && (bool)modelLocator.modelTransform) { bool flag = ((animationEvent.intParameter != 0) ? true : false); InverseKinematics component = modelLocator.modelTransform.GetComponent(); StriderLegController component2 = modelLocator.modelTransform.GetComponent(); if ((bool)component) { component.enabled = flag; } if ((bool)component2) { component2.enabled = flag; } } } public void RefreshAllIK() { IKTargetPassive[] componentsInChildren = GetComponentsInChildren(); foreach (IKTargetPassive obj in componentsInChildren) { obj.UpdateIKTargetPosition(); obj.UpdateYOffset(); } } public void CreateEffect(AnimationEvent animationEvent) { Transform transform = base.transform; int num = -1; if (!string.IsNullOrEmpty(animationEvent.stringParameter)) { num = childLocator.FindChildIndex(animationEvent.stringParameter); if (num != -1) { transform = childLocator.FindChild(num); } } bool transmit = animationEvent.intParameter != 0; EffectData effectData = new EffectData(); effectData.origin = transform.position; effectData.SetChildLocatorTransformReference(bodyObject, num); EffectManager.SpawnEffect((GameObject)animationEvent.objectReferenceParameter, effectData, transmit); } public void CreatePrefab(AnimationEvent animationEvent) { GameObject gameObject = (GameObject)animationEvent.objectReferenceParameter; bool flag = EffectManager.ShouldUsePooledEffect(gameObject); string stringParameter = animationEvent.stringParameter; Transform transform = base.transform; int intParameter = animationEvent.intParameter; if ((bool)childLocator) { Transform transform2 = childLocator.FindChild(stringParameter); if ((bool)transform2) { if (intParameter == 0) { if (!flag) { UnityEngine.Object.Instantiate(gameObject, transform2.position, UnityEngine.Quaternion.identity); } else { EffectManager.GetAndActivatePooledEffect(gameObject, transform2.position, UnityEngine.Quaternion.identity); } } else if (!flag) { UnityEngine.Object.Instantiate(gameObject, transform2.position, transform2.rotation).transform.parent = transform2; } else { EffectManager.GetAndActivatePooledEffect(gameObject, transform2.position, transform2.rotation, transform2); } } else if ((bool)gameObject) { if (!flag) { UnityEngine.Object.Instantiate(gameObject, transform.position, transform.rotation); } else { EffectManager.GetAndActivatePooledEffect(gameObject, transform.position, transform.rotation); } } } else if ((bool)gameObject) { if (!flag) { UnityEngine.Object.Instantiate(gameObject, transform.position, transform.rotation); } else { EffectManager.GetAndActivatePooledEffect(gameObject, transform.position, transform.rotation); } } } public void ItemDrop() { if (NetworkServer.active && (bool)entityLocator) { IChestBehavior component = entityLocator.entity.GetComponent(); if ((bool)(Component)component) { component.ItemDrop(); } } } public void BeginPrint(AnimationEvent animationEvent) { if ((bool)meshRenderer) { Material material = (Material)animationEvent.objectReferenceParameter; float floatParameter = animationEvent.floatParameter; float maxPrintHeight = animationEvent.intParameter; meshRenderer.material = material; printTime = 0f; MaterialPropertyBlock printPropertyBlock = new MaterialPropertyBlock(); StartCoroutine(startPrint(floatParameter, maxPrintHeight, printPropertyBlock)); } } private IEnumerator startPrint(float maxPrintTime, float maxPrintHeight, MaterialPropertyBlock printPropertyBlock) { if ((bool)meshRenderer) { while (printHeight < maxPrintHeight) { printTime += Time.deltaTime; printHeight = printTime / maxPrintTime * maxPrintHeight; meshRenderer.GetPropertyBlock(printPropertyBlock); printPropertyBlock.Clear(); printPropertyBlock.SetFloat("_SliceHeight", printHeight); meshRenderer.SetPropertyBlock(printPropertyBlock); yield return new WaitForEndOfFrame(); } } } public void SetChildEnable(AnimationEvent animationEvent) { string stringParameter = animationEvent.stringParameter; bool active = animationEvent.intParameter > 0; if ((bool)childLocator) { Transform transform = childLocator.FindChild(stringParameter); if ((bool)transform) { transform.gameObject.SetActive(active); } } } public void SwapMaterial(AnimationEvent animationEvent) { Material material = (Material)animationEvent.objectReferenceParameter; if ((bool)meshRenderer) { meshRenderer.material = material; } } } [RequireComponent(typeof(Rigidbody))] public class AntiGravityForce : MonoBehaviour { public Rigidbody rb; [Tooltip("How much to oppose gravity. A value of 1 means it is unaffected by gravity.")] public float antiGravityCoefficient; private void FixedUpdate() { rb.AddForce(-Physics.gravity * antiGravityCoefficient, ForceMode.Acceleration); } } public class ApplyForceOnStart : MonoBehaviour { public UnityEngine.Vector3 localForce; private void Start() { Rigidbody component = GetComponent(); if ((bool)component) { component.AddRelativeForce(localForce); } } } public class ApplyJiggleBoneMotion : MonoBehaviour { public float forceScale = 100f; public Transform rootTransform; public Rigidbody[] rigidbodies; private UnityEngine.Vector3 lastRootPosition; private void FixedUpdate() { UnityEngine.Vector3 position = rootTransform.position; Rigidbody[] array = rigidbodies; for (int i = 0; i < array.Length; i++) { array[i].AddForce((lastRootPosition - position) * forceScale * Time.fixedDeltaTime); } lastRootPosition = position; } } public class ApplyTorqueOnStart : MonoBehaviour { public UnityEngine.Vector3 localTorque; public bool randomize; private void Start() { Rigidbody component = GetComponent(); if ((bool)component) { UnityEngine.Vector3 torque = localTorque; if (randomize) { torque.x = UnityEngine.Random.Range((0f - torque.x) / 2f, torque.x / 2f); torque.y = UnityEngine.Random.Range((0f - torque.y) / 2f, torque.y / 2f); torque.z = UnityEngine.Random.Range((0f - torque.z) / 2f, torque.z / 2f); } component.AddRelativeTorque(torque); } } } [RequireComponent(typeof(EntityStateMachine))] [RequireComponent(typeof(Inventory))] public class ArenaMissionController : NetworkBehaviour { public class ArenaMissionBaseState : EntityState { protected ArenaMissionController arenaMissionController => instance; } public class MissionCompleted : ArenaMissionBaseState { public override void OnEnter() { base.OnEnter(); base.arenaMissionController.clearedEffect.SetActive(value: true); } } [Serializable] public struct MonsterItemStackData { public PickupDropTable dropTable; public int stacks; } [Header("Behavior Values")] public float baseMonsterCredit; public float creditMultiplierPerRound; public int minimumNumberToSpawnPerMonsterType; public int totalRoundsMax; public int maximumNumberToSpawnBeforeSkipping; public float spawnDistanceMultiplier; public float eliteBias; [Header("Cached Components")] public GameObject[] nullWards; public GameObject monsterSpawnPosition; public GameObject rewardSpawnPosition; public CombatDirector[] combatDirectors; public GameObject clearedEffect; public GameObject killEffectPrefab; public GameObject fogDamagePrefab; public PortalSpawner[] completionPortalSpawners; public MonsterItemStackData[] monsterItemStackOrder; public PickupDropTable[] playerRewardOrder; [SerializeField] private int numRewardOptions; [SerializeField] private GameObject pickupPrefab; private EntityStateMachine mainStateMachine; private Xoroshiro128Plus rng; private List activeMonsterCards = new List(); public readonly SyncListInt syncActiveMonsterBodies = new SyncListInt(); private WeightedSelection availableMonsterCards; private float cachedDifficultyCoefficient; [SyncVar] private int _clearedRounds; private int nextItemStackIndex; private GameObject fogDamageInstance; private static int kListsyncActiveMonsterBodies; public int currentRound { get; private set; } public int clearedRounds { get { return _clearedRounds; } private set { Network_clearedRounds = value; } } public static ArenaMissionController instance { get; private set; } private float creditsThisRound => (baseMonsterCredit + creditMultiplierPerRound * (float)(currentRound - 1)) * cachedDifficultyCoefficient; public Inventory inventory { get; private set; } public int Network_clearedRounds { get { return _clearedRounds; } [param: In] set { SetSyncVar(value, ref _clearedRounds, 2u); } } public static event Action onBeatArena; public static event Action onInstanceChangedGlobal; private void Awake() { mainStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Main"); inventory = GetComponent(); syncActiveMonsterBodies.InitializeBehaviour(this, kListsyncActiveMonsterBodies); } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); ArenaMissionController.onInstanceChangedGlobal?.Invoke(); SceneDirector.onPreGeneratePlayerSpawnPointsServer += OnPreGeneratePlayerSpawnPointsServer; } private void OnDisable() { SceneDirector.onPreGeneratePlayerSpawnPointsServer -= OnPreGeneratePlayerSpawnPointsServer; instance = SingletonHelper.Unassign(instance, this); ArenaMissionController.onInstanceChangedGlobal?.Invoke(); } private void OnPreGeneratePlayerSpawnPointsServer(SceneDirector sceneDirector, ref Action generationMethod) { generationMethod = GeneratePlayerSpawnPointsServer; } private void GeneratePlayerSpawnPointsServer() { if (nullWards.Length == 0) { return; } UnityEngine.Vector3 position = nullWards[0].transform.position; NodeGraph groundNodes = SceneInfo.instance.groundNodes; NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(SceneInfo.instance.groundNodes, HullMask.Human); nodeGraphSpider.AddNodeForNextStep(groundNodes.FindClosestNode(position, HullClassification.Human)); for (int i = 0; i < 4; i++) { nodeGraphSpider.PerformStep(); if (nodeGraphSpider.collectedSteps.Count > 16) { break; } } for (int j = 0; j < nodeGraphSpider.collectedSteps.Count; j++) { NodeGraphSpider.StepInfo stepInfo = nodeGraphSpider.collectedSteps[j]; SpawnPoint.AddSpawnPoint(groundNodes, stepInfo.node, rng); } } [Server] public override void OnStartServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::OnStartServer()' called on client"); return; } base.OnStartServer(); fogDamageInstance = UnityEngine.Object.Instantiate(fogDamagePrefab); FogDamageController component = fogDamageInstance.GetComponent(); GameObject[] array = nullWards; foreach (GameObject gameObject in array) { component.AddSafeZone(gameObject.GetComponent()); } NetworkServer.Spawn(fogDamageInstance); cachedDifficultyCoefficient = Run.instance.difficultyCoefficient; rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint); InitCombatDirectors(); Util.ShuffleArray(nullWards, rng); ReadyNextNullWard(); availableMonsterCards = Util.CreateReasonableDirectorCardSpawnList(baseMonsterCredit * cachedDifficultyCoefficient, maximumNumberToSpawnBeforeSkipping, minimumNumberToSpawnPerMonsterType); _ = availableMonsterCards.Count; } [Server] private void ReadyNextNullWard() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::ReadyNextNullWard()' called on client"); return; } if (currentRound > nullWards.Length) { UnityEngine.Debug.LogError("Out of null wards! Aborting."); return; } EntityStateMachine component = nullWards[currentRound].GetComponent(); component.initialStateType = new SerializableEntityStateType(typeof(WardOnAndReady)); component.SetNextState(new WardOnAndReady()); } [Server] private void InitCombatDirectors() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::InitCombatDirectors()' called on client"); return; } for (int i = 0; i < combatDirectors.Length; i++) { CombatDirector obj = combatDirectors[i]; obj.maximumNumberToSpawnBeforeSkipping = maximumNumberToSpawnBeforeSkipping; obj.onSpawnedServer.AddListener(ModifySpawnedMasters); obj.spawnDistanceMultiplier = spawnDistanceMultiplier; obj.eliteBias = eliteBias; } } [Server] public void BeginRound() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::BeginRound()' called on client"); return; } currentRound++; switch (currentRound) { case 1: AddMonsterType(); break; case 2: AddItemStack(); break; case 3: AddMonsterType(); break; case 4: AddItemStack(); break; case 5: AddMonsterType(); break; case 6: AddItemStack(); break; case 7: AddMonsterType(); break; case 8: AddItemStack(); break; case 9: AddItemStack(); break; } int count = activeMonsterCards.Count; for (int i = 0; i < count; i++) { DirectorCard directorCard = activeMonsterCards[i]; float num = creditsThisRound / (float)count; float creditMultiplier = creditMultiplierPerRound * (float)currentRound / (float)count; if (i > combatDirectors.Length) { UnityEngine.Debug.LogError("Trying to activate more combat directors than available. Aborting."); break; } CombatDirector obj = combatDirectors[i]; obj.monsterCredit += num; obj.creditMultiplier = creditMultiplier; obj.currentSpawnTarget = monsterSpawnPosition; obj.OverrideCurrentMonsterCard(directorCard); obj.monsterSpawnTimer = 0f; obj.enabled = true; UnityEngine.Debug.LogFormat("Enabling director {0} with {1} credits to spawn {2}", i, num, directorCard.spawnCard.name); } } [Server] public void ModifySpawnedMasters(GameObject targetGameObject) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::ModifySpawnedMasters(UnityEngine.GameObject)' called on client"); return; } CharacterMaster component = targetGameObject.GetComponent(); BaseAI ai = component.GetComponent(); if ((bool)ai) { ai.onBodyDiscovered += OnBodyDiscovered; } CharacterBody body = component.GetBody(); if ((bool)body) { EntityStateMachine[] components = body.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } } component.inventory.AddItemsFrom(inventory); void OnBodyDiscovered(CharacterBody newBody) { ai.ForceAcquireNearestEnemyIfNoCurrentEnemy(); ai.onBodyDiscovered -= OnBodyDiscovered; } } [Server] public void EndRound() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::EndRound()' called on client"); return; } clearedRounds++; if (currentRound < totalRoundsMax) { ReadyNextNullWard(); } else { if ((bool)fogDamageInstance) { UnityEngine.Object.Destroy(fogDamageInstance); fogDamageInstance = null; } ArenaMissionController.onBeatArena?.Invoke(); mainStateMachine.SetNextState(new MissionCompleted()); Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = "ARENA_END" }); PortalSpawner[] array = completionPortalSpawners; for (int i = 0; i < array.Length; i++) { array[i].AttemptSpawnPortalServer(); } } for (int j = 0; j < combatDirectors.Length; j++) { CombatDirector obj = combatDirectors[j]; obj.enabled = false; obj.monsterCredit = 0f; } ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Monster); for (int num = teamMembers.Count - 1; num >= 0; num--) { teamMembers[num].body.healthComponent.Suicide(base.gameObject, base.gameObject, DamageType.VoidDeath); } int participatingPlayerCount = Run.instance.participatingPlayerCount; if (participatingPlayerCount == 0 || !rewardSpawnPosition) { return; } PickupIndex[] array2 = Array.Empty(); int num2 = currentRound - 1; if (num2 < playerRewardOrder.Length) { array2 = playerRewardOrder[num2]?.GenerateUniqueDrops(numRewardOptions, rng); } if (array2.Length != 0) { ItemTier itemTier = PickupCatalog.GetPickupDef(array2[0]).itemTier; int num3 = participatingPlayerCount; float angle = 360f / (float)num3; UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); int num4 = 0; while (num4 < num3) { GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo); createPickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromArray(array2); createPickupInfo.prefabOverride = pickupPrefab; createPickupInfo.position = rewardSpawnPosition.transform.position; createPickupInfo.rotation = UnityEngine.Quaternion.identity; createPickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(itemTier); GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo; PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, vector); num4++; vector = quaternion * vector; } } } [Server] private void AddMonsterType() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::AddMonsterType()' called on client"); } else if (availableMonsterCards.Count != 0) { int num = availableMonsterCards.EvaluateToChoiceIndex(rng.nextNormalizedFloat); DirectorCard value = availableMonsterCards.choices[num].value; activeMonsterCards.Add(value); syncActiveMonsterBodies.Add((int)(value.spawnCard.prefab.GetComponent()?.bodyPrefab.GetComponent()?.bodyIndex ?? BodyIndex.None)); availableMonsterCards.RemoveChoice(num); CharacterBody component = value.spawnCard.prefab.GetComponent().bodyPrefab.GetComponent(); Chat.SubjectFormatChatMessage subjectFormatChatMessage = new Chat.SubjectFormatChatMessage(); subjectFormatChatMessage.baseToken = "ARENA_ADD_MONSTER"; subjectFormatChatMessage.paramTokens = new string[1] { component.baseNameToken }; Chat.SendBroadcastChat(subjectFormatChatMessage); } } [Server] private void AddItemStack() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::AddItemStack()' called on client"); return; } PickupIndex pickupIndex = PickupIndex.none; if (nextItemStackIndex < monsterItemStackOrder.Length) { PickupDropTable dropTable = monsterItemStackOrder[nextItemStackIndex].dropTable; if ((bool)dropTable) { pickupIndex = dropTable.GenerateDrop(rng); } } if (pickupIndex != PickupIndex.none) { PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); ItemIndex itemIndex = pickupDef.itemIndex; inventory.GiveItem(itemIndex, monsterItemStackOrder[nextItemStackIndex].stacks); Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage { baseToken = "ARENA_ADD_ITEM", pickupToken = pickupDef.nameToken, pickupColor = pickupDef.baseColor }); } nextItemStackIndex++; } private void UNetVersion() { } protected static void InvokeSyncListsyncActiveMonsterBodies(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("SyncList syncActiveMonsterBodies called on server."); } else { ((ArenaMissionController)obj).syncActiveMonsterBodies.HandleMsg(reader); } } static ArenaMissionController() { kListsyncActiveMonsterBodies = 1496902198; NetworkBehaviour.RegisterSyncListDelegate(typeof(ArenaMissionController), kListsyncActiveMonsterBodies, InvokeSyncListsyncActiveMonsterBodies); NetworkCRC.RegisterBehaviour("ArenaMissionController", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { SyncListInt.WriteInstance(writer, syncActiveMonsterBodies); writer.WritePackedUInt32((uint)_clearedRounds); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } SyncListInt.WriteInstance(writer, syncActiveMonsterBodies); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)_clearedRounds); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { SyncListInt.ReadReference(reader, syncActiveMonsterBodies); _clearedRounds = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { SyncListInt.ReadReference(reader, syncActiveMonsterBodies); } if (((uint)num & 2u) != 0) { _clearedRounds = (int)reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public class ArtifactEnabledResponse : MonoBehaviour { public ArtifactDef artifact; public UnityEvent onDiscoveredArtifactEnabled; public UnityEvent onLostArtifactEnabled; private bool _active; private bool active { get { return _active; } set { if (_active != value) { _active = value; if (active) { onDiscoveredArtifactEnabled?.Invoke(); } else { onLostArtifactEnabled?.Invoke(); } } } } private void OnEnable() { RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabledGlobal; RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabledGlobal; active = RunArtifactManager.instance.IsArtifactEnabled(artifact); } private void OnDisable() { active = false; RunArtifactManager.onArtifactDisabledGlobal -= OnArtifactDisabledGlobal; RunArtifactManager.onArtifactEnabledGlobal -= OnArtifactEnabledGlobal; } private void OnArtifactEnabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef) { if (!(artifactDef != artifact)) { active = true; } } private void OnArtifactDisabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef) { if (!(artifactDef != artifact)) { active = false; } } } public class ArtifactEnabler : MonoBehaviour { [SerializeField] private ArtifactDef artifactDef; private bool artifactWasEnabled; private void OnEnable() { if (NetworkServer.active && (bool)artifactDef) { artifactWasEnabled = RunArtifactManager.instance.IsArtifactEnabled(artifactDef); RunArtifactManager.instance.SetArtifactEnabledServer(artifactDef, newEnabled: true); } } private void OnDisable() { if (NetworkServer.active && (bool)artifactDef && (bool)RunArtifactManager.instance) { RunArtifactManager.instance.SetArtifactEnabledServer(artifactDef, artifactWasEnabled); } } } public class ArtifactFormulaDisplay : MonoBehaviour { [Serializable] public struct ArtifactCompoundDisplayInfo { public ArtifactCompoundDef artifactCompoundDef; public Decal decal; } public ArtifactCompoundDisplayInfo[] artifactCompoundDisplayInfos; private void Start() { ArtifactCompoundDisplayInfo[] array = artifactCompoundDisplayInfos; for (int i = 0; i < array.Length; i++) { ArtifactCompoundDisplayInfo artifactCompoundDisplayInfo = array[i]; artifactCompoundDisplayInfo.decal.Material = artifactCompoundDisplayInfo.artifactCompoundDef.decalMaterial; } } } public class ArtifactTrialMissionController : NetworkBehaviour { private class ArtifactTrialMissionControllerBaseState : EntityState { protected ArtifactTrialMissionController missionController { get; private set; } protected virtual bool shouldEnableCombatDirector => false; protected virtual bool shouldEnableBossGroup => false; protected virtual bool shouldAllowMonsters => shouldEnableCombatDirector; public override void OnEnter() { base.OnEnter(); missionController = GetComponent(); if (NetworkServer.active) { CombatDirector[] combatDirectors = missionController.combatDirectors; for (int i = 0; i < combatDirectors.Length; i++) { combatDirectors[i].enabled = shouldEnableCombatDirector; } if (!shouldAllowMonsters) { for (int num = CharacterMaster.readOnlyInstancesList.Count - 1; num >= 0; num--) { CharacterMaster characterMaster = CharacterMaster.readOnlyInstancesList[num]; if (characterMaster.teamIndex == TeamIndex.Monster && (object)characterMaster != missionController.artifactShellMaster) { characterMaster.TrueKill(); } } } } if ((bool)missionController.bossGroup) { missionController.bossGroup.enabled = shouldEnableBossGroup; } } public override void OnExit() { missionController = null; base.OnExit(); } } private class WaitForPlayersState : ArtifactTrialMissionControllerBaseState { public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && NetworkUser.AllParticipatingNetworkUsersReady()) { outer.SetNextState(new IntroState()); } } public override void OnEnter() { base.OnEnter(); FadeToBlackManager.fadeCount++; FadeToBlackManager.ForceFullBlack(); } public override void OnExit() { FadeToBlackManager.fadeCount--; base.OnExit(); } } private class IntroState : ArtifactTrialMissionControllerBaseState { private ForcedCamera cameraController; public override void OnEnter() { base.OnEnter(); cameraController = base.missionController?.introCameraController; if ((bool)cameraController) { cameraController.gameObject.SetActive(value: true); } } public override void OnExit() { if ((bool)cameraController) { cameraController.enabled = false; cameraController = null; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && !cameraController.enabled) { outer.SetNextState(new SetupState()); } } } private class SetupState : ArtifactTrialMissionControllerBaseState { public static float delayBeforePushingNotification; private float keyRespawnTimer; private GameObject keyPickupInstance; private bool pushedNotification; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active) { CharacterBody body = base.missionController.artifactShellMaster.GetBody(); if (!body || body.healthComponent.combinedHealthFraction < 1f) { outer.SetNextState(new PreCombatState()); return; } if (!keyPickupInstance) { keyRespawnTimer -= Time.deltaTime; if (keyRespawnTimer < 0f) { keyRespawnTimer = 30f; GenericPickupController.CreatePickupInfo createPickupInfo = new GenericPickupController.CreatePickupInfo { pickupIndex = PickupCatalog.FindPickupIndex(RoR2Content.Items.ArtifactKey.itemIndex), position = base.missionController.initialKeyLocation.position, rotation = UnityEngine.Quaternion.identity }; keyPickupInstance = GenericPickupController.CreatePickup(in createPickupInfo).gameObject; } } } if (pushedNotification || !(base.fixedAge > delayBeforePushingNotification) || !(base.fixedAge > 1.5f)) { return; } pushedNotification = true; foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList) { if ((bool)readOnlyInstances.playerCharacterMasterController && (bool)readOnlyInstances.playerCharacterMasterController.networkUserObject && readOnlyInstances.playerCharacterMasterController.networkUserObject.GetComponent().isLocalPlayer) { CharacterMasterNotificationQueue.PushArtifactNotification(readOnlyInstances, base.missionController.currentArtifact); } } } } private class PreCombatState : ArtifactTrialMissionControllerBaseState { private static float baseDuration = 1f; protected override bool shouldAllowMonsters => true; public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= baseDuration) { outer.SetNextState(new CombatState()); } } } private class CombatState : ArtifactTrialMissionControllerBaseState { protected override bool shouldEnableCombatDirector => true; protected override bool shouldEnableBossGroup => true; public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal; } } private void OnCharacterDeathGlobal(DamageReport damageReport) { if (Util.CheckRoll(Util.GetExpAdjustedDropChancePercent(base.missionController.chanceForKeyDrop * 100f, damageReport.victim.gameObject))) { UnityEngine.Debug.LogFormat("Creating artifact key pickup droplet."); PickupDropletController.CreatePickupDroplet(base.missionController.GenerateDrop(), damageReport.victimBody.corePosition, UnityEngine.Vector3.up * 20f); } } public override void OnExit() { GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal; base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (!base.missionController.artifactShellMaster || !base.missionController.artifactShellMaster.hasBody)) { outer.SetNextState(new WaitForRewardTaken()); } } } private class WaitForRewardTaken : ArtifactTrialMissionControllerBaseState { private float timer = 3f; protected bool shouldShowBossHealthBar = true; public override void OnEnter() { base.OnEnter(); if ((bool)base.missionController.destroyDisplayRingObject) { base.missionController.destroyDisplayRingObject.SetActive(value: true); } if (RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Delusion)) { foreach (ChestBehavior instances in InstanceTracker.GetInstancesList()) { instances.CallRpcResetChests(); } } if (RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Devotion)) { DevotionInventoryController.ActivateAllDevotedEvolution(); } } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && !base.missionController.artifactPickup) { timer -= Time.fixedDeltaTime; if (timer <= 0f) { outer.SetNextState(new SpawnExitPortalAndIdle()); } } } } private class SpawnExitPortalAndIdle : ArtifactTrialMissionControllerBaseState { public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { GameObject obj = UnityEngine.Object.Instantiate(base.missionController.exitPortalPrefab, base.missionController.exitPortalLocation.position, base.missionController.exitPortalLocation.rotation); obj.GetComponent().useRunNextStageScene = true; NetworkServer.Spawn(obj); } } } [Header("Artifact")] public GenericPickupController artifactPickup; public CharacterMaster artifactShellMaster; public GameObject destroyDisplayRingObject; [Header("Intro Cutscene")] public ForcedCamera introCameraController; [Header("Mission Key Parameters")] public Transform initialKeyLocation; public float chanceForKeyDrop = 0.04f; public PickupDropTable keyDropTable; [Header("Exit Portal")] public GameObject exitPortalPrefab; public Transform exitPortalLocation; [Header("Combat")] public CombatDirector[] combatDirectors; public BossGroup bossGroup; public static ArtifactDef trialArtifact; [SyncVar(hook = "TrySetCurrentArtifact")] private int currentArtifactIndex = -1; private bool artifactWasEnabled; private Xoroshiro128Plus rng; public ArtifactDef currentArtifact => ArtifactCatalog.GetArtifactDef((ArtifactIndex)currentArtifactIndex); public int NetworkcurrentArtifactIndex { get { return currentArtifactIndex; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; TrySetCurrentArtifact(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref currentArtifactIndex, 1u); } } public static event Action onShellTakeDamageServer; public static event Action onShellDeathServer; private void TrySetCurrentArtifact(int newArtifactIndex) { UnityEngine.Debug.LogFormat("TrySetCurrentArtifact currentArtifactIndex={0} newArtifactIndex={1}", currentArtifactIndex, newArtifactIndex); if (newArtifactIndex != currentArtifactIndex) { base.syncVarHookGuard = true; SetCurrentArtifact(newArtifactIndex); base.syncVarHookGuard = false; } } private void SetCurrentArtifact(int newArtifactIndex) { if ((bool)currentArtifact) { OnCurrentArtifactLost(currentArtifact); } NetworkcurrentArtifactIndex = newArtifactIndex; if ((bool)currentArtifact) { OnCurrentArtifactDiscovered(currentArtifact); } } private void Awake() { if (NetworkServer.active && (bool)trialArtifact) { TrySetCurrentArtifact((int)trialArtifact.artifactIndex); trialArtifact = null; } } private void OnDestroy() { TrySetCurrentArtifact(-1); GlobalEventManager.onServerDamageDealt -= OnServerDamageDealt; if (NetworkServer.active) { RemoveAllMissionKeys(); } } public override void OnStartServer() { base.OnStartServer(); rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUlong); GlobalEventManager.onServerDamageDealt += OnServerDamageDealt; GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal; } public override void OnStartClient() { base.OnStartClient(); if (!NetworkServer.active) { SetCurrentArtifact(currentArtifactIndex); } } private void OnCurrentArtifactDiscovered(ArtifactDef artifactDef) { if (NetworkServer.active && (bool)artifactDef) { artifactWasEnabled = RunArtifactManager.instance.IsArtifactEnabled(artifactDef); RunArtifactManager.instance.SetArtifactEnabledServer(artifactDef, newEnabled: true); if ((bool)artifactPickup) { artifactPickup.NetworkpickupIndex = PickupCatalog.FindPickupIndex(artifactDef.artifactIndex); } } } private void OnCurrentArtifactLost(ArtifactDef artifactDef) { if (NetworkServer.active) { if ((bool)artifactDef && (bool)RunArtifactManager.instance) { RunArtifactManager.instance.SetArtifactEnabledServer(artifactDef, artifactWasEnabled); } if ((bool)artifactPickup) { artifactPickup.NetworkpickupIndex = PickupIndex.none; } } } private void OnServerDamageDealt(DamageReport damageReport) { if ((object)damageReport.victimMaster == artifactShellMaster) { OnShellTakeDamageServer(damageReport); } } private void OnCharacterDeathGlobal(DamageReport damageReport) { if ((object)damageReport.victimMaster == artifactShellMaster) { OnShellDeathServer(damageReport); } } private void OnShellTakeDamageServer(DamageReport damageReport) { RemoveAllMissionKeys(); ArtifactTrialMissionController.onShellTakeDamageServer?.Invoke(this, damageReport); } private void OnShellDeathServer(DamageReport damageReport) { ArtifactTrialMissionController.onShellDeathServer?.Invoke(this, damageReport); } public PickupIndex GenerateDrop() { if ((bool)keyDropTable) { PickupIndex pickupIndex = keyDropTable.GenerateDrop(rng); UnityEngine.Debug.LogFormat("itemIndex = {0}, isValid = {1}, pickupNameToken = {2}", pickupIndex.itemIndex, pickupIndex.isValid, pickupIndex.GetPickupNameToken()); return keyDropTable.GenerateDrop(rng); } UnityEngine.Debug.LogError("Failed to generate key drop!"); return PickupIndex.none; } public static void RemoveAllMissionKeys() { ItemIndex itemIndex = RoR2Content.Items.ArtifactKey.itemIndex; PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(itemIndex); foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList) { int itemCount = readOnlyInstances.inventory.GetItemCount(itemIndex); if (itemCount > 0) { readOnlyInstances.inventory.RemoveItem(itemIndex, itemCount); } } List instancesList = InstanceTracker.GetInstancesList(); for (int num = instancesList.Count - 1; num >= 0; num--) { GenericPickupController genericPickupController = instancesList[num]; if (genericPickupController.pickupIndex == pickupIndex) { UnityEngine.Object.Destroy(genericPickupController.gameObject); } } List instancesList2 = InstanceTracker.GetInstancesList(); for (int num2 = instancesList2.Count - 1; num2 >= 0; num2--) { PickupPickerController pickupPickerController = instancesList2[num2]; if (pickupPickerController.IsChoiceAvailable(pickupIndex)) { UnityEngine.Object.Destroy(pickupPickerController.gameObject); } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt32((uint)currentArtifactIndex); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)currentArtifactIndex); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { currentArtifactIndex = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { TrySetCurrentArtifact((int)reader.ReadPackedUInt32()); } } public override void PreStartClient() { } } public class AssignRandomMaterial : MonoBehaviour { public Renderer rend; public Material[] materials; private void Awake() { rend.material = materials[UnityEngine.Random.Range(0, materials.Length)]; } } [RequireComponent(typeof(AkGameObj))] public class AudioManager : MonoBehaviour { private class VolumeConVar : BaseConVar { private readonly string rtpcName; private string fallbackString = "100"; public VolumeConVar(string name, ConVarFlags flags, string defaultValue, string helpText, string rtpcName) : base(name, flags, defaultValue, helpText) { this.rtpcName = rtpcName; } public override void SetString(string newValue) { if (!AkSoundEngine.IsInitialized()) { return; } fallbackString = newValue; if (TextSerialization.TryParseInvariant(newValue, out float result)) { if (rtpcName == cvVolumeMaster.rtpcName) { float num = float.Parse(cvVolumeParentMsx.GetString()); num *= result / 100f; cvVolumeMsx.fallbackString = num.ToString(); AkSoundEngine.SetRTPCValue(cvVolumeMsx.rtpcName, Mathf.Clamp(num, 0f, 100f)); } else if (rtpcName == cvVolumeParentMsx.rtpcName) { float num2 = float.Parse(cvVolumeMaster.fallbackString); float value = result * (num2 / 100f); cvVolumeMsx.fallbackString = value.ToString(); AkSoundEngine.SetRTPCValue(cvVolumeMsx.rtpcName, Mathf.Clamp(value, 0f, 100f)); return; } AkSoundEngine.SetRTPCValue(rtpcName, Mathf.Clamp(result, 0f, 100f)); } } public override string GetString() { int io_rValueType = 1; if (AkSoundEngine.GetRTPCValue(rtpcName, ulong.MaxValue, 0u, out var out_rValue, ref io_rValueType) == AKRESULT.AK_Success) { return TextSerialization.ToStringInvariant(out_rValue); } return fallbackString; } } private class AudioFocusedOnlyConVar : BaseConVar { private class ApplicationFocusListener : MonoBehaviour { public Action onApplicationFocus; private void OnApplicationFocus(bool focus) { onApplicationFocus?.Invoke(focus); } } private static AudioFocusedOnlyConVar instance = new AudioFocusedOnlyConVar("audio_focused_only", ConVarFlags.Archive | ConVarFlags.Engine, null, "Whether or not audio should mute when focus is lost."); private bool onlyPlayWhenFocused; private bool isFocused; private static MethodInfo akSoundEngineController_ActivateAudio_methodInfo = typeof(AkSoundEngineController).GetMethod("ActivateAudio", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public AudioFocusedOnlyConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { isFocused = Application.isFocused; RoR2Application.onUpdate += SearchForAkInitializer; } public override void SetString(string newValue) { if (TextSerialization.TryParseInvariant(newValue, out int result)) { onlyPlayWhenFocused = result != 0; Refresh(); } } public override string GetString() { if (!onlyPlayWhenFocused) { return "0"; } return "1"; } private void OnApplicationFocus(bool focus) { isFocused = focus; Refresh(); } private void Refresh() { bool flag = !isFocused && onlyPlayWhenFocused; bool flag2 = false; AkSoundEngineController akSoundEngineController = AkSoundEngineController.Instance; if (akSoundEngineController != null) { AkSoundEngineController_ActivateAudio(akSoundEngineController, !flag, !flag2); } } private static void AkSoundEngineController_ActivateAudio(AkSoundEngineController akSoundEngineController, bool activate, bool renderAnyway) { akSoundEngineController_ActivateAudio_methodInfo.Invoke(akSoundEngineController, new object[2] { activate, renderAnyway }); } private void SearchForAkInitializer() { AkInitializer akInitializer = (AkInitializer)akInitializerMsInstanceField.GetValue(null); if ((bool)akInitializer) { RoR2Application.onUpdate -= SearchForAkInitializer; ApplicationFocusListener applicationFocusListener = akInitializer.gameObject.AddComponent(); applicationFocusListener.onApplicationFocus = (Action)Delegate.Combine(applicationFocusListener.onApplicationFocus, new Action(OnApplicationFocus)); Refresh(); } } } private class WwiseLogEnabledConVar : BaseConVar { private static WwiseLogEnabledConVar instance = new WwiseLogEnabledConVar("wwise_log_enabled", ConVarFlags.Archive | ConVarFlags.Engine, null, "Wwise logging. 0 = disabled 1 = enabled"); private WwiseLogEnabledConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { } public override void SetString(string newValue) { if (!TextSerialization.TryParseInvariant(newValue, out int result)) { return; } AkInitializer akInitializer = akInitializerMsInstanceField.GetValue(null) as AkInitializer; if ((bool)akInitializer) { AkCallbackManager.InitializationSettings initializationSettings = akInitializer.InitializationSettings?.CallbackManagerInitializationSettings; if (initializationSettings != null) { initializationSettings.IsLoggingEnabled = result != 0; } } } public override string GetString() { AkInitializer akInitializer = akInitializerMsInstanceField.GetValue(null) as AkInitializer; if ((bool)akInitializer && akInitializer.InitializationSettings?.CallbackManagerInitializationSettings != null) { if (!akInitializer.InitializationSettings.CallbackManagerInitializationSettings.IsLoggingEnabled) { return "0"; } return "1"; } return "1"; } } private AkGameObj akGameObj; private static VolumeConVar cvVolumeMaster; private static VolumeConVar cvVolumeSfx; private static VolumeConVar cvVolumeMsx; private static VolumeConVar cvVolumeParentMsx; private static readonly FieldInfo akInitializerMsInstanceField; public static AudioManager instance { get; private set; } public static event Action onAwakeGlobal; private void Awake() { instance = this; akGameObj = GetComponent(); AudioManager.onAwakeGlobal?.Invoke(this); } static AudioManager() { cvVolumeMaster = new VolumeConVar("volume_master", ConVarFlags.Archive | ConVarFlags.Engine, "100", "The master volume of the game audio, from 0 to 100.", "Volume_Master"); cvVolumeSfx = new VolumeConVar("volume_sfx", ConVarFlags.Archive | ConVarFlags.Engine, "100", "The volume of sound effects, from 0 to 100.", "Volume_SFX"); cvVolumeMsx = new VolumeConVar("volume_music", ConVarFlags.Archive | ConVarFlags.Engine, "100", "The music volume, from 0 to 100.", "Volume_MSX"); cvVolumeParentMsx = new VolumeConVar("parent_volume_music", ConVarFlags.Archive, "100", "The parent music volume, from 0 to 100.", "Parent_Volume_MSX"); akInitializerMsInstanceField = typeof(AkInitializer).GetField("ms_Instance", BindingFlags.Static | BindingFlags.NonPublic); PauseManager.onPauseStartGlobal = (Action)Delegate.Combine(PauseManager.onPauseStartGlobal, (Action)delegate { AkSoundEngine.PostEvent("Pause_All", ulong.MaxValue); }); PauseManager.onPauseEndGlobal = (Action)Delegate.Combine(PauseManager.onPauseEndGlobal, (Action)delegate { AkSoundEngine.PostEvent("Unpause_All", ulong.MaxValue); }); } } public sealed class AurelioniteHeartController : NetworkBehaviour, IInteractable, IDisplayNameProvider { public string displayNameToken = "AURELIONITE_HEART_NAME"; public string contextToken; public uint expReward; [SerializeField] private EntityStateMachine entityStateMachine; public Animator heartAnimator; [SyncVar] [HideInInspector] public bool activated; public GameObject rebirthShrine; public bool shouldProximityHighlight = true; public bool Networkactivated { get { return activated; } [param: In] set { SetSyncVar(value, ref activated, 1u); } } private void Start() { if ((bool)Run.instance) { expReward = (uint)((float)expReward * Run.instance.difficultyCoefficient); } } public void OnInteractionBegin(Interactor activator) { if (!activated) { Networkactivated = true; if ((bool)entityStateMachine) { entityStateMachine.SetNextState(new AurelioniteHeartActivationState()); } ExperienceManager.instance.AwardExperience(base.transform.position, activator.GetComponent(), expReward); } } public string GetContextString(Interactor activator) { return Language.GetString(contextToken); } public override int GetNetworkChannel() { return QosChannelIndex.defaultReliable.intVal; } public Interactability GetInteractability(Interactor activator) { if (activated) { return Interactability.Disabled; } return Interactability.Available; } public string GetDisplayName() { return Language.GetString(displayNameToken); } public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator) { return false; } public void OnEnable() { InstanceTracker.Add(this); } public void OnDisable() { InstanceTracker.Remove(this); } public bool ShouldShowOnScanner() { return !activated; } public bool ShouldProximityHighlight() { return shouldProximityHighlight; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(activated); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(activated); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { activated = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { activated = reader.ReadBoolean(); } } public override void PreStartClient() { } } public class AwakeEvent : MonoBehaviour { public UnityEvent action; private void Awake() { action.Invoke(); } } public sealed class BarrelInteraction : NetworkBehaviour, IInteractable, IDisplayNameProvider { public int goldReward; public uint expReward; public string displayNameToken = "BARREL1_NAME"; public string contextToken; public bool shouldProximityHighlight = true; [SyncVar] private bool opened; public bool Networkopened { get { return opened; } [param: In] set { SetSyncVar(value, ref opened, 1u); } } public string GetContextString(Interactor activator) { return Language.GetString(contextToken); } public override int GetNetworkChannel() { return QosChannelIndex.defaultReliable.intVal; } public Interactability GetInteractability(Interactor activator) { if (opened) { return Interactability.Disabled; } return Interactability.Available; } private void Start() { if ((bool)Run.instance) { goldReward = (int)((float)goldReward * Run.instance.difficultyCoefficient); expReward = (uint)((float)expReward * Run.instance.difficultyCoefficient); } } [Server] public void OnInteractionBegin(Interactor activator) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.BarrelInteraction::OnInteractionBegin(RoR2.Interactor)' called on client"); } else if (!opened) { Networkopened = true; EntityStateMachine component = GetComponent(); if ((bool)component) { component.SetNextState(new EntityStates.Barrel.Opening()); } CharacterBody component2 = activator.GetComponent(); if ((bool)component2) { TeamIndex objectTeam = TeamComponent.GetObjectTeam(component2.gameObject); TeamManager.instance.GiveTeamMoney(objectTeam, (uint)goldReward); } CoinDrop(); ExperienceManager.instance.AwardExperience(base.transform.position, activator.GetComponent(), expReward); } } [Server] private void CoinDrop() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.BarrelInteraction::CoinDrop()' called on client"); return; } EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/CoinEmitter"), new EffectData { origin = base.transform.position, genericFloat = goldReward }, transmit: true); } public string GetDisplayName() { return Language.GetString(displayNameToken); } public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator) { return false; } public void OnEnable() { InstanceTracker.Add(this); } public void OnDisable() { InstanceTracker.Remove(this); } public bool ShouldShowOnScanner() { return !opened; } public bool ShouldProximityHighlight() { return shouldProximityHighlight; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(opened); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(opened); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { opened = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { opened = reader.ReadBoolean(); } } public override void PreStartClient() { } } public class BaseDefenseRun : Run { protected new void Awake() { base.Awake(); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool flag = base.OnSerialize(writer, forceAll); bool flag2 = default(bool); return flag2 || flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { base.OnDeserialize(reader, initialState); } public override void PreStartClient() { base.PreStartClient(); } } public abstract class BaseZoneBehavior : NetworkBehaviour, IZone { public abstract bool IsInBounds(UnityEngine.Vector3 position); private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class BasicBezierSpline : MonoBehaviour, ISerializationCallbackReceiver { private struct KeyFrame { public CubicBezier3 curve; public float approximateLength; } public BasicBezierSplineControlPoint[] controlPoints = Array.Empty(); public int samplesPerSegment = 20; private KeyFrame[] keyFrames = Array.Empty(); private UnityEngine.Vector3[] samplesBuffer = Array.Empty(); private float totalLength; private bool keyFramesDirty = true; private void BuildKeyFrames() { totalLength = 0f; Array.Resize(ref keyFrames, controlPoints.Length); Array.Resize(ref samplesBuffer, samplesPerSegment); int i = 0; for (int num = controlPoints.Length - 1; i < num; i++) { BasicBezierSplineControlPoint basicBezierSplineControlPoint = controlPoints[i]; BasicBezierSplineControlPoint basicBezierSplineControlPoint2 = controlPoints[i + 1]; if (!basicBezierSplineControlPoint || !basicBezierSplineControlPoint2) { break; } CubicBezier3 curveSegment = GetCurveSegment(basicBezierSplineControlPoint, basicBezierSplineControlPoint2); float num2 = curveSegment.ApproximateLength(samplesPerSegment); keyFrames[i] = new KeyFrame { curve = curveSegment, approximateLength = num2 }; totalLength += num2; } } public UnityEngine.Vector3 Evaluate(float normalizedPosition) { if (keyFramesDirty) { if (Application.isPlaying) { keyFramesDirty = false; } BuildKeyFrames(); } float num = normalizedPosition * totalLength; float num2 = 0f; int i = 0; for (int num3 = keyFrames.Length; i < num3; i++) { ref KeyFrame reference = ref keyFrames[i]; float a = num2; num2 += reference.approximateLength; if (num2 >= num) { float t = Mathf.InverseLerp(a, num2, num); return EvaluateKeyFrame(t, in reference); } } if (keyFrames.Length != 0) { return keyFrames[keyFrames.Length - 1].curve.p1; } return UnityEngine.Vector3.zero; } private UnityEngine.Vector3 EvaluateKeyFrame(float t, in KeyFrame keyFrame) { float num = t * keyFrame.approximateLength; keyFrame.curve.ToVertices(samplesBuffer); float a = 0f; float num2 = 0f; UnityEngine.Vector3 vector = samplesBuffer[0]; for (int i = 1; i < samplesBuffer.Length; i++) { UnityEngine.Vector3 vector2 = samplesBuffer[i]; float num3 = UnityEngine.Vector3.Distance(vector2, vector); num2 += num3; if (num2 >= num) { return UnityEngine.Vector3.Lerp(vector, vector2, Mathf.InverseLerp(a, num2, num)); } vector = vector2; a = num2; } return keyFrame.curve.p1; } private void DrawKeyFrame(in KeyFrame keyFrame) { Gizmos.color = UnityEngine.Color.Lerp(UnityEngine.Color.green, UnityEngine.Color.black, 0.5f); Gizmos.DrawRay(keyFrame.curve.p0, keyFrame.curve.v0); Gizmos.color = UnityEngine.Color.Lerp(UnityEngine.Color.red, UnityEngine.Color.black, 0.5f); Gizmos.DrawRay(keyFrame.curve.p1, keyFrame.curve.v1); for (int i = 1; i <= 20; i++) { float num = (float)i * 0.05f; Gizmos.color = UnityEngine.Color.Lerp(UnityEngine.Color.red, UnityEngine.Color.green, num); UnityEngine.Vector3 vector = keyFrame.curve.Evaluate(num - 0.05f); UnityEngine.Vector3 vector2 = keyFrame.curve.Evaluate(num); Gizmos.DrawRay(vector, vector2 - vector); } } public void OnDrawGizmos() { if (keyFramesDirty) { if (Application.isPlaying) { keyFramesDirty = false; } BuildKeyFrames(); } for (int i = 0; i < keyFrames.Length; i++) { DrawKeyFrame(in keyFrames[i]); } } public static CubicBezier3 GetCurveSegment(BasicBezierSplineControlPoint startControlPoint, BasicBezierSplineControlPoint endControlPoint) { Transform obj = startControlPoint.transform; Transform transform = endControlPoint.transform; UnityEngine.Vector3 position = obj.position; UnityEngine.Vector3 v = obj.rotation * startControlPoint.forwardVelocity; UnityEngine.Vector3 position2 = transform.position; UnityEngine.Vector3 v2 = transform.rotation * endControlPoint.backwardVelocity; return CubicBezier3.FromVelocities(position, v, position2, v2); } public void OnBeforeSerialize() { } public void OnAfterDeserialize() { keyFramesDirty = true; } } public class BasicBezierSplineControlPoint : MonoBehaviour { public UnityEngine.Vector3 forwardVelocity = UnityEngine.Vector3.forward; public UnityEngine.Vector3 backwardVelocity = UnityEngine.Vector3.back; private void OnDrawGizmos() { Gizmos.color = UnityEngine.Color.yellow; UnityEngine.Matrix4x4 identity = UnityEngine.Matrix4x4.identity; identity.SetTRS(base.transform.position, base.transform.rotation, UnityEngine.Vector3.one); Gizmos.matrix = identity; Gizmos.DrawRay(UnityEngine.Vector3.zero, forwardVelocity); Gizmos.DrawRay(UnityEngine.Vector3.zero, backwardVelocity); Gizmos.DrawFrustum(UnityEngine.Vector3.zero, 60f, -0.2f, 0f, 1f); } } public class BazaarController : MonoBehaviour { [Serializable] public struct SeerSceneOverride { [SerializeField] public SceneDef sceneDef; [SerializeField] public ExpansionDef requiredExpasion; [SerializeField] [Range(0f, 1f)] public float overrideChance; [SerializeField] public int minStagesCleared; [SerializeField] public string bannedEventFlag; } public GameObject shopkeeper; public TextMeshPro shopkeeperChat; public float shopkeeperTrackDistance = 250f; public float shopkeeperTrackAngle = 120f; [Tooltip("Any PurchaseInteraction objects here will have their activation state set based on whether or not the specified unlockable is available.")] public PurchaseInteraction[] unlockableTerminals; public SeerStationController[] seerStations; public SeerSceneOverride[] seerSceneOverrides; private InputBankTest shopkeeperInputBank; private CharacterBody shopkeeperTargetBody; private Xoroshiro128Plus rng; public static BazaarController instance { get; private set; } private void Awake() { instance = SingletonHelper.Assign(instance, this); } private void Start() { if (NetworkServer.active) { OnStartServer(); } } private void OnStartServer() { rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUlong); SetUpSeerStations(); } private void SetUpSeerStations() { SceneDef nextStageScene = Run.instance.nextStageScene; List list = new List(); if (nextStageScene != null) { int stageOrder = nextStageScene.stageOrder; foreach (SceneDef allSceneDef in SceneCatalog.allSceneDefs) { if (allSceneDef.stageOrder == stageOrder && (allSceneDef.requiredExpansion == null || Run.instance.IsExpansionEnabled(allSceneDef.requiredExpansion)) && IsUnlockedBeforeLooping(allSceneDef)) { list.Add(allSceneDef); } } } WeightedSelection weightedSelection = new WeightedSelection(); float num = 0f; SeerSceneOverride[] array = seerSceneOverrides; for (int i = 0; i < array.Length; i++) { SeerSceneOverride seerSceneOverride = array[i]; bool num2 = Run.instance.stageClearCount >= seerSceneOverride.minStagesCleared; bool flag = seerSceneOverride.requiredExpasion == null || Run.instance.IsExpansionEnabled(seerSceneOverride.requiredExpasion); bool flag2 = string.IsNullOrEmpty(seerSceneOverride.bannedEventFlag) || !Run.instance.GetEventFlag(seerSceneOverride.bannedEventFlag); if (num2 && flag && flag2) { weightedSelection.AddChoice(seerSceneOverride.sceneDef, seerSceneOverride.overrideChance); num += seerSceneOverride.overrideChance; } } SeerStationController[] array2 = seerStations; foreach (SeerStationController seerStationController in array2) { if (list.Count == 0) { seerStationController.GetComponent().SetAvailable(newAvailable: false); continue; } Util.ShuffleList(list, rng); int index = list.Count - 1; SceneDef sceneDef = list[index]; if (rng.nextNormalizedFloat < num) { sceneDef = weightedSelection.Evaluate(rng.nextNormalizedFloat); } if (IsSceneAlreadySelected(sceneDef)) { sceneDef = list[index]; } list.RemoveAt(index); seerStationController.SetTargetScene(sceneDef); } } private bool IsUnlockedBeforeLooping(SceneDef sceneDef) { if (Run.instance.stageClearCount < 4 && sceneDef.isLockedBeforeLooping) { return false; } return true; } private bool IsSceneAlreadySelected(SceneDef sceneDef) { for (int i = 0; i < seerStations.Length; i++) { if (sceneDef.sceneDefIndex == (SceneIndex)seerStations[i].ReturnTargetSceneDefIndex()) { return true; } } return false; } private void OnDestroy() { instance = SingletonHelper.Unassign(instance, this); } public void CommentOnAnnoy() { int maxExclusive = 6; if (Util.CheckRoll(20f)) { Chat.SendBroadcastChat(new Chat.NpcChatMessage { sender = shopkeeper, baseToken = "NEWT_ANNOY_" + UnityEngine.Random.Range(1, maxExclusive) }); } } public void CommentOnEnter() { } public void CommentOnLeaving() { } public void CommentOnLunarPurchase() { int maxExclusive = 8; if (Util.CheckRoll(20f)) { Chat.SendBroadcastChat(new Chat.NpcChatMessage { sender = shopkeeper, baseToken = "NEWT_LUNAR_PURCHASE_" + UnityEngine.Random.Range(1, maxExclusive) }); } } public void CommentOnBlueprintPurchase() { } public void CommentOnDronePurchase() { } public void CommentOnUpgrade() { int maxExclusive = 3; if (Util.CheckRoll(100f)) { Chat.SendBroadcastChat(new Chat.NpcChatMessage { sender = shopkeeper, baseToken = "NEWT_UPGRADE_" + UnityEngine.Random.Range(1, maxExclusive) }); } } private void Update() { if (!shopkeeper) { return; } if (!shopkeeperInputBank) { shopkeeperInputBank = shopkeeper.GetComponent(); return; } Ray aimRay = new Ray(shopkeeperInputBank.aimOrigin, shopkeeper.transform.forward); shopkeeperTargetBody = Util.GetEnemyEasyTarget(shopkeeper.GetComponent(), aimRay, shopkeeperTrackDistance, shopkeeperTrackAngle); if ((bool)shopkeeperTargetBody) { UnityEngine.Vector3 direction = shopkeeperTargetBody.mainHurtBox.transform.position - aimRay.origin; aimRay.direction = direction; } shopkeeperInputBank.aimDirection = aimRay.direction; } } public sealed class BazaarUpgradeInteraction : NetworkBehaviour, IInteractable, IHologramContentProvider, IDisplayNameProvider { [SyncVar] public bool available = true; public string displayNameToken; public int cost; public string contextToken; public string[] unlockableProgression; private UnlockableDef[] unlockableProgressionDefs; public float activationCooldownDuration = 1f; private float activationTimer; public GameObject purchaseEffect; public bool shouldProximityHighlight = true; private static readonly Color32 lunarCoinColor = new Color32(198, 173, 250, byte.MaxValue); private static readonly string lunarCoinColorString = Util.RGBToHex(lunarCoinColor); public bool Networkavailable { get { return available; } [param: In] set { SetSyncVar(value, ref available, 1u); } } private void Awake() { unlockableProgressionDefs = new UnlockableDef[unlockableProgression.Length]; for (int i = 0; i < unlockableProgressionDefs.Length; i++) { unlockableProgressionDefs[i] = UnlockableCatalog.GetUnlockableDef(unlockableProgression[i]); } } private void FixedUpdate() { if (NetworkServer.active && !available) { activationTimer -= Time.fixedDeltaTime; if (activationTimer <= 0f) { Networkavailable = true; } } } public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator) { return false; } private UnlockableDef GetInteractorNextUnlockable(GameObject activatorGameObject) { NetworkUser networkUser = Util.LookUpBodyNetworkUser(activatorGameObject); if ((bool)networkUser) { LocalUser localUser = networkUser.localUser; if (localUser != null) { for (int i = 0; i < unlockableProgressionDefs.Length; i++) { UnlockableDef unlockableDef = unlockableProgressionDefs[i]; if (!localUser.userProfile.HasUnlockable(unlockableDef)) { return unlockableDef; } } } else { for (int j = 0; j < unlockableProgressionDefs.Length; j++) { UnlockableDef unlockableDef2 = unlockableProgressionDefs[j]; if (!networkUser.unlockables.Contains(unlockableDef2)) { return unlockableDef2; } } } } return null; } private static bool ActivatorHasUnlockable(Interactor activator, string unlockableName) { NetworkUser networkUser = Util.LookUpBodyNetworkUser(activator.gameObject); if ((bool)networkUser) { return networkUser.localUser?.userProfile.HasUnlockable(unlockableName) ?? networkUser.unlockables.Contains(UnlockableCatalog.GetUnlockableDef(unlockableName)); } return true; } public string GetDisplayName() { return Language.GetString(displayNameToken); } private string GetCostString() { return string.Format(" ({0})", cost, lunarCoinColorString); } public string GetContextString(Interactor activator) { if (!CanBeAffordedByInteractor(activator)) { return null; } return Language.GetString(contextToken) + GetCostString(); } public Interactability GetInteractability(Interactor activator) { if (GetInteractorNextUnlockable(activator.gameObject) == null || !available) { return Interactability.Disabled; } if (!CanBeAffordedByInteractor(activator)) { return Interactability.ConditionsNotMet; } return Interactability.Available; } public void OnInteractionBegin(Interactor activator) { } private int GetCostForInteractor(Interactor activator) { return cost; } public bool CanBeAffordedByInteractor(Interactor activator) { NetworkUser networkUser = Util.LookUpBodyNetworkUser(activator.gameObject); if ((bool)networkUser) { return networkUser.lunarCoins >= GetCostForInteractor(activator); } return false; } public bool ShouldDisplayHologram(GameObject viewer) { return GetInteractorNextUnlockable(viewer) != null; } public GameObject GetHologramContentPrefab() { return LegacyResourcesAPI.Load("Prefabs/CostHologramContent"); } public void UpdateHologramContent(GameObject hologramContentObject, Transform viewer) { CostHologramContent component = hologramContentObject.GetComponent(); if ((bool)component) { component.displayValue = cost; component.costType = CostTypeIndex.LunarCoin; } } private void OnEnable() { InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); } public bool ShouldShowOnScanner() { return available; } public bool ShouldProximityHighlight() { return shouldProximityHighlight; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(available); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(available); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { available = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { available = reader.ReadBoolean(); } } public override void PreStartClient() { } } public class Billboard : MonoBehaviour { private static List instanceTransformsList; static Billboard() { instanceTransformsList = new List(); SceneCamera.onSceneCameraPreCull += OnSceneCameraPreCull; } private static void OnSceneCameraPreCull(SceneCamera sceneCamera) { UnityEngine.Quaternion rotation = sceneCamera.transform.rotation; for (int i = 0; i < instanceTransformsList.Count; i++) { instanceTransformsList[i].rotation = rotation; } } private void OnEnable() { instanceTransformsList.Add(base.transform); } private void OnDisable() { instanceTransformsList.Remove(base.transform); } } public class BloodSiphonNearbyController : NetworkBehaviour { [UnityEngine.Min(float.Epsilon)] public float minHealthFractionCoefficient; public float maxHealthFractionCoefficient; public float tickRate = 1f; public DamageTypeCombo damageType; [SyncVar] public int maxTargets; public TetherVfxOrigin tetherVfxOrigin; public GameObject activeVfx; protected new Transform transform; private HoldoutZoneController holdoutZone; protected SphereSearch sphereSearch; protected float timer; protected float currentRadius; private bool isTetheredToAtLeastOneObject; public int NetworkmaxTargets { get { return maxTargets; } [param: In] set { SetSyncVar(value, ref maxTargets, 1u); } } protected void Awake() { transform = base.transform; sphereSearch = new SphereSearch(); timer = 0f; holdoutZone = GetComponentInParent(); } protected void FixedUpdate() { timer -= Time.fixedDeltaTime; if (timer <= 0f) { timer += 1f / tickRate; Tick(); } } private void OnTransformParentChanged() { holdoutZone = GetComponentInParent(); } protected void Tick() { if ((bool)holdoutZone) { currentRadius = holdoutZone.currentRadius; } List list = CollectionPool>.RentCollection(); SearchForTargets(list); float num = minHealthFractionCoefficient; if ((bool)holdoutZone) { num = Mathf.Lerp(minHealthFractionCoefficient, maxHealthFractionCoefficient, holdoutZone.charge); } float num2 = num / tickRate; List list2 = CollectionPool>.RentCollection(); for (int i = 0; i < list.Count; i++) { HurtBox hurtBox = list[i]; if ((bool)hurtBox && (bool)hurtBox.healthComponent && hurtBox.healthComponent.alive) { HealthComponent healthComponent = hurtBox.healthComponent; Transform transform = healthComponent.body.coreTransform ?? hurtBox.transform; list2.Add(transform); if (NetworkServer.active) { DamageInfo damageInfo = new DamageInfo(); damageInfo.attacker = null; damageInfo.inflictor = base.gameObject; damageInfo.position = transform.position; damageInfo.crit = false; damageInfo.damage = num2 * healthComponent.fullCombinedHealth; damageInfo.damageColorIndex = DamageColorIndex.Bleed; damageInfo.damageType = damageType; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.procCoefficient = 0f; damageInfo.procChainMask = default(ProcChainMask); hurtBox.healthComponent.TakeDamage(damageInfo); } } if (list2.Count >= maxTargets) { break; } } isTetheredToAtLeastOneObject = (float)list2.Count > 0f; if ((bool)tetherVfxOrigin) { tetherVfxOrigin.SetTetheredTransforms(list2); } if ((bool)activeVfx) { activeVfx.SetActive(isTetheredToAtLeastOneObject); } CollectionPool>.ReturnCollection(list2); CollectionPool>.ReturnCollection(list); } protected void SearchForTargets(List dest) { if (currentRadius > 0f) { TeamMask mask = default(TeamMask); mask.AddTeam(TeamIndex.Player); sphereSearch.mask = LayerIndex.entityPrecise.mask; sphereSearch.origin = transform.position; sphereSearch.radius = currentRadius; sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal; sphereSearch.RefreshCandidates(); sphereSearch.FilterCandidatesByHurtBoxTeam(mask); sphereSearch.OrderCandidatesByDistance(); sphereSearch.FilterCandidatesByDistinctHurtBoxEntities(); sphereSearch.GetHurtBoxes(dest); sphereSearch.ClearCandidates(); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt32((uint)maxTargets); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)maxTargets); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { maxTargets = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { maxTargets = (int)reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public class BlueprintController : MonoBehaviour { [NonSerialized] public bool ok; public Material okMaterial; public Material invalidMaterial; public Renderer[] renderers; private new Transform transform; private void Awake() { transform = base.transform; } private void Update() { Material sharedMaterial = (ok ? okMaterial : invalidMaterial); for (int i = 0; i < renderers.Length; i++) { renderers[i].sharedMaterial = sharedMaterial; } } public void PushState(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, bool ok) { transform.position = position; transform.rotation = rotation; this.ok = ok; } } public class BlueprintTerminal : NetworkBehaviour { [Serializable] public struct UnlockableOption { [Obsolete("'unlockableName' will be discontinued. Use 'unlockableDef' instead.", false)] [Tooltip("'unlockableName' will be discontinued. Use 'unlockableDef' instead.")] public string unlockableName; public UnlockableDef unlockableDef; public int cost; public float weight; public UnlockableDef GetResolvedUnlockableDef() { string text = unlockableName; if (!unlockableDef && !string.IsNullOrEmpty(text)) { unlockableDef = UnlockableCatalog.GetUnlockableDef(text); } return unlockableDef; } } [SyncVar(hook = "SetHasBeenPurchased")] private bool hasBeenPurchased; public Transform displayBaseTransform; [Tooltip("The unlockables to grant")] public UnlockableOption[] unlockableOptions; private int unlockableChoice; public string unlockSoundString; public float idealDisplayVolume = 1.5f; public GameObject unlockEffect; private GameObject displayInstance; public bool NetworkhasBeenPurchased { get { return hasBeenPurchased; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SetHasBeenPurchased(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref hasBeenPurchased, 1u); } } private void SetHasBeenPurchased(bool newHasBeenPurchased) { if (hasBeenPurchased != newHasBeenPurchased) { NetworkhasBeenPurchased = newHasBeenPurchased; Rebuild(); } } public void Start() { if (NetworkServer.active) { RollChoice(); } if (NetworkClient.active) { Rebuild(); } } private void RollChoice() { WeightedSelection weightedSelection = new WeightedSelection(); for (int i = 0; i < unlockableOptions.Length; i++) { weightedSelection.AddChoice(i, unlockableOptions[i].weight); } unlockableChoice = weightedSelection.Evaluate(UnityEngine.Random.value); Rebuild(); } private void Rebuild() { UnlockableOption unlockableOption = unlockableOptions[unlockableChoice]; if ((bool)displayInstance) { UnityEngine.Object.Destroy(displayInstance); } displayBaseTransform.gameObject.SetActive(!hasBeenPurchased); if (!hasBeenPurchased && (bool)displayBaseTransform) { UnlockableDef resolvedUnlockableDef = unlockableOption.GetResolvedUnlockableDef(); if ((bool)resolvedUnlockableDef) { GameObject displayModelPrefab = resolvedUnlockableDef.displayModelPrefab; if ((bool)displayModelPrefab) { displayInstance = UnityEngine.Object.Instantiate(displayModelPrefab, displayBaseTransform.position, displayBaseTransform.transform.rotation, displayBaseTransform); Renderer componentInChildren = displayInstance.GetComponentInChildren(); float num = 1f; if ((bool)componentInChildren) { displayInstance.transform.rotation = UnityEngine.Quaternion.identity; UnityEngine.Vector3 size = componentInChildren.bounds.size; float f = size.x * size.y * size.z; num *= Mathf.Pow(idealDisplayVolume, 1f / 3f) / Mathf.Pow(f, 1f / 3f); } displayInstance.transform.localScale = new UnityEngine.Vector3(num, num, num); } } } PurchaseInteraction component = GetComponent(); if ((bool)component) { component.Networkcost = unlockableOption.cost; } } [Server] public void GrantUnlock(Interactor interactor) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.BlueprintTerminal::GrantUnlock(RoR2.Interactor)' called on client"); return; } SetHasBeenPurchased(newHasBeenPurchased: true); UnlockableOption unlockableOption = unlockableOptions[unlockableChoice]; UnlockableDef resolvedUnlockableDef = unlockableOption.GetResolvedUnlockableDef(); EffectManager.SpawnEffect(unlockEffect, new EffectData { origin = base.transform.position }, transmit: true); if ((bool)Run.instance) { Util.PlaySound(unlockSoundString, interactor.gameObject); CharacterBody component = interactor.GetComponent(); Run.instance.GrantUnlockToSinglePlayer(resolvedUnlockableDef, component); string pickupToken = "???"; if (resolvedUnlockableDef != null) { pickupToken = resolvedUnlockableDef.nameToken; } Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage { subjectAsCharacterBody = component, baseToken = "PLAYER_PICKUP", pickupToken = pickupToken, pickupColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Unlockable), pickupQuantity = 1u }); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(hasBeenPurchased); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(hasBeenPurchased); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { hasBeenPurchased = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { SetHasBeenPurchased(reader.ReadBoolean()); } } public override void PreStartClient() { } } public class BodyAnimatorSmoothingParameters : MonoBehaviour { [Serializable] public struct SmoothingParameters { public float walkMagnitudeSmoothDamp; public float walkAngleSmoothDamp; public float forwardSpeedSmoothDamp; public float rightSpeedSmoothDamp; public float intoJumpTransitionTime; public float turnAngleSmoothDamp; } public SmoothingParameters smoothingParameters; public static SmoothingParameters defaultParameters = new SmoothingParameters { walkMagnitudeSmoothDamp = 0.2f, walkAngleSmoothDamp = 0.2f, forwardSpeedSmoothDamp = 0.1f, rightSpeedSmoothDamp = 0.1f, intoJumpTransitionTime = 0.05f, turnAngleSmoothDamp = 1f }; } public class BoneParticleController : MonoBehaviour { public GameObject childParticlePrefab; public float spawnFrequency; public SkinnedMeshRenderer skinnedMeshRenderer; private float stopwatch; private List bonesList; private void Start() { bonesList = new List(); Transform[] bones = skinnedMeshRenderer.bones; foreach (Transform transform in bones) { if (transform.name.IndexOf("IK", StringComparison.OrdinalIgnoreCase) == -1 && transform.name.IndexOf("Root", StringComparison.OrdinalIgnoreCase) == -1 && transform.name.IndexOf("Base", StringComparison.OrdinalIgnoreCase) == -1) { UnityEngine.Debug.LogFormat("added bone {0}", transform); bonesList.Add(transform); } } } private void Update() { if (!skinnedMeshRenderer) { return; } stopwatch += Time.deltaTime; if (stopwatch > 1f / spawnFrequency) { stopwatch -= 1f / spawnFrequency; int count = bonesList.Count; Transform transform = bonesList[UnityEngine.Random.Range(0, count)]; if ((bool)transform) { UnityEngine.Object.Instantiate(childParticlePrefab, transform.transform.position, UnityEngine.Quaternion.identity, transform); } } } } public class BoneShrink : MonoBehaviour { private new Transform transform; private void Awake() { transform = base.transform; } private void LateUpdate() { transform.localScale = new UnityEngine.Vector3(0.01f, 0.01f, 0.01f); } } [RequireComponent(typeof(CombatSquad))] public class BossGroup : MonoBehaviour { private struct BossMemory { public NetworkInstanceId masterInstanceId; public float maxObservedMaxHealth; public float lastObservedHealth; public CharacterMaster cachedMaster; public CharacterBody cachedBody; } private class DefeatBossObjectiveTracker : ObjectivePanelController.ObjectiveTracker { public DefeatBossObjectiveTracker() { baseToken = "OBJECTIVE_DEFEAT_BOSS"; } } public class EnableHudHealthBarState : EntityState { private BossGroup bossGroup; public override void OnEnter() { base.OnEnter(); bossGroup = GetComponent(); if ((object)bossGroup != null) { bossGroup.shouldDisplayHealthBarOnHud = true; } } public override void OnExit() { if ((object)bossGroup != null) { bossGroup.shouldDisplayHealthBarOnHud = false; } base.OnExit(); } } public float bossDropChance = 0.15f; public Transform dropPosition; public PickupDropTable dropTable; public bool scaleRewardsByPlayerCount = true; [Tooltip("Whether or not this boss group should display a health bar on the HUD while any of its members are alive. Other scripts can change this at runtime to suppress a health bar until the boss is angered, for example. This field is not networked, so whatever is driving the value should be synchronized over the network.")] public bool shouldDisplayHealthBarOnHud = true; private Xoroshiro128Plus rng; private List bossDropTables; private Run.FixedTimeStamp enabledTime; [Header("Deprecated")] public bool forceTier3Reward; private List bossDrops; private static readonly int initialBossMemoryCapacity = 8; private BossMemory[] bossMemories = new BossMemory[initialBossMemoryCapacity]; private int bossMemoryCount; private static int lastTotalBossCount = 0; private static bool totalBossCountDirty = false; public float fixedAge => combatSquad.awakeTime.timeSince; public float fixedTimeSinceEnabled => enabledTime.timeSince; public int bonusRewardCount { get; set; } public CombatSquad combatSquad { get; private set; } public string bestObservedName { get; private set; } = ""; public string bestObservedSubtitle { get; private set; } = ""; public float totalMaxObservedMaxHealth { get; private set; } public float totalObservedHealth { get; private set; } public static event Action onBossGroupStartServer; public static event Action onBossGroupDefeatedServer; private void Awake() { base.enabled = false; combatSquad = GetComponent(); combatSquad.onMemberDiscovered += OnMemberDiscovered; combatSquad.onMemberLost += OnMemberLost; if (NetworkServer.active) { combatSquad.onDefeatedServer += OnDefeatedServer; combatSquad.onMemberAddedServer += OnMemberAddedServer; combatSquad.onMemberDefeatedServer += OnMemberDefeatedServer; rng = new Xoroshiro128Plus(Run.instance.bossRewardRng.nextUlong); bossDrops = new List(); bossDropTables = new List(); } } private void Start() { if (NetworkServer.active) { BossGroup.onBossGroupStartServer?.Invoke(this); } } private void OnEnable() { InstanceTracker.Add(this); ObjectivePanelController.collectObjectiveSources += ReportObjective; enabledTime = Run.FixedTimeStamp.now; } private void OnDisable() { ObjectivePanelController.collectObjectiveSources -= ReportObjective; InstanceTracker.Remove(this); } private void FixedUpdate() { UpdateBossMemories(); } private void OnDefeatedServer() { DropRewards(); Run.instance.OnServerBossDefeated(this); BossGroup.onBossGroupDefeatedServer?.Invoke(this); } private void OnMemberAddedServer(CharacterMaster memberMaster) { Run.instance.OnServerBossAdded(this, memberMaster); } private void OnMemberDefeatedServer(CharacterMaster memberMaster, DamageReport damageReport) { DeathRewards deathRewards = memberMaster.GetBodyObject()?.GetComponent(); if (!deathRewards) { return; } if ((bool)deathRewards.bossDropTable) { bossDropTables.Add(deathRewards.bossDropTable); return; } PickupIndex pickupIndex = (PickupIndex)deathRewards.bossPickup; if (pickupIndex != PickupIndex.none) { bossDrops.Add(pickupIndex); } } private void OnMemberDiscovered(CharacterMaster memberMaster) { base.enabled = true; memberMaster.isBoss = true; totalBossCountDirty = true; RememberBoss(memberMaster); } private void OnMemberLost(CharacterMaster memberMaster) { memberMaster.isBoss = false; totalBossCountDirty = true; if (combatSquad.memberCount == 0) { base.enabled = false; } } private void DropRewards() { if (!Run.instance) { UnityEngine.Debug.LogError("No valid run instance!"); return; } if (rng == null) { UnityEngine.Debug.LogError("RNG is null!"); return; } int participatingPlayerCount = Run.instance.participatingPlayerCount; if (participatingPlayerCount == 0) { return; } if ((bool)dropPosition) { PickupIndex none = PickupIndex.none; if ((bool)dropTable) { none = dropTable.GenerateDrop(rng); } else { List list = Run.instance.availableTier2DropList; if (forceTier3Reward) { list = Run.instance.availableTier3DropList; } none = rng.NextElementUniform(list); } int num = 1 + bonusRewardCount; if (scaleRewardsByPlayerCount) { num *= participatingPlayerCount; } float angle = 360f / (float)num; UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); bool flag = bossDrops != null && bossDrops.Count > 0; bool flag2 = bossDropTables != null && bossDropTables.Count > 0; int num2 = 0; while (num2 < num) { PickupIndex pickupIndex = none; if (bossDrops != null && (flag || flag2) && rng.nextNormalizedFloat <= bossDropChance) { if (flag2) { PickupDropTable pickupDropTable = rng.NextElementUniform(bossDropTables); if (pickupDropTable != null) { pickupIndex = pickupDropTable.GenerateDrop(rng); } } else { pickupIndex = rng.NextElementUniform(bossDrops); } } PickupDropletController.CreatePickupDroplet(pickupIndex, dropPosition.position, vector); num2++; vector = quaternion * vector; } } else { UnityEngine.Debug.LogWarning("dropPosition not set for BossGroup! No item will be spawned."); } } private int FindBossMemoryIndex(NetworkInstanceId id) { for (int i = 0; i < bossMemoryCount; i++) { if (bossMemories[i].masterInstanceId == id) { return i; } } return -1; } private void RememberBoss(CharacterMaster master) { if ((bool)master) { int num = FindBossMemoryIndex(master.netId); if (num == -1) { num = AddBossMemory(master); } ref BossMemory reference = ref bossMemories[num]; reference.cachedMaster = master; reference.cachedBody = master.GetBody(); UpdateObservations(ref reference); } } private void UpdateObservations(ref BossMemory memory) { memory.lastObservedHealth = 0f; if ((bool)memory.cachedMaster && !memory.cachedBody) { memory.cachedBody = memory.cachedMaster.GetBody(); } if (!memory.cachedBody) { return; } if (bestObservedName.Length == 0 && bestObservedSubtitle.Length == 0 && Time.fixedDeltaTime * 3f < memory.cachedBody.localStartTime.timeSince) { bestObservedName = Util.GetBestBodyName(memory.cachedBody.gameObject); bestObservedSubtitle = memory.cachedBody.GetSubtitle(); if (bestObservedSubtitle.Length == 0) { bestObservedSubtitle = Language.GetString("NULL_SUBTITLE"); } bestObservedSubtitle = " " + bestObservedSubtitle + ""; } HealthComponent healthComponent = memory.cachedBody.healthComponent; memory.maxObservedMaxHealth = Mathf.Max(memory.maxObservedMaxHealth, healthComponent.fullCombinedHealth); memory.lastObservedHealth = healthComponent.combinedHealth; } private int AddBossMemory(CharacterMaster master) { BossMemory bossMemory = default(BossMemory); bossMemory.masterInstanceId = master.netId; bossMemory.maxObservedMaxHealth = 0f; bossMemory.cachedMaster = master; BossMemory value = bossMemory; ArrayUtils.ArrayAppend(ref bossMemories, ref bossMemoryCount, in value); return bossMemoryCount - 1; } private void UpdateBossMemories() { totalMaxObservedMaxHealth = 0f; totalObservedHealth = 0f; for (int i = 0; i < bossMemoryCount; i++) { ref BossMemory reference = ref bossMemories[i]; UpdateObservations(ref reference); totalMaxObservedMaxHealth += reference.maxObservedMaxHealth; totalObservedHealth += Mathf.Max(reference.lastObservedHealth, 0f); } } public static int GetTotalBossCount() { if (totalBossCountDirty) { totalBossCountDirty = false; lastTotalBossCount = 0; List instancesList = InstanceTracker.GetInstancesList(); for (int i = 0; i < instancesList.Count; i++) { lastTotalBossCount += instancesList[i].combatSquad.readOnlyMembersList.Count; } } return lastTotalBossCount; } public static BossGroup FindBossGroup(CharacterBody body) { if (!body || !body.isBoss) { return null; } CharacterMaster master = body.master; if (!master) { return null; } List instancesList = InstanceTracker.GetInstancesList(); for (int i = 0; i < instancesList.Count; i++) { BossGroup bossGroup = instancesList[i]; if (bossGroup.combatSquad.ContainsMember(master)) { return bossGroup; } } return null; } public void ReportObjective(CharacterMaster master, List output) { if (combatSquad.readOnlyMembersList.Count != 0) { output.Add(new ObjectivePanelController.ObjectiveSourceDescriptor { source = this, master = master, objectiveType = typeof(DefeatBossObjectiveTracker) }); } } } public class BoxZone : BaseZoneBehavior, IZone { [SerializeField] [Tooltip("If false, \"IsInBounds\" returns true when inside the box. If true, outside the box is considered in bounds.")] private bool isInverted; public override bool IsInBounds(UnityEngine.Vector3 position) { UnityEngine.Vector3 vector = position - base.transform.position; vector.x = Mathf.Abs(vector.x); vector.y = Mathf.Abs(vector.y); vector.z = Mathf.Abs(vector.z); UnityEngine.Vector3 vector2 = base.transform.lossyScale * 0.5f; if (isInverted) { if (vector.x > vector2.x && vector.y > vector2.y) { return vector.z > vector2.z; } return false; } if (vector.x < vector2.x && vector.y < vector2.y) { return vector.z < vector2.z; } return false; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool flag = base.OnSerialize(writer, forceAll); bool flag2 = default(bool); return flag2 || flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { base.OnDeserialize(reader, initialState); } public override void PreStartClient() { base.PreStartClient(); } } public class BuffPassengerWhileSeated : MonoBehaviour { [SerializeField] private BuffDef buff; [SerializeField] private VehicleSeat vehicleSeat; private void OnEnable() { if ((bool)vehicleSeat) { if ((bool)vehicleSeat.currentPassengerBody) { AddBuff(vehicleSeat.currentPassengerBody); } vehicleSeat.onPassengerEnter += OnPassengerEnter; vehicleSeat.onPassengerExit += OnPassengerExit; } } private void OnDisable() { if ((bool)vehicleSeat) { if ((bool)vehicleSeat.currentPassengerBody) { RemoveBuff(vehicleSeat.currentPassengerBody); } vehicleSeat.onPassengerEnter -= OnPassengerEnter; vehicleSeat.onPassengerExit -= OnPassengerExit; } } private void OnPassengerEnter(GameObject passengerObject) { CharacterBody component = passengerObject.GetComponent(); if ((bool)component) { AddBuff(component); } } private void OnPassengerExit(GameObject passengerObject) { CharacterBody component = passengerObject.GetComponent(); if ((bool)component) { RemoveBuff(component); } } private void AddBuff(CharacterBody passengerBody) { passengerBody.AddBuff(buff); } private void RemoveBuff(CharacterBody passengerBody) { passengerBody.RemoveBuff(buff); } } public class BuffPickup : MonoBehaviour { [Tooltip("The base object to destroy when this pickup is consumed.")] public GameObject baseObject; [Tooltip("The team filter object which determines who can pick up this pack.")] public TeamFilter teamFilter; public GameObject pickupEffect; public BuffDef buffDef; public float buffDuration; private bool alive = true; private void OnTriggerStay(Collider other) { if (NetworkServer.active && alive && TeamComponent.GetObjectTeam(other.gameObject) == teamFilter.teamIndex) { CharacterBody component = other.GetComponent(); if ((bool)component) { component.AddTimedBuff(buffDef.buffIndex, buffDuration); UnityEngine.Object.Instantiate(pickupEffect, other.transform.position, UnityEngine.Quaternion.identity); UnityEngine.Object.Destroy(baseObject); } } } } [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, UnityEngine.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) { UnityEngine.Object.Destroy(base.gameObject); } } if ((bool)rangeIndicator) { float num = Mathf.SmoothDamp(rangeIndicator.localScale.x, calculatedRadius, ref rangeIndicatorScaleVelocity, 0.2f); rangeIndicator.localScale = new UnityEngine.Vector3(num, num, num); } } private void FixedUpdate() { if (!NetworkServer.active) { return; } buffTimer -= Time.fixedDeltaTime; if (!(buffTimer <= 0f)) { return; } buffTimer = interval; float radiusSqr = calculatedRadius * calculatedRadius; UnityEngine.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, UnityEngine.Vector3 currentPosition) { if (!NetworkServer.active || !buffDef) { return; } foreach (TeamComponent recipient in recipients) { UnityEngine.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) { UnityEngine.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() { } } public class BurnEffectController : MonoBehaviour { public class EffectParams { public string startSound; public string stopSound; public Material overlayMaterial; public GameObject fireEffectPrefab; } private List burnEffectInstances; public GameObject target; private TemporaryOverlayInstance temporaryOverlay; private int soundID; public EffectParams effectType = normalEffect; public static EffectParams normalEffect; public static EffectParams helfireEffect; public static EffectParams poisonEffect; public static EffectParams blightEffect; public static EffectParams strongerBurnEffect; public float fireParticleSize = 5f; [InitDuringStartup] private static void Init() { normalEffect = new EffectParams { startSound = "Play_item_proc_igniteOnKill_Loop", stopSound = "Stop_item_proc_igniteOnKill_Loop" }; LegacyResourcesAPI.LoadAsyncCallback("Materials/matOnFire", delegate(Material val) { normalEffect.overlayMaterial = val; }); LegacyResourcesAPI.LoadAsyncCallback("Prefabs/FireEffect", delegate(GameObject val) { normalEffect.fireEffectPrefab = val; }); helfireEffect = new EffectParams { startSound = "Play_item_proc_igniteOnKill_Loop", stopSound = "Stop_item_proc_igniteOnKill_Loop" }; LegacyResourcesAPI.LoadAsyncCallback("Materials/matOnHelfire", delegate(Material val) { helfireEffect.overlayMaterial = val; }); LegacyResourcesAPI.LoadAsyncCallback("Prefabs/HelfireEffect", delegate(GameObject val) { helfireEffect.fireEffectPrefab = val; }); poisonEffect = new EffectParams(); LegacyResourcesAPI.LoadAsyncCallback("Materials/matPoisoned", delegate(Material val) { poisonEffect.overlayMaterial = val; }); LegacyResourcesAPI.LoadAsyncCallback("Prefabs/PoisonEffect", delegate(GameObject val) { poisonEffect.fireEffectPrefab = val; }); blightEffect = new EffectParams(); LegacyResourcesAPI.LoadAsyncCallback("Materials/matBlighted", delegate(Material val) { blightEffect.overlayMaterial = val; }); LegacyResourcesAPI.LoadAsyncCallback("Prefabs/BlightEffect", delegate(GameObject val) { blightEffect.fireEffectPrefab = val; }); strongerBurnEffect = new EffectParams(); LegacyResourcesAPI.LoadAsyncCallback("Materials/matStrongerBurn", delegate(Material val) { strongerBurnEffect.overlayMaterial = val; }); LegacyResourcesAPI.LoadAsyncCallback("Prefabs/StrongerBurnEffect", delegate(GameObject val) { strongerBurnEffect.fireEffectPrefab = val; }); } private void Start() { if (effectType == null) { UnityEngine.Debug.LogError("BurnEffectController on " + base.gameObject.name + " has no effect type!"); return; } Util.PlaySound(effectType.startSound, base.gameObject); burnEffectInstances = new List(); if (effectType.overlayMaterial != null) { temporaryOverlay = TemporaryOverlayManager.AddOverlay(base.gameObject); temporaryOverlay.originalMaterial = effectType.overlayMaterial; } if (!target) { return; } CharacterModel component = target.GetComponent(); if (!component) { return; } if (temporaryOverlay != null) { temporaryOverlay.AddToCharacterModel(component); } CharacterBody body = component.body; CharacterModel.RendererInfo[] baseRendererInfos = component.baseRendererInfos; if (!body) { return; } for (int i = 0; i < baseRendererInfos.Length; i++) { if (!baseRendererInfos[i].ignoreOverlays) { BurnEffectControllerHelper burnEffectControllerHelper = AddFireParticles(baseRendererInfos[i].renderer, body.coreTransform); if ((bool)burnEffectControllerHelper) { burnEffectInstances.Add(burnEffectControllerHelper); } } } } private void OnDestroy() { Util.PlaySound(effectType.stopSound, base.gameObject); if (temporaryOverlay != null) { temporaryOverlay.Destroy(); } for (int i = 0; i < burnEffectInstances.Count; i++) { if ((bool)burnEffectInstances[i]) { burnEffectInstances[i].EndEffect(); } } } private BurnEffectControllerHelper AddFireParticles(Renderer modelRenderer, Transform targetParentTransform) { if (modelRenderer is MeshRenderer || modelRenderer is SkinnedMeshRenderer) { GameObject fireEffectPrefab = effectType.fireEffectPrefab; EffectManagerHelper andActivatePooledEffect = EffectManager.GetAndActivatePooledEffect(fireEffectPrefab, targetParentTransform); if (!andActivatePooledEffect) { UnityEngine.Debug.LogWarning("Could not spawn the BurnEffect prefab: " + fireEffectPrefab?.ToString() + "."); return null; } BurnEffectControllerHelper component = andActivatePooledEffect.GetComponent(); if (!component) { UnityEngine.Debug.LogWarning("Burn effect " + fireEffectPrefab?.ToString() + " doesn't have a BurnEffectControllerHelper applied. It can't be applied."); andActivatePooledEffect.ReturnToPool(); return null; } component.InitializeBurnEffect(modelRenderer); return component; } return null; } public void HandleDestroy() { UnityEngine.Object.Destroy(base.gameObject); } } public class BurnEffectControllerHelper : MonoBehaviour { public ParticleSystem burnParticleSystem; public DestroyOnTimer destroyOnTimer; public LightIntensityCurve lightIntensityCurve; public NormalizeParticleScale normalizeParticleScale; public BoneParticleController boneParticleController; private void Awake() { if (!burnParticleSystem) { burnParticleSystem = GetComponent(); } if (!destroyOnTimer) { destroyOnTimer = GetComponent(); } if (!lightIntensityCurve) { lightIntensityCurve = GetComponentInChildren(); } if (!normalizeParticleScale) { normalizeParticleScale = GetComponentInChildren(); } if (!boneParticleController) { boneParticleController = GetComponentInChildren(); } } private void OnEnable() { if ((bool)lightIntensityCurve) { lightIntensityCurve.enabled = false; } } public void InitializeBurnEffect(Renderer modelRenderer) { if (!burnParticleSystem || !modelRenderer) { return; } ParticleSystem.ShapeModule shape = burnParticleSystem.shape; if (modelRenderer is MeshRenderer meshRenderer) { shape.shapeType = ParticleSystemShapeType.MeshRenderer; shape.meshRenderer = meshRenderer; } else if (modelRenderer is SkinnedMeshRenderer skinnedMeshRenderer) { shape.shapeType = ParticleSystemShapeType.SkinnedMeshRenderer; shape.skinnedMeshRenderer = skinnedMeshRenderer; if ((bool)boneParticleController) { boneParticleController.skinnedMeshRenderer = skinnedMeshRenderer; } } if ((bool)normalizeParticleScale) { normalizeParticleScale.UpdateParticleSystem(); } burnParticleSystem.gameObject.SetActive(value: true); } public void EndEffect() { if ((bool)burnParticleSystem) { ParticleSystem.EmissionModule emission = burnParticleSystem.emission; emission.enabled = false; } if ((bool)destroyOnTimer) { destroyOnTimer.enabled = true; } if ((bool)lightIntensityCurve) { lightIntensityCurve.enabled = true; } } } [DisallowMultipleComponent] [RequireComponent(typeof(Camera))] public class CameraResolutionScaler : MonoBehaviour { private class ResolutionScaleConVar : BaseConVar { private static ResolutionScaleConVar instance = new ResolutionScaleConVar("resolution_scale", ConVarFlags.Archive, null, "Resolution scale. Currently nonfunctional."); private ResolutionScaleConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { } public override void SetString(string newValue) { TextSerialization.TryParseInvariant(newValue, out float _); } public override string GetString() { return TextSerialization.ToStringInvariant(resolutionScale); } } private RenderTexture oldRenderTexture; private static float resolutionScale = 1f; private RenderTexture scalingRenderTexture; public Camera camera { get; private set; } private void Awake() { camera = GetComponent(); } private void OnPreRender() { ApplyScalingRenderTexture(); } private void OnRenderImage(RenderTexture source, RenderTexture destination) { if (!scalingRenderTexture) { Graphics.Blit(source, destination); return; } camera.targetTexture = oldRenderTexture; Graphics.Blit(source, oldRenderTexture); oldRenderTexture = null; } private static void SetResolutionScale(float newResolutionScale) { if (resolutionScale != newResolutionScale) { resolutionScale = newResolutionScale; } } private void ApplyScalingRenderTexture() { oldRenderTexture = camera.targetTexture; bool flag = resolutionScale != 1f; camera.targetTexture = null; UnityEngine.Rect pixelRect = camera.pixelRect; int num = Mathf.FloorToInt(pixelRect.width * resolutionScale); int num2 = Mathf.FloorToInt(pixelRect.height * resolutionScale); if ((bool)scalingRenderTexture && (scalingRenderTexture.width != num || scalingRenderTexture.height != num2)) { UnityEngine.Object.Destroy(scalingRenderTexture); scalingRenderTexture = null; } if (flag != (bool)scalingRenderTexture) { if (flag) { scalingRenderTexture = new RenderTexture(num, num2, 24); scalingRenderTexture.autoGenerateMips = false; scalingRenderTexture.filterMode = (((double)resolutionScale > 1.0) ? FilterMode.Bilinear : FilterMode.Point); } else { UnityEngine.Object.Destroy(scalingRenderTexture); scalingRenderTexture = null; } } if (flag) { camera.targetTexture = scalingRenderTexture; } } private void OnDestroy() { if ((bool)scalingRenderTexture) { UnityEngine.Object.Destroy(scalingRenderTexture); scalingRenderTexture = null; } } } public interface ICameraStateProvider { void GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState); bool IsUserLookAllowed(CameraRigController cameraRigController); bool IsUserControlAllowed(CameraRigController cameraRigController); bool IsHudAllowed(CameraRigController cameraRigController); } public struct CameraState { public UnityEngine.Vector3 position; public UnityEngine.Quaternion rotation; public float fov; public static CameraState Lerp(ref CameraState a, ref CameraState b, float t) { CameraState result = default(CameraState); result.position = UnityEngine.Vector3.LerpUnclamped(a.position, b.position, t); result.rotation = UnityEngine.Quaternion.SlerpUnclamped(a.rotation, b.rotation, t); result.fov = Mathf.LerpUnclamped(a.fov, b.fov, t); return result; } public static CameraState SmoothDamp(CameraState current, CameraState target, ref UnityEngine.Vector3 positionVelocity, ref float angleVelocity, ref float fovVelocity, float smoothTime) { CameraState result = default(CameraState); result.position = UnityEngine.Vector3.SmoothDamp(current.position, target.position, ref positionVelocity, smoothTime); result.rotation = Util.SmoothDampQuaternion(current.rotation, target.rotation, ref angleVelocity, smoothTime); result.fov = Mathf.SmoothDamp(current.fov, target.fov, ref fovVelocity, smoothTime); return result; } } public enum HudType { Default, Large, Auto } public class CameraRigController : MonoBehaviour { [Obsolete("CameraMode objects are now used instead of enums.", true)] public enum CameraMode { None, PlayerBasic, Fly, SpectateOrbit, SpectateUser } public struct AimAssistInfo { public HurtBox aimAssistHurtbox; public UnityEngine.Vector3 localPositionOnHurtbox; public UnityEngine.Vector3 worldPosition; } [Tooltip("The main camera for rendering the scene.")] [Header("Component References")] public Camera sceneCam; [Tooltip("The UI camera.")] public Camera uiCam; [Tooltip("The skybox camera.")] public Camera skyboxCam; [Tooltip("The particle system to play while sprinting.")] public ParticleSystem sprintingParticleSystem; [Tooltip("The particle system to play while skills are disabled.")] public ParticleSystem disabledSkillsParticleSystem; [Header("Camera Parameters")] [Tooltip("The default FOV of this camera.")] public float baseFov = 60f; [Tooltip("The viewport to use.")] public UnityEngine.Rect viewport = new UnityEngine.Rect(0f, 0f, 1f, 1f); [Tooltip("The maximum distance of the raycast used to determine the aim vector.")] public float maxAimRaycastDistance = 1000f; [Tooltip("If true, treat this camera as though it's in a cutscene")] public bool isCutscene; [Header("Near-Camera Character Dithering")] public bool enableFading = true; public float fadeStartDistance = 1f; public float fadeEndDistance = 4f; [Header("Behavior")] [Tooltip("Whether or not to create a HUD.")] public bool createHud = true; [Tooltip("Whether or not this camera being enabled forces player-owned cameras to be disabled.")] public bool suppressPlayerCameras; [Tooltip("Forces music to be enabled for this camera.")] public bool enableMusic; private ulong musicListenerId; private bool musicEnabled; [Header("Target (for debug only)")] public GameObject nextTarget; public static Action OnChangeHUD; public static Action OnHUDUpdated; private CameraModeBase _cameraMode; private GameObject _target; private CameraState desiredCameraState; public CameraState currentCameraState; public bool doNotOverrideCameraState; private CameraState lerpCameraState; private float lerpCameraTime = 1f; private float lerpCameraTimeScale = 1f; private ICameraStateProvider overrideCam; private CameraModeBase.CameraModeContext cameraModeContext; private NetworkUser _viewer; private LocalUser _localUserViewer; private static GameObject DamageNumberManagerPrefab; private static GameObject HudPrefab; private static string previousHudPath; public CameraTargetParams targetParams; private const string musicSystemDeviceShareSet = "Music_Audio_Device"; public AimAssistInfo lastAimAssist; public AimAssistInfo aimAssist; private static List instancesList = new List(); public static readonly ReadOnlyCollection readOnlyInstancesList = instancesList.AsReadOnly(); public static FloatConVar aimStickExponent = new FloatConVar("aim_stick_exponent", ConVarFlags.None, "1", "The exponent for stick input used for aiming."); public static FloatConVar aimStickDualZoneThreshold = new FloatConVar("aim_stick_dual_zone_threshold", ConVarFlags.None, "0.90", "The threshold for stick dual zone behavior."); public static FloatConVar aimStickDualZoneSlope = new FloatConVar("aim_stick_dual_zone_slope", ConVarFlags.None, "0.40", "The slope value for stick dual zone behavior."); public static FloatConVar aimStickDualZoneSmoothing = new FloatConVar("aim_stick_smoothing", ConVarFlags.None, "0.05", "The smoothing value for stick aiming."); public static FloatConVar aimStickGlobalScale = new FloatConVar("aim_stick_global_scale", ConVarFlags.Archive, "1.00", "The global sensitivity scale for stick aiming."); public static FloatConVar aimStickAssistMinSlowdownScale = new FloatConVar("aim_stick_assist_min_slowdown_scale", ConVarFlags.None, "1", "The MIN amount the sensitivity scales down when passing over an enemy."); public static FloatConVar aimStickAssistMaxSlowdownScale = new FloatConVar("aim_stick_assist_max_slowdown_scale", ConVarFlags.None, "0.4", "The MAX amount the sensitivity scales down when passing over an enemy. UNUSED"); public static FloatConVar aimStickAssistMinDelta = new FloatConVar("aim_stick_assist_min_delta", ConVarFlags.None, "0", "The MIN amount in radians the aim assist will turn towards"); public static FloatConVar aimStickAssistMaxDelta = new FloatConVar("aim_stick_assist_max_delta", ConVarFlags.None, "1.57", "The MAX amount in radians the aim assist will turn towards"); public static FloatConVar aimStickAssistMaxInputHelp = new FloatConVar("aim_stick_assist_max_input_help", ConVarFlags.None, "0.2", "The amount, from 0-1, that the aim assist will actually ADD magnitude towards. Helps you keep target while strafing. CURRENTLY UNUSED."); public static FloatConVar aimStickAssistMaxSize = new FloatConVar("aim_stick_assist_max_size", ConVarFlags.None, "3", "The size, as a coefficient, of the aim assist 'white' zone."); public static FloatConVar aimStickAssistMinSize = new FloatConVar("aim_stick_assist_min_size", ConVarFlags.None, "1", "The minimum size, as a percentage of the GUI, of the aim assist 'red' zone."); public static BoolConVar enableSprintSensitivitySlowdown = new BoolConVar("enable_sprint_sensitivity_slowdown", ConVarFlags.Archive, "1", "Enables sensitivity reduction while sprinting."); private float hitmarkerAlpha; private float hitmarkerTimer; public bool disableSpectating { get; set; } public CameraModeBase cameraMode { get { return _cameraMode; } set { if (_cameraMode != value) { _cameraMode?.OnUninstall(this); _cameraMode = value; _cameraMode?.OnInstall(this); } } } public HUD hud { get; private set; } public GameObject firstPersonTarget { get; private set; } public TeamIndex targetTeamIndex { get; private set; } = TeamIndex.None; public CharacterBody targetBody { get; private set; } public UnityEngine.Vector3 rawScreenShakeDisplacement { get; private set; } public UnityEngine.Vector3 crosshairWorldPosition { get; private set; } public bool hasOverride => overrideCam != null; public bool isControlAllowed { get { if (hasOverride) { return overrideCam.IsUserControlAllowed(this); } return true; } } public bool isHudAllowed { get { if ((bool)target) { if (hasOverride) { return overrideCam.IsHudAllowed(this); } return true; } return false; } } public GameObject target { get { return _target; } private set { if ((object)_target != value) { GameObject oldTarget = _target; _target = value; bool flag = _target; targetParams = (flag ? target.GetComponent() : null); targetBody = (flag ? target.GetComponent() : null); cameraMode?.OnTargetChanged(this, new CameraModeBase.OnTargetChangedArgs { oldTarget = oldTarget, newTarget = _target }); CameraRigController.onCameraTargetChanged?.Invoke(this, target); } } } public NetworkUser viewer { get { return _viewer; } set { _viewer = value; localUserViewer = (_viewer ? _viewer.localUser : null); } } public LocalUser localUserViewer { get { return _localUserViewer; } private set { if (_localUserViewer != value) { if (_localUserViewer != null) { _localUserViewer.cameraRigController = null; } _localUserViewer = value; if (_localUserViewer != null) { _localUserViewer.cameraRigController = this; } if ((bool)hud) { hud.localUserViewer = _localUserViewer; } } } } public HurtBox lastCrosshairHurtBox { get; private set; } public static event Action onCameraTargetChanged; public static event Action onCameraEnableGlobal; public static event Action onCameraDisableGlobal; private void StartStateLerp(float lerpDuration) { lerpCameraState = currentCameraState; if (lerpDuration > 0f) { lerpCameraTime = 0f; lerpCameraTimeScale = 1f / lerpDuration; } else { lerpCameraTime = 1f; lerpCameraTimeScale = 0f; } } public void SetOverrideCam(ICameraStateProvider newOverrideCam, float lerpDuration = 1f) { if (newOverrideCam != overrideCam) { if (overrideCam != null && newOverrideCam == null) { cameraMode?.MatchState(in cameraModeContext, in currentCameraState); } overrideCam = newOverrideCam; StartStateLerp(lerpDuration); } } public bool IsOverrideCam(ICameraStateProvider testOverrideCam) { return overrideCam == testOverrideCam; } public static IEnumerator InitializeReferences() { AsyncOperationHandle handle2 = LegacyResourcesAPI.LoadAsync("Prefabs/DamageNumberManager"); while (!handle2.IsDone) { yield return null; } DamageNumberManagerPrefab = handle2.Result; previousHudPath = GetHUDPath(); handle2 = LegacyResourcesAPI.LoadAsync(previousHudPath); while (!handle2.IsDone) { yield return null; } HudPrefab = handle2.Result; } private void Start() { RoR2Application.onUpdate += EarlyUpdate; OnChangeHUD = (Action)Delegate.Combine(OnChangeHUD, new Action(UpdateHUD)); UpdateHUD(); if ((bool)uiCam) { uiCam.transform.parent = null; uiCam.transform.SetPositionAndRotation(UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity); } if (!DamageNumberManager.instance) { if (DamageNumberManagerPrefab != null) { UnityEngine.Object.Instantiate(DamageNumberManagerPrefab); } else { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/DamageNumberManager"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { UnityEngine.Object.Instantiate(x.Result); }; } } currentCameraState = new CameraState { position = base.transform.position, rotation = base.transform.rotation, fov = baseFov }; cameraMode = CameraModePlayerBasic.playerBasic; if (enableMusic && (!RoR2Application.isInLocalMultiPlayer || _viewer.localUser.inputPlayer.name == "PlayerMain")) { EnableMusicForCamera(); } } private void UpdateHUD() { if (createHud) { if ((bool)hud) { UnityEngine.Object.Destroy(hud.gameObject); } string hUDPath = GetHUDPath(); if (HudPrefab == null || hUDPath != previousHudPath) { HudPrefab = LegacyResourcesAPI.Load(hUDPath); previousHudPath = hUDPath; } GameObject gameObject = UnityEngine.Object.Instantiate(HudPrefab); hud = gameObject.GetComponent(); hud.cameraRigController = this; SetPostProcessVolumeExclusive(hud.scoreboardPostProcessVolume); hud.GetComponent().worldCamera = uiCam; hud.GetComponent().cameraRigController = this; hud.localUserViewer = localUserViewer; OnHUDUpdated?.Invoke(); } } [CanBeNull] private static string GetHUDPath() { if (NetworkUser.readOnlyLocalPlayersList == null || NetworkUser.readOnlyLocalPlayersList.Count < 1) { return "Prefabs/HUDSimple"; } UserProfile userProfile = NetworkUser.readOnlyLocalPlayersList[0]?.localUser?.userProfile; if (userProfile != null) { switch ((HudType)userProfile.hudSizeMode) { case HudType.Default: return "Prefabs/HUDSimple"; case HudType.Large: return "Prefabs/HUDSimple_Big"; case HudType.Auto: return "Prefabs/HUDSimple_Big"; default: UnityEngine.Debug.LogWarning(string.Format("Undefined {0}. Value : {1}. Resorting to default HUD.", "HudType", userProfile.hudSizeMode)); return "Prefabs/HUDSimple"; } } return "Prefabs/HUDSimple"; } private void OnEnable() { instancesList.Add(this); if ((bool)uiCam) { uiCam.gameObject.SetActive(value: true); } if ((bool)hud) { hud.gameObject.SetActive(value: true); } CameraRigController.onCameraEnableGlobal?.Invoke(this); } private void OnDisable() { CameraRigController.onCameraDisableGlobal?.Invoke(this); if ((bool)uiCam) { uiCam.gameObject.SetActive(value: false); } if ((bool)hud) { hud.gameObject.SetActive(value: false); } instancesList.Remove(this); } private void OnDestroy() { RoR2Application.onUpdate -= EarlyUpdate; OnChangeHUD = (Action)Delegate.Remove(OnChangeHUD, new Action(UpdateHUD)); cameraMode = null; if ((bool)uiCam) { UnityEngine.Object.Destroy(uiCam.gameObject); } if ((bool)hud) { UnityEngine.Object.Destroy(hud.gameObject); } DisableMusicForCamera(); } private void EarlyUpdate() { target = nextTarget; if ((bool)targetBody) { targetTeamIndex = targetBody.teamComponent.teamIndex; } if (Time.deltaTime != 0f && !isCutscene) { lerpCameraTime += Time.deltaTime * lerpCameraTimeScale; firstPersonTarget = null; sceneCam.rect = viewport; GenerateCameraModeContext(out cameraModeContext); if (cameraMode != null) { cameraMode.CollectLookInput(in cameraModeContext, out var result); CameraModeBase cameraModeBase = cameraMode; ref CameraModeBase.CameraModeContext context = ref cameraModeContext; CameraModeBase.ApplyLookInputArgs args = new CameraModeBase.ApplyLookInputArgs { lookInput = result.lookInput }; cameraModeBase.ApplyLookInput(in context, in args); } } } private void LateUpdate() { if (Time.deltaTime == 0f || isCutscene) { return; } CameraState cameraState = currentCameraState; if (cameraMode != null && cameraModeContext.cameraInfo.cameraRigController != null && !doNotOverrideCameraState) { cameraMode.Update(in cameraModeContext, out var result); cameraState = result.cameraState; firstPersonTarget = result.firstPersonTarget; crosshairWorldPosition = result.crosshairWorldPosition; SetParticleSystemActive(result.showSprintParticles, sprintingParticleSystem); SetParticleSystemActive(result.showDisabledSkillsParticles, disabledSkillsParticleSystem); } if ((bool)hud) { CharacterMaster targetMaster = (targetBody ? targetBody.master : null); hud.targetMaster = targetMaster; } CameraState cameraState2 = cameraState; if (overrideCam != null) { if (!(overrideCam is UnityEngine.Object @object) || (bool)@object) { overrideCam.GetCameraState(this, ref cameraState2); } else { overrideCam = null; } } if (lerpCameraTime >= 1f) { currentCameraState = cameraState2; } else { currentCameraState = CameraState.Lerp(ref lerpCameraState, ref cameraState2, RemapLerpTime(lerpCameraTime)); } SetCameraState(currentCameraState); } public void UpdatePreviousCameraState(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation) { cameraModeContext.cameraInfo.previousCameraState.position = position; cameraModeContext.cameraInfo.previousCameraState.rotation = rotation; } private void GenerateCameraModeContext(out CameraModeBase.CameraModeContext result) { result.cameraInfo = default(CameraModeBase.CameraInfo); result.targetInfo = default(CameraModeBase.TargetInfo); result.viewerInfo = default(CameraModeBase.ViewerInfo); ref CameraModeBase.CameraInfo cameraInfo = ref result.cameraInfo; ref CameraModeBase.TargetInfo targetInfo = ref result.targetInfo; ref CameraModeBase.ViewerInfo viewerInfo = ref result.viewerInfo; cameraInfo.cameraRigController = this; cameraInfo.sceneCam = sceneCam; cameraInfo.overrideCam = overrideCam; cameraInfo.previousCameraState = currentCameraState; cameraInfo.baseFov = baseFov; targetInfo.target = (target ? target : null); targetInfo.body = targetBody; targetInfo.inputBank = targetInfo.target?.GetComponent(); if (targetBody != null && targetBody.currentVehicle != null && targetBody.currentVehicle.targetParams != null) { targetInfo.targetParams = targetBody.currentVehicle.targetParams; } else { targetInfo.targetParams = targetParams; } targetInfo.teamIndex = targetInfo.target?.GetComponent()?.teamIndex ?? TeamIndex.None; targetInfo.isSprinting = (bool)targetInfo.body && targetInfo.body.isSprinting; targetInfo.skillsAreDisabled = (bool)targetInfo.body && targetInfo.body.allSkillsDisabled; targetInfo.master = targetInfo.body?.master; targetInfo.networkUser = targetInfo.master?.playerCharacterMasterController?.networkUser; targetInfo.networkedViewAngles = targetInfo.networkUser?.GetComponent(); targetInfo.isViewerControlled = (bool)targetInfo.networkUser && (object)targetInfo.networkUser == localUserViewer?.currentNetworkUser; viewerInfo.localUser = localUserViewer; viewerInfo.userProfile = localUserViewer?.userProfile; viewerInfo.inputPlayer = localUserViewer?.inputPlayer; viewerInfo.eventSystem = localUserViewer?.eventSystem; viewerInfo.hasCursor = (bool)viewerInfo.eventSystem && viewerInfo.eventSystem.isCursorVisible; viewerInfo.isUIFocused = localUserViewer?.isUIFocused ?? false; } public void CloneCameraContext(CameraRigController cloneThisCamera) { if (!(cloneThisCamera == null)) { cameraModeContext = cloneThisCamera.cameraModeContext; } } public float Raycast(Ray ray, float maxDistance, float wallCushion) { int num = 0; num = HGPhysics.SphereCastAll(out var hits, ray.origin, wallCushion, ray.direction, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore); float num2 = maxDistance; for (int i = 0; i < num; i++) { float distance = hits[i].distance; if (distance < num2) { Collider collider = hits[i].collider; if ((bool)collider && !collider.GetComponent()) { num2 = distance; } } } HGPhysics.ReturnResults(hits); return num2; } private static float RemapLerpTime(float t) { float num = 1f; float num2 = 0f; float num3 = 1f; if ((t /= num / 2f) < 1f) { return num3 / 2f * t * t + num2; } return (0f - num3) / 2f * ((t -= 1f) * (t - 2f) - 1f) + num2; } public void SetCameraState(CameraState cameraState) { currentCameraState = cameraState; float num = ((localUserViewer == null) ? 1f : localUserViewer.userProfile.screenShakeScale); UnityEngine.Vector3 position = cameraState.position; rawScreenShakeDisplacement = ShakeEmitter.ComputeTotalShakeAtPoint(cameraState.position); UnityEngine.Vector3 vector = rawScreenShakeDisplacement * num; UnityEngine.Vector3 position2 = position + vector; if (vector != UnityEngine.Vector3.zero && Physics.SphereCast(position, direction: vector, radius: sceneCam.nearClipPlane, hitInfo: out var hitInfo, maxDistance: vector.magnitude, layerMask: LayerIndex.world.mask, queryTriggerInteraction: QueryTriggerInteraction.Ignore)) { position2 = position + vector.normalized * hitInfo.distance; } base.transform.SetPositionAndRotation(position2, cameraState.rotation); if ((bool)sceneCam) { sceneCam.fieldOfView = cameraState.fov; } } public static Ray ModifyAimRayIfApplicable(Ray originalAimRay, GameObject target, out float extraRaycastDistance) { CameraRigController cameraRigController = null; for (int i = 0; i < readOnlyInstancesList.Count; i++) { CameraRigController cameraRigController2 = readOnlyInstancesList[i]; if (cameraRigController2.target == target && cameraRigController2._localUserViewer.cachedBodyObject == target && !cameraRigController2.hasOverride) { cameraRigController = cameraRigController2; break; } } if ((bool)cameraRigController) { Camera camera = cameraRigController.sceneCam; extraRaycastDistance = (originalAimRay.origin - camera.transform.position).magnitude; return camera.ViewportPointToRay(new UnityEngine.Vector2(0.5f, 0.5f)); } extraRaycastDistance = 0f; return originalAimRay; } private void SetSprintParticlesActive(bool newSprintParticlesActive) { if (!sprintingParticleSystem) { return; } ParticleSystem.MainModule main = sprintingParticleSystem.main; if (newSprintParticlesActive) { main.loop = true; if (!sprintingParticleSystem.isPlaying) { sprintingParticleSystem.Play(); } } else { main.loop = false; } } private void SetParticleSystemActive(bool newParticlesActive, ParticleSystem particleSystem) { if (!particleSystem) { return; } ParticleSystem.MainModule main = particleSystem.main; if (newParticlesActive) { main.loop = true; if (!particleSystem.isPlaying) { particleSystem.Play(); } } else { main.loop = false; } } public void SetPostProcessVolumeExclusive(PostProcessVolume volume) { if (!(volume == null) && !(sceneCam == null)) { volume.targetLayer = sceneCam.GetComponent(); } } [InitDuringStartup] private static void Init() { SceneCamera.onSceneCameraPreCull += delegate(SceneCamera sceneCam) { sceneCam.cameraRigController.sprintingParticleSystem.gameObject.layer = LayerIndex.defaultLayer.intVal; }; SceneCamera.onSceneCameraPostRender += delegate(SceneCamera sceneCam) { sceneCam.cameraRigController.sprintingParticleSystem.gameObject.layer = LayerIndex.noDraw.intVal; }; } public static bool IsObjectSpectatedByAnyCamera(GameObject gameObject) { for (int i = 0; i < instancesList.Count; i++) { if (instancesList[i].target == gameObject) { return true; } } return false; } [ContextMenu("Print Debug Info")] private void PrintDebugInfo() { UnityEngine.Debug.LogFormat("hasOverride={0} overrideCam={1} isControlAllowed={2}", hasOverride, overrideCam, isControlAllowed); } public void EnableMusicForCamera(string deviceShareSet = "Music_Audio_Device") { GameObject gameObject = new GameObject("MusicListener", typeof(AkGameObj), typeof(AkAudioListener)); Transform obj = gameObject.transform; obj.localPosition = UnityEngine.Vector3.zero; obj.localRotation = UnityEngine.Quaternion.identity; obj.localScale = UnityEngine.Vector3.one; obj.SetParent(sceneCam.transform, worldPositionStays: false); AkOutputSettings in_Settings = new AkOutputSettings(deviceShareSet); ulong[] array = new ulong[1] { AkSoundEngine.GetAkGameObjectID(gameObject) }; AkSoundEngine.AddOutput(in_Settings, out var out_pDeviceID, array, (uint)array.Length); musicListenerId = out_pDeviceID; musicEnabled = true; } public void DisableMusicForCamera() { if (musicEnabled) { AkSoundEngine.RemoveOutput(musicListenerId); } } } [RequireComponent(typeof(CameraRigController))] public class CameraRigControllerSpectateControls : MonoBehaviour { private CameraRigController cameraRigController; private void Awake() { cameraRigController = GetComponent(); } private static bool CanUserSpectateBody(NetworkUser viewer, CharacterBody body) { return Util.LookUpBodyNetworkUser(body.gameObject); } public static GameObject GetNextSpectateGameObject(NetworkUser viewer, GameObject currentGameObject) { ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; if (readOnlyInstancesList.Count == 0) { return null; } CharacterBody characterBody = (currentGameObject ? currentGameObject.GetComponent() : null); int num = (characterBody ? readOnlyInstancesList.IndexOf(characterBody) : 0); for (int i = num + 1; i < readOnlyInstancesList.Count; i++) { if (CanUserSpectateBody(viewer, readOnlyInstancesList[i])) { return readOnlyInstancesList[i].gameObject; } } for (int j = 0; j <= num; j++) { if (CanUserSpectateBody(viewer, readOnlyInstancesList[j])) { return readOnlyInstancesList[j].gameObject; } } return null; } public static GameObject GetPreviousSpectateGameObject(NetworkUser viewer, GameObject currentGameObject) { ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; if (readOnlyInstancesList.Count == 0) { return null; } CharacterBody characterBody = (currentGameObject ? currentGameObject.GetComponent() : null); int num = (characterBody ? readOnlyInstancesList.IndexOf(characterBody) : 0); for (int num2 = num - 1; num2 >= 0; num2--) { if (CanUserSpectateBody(viewer, readOnlyInstancesList[num2])) { return readOnlyInstancesList[num2].gameObject; } } for (int num3 = readOnlyInstancesList.Count - 1; num3 >= num; num3--) { if (CanUserSpectateBody(viewer, readOnlyInstancesList[num3])) { return readOnlyInstancesList[num3].gameObject; } } return null; } private void Update() { Player player = cameraRigController.localUserViewer?.inputPlayer; if (cameraRigController.cameraMode != null && cameraRigController.cameraMode.IsSpectating(cameraRigController) && player != null) { if (player.GetButtonDown(7)) { cameraRigController.nextTarget = GetNextSpectateGameObject(cameraRigController.viewer, cameraRigController.target); } if (player.GetButtonDown(8)) { cameraRigController.nextTarget = GetPreviousSpectateGameObject(cameraRigController.viewer, cameraRigController.target); } } } } public class CameraTargetParams : MonoBehaviour { [Serializable] public enum AimType { Standard, FirstPerson, Aura, Sprinting, OverTheShoulder, ZoomedOut, GroundToAir } public class AimRequest : IDisposable { public readonly AimType aimType; private Action disposeCallback; public AimRequest(AimType type, Action onDispose) { disposeCallback = onDispose; aimType = type; } public void Dispose() { disposeCallback?.Invoke(this); disposeCallback = null; } } public struct CameraParamsOverrideRequest { public CharacterCameraParamsData cameraParamsData; public float priority; } internal class CameraParamsOverride { public CharacterCameraParamsData cameraParamsData; public float priority; public float enterStartTime; public float enterEndTime; public float exitStartTime; public float exitEndTime; public float CalculateAlpha(float t) { float num = 1f; if (t < enterEndTime) { num *= Mathf.Clamp01(Mathf.InverseLerp(enterStartTime, enterEndTime, t)); } if (t > exitStartTime) { num *= Mathf.Clamp01(Mathf.InverseLerp(exitEndTime, exitStartTime, t)); } return easeCurve.Evaluate(num); } } public struct CameraParamsOverrideHandle { internal readonly CameraParamsOverride target; public bool isValid => target != null; internal CameraParamsOverrideHandle(CameraParamsOverride target) { this.target = target; } } public CharacterCameraParams cameraParams; public Transform cameraPivotTransform; [ShowFieldObsolete] [Obsolete] public float fovOverride; [HideInInspector] public UnityEngine.Vector2 recoil; [HideInInspector] public bool dontRaycastToPivot; private static float targetRecoilDampTime = 0.08f; private static float recoilDampTime = 0.05f; private UnityEngine.Vector2 targetRecoil; private UnityEngine.Vector2 recoilVelocity; private UnityEngine.Vector2 targetRecoilVelocity; private List aimRequestStack = new List(); private static readonly AnimationCurve easeCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); private List cameraParamsOverrides; private CharacterCameraParamsData _currentCameraParamsData; public ref CharacterCameraParamsData currentCameraParamsData => ref _currentCameraParamsData; public void AddRecoil(float verticalMin, float verticalMax, float horizontalMin, float horizontalMax) { targetRecoil += new UnityEngine.Vector2(UnityEngine.Random.Range(horizontalMin, horizontalMax), UnityEngine.Random.Range(verticalMin, verticalMax)); } public AimRequest RequestAimType(AimType aimType) { switch (aimType) { case AimType.Aura: { CharacterCameraParamsData data3 = cameraParams.data; data3.idealLocalCameraPos.value += new UnityEngine.Vector3(0f, 1.5f, -7f); CameraParamsOverrideHandle overrideHandle = AddParamsOverride(new CameraParamsOverrideRequest { cameraParamsData = data3, priority = 0.1f }, 0.5f); AimRequest aimRequest4 = new AimRequest(aimType, delegate(AimRequest aimRequest) { RemoveRequest(aimRequest); RemoveParamsOverride(overrideHandle, 0.5f); }); aimRequestStack.Add(aimRequest4); return aimRequest4; } case AimType.ZoomedOut: { CharacterCameraParamsData data2 = cameraParams.data; data2.idealLocalCameraPos.value += new UnityEngine.Vector3(0f, 2f, -20f); CameraParamsOverrideHandle overrideHandle2 = AddParamsOverride(new CameraParamsOverrideRequest { cameraParamsData = data2, priority = 0.1f }, 0.5f); AimRequest aimRequest3 = new AimRequest(aimType, delegate(AimRequest aimRequest) { RemoveRequest(aimRequest); RemoveParamsOverride(overrideHandle2, 0.5f); }); aimRequestStack.Add(aimRequest3); return aimRequest3; } case AimType.GroundToAir: { CharacterCameraParamsData data = cameraParams.data; data.idealLocalCameraPos.value += new UnityEngine.Vector3(0f, 3f, -25f); CameraParamsOverrideHandle overrideHandle3 = AddParamsOverride(new CameraParamsOverrideRequest { cameraParamsData = data, priority = 0.1f }, 0.4f); AimRequest aimRequest2 = new AimRequest(aimType, delegate(AimRequest aimRequest) { RemoveRequest(aimRequest); RemoveParamsOverride(overrideHandle3, UnseenHand.cameraTransitionOutTime); }); aimRequestStack.Add(aimRequest2); return aimRequest2; } default: return null; } } private void RemoveRequest(AimRequest request) { aimRequestStack.Remove(request); } private void Awake() { CharacterBody component = GetComponent(); if ((bool)component && cameraPivotTransform == null) { cameraPivotTransform = component.aimOriginTransform; } cameraParamsOverrides = CollectionPool>.RentCollection(); } private void OnDestroy() { cameraParamsOverrides = CollectionPool>.ReturnCollection(cameraParamsOverrides); } private void Update() { targetRecoil = UnityEngine.Vector2.SmoothDamp(targetRecoil, UnityEngine.Vector2.zero, ref targetRecoilVelocity, targetRecoilDampTime, 180f, Time.deltaTime); recoil = UnityEngine.Vector2.SmoothDamp(recoil, targetRecoil, ref recoilVelocity, recoilDampTime, 180f, Time.deltaTime); CalcParams(out currentCameraParamsData); float time = Time.time; for (int num = cameraParamsOverrides.Count - 1; num >= 0; num--) { if (cameraParamsOverrides[num].exitEndTime <= time) { cameraParamsOverrides.RemoveAt(num); } } } public CameraParamsOverrideHandle AddParamsOverride(CameraParamsOverrideRequest request, float transitionDuration = 0.2f) { float time = Time.time; CameraParamsOverride cameraParamsOverride = new CameraParamsOverride { cameraParamsData = request.cameraParamsData, enterStartTime = time, enterEndTime = time + transitionDuration, exitStartTime = float.PositiveInfinity, exitEndTime = float.PositiveInfinity, priority = request.priority }; int i; for (i = 0; i < cameraParamsOverrides.Count && !(request.priority <= cameraParamsOverrides[i].priority); i++) { } cameraParamsOverrides.Insert(i, cameraParamsOverride); return new CameraParamsOverrideHandle(cameraParamsOverride); } public CameraParamsOverrideHandle RemoveParamsOverride(CameraParamsOverrideHandle handle, float transitionDuration = 0.2f) { if (cameraParamsOverrides == null) { return default(CameraParamsOverrideHandle); } CameraParamsOverride cameraParamsOverride = null; for (int i = 0; i < cameraParamsOverrides.Count; i++) { if (handle.target == cameraParamsOverrides[i]) { cameraParamsOverride = cameraParamsOverrides[i]; break; } } if (cameraParamsOverride == null || cameraParamsOverride.exitStartTime != float.PositiveInfinity) { return default(CameraParamsOverrideHandle); } cameraParamsOverride.exitEndTime = (cameraParamsOverride.exitStartTime = Time.time) + transitionDuration; return default(CameraParamsOverrideHandle); } public void CalcParams(out CharacterCameraParamsData dest) { dest = (cameraParams ? cameraParams.data : CharacterCameraParamsData.basic); float time = Time.time; for (int i = 0; i < cameraParamsOverrides.Count; i++) { CameraParamsOverride cameraParamsOverride = cameraParamsOverrides[i]; if (cameraParamsOverride != null && cameraParamsOverride.cameraParamsData.overrideFirstPersonFadeDuration > 0f) { dest.overrideFirstPersonFadeDuration += cameraParamsOverride.cameraParamsData.overrideFirstPersonFadeDuration; } CharacterCameraParamsData.Blend(in cameraParamsOverride.cameraParamsData, ref dest, cameraParamsOverride.CalculateAlpha(time)); } } } public class CampDirector : MonoBehaviour { private struct NodeDistanceSqrPair { public NodeGraph.NodeIndex nodeIndex; public float distanceSqr; } [Header("Main Properties")] [Tooltip("Which interactables the camp can spawn. If left blank, will fall back to the stage's.")] public DirectorCardCategorySelection interactableDirectorCards; public int baseMonsterCredit; public int baseInteractableCredit; public float campMinimumRadius; public float campMaximumRadius; public Transform campCenterTransform; public CombatDirector combatDirector; [Header("Combat Director Properties")] public EliteDef eliteDef; [Header("Optional Properties")] public bool scaleMonsterCreditWithDifficultyCoefficient; [Range(0f, 1f)] [Tooltip("The amount of credits to take away from the scenedirector's monster credits. A value of 1 takes away all the credits the camp spends - a value of 0 takes away none.")] public float monsterCreditPenaltyCoefficient = 0.5f; private Xoroshiro128Plus rng; private int monsterCredit; private static readonly WeightedSelection cardSelector = new WeightedSelection(); private void Start() { if (NetworkServer.active) { rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint); CalculateCredits(); PopulateCamp(); } } private void OnEnable() { SceneDirector.onPrePopulateMonstersSceneServer += OnSceneDirectorPrePopulate; } private void OnDisable() { SceneDirector.onPrePopulateMonstersSceneServer -= OnSceneDirectorPrePopulate; } private void OnSceneDirectorPrePopulate(SceneDirector sceneDirector) { CalculateCredits(); sceneDirector.ReduceMonsterCredits((int)((float)monsterCredit * monsterCreditPenaltyCoefficient)); } private WeightedSelection GenerateInteractableCardSelection() { DirectorCardCategorySelection directorCardCategorySelection = ScriptableObject.CreateInstance(); if ((bool)interactableDirectorCards) { directorCardCategorySelection.CopyFrom(interactableDirectorCards); } else if ((bool)ClassicStageInfo.instance && (bool)ClassicStageInfo.instance.interactableCategories) { directorCardCategorySelection.CopyFrom(ClassicStageInfo.instance.interactableCategories); } WeightedSelection result = directorCardCategorySelection.GenerateDirectorCardWeightedSelection(); UnityEngine.Object.Destroy(directorCardCategorySelection); return result; } private void PopulateCamp() { WeightedSelection deck = GenerateInteractableCardSelection(); while (baseInteractableCredit > 0) { DirectorCard directorCard = SelectCard(deck, baseInteractableCredit); if (directorCard == null) { break; } if (!directorCard.IsAvailable()) { continue; } baseInteractableCredit -= directorCard.cost; if (!Run.instance) { continue; } for (int i = 0; i < 10; i++) { DirectorPlacementRule placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = campMinimumRadius, maxDistance = campMaximumRadius, position = campCenterTransform.position, spawnOnTarget = campCenterTransform }; GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(directorCard.spawnCard, placementRule, rng)); if ((bool)gameObject) { PurchaseInteraction component = gameObject.GetComponent(); if ((bool)component && component.costType == CostTypeIndex.Money) { component.Networkcost = Run.instance.GetDifficultyScaledCost(component.cost); } break; } } } if ((bool)Run.instance && CombatDirector.cvDirectorCombatDisable.value) { monsterCredit = 0; } if ((bool)combatDirector) { combatDirector.monsterCredit += monsterCredit; monsterCredit = 0; combatDirector.onSpawnedServer.AddListener(OnMonsterSpawnedServer); combatDirector.SpendAllCreditsOnMapSpawns(campCenterTransform); combatDirector.onSpawnedServer.RemoveListener(OnMonsterSpawnedServer); } void OnMonsterSpawnedServer(GameObject masterObject) { EquipmentIndex equipmentIndex = eliteDef?.eliteEquipmentDef?.equipmentIndex ?? EquipmentIndex.None; CharacterMaster component2 = masterObject.GetComponent(); GameObject bodyObject = component2.GetBodyObject(); if ((bool)bodyObject) { EntityStateMachine[] components = bodyObject.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } } if (equipmentIndex != EquipmentIndex.None) { component2.inventory.SetEquipmentIndex(equipmentIndex); } } } private DirectorCard SelectCard(WeightedSelection deck, int maxCost) { cardSelector.Clear(); int i = 0; for (int count = deck.Count; i < count; i++) { WeightedSelection.ChoiceInfo choice = deck.GetChoice(i); if (choice.value.cost <= maxCost) { cardSelector.AddChoice(choice); } } if (cardSelector.Count == 0) { return null; } return cardSelector.Evaluate(rng.nextNormalizedFloat); } private void CalculateCredits() { if (scaleMonsterCreditWithDifficultyCoefficient) { monsterCredit = Mathf.CeilToInt((float)baseMonsterCredit * Run.instance.difficultyCoefficient); } else { monsterCredit = baseMonsterCredit; } } } public class CaptainDefenseMatrixController : MonoBehaviour { public int defenseMatrixToGrantPlayer = 1; public int defenseMatrixToGrantMechanicalAllies = 1; private CharacterBody characterBody; private void Awake() { characterBody = GetComponent(); } private void Start() { if (NetworkServer.active) { TryGrantItem(); } } private void OnEnable() { if (NetworkServer.active) { MasterSummon.onServerMasterSummonGlobal += OnServerMasterSummonGlobal; } } private void OnDisable() { if (NetworkServer.active) { MasterSummon.onServerMasterSummonGlobal -= OnServerMasterSummonGlobal; } } private void TryGrantItem() { if ((bool)characterBody.master) { bool flag = false; if ((bool)characterBody.master.playerStatsComponent) { flag = characterBody.master.playerStatsComponent.currentStats.GetStatValueDouble(PerBodyStatDef.totalTimeAlive, BodyCatalog.GetBodyName(characterBody.bodyIndex)) > 0.0; } if (!flag && characterBody.master.inventory.GetItemCount(RoR2Content.Items.CaptainDefenseMatrix) <= 0) { characterBody.master.inventory.GiveItem(RoR2Content.Items.CaptainDefenseMatrix, defenseMatrixToGrantPlayer); } } } private void OnServerMasterSummonGlobal(MasterSummon.MasterSummonReport summonReport) { if (!characterBody.master || !(characterBody.master == summonReport.leaderMasterInstance)) { return; } CharacterMaster summonMasterInstance = summonReport.summonMasterInstance; if ((bool)summonMasterInstance) { CharacterBody body = summonMasterInstance.GetBody(); if ((bool)body && (body.bodyFlags & CharacterBody.BodyFlags.Mechanical) != 0) { summonMasterInstance.inventory.GiveItem(RoR2Content.Items.CaptainDefenseMatrix, defenseMatrixToGrantMechanicalAllies); } } } } [RequireComponent(typeof(CharacterBody))] public class CaptainSupplyDropController : NetworkBehaviour { [Header("Referenced Components")] public GenericSkill orbitalStrikeSkill; public GenericSkill prepSupplyDropSkill; public GenericSkill supplyDrop1Skill; public GenericSkill supplyDrop2Skill; [Header("Skill Defs")] public SkillDef usedUpSkillDef; public SkillDef lostConnectionSkillDef; [SyncVar] private byte netEnabledSkillsMask; private byte authorityEnabledSkillsMask; private bool attemptSupplyDropReset; private CharacterBody characterBody; [CanBeNull] private SkillDef currentSupplyDrop1SkillDef; [CanBeNull] private SkillDef currentSupplyDrop2SkillDef; [CanBeNull] private SkillDef currentPrepSupplyDropSkillDef; [CanBeNull] private SkillDef currentOrbitalStrikeSkillDef; private static int kCmdCmdSetSkillMask; private bool canUseOrbitalSkills { get { if (SceneCatalog.mostRecentSceneDef.sceneType != SceneType.Stage) { return SceneCatalog.mostRecentSceneDef.sceneType == SceneType.UntimedStage; } return true; } } private bool hasEffectiveAuthority => characterBody.hasEffectiveAuthority; public byte NetworknetEnabledSkillsMask { get { return netEnabledSkillsMask; } [param: In] set { SetSyncVar(value, ref netEnabledSkillsMask, 1u); } } private void Awake() { characterBody = GetComponent(); attemptSupplyDropReset = (bool)supplyDrop1Skill || (bool)supplyDrop2Skill; Release.onEnter += OnPodRelease; } private void OnPodRelease(Release state, CharacterBody body) { if ((object)body == characterBody && base.hasAuthority) { CheckSkillsForReset(); if ((bool)supplyDrop1Skill && supplyDrop1Skill.stock == 0) { UnityEngine.Debug.LogError($"SupplyDrop1Skill's got no stocks, max stock = {supplyDrop1Skill.maxStock}. Forcing one stock"); supplyDrop1Skill.AddOneStock(); } if ((bool)supplyDrop2Skill && supplyDrop2Skill.stock == 0) { UnityEngine.Debug.LogError($"SupplyDrop2Skill's got no stocks, max stock = {supplyDrop2Skill.maxStock}. Forcing one stock"); supplyDrop2Skill.AddOneStock(); } } } private void FixedUpdate() { UpdateSkillOverrides(); if (hasEffectiveAuthority && attemptSupplyDropReset) { CheckSkillsForReset(); attemptSupplyDropReset = (!supplyDrop1Skill || supplyDrop1Skill.stock == 0) && (!supplyDrop2Skill || supplyDrop2Skill.stock == 0); _ = attemptSupplyDropReset; } } private void CheckSkillsForReset() { if ((bool)supplyDrop1Skill && supplyDrop1Skill.stock == 0) { if (supplyDrop1Skill.maxStock <= 0) { UnityEngine.Debug.LogError($"SupplyDrop1Skill's max stock = {supplyDrop1Skill.maxStock}. Recalculating..."); supplyDrop1Skill.RecalculateValues(); } if (supplyDrop1Skill.maxStock > 0) { supplyDrop1Skill.Reset(); } } if ((bool)supplyDrop2Skill && supplyDrop2Skill.stock == 0) { if (supplyDrop2Skill.maxStock <= 0) { UnityEngine.Debug.LogError($"SupplyDrop2Skill's max stock = {supplyDrop2Skill.maxStock}. Recalculating..."); supplyDrop2Skill.RecalculateValues(); } if (supplyDrop2Skill.maxStock > 0) { supplyDrop2Skill.Reset(); } } } private void OnDisable() { SetSkillOverride(ref currentSupplyDrop1SkillDef, null, supplyDrop1Skill); SetSkillOverride(ref currentSupplyDrop2SkillDef, null, supplyDrop2Skill); } private void SetSkillOverride([CanBeNull] ref SkillDef currentSkillDef, [CanBeNull] SkillDef newSkillDef, [NotNull] GenericSkill component) { if ((object)currentSkillDef != newSkillDef) { if ((object)currentSkillDef != null) { component.UnsetSkillOverride(this, currentSkillDef, GenericSkill.SkillOverridePriority.Contextual); } currentSkillDef = newSkillDef; if ((object)currentSkillDef != null) { component.SetSkillOverride(this, currentSkillDef, GenericSkill.SkillOverridePriority.Contextual); } } } private void UpdateSkillOverrides() { if (!base.enabled) { return; } byte b = 0; if (hasEffectiveAuthority) { byte b2 = 0; if (supplyDrop1Skill.stock > 0 || !supplyDrop1Skill.skillDef) { b2 = (byte)(b2 | 1u); } if (supplyDrop2Skill.stock > 0 || !supplyDrop2Skill.skillDef) { b2 = (byte)(b2 | 2u); } if (b2 != authorityEnabledSkillsMask) { authorityEnabledSkillsMask = b2; if (NetworkServer.active) { NetworknetEnabledSkillsMask = authorityEnabledSkillsMask; } else { CallCmdSetSkillMask(authorityEnabledSkillsMask); } } b = authorityEnabledSkillsMask; } else { b = netEnabledSkillsMask; } bool flag = (b & 1) != 0; bool flag2 = (b & 2) != 0; SetSkillOverride(ref currentSupplyDrop1SkillDef, flag ? null : usedUpSkillDef, supplyDrop1Skill); SetSkillOverride(ref currentSupplyDrop2SkillDef, flag2 ? null : usedUpSkillDef, supplyDrop2Skill); } [Command] private void CmdSetSkillMask(byte newMask) { NetworknetEnabledSkillsMask = newMask; } private void UNetVersion() { } protected static void InvokeCmdCmdSetSkillMask(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetSkillMask called on client."); } else { ((CaptainSupplyDropController)obj).CmdSetSkillMask((byte)reader.ReadPackedUInt32()); } } public void CallCmdSetSkillMask(byte newMask) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetSkillMask called on server."); return; } if (base.isServer) { CmdSetSkillMask(newMask); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetSkillMask); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32(newMask); SendCommandInternal(networkWriter, 0, "CmdSetSkillMask"); } static CaptainSupplyDropController() { kCmdCmdSetSkillMask = 176967897; NetworkBehaviour.RegisterCommandDelegate(typeof(CaptainSupplyDropController), kCmdCmdSetSkillMask, InvokeCmdCmdSetSkillMask); NetworkCRC.RegisterBehaviour("CaptainSupplyDropController", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt32(netEnabledSkillsMask); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32(netEnabledSkillsMask); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { netEnabledSkillsMask = (byte)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { netEnabledSkillsMask = (byte)reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } [DisallowMultipleComponent] [RequireComponent(typeof(TeamComponent))] [RequireComponent(typeof(SkillLocator))] public class CharacterBody : NetworkBehaviour, ILifeBehavior, IDisplayNameProvider, IOnTakeDamageServerReceiver, IOnKilledOtherServerReceiver { public static class CommonAssets { public static SkillDef lunarUtilityReplacementSkillDef; public static SkillDef lunarPrimaryReplacementSkillDef; public static SkillDef lunarSecondaryReplacementSkillDef; public static SkillDef lunarSpecialReplacementSkillDef; public static NetworkSoundEventDef nullifiedBuffAppliedSound; public static NetworkSoundEventDef pulverizeBuildupBuffAppliedSound; public static NetworkSoundEventDef[] procCritAttackSpeedSounds; public static GameObject thornExplosionEffect; public static GameObject teleportOnLowHealthVFX; public static GameObject teleportOnLowHealthExplosion; public static GameObject teleportOnLowHealthExplosionNova; public static GameObject prayerBeadEffect; public static GameObject goldOnStageStartEffect; public static void Load() { LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseNullifiedBuffApplied", delegate(NetworkSoundEventDef asset) { nullifiedBuffAppliedSound = asset; }); LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nsePulverizeBuildupBuffApplied", delegate(NetworkSoundEventDef asset) { pulverizeBuildupBuffAppliedSound = asset; }); procCritAttackSpeedSounds = new NetworkSoundEventDef[3]; LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseProcCritAttackSpeed1", delegate(NetworkSoundEventDef asset) { procCritAttackSpeedSounds[0] = asset; }); LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseProcCritAttackSpeed2", delegate(NetworkSoundEventDef asset) { procCritAttackSpeedSounds[1] = asset; }); LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseProcCritAttackSpeed3", delegate(NetworkSoundEventDef asset) { procCritAttackSpeedSounds[2] = asset; }); AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/NoxiousThornExplosion"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { thornExplosionEffect = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/TeleportOnLowHealthVFX"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { teleportOnLowHealthVFX = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/TeleportOnLowHealthExplosion"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { teleportOnLowHealthExplosion = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/VagrantNovaExplosion"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { teleportOnLowHealthExplosionNova = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ExtraStatsOnLevelUpScrapEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { prayerBeadEffect = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/GoldOnStageStartCoinGain"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { goldOnStageStartEffect = x.Result; }; SkillCatalog.skillsDefined.CallWhenAvailable(delegate { lunarUtilityReplacementSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("LunarUtilityReplacement")); lunarPrimaryReplacementSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("LunarPrimaryReplacement")); lunarSecondaryReplacementSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("LunarSecondaryReplacement")); lunarSpecialReplacementSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("LunarDetonatorSpecialReplacement")); }); } } private class TimedBuff { public BuffIndex buffIndex; public float timer; } public delegate void JumpDelegate(); [Flags] public enum BodyFlags : uint { None = 0u, IgnoreFallDamage = 1u, Mechanical = 2u, Masterless = 4u, ImmuneToGoo = 8u, ImmuneToExecutes = 0x10u, SprintAnyDirection = 0x20u, ResistantToAOE = 0x40u, HasBackstabPassive = 0x80u, HasBackstabImmunity = 0x100u, OverheatImmune = 0x200u, Void = 0x400u, ImmuneToVoidDeath = 0x800u, IgnoreItemUpdates = 0x1000u, Devotion = 0x2000u, IgnoreKnockback = 0x4000u, ImmuneToLava = 0x8000u } private struct ItemAvailability { public int helfireCount; public bool hasFireTrail; public bool hasAffixLunar; public bool hasAffixPoison; } [Serializable] public struct NetworkItemBehaviorData { public int intItemValue; public float floatValue; public ItemIndex itemIndex { get { return (ItemIndex)intItemValue; } set { intItemValue = (int)value; } } public NetworkItemBehaviorData(ItemIndex _index, float _floatValue) { intItemValue = (int)_index; floatValue = _floatValue; } public NetworkItemBehaviorData(int _index, float _floatVal) { intItemValue = _index; floatValue = _floatVal; } } public class ItemBehavior : MonoBehaviour { public CharacterBody body; public int stack; } public class AffixHauntedBehavior : ItemBehavior { private GameObject affixHauntedWard; private void FixedUpdate() { if (!NetworkServer.active) { return; } bool flag = stack > 0; if ((bool)affixHauntedWard != flag) { if (flag) { affixHauntedWard = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/AffixHauntedWard")); affixHauntedWard.GetComponent().teamIndex = body.teamComponent.teamIndex; affixHauntedWard.GetComponent().Networkradius = 30f + body.radius; affixHauntedWard.GetComponent().AttachToGameObjectAndSpawn(body.gameObject); } else { UnityEngine.Object.Destroy(affixHauntedWard); affixHauntedWard = null; } } } private void OnDisable() { if ((bool)affixHauntedWard) { UnityEngine.Object.Destroy(affixHauntedWard); } } } public class QuestVolatileBatteryBehaviorServer : ItemBehavior { private NetworkedBodyAttachment attachment; private void Start() { attachment = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/QuestVolatileBatteryAttachment")).GetComponent(); attachment.AttachToGameObjectAndSpawn(body.gameObject); } private void OnDestroy() { if ((bool)attachment) { UnityEngine.Object.Destroy(attachment.gameObject); attachment = null; } } } public class TimeBubbleItemBehaviorServer : ItemBehavior { private void OnDestroy() { if ((bool)body.timeBubbleWardInstance) { UnityEngine.Object.Destroy(body.timeBubbleWardInstance); } } } public class ElementalRingsBehavior : ItemBehavior { private void OnDisable() { if ((bool)body) { if (body.HasBuff(RoR2Content.Buffs.ElementalRingsReady)) { body.RemoveBuff(RoR2Content.Buffs.ElementalRingsReady); } if (body.HasBuff(RoR2Content.Buffs.ElementalRingsCooldown)) { body.RemoveBuff(RoR2Content.Buffs.ElementalRingsCooldown); } } } private void FixedUpdate() { bool flag = body.HasBuff(RoR2Content.Buffs.ElementalRingsCooldown); bool flag2 = body.HasBuff(RoR2Content.Buffs.ElementalRingsReady); if (!flag && !flag2) { body.AddBuff(RoR2Content.Buffs.ElementalRingsReady); } if (flag2 && flag) { body.RemoveBuff(RoR2Content.Buffs.ElementalRingsReady); } } } public class AffixEchoBehavior : ItemBehavior { private DeployableMinionSpawner echoSpawner1; private DeployableMinionSpawner echoSpawner2; private CharacterSpawnCard spawnCard; private List spawnedEchoes = new List(); private void FixedUpdate() { spawnCard.nodeGraphType = (body.isFlying ? MapNodeGroup.GraphType.Air : MapNodeGroup.GraphType.Ground); } private void Awake() { base.enabled = false; } private void OnEnable() { MasterCatalog.MasterIndex masterIndex = MasterCatalog.FindAiMasterIndexForBody(body.bodyIndex); spawnCard = ScriptableObject.CreateInstance(); spawnCard.prefab = MasterCatalog.GetMasterPrefab(masterIndex); spawnCard.inventoryToCopy = body.inventory; spawnCard.equipmentToGrant = new EquipmentDef[1]; spawnCard.itemsToGrant = new ItemCountPair[1] { new ItemCountPair { itemDef = RoR2Content.Items.SummonedEcho, count = 1 } }; CreateSpawners(); } private void OnDisable() { UnityEngine.Object.Destroy(spawnCard); spawnCard = null; for (int num = spawnedEchoes.Count - 1; num >= 0; num--) { if ((bool)spawnedEchoes[num]) { spawnedEchoes[num].TrueKill(); } } DestroySpawners(); } private void CreateSpawners() { Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.seed ^ (ulong)GetInstanceID()); CreateSpawner(ref echoSpawner1, DeployableSlot.RoboBallRedBuddy, spawnCard); CreateSpawner(ref echoSpawner2, DeployableSlot.RoboBallGreenBuddy, spawnCard); void CreateSpawner(ref DeployableMinionSpawner buddySpawner, DeployableSlot deployableSlot, SpawnCard spawnCard) { buddySpawner = new DeployableMinionSpawner(body.master, deployableSlot, rng) { respawnInterval = 30f, spawnCard = spawnCard }; buddySpawner.onMinionSpawnedServer += OnMinionSpawnedServer; } } private void DestroySpawners() { echoSpawner1?.Dispose(); echoSpawner1 = null; echoSpawner2?.Dispose(); echoSpawner2 = null; } private void OnMinionSpawnedServer(SpawnCard.SpawnResult spawnResult) { GameObject spawnedInstance = spawnResult.spawnedInstance; if (!spawnedInstance) { return; } CharacterMaster spawnedMaster = spawnedInstance.GetComponent(); if ((bool)spawnedMaster) { spawnedEchoes.Add(spawnedMaster); OnDestroyCallback.AddCallback(spawnedMaster.gameObject, delegate { spawnedEchoes.Remove(spawnedMaster); }); } } } private static class AssetReferences { public static GameObject engiShieldTempEffectPrefab; public static GameObject bucklerShieldTempEffectPrefab; public static GameObject slowDownTimeTempEffectPrefab; public static GameObject crippleEffectPrefab; public static GameObject tonicBuffEffectPrefab; public static GameObject weakTempEffectPrefab; public static GameObject energizedTempEffectPrefab; public static GameObject barrierTempEffectPrefab; public static GameObject nullifyStack1EffectPrefab; public static GameObject nullifyStack2EffectPrefab; public static GameObject nullifyStack3EffectPrefab; public static GameObject regenBoostEffectPrefab; public static GameObject elephantDefenseEffectPrefab; public static GameObject healingDisabledEffectPrefab; public static GameObject noCooldownEffectPrefab; public static GameObject doppelgangerEffectPrefab; public static GameObject deathmarkEffectPrefab; public static GameObject crocoRegenEffectPrefab; public static GameObject mercExposeEffectPrefab; public static GameObject lifestealOnHitEffectPrefab; public static GameObject teamWarCryEffectPrefab; public static GameObject randomDamageEffectPrefab; public static GameObject lunarGolemShieldEffectPrefab; public static GameObject warbannerEffectPrefab; public static GameObject teslaFieldEffectPrefab; public static GameObject lunarSecondaryRootEffectPrefab; public static GameObject lunarDetonatorEffectPrefab; public static GameObject fruitingEffectPrefab; public static GameObject mushroomVoidTempEffectPrefab; public static GameObject bearVoidTempEffectPrefab; public static GameObject outOfCombatArmorEffectPrefab; public static GameObject voidFogMildEffectPrefab; public static GameObject voidFogStrongEffectPrefab; public static GameObject voidJailerSlowEffectPrefab; public static GameObject voidRaidcrabWardWipeFogEffectPrefab; public static GameObject aurelioniteBlessingEffectInstance; public static GameObject permanentDebuffEffectPrefab; public static void Resolve() { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/EngiShield"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { engiShieldTempEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/BucklerDefense"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { bucklerShieldTempEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/SlowDownTime"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { slowDownTimeTempEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/CrippleEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { crippleEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/TonicBuffEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { tonicBuffEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/WeakEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { weakTempEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/EnergizedEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { energizedTempEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/BarrierEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { barrierTempEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/RegenBoostEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { regenBoostEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/ElephantDefense"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { elephantDefenseEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/HealingDisabledEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { healingDisabledEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/NoCooldownEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { noCooldownEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/DoppelgangerEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { doppelgangerEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/NullifyStack1Effect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { nullifyStack1EffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/NullifyStack2Effect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { nullifyStack2EffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/NullifyStack3Effect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { nullifyStack3EffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/DeathMarkEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { deathmarkEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/CrocoRegenEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { crocoRegenEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/MercExposeEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { mercExposeEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/LifeStealOnHitAura"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { lifestealOnHitEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/TeamWarCryAura"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { teamWarCryEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/LunarDefense"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { lunarGolemShieldEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/RandomDamageBuffEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { randomDamageEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/WarbannerBuffEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { warbannerEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/TeslaFieldBuffEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { teslaFieldEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/LunarSecondaryRootEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { lunarSecondaryRootEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/LunarDetonatorEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { lunarDetonatorEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/FruitingEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { fruitingEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/MushroomVoidEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { mushroomVoidTempEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/BearVoidEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { bearVoidTempEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/VoidFogMildEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { voidFogMildEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/TemporaryVisualEffects/VoidFogStrongEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { voidFogStrongEffectPrefab = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC1/VoidRaidCrab/VoidRaidCrabWardWipeFogEffect.prefab"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { voidRaidcrabWardWipeFogEffectPrefab = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC1/OutOfCombatArmor/OutOfCombatArmorEffect.prefab"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { outOfCombatArmorEffectPrefab = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC1/VoidJailer/VoidJailerTetherDebuff.prefab"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { voidJailerSlowEffectPrefab = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC2/Elites/EliteAurelionite/AffixAurelioniteArmorBubble.prefab"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { aurelioniteBlessingEffectInstance = x.Result; }; } } private class ConstructTurretMessage : MessageBase { public GameObject builder; public UnityEngine.Vector3 position; public UnityEngine.Quaternion rotation; public MasterCatalog.NetworkMasterIndex turretMasterIndex; public override void Serialize(NetworkWriter writer) { writer.Write(builder); writer.Write(position); writer.Write(rotation); GeneratedNetworkCode._WriteNetworkMasterIndex_MasterCatalog(writer, turretMasterIndex); } public override void Deserialize(NetworkReader reader) { builder = reader.ReadGameObject(); position = reader.ReadVector3(); rotation = reader.ReadQuaternion(); turretMasterIndex = GeneratedNetworkCode._ReadNetworkMasterIndex_MasterCatalog(reader); } } private class DelayedDamageInfo { public DamageInfo halfDamage = new DamageInfo(); public float timeUntilDamage = 3f; } public class TeleportOnLowHealthBehavior : ItemBehavior { private CharacterBody characterBody; private bool hasActivated; private bool hasItem; private bool hasBuff; private bool hasCooldown; private void Start() { if (!hasActivated) { characterBody = GetComponent(); characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealth); characterBody.RemoveOldestTimedBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown); characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown); characterBody.AddBuff(DLC2Content.Buffs.TeleportOnLowHealth); characterBody.hasTeleported = false; hasActivated = true; } } private void Update() { hasItem = characterBody.inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealth) > 0; hasBuff = characterBody.HasBuff(DLC2Content.Buffs.TeleportOnLowHealth); hasCooldown = characterBody.HasBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown); if (!hasItem) { if (hasBuff) { characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealth); } if (hasCooldown) { characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown); } } else if (!hasBuff && !hasCooldown && characterBody.hasTeleported) { characterBody.AddBuff(DLC2Content.Buffs.TeleportOnLowHealth); characterBody.hasTeleported = false; } } private void OnDisable() { characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealth); characterBody.RemoveOldestTimedBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown); characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown); } } public class DelayedDamageBehavior : ItemBehavior { private CharacterBody characterBody; private bool hasActivated; private bool hasItem; private bool hasBuff; private bool hasCooldown; private void Start() { if (!hasActivated) { characterBody = GetComponent(); hasActivated = true; } } private void Update() { hasItem = characterBody.inventory.GetItemCount(DLC2Content.Items.DelayedDamage) > 0; hasBuff = characterBody.HasBuff(DLC2Content.Buffs.DelayedDamageBuff); hasCooldown = characterBody.HasBuff(DLC2Content.Buffs.DelayedDamageBuff); if (!hasItem) { if (hasBuff) { characterBody.RemoveBuff(DLC2Content.Buffs.DelayedDamageBuff); characterBody.RemoveOldestTimedBuff(DLC2Content.Buffs.DelayedDamageBuff); } if (hasCooldown) { characterBody.RemoveBuff(DLC2Content.Buffs.DelayedDamageBuff); characterBody.RemoveOldestTimedBuff(DLC2Content.Buffs.DelayedDamageBuff); characterBody.RemoveBuff(DLC2Content.Buffs.DelayedDamageDebuff); } } } } public class MeteorAttackOnHighDamageBehavior : ItemBehavior { private CharacterBody characterBody; private bool hasActivated; private void FixedUpdate() { if (!hasActivated) { characterBody = GetComponent(); hasActivated = true; } if (characterBody.runicLensMeteorReady) { characterBody.runicLensStartTime = Run.instance.time; if (characterBody.runicLensStartTime >= characterBody.runicLensImpactTime && characterBody.runicLensMeteorReady) { characterBody.detonateRunicLensMeteor(); characterBody.runicLensMeteorReady = false; } } } } [Serializable] public class CharacterBodyUnityEvent : UnityEvent { } [HideInInspector] [Tooltip("This is assigned to the prefab automatically by BodyCatalog at runtime. Do not set this value manually.")] public BodyIndex bodyIndex = BodyIndex.None; public bool CharacterIsVisible; [Tooltip("How much the combat director paid for this character. If this enemy is culled, then we refund the combat director for the cost it paid to spawn us.")] public float cost = -1f; public bool dontCull; [Tooltip("The baseline importance for this character. 0 is standard, elites get a +2 modifier, bosses get +10, players get +5000. Characters of low importance are culled in some circumstances.")] public int BaseImportance; [Tooltip("The dynamically calculated level of importance for this enemy.")] public int Importance = -1; public bool inLava; [Tooltip("The language token to use as the base name of this character.")] public string baseNameToken; public string subtitleNameToken; private BuffIndex[] activeBuffsList; private int activeBuffsListCount; private int[] buffs; private int eliteBuffCount; private List timedBuffs = new List(); [NonSerialized] public int pendingTonicAfflictionCount; public JumpDelegate onJump; private int previousMultiKillBuffCount; private GameObject warCryEffectInstance; [EnumMask(typeof(BodyFlags))] public BodyFlags bodyFlags; private NetworkInstanceId masterObjectId; private GameObject _masterObject; private CharacterMaster _master; private bool linkedToMaster; private bool disablingHurtBoxes; private EquipmentIndex previousEquipmentIndex = EquipmentIndex.None; private new Transform transform; private SfxLocator sfxLocator; public float lavaCooldown = 0.2f; private float lavaTimer; private ItemAvailability itemAvailability; private static List instancesList; public static readonly ReadOnlyCollection readOnlyInstancesList; private bool _isSprinting; private const float outOfCombatDelay = 5f; private const float outOfDangerDelay = 7f; private float outOfCombatStopwatch; private float outOfDangerStopwatch; private bool _outOfDanger = true; private UnityEngine.Vector3 previousPosition; private const float notMovingWait = 1f; private float notMovingStopwatch; public bool rootMotionInMainState; public float mainRootSpeed; public float baseMaxHealth; public float baseRegen; public float baseMaxShield; public float baseMoveSpeed; public float baseAcceleration; public float baseJumpPower; public float baseDamage; public float baseAttackSpeed; public float baseCrit; public float baseArmor; public float baseVisionDistance = float.PositiveInfinity; public int baseJumpCount = 1; public float sprintingSpeedMultiplier = 1.45f; public bool autoCalculateLevelStats; public float levelMaxHealth; public float levelRegen; public float levelMaxShield; public float levelMoveSpeed; public float levelJumpPower; public float levelDamage; public float levelAttackSpeed; public float levelCrit; public float levelArmor; private float m_surfaceSpeedBoost; private bool statsDirty; private int currentHealthLevel; private int oldHealthLevel; private float damageFromRecalculateStats; private int numberOfKills; private bool canCleanInventory = true; public int extraSecondaryFromSkill; public int extraSpecialFromSkill; private GameObject lowerHealthHigherDamageSteam; [HideInInspector] public LowerHealthHigherDamageEffectUpdater lowerHealthHigherDamageEffectUpdater; private bool boostAllStatsTimerStarted; private bool boostAllStatsCoolDownTimerStarted; private float boostAllStatsTimer; private float boostAllStatsTriggerTimer = 5f; private float boostAllStatsCoolDownTriggerTimer = 10f; private float boostAllStatsCoolDownStartTimer; private float boostAllStatsCoolDownTimer; private float boostAllStatsStartTimer; private float boostAllStatsTriggerChance; public bool canBoostAllStats; private float boostAllStatsDefaultTriggerChance = 0.25f; private float boostAllStatsTriggerIncrease = 0.1f; private float boostAllStatsMultiplier = 0.2f; private int extraStatsOnLevelUpCountModifier; [HideInInspector] public IncreaseDamageOnMultiKillItemDisplayUpdater increaseDamageOnMultiKillItemDisplayUpdater; private bool lowerPricedChestsActive; private bool canPurchaseLoweredPricedChests; public bool allSkillsDisabled; private ScreenDamageCalculatorDisabledSkills screenDamageSkillsDisabled; private int oldComboMeter; public bool isTeleporting; public int solitudeLevelCount; private float aimTimer; private const uint masterDirtyBit = 1u; private const uint buffsDirtyBit = 2u; private const uint outOfCombatBit = 4u; private const uint outOfDangerBit = 8u; private const uint sprintingBit = 16u; private const uint allDirtyBits = 31u; public Action OnNetworkItemBehaviorUpdate; private HelfireController helfireController; private float helfireLifetime; private DamageTrail fireTrail; public bool wasLucky; private const float poisonballAngle = 25f; private const float poisonballDamageCoefficient = 1f; private const float poisonballRefreshTime = 6f; private float poisonballTimer; private const float lunarMissileDamageCoefficient = 0.3f; private const float lunarMissileRefreshTime = 10f; private const float lunarMissileDelayBetweenShots = 0.1f; private float lunarMissileRechargeTimer = 10f; private float lunarMissileTimerBetweenShots; private int remainingMissilesToFire; private GameObject lunarMissilePrefab; private GameObject timeBubbleWardInstance; private TemporaryVisualEffect engiShieldTempEffectInstance; private TemporaryVisualEffect bucklerShieldTempEffectInstance; private TemporaryVisualEffect slowDownTimeTempEffectInstance; private TemporaryVisualEffect crippleEffectInstance; private TemporaryVisualEffect tonicBuffEffectInstance; private TemporaryVisualEffect weakTempEffectInstance; private TemporaryVisualEffect energizedTempEffectInstance; private TemporaryVisualEffect barrierTempEffectInstance; private TemporaryVisualEffect nullifyStack1EffectInstance; private TemporaryVisualEffect nullifyStack2EffectInstance; private TemporaryVisualEffect nullifyStack3EffectInstance; private TemporaryVisualEffect regenBoostEffectInstance; private TemporaryVisualEffect elephantDefenseEffectInstance; private TemporaryVisualEffect healingDisabledEffectInstance; private TemporaryVisualEffect noCooldownEffectInstance; private TemporaryVisualEffect doppelgangerEffectInstance; private TemporaryVisualEffect deathmarkEffectInstance; private TemporaryVisualEffect crocoRegenEffectInstance; private TemporaryVisualEffect mercExposeEffectInstance; private TemporaryVisualEffect lifestealOnHitEffectInstance; private TemporaryVisualEffect teamWarCryEffectInstance; private TemporaryVisualEffect randomDamageEffectInstance; private TemporaryVisualEffect lunarGolemShieldEffectInstance; private TemporaryVisualEffect warbannerEffectInstance; private TemporaryVisualEffect teslaFieldEffectInstance; private TemporaryVisualEffect lunarSecondaryRootEffectInstance; private TemporaryVisualEffect lunarDetonatorEffectInstance; private TemporaryVisualEffect fruitingEffectInstance; private TemporaryVisualEffect mushroomVoidTempEffectInstance; private TemporaryVisualEffect bearVoidTempEffectInstance; private TemporaryVisualEffect outOfCombatArmorEffectInstance; private TemporaryVisualEffect voidFogMildEffectInstance; private TemporaryVisualEffect voidFogStrongEffectInstance; private TemporaryVisualEffect voidJailerSlowEffectInstance; private TemporaryVisualEffect voidRaidcrabWardWipeFogEffectInstance; private TemporaryVisualEffect aurelioniteBlessingEffectInstance; [Tooltip("How long it takes for spread bloom to reset from full.")] public float spreadBloomDecayTime = 0.45f; [Tooltip("The spread bloom interpretation curve.")] public AnimationCurve spreadBloomCurve; private float spreadBloomInternal; [FormerlySerializedAs("crosshairPrefab")] [SerializeField] [Tooltip("The crosshair prefab used for this body.")] private GameObject _defaultCrosshairPrefab; [HideInInspector] public bool hideCrosshair; private const float multiKillMaxInterval = 1f; private float multiKillTimer; private const int multiKillThresholdForWarcry = 4; private const float increasedDamageMultiKillMaxInterval = 5f; private float increasedDamageKillTimer; private int oldKillcount; private const int multiKillThresholdForIncreasedDamage = 5; private int secondarySkillStacks; [HideInInspector] public IncreasePrimaryDamageEffectUpdater increasePrimaryDamageEffectUpdater; private float delayedDamageRefreshTime = 10f; private float secondHalfOfDamageTime = 3f; private int oldDelayedDamageCount; private bool halfDamageReady; private float halfDamageTimer; public bool protectFromOneShot; private DamageInfo secondHalfOfDamage; private List incomingDamageList = new List(); public bool hasTeleported; private UnityEngine.Vector3 runicLensPosition; private EffectData runicLensEffectData = new EffectData(); private DamageInfo runicLensDamageInfo = new DamageInfo(); private float runicLensDamage; private float runicLensBlastForce; private float runicLensBlastRadius; private float runicLensStartTime; private float runicLensImpactTime; public bool runicLensMeteorReady; private bool hasStackableDebuff; private bool tamperedHeartActive; private float tamperedHeartRegenBonus; private float tamperedHeartMSpeedBonus; private float tamperedHeartDamageBonus; private float tamperedHeartAttackSpeedBonus; private float tamperedHeartArmorBonus; [Tooltip("The child transform to be used as the aiming origin.")] public Transform aimOriginTransform; [Tooltip("The hull size to use when pathfinding for this object.")] public HullClassification hullClassification; [Tooltip("The icon displayed for ally healthbars")] public Texture portraitIcon; [Tooltip("The main color of the body. Currently only used in the logbook.")] public UnityEngine.Color bodyColor = UnityEngine.Color.clear; [Tooltip("By default, players and enemies are assigned to either PlayerBody or EnemyBody, based on team. But some enemies (Gups) want a specific layer - this will skip that assignment.")] public bool doNotReassignToTeamBasedCollisionLayer; [FormerlySerializedAs("isBoss")] [Tooltip("Whether or not this is a boss for dropping items on death.")] public bool isChampion; public VehicleSeat currentVehicle; [Tooltip("The pod prefab to use for handling this character's first-time spawn animation.")] public GameObject preferredPodPrefab; [Tooltip("The preferred state to use for handling the character's first-time spawn animation. Only used with no preferred pod prefab.")] public SerializableEntityStateType preferredInitialStateType = new SerializableEntityStateType(typeof(Uninitialized)); public uint skinIndex; public string customKillTotalStatName; public Transform overrideCoreTransform; private static int kCmdCmdAddTimedBuff; private static int kCmdCmdSetInLava; private static int kCmdCmdUpdateSprint; private static int kCmdCmdOnSkillActivated; private static int kCmdCmdTransmitItemBehavior; private static int kRpcRpcTransmitItemBehavior; private static int kCmdCmdSpawnDelayedDamageEffect; private static int kRpcRpcTeleportCharacterToSafety; private static int kRpcRpcBark; private static int kCmdCmdRequestVehicleEjection; private static int kRpcRpcUsePreferredInitialStateType; public CharacterMaster master { get { if (!masterObject) { return null; } return _master; } } public Inventory inventory { get; private set; } public bool isPlayerControlled { get; private set; } public float executeEliteHealthFraction { get; private set; } public GameObject masterObject { get { if (!_masterObject) { if (NetworkServer.active) { _masterObject = NetworkServer.FindLocalObject(masterObjectId); } else if (NetworkClient.active) { _masterObject = ClientScene.FindLocalObject(masterObjectId); } _master = (_masterObject ? _masterObject.GetComponent() : null); if ((bool)_master) { PlayerCharacterMasterController component = _masterObject.GetComponent(); isPlayerControlled = component; if ((bool)inventory) { inventory.onInventoryChanged -= OnInventoryChanged; } inventory = _master.inventory; if ((bool)inventory) { inventory.onInventoryChanged += OnInventoryChanged; OnInventoryChanged(); } statsDirty = true; } } return _masterObject; } set { masterObjectId = value.GetComponent().netId; statsDirty = true; } } public Rigidbody rigidbody { get; private set; } public NetworkIdentity networkIdentity { get; private set; } public CharacterMotor characterMotor { get; private set; } public CharacterDirection characterDirection { get; private set; } public TeamComponent teamComponent { get; private set; } public HealthComponent healthComponent { get; private set; } public EquipmentSlot equipmentSlot { get; private set; } public InputBankTest inputBank { get; private set; } public SkillLocator skillLocator { get; private set; } public ModelLocator modelLocator { get; private set; } public HurtBoxGroup hurtBoxGroup { get; private set; } public HurtBox mainHurtBox { get; private set; } public Transform coreTransform { get; private set; } public bool hasEffectiveAuthority { get; private set; } public bool isSprinting { get { return _isSprinting; } set { if (_isSprinting != value) { _isSprinting = value; RecalculateStats(); if (value) { OnSprintStart(); } else { OnSprintStop(); } if (NetworkServer.active) { SetDirtyBit(16u); } else if (hasEffectiveAuthority) { CallCmdUpdateSprint(value); } } } } public bool outOfCombat { get; private set; } = true; public bool outOfDanger { get { return _outOfDanger; } private set { if (_outOfDanger != value) { _outOfDanger = value; OnOutOfDangerChanged(); } } } public float experience { get; private set; } public float level { get; private set; } public float maxHealth { get; private set; } public float maxBarrier { get; private set; } public float barrierDecayRate { get; private set; } public float regen { get; private set; } public float maxShield { get; private set; } public float moveSpeed { get; private set; } public float acceleration { get; private set; } public float surfaceSpeedBoost { get { return m_surfaceSpeedBoost; } set { if (!Mathf.Approximately(m_surfaceSpeedBoost, value)) { m_surfaceSpeedBoost = value; RecalculateStats(); } } } public float jumpPower { get; private set; } public int maxJumpCount { get; private set; } public float maxJumpHeight { get; private set; } public float damage { get; private set; } public float attackSpeed { get; private set; } public float crit { get; private set; } public float critMultiplier { get; private set; } public float bleedChance { get; private set; } public float armor { get; private set; } public float visionDistance { get; private set; } public float critHeal { get; private set; } public float cursePenalty { get; private set; } public bool hasOneShotProtection { get; private set; } public bool isGlass { get; private set; } public float oneShotProtectionFraction { get; private set; } public bool canPerformBackstab { get; private set; } public bool canReceiveBackstab { get; private set; } public float maxBonusHealth { get; private set; } public bool shouldAim { get { if (aimTimer > 0f) { return !isSprinting; } return false; } } public int killCountServer { get; private set; } public float bestFitRadius => Mathf.Max(radius, characterMotor ? characterMotor.capsuleHeight : 1f); public float bestFitActualRadius => Mathf.Max(radius, characterMotor ? (characterMotor.capsuleHeight * 0.5f) : 1f); public bool hasCloakBuff { get { if (!HasBuff(RoR2Content.Buffs.Cloak)) { return HasBuff(RoR2Content.Buffs.AffixHauntedRecipient); } return true; } } public float spreadBloomAngle => spreadBloomCurve.Evaluate(spreadBloomInternal); public GameObject defaultCrosshairPrefab => _defaultCrosshairPrefab; public int multiKillCount { get; private set; } public int increasedDamageKillCount { get; private set; } public int increasedDamageKillCountBuff { get; private set; } public float luminousShotDamage { get; private set; } public bool luminousShotReady { get; private set; } public UnityEngine.Vector3 corePosition { get { if (!coreTransform) { return transform.position; } return coreTransform.position; } } public UnityEngine.Vector3 footPosition { get { UnityEngine.Vector3 position = transform.position; if ((bool)characterMotor) { position.y -= characterMotor.capsuleHeight * 0.5f; } return position; } } public float radius { get; private set; } public UnityEngine.Vector3 aimOrigin { get { if (!aimOriginTransform) { return corePosition; } return aimOriginTransform.position; } } public bool isElite { get; private set; } public bool isBoss { get { if ((bool)master) { return master.isBoss; } return false; } } public bool isFlying { get { if ((bool)characterMotor) { return characterMotor.isFlying; } return true; } } public Run.FixedTimeStamp localStartTime { get; private set; } = Run.FixedTimeStamp.positiveInfinity; public bool isEquipmentActivationAllowed { get { if ((bool)currentVehicle) { return currentVehicle.isEquipmentActivationAllowed; } return true; } } public event Action onInventoryChanged; public event Action onSkillActivatedServer; public event Action onSkillActivatedAuthority; public static event Action onBodyAwakeGlobal; public static event Action onBodyDestroyGlobal; public static event Action onBodyStartGlobal; public static event Action onBodyInventoryChangedGlobal; [MethodImpl(MethodImplOptions.AggressiveInlining)] public CharacterBody GetBody() { return this; } public void DebugDrawLine(UnityEngine.Vector3 start, UnityEngine.Vector3 end, UnityEngine.Color color) { UnityEngine.Debug.DrawLine(start, end, color, 5f); } [InitDuringStartup] private static void LoadCommonAssets() { CommonAssets.Load(); } public string GetDisplayName() { return Language.GetString(baseNameToken); } public string GetSubtitle() { return Language.GetString(subtitleNameToken); } public string GetUserName() { string text = ""; if ((bool)master) { PlayerCharacterMasterController component = master.GetComponent(); if ((bool)component) { text = component.GetDisplayName(); } } if (string.IsNullOrEmpty(text)) { text = GetDisplayName(); } return text; } public string GetColoredUserName() { Color32 color = new Color32(127, 127, 127, byte.MaxValue); string text = null; if ((bool)master) { PlayerCharacterMasterController component = master.GetComponent(); if ((bool)component) { GameObject networkUserObject = component.networkUserObject; if ((bool)networkUserObject) { NetworkUser component2 = networkUserObject.GetComponent(); if ((bool)component2) { color = component2.userColor; text = component2.userName; } } } } if (text == null) { text = GetDisplayName(); } return Util.GenerateColoredString(text, color); } [Server] private void WriteBuffs(NetworkWriter writer) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::WriteBuffs(UnityEngine.Networking.NetworkWriter)' called on client"); return; } writer.Write((byte)activeBuffsListCount); for (int i = 0; i < activeBuffsListCount; i++) { BuffIndex buffIndex = activeBuffsList[i]; BuffDef buffDef = BuffCatalog.GetBuffDef(buffIndex); writer.WriteBuffIndex(buffIndex); if (buffDef.canStack) { writer.WritePackedUInt32((uint)buffs[(int)buffIndex]); } } } [Client] private void ReadBuffs(NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.CharacterBody::ReadBuffs(UnityEngine.Networking.NetworkReader)' called on server"); return; } if (activeBuffsList == null) { UnityEngine.Debug.LogError("Trying to ReadBuffs, but our activeBuffsList is null"); return; } int activeBuffsIndexToCheck = 0; int num = reader.ReadByte(); BuffIndex buffIndex = BuffIndex.None; for (int i = 0; i < num; i++) { BuffIndex buffIndex2 = reader.ReadBuffIndex(); BuffDef buffDef = BuffCatalog.GetBuffDef(buffIndex2); if (buffDef != null) { int num2 = 1; if (buffDef.canStack) { num2 = (int)reader.ReadPackedUInt32(); } if (num2 > 0 && !NetworkServer.active) { ZeroBuffIndexRange(buffIndex + 1, buffIndex2); SetBuffCount(buffIndex2, num2); } buffIndex = buffIndex2; } else { UnityEngine.Debug.LogErrorFormat("No BuffDef for index {0}. body={1}, netID={2}", buffIndex2, base.gameObject, base.netId); } } if (!NetworkServer.active) { ZeroBuffIndexRange(buffIndex + 1, (BuffIndex)BuffCatalog.buffCount); } void ZeroBuffIndexRange(BuffIndex start, BuffIndex end) { while (activeBuffsIndexToCheck < activeBuffsListCount) { BuffIndex buffIndex3 = activeBuffsList[activeBuffsIndexToCheck]; if (end <= buffIndex3) { break; } int num3; if (start <= buffIndex3) { SetBuffCount(buffIndex3, 0); num3 = activeBuffsIndexToCheck - 1; activeBuffsIndexToCheck = num3; } num3 = activeBuffsIndexToCheck + 1; activeBuffsIndexToCheck = num3; } } } [Server] public void AddBuff(BuffIndex buffType) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddBuff(RoR2.BuffIndex)' called on client"); } else if (buffType != BuffIndex.None) { SetBuffCount(buffType, buffs[(int)buffType] + 1); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Server] public void AddBuff(BuffDef buffDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddBuff(RoR2.BuffDef)' called on client"); } else { AddBuff(buffDef?.buffIndex ?? BuffIndex.None); } } [Server] public void RemoveBuff(BuffIndex buffType) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::RemoveBuff(RoR2.BuffIndex)' called on client"); } else { if (buffType == BuffIndex.None) { return; } SetBuffCount(buffType, buffs[(int)buffType] - 1); if (buffType == RoR2Content.Buffs.MedkitHeal.buffIndex) { if (GetBuffCount(RoR2Content.Buffs.MedkitHeal.buffIndex) == 0) { int itemCount = inventory.GetItemCount(RoR2Content.Items.Medkit); float num = 20f; float num2 = maxHealth * 0.05f * (float)itemCount; healthComponent.Heal(num + num2, default(ProcChainMask)); EffectData effectData = new EffectData { origin = transform.position }; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/MedkitHealEffect"), effectData, transmit: true); } } else if (buffType == RoR2Content.Buffs.TonicBuff.buffIndex) { if ((bool)inventory && GetBuffCount(RoR2Content.Buffs.TonicBuff) == 0 && pendingTonicAfflictionCount > 0) { inventory.GiveItem(RoR2Content.Items.TonicAffliction, pendingTonicAfflictionCount); PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(RoR2Content.Items.TonicAffliction.itemIndex); GenericPickupController.SendPickupMessage(master, pickupIndex); pendingTonicAfflictionCount = 0; } } else if (buffType == DLC2Content.Buffs.SoulCost.buffIndex) { cursePenalty -= 0.1f * (float)GetBuffCount(DLC2Content.Buffs.SoulCost); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Server] public void RemoveBuff(BuffDef buffDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::RemoveBuff(RoR2.BuffDef)' called on client"); } else { RemoveBuff(buffDef?.buffIndex ?? BuffIndex.None); } } public void SetBuffCount(BuffIndex buffType, int newCount) { newCount = Mathf.Max(newCount, 0); ref int reference = ref buffs[(int)buffType]; if (newCount == reference) { return; } int num = reference; reference = newCount; BuffDef buffDef = BuffCatalog.GetBuffDef(buffType); bool flag = true; if (!buffDef.canStack) { flag = num == 0 != (newCount == 0); } if (flag) { if (newCount == 0) { ArrayUtils.ArrayRemoveAt(activeBuffsList, ref activeBuffsListCount, Array.IndexOf(activeBuffsList, buffType)); OnBuffFinalStackLost(buffDef); } else if (num == 0) { int i; for (i = 0; i < activeBuffsListCount && buffType >= activeBuffsList[i]; i++) { } ArrayUtils.ArrayInsert(ref activeBuffsList, ref activeBuffsListCount, i, in buffType); OnBuffFirstStackGained(buffDef); } if (NetworkServer.active) { SetDirtyBit(2u); } } statsDirty = true; if (NetworkClient.active) { OnClientBuffsChanged(); } UpdateItemAvailability(); } private void OnBuffFirstStackGained(BuffDef buffDef) { if (buffDef.isElite) { eliteBuffCount++; } if (buffDef == RoR2Content.Buffs.Intangible) { UpdateHurtBoxesEnabled(); } else if (buffDef == RoR2Content.Buffs.WarCryBuff) { if (HasBuff(RoR2Content.Buffs.TeamWarCry)) { ClearTimedBuffs(RoR2Content.Buffs.TeamWarCry); } } else if (buffDef == RoR2Content.Buffs.TeamWarCry) { if (HasBuff(RoR2Content.Buffs.WarCryBuff)) { ClearTimedBuffs(RoR2Content.Buffs.WarCryBuff); } } else if (buffDef == RoR2Content.Buffs.AffixEcho && NetworkServer.active) { AddItemBehavior(1); } } private void OnBuffFinalStackLost(BuffDef buffDef) { if (buffDef.isElite) { eliteBuffCount--; } if (buffDef.buffIndex == RoR2Content.Buffs.Intangible.buffIndex) { UpdateHurtBoxesEnabled(); } else if (buffDef == RoR2Content.Buffs.AffixEcho && NetworkServer.active) { AddItemBehavior(0); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int GetBuffCount(BuffIndex buffType) { return ArrayUtils.GetSafe(buffs, (int)buffType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int GetBuffCount(BuffDef buffDef) { return GetBuffCount(buffDef?.buffIndex ?? BuffIndex.None); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasBuff(BuffIndex buffType) { return GetBuffCount(buffType) > 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasBuff(BuffDef buffDef) { return HasBuff(buffDef?.buffIndex ?? BuffIndex.None); } public void AddTimedBuffAuthority(BuffIndex buffType, float duration) { if (NetworkServer.active) { AddTimedBuff(buffType, duration); } else { CallCmdAddTimedBuff(buffType, duration); } } [Command] public void CmdAddTimedBuff(BuffIndex buffType, float duration) { AddTimedBuff(buffType, duration); } [Server] public void AddTimedBuff(BuffDef buffDef, float duration, int maxStacks) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddTimedBuff(RoR2.BuffDef,System.Single,System.Int32)' called on client"); } else { if (ImmuneToDebuffBehavior.OverrideDebuff(buffDef, this)) { return; } if (GetBuffCount(buffDef) < maxStacks) { AddTimedBuff(buffDef, duration); return; } int num = -1; float num2 = duration; for (int i = 0; i < timedBuffs.Count; i++) { if (timedBuffs[i].buffIndex == buffDef.buffIndex && timedBuffs[i].timer < num2) { num = i; num2 = timedBuffs[i].timer; } } if (num >= 0) { timedBuffs[num].timer = duration; } } } [Server] public void AddTimedBuff(BuffDef buffDef, float duration) { BuffIndex buffType; if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddTimedBuff(RoR2.BuffDef,System.Single)' called on client"); } else { if ((object)buffDef == null || ImmuneToDebuffBehavior.OverrideDebuff(buffDef, this)) { return; } buffType = buffDef.buffIndex; if (buffType == BuffIndex.None) { return; } if (buffDef == RoR2Content.Buffs.AttackSpeedOnCrit) { int num = (inventory ? inventory.GetItemCount(RoR2Content.Items.AttackSpeedOnCrit) : 0); int num2 = 1 + num * 2; int num3 = 0; int num4 = -1; float num5 = 999f; for (int i = 0; i < timedBuffs.Count; i++) { if (timedBuffs[i].buffIndex == buffType) { num3++; if (timedBuffs[i].timer < num5) { num4 = i; num5 = timedBuffs[i].timer; } } } if (num3 < num2) { timedBuffs.Add(new TimedBuff { buffIndex = buffType, timer = duration }); AddBuff(buffType); ChildLocator component = modelLocator.modelTransform.GetComponent(); if ((bool)component) { Transform obj = component.FindChild("HandL"); Transform transform = component.FindChild("HandR"); GameObject effectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/WolfProcEffect"); if ((bool)obj) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, "HandL", transmit: true); } if ((bool)transform) { EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, "HandR", transmit: true); } } } else if (num4 > -1) { timedBuffs[num4].timer = duration; } EntitySoundManager.EmitSoundServer(CommonAssets.procCritAttackSpeedSounds[Mathf.Min(CommonAssets.procCritAttackSpeedSounds.Length - 1, num3)].index, networkIdentity); } else if (buffDef == RoR2Content.Buffs.BeetleJuice) { if (RefreshStacks() < 10) { timedBuffs.Add(new TimedBuff { buffIndex = buffType, timer = duration }); AddBuff(buffType); } } else if (buffDef == RoR2Content.Buffs.NullifyStack) { if (HasBuff(RoR2Content.Buffs.Nullified)) { return; } int num6 = 0; for (int j = 0; j < timedBuffs.Count; j++) { if (timedBuffs[j].buffIndex == buffType) { num6++; if (timedBuffs[j].timer < duration) { timedBuffs[j].timer = duration; } } } if (num6 < 2) { timedBuffs.Add(new TimedBuff { buffIndex = buffType, timer = duration }); AddBuff(buffType); } else { ClearTimedBuffs(RoR2Content.Buffs.NullifyStack.buffIndex); AddTimedBuff(RoR2Content.Buffs.Nullified.buffIndex, 3f); } } else if (buffDef == RoR2Content.Buffs.AffixHauntedRecipient) { if (!HasBuff(RoR2Content.Buffs.AffixHaunted)) { DefaultBehavior(); } } else if (buffDef == DLC2Content.Buffs.EliteBeadCorruption) { if (!HasBuff(DLC2Content.Buffs.EliteBead)) { DefaultBehavior(); } } else if (buffDef == RoR2Content.Buffs.LunarDetonationCharge) { RefreshStacks(); DefaultBehavior(); } else if (buffDef == RoR2Content.Buffs.Overheat) { RefreshStacks(); DefaultBehavior(); } else if (buffDef == DLC2Content.Buffs.BoostAllStatsBuff) { RefreshStacks(); DefaultBehavior(); } else { DefaultBehavior(); } } void DefaultBehavior() { bool flag = false; if (!buffDef.canStack) { for (int k = 0; k < timedBuffs.Count; k++) { if (timedBuffs[k].buffIndex == buffType) { flag = true; timedBuffs[k].timer = Mathf.Max(timedBuffs[k].timer, duration); break; } } } if (!flag) { timedBuffs.Add(new TimedBuff { buffIndex = buffType, timer = duration }); AddBuff(buffType); } if ((bool)buffDef.startSfx) { EntitySoundManager.EmitSoundServer(buffDef.startSfx.index, networkIdentity); } } int RefreshStacks() { int num7 = 0; for (int l = 0; l < timedBuffs.Count; l++) { TimedBuff timedBuff = timedBuffs[l]; if (timedBuff.buffIndex == buffType) { num7++; if (timedBuff.timer < duration) { timedBuff.timer = duration; } } } return num7; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Server] public void AddTimedBuff(BuffIndex buffIndex, float duration) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddTimedBuff(RoR2.BuffIndex,System.Single)' called on client"); } else { AddTimedBuff(BuffCatalog.GetBuffDef(buffIndex), duration); } } [Server] public void ClearTimedBuffs(BuffIndex buffType) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::ClearTimedBuffs(RoR2.BuffIndex)' called on client"); return; } for (int num = timedBuffs.Count - 1; num >= 0; num--) { TimedBuff timedBuff = timedBuffs[num]; if (timedBuff.buffIndex == buffType) { timedBuffs.RemoveAt(num); RemoveBuff(timedBuff.buffIndex); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Server] public void ClearTimedBuffs(BuffDef buffDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::ClearTimedBuffs(RoR2.BuffDef)' called on client"); } else { ClearTimedBuffs(buffDef?.buffIndex ?? BuffIndex.None); } } [Server] public void RemoveOldestTimedBuff(BuffIndex buffType) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::RemoveOldestTimedBuff(RoR2.BuffIndex)' called on client"); return; } float num = float.NegativeInfinity; int num2 = -1; for (int num3 = timedBuffs.Count - 1; num3 >= 0; num3--) { TimedBuff timedBuff = timedBuffs[num3]; if (timedBuff.buffIndex == buffType && num < timedBuff.timer) { num = timedBuff.timer; num2 = num3; } } if (num2 > 0) { timedBuffs.RemoveAt(num2); RemoveBuff(buffType); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Server] public void RemoveOldestTimedBuff(BuffDef buffDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::RemoveOldestTimedBuff(RoR2.BuffDef)' called on client"); } else { RemoveOldestTimedBuff(buffDef?.buffIndex ?? BuffIndex.None); } } [Server] private void UpdateBuffs(float deltaTime) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateBuffs(System.Single)' called on client"); return; } for (int num = timedBuffs.Count - 1; num >= 0; num--) { TimedBuff timedBuff = timedBuffs[num]; timedBuff.timer -= deltaTime; if (timedBuff.timer <= 0f) { timedBuffs.RemoveAt(num); RemoveBuff(timedBuff.buffIndex); } } } [Client] private void OnClientBuffsChanged() { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.CharacterBody::OnClientBuffsChanged()' called on server"); return; } bool num = HasBuff(RoR2Content.Buffs.WarCryBuff); if (!num && (bool)warCryEffectInstance) { UnityEngine.Object.Destroy(warCryEffectInstance); } if (num && !warCryEffectInstance) { Transform transform = (mainHurtBox ? mainHurtBox.transform : this.transform); if ((bool)transform) { warCryEffectInstance = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/Effects/WarCryEffect"), transform.position, UnityEngine.Quaternion.identity, transform); } } if ((bool)inventory && inventory.GetItemCount(DLC2Content.Items.IncreaseDamageOnMultiKill) > 0) { int buffCount = GetBuffCount(DLC2Content.Buffs.IncreaseDamageBuff); if ((bool)increaseDamageOnMultiKillItemDisplayUpdater) { increaseDamageOnMultiKillItemDisplayUpdater.UpdateKillCounterText(buffCount); } if (previousMultiKillBuffCount < buffCount) { Util.PlaySound("Play_item_proc_increaseDamageMultiKill", base.gameObject); } previousMultiKillBuffCount = buffCount; } } public NetworkInstanceId GetMasterObjectId() { return masterObjectId; } private void GetSelectedCharacterType() { } private void UpdateHurtBoxesEnabled() { bool flag = ((bool)inventory && inventory.GetItemCount(RoR2Content.Items.Ghost) > 0) || HasBuff(RoR2Content.Buffs.Intangible); if (flag == disablingHurtBoxes) { return; } if ((bool)hurtBoxGroup) { if (flag) { HurtBoxGroup obj = hurtBoxGroup; int hurtBoxesDeactivatorCounter = obj.hurtBoxesDeactivatorCounter + 1; obj.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } else { HurtBoxGroup obj2 = hurtBoxGroup; int hurtBoxesDeactivatorCounter = obj2.hurtBoxesDeactivatorCounter - 1; obj2.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter; } } disablingHurtBoxes = flag; } private void OnInventoryChanged() { EquipmentIndex currentEquipmentIndex = inventory.currentEquipmentIndex; if (currentEquipmentIndex != previousEquipmentIndex) { EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(previousEquipmentIndex); EquipmentDef equipmentDef2 = EquipmentCatalog.GetEquipmentDef(currentEquipmentIndex); if (equipmentDef != null) { OnEquipmentLost(equipmentDef); } if (equipmentDef2 != null) { OnEquipmentGained(equipmentDef2); } previousEquipmentIndex = currentEquipmentIndex; } statsDirty = true; UpdateHurtBoxesEnabled(); AddItemBehavior(HasBuff(RoR2Content.Buffs.AffixHaunted) ? 1 : 0); AddItemBehavior(HasBuff(DLC1Content.Buffs.EliteEarth) ? 1 : 0); AddItemBehavior(HasBuff(DLC1Content.Buffs.EliteVoid) ? 1 : 0); AddItemBehavior(HasBuff(DLC2Content.Buffs.EliteBead) ? 1 : 0); AddItemBehavior(HasBuff(DLC2Content.Buffs.EliteAurelionite) ? 1 : 0); if (NetworkServer.active) { AddItemBehavior((inventory.GetEquipment(inventory.activeEquipmentSlot).equipmentDef == RoR2Content.Equipment.QuestVolatileBattery) ? 1 : 0); AddItemBehavior(inventory.GetItemCount(RoR2Content.Items.IceRing) + inventory.GetItemCount(RoR2Content.Items.FireRing)); AddItemBehavior(inventory.GetItemCount(DLC1Content.Items.ElementalRingVoid)); AddItemBehavior(inventory.GetItemCount(DLC1Content.Items.OutOfCombatArmor)); AddItemBehavior(inventory.GetItemCount(DLC1Content.Items.PrimarySkillShuriken)); AddItemBehavior(inventory.GetItemCount(DLC1Content.Items.MushroomVoid)); AddItemBehavior(inventory.GetItemCount(DLC1Content.Items.BearVoid)); AddItemBehavior(inventory.GetItemCount(DLC1Content.Items.LunarSun)); AddItemBehavior(inventory.GetItemCount(DLC1Content.Items.VoidMegaCrabItem)); AddItemBehavior(inventory.GetItemCount(DLC1Content.Items.DroneWeapons)); AddItemBehavior(inventory.GetItemCount(DLC1Content.Items.DroneWeaponsBoost)); AddItemBehavior(inventory.GetItemCount(DLC2Content.Items.MeteorAttackOnHighDamage)); AddItemBehavior(inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealth)); } executeEliteHealthFraction = Util.ConvertAmplificationPercentageIntoReductionPercentage(13f * (float)inventory.GetItemCount(RoR2Content.Items.ExecuteLowHealthElite)) / 100f; if ((bool)skillLocator) { ReplaceSkillIfItemPresent(skillLocator.primary, RoR2Content.Items.LunarPrimaryReplacement.itemIndex, CommonAssets.lunarPrimaryReplacementSkillDef); ReplaceSkillIfItemPresent(skillLocator.secondary, RoR2Content.Items.LunarSecondaryReplacement.itemIndex, CommonAssets.lunarSecondaryReplacementSkillDef); ReplaceSkillIfItemPresent(skillLocator.special, RoR2Content.Items.LunarSpecialReplacement.itemIndex, CommonAssets.lunarSpecialReplacementSkillDef); ReplaceSkillIfItemPresent(skillLocator.utility, RoR2Content.Items.LunarUtilityReplacement.itemIndex, CommonAssets.lunarUtilityReplacementSkillDef); } this.onInventoryChanged?.Invoke(); CharacterBody.onBodyInventoryChangedGlobal?.Invoke(this); UpdateItemAvailability(); } private void ReplaceSkillIfItemPresent(GenericSkill skill, ItemIndex itemIndex, SkillDef skillDef) { if ((bool)skill) { if (inventory.GetItemCount(itemIndex) > 0 && (bool)skillDef) { skill.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Replacement); } else { skill.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Replacement); } } } private void OnEquipmentLost(EquipmentDef equipmentDef) { if (NetworkServer.active && (object)equipmentDef.passiveBuffDef != null) { RemoveBuff(equipmentDef.passiveBuffDef); } } private void OnEquipmentGained(EquipmentDef equipmentDef) { if (NetworkServer.active && (object)equipmentDef.passiveBuffDef != null) { AddBuff(equipmentDef.passiveBuffDef); } } private void UpdateMasterLink() { if (!linkedToMaster && (bool)master && (bool)master) { master.OnBodyStart(this); linkedToMaster = true; skinIndex = master.loadout.bodyLoadoutManager.GetSkinIndex(bodyIndex); } } public static void Init() { AssetReferences.Resolve(); } private void Awake() { transform = base.transform; rigidbody = GetComponent(); networkIdentity = GetComponent(); teamComponent = GetComponent(); healthComponent = GetComponent(); equipmentSlot = GetComponent(); skillLocator = GetComponent(); modelLocator = GetComponent(); characterMotor = GetComponent(); characterDirection = GetComponent(); inputBank = GetComponent(); sfxLocator = GetComponent(); activeBuffsList = BuffCatalog.GetPerBuffBuffer(); buffs = BuffCatalog.GetPerBuffBuffer(); if ((bool)modelLocator) { modelLocator.onModelChanged += OnModelChanged; OnModelChanged(modelLocator.modelTransform); } radius = 1f; CapsuleCollider component = GetComponent(); if ((bool)component) { radius = component.radius; } else { SphereCollider component2 = GetComponent(); if ((bool)component2) { radius = component2.radius; } } try { CharacterBody.onBodyAwakeGlobal?.Invoke(this); } catch (Exception message) { UnityEngine.Debug.LogError(message); } } private void OnModelChanged(Transform modelTransform) { hurtBoxGroup = null; mainHurtBox = null; coreTransform = transform; if ((bool)modelTransform) { hurtBoxGroup = modelTransform.GetComponent(); if ((bool)hurtBoxGroup) { mainHurtBox = hurtBoxGroup.mainHurtBox; if ((bool)mainHurtBox) { coreTransform = mainHurtBox.transform; } } } if ((bool)overrideCoreTransform) { coreTransform = overrideCoreTransform; } } private void Start() { UpdateAuthority(); localStartTime = Run.FixedTimeStamp.now; bool num = (bodyFlags & BodyFlags.Masterless) != 0; outOfCombatStopwatch = float.PositiveInfinity; outOfDangerStopwatch = float.PositiveInfinity; notMovingStopwatch = 0f; if (NetworkServer.active) { outOfCombat = true; outOfDanger = true; } RecalculateStats(); UpdateMasterLink(); if (num) { healthComponent.Networkhealth = maxHealth; } if ((bool)sfxLocator && healthComponent.alive) { Util.PlaySound(sfxLocator.aliveLoopStart, base.gameObject); } if (!doNotReassignToTeamBasedCollisionLayer) { base.gameObject.layer = LayerIndex.GetAppropriateLayerForTeam(teamComponent.teamIndex); if (characterMotor != null) { characterMotor.Motor.RebuildCollidableLayers(); } } CharacterBody.onBodyStartGlobal?.Invoke(this); if ((bool)master && NetworkServer.active) { if (master.devotionInventoryPrefab == null) { _ = master.isDevotedMinion; } if (isPlayerControlled && (bool)master.devotionInventoryPrefab) { _ = master.devotionInventoryPrefab != null; } int num2 = ((inventory != null) ? inventory.GetItemCount(DLC2Content.Items.GoldOnStageStart) : 0); if (num2 > 0) { TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.GoldOnStageStart.itemIndex, 0f)); uint difficultyScaledCost = (uint)Run.instance.GetDifficultyScaledCost((int)(50f + level * 1.5f * (float)num2)); master.GiveMoney(difficultyScaledCost); } } } public void Update() { float deltaTime = Time.deltaTime; outOfCombatStopwatch += deltaTime; outOfDangerStopwatch += deltaTime; aimTimer = Mathf.Max(aimTimer - deltaTime, 0f); UpdateOutOfCombatAndDanger(); UpdateSpreadBloom(deltaTime); DoItemUpdates(deltaTime); UpdateNotMoving(deltaTime); HandleLavaDamage(deltaTime); } private void UpdateNotMoving(float deltaTime) { if (NetworkServer.active) { UnityEngine.Vector3 position = transform.position; float num = 0.1f * deltaTime; if ((position - previousPosition).sqrMagnitude <= num * num) { notMovingStopwatch += deltaTime; } else { notMovingStopwatch = 0f; } previousPosition = position; } } private void DoItemUpdates(float deltaTime) { if ((bodyFlags & BodyFlags.IgnoreItemUpdates) == 0) { if (NetworkServer.active) { UpdateMultiKill(deltaTime); UpdateHelfire(deltaTime); UpdateAffixPoison(deltaTime); UpdateAffixLunar(deltaTime); UpdateLowerHealthHigherDamage(); UpdateDelayedDamage(deltaTime); UpdateSecondHalfOfDamage(deltaTime); } UpdateFireTrail(); } } private void UpdateOutOfCombatAndDanger() { bool active = NetworkServer.active; bool flag = outOfCombat; bool flag2 = flag; if (active || hasEffectiveAuthority) { flag2 = outOfCombatStopwatch >= 5f; if (outOfCombat != flag2) { if (NetworkServer.active) { SetDirtyBit(4u); } outOfCombat = flag2; statsDirty = true; } } if (active) { bool flag3 = outOfDangerStopwatch >= 7f; bool flag4 = outOfDanger; bool flag5 = flag && flag4; bool num = flag2 && flag3; if (outOfDanger != flag3) { SetDirtyBit(8u); outOfDanger = flag3; statsDirty = true; } if (num && !flag5) { OnOutOfCombatAndDangerServer(); } } } [Command] public void CmdSetInLava(bool b) { inLava = b; } public void SetInLava(bool b) { if (inLava != b) { if (!NetworkServer.active && base.hasAuthority) { CallCmdSetInLava(b); } inLava = b; } } public void InflictLavaDamage() { DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = 10f; if (isChampion || isBoss) { damageInfo.damage = healthComponent.fullCombinedHealth / 100f; } else if (teamComponent.teamIndex == TeamIndex.Monster || teamComponent.teamIndex == TeamIndex.Void) { damageInfo.damage = healthComponent.fullCombinedHealth / 50f; } else { damageInfo.damage = healthComponent.fullCombinedHealth / 10f; } damageInfo.damageType = DamageType.IgniteOnHit; damageInfo.position = footPosition; healthComponent.TakeDamage(damageInfo); } public void HandleLavaDamage(float deltaTime) { bool flag = (bodyFlags & BodyFlags.ImmuneToLava) != 0; if (inLava && NetworkServer.active) { lavaTimer -= deltaTime; if (lavaTimer <= 0f && !flag) { InflictLavaDamage(); lavaTimer = lavaCooldown; } } else { lavaTimer = 0f; } } private void UpdateItemAvailability() { if ((bool)inventory) { itemAvailability.helfireCount = inventory.GetItemCount(JunkContent.Items.BurnNearby); } itemAvailability.hasFireTrail = HasBuff(RoR2Content.Buffs.AffixRed); itemAvailability.hasAffixLunar = HasBuff(RoR2Content.Buffs.AffixLunar); itemAvailability.hasAffixPoison = HasBuff(RoR2Content.Buffs.AffixPoison); } public void FixedUpdate() { float fixedDeltaTime = Time.fixedDeltaTime; bool flag = (bodyFlags & BodyFlags.IgnoreItemUpdates) == 0; if (NetworkServer.active) { if (flag) { UpdateBuffs(fixedDeltaTime); } UpdateOutOfCombatAndDanger(); } if (statsDirty) { RecalculateStats(); } } public void OnDeathStart() { base.enabled = false; if ((bool)sfxLocator) { Util.PlaySound(sfxLocator.aliveLoopStop, base.gameObject); } if (NetworkServer.active && (bool)currentVehicle) { currentVehicle.EjectPassenger(base.gameObject); } if ((bool)master) { master.OnBodyDeath(this); } ModelLocator component = GetComponent(); if (!component) { return; } Transform modelTransform = component.modelTransform; if ((bool)modelTransform) { CharacterModel component2 = modelTransform.GetComponent(); if ((bool)component2) { component2.OnDeath(); } } } public void OnTakeDamageServer(DamageReport damageReport) { if (damageReport.damageDealt > 0f) { outOfDangerStopwatch = 0f; } if ((bool)master) { master.OnBodyDamaged(damageReport); } } public void OnSkillActivated(GenericSkill skill) { if (skill.isCombatSkill) { outOfCombatStopwatch = 0f; } if (hasEffectiveAuthority) { this.onSkillActivatedAuthority?.Invoke(skill); } if (NetworkServer.active) { this.onSkillActivatedServer?.Invoke(skill); if (inventory.GetItemCount(DLC2Content.Items.IncreasePrimaryDamage) <= 0) { return; } if (bodyIndex == BodyCatalog.SpecialCases.RailGunner()) { if ((object)skillLocator.primary == skill) { if (GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff) > 0 && !EntityStates.Railgunner.Scope.BaseScopeState.inScope) { luminousShotReady = true; } } else { luminousShotReady = false; } if ((object)skillLocator.primary == skill && EntityStates.Railgunner.Scope.BaseScopeState.inScope) { AddIncreasePrimaryDamageStack(); } } else { if (!skill.skillDef.autoHandleLuminousShot) { return; } if ((object)skillLocator.secondary == skill) { AddIncreasePrimaryDamageStack(); } else if ((object)skillLocator.primary == skill) { if (GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff) > 0) { luminousShotReady = true; } else { luminousShotReady = false; } } } } else { CallCmdOnSkillActivated((sbyte)skillLocator.FindSkillSlot(skill)); } } public void OnDestroy() { try { CharacterBody.onBodyDestroyGlobal?.Invoke(this); } catch (Exception message) { UnityEngine.Debug.LogError(message); } if ((bool)sfxLocator) { Util.PlaySound(sfxLocator.aliveLoopStop, base.gameObject); } if ((object)modelLocator != null) { modelLocator.onModelChanged -= OnModelChanged; } if ((bool)inventory) { inventory.onInventoryChanged -= OnInventoryChanged; } if ((bool)master) { master.OnBodyDestroyed(this); } } public float GetNormalizedThreatValue() { if ((bool)Run.instance) { return (master ? ((float)master.money) : 0f) * Run.instance.oneOverCompensatedDifficultyCoefficientSquared; } return 0f; } private void OnEnable() { instancesList.Add(this); } private void OnDisable() { instancesList.Remove(this); } private void OnValidate() { if (autoCalculateLevelStats) { PerformAutoCalculateLevelStats(); } if (!Application.isPlaying && bodyIndex != BodyIndex.None) { bodyIndex = BodyIndex.None; } } private void UpdateAuthority() { hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject); } public override void OnStartAuthority() { UpdateAuthority(); } public override void OnStopAuthority() { UpdateAuthority(); } private void OnSprintStart() { if ((bool)sfxLocator) { Util.PlaySound(sfxLocator.sprintLoopStart, base.gameObject); } } private void OnSprintStop() { if ((bool)sfxLocator) { Util.PlaySound(sfxLocator.sprintLoopStop, base.gameObject); } } [Command] private void CmdUpdateSprint(bool newIsSprinting) { isSprinting = newIsSprinting; } [Command] private void CmdOnSkillActivated(sbyte skillIndex) { OnSkillActivated(skillLocator.GetSkill((SkillSlot)skillIndex)); } private void OnOutOfDangerChanged() { if (outOfDanger && healthComponent.shield != healthComponent.fullShield) { Util.PlaySound("Play_item_proc_personal_shield_recharge", base.gameObject); } } [Server] private void OnOutOfCombatAndDangerServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::OnOutOfCombatAndDangerServer()' called on client"); } } [Server] public bool GetNotMoving() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterBody::GetNotMoving()' called on client"); return false; } return notMovingStopwatch >= 1f; } public void PerformAutoCalculateLevelStats() { levelMaxHealth = Mathf.Round(baseMaxHealth * 0.3f); levelMaxShield = Mathf.Round(baseMaxShield * 0.3f); levelRegen = baseRegen * 0.2f; levelMoveSpeed = 0f; levelJumpPower = 0f; levelDamage = baseDamage * 0.2f; levelAttackSpeed = 0f; levelCrit = 0f; levelArmor = 0f; } public void MarkAllStatsDirty() { statsDirty = true; } private void UpdateLowerHealthHigherDamageVFX() { if ((bool)lowerHealthHigherDamageSteam) { ParticleSystem.EmissionModule emission = lowerHealthHigherDamageSteam.GetComponent().emission; emission.rateOverTime = 35f; } } public void UpdateLowerHealthHigherDamage() { if (!inventory) { return; } int itemCount = inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage); if (NetworkServer.active) { if (itemCount > 0) { if ((bool)inventory && healthComponent.health > 0f && teamComponent.teamIndex == TeamIndex.Player) { float normalizedHealth = healthComponent.GetNormalizedHealth(); if ((double)normalizedHealth <= 0.5 && !HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff)) { AddBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff); Util.PlaySound("Play_item_proc_lowerHealthHigherDamage_proc", base.gameObject); TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.LowerHealthHigherDamage.itemIndex, 1f)); } else if (HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff) && (double)normalizedHealth > 0.5) { RemoveBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff); TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.LowerHealthHigherDamage.itemIndex, 0f)); } } } else if (HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff)) { RemoveBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff); TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.LowerHealthHigherDamage.itemIndex, 0f)); } } else if (itemCount == 0 && HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff) && healthComponent.health > 0f && teamComponent.teamIndex == TeamIndex.Player && (double)healthComponent.GetNormalizedHealth() > 0.5) { RemoveBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff); TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.LowerHealthHigherDamage.itemIndex, 0f)); } } private void SetBoostAllStatsStartTimer(float t) { if (!boostAllStatsTimerStarted) { boostAllStatsStartTimer = t; boostAllStatsTimer = boostAllStatsStartTimer; boostAllStatsTimerStarted = true; } } private void SetBoostAllStatsCoolDownTimer(float t) { if (boostAllStatsCoolDownTimerStarted) { boostAllStatsCoolDownStartTimer = t; boostAllStatsCoolDownTimer = boostAllStatsCoolDownStartTimer; } } private float CalculateBoostAllStatsTriggerChance(int i) { boostAllStatsTriggerChance = boostAllStatsDefaultTriggerChance + boostAllStatsTriggerIncrease * (float)(i - 1); if ((double)boostAllStatsTriggerChance >= 0.5) { boostAllStatsTriggerChance = 0.5f; } return boostAllStatsTriggerChance; } private void UpdateBoostAllStatsTimer(float t) { if (!NetworkServer.active || !inventory) { return; } int itemCount = inventory.GetItemCount(DLC2Content.Items.BoostAllStats); if (!boostAllStatsCoolDownTimerStarted && itemCount > 0) { SetBoostAllStatsStartTimer(t); boostAllStatsTimer += t; if (boostAllStatsTimer >= boostAllStatsStartTimer + boostAllStatsTriggerTimer) { if (RoR2Application.rng.RangeFloat(0f, 1f) <= CalculateBoostAllStatsTriggerChance(inventory.GetItemCount(DLC2Content.Items.BoostAllStats))) { AddBuff(DLC2Content.Buffs.BoostAllStatsBuff); RecalculateStats(); boostAllStatsTimerStarted = false; boostAllStatsCoolDownTimerStarted = true; SetBoostAllStatsCoolDownTimer(t); } else { boostAllStatsTimerStarted = false; boostAllStatsCoolDownTimerStarted = false; } } } else if (boostAllStatsCoolDownTimerStarted) { boostAllStatsCoolDownTimer += t; if (boostAllStatsCoolDownTimer >= boostAllStatsStartTimer + boostAllStatsCoolDownTriggerTimer) { RemoveBuff(DLC2Content.Buffs.BoostAllStatsBuff); RecalculateStats(); boostAllStatsCoolDownTimerStarted = false; } } } public void RecalculateStats() { if (!Run.instance) { return; } float num = level; TeamManager.instance.GetTeamExperience(teamComponent.teamIndex); float num2 = TeamManager.instance.GetTeamLevel(teamComponent.teamIndex); int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; int num9 = 0; int num10 = 0; int num11 = 0; int num12 = 0; int num13 = 0; int num14 = 0; int num15 = 0; int num16 = 0; int num17 = 0; int num18 = 0; int num19 = 0; int num20 = 0; int num21 = 0; int num22 = 0; int num23 = 0; int num24 = 0; int num25 = 0; int num26 = 0; int num27 = 0; int num28 = 0; int num29 = 0; int num30 = 0; int num31 = 0; int num32 = 0; int num33 = 0; int num34 = 0; int num35 = 0; int num36 = 0; int num37 = 0; int num38 = 0; int num39 = 0; int num40 = 0; int num41 = 0; int num42 = 0; int num43 = 0; int num44 = 0; int num45 = 0; int num46 = 0; int num47 = 0; int num48 = 0; int num49 = 0; int num50 = 0; EquipmentIndex equipmentIndex = EquipmentIndex.None; uint num51 = 0u; int num52 = 0; int num53 = 0; int num54 = 0; int num55 = 0; if ((bool)inventory) { num3 = inventory.GetItemCount(RoR2Content.Items.LevelBonus); num4 = inventory.GetItemCount(RoR2Content.Items.Infusion); num5 = inventory.GetItemCount(RoR2Content.Items.HealWhileSafe); num6 = inventory.GetItemCount(RoR2Content.Items.PersonalShield); num7 = inventory.GetItemCount(RoR2Content.Items.Hoof); num8 = inventory.GetItemCount(RoR2Content.Items.SprintOutOfCombat); num9 = inventory.GetItemCount(RoR2Content.Items.Feather); num10 = inventory.GetItemCount(RoR2Content.Items.Syringe); num11 = inventory.GetItemCount(RoR2Content.Items.CritGlasses); num12 = inventory.GetItemCount(RoR2Content.Items.AttackSpeedOnCrit); num13 = inventory.GetItemCount(JunkContent.Items.CooldownOnCrit); num14 = inventory.GetItemCount(RoR2Content.Items.HealOnCrit); num15 = inventory.GetItemCount(RoR2Content.Items.ShieldOnly); num16 = inventory.GetItemCount(RoR2Content.Items.AlienHead); num17 = inventory.GetItemCount(RoR2Content.Items.Knurl); num18 = inventory.GetItemCount(RoR2Content.Items.BoostHp); num19 = inventory.GetItemCount(JunkContent.Items.CritHeal); num20 = inventory.GetItemCount(RoR2Content.Items.SprintBonus); num21 = inventory.GetItemCount(RoR2Content.Items.SecondarySkillMagazine); num23 = inventory.GetItemCount(RoR2Content.Items.SprintArmor); num24 = inventory.GetItemCount(RoR2Content.Items.UtilitySkillMagazine); num25 = inventory.GetItemCount(RoR2Content.Items.HealthDecay); num27 = inventory.GetItemCount(RoR2Content.Items.TonicAffliction); num28 = inventory.GetItemCount(RoR2Content.Items.LunarDagger); num26 = inventory.GetItemCount(RoR2Content.Items.DrizzlePlayerHelper); num29 = inventory.GetItemCount(RoR2Content.Items.MonsoonPlayerHelper); num30 = inventory.GetItemCount(RoR2Content.Items.Pearl); num31 = inventory.GetItemCount(RoR2Content.Items.ShinyPearl); num32 = inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger); num33 = inventory.GetItemCount(RoR2Content.Items.CutHp); num34 = inventory.GetItemCount(RoR2Content.Items.BoostAttackSpeed); num35 = inventory.GetItemCount(RoR2Content.Items.BleedOnHitAndExplode); num36 = inventory.GetItemCount(RoR2Content.Items.LunarBadLuck); num37 = inventory.GetItemCount(RoR2Content.Items.FlatHealth); num38 = inventory.GetItemCount(RoR2Content.Items.TeamSizeDamageBonus); num39 = inventory.GetItemCount(RoR2Content.Items.SummonedEcho); num40 = inventory.GetItemCount(RoR2Content.Items.UseAmbientLevel); num22 = inventory.GetItemCount(DLC1Content.Items.EquipmentMagazineVoid); num44 = inventory.GetItemCount(DLC1Content.Items.HalfAttackSpeedHalfCooldowns); num45 = inventory.GetItemCount(DLC1Content.Items.HalfSpeedDoubleHealth); num41 = inventory.GetItemCount(RoR2Content.Items.BleedOnHit); num42 = inventory.GetItemCount(DLC1Content.Items.AttackSpeedAndMoveSpeed); num43 = inventory.GetItemCount(DLC1Content.Items.CritDamage); num46 = inventory.GetItemCount(DLC1Content.Items.ConvertCritChanceToCritDamage); num47 = inventory.GetItemCount(DLC1Content.Items.DroneWeaponsBoost); num48 = inventory.GetItemCount(DLC1Content.Items.MissileVoid); equipmentIndex = inventory.currentEquipmentIndex; num51 = inventory.infusionBonus; num49 = ((equipmentIndex == DLC1Content.Equipment.EliteVoidEquipment.equipmentIndex) ? 1 : 0); num50 = inventory.GetItemCount(DLC1Content.Items.OutOfCombatArmor); inventory.GetItemCount(DLC1Content.Items.VoidmanPassiveItem); num52 = inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage); num53 = inventory.GetItemCount(DLC2Content.Items.BoostAllStats); inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealth); num54 = inventory.GetItemCount(DLC2Content.Items.IncreaseDamageOnMultiKill); inventory.GetItemCount(DLC2Content.Items.GoldOnStageStart); num55 = inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp); } level = num2; if (num40 > 0) { level = Math.Max(level, Run.instance.ambientLevelFloor); } level += num3; EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); float num56 = level - 1f; isElite = eliteBuffCount > 0; bool flag = HasBuff(RoR2Content.Buffs.TonicBuff); bool num57 = HasBuff(RoR2Content.Buffs.Entangle); bool flag2 = HasBuff(RoR2Content.Buffs.Nullified); bool flag3 = HasBuff(RoR2Content.Buffs.LunarSecondaryRoot); bool flag4 = teamComponent.teamIndex == TeamIndex.Player && RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.glassArtifactDef); bool num58 = num15 > 0 || HasBuff(RoR2Content.Buffs.AffixLunar); bool flag5 = (object)equipmentDef != null && (object)equipmentDef == JunkContent.Equipment.EliteYellowEquipment; hasOneShotProtection = isPlayerControlled; int buffCount = GetBuffCount(RoR2Content.Buffs.BeetleJuice); int buffCount2 = GetBuffCount(DLC2Content.Buffs.RevitalizeBuff); isGlass = flag4 || num28 > 0; canPerformBackstab = (bodyFlags & BodyFlags.HasBackstabPassive) == BodyFlags.HasBackstabPassive; canReceiveBackstab = (bodyFlags & BodyFlags.HasBackstabImmunity) != BodyFlags.HasBackstabImmunity; float num59 = maxHealth; float num60 = maxShield; if (num55 > extraStatsOnLevelUpCountModifier && num55 > 0) { extraStatsOnLevelUpCountModifier = num55; } if (num55 < extraStatsOnLevelUpCountModifier && (bool)inventory) { UnityEngine.Object.Instantiate(CommonAssets.prayerBeadEffect, base.gameObject.transform.position, UnityEngine.Quaternion.identity).transform.parent = base.gameObject.transform; extraStatsOnLevelUpCountModifier -= num55; float beadAppliedHealth = inventory.beadAppliedHealth; prayerBeadCalculateAppliedStats(levelMaxHealth); prayerBeadCalculateAppliedStats(levelMaxShield); prayerBeadCalculateAppliedStats(levelRegen); prayerBeadCalculateAppliedStats(levelDamage); extraStatsOnLevelUpCountModifier = num55; if (HasBuff(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff)) { SetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff.buffIndex, 0); bool gainedStats = inventory.beadAppliedHealth > beadAppliedHealth; master.OnBeadReset(gainedStats); } } HandleDisableAllSkillsDebuff(); float num61 = baseMaxHealth + levelMaxHealth * num56; if (teamComponent.teamIndex == TeamIndex.Player && (bool)inventory && inventory.beadAppliedHealth > 0f) { num61 += inventory.beadAppliedHealth; } float num62 = 1f; num62 += (float)num18 * 0.1f; num62 += (float)(num30 + num31) * 0.1f; num62 += (float)buffCount2 * 0.07f; num62 += (float)num49 * 0.5f; num62 += (float)num45 * 1f; if (num4 > 0) { num61 += (float)num51; } num61 += (float)num37 * 25f; num61 += (float)num17 * 40f; num61 *= num62; num61 /= (float)(num33 + 1); if (num32 > 0) { num61 *= 10f; } if (num39 > 0) { num61 *= 0.1f; } maxHealth = num61; float num63 = baseMaxShield + levelMaxShield * num56; if (teamComponent.teamIndex == TeamIndex.Player && (bool)inventory && inventory.beadAppliedShield > 0f) { num63 += inventory.beadAppliedShield; } num63 += (float)num6 * 0.08f * maxHealth; if (HasBuff(RoR2Content.Buffs.EngiShield)) { num63 += maxHealth * 1f; } if (HasBuff(JunkContent.Buffs.EngiTeamShield)) { num63 += maxHealth * 0.5f; } if (num48 > 0) { num63 += maxHealth * 0.1f; } if (num58) { num63 += maxHealth * (1.5f + (float)(num15 - 1) * 0.25f); maxHealth = 1f; } if (HasBuff(RoR2Content.Buffs.AffixBlue)) { float num64 = maxHealth * 0.5f; maxHealth -= num64; num63 += maxHealth; } maxShield = num63; float num65 = baseRegen + levelRegen * num56; if (teamComponent.teamIndex == TeamIndex.Player && (bool)inventory && inventory.beadAppliedRegen > 0f) { num65 += inventory.beadAppliedRegen; } float num66 = 1f + num56 * 0.2f; float num67 = (float)num17 * 1.6f * num66; float num68 = ((outOfDanger && num5 > 0) ? (3f * (float)num5) : 0f) * num66; float num69 = (HasBuff(JunkContent.Buffs.MeatRegenBoost) ? 2f : 0f) * num66; float num70 = (float)GetBuffCount(RoR2Content.Buffs.CrocoRegen) * maxHealth * 0.1f; float num71 = (float)num31 * 0.1f * num66; float num72 = (float)buffCount2 * 0.07f * num66; float num73 = 1f; if (num26 > 0) { num73 += 0.5f; } if (num29 > 0) { num73 -= 0.4f; } float num74 = (num65 + num67 + num68 + num69 + num71 + num72) * num73; if (HasBuff(RoR2Content.Buffs.OnFire) || HasBuff(DLC1Content.Buffs.StrongerBurn)) { num74 = Mathf.Min(0f, num74); } num74 += num70; if (num58) { num74 = Mathf.Max(num74, 0f); } if (num25 > 0) { num74 = Mathf.Min(num74, 0f) - maxHealth / cursePenalty / (float)num25; } if (tamperedHeartActive) { num74 += tamperedHeartRegenBonus; } if (HasBuff(DLC2Content.Buffs.HealAndReviveRegenBuff)) { num74 += num74 * 0.5f; } regen = num74; float num75 = baseMoveSpeed + levelMoveSpeed * num56; num75 += surfaceSpeedBoost; float num76 = 1f; if (flag5) { num75 += 2f; } if (isSprinting) { num75 *= sprintingSpeedMultiplier; } num76 += (float)num7 * 0.14f; num76 += (float)num42 * 0.07f; num76 += (float)num31 * 0.1f; num76 += (float)buffCount2 * 0.07f; num76 += 0.25f * (float)GetBuffCount(DLC1Content.Buffs.KillMoveSpeed); if (teamComponent.teamIndex == TeamIndex.Monster && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse4) { num76 += 0.4f; } if (isSprinting && num20 > 0) { num76 += 0.25f * (float)num20 / sprintingSpeedMultiplier; } if (num8 > 0 && HasBuff(RoR2Content.Buffs.WhipBoost)) { num76 += (float)num8 * 0.3f; } if (num39 > 0) { num76 += 0.66f; } if (HasBuff(RoR2Content.Buffs.BugWings)) { num76 += 0.2f; } if (HasBuff(RoR2Content.Buffs.Warbanner)) { num76 += 0.3f; } if (HasBuff(JunkContent.Buffs.EnrageAncientWisp)) { num76 += 0.4f; } if (HasBuff(RoR2Content.Buffs.CloakSpeed)) { num76 += 0.4f; } if (HasBuff(RoR2Content.Buffs.WarCryBuff) || HasBuff(RoR2Content.Buffs.TeamWarCry)) { num76 += 0.5f; } if (HasBuff(JunkContent.Buffs.EngiTeamShield)) { num76 += 0.3f; } if (HasBuff(RoR2Content.Buffs.AffixLunar)) { num76 += 0.3f; } if (tamperedHeartActive) { num75 += num75 * tamperedHeartMSpeedBonus; } float num77 = 1f; if (HasBuff(RoR2Content.Buffs.Slow50)) { num77 += 0.5f; } if (HasBuff(RoR2Content.Buffs.Slow60)) { num77 += 0.6f; } if (HasBuff(RoR2Content.Buffs.Slow80)) { num77 += 0.8f; } if (HasBuff(RoR2Content.Buffs.ClayGoo)) { num77 += 0.5f; } if (HasBuff(JunkContent.Buffs.Slow30)) { num77 += 0.3f; } if (HasBuff(RoR2Content.Buffs.Cripple)) { num77 += 1f; } if (HasBuff(DLC1Content.Buffs.JailerSlow)) { num77 += 1f; } num77 += (float)num45 * 1f; num75 *= num76 / num77; if (buffCount > 0) { num75 *= 1f - 0.05f * (float)buffCount; } moveSpeed = num75; acceleration = ((baseMoveSpeed == 0f) ? 0f : (moveSpeed / baseMoveSpeed * baseAcceleration)); if (num57 || flag2 || flag3) { moveSpeed = 0f; acceleration = 80f; } float num78 = baseJumpPower + levelJumpPower * num56; jumpPower = num78; maxJumpHeight = Trajectory.CalculateApex(jumpPower); maxJumpCount = baseJumpCount + num9; oneShotProtectionFraction = 0.1f; float num79 = baseDamage + levelDamage * num56; if (teamComponent.teamIndex == TeamIndex.Player && (bool)inventory && inventory.beadAppliedDamage > 0f) { num79 += inventory.beadAppliedDamage; } float num80 = 1f; int num81 = (inventory ? inventory.GetItemCount(RoR2Content.Items.BoostDamage) : 0); if (num81 > 0) { num80 += (float)num81 * 0.1f; } if (num38 > 0) { int num82 = Math.Max(TeamComponent.GetTeamMembers(teamComponent.teamIndex).Count - 1, 0); num80 += (float)(num82 * num38) * 1f; } if (buffCount > 0) { num80 -= 0.05f * (float)buffCount; } if (HasBuff(JunkContent.Buffs.GoldEmpowered)) { num80 += 1f; } if (HasBuff(RoR2Content.Buffs.PowerBuff)) { num80 += 0.5f; } num80 += (float)num31 * 0.1f; num80 += (float)buffCount2 * 0.07f; num80 += Mathf.Pow(2f, num28) - 1f; num80 -= (float)num49 * 0.3f; num79 *= num80; if (num32 > 0) { num79 *= 0.04f; } if (flag4) { num79 *= 5f; } damage = num79; damageFromRecalculateStats = damage; if (HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff)) { damage += baseDamage * (float)currentHealthLevel * 0.1f * (float)num52 * 0.5f; } _ = tamperedHeartActive; if (HasBuff(DLC2Content.Buffs.IncreaseDamageBuff)) { int buffCount3 = GetBuffCount(DLC2Content.Buffs.IncreaseDamageBuff); float num83 = 0f; if (buffCount3 >= 2) { num83 = (float)(buffCount3 * (buffCount3 + num54 * 5)) * 0.01f; } else if (buffCount3 == 1) { num83 = (float)(1 + num54 * 5) * 0.01f; } damage += baseDamage * num83; if (oldComboMeter < buffCount3) { oldComboMeter = buffCount3; } } float num84 = baseAttackSpeed + levelAttackSpeed * num56; float num85 = 1f; num85 += (float)num34 * 0.1f; num85 += (float)num10 * 0.15f; num85 += (float)num42 * 0.075f; num85 += (float)num47 * 0.5f; if (flag5) { num85 += 0.5f; } num85 += (float)GetBuffCount(RoR2Content.Buffs.AttackSpeedOnCrit) * 0.12f; if (HasBuff(RoR2Content.Buffs.Warbanner)) { num85 += 0.3f; } if (HasBuff(RoR2Content.Buffs.Energized)) { num85 += 0.7f; } if (HasBuff(RoR2Content.Buffs.WarCryBuff) || HasBuff(RoR2Content.Buffs.TeamWarCry)) { num85 += 1f; } num85 += (float)num31 * 0.1f; num85 += (float)buffCount2 * 0.07f; num85 /= (float)(num44 + 1); num85 = Mathf.Max(num85, 0.1f); num84 *= num85; if (buffCount > 0) { num84 *= 1f - 0.05f * (float)buffCount; } if (tamperedHeartActive) { num84 += num84 * tamperedHeartAttackSpeedBonus; } attackSpeed = num84; critMultiplier = 2f + 1f * (float)num43; float num86 = baseCrit + levelCrit * num56; num86 += (float)num11 * 10f; if (num12 > 0) { num86 += 5f; } if (num35 > 0) { num86 += 5f; } if (num13 > 0) { num86 += 5f; } if (num14 > 0) { num86 += 5f; } if (num19 > 0) { num86 += 5f; } if (HasBuff(RoR2Content.Buffs.FullCrit)) { num86 += 100f; } num86 += (float)num31 * 10f; num86 += (float)buffCount2 * 7f; if (num46 == 0) { crit = num86; } else { critMultiplier += num86 * 0.01f; crit = 0f; } armor = baseArmor + levelArmor * num56; armor *= 1f + 0.1f * (float)num31; armor *= 1f + 0.07f * (float)buffCount2; armor += (float)num26 * 70f; armor += (HasBuff(RoR2Content.Buffs.ArmorBoost) ? 200f : 0f); armor += (HasBuff(RoR2Content.Buffs.SmallArmorBoost) ? 100f : 0f); armor += (HasBuff(DLC1Content.Buffs.OutOfCombatArmorBuff) ? (100f * (float)num50) : 0f); armor += (HasBuff(RoR2Content.Buffs.ElephantArmorBoost) ? 500f : 0f); armor += (HasBuff(DLC1Content.Buffs.VoidSurvivorCorruptMode) ? 100f : 0f); armor += (HasBuff(DLC2Content.Buffs.AurelioniteBlessing) ? (60f + 0.1f * (float)master.money) : 0f); if (HasBuff(RoR2Content.Buffs.Cripple)) { armor -= 20f; } if (HasBuff(RoR2Content.Buffs.Pulverized)) { armor -= 60f; } if (isSprinting && num23 > 0) { armor += num23 * 30; } if (tamperedHeartActive) { armor += tamperedHeartArmorBonus; } int buffCount4 = GetBuffCount(DLC1Content.Buffs.PermanentDebuff); armor -= (float)buffCount4 * 2f; float num87 = 0f; if (num36 > 0) { num87 += 2f + 1f * (float)(num36 - 1); } float num88 = 1f; if (HasBuff(JunkContent.Buffs.GoldEmpowered)) { num88 *= 0.25f; } for (int i = 0; i < num16; i++) { num88 *= 0.75f; } for (int j = 0; j < num44; j++) { num88 *= 0.5f; } for (int k = 0; k < num47; k++) { num88 *= 0.5f; } if (teamComponent.teamIndex == TeamIndex.Monster && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse7) { num88 *= 0.5f; } if (HasBuff(RoR2Content.Buffs.NoCooldowns)) { num88 = 0f; } if ((bool)skillLocator.primary) { skillLocator.primary.cooldownScale = num88; skillLocator.primary.flatCooldownReduction = num87; } if ((bool)skillLocator.secondaryBonusStockSkill) { skillLocator.secondaryBonusStockSkill.cooldownScale = num88; skillLocator.secondaryBonusStockSkill.SetBonusStockFromBody(num21 + extraSecondaryFromSkill); skillLocator.secondaryBonusStockSkill.flatCooldownReduction = num87; } if ((bool)skillLocator.utilityBonusStockSkill) { float num89 = num88; if (num24 > 0) { num89 *= 2f / 3f; } skillLocator.utilityBonusStockSkill.cooldownScale = num89; skillLocator.utilityBonusStockSkill.flatCooldownReduction = num87; skillLocator.utilityBonusStockSkill.SetBonusStockFromBody(num24 * 2); } if ((bool)skillLocator.specialBonusStockSkill) { skillLocator.specialBonusStockSkill.cooldownScale = num88; if (num22 > 0) { skillLocator.specialBonusStockSkill.cooldownScale *= 0.67f; } skillLocator.specialBonusStockSkill.flatCooldownReduction = num87; skillLocator.specialBonusStockSkill.SetBonusStockFromBody(num22 + extraSpecialFromSkill); } critHeal = 0f; if (num19 > 0) { float num90 = crit; crit /= num19 + 1; critHeal = num90 - crit; } cursePenalty = 1f; if (num28 > 0) { cursePenalty = Mathf.Pow(2f, num28); } if (flag4) { cursePenalty *= 10f; } int buffCount5 = GetBuffCount(RoR2Content.Buffs.PermanentCurse); if (buffCount5 > 0) { cursePenalty += (float)buffCount5 * 0.01f; } if (HasBuff(RoR2Content.Buffs.Weak)) { armor -= 30f; damage *= 0.6f; moveSpeed *= 0.6f; } if (HasBuff(DLC2Content.Buffs.lunarruin)) { moveSpeed *= 0.8f; } if (flag) { maxHealth *= 1.5f; maxShield *= 1.5f; attackSpeed *= 1.7f; moveSpeed *= 1.3f; armor += 20f; damage *= 2f; regen *= 4f; } if (HasBuff(DLC2Content.Buffs.BoostAllStatsBuff)) { float num91 = (float)num53 * boostAllStatsMultiplier; _ = maxHealth; _ = moveSpeed; _ = damage; _ = attackSpeed; _ = crit; _ = regen; maxHealth += maxHealth * num91; moveSpeed += moveSpeed * num91; damage += damage * num91; attackSpeed += attackSpeed * num91; crit += crit * num91; regen += regen * num91; } maxBonusHealth = maxHealth; if (num27 > 0 && !flag) { float num92 = Mathf.Pow(0.95f, num27); attackSpeed *= num92; moveSpeed *= num92; damage *= num92; regen *= num92; cursePenalty += 0.1f * (float)num27; } if (HasBuff(DLC2Content.Buffs.SoulCost)) { cursePenalty += 0.1f * (float)GetBuffCount(DLC2Content.Buffs.SoulCost); } maxHealth /= cursePenalty; maxShield /= cursePenalty; oneShotProtectionFraction = Mathf.Max(0f, oneShotProtectionFraction - (1f - 1f / cursePenalty)); maxBarrier = maxHealth + maxShield; barrierDecayRate = maxBarrier / 30f; if (NetworkServer.active) { float num93 = maxHealth - num59; float num94 = maxShield - num60; if (num93 > 0f) { healthComponent.Heal(num93, default(ProcChainMask), nonRegen: false); } else if (healthComponent.health > maxHealth) { healthComponent.Networkhealth = Mathf.Max(healthComponent.health + num93, maxHealth); } if (num94 > 0f) { healthComponent.RechargeShield(num94); } else if (healthComponent.shield > maxShield) { healthComponent.Networkshield = Mathf.Max(healthComponent.shield + num94, maxShield); } } bleedChance = 10f * (float)num41; visionDistance = baseVisionDistance; if (HasBuff(DLC1Content.Buffs.Blinded)) { visionDistance = Mathf.Min(visionDistance, 15f); } if (level != num) { OnCalculatedLevelChanged(num, level); } int num95 = 0; if (num53 > 0 && !HasBuff(DLC2Content.Buffs.BoostAllStatsBuff)) { BuffIndex[] nonHiddenBuffIndices = BuffCatalog.nonHiddenBuffIndices; foreach (BuffIndex buffIndex in nonHiddenBuffIndices) { if (HasBuff(buffIndex) && buffIndex != DLC2Content.Buffs.BoostAllStatsBuff.buffIndex && !BuffCatalog.ignoreGrowthNectarIndices.Contains(buffIndex)) { num95++; if (num95 >= 5 && !HasBuff(DLC2Content.Buffs.BoostAllStatsBuff)) { AddTimedBuff(DLC2Content.Buffs.BoostAllStatsBuff, 5f); } } } } UpdateAllTemporaryVisualEffects(); statsDirty = false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void HandleDisableAllSkillsDebuff() { bool flag = HasBuff(DLC2Content.Buffs.DisableAllSkills); if (flag != allSkillsDisabled) { if (flag) { HandleSkillDisableState(_disable: true); allSkillsDisabled = true; } else { HandleSkillDisableState(_disable: false); allSkillsDisabled = false; } } void HandleSkillDisableState(bool _disable) { if (base.hasAuthority) { SkillDef skillDef = LegacyResourcesAPI.Load("Skills/DisabledSkills"); if (!skillDef) { UnityEngine.Debug.LogWarning("Could not find disabledSkill for DisableAllSkills."); } else if (_disable) { skillLocator.primary.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual); skillLocator.secondary.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual); skillLocator.utility.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual); skillLocator.special.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual); inventory.SetEquipmentDisabled(_active: true); Util.PlaySound("Play_env_meridian_primeDevestator_debuff", base.gameObject); screenDamageSkillsDisabled = new ScreenDamageCalculatorDisabledSkills(); healthComponent.screenDamageCalculator = screenDamageSkillsDisabled; } else { skillLocator.primary.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual); skillLocator.secondary.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual); skillLocator.utility.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual); skillLocator.special.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual); inventory.SetEquipmentDisabled(_active: false); if (screenDamageSkillsDisabled != null) { if (healthComponent.screenDamageCalculator == screenDamageSkillsDisabled) { healthComponent.screenDamageCalculator = null; } screenDamageSkillsDisabled.End(); } } } } } public void OnTeamLevelChanged() { statsDirty = true; } private void OnCalculatedLevelChanged(float oldLevel, float newLevel) { if (newLevel > oldLevel) { int num = Mathf.FloorToInt(oldLevel); if (Mathf.FloorToInt(newLevel) > num && num != 0) { OnLevelUp(); } } } private void OnLevelUp() { GlobalEventManager.OnCharacterLevelUp(this); if (inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock) > 0) { solitudeLevelCount++; AddFreeChestBuff(); Util.PlaySound("Play_item_proc_onLevelUpFreeUnlock_activate", base.gameObject); } } public void SetAimTimer(float duration) { aimTimer = duration; } public override void OnDeserialize(NetworkReader reader, bool initialState) { byte num = reader.ReadByte(); if (((uint)num & (true ? 1u : 0u)) != 0) { NetworkInstanceId networkInstanceId = reader.ReadNetworkId(); if (networkInstanceId != masterObjectId) { masterObjectId = networkInstanceId; statsDirty = true; } } if ((num & 2u) != 0) { ReadBuffs(reader); } if ((num & 4u) != 0) { bool flag = reader.ReadBoolean(); if (!hasEffectiveAuthority && flag != outOfCombat) { outOfCombat = flag; statsDirty = true; } } if ((num & 8u) != 0) { bool flag2 = reader.ReadBoolean(); if (flag2 != outOfDanger) { outOfDanger = flag2; statsDirty = true; } } if ((num & 0x10u) != 0) { bool flag3 = reader.ReadBoolean(); if (flag3 != isSprinting && !hasEffectiveAuthority) { statsDirty = true; isSprinting = flag3; } } } public override bool OnSerialize(NetworkWriter writer, bool initialState) { uint num = base.syncVarDirtyBits; if (initialState) { num = 31u; } bool num2 = (num & 1) != 0; bool flag = (num & 2) != 0; bool flag2 = (num & 4) != 0; bool flag3 = (num & 8) != 0; bool flag4 = (num & 0x10) != 0; writer.Write((byte)num); if (num2) { writer.Write(masterObjectId); } if (flag) { WriteBuffs(writer); } if (flag2) { writer.Write(outOfCombat); } if (flag3) { writer.Write(outOfDanger); } if (flag4) { writer.Write(isSprinting); } if (!initialState) { return num != 0; } return false; } public void TransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData) { if (!NetworkServer.active) { InternalTransmitItemBehavior(itemBehaviorData); CallCmdTransmitItemBehavior(itemBehaviorData); } else { ServerTransmitItemBehavior(itemBehaviorData); } } [Server] private void ServerTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::ServerTransmitItemBehavior(RoR2.CharacterBody/NetworkItemBehaviorData)' called on client"); return; } CallRpcTransmitItemBehavior(itemBehaviorData); InternalTransmitItemBehavior(itemBehaviorData); } [Command] private void CmdTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData) { ServerTransmitItemBehavior(itemBehaviorData); } [ClientRpc(channel = 1)] private void RpcTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData) { if (!NetworkServer.active) { InternalTransmitItemBehavior(itemBehaviorData); } } private void InternalTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData) { OnNetworkItemBehaviorUpdate?.Invoke(itemBehaviorData); } public T AddItemBehavior(int stack) where T : ItemBehavior { T val = GetComponent(); if (stack > 0) { if (!val) { val = base.gameObject.AddComponent(); val.body = this; val.enabled = true; } val.stack = stack; return val; } if ((bool)val) { UnityEngine.Object.Destroy(val); } return null; } public void HandleOnKillEffectsServer(DamageReport damageReport) { int num = killCountServer + 1; killCountServer = num; AddMultiKill(1); } public void OnKilledOtherServer(DamageReport damageReport) { } public void AddHelfireDuration(float duration) { helfireLifetime = duration; } [Server] private void UpdateHelfire(float deltaTime) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateHelfire(System.Single)' called on client"); return; } helfireLifetime -= deltaTime; bool flag = false; if ((bool)inventory) { flag = itemAvailability.helfireCount > 0 || helfireLifetime > 0f; } if ((bool)helfireController != flag) { if (flag) { helfireController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/HelfireController")).GetComponent(); helfireController.networkedBodyAttachment.AttachToGameObjectAndSpawn(base.gameObject); } else { UnityEngine.Object.Destroy(helfireController.gameObject); helfireController = null; } } } private void UpdateFireTrail() { bool hasFireTrail = itemAvailability.hasFireTrail; if (hasFireTrail != (bool)fireTrail) { if (hasFireTrail) { fireTrail = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/FireTrail"), transform).GetComponent(); fireTrail.transform.position = footPosition; fireTrail.owner = base.gameObject; fireTrail.radius *= radius; } else { UnityEngine.Object.Destroy(fireTrail.gameObject); fireTrail = null; } } if ((bool)fireTrail) { fireTrail.damagePerSecond = damage * 1.5f; } } private void UpdateAffixPoison(float deltaTime) { if (!itemAvailability.hasAffixPoison) { return; } poisonballTimer += deltaTime; if (poisonballTimer >= 6f) { int num = 3 + (int)radius; poisonballTimer = 0f; UnityEngine.Vector3 up = UnityEngine.Vector3.up; float num2 = 360f / (float)num; UnityEngine.Vector3 normalized = UnityEngine.Vector3.ProjectOnPlane(transform.forward, up).normalized; UnityEngine.Vector3 vector = UnityEngine.Vector3.RotateTowards(up, normalized, 0.43633232f, float.PositiveInfinity); for (int i = 0; i < num; i++) { UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num2 * (float)i, up) * vector; ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load("Prefabs/Projectiles/PoisonOrbProjectile"), corePosition, Util.QuaternionSafeLookRotation(forward), base.gameObject, damage * 1f, 0f, Util.CheckRoll(crit, master)); } } } private void UpdateAffixLunar(float deltaTime) { if (!outOfCombat && itemAvailability.hasAffixLunar) { lunarMissileRechargeTimer += deltaTime; lunarMissileTimerBetweenShots += deltaTime; int num = 4; if (!lunarMissilePrefab) { lunarMissilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/LunarMissileProjectile"); } if (lunarMissileRechargeTimer >= 10f) { lunarMissileRechargeTimer = 0f; remainingMissilesToFire += num; } if (remainingMissilesToFire > 0 && lunarMissileTimerBetweenShots > 0.1f) { lunarMissileTimerBetweenShots = 0f; UnityEngine.Vector3 vector = (inputBank ? inputBank.aimDirection : transform.forward); float num2 = 180f / (float)num; float num3 = 3f + (float)(int)radius * 1f; float num4 = damage * 0.3f; UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(vector); UnityEngine.Vector3 vector2 = UnityEngine.Quaternion.AngleAxis((float)(remainingMissilesToFire - 1) * num2 - num2 * (float)(num - 1) / 2f, vector) * UnityEngine.Vector3.up * num3; UnityEngine.Vector3 position = aimOrigin + vector2; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = lunarMissilePrefab; fireProjectileInfo.position = position; fireProjectileInfo.rotation = rotation; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.damage = num4; fireProjectileInfo.crit = Util.CheckRoll(crit, master); fireProjectileInfo.force = 200f; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); remainingMissilesToFire--; } } } private void UpdateAllTemporaryVisualEffects() { int buffCount = GetBuffCount(RoR2Content.Buffs.NullifyStack); UpdateSingleTemporaryVisualEffect(ref engiShieldTempEffectInstance, AssetReferences.engiShieldTempEffectPrefab, bestFitRadius, healthComponent.shield > 0f && HasBuff(RoR2Content.Buffs.EngiShield)); ref TemporaryVisualEffect tempEffect = ref bucklerShieldTempEffectInstance; GameObject bucklerShieldTempEffectPrefab = AssetReferences.bucklerShieldTempEffectPrefab; float effectRadius = radius; int active; if (isSprinting) { Inventory obj = inventory; active = (((object)obj != null && obj.GetItemCount(RoR2Content.Items.SprintArmor) > 0) ? 1 : 0); } else { active = 0; } UpdateSingleTemporaryVisualEffect(ref tempEffect, bucklerShieldTempEffectPrefab, effectRadius, (byte)active != 0); UpdateSingleTemporaryVisualEffect(ref slowDownTimeTempEffectInstance, AssetReferences.slowDownTimeTempEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Slow60)); UpdateSingleTemporaryVisualEffect(ref crippleEffectInstance, AssetReferences.crippleEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Cripple)); UpdateSingleTemporaryVisualEffect(ref tonicBuffEffectInstance, AssetReferences.tonicBuffEffectPrefab, radius, HasBuff(RoR2Content.Buffs.TonicBuff)); UpdateSingleTemporaryVisualEffect(ref weakTempEffectInstance, AssetReferences.weakTempEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Weak)); UpdateSingleTemporaryVisualEffect(ref energizedTempEffectInstance, AssetReferences.energizedTempEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Energized)); UpdateSingleTemporaryVisualEffect(ref barrierTempEffectInstance, AssetReferences.barrierTempEffectPrefab, bestFitRadius, healthComponent.barrier > 0f); UpdateSingleTemporaryVisualEffect(ref regenBoostEffectInstance, AssetReferences.regenBoostEffectPrefab, bestFitRadius, HasBuff(JunkContent.Buffs.MeatRegenBoost)); UpdateSingleTemporaryVisualEffect(ref elephantDefenseEffectInstance, AssetReferences.elephantDefenseEffectPrefab, radius, HasBuff(RoR2Content.Buffs.ElephantArmorBoost)); UpdateSingleTemporaryVisualEffect(ref healingDisabledEffectInstance, AssetReferences.healingDisabledEffectPrefab, radius, HasBuff(RoR2Content.Buffs.HealingDisabled)); UpdateSingleTemporaryVisualEffect(ref noCooldownEffectInstance, AssetReferences.noCooldownEffectPrefab, radius, HasBuff(RoR2Content.Buffs.NoCooldowns), "Head"); ref TemporaryVisualEffect tempEffect2 = ref doppelgangerEffectInstance; GameObject doppelgangerEffectPrefab = AssetReferences.doppelgangerEffectPrefab; float effectRadius2 = radius; Inventory obj2 = inventory; UpdateSingleTemporaryVisualEffect(ref tempEffect2, doppelgangerEffectPrefab, effectRadius2, (object)obj2 != null && obj2.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0, "Head"); UpdateSingleTemporaryVisualEffect(ref nullifyStack1EffectInstance, AssetReferences.nullifyStack1EffectPrefab, radius, buffCount == 1); UpdateSingleTemporaryVisualEffect(ref nullifyStack2EffectInstance, AssetReferences.nullifyStack2EffectPrefab, radius, buffCount == 2); UpdateSingleTemporaryVisualEffect(ref nullifyStack3EffectInstance, AssetReferences.nullifyStack3EffectPrefab, radius, HasBuff(RoR2Content.Buffs.Nullified)); UpdateSingleTemporaryVisualEffect(ref deathmarkEffectInstance, AssetReferences.deathmarkEffectPrefab, radius, HasBuff(RoR2Content.Buffs.DeathMark)); UpdateSingleTemporaryVisualEffect(ref crocoRegenEffectInstance, AssetReferences.crocoRegenEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.CrocoRegen)); UpdateSingleTemporaryVisualEffect(ref mercExposeEffectInstance, AssetReferences.mercExposeEffectPrefab, radius, HasBuff(RoR2Content.Buffs.MercExpose)); UpdateSingleTemporaryVisualEffect(ref lifestealOnHitEffectInstance, AssetReferences.lifestealOnHitEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.LifeSteal)); UpdateSingleTemporaryVisualEffect(ref teamWarCryEffectInstance, AssetReferences.teamWarCryEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.TeamWarCry), "HeadCenter"); UpdateSingleTemporaryVisualEffect(ref lunarGolemShieldEffectInstance, AssetReferences.lunarGolemShieldEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.LunarShell)); UpdateSingleTemporaryVisualEffect(ref randomDamageEffectInstance, AssetReferences.randomDamageEffectPrefab, radius, HasBuff(RoR2Content.Buffs.PowerBuff)); UpdateSingleTemporaryVisualEffect(ref warbannerEffectInstance, AssetReferences.warbannerEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Warbanner)); UpdateSingleTemporaryVisualEffect(ref teslaFieldEffectInstance, AssetReferences.teslaFieldEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.TeslaField)); UpdateSingleTemporaryVisualEffect(ref lunarSecondaryRootEffectInstance, AssetReferences.lunarSecondaryRootEffectPrefab, radius, HasBuff(RoR2Content.Buffs.LunarSecondaryRoot)); UpdateSingleTemporaryVisualEffect(ref lunarDetonatorEffectInstance, AssetReferences.lunarDetonatorEffectPrefab, radius, HasBuff(RoR2Content.Buffs.LunarDetonationCharge)); UpdateSingleTemporaryVisualEffect(ref fruitingEffectInstance, AssetReferences.fruitingEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Fruiting)); UpdateSingleTemporaryVisualEffect(ref mushroomVoidTempEffectInstance, AssetReferences.mushroomVoidTempEffectPrefab, radius, HasBuff(DLC1Content.Buffs.MushroomVoidActive)); UpdateSingleTemporaryVisualEffect(ref bearVoidTempEffectInstance, AssetReferences.bearVoidTempEffectPrefab, radius, HasBuff(DLC1Content.Buffs.BearVoidReady)); UpdateSingleTemporaryVisualEffect(ref outOfCombatArmorEffectInstance, AssetReferences.outOfCombatArmorEffectPrefab, radius, HasBuff(DLC1Content.Buffs.OutOfCombatArmorBuff)); UpdateSingleTemporaryVisualEffect(ref voidFogMildEffectInstance, AssetReferences.voidFogMildEffectPrefab, radius, HasBuff(RoR2Content.Buffs.VoidFogMild)); UpdateSingleTemporaryVisualEffect(ref voidFogStrongEffectInstance, AssetReferences.voidFogStrongEffectPrefab, radius, HasBuff(RoR2Content.Buffs.VoidFogStrong)); UpdateSingleTemporaryVisualEffect(ref voidRaidcrabWardWipeFogEffectInstance, AssetReferences.voidRaidcrabWardWipeFogEffectPrefab, radius, HasBuff(DLC1Content.Buffs.VoidRaidCrabWardWipeFog)); UpdateSingleTemporaryVisualEffect(ref voidJailerSlowEffectInstance, AssetReferences.voidJailerSlowEffectPrefab, radius, HasBuff(DLC1Content.Buffs.JailerSlow)); UpdateSingleTemporaryVisualEffect(ref aurelioniteBlessingEffectInstance, AssetReferences.aurelioniteBlessingEffectInstance, bestFitActualRadius, HasBuff(DLC2Content.Buffs.AurelioniteBlessing), "Pelvis"); if ((bool)mushroomVoidTempEffectInstance && !HasBuff(DLC1Content.Buffs.MushroomVoidActive)) { UnityEngine.Object.Destroy(mushroomVoidTempEffectInstance.gameObject); } } private void UpdateSingleTemporaryVisualEffect(ref TemporaryVisualEffect tempEffect, string resourceString, float effectRadius, bool active, string childLocatorOverride = "") { bool flag = tempEffect != null; if (flag == active) { return; } if (active) { if (flag) { return; } GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load(resourceString), corePosition, UnityEngine.Quaternion.identity); tempEffect = gameObject.GetComponent(); tempEffect.parentTransform = coreTransform; tempEffect.visualState = TemporaryVisualEffect.VisualState.Enter; tempEffect.healthComponent = healthComponent; tempEffect.radius = effectRadius; LocalCameraEffect component = gameObject.GetComponent(); if ((bool)component) { component.targetCharacter = base.gameObject; } if (string.IsNullOrEmpty(childLocatorOverride)) { return; } ChildLocator childLocator = modelLocator?.modelTransform?.GetComponent(); if ((bool)childLocator) { Transform transform = childLocator.FindChild(childLocatorOverride); if ((bool)transform) { tempEffect.parentTransform = transform; } } } else if ((bool)tempEffect) { tempEffect.visualState = TemporaryVisualEffect.VisualState.Exit; } } private void UpdateSingleTemporaryVisualEffect(ref TemporaryVisualEffect tempEffect, GameObject tempEffectPrefab, float effectRadius, bool active, string childLocatorOverride = "") { bool flag = tempEffect != null; if (flag == active) { return; } if (active) { if (flag) { return; } if ((bool)tempEffectPrefab) { GameObject gameObject = UnityEngine.Object.Instantiate(tempEffectPrefab, corePosition, UnityEngine.Quaternion.identity); tempEffect = gameObject.GetComponent(); tempEffect.parentTransform = coreTransform; tempEffect.visualState = TemporaryVisualEffect.VisualState.Enter; tempEffect.healthComponent = healthComponent; tempEffect.radius = effectRadius; LocalCameraEffect component = gameObject.GetComponent(); if ((bool)component) { component.targetCharacter = base.gameObject; } if (string.IsNullOrEmpty(childLocatorOverride)) { return; } ChildLocator childLocator = modelLocator?.modelTransform?.GetComponent(); if ((bool)childLocator) { Transform transform = childLocator.FindChild(childLocatorOverride); if ((bool)transform) { tempEffect.parentTransform = transform; } } } else { UnityEngine.Debug.LogError("Can't instantiate null temporary visual effect"); } } else if ((bool)tempEffect) { tempEffect.visualState = TemporaryVisualEffect.VisualState.Exit; } } public VisibilityLevel GetVisibilityLevel(CharacterBody observer) { return GetVisibilityLevel(observer ? observer.teamComponent.teamIndex : TeamIndex.None); } public VisibilityLevel GetVisibilityLevel(TeamIndex observerTeam) { if (!hasCloakBuff) { return VisibilityLevel.Visible; } if (teamComponent.teamIndex != observerTeam) { return VisibilityLevel.Cloaked; } return VisibilityLevel.Revealed; } public void AddSpreadBloom(float value) { spreadBloomInternal = Mathf.Min(spreadBloomInternal + value, 1f); } public void SetSpreadBloom(float value, bool canOnlyIncreaseBloom = true) { if (canOnlyIncreaseBloom) { spreadBloomInternal = Mathf.Clamp(value, spreadBloomInternal, 1f); } else { spreadBloomInternal = Mathf.Min(value, 1f); } } private void UpdateSpreadBloom(float dt) { float num = 1f / spreadBloomDecayTime; spreadBloomInternal = Mathf.Max(spreadBloomInternal - num * dt, 0f); } [Client] public void SendConstructTurret(CharacterBody builder, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, MasterCatalog.MasterIndex masterIndex) { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.CharacterBody::SendConstructTurret(RoR2.CharacterBody,UnityEngine.Vector3,UnityEngine.Quaternion,RoR2.MasterCatalog/MasterIndex)' called on server"); return; } ConstructTurretMessage msg = new ConstructTurretMessage { builder = builder.gameObject, position = position, rotation = rotation, turretMasterIndex = masterIndex }; ClientScene.readyConnection.Send(62, msg); } [NetworkMessageHandler(msgType = 62, server = true)] private static void HandleConstructTurret(NetworkMessage netMsg) { ConstructTurretMessage constructTurretMessage = netMsg.ReadMessage(); if (!constructTurretMessage.builder) { return; } CharacterBody component = constructTurretMessage.builder.GetComponent(); if ((bool)component) { CharacterMaster characterMaster = component.master; if ((bool)characterMaster) { CharacterMaster characterMaster2 = new MasterSummon { masterPrefab = MasterCatalog.GetMasterPrefab(constructTurretMessage.turretMasterIndex), position = constructTurretMessage.position, rotation = constructTurretMessage.rotation, summonerBodyObject = component.gameObject, ignoreTeamMemberLimit = true, inventoryToCopy = characterMaster.inventory }.Perform(); Deployable deployable = characterMaster2.gameObject.AddComponent(); deployable.onUndeploy = new UnityEvent(); deployable.onUndeploy.AddListener(characterMaster2.TrueKill); characterMaster.AddDeployable(deployable, DeployableSlot.EngiTurret); } } } public void AddIncreasedDamageMultiKillTime() { increasedDamageKillTimer = 5f; } [Server] public void AddMultiKill(int kills) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddMultiKill(System.Int32)' called on client"); return; } multiKillTimer = 1f; multiKillCount += kills; int num = (inventory ? inventory.GetItemCount(RoR2Content.Items.WarCryOnMultiKill) : 0); if (num > 0 && multiKillCount >= 4) { AddTimedBuff(RoR2Content.Buffs.WarCryBuff, 2f + 4f * (float)num); } increasedDamageKillTimer = 5f; increasedDamageKillCount += kills; increasedDamageKillCountBuff += kills; if ((((bool)inventory && inventory.GetItemCount(DLC2Content.Items.IncreaseDamageOnMultiKill) != 0) ? 1 : 0) > (false ? 1 : 0)) { if (increasedDamageKillCountBuff >= 5) { AddBuff(DLC2Content.Buffs.IncreaseDamageBuff); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/IncreaseDamageOnMultiKillVFX"), new EffectData { origin = base.gameObject.transform.position }, transmit: true); increasedDamageKillCountBuff = 0; } if (increasedDamageKillCount > oldKillcount) { oldKillcount = increasedDamageKillCount; } } } [Server] private void UpdateMultiKill(float deltaTime) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateMultiKill(System.Single)' called on client"); return; } multiKillTimer -= deltaTime; if (multiKillTimer <= 0f) { multiKillTimer = 0f; multiKillCount = 0; } increasedDamageKillTimer -= deltaTime; if (increasedDamageKillTimer <= 0f) { increasedDamageKillTimer = 0f; increasedDamageKillCount = 0; increasedDamageKillCountBuff = 0; oldKillcount = 0; oldComboMeter = 0; if (HasBuff(DLC2Content.Buffs.IncreaseDamageBuff)) { RemoveBuff(DLC2Content.Buffs.IncreaseDamageBuff); } } } public void AddIncreasePrimaryDamageStack() { int buffCount = GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff); int itemCount = inventory.GetItemCount(DLC2Content.Items.IncreasePrimaryDamage); int num = 4 + itemCount; if (buffCount < num) { AddBuff(DLC2Content.Buffs.IncreasePrimaryDamageBuff); } buffCount = GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff); TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.IncreasePrimaryDamage.itemIndex, buffCount)); float num2 = baseDamage + levelDamage * (level - 1f); luminousShotDamage = num2 * (1.25f + 0.25f * (float)itemCount) * (float)buffCount; } public void IncreasePrimaryDamageReset() { if (GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff) > 0) { SetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff.buffIndex, 0); TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.IncreasePrimaryDamage.itemIndex, 0f)); } luminousShotReady = false; } [Server] private void UpdateDelayedDamage(float deltaTime) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateDelayedDamage(System.Single)' called on client"); return; } int num = (inventory ? inventory.GetItemCount(DLC2Content.Items.DelayedDamage) : 0); if (num > 0) { int buffCount = GetBuffCount(DLC2Content.Buffs.DelayedDamageBuff); if (oldDelayedDamageCount < num) { int num2 = num - oldDelayedDamageCount; for (int i = 0; i < num2; i++) { AddBuff(DLC2Content.Buffs.DelayedDamageBuff); } oldDelayedDamageCount = num; } else if (oldDelayedDamageCount > num) { oldDelayedDamageCount = num; } if (buffCount < num) { delayedDamageRefreshTime -= deltaTime; if (delayedDamageRefreshTime <= 0f) { AddBuff(DLC2Content.Buffs.DelayedDamageBuff); delayedDamageRefreshTime = 10f; } } } else { delayedDamageRefreshTime = 10f; oldDelayedDamageCount = 0; RemoveBuff(DLC2Content.Buffs.DelayedDamageBuff); RemoveBuff(DLC2Content.Buffs.DelayedDamageDebuff); RemoveOldestTimedBuff(DLC2Content.Buffs.DelayedDamageDebuff); } } public void SpawnDelayedDamageEffect() { if (NetworkServer.active) { ServerSpawnDelayedDamageEffect(); } else { CallCmdSpawnDelayedDamageEffect(); } } [Server] private void ServerSpawnDelayedDamageEffect() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::ServerSpawnDelayedDamageEffect()' called on client"); } else { UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/Effects/DelayedDamageIndicator"), mainHurtBox ? mainHurtBox.transform.position : transform.position, UnityEngine.Quaternion.identity, mainHurtBox ? mainHurtBox.transform : transform); } } [Command] private void CmdSpawnDelayedDamageEffect() { ServerSpawnDelayedDamageEffect(); } public void SecondHalfOfDelayedDamage(DamageInfo halfDamage) { RemoveBuff(DLC2Content.Buffs.DelayedDamageBuff); AddBuff(DLC2Content.Buffs.DelayedDamageDebuff); TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.DelayedDamage.itemIndex, 0f)); DelayedDamageInfo delayedDamageInfo = new DelayedDamageInfo(); delayedDamageInfo.halfDamage = halfDamage; incomingDamageList.Add(delayedDamageInfo); if (incomingDamageList.Count == 0) { halfDamageReady = false; } else { halfDamageReady = true; } } [Server] private void UpdateSecondHalfOfDamage(float deltaTime) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateSecondHalfOfDamage(System.Single)' called on client"); } else { if (!halfDamageReady) { return; } for (int i = 0; i < incomingDamageList.Count; i++) { DelayedDamageInfo delayedDamageInfo = incomingDamageList[i]; DamageInfo halfDamage = delayedDamageInfo.halfDamage; halfDamage.position = GetBody().corePosition; if (protectFromOneShot) { halfDamage.damageType = DamageType.NonLethal; } delayedDamageInfo.timeUntilDamage -= deltaTime; if (delayedDamageInfo.timeUntilDamage <= 0f) { Util.PlaySound("Play_item_proc_delayedDamage_2ndHit", base.gameObject); healthComponent.TakeDamage(halfDamage); RemoveBuff(DLC2Content.Buffs.DelayedDamageDebuff); incomingDamageList.RemoveAt(i); protectFromOneShot = false; } } } } [ClientRpc] public void RpcTeleportCharacterToSafety() { if (!hasEffectiveAuthority) { return; } Transform transform = modelLocator?.modelTransform; if (!(transform == null)) { CharacterModel component = transform.GetComponent(); UnityEngine.Vector3 position = coreTransform.position; int itemCount = inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealth); BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = base.gameObject; blastAttack.baseDamage = damage * ((float)itemCount * 3.5f); blastAttack.baseForce = 2000f; blastAttack.bonusForce = UnityEngine.Vector3.zero; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = RollCrit(); blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.damageType = DamageType.Generic; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.inflictor = base.gameObject; blastAttack.position = position; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = 1f; blastAttack.radius = 25f; blastAttack.losType = BlastAttack.LoSType.None; blastAttack.teamIndex = TeamIndex.Player; blastAttack.Fire(); EffectManager.SpawnEffect(CommonAssets.teleportOnLowHealthExplosion, new EffectData { origin = position, scale = 50f, rotation = UnityEngine.Quaternion.identity }, transmit: true); Util.PlaySound("Play_item_proc_teleportOnLowHealth", base.gameObject); NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); List source = nodeGraph.FindNodesInRange(corePosition, 100f, 200f, HullMask.Human); nodeGraph.GetNodePosition(source.First(), out var position2); TeleportHelper.TeleportBody(this, position2); TeleportOutController.AddTPOutEffect(component, 1f, 0f, 1f); EffectManager.SpawnEffect(CommonAssets.teleportOnLowHealthVFX, new EffectData { origin = this.transform.position, rotation = UnityEngine.Quaternion.identity }, transmit: true); UnityEngine.Vector3 normalized = (position - position2).normalized; if ((bool)characterDirection) { characterDirection.forward = normalized; } if ((bool)master && (bool)master.playerCharacterMasterController) { master.playerCharacterMasterController.RedirectCamera(UnityEngine.Quaternion.LookRotation(normalized).eulerAngles); } } } private void prayerBeadCalculateAppliedStats(float levelStat) { if (teamComponent.teamIndex == TeamIndex.Player) { float num = (float)GetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff) * levelStat * (0.2f + 0.05f * (float)(inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp) - 1)); if (levelStat == levelMaxHealth) { _ = inventory.beadAppliedHealth; inventory.beadAppliedHealth += num; } else if (levelStat == levelMaxShield) { _ = inventory.beadAppliedShield; inventory.beadAppliedShield += num; } else if (levelStat == levelRegen) { _ = inventory.beadAppliedRegen; inventory.beadAppliedRegen += num; } else if (levelStat == levelDamage) { _ = inventory.beadAppliedDamage; inventory.beadAppliedDamage += num; } } } [HideInInspector] public void runicLensUpdateVariables(float damage, UnityEngine.Vector3 position, DamageInfo damageInfo, float blastForce, float blastRadius) { runicLensPosition = position; runicLensImpactTime = Run.instance.time + 2f; runicLensMeteorReady = true; runicLensDamage = damage; runicLensDamageInfo = damageInfo; runicLensBlastForce = blastForce; runicLensBlastRadius = blastRadius; } public void detonateRunicLensMeteor() { GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/RunicMeteorStrikeImpact"); Util.PlaySound("Play_item_proc_meteorAttackOnHighDamage_impact", base.gameObject); EffectData effectData = new EffectData { origin = runicLensPosition }; EffectManager.SpawnEffect(gameObject, effectData, transmit: true); BlastAttack blastAttack = new BlastAttack(); blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.inflictor = gameObject; blastAttack.baseDamage = runicLensDamage; blastAttack.baseForce = runicLensBlastForce; blastAttack.attackerFiltering = AttackerFiltering.Default; blastAttack.crit = runicLensDamageInfo.crit; blastAttack.attacker = runicLensDamageInfo.attacker; blastAttack.bonusForce = UnityEngine.Vector3.zero; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.position = runicLensPosition; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = 0.5f; blastAttack.teamIndex = TeamIndex.Player; blastAttack.radius = runicLensBlastRadius; blastAttack.Fire(); } public void TriggerEnemyDebuffs(DamageInfo damageInfo) { SphereSearch sphereSearch = new SphereSearch(); List list = CollectionPool>.RentCollection(); sphereSearch.mask = LayerIndex.entityPrecise.mask; sphereSearch.origin = base.gameObject.transform.position; sphereSearch.radius = 30f; sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal; sphereSearch.RefreshCandidates(); sphereSearch.FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(teamComponent.teamIndex)); sphereSearch.OrderCandidatesByDistance(); sphereSearch.FilterCandidatesByDistinctHurtBoxEntities(); sphereSearch.GetHurtBoxes(list); sphereSearch.ClearCandidates(); EffectManager.SpawnEffect(CommonAssets.thornExplosionEffect, new EffectData { origin = coreTransform.position, scale = 60f, rotation = UnityEngine.Quaternion.identity }, transmit: true); Util.PlaySound("Play_item_proc_triggerEnemyDebuffs", base.gameObject); for (int i = 0; i < list.Count; i++) { HurtBox hurtBox = list[i]; if (!hurtBox || !hurtBox.healthComponent || !hurtBox.healthComponent.alive) { continue; } CharacterBody body = hurtBox.healthComponent.body; int itemCount = inventory.GetItemCount(DLC2Content.Items.TriggerEnemyDebuffs); int num = 1; if (!body.hasStackableDebuff) { DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.Bleed, 3f * damageInfo.procCoefficient); continue; } int buffCount = body.GetBuffCount(RoR2Content.Buffs.OnFire); if (buffCount > 0) { float num2 = 0.5f; int num3 = num * itemCount; InflictDotInfo inflictDotInfo = default(InflictDotInfo); inflictDotInfo.attackerObject = damageInfo.attacker; inflictDotInfo.victimObject = body.gameObject; inflictDotInfo.totalDamage = damageInfo.damage * num2; inflictDotInfo.damageMultiplier = 1f; inflictDotInfo.dotIndex = DotController.DotIndex.Burn; InflictDotInfo inflictDotInfo2 = inflictDotInfo; for (int j = 0; j < num3; j++) { DotController.InflictDot(ref inflictDotInfo2); } } buffCount = body.GetBuffCount(RoR2Content.Buffs.BeetleJuice); if (buffCount > 0) { int newCount = buffCount + num * itemCount; body.SetBuffCount(RoR2Content.Buffs.BeetleJuice.buffIndex, newCount); } buffCount = body.GetBuffCount(RoR2Content.Buffs.NullifyStack); if (buffCount > 0) { int newCount2 = buffCount + num * itemCount; body.SetBuffCount(RoR2Content.Buffs.NullifyStack.buffIndex, newCount2); } buffCount = body.GetBuffCount(RoR2Content.Buffs.Bleeding); if (buffCount > 0) { int num4 = num * itemCount; for (int k = 0; k < num4; k++) { DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.Bleed, 3f * damageInfo.procCoefficient); } } buffCount = body.GetBuffCount(RoR2Content.Buffs.SuperBleed); if (buffCount > 0) { int num5 = num * itemCount; for (int l = 0; l < num5; l++) { DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.SuperBleed, 15f * damageInfo.procCoefficient); } } buffCount = body.GetBuffCount(RoR2Content.Buffs.Blight); if (buffCount > 0) { int num6 = num * itemCount; for (int m = 0; m < num6; m++) { DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.Blight, 5f * damageInfo.procCoefficient); } } buffCount = body.GetBuffCount(RoR2Content.Buffs.Overheat); if (buffCount > 0) { int newCount3 = buffCount + num * itemCount; body.SetBuffCount(RoR2Content.Buffs.Overheat.buffIndex, newCount3); } buffCount = body.GetBuffCount(RoR2Content.Buffs.PulverizeBuildup); if (buffCount > 0) { int newCount4 = buffCount + num * itemCount; body.SetBuffCount(RoR2Content.Buffs.PulverizeBuildup.buffIndex, newCount4); } buffCount = body.GetBuffCount(DLC1Content.Buffs.StrongerBurn); if (buffCount > 0) { int num7 = num * itemCount; for (int n = 0; n < num7; n++) { DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.StrongerBurn, 3f * damageInfo.procCoefficient); } } buffCount = body.GetBuffCount(DLC1Content.Buffs.Fracture); if (buffCount > 0) { int num8 = num * itemCount; DotController.DotDef dotDef = DotController.GetDotDef(DotController.DotIndex.Fracture); for (int num9 = 0; num9 < num8; num9++) { DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.Fracture, dotDef.interval); } } buffCount = body.GetBuffCount(DLC1Content.Buffs.PermanentDebuff); if (buffCount > 0) { int newCount5 = buffCount + num * itemCount; body.SetBuffCount(DLC1Content.Buffs.PermanentDebuff.buffIndex, newCount5); } buffCount = body.GetBuffCount(DLC2Content.Buffs.lunarruin); if (buffCount > 0) { int num10 = buffCount + num * itemCount; body.SetBuffCount(DLC2Content.Buffs.lunarruin.buffIndex, num10); for (int num11 = 0; num11 < num10; num11++) { DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.LunarRuin, 5f); } } } } private void IncreaseStunPierceDamage(int kills) { } public void ApplyTamperedHeartPassive(float heartRegen, float heartMSpeed, float heartDamage, float armor, float attackSpeed) { tamperedHeartActive = true; tamperedHeartRegenBonus = heartRegen; tamperedHeartMSpeedBonus = heartMSpeed; tamperedHeartDamageBonus = heartDamage; tamperedHeartAttackSpeedBonus = attackSpeed; tamperedHeartArmorBonus = armor; } public void AddFreeChestBuff() { int itemCount = inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock); for (int i = 0; i < itemCount; i++) { AddBuff(DLC2Content.Buffs.FreeUnlocks.buffIndex); } } [ClientRpc] public void RpcBark() { if ((bool)sfxLocator) { Util.PlaySound(sfxLocator.barkSound, base.gameObject); } } [Command] public void CmdRequestVehicleEjection() { if ((bool)currentVehicle) { currentVehicle.EjectPassenger(base.gameObject); } } public bool RollCrit() { if ((bool)master) { return Util.CheckRoll(crit, master); } return false; } public bool IsCullable() { if (!dontCull && Importance - TeamComponent.GetTeamAverageImportance(teamComponent) < 3 && teamComponent.teamIndex != TeamIndex.Player && !isBoss) { return TeamComponent.GetTeamMembers(TeamIndex.Monster).Count >= 10; } return false; } public bool IsActivelyCullable() { if (!isBoss) { if (!NearAnyPlayers(75f)) { return !CharacterIsVisible; } return false; } return false; } public bool NearAnyPlayers(float checkRadius) { float num = checkRadius * checkRadius; foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if ((bool)instance.master && (bool)instance.master.GetBody() && (transform.position - instance.master.GetBody().transform.position).sqrMagnitude < num) { return true; } } return false; } [ClientRpc] private void RpcUsePreferredInitialStateType() { if (hasEffectiveAuthority) { SetBodyStateToPreferredInitialState(); } } public void SetBodyStateToPreferredInitialState() { if (!hasEffectiveAuthority) { if (NetworkServer.active) { CallRpcUsePreferredInitialStateType(); } return; } Type stateType = preferredInitialStateType.stateType; if (!(stateType == null) && !(stateType == typeof(Uninitialized))) { EntityStateMachine.FindByCustomName(base.gameObject, "Body")?.SetState(EntityStateCatalog.InstantiateState(stateType)); } } [Server] public void SetLoadoutServer(Loadout loadout) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::SetLoadoutServer(RoR2.Loadout)' called on client"); } else { skillLocator.ApplyLoadoutServer(loadout, bodyIndex); } } static CharacterBody() { instancesList = new List(); readOnlyInstancesList = new ReadOnlyCollection(instancesList); kCmdCmdAddTimedBuff = -160178508; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdAddTimedBuff, InvokeCmdCmdAddTimedBuff); kCmdCmdSetInLava = 234733148; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdSetInLava, InvokeCmdCmdSetInLava); kCmdCmdUpdateSprint = -1006016914; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdUpdateSprint, InvokeCmdCmdUpdateSprint); kCmdCmdOnSkillActivated = 384138986; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdOnSkillActivated, InvokeCmdCmdOnSkillActivated); kCmdCmdTransmitItemBehavior = 394448000; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdTransmitItemBehavior, InvokeCmdCmdTransmitItemBehavior); kCmdCmdSpawnDelayedDamageEffect = 1860577938; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdSpawnDelayedDamageEffect, InvokeCmdCmdSpawnDelayedDamageEffect); kCmdCmdRequestVehicleEjection = 1803737791; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdRequestVehicleEjection, InvokeCmdCmdRequestVehicleEjection); kRpcRpcTransmitItemBehavior = -729896618; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterBody), kRpcRpcTransmitItemBehavior, InvokeRpcRpcTransmitItemBehavior); kRpcRpcTeleportCharacterToSafety = -245876694; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterBody), kRpcRpcTeleportCharacterToSafety, InvokeRpcRpcTeleportCharacterToSafety); kRpcRpcBark = -76716871; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterBody), kRpcRpcBark, InvokeRpcRpcBark); kRpcRpcUsePreferredInitialStateType = 638695010; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterBody), kRpcRpcUsePreferredInitialStateType, InvokeRpcRpcUsePreferredInitialStateType); NetworkCRC.RegisterBehaviour("CharacterBody", 0); } private void UNetVersion() { } protected static void InvokeCmdCmdAddTimedBuff(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdAddTimedBuff called on client."); } else { ((CharacterBody)obj).CmdAddTimedBuff((BuffIndex)reader.ReadInt32(), reader.ReadSingle()); } } protected static void InvokeCmdCmdSetInLava(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetInLava called on client."); } else { ((CharacterBody)obj).CmdSetInLava(reader.ReadBoolean()); } } protected static void InvokeCmdCmdUpdateSprint(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdUpdateSprint called on client."); } else { ((CharacterBody)obj).CmdUpdateSprint(reader.ReadBoolean()); } } protected static void InvokeCmdCmdOnSkillActivated(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdOnSkillActivated called on client."); } else { ((CharacterBody)obj).CmdOnSkillActivated((sbyte)reader.ReadPackedUInt32()); } } protected static void InvokeCmdCmdTransmitItemBehavior(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdTransmitItemBehavior called on client."); } else { ((CharacterBody)obj).CmdTransmitItemBehavior(GeneratedNetworkCode._ReadNetworkItemBehaviorData_CharacterBody(reader)); } } protected static void InvokeCmdCmdSpawnDelayedDamageEffect(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSpawnDelayedDamageEffect called on client."); } else { ((CharacterBody)obj).CmdSpawnDelayedDamageEffect(); } } protected static void InvokeCmdCmdRequestVehicleEjection(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdRequestVehicleEjection called on client."); } else { ((CharacterBody)obj).CmdRequestVehicleEjection(); } } public void CallCmdAddTimedBuff(BuffIndex buffType, float duration) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdAddTimedBuff called on server."); return; } if (base.isServer) { CmdAddTimedBuff(buffType, duration); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdAddTimedBuff); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)buffType); networkWriter.Write(duration); SendCommandInternal(networkWriter, 0, "CmdAddTimedBuff"); } public void CallCmdSetInLava(bool b) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetInLava called on server."); return; } if (base.isServer) { CmdSetInLava(b); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetInLava); networkWriter.Write(GetComponent().netId); networkWriter.Write(b); SendCommandInternal(networkWriter, 0, "CmdSetInLava"); } public void CallCmdUpdateSprint(bool newIsSprinting) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdUpdateSprint called on server."); return; } if (base.isServer) { CmdUpdateSprint(newIsSprinting); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdUpdateSprint); networkWriter.Write(GetComponent().netId); networkWriter.Write(newIsSprinting); SendCommandInternal(networkWriter, 0, "CmdUpdateSprint"); } public void CallCmdOnSkillActivated(sbyte skillIndex) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdOnSkillActivated called on server."); return; } if (base.isServer) { CmdOnSkillActivated(skillIndex); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdOnSkillActivated); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32((uint)skillIndex); SendCommandInternal(networkWriter, 0, "CmdOnSkillActivated"); } public void CallCmdTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdTransmitItemBehavior called on server."); return; } if (base.isServer) { CmdTransmitItemBehavior(itemBehaviorData); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdTransmitItemBehavior); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WriteNetworkItemBehaviorData_CharacterBody(networkWriter, itemBehaviorData); SendCommandInternal(networkWriter, 0, "CmdTransmitItemBehavior"); } public void CallCmdSpawnDelayedDamageEffect() { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSpawnDelayedDamageEffect called on server."); return; } if (base.isServer) { CmdSpawnDelayedDamageEffect(); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSpawnDelayedDamageEffect); networkWriter.Write(GetComponent().netId); SendCommandInternal(networkWriter, 0, "CmdSpawnDelayedDamageEffect"); } public void CallCmdRequestVehicleEjection() { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdRequestVehicleEjection called on server."); return; } if (base.isServer) { CmdRequestVehicleEjection(); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdRequestVehicleEjection); networkWriter.Write(GetComponent().netId); SendCommandInternal(networkWriter, 0, "CmdRequestVehicleEjection"); } protected static void InvokeRpcRpcTransmitItemBehavior(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcTransmitItemBehavior called on server."); } else { ((CharacterBody)obj).RpcTransmitItemBehavior(GeneratedNetworkCode._ReadNetworkItemBehaviorData_CharacterBody(reader)); } } protected static void InvokeRpcRpcTeleportCharacterToSafety(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcTeleportCharacterToSafety called on server."); } else { ((CharacterBody)obj).RpcTeleportCharacterToSafety(); } } protected static void InvokeRpcRpcBark(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcBark called on server."); } else { ((CharacterBody)obj).RpcBark(); } } protected static void InvokeRpcRpcUsePreferredInitialStateType(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcUsePreferredInitialStateType called on server."); } else { ((CharacterBody)obj).RpcUsePreferredInitialStateType(); } } public void CallRpcTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcTransmitItemBehavior called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcTransmitItemBehavior); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WriteNetworkItemBehaviorData_CharacterBody(networkWriter, itemBehaviorData); SendRPCInternal(networkWriter, 1, "RpcTransmitItemBehavior"); } public void CallRpcTeleportCharacterToSafety() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcTeleportCharacterToSafety called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcTeleportCharacterToSafety); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcTeleportCharacterToSafety"); } public void CallRpcBark() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcBark called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcBark); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcBark"); } public void CallRpcUsePreferredInitialStateType() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcUsePreferredInitialStateType called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcUsePreferredInitialStateType); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcUsePreferredInitialStateType"); } public override void PreStartClient() { } } public class CharacterDeathBehavior : MonoBehaviour { [Tooltip("The state machine to set the state of when this character is killed.")] public EntityStateMachine deathStateMachine; [Tooltip("The state to enter when this character is killed.")] public SerializableEntityStateType deathState; [Tooltip("The state machine(s) to set to idle when this character is killed.")] public EntityStateMachine[] idleStateMachine; [Tooltip("Be default, dead characters are set to the debris layer. Check this to bypass that.")] [SerializeField] private bool bypassDeathLayerChange; public void OnDeath() { if (Util.HasEffectiveAuthority(base.gameObject)) { if ((bool)deathStateMachine) { deathStateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref deathState)); } EntityStateMachine[] array = idleStateMachine; for (int i = 0; i < array.Length; i++) { array[i].SetNextState(new EntityStates.Idle()); } } if (!bypassDeathLayerChange) { base.gameObject.layer = LayerIndex.debris.intVal; CharacterMotor component = GetComponent(); if ((bool)component) { component.Motor.RebuildCollidableLayers(); } } ILifeBehavior[] components = GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].OnDeathStart(); } ModelLocator component2 = GetComponent(); if (!component2) { return; } Transform modelTransform = component2.modelTransform; if ((bool)modelTransform) { components = modelTransform.GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].OnDeathStart(); } } } } public class CharacterDirection : NetworkBehaviour, ILifeBehavior { private struct TurnAnimatorParamsSet { public float angleMin; public float angleMax; public bool turnRight45; public bool turnRight90; public bool turnRight135; public bool turnLeft45; public bool turnLeft90; public bool turnLeft135; private static readonly int turnRight45ParamHash = Animator.StringToHash("turnRight45"); private static readonly int turnRight90ParamHash = Animator.StringToHash("turnRight90"); private static readonly int turnRight135ParamHash = Animator.StringToHash("turnRight135"); private static readonly int turnLeft45ParamHash = Animator.StringToHash("turnLeft45"); private static readonly int turnLeft90ParamHash = Animator.StringToHash("turnLeft90"); private static readonly int turnLeft135ParamHash = Animator.StringToHash("turnLeft135"); public void Apply(Animator animator) { animator.SetBool(turnRight45ParamHash, turnRight45); animator.SetBool(turnRight90ParamHash, turnRight90); animator.SetBool(turnRight135ParamHash, turnRight135); animator.SetBool(turnLeft45ParamHash, turnLeft45); animator.SetBool(turnLeft90ParamHash, turnLeft90); animator.SetBool(turnLeft135ParamHash, turnLeft135); } } [HideInInspector] public UnityEngine.Vector3 moveVector; [Tooltip("The transform to rotate.")] public Transform targetTransform; [Tooltip("The transform to take the rotation from for animator purposes. Commonly the root node.")] public Transform overrideAnimatorForwardTransform; public RootMotionAccumulator rootMotionAccumulator; public Animator modelAnimator; [Tooltip("The character direction is set by root rotation, rather than moveVector.")] public bool driveFromRootRotation; [Tooltip("The maximum turn rate in degrees/second.")] public float turnSpeed = 360f; [SerializeField] private string turnSoundName; private int previousParamsIndex = -1; private float yRotationVelocity; private float _yaw; private UnityEngine.Vector3 targetVector = UnityEngine.Vector3.zero; private const float offset = 22.5f; private static readonly TurnAnimatorParamsSet[] turnAnimatorParamsSets = new TurnAnimatorParamsSet[7] { new TurnAnimatorParamsSet { angleMin = -180f, angleMax = -112.5f, turnRight45 = false, turnRight90 = false, turnRight135 = false, turnLeft45 = false, turnLeft90 = false, turnLeft135 = true }, new TurnAnimatorParamsSet { angleMin = -112.5f, angleMax = -67.5f, turnRight45 = false, turnRight90 = false, turnRight135 = false, turnLeft45 = false, turnLeft90 = true, turnLeft135 = false }, new TurnAnimatorParamsSet { angleMin = -67.5f, angleMax = -22.5f, turnRight45 = false, turnRight90 = false, turnRight135 = false, turnLeft45 = true, turnLeft90 = false, turnLeft135 = false }, new TurnAnimatorParamsSet { turnRight45 = false, turnRight90 = false, turnRight135 = false, turnLeft45 = false, turnLeft90 = false, turnLeft135 = false }, new TurnAnimatorParamsSet { angleMin = 22.5f, angleMax = 67.5f, turnRight45 = true, turnRight90 = false, turnRight135 = false, turnLeft45 = false, turnLeft90 = false, turnLeft135 = false }, new TurnAnimatorParamsSet { angleMin = 67.5f, angleMax = 112.5f, turnRight45 = false, turnRight90 = true, turnRight135 = false, turnLeft45 = false, turnLeft90 = false, turnLeft135 = false }, new TurnAnimatorParamsSet { angleMin = 112.5f, angleMax = 180f, turnRight45 = false, turnRight90 = false, turnRight135 = true, turnLeft45 = false, turnLeft90 = false, turnLeft135 = false } }; private static readonly int paramsMidIndex = turnAnimatorParamsSets.Length >> 1; public float yaw { get { return _yaw; } set { _yaw = value; if ((bool)targetTransform) { targetTransform.rotation = UnityEngine.Quaternion.Euler(0f, _yaw, 0f); } } } public UnityEngine.Vector3 animatorForward { get { if (!overrideAnimatorForwardTransform) { return forward; } float y = overrideAnimatorForwardTransform.eulerAngles.y; return UnityEngine.Quaternion.Euler(0f, y, 0f) * UnityEngine.Vector3.forward; } } public UnityEngine.Vector3 forward { get { return UnityEngine.Quaternion.Euler(0f, yaw, 0f) * UnityEngine.Vector3.forward; } set { value.y = 0f; yaw = Util.QuaternionSafeLookRotation(value, UnityEngine.Vector3.up).eulerAngles.y; } } public bool hasEffectiveAuthority { get; private set; } private void UpdateAuthority() { hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject); } public override void OnStartAuthority() { UpdateAuthority(); } public override void OnStopAuthority() { UpdateAuthority(); } private void Start() { UpdateAuthority(); ModelLocator component = GetComponent(); if ((bool)component) { modelAnimator = component.modelTransform.GetComponent(); } } private void Update() { Simulate(Time.deltaTime); } public void OnDeathStart() { base.enabled = false; } private static int PickIndex(float angle) { float num = Mathf.Sign(angle); int num2 = Mathf.CeilToInt((angle * num - 22.5f) * (1f / 45f)); return Mathf.Clamp(paramsMidIndex + num2 * (int)num, 0, turnAnimatorParamsSets.Length - 1); } private void Simulate(float deltaTime) { UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(0f, yaw, 0f); if (!hasEffectiveAuthority) { return; } if (driveFromRootRotation) { UnityEngine.Quaternion quaternion2 = rootMotionAccumulator.ExtractRootRotation(); if ((bool)targetTransform) { targetTransform.rotation = quaternion * quaternion2; float y = targetTransform.rotation.eulerAngles.y; yaw = y; float angle = 0f; if (moveVector.sqrMagnitude > 0f) { angle = Util.AngleSigned(UnityEngine.Vector3.ProjectOnPlane(moveVector, UnityEngine.Vector3.up), targetTransform.forward, -UnityEngine.Vector3.up); } int num = PickIndex(angle); if (turnSoundName != null && num != previousParamsIndex) { Util.PlaySound(turnSoundName, base.gameObject); } previousParamsIndex = num; turnAnimatorParamsSets[num].Apply(modelAnimator); } } targetVector = moveVector; targetVector.y = 0f; if (targetVector != UnityEngine.Vector3.zero && deltaTime != 0f) { targetVector.Normalize(); UnityEngine.Quaternion quaternion3 = Util.QuaternionSafeLookRotation(targetVector, UnityEngine.Vector3.up); float y2 = Mathf.SmoothDampAngle(yaw, quaternion3.eulerAngles.y, ref yRotationVelocity, 360f / turnSpeed * 0.25f, float.PositiveInfinity, deltaTime); quaternion = UnityEngine.Quaternion.Euler(0f, y2, 0f); yaw = y2; } if ((bool)targetTransform) { targetTransform.rotation = quaternion; } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class CharacterEmoteDefinitions : MonoBehaviour { [Serializable] public struct EmoteDef { public string name; public string displayName; public EntityStateMachine targetStateMachine; public SerializableEntityStateType state; } public EmoteDef[] emoteDefinitions; public int FindEmoteIndex(string name) { for (int i = 0; i < emoteDefinitions.Length; i++) { if (emoteDefinitions[i].name == name) { return i; } } return -1; } } [RequireComponent(typeof(MinionOwnership))] [RequireComponent(typeof(Inventory))] [DisallowMultipleComponent] public class CharacterMaster : NetworkBehaviour { private static class CommonAssets { public static GameObject goldOnStageStartEffect; public static void Resolve() { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/GoldOnStageStartCoinGain"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { goldOnStageStartEffect = x.Result; }; } } public enum SEEKER_REVIVE_STATUS { UNUSED, USED, BURNED } [Tooltip("This is assigned to the prefab automatically by MasterCatalog at runtime. Do not set this value manually.")] [HideInInspector] [SerializeField] private int _masterIndex; [Tooltip("The prefab of this character's body.")] public GameObject bodyPrefab; [Tooltip("Whether or not to spawn the body at the position of this manager object as soon as Start runs.")] public bool spawnOnStart; [Tooltip("The team of the body.")] [FormerlySerializedAs("teamIndex")] [SerializeField] private TeamIndex _teamIndex; public UnityEvent onBodyDeath; [Tooltip("Whether or not to destroy this master when the body dies.")] public bool destroyOnBodyDeath = true; private static List instancesList; private static ReadOnlyCollection _readOnlyInstancesList; private BaseAI[] aiComponents; private const uint bodyDirtyBit = 1u; private const uint moneyDirtyBit = 2u; private const uint survivalTimeDirtyBit = 4u; private const uint teamDirtyBit = 8u; private const uint loadoutDirtyBit = 16u; private const uint miscFlagsDirtyBit = 32u; private const uint voidCoinsDirtyBit = 64u; private const uint allDirtyBits = 127u; public readonly Loadout loadout = new Loadout(); private NetworkInstanceId _bodyInstanceId = NetworkInstanceId.Invalid; private GameObject resolvedBodyInstance; private bool bodyResolved; private ulong beadExperience; private int numberOfBeadStatsGained; private uint oldBeadLevel = 1u; private uint newBeadLevel; private ulong beadXPNeededForCurrentLevel = 20uL; private uint _money; public uint lssMoneyExp; private uint _voidCoins; public bool isBoss; private Xoroshiro128Plus cloverVoidRng; [NonSerialized] private List deployablesList; public bool preventGameOver = true; private UnityEngine.Vector3 deathAimVector = UnityEngine.Vector3.zero; private bool killedByUnsafeArea; private const float respawnDelayDuration = 2f; private float _internalSurvivalTime; private BodyIndex killerBodyIndex = BodyIndex.None; private bool preventRespawnUntilNextStageServer; private SEEKER_REVIVE_STATUS seekerUsedRevive; [HideInInspector] public GameObject devotionInventoryPrefab; [HideInInspector] public DevotionInventoryController devotionInventoryUpdaterRef; [HideInInspector] public ItemIndex devotionItem; [HideInInspector] public int devotedEvolutionTracker; [HideInInspector] public bool isDevotedMinion; [HideInInspector] public Interactor summonerRef; private bool godMode; private uint lostBodyToDeathFlag = 1u; private uint _miscFlags; private static int kRpcRpcOnPlayerBodyDamaged; private static int kCmdCmdRespawn; private static int kRpcRpcSetSeekerRevive; public MasterCatalog.MasterIndex masterIndex { get { return (MasterCatalog.MasterIndex)_masterIndex; } set { _masterIndex = (int)value; } } public NetworkIdentity networkIdentity { get; private set; } public bool hasEffectiveAuthority { get; private set; } public TeamIndex teamIndex { get { return _teamIndex; } set { if (_teamIndex != value) { _teamIndex = value; if (NetworkServer.active) { SetDirtyBit(8u); } } } } public static ReadOnlyCollection readOnlyInstancesList => _readOnlyInstancesList; public Inventory inventory { get; private set; } public PlayerCharacterMasterController playerCharacterMasterController { get; private set; } public PlayerStatsComponent playerStatsComponent { get; private set; } public MinionOwnership minionOwnership { get; private set; } private NetworkInstanceId bodyInstanceId { get { return _bodyInstanceId; } set { if (!(value == _bodyInstanceId)) { SetDirtyBit(1u); _bodyInstanceId = value; } } } public BodyIndex backupBodyIndex { get; private set; } private GameObject bodyInstanceObject { get { if (!bodyResolved) { resolvedBodyInstance = Util.FindNetworkObject(bodyInstanceId); if ((bool)resolvedBodyInstance) { bodyResolved = true; StoreBackupBodyIndex(); } } return resolvedBodyInstance; } set { NetworkInstanceId invalid = NetworkInstanceId.Invalid; resolvedBodyInstance = null; bodyResolved = true; if ((bool)value) { NetworkIdentity component = value.GetComponent(); if ((bool)component) { invalid = component.netId; resolvedBodyInstance = value; StoreBackupBodyIndex(); } } bodyInstanceId = invalid; } } public uint money { get { return _money; } set { if (value != _money) { SetDirtyBit(2u); _money = value; } } } public uint voidCoins { get { return _voidCoins; } set { if (value != _voidCoins) { SetDirtyBit(64u); _voidCoins = value; } } } public float luck { get; set; } public bool hasBody => bodyInstanceObject; public UnityEngine.Vector3 deathFootPosition { get; private set; } = UnityEngine.Vector3.zero; private float internalSurvivalTime { get { return _internalSurvivalTime; } set { if (value != _internalSurvivalTime) { SetDirtyBit(4u); _internalSurvivalTime = value; } } } public float currentLifeStopwatch { get { if (internalSurvivalTime <= 0f) { return 0f - internalSurvivalTime; } if ((bool)Run.instance) { return Run.instance.GetRunStopwatch() - internalSurvivalTime; } return 0f; } } private uint miscFlags { get { return _miscFlags; } set { if (value != _miscFlags) { _miscFlags = value; if (NetworkServer.active) { SetDirtyBit(32u); } } } } public bool lostBodyToDeath { get { return (miscFlags & lostBodyToDeathFlag) != 0; } private set { if (value) { miscFlags |= lostBodyToDeathFlag; } else { miscFlags &= ~lostBodyToDeathFlag; } } } public static event Action onStartGlobal; public static event Action onCharacterMasterDiscovered; public static event Action onCharacterMasterLost; public event Action onBodyStart; public event Action onBodyDestroyed; public event Action onPlayerBodyDamaged; private void UpdateAuthority() { hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity); } public override void OnStartAuthority() { base.OnStartAuthority(); UpdateAuthority(); } public override void OnStopAuthority() { UpdateAuthority(); base.OnStopAuthority(); } [Server] public void SetLoadoutServer(Loadout newLoadout) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::SetLoadoutServer(RoR2.Loadout)' called on client"); return; } newLoadout.Copy(loadout); SetDirtyBit(16u); } private void StoreBackupBodyIndex() { if ((bool)resolvedBodyInstance) { CharacterBody component = resolvedBodyInstance.GetComponent(); if ((bool)component) { backupBodyIndex = component.bodyIndex; } } } private void OnSyncBodyInstanceId(NetworkInstanceId value) { resolvedBodyInstance = null; bodyResolved = value == NetworkInstanceId.Invalid; _bodyInstanceId = value; } public void TrackBeadExperience(ulong amount) { if (!inventory) { return; } int itemCount = inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp); if (itemCount <= 0) { return; } ulong num = amount * (ulong)(0.25f * (float)(itemCount - 1)); ulong num2 = amount * (ulong)(0.025f * (float)numberOfBeadStatsGained); if (num2 >= num + amount) { num2 = (ulong)(0.8f * (float)(num + amount)); } beadExperience += amount + num - num2; newBeadLevel = TeamManager.instance.FindLevelForBeadExperience(beadExperience); if (beadExperience >= beadXPNeededForCurrentLevel) { CharacterBody body = GetBody(); body.SetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff.buffIndex, (int)oldBeadLevel); float num3 = body.GetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff); float num4 = 1f; switch (body.hullClassification) { case HullClassification.Golem: num4 = 2f; break; case HullClassification.BeetleQueen: num4 = 3f; break; } num4 += num3 / (num3 * 0.25f + 1f); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ExtraStatsOnLevelUpEffect"), new EffectData { origin = body.footPosition, scale = num4 }, transmit: true); Util.PlaySound("Play_item_proc_extraStatsOnLevelUp", body.gameObject); oldBeadLevel = newBeadLevel; beadXPNeededForCurrentLevel = TeamManager.GetExperienceForLevel(oldBeadLevel + 1); } } public void OnBeadReset(bool gainedStats) { if (gainedStats) { numberOfBeadStatsGained += (int)oldBeadLevel; } oldBeadLevel = 1u; beadExperience = 0uL; beadXPNeededForCurrentLevel = 20uL; } [Server] public void GiveExperience(ulong amount) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::GiveExperience(System.UInt64)' called on client"); } else { TeamManager.instance.GiveTeamExperience(teamIndex, amount); } } public void GiveMoney(uint amount) { int itemCount = inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock); int num = TeamManager.LongstandingSolitudesInParty(); if (itemCount > 0) { double num2 = TeamManager.GetExperienceForLevel((uint)GetBody().level + 1); uint difficultyScaledCost = (uint)Run.instance.GetDifficultyScaledCost(25, Run.instance.difficultyCoefficient); lssMoneyExp += amount; if ((float)lssMoneyExp >= (float)(difficultyScaledCost * num) + GetBody().level) { GiveExperience((ulong)(num2 / (double)(10 + (itemCount - 1) * 15))); lssMoneyExp = 0u; } } else { money += amount; StatManager.OnGoldCollected(this, amount); } } public void GiveVoidCoins(uint amount) { voidCoins += amount; } public int GetDeployableSameSlotLimit(DeployableSlot slot) { int result = 0; int num = 1; if (RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.swarmsArtifactDef)) { num = 2; } switch (slot) { case DeployableSlot.EngiMine: result = 4; if ((bool)bodyInstanceObject) { result = bodyInstanceObject.GetComponent().secondary.maxStock; } break; case DeployableSlot.EngiTurret: result = ((inventory.GetItemCount(DLC1Content.Items.EquipmentMagazineVoid) <= 0) ? 2 : 3); break; case DeployableSlot.BeetleGuardAlly: result = inventory.GetItemCount(RoR2Content.Items.BeetleGland) * num; break; case DeployableSlot.EngiBubbleShield: result = 1; break; case DeployableSlot.LoaderPylon: result = 3; break; case DeployableSlot.EngiSpiderMine: result = 4; if ((bool)bodyInstanceObject) { result = bodyInstanceObject.GetComponent().secondary.maxStock; } break; case DeployableSlot.RoboBallMini: result = 3; break; case DeployableSlot.ParentPodAlly: result = inventory.GetItemCount(JunkContent.Items.Incubator) * num; break; case DeployableSlot.ParentAlly: result = inventory.GetItemCount(JunkContent.Items.Incubator) * num; break; case DeployableSlot.PowerWard: result = 1; break; case DeployableSlot.CrippleWard: result = 5; break; case DeployableSlot.DeathProjectile: result = 3; break; case DeployableSlot.RoboBallRedBuddy: case DeployableSlot.RoboBallGreenBuddy: result = num; break; case DeployableSlot.GummyClone: result = 3; break; case DeployableSlot.LunarSunBomb: result = LunarSunBehavior.GetMaxProjectiles(inventory); break; case DeployableSlot.VendingMachine: result = 1; break; case DeployableSlot.VoidMegaCrabItem: result = VoidMegaCrabItemBehavior.GetMaxProjectiles(inventory); break; case DeployableSlot.DroneWeaponsDrone: result = 1; break; case DeployableSlot.MinorConstructOnKill: result = inventory.GetItemCount(DLC1Content.Items.MinorConstructOnKill) * 4; break; case DeployableSlot.CaptainSupplyDrop: result = 2; break; } return result; } [Server] public void AddDeployable(Deployable deployable, DeployableSlot slot) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::AddDeployable(RoR2.Deployable,RoR2.DeployableSlot)' called on client"); return; } if ((bool)deployable.ownerMaster) { UnityEngine.Debug.LogErrorFormat("Attempted to add deployable {0} which already belongs to master {1} to master {2}.", deployable.gameObject, deployable.ownerMaster.gameObject, base.gameObject); } if (deployablesList == null) { deployablesList = new List(); } int num = 0; int deployableSameSlotLimit = GetDeployableSameSlotLimit(slot); for (int num2 = deployablesList.Count - 1; num2 >= 0; num2--) { if (deployablesList[num2].slot == slot) { num++; if (num >= deployableSameSlotLimit) { Deployable deployable2 = deployablesList[num2].deployable; deployablesList.RemoveAt(num2); deployable2.ownerMaster = null; deployable2.onUndeploy.Invoke(); } } } deployablesList.Add(new DeployableInfo { deployable = deployable, slot = slot }); deployable.ownerMaster = this; } [Server] public int GetDeployableCount(DeployableSlot slot) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Int32 RoR2.CharacterMaster::GetDeployableCount(RoR2.DeployableSlot)' called on client"); return 0; } if (deployablesList == null) { return 0; } int num = 0; for (int num2 = deployablesList.Count - 1; num2 >= 0; num2--) { if (deployablesList[num2].slot == slot) { num++; } } return num; } [Server] public bool IsDeployableLimited(DeployableSlot slot) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsDeployableLimited(RoR2.DeployableSlot)' called on client"); return false; } return GetDeployableCount(slot) >= GetDeployableSameSlotLimit(slot); } [Server] public void RemoveDeployable(Deployable deployable) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::RemoveDeployable(RoR2.Deployable)' called on client"); } else { if (deployablesList == null || deployable.ownerMaster != this) { return; } for (int num = deployablesList.Count - 1; num >= 0; num--) { if (deployablesList[num].deployable == deployable) { deployablesList.RemoveAt(num); } } deployable.ownerMaster = null; } } [Server] public bool IsDeployableSlotAvailable(DeployableSlot deployableSlot) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsDeployableSlotAvailable(RoR2.DeployableSlot)' called on client"); return false; } return GetDeployableCount(deployableSlot) < GetDeployableSameSlotLimit(deployableSlot); } [Server] public CharacterBody SpawnBody(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterBody RoR2.CharacterMaster::SpawnBody(UnityEngine.Vector3,UnityEngine.Quaternion)' called on client"); return null; } if ((bool)bodyInstanceObject) { UnityEngine.Debug.LogError("Character cannot have more than one body at this time."); return null; } if (!bodyPrefab) { UnityEngine.Debug.LogErrorFormat("Attempted to spawn body of character master {0} with no body prefab.", base.gameObject); } if (!bodyPrefab.GetComponent()) { UnityEngine.Debug.LogErrorFormat("Attempted to spawn body of character master {0} with a body prefab that has no {1} component attached.", base.gameObject, typeof(CharacterBody).Name); } bool flag = bodyPrefab.GetComponent(); GameObject gameObject = UnityEngine.Object.Instantiate(bodyPrefab, position, flag ? UnityEngine.Quaternion.identity : rotation); CharacterBody component = gameObject.GetComponent(); component.masterObject = base.gameObject; component.teamComponent.teamIndex = teamIndex; component.SetLoadoutServer(loadout); if (flag) { CharacterDirection component2 = gameObject.GetComponent(); float y = rotation.eulerAngles.y; component2.yaw = y; } NetworkConnection clientAuthorityOwner = GetComponent().clientAuthorityOwner; if (clientAuthorityOwner != null) { clientAuthorityOwner.isReady = true; NetworkServer.SpawnWithClientAuthority(gameObject, clientAuthorityOwner); } else { NetworkServer.Spawn(gameObject); } bodyInstanceObject = gameObject; Run.instance.OnServerCharacterBodySpawned(component); return component; } [Server] public void DestroyBody() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::DestroyBody()' called on client"); } else if ((bool)bodyInstanceObject) { CharacterBody body = GetBody(); UnityEngine.Object.Destroy(bodyInstanceObject); OnBodyDestroyed(body); bodyInstanceObject = null; } } public GameObject GetBodyObject() { return bodyInstanceObject; } public CharacterBody GetBody() { GameObject bodyObject = GetBodyObject(); if (!bodyObject) { return null; } return bodyObject.GetComponent(); } private void Awake() { networkIdentity = GetComponent(); inventory = GetComponent(); aiComponents = (NetworkServer.active ? GetComponents() : Array.Empty()); playerCharacterMasterController = GetComponent(); playerStatsComponent = GetComponent(); minionOwnership = GetComponent(); inventory.onInventoryChanged += OnInventoryChanged; inventory.onItemAddedClient += OnItemAddedClient; inventory.onEquipmentExternalRestockServer += OnInventoryEquipmentExternalRestockServer; OnInventoryChanged(); Stage.onServerStageBegin += OnServerStageBegin; } private void OnItemAddedClient(ItemIndex itemIndex) { StartCoroutine(HighlightNewItem(itemIndex)); } private IEnumerator HighlightNewItem(ItemIndex itemIndex) { yield return new WaitForSeconds(0.05f); GameObject bodyObject = GetBodyObject(); if (!bodyObject) { yield break; } ModelLocator component = bodyObject.GetComponent(); if (!component) { yield break; } Transform modelTransform = component.modelTransform; if ((bool)modelTransform) { CharacterModel component2 = modelTransform.GetComponent(); if ((bool)component2) { component2.HighlightItemDisplay(itemIndex); } } } private void Start() { UpdateAuthority(); if (NetworkServer.active && spawnOnStart && !bodyInstanceObject) { SpawnBodyHere(); } CharacterMaster.onStartGlobal?.Invoke(this); } public void SetAIUpdateFrequency(bool updateEveryFrame) { BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].forceUpdateEveryFrame = updateEveryFrame; } } private void OnInventoryChanged() { luck = 0f; luck += inventory.GetItemCount(RoR2Content.Items.Clover); luck -= inventory.GetItemCount(RoR2Content.Items.LunarBadLuck); if (NetworkServer.active && (bool)inventory) { CharacterBody body = GetBody(); if ((bool)body && body.bodyIndex != BodyCatalog.SpecialCases.HereticBody() && inventory.GetItemCount(RoR2Content.Items.LunarPrimaryReplacement.itemIndex) > 0 && inventory.GetItemCount(RoR2Content.Items.LunarSecondaryReplacement.itemIndex) > 0 && inventory.GetItemCount(RoR2Content.Items.LunarSpecialReplacement.itemIndex) > 0 && inventory.GetItemCount(RoR2Content.Items.LunarUtilityReplacement.itemIndex) > 0) { TransformBody("HereticBody"); } if (inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock) > 0 && money != 0) { GiveMoney(money); money = 0u; } } SetUpGummyClone(); } private void OnInventoryEquipmentExternalRestockServer() { CharacterBody body = GetBody(); if ((bool)body) { EffectData effectData = new EffectData(); effectData.origin = body.corePosition; effectData.SetNetworkedObjectReference(body.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/EquipmentRestockEffect"), effectData, transmit: true); } } [Server] public void SpawnBodyHere() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::SpawnBodyHere()' called on client"); } else { SpawnBody(base.transform.position, base.transform.rotation); } } private void OnEnable() { instancesList.Add(this); CharacterMaster.onCharacterMasterDiscovered?.Invoke(this); } private void OnDisable() { try { CharacterMaster.onCharacterMasterLost?.Invoke(this); } catch (Exception message) { UnityEngine.Debug.LogError(message); } instancesList.Remove(this); } private void OnDestroy() { if (isBoss) { isBoss = false; } Stage.onServerStageBegin -= OnServerStageBegin; } public void OnBodyStart(CharacterBody body) { if (NetworkServer.active) { lostBodyToDeath = false; } preventGameOver = true; killerBodyIndex = BodyIndex.None; killedByUnsafeArea = false; body.RecalculateStats(); if (NetworkServer.active) { BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].OnBodyStart(body); } } if ((bool)playerCharacterMasterController) { if ((bool)playerCharacterMasterController.networkUserObject) { _ = playerCharacterMasterController.networkUserObject.GetComponent().isLocalPlayer; } playerCharacterMasterController.OnBodyStart(); } if (inventory.GetItemCount(RoR2Content.Items.Ghost) > 0) { Util.PlaySound("Play_item_proc_ghostOnKill", body.gameObject); } if (NetworkServer.active) { HealthComponent healthComponent = body.healthComponent; if ((bool)healthComponent) { if (teamIndex == TeamIndex.Player && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse1) { healthComponent.Networkhealth = healthComponent.fullHealth * 0.5f; } else { healthComponent.Networkhealth = healthComponent.fullHealth; } } UpdateBodyGodMode(); StartLifeStopwatch(); } SetUpGummyClone(); this.onBodyStart?.Invoke(body); if (inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp) > 0) { uint num = TeamManager.instance.FindLevelForBeadExperience(beadExperience); body.SetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff.buffIndex, (int)(num - 1)); } } [Server] public bool IsExtraLifePendingServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsExtraLifePendingServer()' called on client"); return false; } if (!IsInvoking("RespawnExtraLife") && !IsInvoking("RespawnExtraLifeVoid") && !IsInvoking("RespawnExtraLifeShrine")) { return IsInvoking("RespawnExtraLifeHealAndRevive"); } return true; } [Server] public bool IsDeadAndOutOfLivesServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsDeadAndOutOfLivesServer()' called on client"); return false; } CharacterBody body = GetBody(); if (body != null) { if (body.healthComponent.alive) { return false; } if (body.HasBuff(DLC2Content.Buffs.ExtraLifeBuff)) { return false; } bool flag = false; if (body.equipmentSlot != null && body.equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex) { flag = true; } if (flag) { return false; } } return inventory.GetItemCount(RoR2Content.Items.ExtraLife) <= 0 && inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) <= 0 && !IsExtraLifePendingServer(); } public void OnBodyDeath(CharacterBody body) { if (NetworkServer.active) { lostBodyToDeath = true; deathFootPosition = body.footPosition; BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].OnBodyDeath(body); } if ((bool)playerCharacterMasterController) { playerCharacterMasterController.OnBodyDeath(); } if (body.HasBuff(DLC2Content.Buffs.ExtraLifeBuff)) { body.RemoveBuff(DLC2Content.Buffs.ExtraLifeBuff); Invoke("RespawnExtraLifeShrine", 2f); Invoke("PlayExtraLifeSFX", 1f); } else { bool flag = false; if ((bool)body.equipmentSlot && body.equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex) { flag = true; } if (flag) { CharacterMasterNotificationQueue.SendTransformNotification(this, inventory.currentEquipmentIndex, DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default); inventory.SetEquipmentIndex(DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex); Invoke("RespawnExtraLifeHealAndRevive", 2f); Invoke("PlayExtraLifeSFX", 1f); } else if (inventory.GetItemCount(RoR2Content.Items.ExtraLife) > 0) { inventory.RemoveItem(RoR2Content.Items.ExtraLife); Invoke("RespawnExtraLife", 2f); Invoke("PlayExtraLifeSFX", 1f); } else if (inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) > 0) { inventory.RemoveItem(DLC1Content.Items.ExtraLifeVoid); Invoke("RespawnExtraLifeVoid", 2f); Invoke("PlayExtraLifeVoidSFX", 1f); } else { if (destroyOnBodyDeath) { UnityEngine.Object.Destroy(base.gameObject, 1f); } preventGameOver = false; preventRespawnUntilNextStageServer = true; } } if (TryGetComponent(out var component)) { component.OnDevotedBodyDead(); } if ((bool)devotionInventoryPrefab) { devotionInventoryPrefab.GetComponent().RemoveItem(devotionItem, devotedEvolutionTracker + 1); devotionInventoryUpdaterRef.DropScrapOnDeath(devotionItem, body); devotionInventoryUpdaterRef.UpdateAllMinions(); } ResetLifeStopwatch(); } onBodyDeath?.Invoke(); } public void TrueKill() { TrueKill(null, null, DamageType.Generic); } public void TrueKill(GameObject killerOverride = null, GameObject inflictorOverride = null, DamageTypeCombo damageTypeOverride = default(DamageTypeCombo)) { int itemCount = inventory.GetItemCount(RoR2Content.Items.ExtraLife); if (itemCount > 0) { inventory.ResetItem(RoR2Content.Items.ExtraLife); inventory.GiveItem(RoR2Content.Items.ExtraLifeConsumed, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, RoR2Content.Items.ExtraLife.itemIndex, RoR2Content.Items.ExtraLifeConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); } if (inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) > 0) { inventory.ResetItem(DLC1Content.Items.ExtraLifeVoid); inventory.GiveItem(DLC1Content.Items.ExtraLifeVoidConsumed, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC1Content.Items.ExtraLifeVoid.itemIndex, DLC1Content.Items.ExtraLifeVoidConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); } if (GetBody().HasBuff(DLC2Content.Buffs.ExtraLifeBuff)) { GetBody().RemoveBuff(DLC2Content.Buffs.ExtraLifeBuff); } bool flag = false; if ((bool)GetBody().equipmentSlot && GetBody().equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex) { flag = true; } if (flag) { CharacterMasterNotificationQueue.SendTransformNotification(this, inventory.currentEquipmentIndex, DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default); inventory.SetEquipmentIndex(DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex); } CancelInvoke("RespawnExtraLife"); CancelInvoke("PlayExtraLifeSFX"); CancelInvoke("RespawnExtraLifeVoid"); CancelInvoke("PlayExtraLifeVoidSFX"); CancelInvoke("RespawnExtraLifeShrine"); CharacterBody body = GetBody(); if ((bool)body) { body.healthComponent.Suicide(killerOverride, inflictorOverride, damageTypeOverride); } } private void PlayExtraLifeSFX() { GameObject gameObject = bodyInstanceObject; if ((bool)gameObject) { Util.PlaySound("Play_item_proc_extraLife", gameObject); } } private void PlayExtraLifeVoidSFX() { GameObject gameObject = bodyInstanceObject; if ((bool)gameObject) { Util.PlaySound("Play_item_void_extraLife", gameObject); } } public void RespawnExtraLife() { inventory.GiveItem(RoR2Content.Items.ExtraLifeConsumed); CharacterMasterNotificationQueue.SendTransformNotification(this, RoR2Content.Items.ExtraLife.itemIndex, RoR2Content.Items.ExtraLifeConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); UnityEngine.Vector3 vector = deathFootPosition; if (killedByUnsafeArea) { vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent(), RoR2Application.rng) ?? deathFootPosition; } Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true); GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f); if (NetworkServer.active) { inventory.SetEquipmentDisabled(_active: false); } GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Effects/HippoRezEffect"); if ((bool)bodyInstanceObject) { EntityStateMachine[] components = bodyInstanceObject.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } if ((bool)gameObject) { EffectManager.SpawnEffect(gameObject, new EffectData { origin = vector, rotation = bodyInstanceObject.transform.rotation }, transmit: true); } } } public void RespawnExtraLifeVoid() { inventory.GiveItem(DLC1Content.Items.ExtraLifeVoidConsumed); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC1Content.Items.ExtraLifeVoid.itemIndex, DLC1Content.Items.ExtraLifeVoidConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); UnityEngine.Vector3 vector = deathFootPosition; if (killedByUnsafeArea) { vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent(), RoR2Application.rng) ?? deathFootPosition; } Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true); GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f); if (NetworkServer.active) { inventory.SetEquipmentDisabled(_active: false); } if ((bool)bodyInstanceObject) { EntityStateMachine[] components = bodyInstanceObject.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } if ((bool)ExtraLifeVoidManager.rezEffectPrefab) { EffectManager.SpawnEffect(ExtraLifeVoidManager.rezEffectPrefab, new EffectData { origin = vector, rotation = bodyInstanceObject.transform.rotation }, transmit: true); } } foreach (ContagiousItemManager.TransformationInfo transformationInfo in ContagiousItemManager.transformationInfos) { ContagiousItemManager.TryForceReplacement(inventory, transformationInfo.originalItem); } } public void RespawnExtraLifeShrine() { UnityEngine.Vector3 vector = deathFootPosition; if (killedByUnsafeArea) { vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent(), RoR2Application.rng) ?? deathFootPosition; } Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true); GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f); GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Effects/fxHealAndReviveGold"); if ((bool)bodyInstanceObject) { EntityStateMachine[] components = bodyInstanceObject.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } if ((bool)gameObject) { EffectManager.SpawnEffect(gameObject, new EffectData { origin = vector, rotation = bodyInstanceObject.transform.rotation }, transmit: true); Util.PlaySound("Play_item_use_healAndRevive_activate", base.gameObject); } } } public void RespawnExtraLifeHealAndRevive() { UnityEngine.Vector3 vector = deathFootPosition; if (killedByUnsafeArea) { vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent(), RoR2Application.rng) ?? deathFootPosition; } Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true); GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f); GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Effects/fxHealAndReviveGold"); if ((bool)bodyInstanceObject) { EntityStateMachine[] components = bodyInstanceObject.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } if ((bool)gameObject) { EffectManager.SpawnEffect(gameObject, new EffectData { origin = vector, rotation = bodyInstanceObject.transform.rotation }, transmit: true); Util.PlaySound("Play_item_use_healAndRevive_activate", base.gameObject); } } } public void OnBodyDamaged(DamageReport damageReport) { BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].OnBodyDamaged(damageReport); } if ((bool)playerCharacterMasterController) { HandleOnPlayerBodyDamaged(); CallRpcOnPlayerBodyDamaged(); } } [ClientRpc] private void RpcOnPlayerBodyDamaged() { HandleOnPlayerBodyDamaged(); } private void HandleOnPlayerBodyDamaged() { this.onPlayerBodyDamaged?.Invoke(playerCharacterMasterController); } public void OnBodyDestroyed(CharacterBody characterBody) { if ((object)characterBody != GetBody()) { return; } if (NetworkServer.active) { BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].OnBodyDestroyed(characterBody); } PauseLifeStopwatch(); } this.onBodyDestroyed?.Invoke(characterBody); } [Server] private void StartLifeStopwatch() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::StartLifeStopwatch()' called on client"); } else if (!(internalSurvivalTime > 0f)) { internalSurvivalTime = Run.instance.GetRunStopwatch() - currentLifeStopwatch; } } [Server] private void PauseLifeStopwatch() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::PauseLifeStopwatch()' called on client"); } else if (!(internalSurvivalTime <= 0f)) { internalSurvivalTime = 0f - currentLifeStopwatch; } } [Server] private void ResetLifeStopwatch() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::ResetLifeStopwatch()' called on client"); } else { internalSurvivalTime = 0f; } } [Server] public BodyIndex GetKillerBodyIndex() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'RoR2.BodyIndex RoR2.CharacterMaster::GetKillerBodyIndex()' called on client"); return default(BodyIndex); } return killerBodyIndex; } [InitDuringStartup] private static void Init() { GlobalEventManager.onCharacterDeathGlobal += delegate(DamageReport damageReport) { CharacterMaster victimMaster = damageReport.victimMaster; if ((bool)victimMaster) { victimMaster.killerBodyIndex = BodyCatalog.FindBodyIndex(damageReport.damageInfo.attacker); victimMaster.killedByUnsafeArea = (bool)damageReport.damageInfo.inflictor && (bool)damageReport.damageInfo.inflictor.GetComponent(); } }; Stage.onServerStageBegin += delegate { foreach (CharacterMaster instances in instancesList) { instances.preventRespawnUntilNextStageServer = false; } }; CommonAssets.Resolve(); } [Command] public void CmdRespawn(string bodyName) { if (preventRespawnUntilNextStageServer) { return; } if (!string.IsNullOrEmpty(bodyName)) { bodyPrefab = BodyCatalog.FindBodyPrefab(bodyName); if (!bodyPrefab) { UnityEngine.Debug.LogError("CmdRespawn failed to find bodyPrefab for name '" + bodyName + "'."); } } if ((bool)Stage.instance) { Stage.instance.RespawnCharacter(this); } } [Server] public void TransformBody(string bodyName) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::TransformBody(System.String)' called on client"); } else if (!string.IsNullOrEmpty(bodyName)) { bodyPrefab = BodyCatalog.FindBodyPrefab(bodyName); if (bodyPrefab != null) { Transform component = bodyInstanceObject.GetComponent(); UnityEngine.Vector3 position = component.position; UnityEngine.Quaternion rotation = component.rotation; DestroyBody(); CharacterBody component2 = bodyPrefab.GetComponent(); if ((bool)component2) { position = CalculateSafeGroundPosition(position, component2); SpawnBody(position, rotation).GetComponent()?.PrepareTransformation(); } else { UnityEngine.Debug.LogErrorFormat("Trying to respawn as object {0} who has no Character Body!", bodyPrefab); } } else { UnityEngine.Debug.LogError("Can't TransformBody because there's no prefab for body named '" + bodyName + "'"); } } else { UnityEngine.Debug.LogError("Can't TransformBody with null or empty body name."); } } [Server] private void OnServerStageBegin(Stage stage) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::OnServerStageBegin(RoR2.Stage)' called on client"); return; } TryCloverVoidUpgrades(); TryRegenerateScrap(); TrySaleStar(); } [ClientRpc] public void RpcSetSeekerRevive(SEEKER_REVIVE_STATUS s) { seekerUsedRevive = s; } public SEEKER_REVIVE_STATUS getSeekerUsedRevive() { return seekerUsedRevive; } private void TryRegenerateScrap() { int itemCount = inventory.GetItemCount(DLC1Content.Items.RegeneratingScrapConsumed); if (itemCount > 0) { inventory.RemoveItem(DLC1Content.Items.RegeneratingScrapConsumed, itemCount); inventory.GiveItem(DLC1Content.Items.RegeneratingScrap, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC1Content.Items.RegeneratingScrapConsumed.itemIndex, DLC1Content.Items.RegeneratingScrap.itemIndex, CharacterMasterNotificationQueue.TransformationType.RegeneratingScrapRegen); } } private void TrySaleStar() { int itemCount = inventory.GetItemCount(DLC2Content.Items.LowerPricedChestsConsumed); if (itemCount > 0) { inventory.RemoveItem(DLC2Content.Items.LowerPricedChestsConsumed, itemCount); inventory.GiveItem(DLC2Content.Items.LowerPricedChests, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC2Content.Items.LowerPricedChestsConsumed.itemIndex, DLC2Content.Items.LowerPricedChests.itemIndex, CharacterMasterNotificationQueue.TransformationType.SaleStarRegen); } } private void TryTeleportOnLowHealthRegen() { int itemCount = inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealthConsumed); if (itemCount > 0) { inventory.RemoveItem(DLC2Content.Items.TeleportOnLowHealthConsumed, itemCount); inventory.GiveItem(DLC2Content.Items.TeleportOnLowHealth, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC2Content.Items.TeleportOnLowHealthConsumed.itemIndex, DLC2Content.Items.TeleportOnLowHealth.itemIndex, CharacterMasterNotificationQueue.TransformationType.TeleportOnLowHealthRegen); } } [Server] public void TrackDevotionItem(ItemIndex itemIndex, Interactor summoner, GameObject devotedInventoryRef, DevotionInventoryController devotionInventoryUpdater) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::TrackDevotionItem(RoR2.ItemIndex,RoR2.Interactor,UnityEngine.GameObject,RoR2.DevotionInventoryController)' called on client"); return; } _ = summoner == null; devotionItem = itemIndex; summonerRef = summoner; devotionInventoryPrefab = devotedInventoryRef; isDevotedMinion = true; devotionInventoryUpdaterRef = devotionInventoryUpdater; } [Server] private void TryCloverVoidUpgrades() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::TryCloverVoidUpgrades()' called on client"); return; } if (cloverVoidRng == null) { cloverVoidRng = new Xoroshiro128Plus(Run.instance.seed); } int itemCount = inventory.GetItemCount(DLC1Content.Items.CloverVoid); List list = new List(Run.instance.availableTier2DropList); List list2 = new List(Run.instance.availableTier3DropList); List list3 = new List(inventory.itemAcquisitionOrder); Util.ShuffleList(list3, cloverVoidRng); int num = itemCount * 3; int num2 = 0; int num3 = 0; while (num2 < num && num3 < list3.Count) { ItemDef startingItemDef = ItemCatalog.GetItemDef(list3[num3]); ItemDef itemDef = null; List list4 = null; switch (startingItemDef.tier) { case ItemTier.Tier1: list4 = list; break; case ItemTier.Tier2: list4 = list2; break; } if (list4 != null && list4.Count > 0) { Util.ShuffleList(list4, cloverVoidRng); list4.Sort(CompareTags); itemDef = ItemCatalog.GetItemDef(list4[0].itemIndex); } if (itemDef != null) { if (inventory.GetItemCount(itemDef.itemIndex) == 0) { list3.Add(itemDef.itemIndex); } num2++; int itemCount2 = inventory.GetItemCount(startingItemDef.itemIndex); inventory.RemoveItem(startingItemDef.itemIndex, itemCount2); inventory.GiveItem(itemDef.itemIndex, itemCount2); CharacterMasterNotificationQueue.SendTransformNotification(this, startingItemDef.itemIndex, itemDef.itemIndex, CharacterMasterNotificationQueue.TransformationType.CloverVoid); } num3++; int CompareTags(PickupIndex lhs, PickupIndex rhs) { int num4 = 0; int num5 = 0; ItemDef itemDef2 = ItemCatalog.GetItemDef(lhs.itemIndex); ItemDef itemDef3 = ItemCatalog.GetItemDef(rhs.itemIndex); if (startingItemDef.ContainsTag(ItemTag.Damage)) { if (itemDef2.ContainsTag(ItemTag.Damage)) { num4 = 1; } if (itemDef3.ContainsTag(ItemTag.Damage)) { num5 = 1; } } if (startingItemDef.ContainsTag(ItemTag.Healing)) { if (itemDef2.ContainsTag(ItemTag.Healing)) { num4 = 1; } if (itemDef3.ContainsTag(ItemTag.Healing)) { num5 = 1; } } if (startingItemDef.ContainsTag(ItemTag.Utility)) { if (itemDef2.ContainsTag(ItemTag.Utility)) { num4 = 1; } if (itemDef3.ContainsTag(ItemTag.Utility)) { num5 = 1; } } return num5 - num4; } } if (num2 > 0) { GameObject gameObject = bodyInstanceObject; if ((bool)gameObject) { Util.PlaySound("Play_item_proc_extraLife", gameObject); } } } private static GameObject PickRandomSurvivorBodyPrefab(Xoroshiro128Plus rng, NetworkUser networkUser, bool allowHidden) { SurvivorDef[] array = SurvivorCatalog.allSurvivorDefs.Where(SurvivorIsUnlockedAndAvailable).ToArray(); return rng.NextElementUniform(array).bodyPrefab; bool SurvivorIsUnlockedAndAvailable(SurvivorDef survivorDef) { if (allowHidden || !survivorDef.hidden) { if (!survivorDef.CheckRequiredExpansionEnabled(networkUser)) { return false; } UnlockableDef unlockableDef = survivorDef.unlockableDef; if ((object)unlockableDef != null) { return networkUser.unlockables.Contains(unlockableDef); } return true; } return false; } } [Server] public CharacterBody Respawn(UnityEngine.Vector3 footPosition, UnityEngine.Quaternion rotation, bool wasRevivedMidStage = false) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterBody RoR2.CharacterMaster::Respawn(UnityEngine.Vector3,UnityEngine.Quaternion,System.Boolean)' called on client"); return null; } if (!wasRevivedMidStage) { CallRpcSetSeekerRevive(SEEKER_REVIVE_STATUS.UNUSED); } else if (seekerUsedRevive == SEEKER_REVIVE_STATUS.USED) { CallRpcSetSeekerRevive(SEEKER_REVIVE_STATUS.BURNED); } DestroyBody(); if ((bool)playerCharacterMasterController && RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.randomSurvivorOnRespawnArtifactDef)) { bodyPrefab = PickRandomSurvivorBodyPrefab(Run.instance.randomSurvivorOnRespawnRng, playerCharacterMasterController.networkUser, allowHidden: false); } if ((bool)bodyPrefab) { CharacterBody component = bodyPrefab.GetComponent(); if ((bool)component) { UnityEngine.Vector3 position = footPosition; if (true) { position = CalculateSafeGroundPosition(footPosition, component); } return SpawnBody(position, rotation); } UnityEngine.Debug.LogErrorFormat("Trying to respawn as object {0} who has no Character Body!", bodyPrefab); } else { UnityEngine.Debug.LogErrorFormat("CharacterMaster.Respawn failed. {0} does not have a valid body prefab assigned.", base.gameObject.name); } return null; } private UnityEngine.Vector3 CalculateSafeGroundPosition(UnityEngine.Vector3 desiredFootPos, CharacterBody body) { if ((bool)body) { UnityEngine.Vector3 result = desiredFootPos; RaycastHit hitInfo = default(RaycastHit); Ray ray = new Ray(desiredFootPos + UnityEngine.Vector3.up * 2f, UnityEngine.Vector3.down); float maxDistance = 4f; if (Physics.SphereCast(ray, body.radius, out hitInfo, maxDistance, LayerIndex.world.mask)) { result.y = ray.origin.y - hitInfo.distance; } float bodyPrefabFootOffset = Util.GetBodyPrefabFootOffset(bodyPrefab); result.y += bodyPrefabFootOffset; return result; } UnityEngine.Debug.LogError("Can't calculate safe ground position if the CharacterBody is null"); return desiredFootPos; } private void SetUpGummyClone() { if (!NetworkServer.active || !inventory || inventory.GetItemCount(DLC1Content.Items.GummyCloneIdentifier.itemIndex) <= 0) { return; } if (!base.gameObject.GetComponent()) { base.gameObject.AddComponent().lifeTimer = 30f; } CharacterBody body = GetBody(); if ((bool)body) { CharacterDeathBehavior component = body.GetComponent(); if ((bool)component && component.deathState.stateType != typeof(GummyCloneDeathState)) { component.deathState = new SerializableEntityStateType(typeof(GummyCloneDeathState)); } body.portraitIcon = LegacyResourcesAPI.Load("Textures/BodyIcons/texGummyCloneBody"); } } public void SetMasterBodyDirtyBit() { SetDirtyBit(1u); } private void ToggleGod() { godMode = !godMode; UpdateBodyGodMode(); } private void UpdateBodyGodMode() { if ((bool)bodyInstanceObject) { HealthComponent component = bodyInstanceObject.GetComponent(); if ((bool)component) { component.godMode = godMode; } } } public override bool OnSerialize(NetworkWriter writer, bool initialState) { uint num = base.syncVarDirtyBits; if (initialState) { num = 127u; } bool num2 = (num & 1) != 0; bool flag = (num & 2) != 0; bool flag2 = (num & 0x40) != 0; bool flag3 = (num & 4) != 0; bool flag4 = (num & 8) != 0; bool flag5 = (num & 0x10) != 0; bool flag6 = (num & 0x20) != 0; writer.Write((byte)num); if (num2) { writer.Write(_bodyInstanceId); } if (flag) { writer.WritePackedUInt32(_money); } if (flag2) { writer.WritePackedUInt32(_voidCoins); } if (flag3) { writer.Write(_internalSurvivalTime); } if (flag4) { writer.Write(teamIndex); } if (flag5) { loadout.Serialize(writer); } if (flag6) { writer.WritePackedUInt32(miscFlags); } return num != 0; } public override void OnDeserialize(NetworkReader reader, bool initialState) { byte num = reader.ReadByte(); bool flag = (num & 1) != 0; bool flag2 = (num & 2) != 0; bool flag3 = (num & 0x40) != 0; bool flag4 = (num & 4) != 0; bool flag5 = (num & 8) != 0; bool flag6 = (num & 0x10) != 0; bool num2 = (num & 0x20) != 0; if (flag) { NetworkInstanceId value = reader.ReadNetworkId(); OnSyncBodyInstanceId(value); } if (flag2) { _money = reader.ReadPackedUInt32(); } if (flag3) { _voidCoins = reader.ReadPackedUInt32(); } if (flag4) { _internalSurvivalTime = reader.ReadSingle(); } if (flag5) { teamIndex = reader.ReadTeamIndex(); } if (flag6) { loadout.Deserialize(reader); } if (num2) { miscFlags = reader.ReadPackedUInt32(); } } static CharacterMaster() { instancesList = new List(); _readOnlyInstancesList = new ReadOnlyCollection(instancesList); kCmdCmdRespawn = 1097984413; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterMaster), kCmdCmdRespawn, InvokeCmdCmdRespawn); kRpcRpcOnPlayerBodyDamaged = -1070481806; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMaster), kRpcRpcOnPlayerBodyDamaged, InvokeRpcRpcOnPlayerBodyDamaged); kRpcRpcSetSeekerRevive = 458435899; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMaster), kRpcRpcSetSeekerRevive, InvokeRpcRpcSetSeekerRevive); NetworkCRC.RegisterBehaviour("CharacterMaster", 0); } private void UNetVersion() { } protected static void InvokeCmdCmdRespawn(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdRespawn called on client."); } else { ((CharacterMaster)obj).CmdRespawn(reader.ReadString()); } } public void CallCmdRespawn(string bodyName) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdRespawn called on server."); return; } if (base.isServer) { CmdRespawn(bodyName); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdRespawn); networkWriter.Write(GetComponent().netId); networkWriter.Write(bodyName); SendCommandInternal(networkWriter, 0, "CmdRespawn"); } protected static void InvokeRpcRpcOnPlayerBodyDamaged(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcOnPlayerBodyDamaged called on server."); } else { ((CharacterMaster)obj).RpcOnPlayerBodyDamaged(); } } protected static void InvokeRpcRpcSetSeekerRevive(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcSetSeekerRevive called on server."); } else { ((CharacterMaster)obj).RpcSetSeekerRevive((SEEKER_REVIVE_STATUS)reader.ReadInt32()); } } public void CallRpcOnPlayerBodyDamaged() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcOnPlayerBodyDamaged called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnPlayerBodyDamaged); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcOnPlayerBodyDamaged"); } public void CallRpcSetSeekerRevive(SEEKER_REVIVE_STATUS s) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcSetSeekerRevive called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcSetSeekerRevive); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)s); SendRPCInternal(networkWriter, 0, "RpcSetSeekerRevive"); } public override void PreStartClient() { } } [Serializable] public class CharacterMasterUnityEvent : UnityEvent { } public class CharacterMasterNotificationQueue : MonoBehaviour { public enum TransformationType { Default, ContagiousVoid, CloverVoid, Suppressed, LunarSun, RegeneratingScrapRegen, SaleStarRegen, TeleportOnLowHealthRegen } public class TransformationInfo { public readonly TransformationType transformationType; public readonly object previousData; public static bool operator ==(TransformationInfo lhs, TransformationInfo rhs) { bool flag = (object)lhs == null; bool flag2 = (object)rhs == null; if (!(flag && flag2)) { if (!flag && !flag2 && lhs.previousData == rhs.previousData) { return lhs.transformationType == rhs.transformationType; } return false; } return true; } public static bool operator !=(TransformationInfo lhs, TransformationInfo rhs) { return !(lhs == rhs); } public TransformationInfo(TransformationType transformationType, object previousData) { this.transformationType = transformationType; this.previousData = previousData; } } public class NotificationInfo { public readonly object data; public readonly TransformationInfo transformation; public static bool operator ==(NotificationInfo lhs, NotificationInfo rhs) { bool flag = (object)lhs == null; bool flag2 = (object)rhs == null; if (!(flag && flag2)) { if (!flag && !flag2 && lhs.data == rhs.data) { return lhs.transformation == rhs.transformation; } return false; } return true; } public static bool operator !=(NotificationInfo lhs, NotificationInfo rhs) { return !(lhs == rhs); } public NotificationInfo(object data, TransformationInfo transformation = null) { this.data = data; this.transformation = transformation; } } private class TimedNotificationInfo { public NotificationInfo notification; public float startTime; public float duration; } private class TransformNotificationMessage : MessageBase { public GameObject masterGameObject; public PickupIndex oldIndex; public PickupIndex newIndex; public TransformationType transformationType; public override void Serialize(NetworkWriter writer) { writer.Write(masterGameObject); GeneratedNetworkCode._WritePickupIndex_None(writer, oldIndex); GeneratedNetworkCode._WritePickupIndex_None(writer, newIndex); writer.Write((int)transformationType); } public override void Deserialize(NetworkReader reader) { masterGameObject = reader.ReadGameObject(); oldIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader); newIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader); transformationType = (TransformationType)reader.ReadInt32(); } } public const float firstNotificationLengthSeconds = 6f; public const float repeatNotificationLengthSeconds = 6f; private static readonly TransformNotificationMessage transformNotificationMessageInstance = new TransformNotificationMessage(); private CharacterMaster master; private List notifications = new List(); public event Action onCurrentNotificationChanged; public static void PushPickupNotification(CharacterMaster characterMaster, PickupIndex pickupIndex) { if (!characterMaster.hasAuthority) { UnityEngine.Debug.LogError("Can't PushPickupNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local."); return; } PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); ItemIndex itemIndex = pickupDef.itemIndex; if (itemIndex != ItemIndex.None) { PushItemNotification(characterMaster, itemIndex); return; } EquipmentIndex equipmentIndex = pickupDef.equipmentIndex; if (equipmentIndex != EquipmentIndex.None) { PushEquipmentNotification(characterMaster, equipmentIndex); } } public static void PushItemNotification(CharacterMaster characterMaster, ItemIndex itemIndex) { if (!characterMaster.hasAuthority) { UnityEngine.Debug.LogError("Can't PushItemNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local."); return; } CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster); if (!notificationQueueForMaster || itemIndex == ItemIndex.None) { return; } ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); if (!(itemDef == null) && !itemDef.hidden) { float duration = 6f; if (characterMaster.inventory.GetItemCount(itemIndex) > 1) { duration = 6f; } notificationQueueForMaster.PushNotification(new NotificationInfo(ItemCatalog.GetItemDef(itemIndex)), duration); } } public static void PushEquipmentNotification(CharacterMaster characterMaster, EquipmentIndex equipmentIndex) { if (!characterMaster.hasAuthority) { UnityEngine.Debug.LogError("Can't PushEquipmentNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local."); return; } CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster); if ((bool)notificationQueueForMaster && equipmentIndex != EquipmentIndex.None) { notificationQueueForMaster.PushNotification(new NotificationInfo(EquipmentCatalog.GetEquipmentDef(equipmentIndex)), 6f); } } public static void PushArtifactNotification(CharacterMaster characterMaster, ArtifactDef artifactDef) { if (!characterMaster.hasAuthority) { UnityEngine.Debug.LogError("Can't PushArtifactNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local."); return; } CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster); if ((bool)notificationQueueForMaster) { notificationQueueForMaster.PushNotification(new NotificationInfo(artifactDef), 6f); } } public static void PushEquipmentTransformNotification(CharacterMaster characterMaster, EquipmentIndex oldIndex, EquipmentIndex newIndex, TransformationType transformationType) { if (!characterMaster.hasAuthority) { UnityEngine.Debug.LogError("Can't PushEquipmentTransformNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local."); return; } CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster); if ((bool)notificationQueueForMaster && oldIndex != EquipmentIndex.None && newIndex != EquipmentIndex.None) { object equipmentDef = EquipmentCatalog.GetEquipmentDef(oldIndex); TransformationInfo transformation = new TransformationInfo(transformationType, equipmentDef); NotificationInfo info = new NotificationInfo(EquipmentCatalog.GetEquipmentDef(newIndex), transformation); notificationQueueForMaster.PushNotification(info, 6f); } } public static void PushItemTransformNotification(CharacterMaster characterMaster, ItemIndex oldIndex, ItemIndex newIndex, TransformationType transformationType) { if (!characterMaster.hasAuthority) { UnityEngine.Debug.LogError("Can't PushItemTransformNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local."); return; } CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster); if ((bool)notificationQueueForMaster && oldIndex != ItemIndex.None && newIndex != ItemIndex.None) { object itemDef = ItemCatalog.GetItemDef(oldIndex); TransformationInfo transformation = new TransformationInfo(transformationType, itemDef); NotificationInfo info = new NotificationInfo(ItemCatalog.GetItemDef(newIndex), transformation); notificationQueueForMaster.PushNotification(info, 6f); } } public static CharacterMasterNotificationQueue GetNotificationQueueForMaster(CharacterMaster master) { if (master != null) { CharacterMasterNotificationQueue characterMasterNotificationQueue = master.GetComponent(); if (!characterMasterNotificationQueue) { characterMasterNotificationQueue = master.gameObject.AddComponent(); characterMasterNotificationQueue.master = master; } return characterMasterNotificationQueue; } return null; } public static void SendTransformNotification(CharacterMaster characterMaster, ItemIndex oldIndex, ItemIndex newIndex, TransformationType transformationType) { SendTransformNotificationInternal(characterMaster, PickupCatalog.FindPickupIndex(oldIndex), PickupCatalog.FindPickupIndex(newIndex), transformationType); } public static void SendTransformNotification(CharacterMaster characterMaster, EquipmentIndex oldIndex, EquipmentIndex newIndex, TransformationType transformationType) { SendTransformNotificationInternal(characterMaster, PickupCatalog.FindPickupIndex(oldIndex), PickupCatalog.FindPickupIndex(newIndex), transformationType); } private static void SendTransformNotificationInternal(CharacterMaster characterMaster, PickupIndex oldIndex, PickupIndex newIndex, TransformationType transformationType) { if (NetworkServer.active) { TransformNotificationMessage msg = new TransformNotificationMessage { masterGameObject = characterMaster.gameObject, oldIndex = oldIndex, newIndex = newIndex, transformationType = transformationType }; NetworkServer.SendByChannelToAll(78, msg, QosChannelIndex.chat.intVal); } else { UnityEngine.Debug.LogError("Can't SendTransformNotification if this isn't the server."); } } [NetworkMessageHandler(msgType = 78, client = true)] private static void HandleTransformNotification(NetworkMessage netMsg) { netMsg.ReadMessage(transformNotificationMessageInstance); if ((bool)transformNotificationMessageInstance.masterGameObject) { CharacterMaster component = transformNotificationMessageInstance.masterGameObject.GetComponent(); if ((bool)component && component.hasAuthority) { PickupDef pickupDef = PickupCatalog.GetPickupDef(transformNotificationMessageInstance.oldIndex); PickupDef pickupDef2 = PickupCatalog.GetPickupDef(transformNotificationMessageInstance.newIndex); if (pickupDef != null && pickupDef2 != null) { if (pickupDef2.equipmentIndex != EquipmentIndex.None) { PushEquipmentTransformNotification(component, pickupDef.equipmentIndex, pickupDef2.equipmentIndex, transformNotificationMessageInstance.transformationType); } else if (pickupDef2.itemIndex != ItemIndex.None) { PushItemTransformNotification(component, pickupDef.itemIndex, pickupDef2.itemIndex, transformNotificationMessageInstance.transformationType); } } else { UnityEngine.Debug.LogError($"Can't handle transform notification for pickup indices: {transformNotificationMessageInstance.oldIndex} -> {transformNotificationMessageInstance.newIndex}"); } } } transformNotificationMessageInstance.masterGameObject = null; } public void FixedUpdate() { if (GetCurrentNotificationT() > 1f) { notifications.RemoveAt(0); if (notifications.Count > 0) { notifications[0].startTime = Run.instance.fixedTime; } this.onCurrentNotificationChanged?.Invoke(this); } } public NotificationInfo GetCurrentNotification() { if (notifications.Count > 0) { return notifications[0].notification; } return null; } private void PushNotification(NotificationInfo info, float duration) { if (notifications.Count == 0 || notifications[notifications.Count - 1].notification != info) { notifications.Add(new TimedNotificationInfo { notification = info, startTime = Run.instance.fixedTime, duration = duration }); if (notifications.Count == 1) { this.onCurrentNotificationChanged?.Invoke(this); } } } public float GetCurrentNotificationT() { if (notifications.Count > 0) { TimedNotificationInfo timedNotificationInfo = notifications[0]; return (Run.instance.fixedTime - timedNotificationInfo.startTime) / timedNotificationInfo.duration; } return 0f; } } public class CharacterModel : MonoBehaviour { [Serializable] public struct RendererInfo : IEquatable { [PrefabReference] public Renderer renderer; public Material defaultMaterial; public ShadowCastingMode defaultShadowCastingMode; public bool ignoreOverlays; public bool hideOnDeath; public bool Equals(RendererInfo other) { if ((object)renderer == other.renderer && (object)defaultMaterial == other.defaultMaterial && object.Equals(defaultShadowCastingMode, other.defaultShadowCastingMode) && object.Equals(ignoreOverlays, other.ignoreOverlays)) { return object.Equals(hideOnDeath, other.hideOnDeath); } return false; } } [Serializable] public struct LightInfo { public Light light; public UnityEngine.Color defaultColor; public LightInfo(Light light) { this.light = light; defaultColor = light.color; } } private struct HurtBoxInfo { public readonly Transform transform; public readonly float estimatedRadius; public HurtBoxInfo(HurtBox hurtBox) { transform = hurtBox.transform; estimatedRadius = Util.SphereVolumeToRadius(hurtBox.volume); } } private struct ParentedPrefabDisplay { public ItemIndex itemIndex; public EquipmentIndex equipmentIndex; public GameObject instance { get; private set; } public ItemDisplay itemDisplay { get; private set; } public void Apply(CharacterModel characterModel, GameObject prefab, Transform parent, UnityEngine.Vector3 localPosition, UnityEngine.Quaternion localRotation, UnityEngine.Vector3 localScale) { instance = UnityEngine.Object.Instantiate(prefab.gameObject, parent); instance.transform.localPosition = localPosition; instance.transform.localRotation = localRotation; instance.transform.localScale = localScale; LimbMatcher component = instance.GetComponent(); if ((bool)component && (bool)characterModel.childLocator) { component.SetChildLocator(characterModel.childLocator); } itemDisplay = instance.GetComponent(); } public void Undo() { if ((bool)instance) { UnityEngine.Object.Destroy(instance); instance = null; } } } private struct LimbMaskDisplay { public ItemIndex itemIndex; public EquipmentIndex equipmentIndex; public LimbFlags maskValue; public void Apply(CharacterModel characterModel, LimbFlags mask) { maskValue = mask; characterModel.limbFlagSet.AddFlags(mask); } public void Undo(CharacterModel characterModel) { characterModel.limbFlagSet.RemoveFlags(maskValue); } } [Serializable] private class LimbFlagSet { private readonly byte[] flagCounts = new byte[5]; private LimbFlags flags; private static readonly int[] primeConversionTable; public int materialMaskValue { get; private set; } public LimbFlagSet() { materialMaskValue = 1; } static LimbFlagSet() { int[] array = new int[5] { 2, 3, 5, 11, 17 }; primeConversionTable = new int[31]; for (int i = 0; i < primeConversionTable.Length; i++) { int num = 1; for (int j = 0; j < 5; j++) { if ((i & (1 << j)) != 0) { num *= array[j]; } } primeConversionTable[i] = num; } } private static int ConvertLimbFlagsToMaterialMask(LimbFlags limbFlags) { return primeConversionTable[(int)limbFlags]; } public void AddFlags(LimbFlags addedFlags) { LimbFlags limbFlags = flags; flags |= addedFlags; for (int i = 0; i < 5; i++) { if (((uint)addedFlags & (uint)(1 << i)) != 0) { flagCounts[i]++; } } if (flags != limbFlags) { materialMaskValue = ConvertLimbFlagsToMaterialMask(flags); } } public void RemoveFlags(LimbFlags removedFlags) { LimbFlags limbFlags = flags; for (int i = 0; i < 5; i++) { if (((uint)removedFlags & (uint)(1 << i)) != 0 && --flagCounts[i] == 0) { flags &= (LimbFlags)(~(1 << i)); } } if (flags != limbFlags) { materialMaskValue = ConvertLimbFlagsToMaterialMask(flags); } } } public CharacterBody body; public ItemDisplayRuleSet itemDisplayRuleSet; public bool autoPopulateLightInfos = true; public List gameObjectActivationTransforms = new List(); [FormerlySerializedAs("rendererInfos")] public RendererInfo[] baseRendererInfos = Array.Empty(); public LightInfo[] baseLightInfos = Array.Empty(); private ChildLocator childLocator; private GameObject goldAffixEffect; private HurtBoxInfo[] hurtBoxInfos = Array.Empty(); private Transform coreTransform; private static readonly UnityEngine.Color hitFlashBaseColor; private static readonly UnityEngine.Color hitFlashShieldColor; private static readonly UnityEngine.Color healFlashColor; private static readonly float hitFlashDuration; private static readonly float healFlashDuration; private VisibilityLevel _visibility = VisibilityLevel.Visible; private bool _isGhost; private bool _isDoppelganger; private bool _isEcho; [NonSerialized] [HideInInspector] public int invisibilityCount; [NonSerialized] public List temporaryOverlays = new List(); private bool materialsDirty = true; private MaterialPropertyBlock propertyStorage; private EquipmentIndex inventoryEquipmentIndex = EquipmentIndex.None; private EliteIndex myEliteIndex = EliteIndex.None; private float fade = 1f; private float firstPersonFade = 1f; public float corpseFade = 1f; public bool CharacterOnScreen; private SkinnedMeshRenderer mainSkinnedMeshRenderer; public RendererVisiblity visibilityChecker; private static readonly UnityEngine.Color poisonEliteLightColor; private static readonly UnityEngine.Color hauntedEliteLightColor; private static readonly UnityEngine.Color lunarEliteLightColor; private static readonly UnityEngine.Color voidEliteLightColor; private UnityEngine.Color? lightColorOverride; private Material particleMaterialOverride; private GameObject poisonAffixEffect; private GameObject hauntedAffixEffect; private GameObject voidAffixEffect; private float affixHauntedCloakLockoutDuration = 3f; private EquipmentIndex currentEquipmentDisplayIndex = EquipmentIndex.None; private ItemMask enabledItemDisplays; private List parentedPrefabDisplays = new List(); private List limbMaskDisplays = new List(); private LimbFlagSet limbFlagSet = new LimbFlagSet(); public static Material revealedMaterial; public static Material cloakedMaterial; public static Material ghostMaterial; public static Material bellBuffMaterial; public static Material wolfhatMaterial; public static Material energyShieldMaterial; public static Material fullCritMaterial; public static Material beetleJuiceMaterial; public static Material brittleMaterial; public static Material clayGooMaterial; public static Material slow80Material; public static Material immuneMaterial; public static Material elitePoisonOverlayMaterial; public static Material elitePoisonParticleReplacementMaterial; public static Material eliteHauntedOverlayMaterial; public static Material eliteJustHauntedOverlayMaterial; public static Material eliteHauntedParticleReplacementMaterial; public static Material eliteLunarParticleReplacementMaterial; public static Material eliteVoidParticleReplacementMaterial; public static Material eliteVoidOverlayMaterial; public static Material weakMaterial; public static Material pulverizedMaterial; public static Material doppelgangerMaterial; public static Material ghostParticleReplacementMaterial; public static Material lunarGolemShieldMaterial; public static Material echoMaterial; public static Material gummyCloneMaterial; public static Material voidSurvivorCorruptMaterial; public static Material voidShieldMaterial; public static Material growthNectarMaterial; public static Material eliteAurelioniteAffixOverlay; public static Material yesChefHeatMaterial; private static readonly int maxOverlays; private Material[] currentOverlays = new Material[maxOverlays]; private int activeOverlayCount; private bool wasPreviouslyClayGooed; private bool wasPreviouslyHaunted; private RtpcSetter rtpcEliteEnemy; private int shaderEliteRampIndex = -1; private bool eliteChanged; public int activeOverlays; public int oldOverlays; public float hitFlashValue; public float healFlashValue; public float oldHit; public float oldHeal; public float oldFade; private EliteIndex oldEliteIndex = EliteIndex.None; public bool forceUpdate; private static Material[][] sharedMaterialArrays; private static readonly int maxMaterials; public VisibilityLevel visibility { get { return _visibility; } set { if (_visibility != value) { _visibility = value; materialsDirty = true; } } } public bool isGhost { get { return _isGhost; } set { if (_isGhost != value) { _isGhost = value; materialsDirty = true; } } } public bool isDoppelganger { get { return _isDoppelganger; } set { if (_isDoppelganger != value) { _isDoppelganger = value; materialsDirty = true; } } } public bool isEcho { get { return _isEcho; } set { if (_isEcho != value) { _isEcho = value; materialsDirty = true; } } } private void Awake() { enabledItemDisplays = ItemMask.Rent(); childLocator = GetComponent(); HurtBoxGroup component = GetComponent(); coreTransform = base.transform; if ((bool)component) { coreTransform = component.mainHurtBox?.transform ?? coreTransform; HurtBox[] hurtBoxes = component.hurtBoxes; if (hurtBoxes.Length != 0) { hurtBoxInfos = new HurtBoxInfo[hurtBoxes.Length]; for (int i = 0; i < hurtBoxes.Length; i++) { hurtBoxInfos[i] = new HurtBoxInfo(hurtBoxes[i]); } } } propertyStorage = new MaterialPropertyBlock(); RendererInfo[] array = baseRendererInfos; for (int j = 0; j < array.Length; j++) { RendererInfo rendererInfo = array[j]; if (rendererInfo.renderer is SkinnedMeshRenderer) { mainSkinnedMeshRenderer = (SkinnedMeshRenderer)rendererInfo.renderer; break; } } if ((bool)body && Util.IsPrefab(body.gameObject) && !Util.IsPrefab(base.gameObject)) { body = null; } } private void Start() { forceUpdate = true; visibility = VisibilityLevel.Invisible; UpdateMaterials(); } private void OnEnable() { InstanceTracker.Add(this); if ((object)body != null) { rtpcEliteEnemy = new RtpcSetter("eliteEnemy", body.gameObject); body.onInventoryChanged += OnInventoryChanged; } } private void OnDisable() { InstanceUpdate(); if ((object)body != null) { body.onInventoryChanged -= OnInventoryChanged; } InstanceTracker.Remove(this); } public void SetVisible(bool visible) { if ((bool)body) { body.CharacterIsVisible = (CharacterOnScreen = visible); } } private void OnDestroy() { ItemMask.Return(enabledItemDisplays); } private void OnInventoryChanged() { if ((bool)body) { Inventory inventory = body.inventory; if ((bool)inventory) { UpdateItemDisplay(inventory); inventoryEquipmentIndex = inventory.GetEquipmentIndex(); SetEquipmentDisplay(inventoryEquipmentIndex); forceUpdate = true; } } } private void InstanceUpdate() { if (isGhost) { particleMaterialOverride = ghostParticleReplacementMaterial; } else if (myEliteIndex == RoR2Content.Elites.Poison.eliteIndex) { lightColorOverride = poisonEliteLightColor; particleMaterialOverride = elitePoisonParticleReplacementMaterial; } else if (myEliteIndex == RoR2Content.Elites.Haunted.eliteIndex) { lightColorOverride = hauntedEliteLightColor; particleMaterialOverride = eliteHauntedParticleReplacementMaterial; } else if (myEliteIndex == RoR2Content.Elites.Lunar.eliteIndex) { lightColorOverride = lunarEliteLightColor; particleMaterialOverride = eliteLunarParticleReplacementMaterial; } else if (myEliteIndex == DLC1Content.Elites.Void.eliteIndex && (bool)body && body.healthComponent.alive) { lightColorOverride = voidEliteLightColor; particleMaterialOverride = eliteVoidParticleReplacementMaterial; } else { lightColorOverride = null; particleMaterialOverride = null; } UpdateGoldAffix(); UpdatePoisonAffix(); UpdateHauntedAffix(); UpdateVoidAffix(); UpdateLights(); } private void UpdateLights() { LightInfo[] array = baseLightInfos; if (array.Length == 0) { return; } if (lightColorOverride.HasValue) { UnityEngine.Color value = lightColorOverride.Value; for (int i = 0; i < array.Length; i++) { array[i].light.color = value; } } else { for (int j = 0; j < array.Length; j++) { ref LightInfo reference = ref array[j]; reference.light.color = reference.defaultColor; } } } [InitDuringStartup] private static void Init() { RoR2Application.onLateUpdate += StaticUpdate; } private static void StaticUpdate() { foreach (CharacterModel instances in InstanceTracker.GetInstancesList()) { instances.InstanceUpdate(); } } public void AddTempOverlay(TemporaryOverlayInstance overlay) { temporaryOverlays.Add(overlay); materialsDirty = true; } public void RemoveTempOverlay(TemporaryOverlayInstance overlay) { temporaryOverlays.Remove(overlay); materialsDirty = true; } private bool IsCurrentEliteType(EliteDef eliteDef) { if ((object)eliteDef == null || eliteDef.eliteIndex == EliteIndex.None) { return false; } return eliteDef.eliteIndex == myEliteIndex; } private void UpdateGoldAffix() { if (IsCurrentEliteType(JunkContent.Elites.Gold) == (bool)goldAffixEffect) { return; } if (!goldAffixEffect) { goldAffixEffect = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/GoldAffixEffect"), base.transform); ParticleSystem.ShapeModule shape = goldAffixEffect.GetComponent().shape; if ((bool)mainSkinnedMeshRenderer) { shape.shapeType = ParticleSystemShapeType.SkinnedMeshRenderer; shape.skinnedMeshRenderer = mainSkinnedMeshRenderer; } } else { UnityEngine.Object.Destroy(goldAffixEffect); goldAffixEffect = null; } } private void UpdatePoisonAffix() { if ((myEliteIndex == RoR2Content.Elites.Poison.eliteIndex && body.healthComponent.alive) == (bool)poisonAffixEffect) { return; } if (!poisonAffixEffect) { poisonAffixEffect = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/PoisonAffixEffect"), base.transform); if ((bool)mainSkinnedMeshRenderer) { JitterBones[] components = poisonAffixEffect.GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].skinnedMeshRenderer = mainSkinnedMeshRenderer; } } } else { UnityEngine.Object.Destroy(poisonAffixEffect); poisonAffixEffect = null; } } private void UpdateHauntedAffix() { if ((myEliteIndex == RoR2Content.Elites.Haunted.eliteIndex && body.healthComponent.alive) == (bool)hauntedAffixEffect) { return; } if (!hauntedAffixEffect) { hauntedAffixEffect = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/HauntedAffixEffect"), base.transform); if ((bool)mainSkinnedMeshRenderer) { JitterBones[] components = hauntedAffixEffect.GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].skinnedMeshRenderer = mainSkinnedMeshRenderer; } } } else { UnityEngine.Object.Destroy(hauntedAffixEffect); hauntedAffixEffect = null; } } private void UpdateVoidAffix() { if ((myEliteIndex == DLC1Content.Elites.Void.eliteIndex && body.healthComponent.alive) == (bool)voidAffixEffect) { return; } if (!voidAffixEffect) { voidAffixEffect = UnityEngine.Object.Instantiate(Addressables.LoadAssetAsync("RoR2/DLC1/EliteVoid/VoidAffixEffect.prefab").WaitForCompletion(), base.transform); if ((bool)mainSkinnedMeshRenderer) { JitterBones[] components = voidAffixEffect.GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].skinnedMeshRenderer = mainSkinnedMeshRenderer; } } } else { UnityEngine.Object.Destroy(voidAffixEffect); voidAffixEffect = null; } } private void OnValidate() { if (Application.isPlaying) { return; } for (int i = 0; i < baseLightInfos.Length; i++) { ref LightInfo reference = ref baseLightInfos[i]; if ((bool)reference.light) { reference.defaultColor = reference.light.color; } } _ = (bool)itemDisplayRuleSet; if (autoPopulateLightInfos) { LightInfo[] first = (from light in GetComponentsInChildren() select new LightInfo(light)).ToArray(); if (!first.SequenceEqual(baseLightInfos)) { baseLightInfos = first; } } } private static void RefreshObstructorsForCamera(CameraRigController cameraRigController) { UnityEngine.Vector3 position = cameraRigController.transform.position; foreach (CharacterModel instances in InstanceTracker.GetInstancesList()) { if (cameraRigController.enableFading) { float nearestHurtBoxDistance = instances.GetNearestHurtBoxDistance(position); instances.fade = Mathf.Clamp01(Util.Remap(nearestHurtBoxDistance, cameraRigController.fadeStartDistance, cameraRigController.fadeEndDistance, 0f, 1f)); } else { instances.fade = 1f; } } } private float GetNearestHurtBoxDistance(UnityEngine.Vector3 cameraPosition) { float num = float.PositiveInfinity; for (int i = 0; i < hurtBoxInfos.Length; i++) { float num2 = UnityEngine.Vector3.Distance(hurtBoxInfos[i].transform.position, cameraPosition) - hurtBoxInfos[i].estimatedRadius; if (num2 < num) { num = Mathf.Min(num2, num); } } return num; } private void UpdateForCamera(CameraRigController cameraRigController) { VisibilityLevel num = visibility; visibility = VisibilityLevel.Visible; float target = 1f; if ((bool)body) { if ((object)cameraRigController.firstPersonTarget == body.gameObject) { target = 0f; } visibility = body.GetVisibilityLevel(cameraRigController.targetTeamIndex); } float num2 = 0.25f; if ((bool)cameraRigController.targetParams && cameraRigController.targetParams.currentCameraParamsData.overrideFirstPersonFadeDuration > 0f) { num2 = cameraRigController.targetParams.currentCameraParamsData.overrideFirstPersonFadeDuration; } firstPersonFade = Mathf.MoveTowards(firstPersonFade, target, Time.deltaTime / num2); fade *= firstPersonFade * corpseFade; if (fade <= 0f || invisibilityCount > 0) { visibility = VisibilityLevel.Invisible; } if (num != visibility) { forceUpdate = true; } bool flag = forceUpdate; if (!flag) { for (int i = 0; i < baseRendererInfos.Length; i++) { if ((bool)baseRendererInfos[i].renderer && baseRendererInfos[i].renderer.isVisible) { flag = true; break; } } } if (flag) { UpdateOverlays(); if (materialsDirty) { UpdateMaterials(); materialsDirty = false; } } } static CharacterModel() { hitFlashBaseColor = new Color32(193, 108, 51, byte.MaxValue); hitFlashShieldColor = new Color32(132, 159, byte.MaxValue, byte.MaxValue); healFlashColor = new Color32(104, 196, 49, byte.MaxValue); hitFlashDuration = 0.15f; healFlashDuration = 0.35f; poisonEliteLightColor = new Color32(90, byte.MaxValue, 193, 204); hauntedEliteLightColor = new Color32(152, 228, 217, 204); lunarEliteLightColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 127); voidEliteLightColor = new Color32(151, 78, 132, 204); maxOverlays = 6; maxMaterials = 1 + maxOverlays; SceneCamera.onSceneCameraPreRender += OnSceneCameraPreRender; } private static void OnSceneCameraPreRender(SceneCamera sceneCamera) { if ((bool)sceneCamera.cameraRigController) { RefreshObstructorsForCamera(sceneCamera.cameraRigController); } if (!sceneCamera.cameraRigController) { return; } foreach (CharacterModel instances in InstanceTracker.GetInstancesList()) { instances.UpdateForCamera(sceneCamera.cameraRigController); } } private void InstantiateDisplayRuleGroup(DisplayRuleGroup displayRuleGroup, ItemIndex itemIndex, EquipmentIndex equipmentIndex) { if (displayRuleGroup.rules == null) { return; } for (int i = 0; i < displayRuleGroup.rules.Length; i++) { ItemDisplayRule itemDisplayRule = displayRuleGroup.rules[i]; switch (itemDisplayRule.ruleType) { case ItemDisplayRuleType.ParentedPrefab: if ((bool)childLocator) { Transform transform = childLocator.FindChild(itemDisplayRule.childName); if ((bool)transform) { ParentedPrefabDisplay parentedPrefabDisplay = default(ParentedPrefabDisplay); parentedPrefabDisplay.itemIndex = itemIndex; parentedPrefabDisplay.equipmentIndex = equipmentIndex; ParentedPrefabDisplay item2 = parentedPrefabDisplay; item2.Apply(this, itemDisplayRule.followerPrefab, transform, itemDisplayRule.localPos, UnityEngine.Quaternion.Euler(itemDisplayRule.localAngles), itemDisplayRule.localScale); parentedPrefabDisplays.Add(item2); } } break; case ItemDisplayRuleType.LimbMask: { LimbMaskDisplay limbMaskDisplay = default(LimbMaskDisplay); limbMaskDisplay.itemIndex = itemIndex; limbMaskDisplay.equipmentIndex = equipmentIndex; LimbMaskDisplay item = limbMaskDisplay; item.Apply(this, itemDisplayRule.limbMask); limbMaskDisplays.Add(item); break; } } } } private void SetEquipmentDisplay(EquipmentIndex newEquipmentIndex) { if (newEquipmentIndex == currentEquipmentDisplayIndex) { return; } for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--) { if (parentedPrefabDisplays[num].equipmentIndex != EquipmentIndex.None) { parentedPrefabDisplays[num].Undo(); parentedPrefabDisplays.RemoveAt(num); } } for (int num2 = limbMaskDisplays.Count - 1; num2 >= 0; num2--) { if (limbMaskDisplays[num2].equipmentIndex != EquipmentIndex.None) { limbMaskDisplays[num2].Undo(this); limbMaskDisplays.RemoveAt(num2); } } currentEquipmentDisplayIndex = newEquipmentIndex; if ((bool)itemDisplayRuleSet) { DisplayRuleGroup equipmentDisplayRuleGroup = itemDisplayRuleSet.GetEquipmentDisplayRuleGroup(newEquipmentIndex); InstantiateDisplayRuleGroup(equipmentDisplayRuleGroup, ItemIndex.None, newEquipmentIndex); } } private void EnableItemDisplay(ItemIndex itemIndex) { if (!enabledItemDisplays.Contains(itemIndex)) { enabledItemDisplays.Add(itemIndex); if ((bool)itemDisplayRuleSet) { DisplayRuleGroup itemDisplayRuleGroup = itemDisplayRuleSet.GetItemDisplayRuleGroup(itemIndex); InstantiateDisplayRuleGroup(itemDisplayRuleGroup, itemIndex, EquipmentIndex.None); } } } public void DisableAllItemDisplays() { ItemIndex itemIndex = ItemIndex.Count; for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++) { DisableItemDisplay(itemIndex); } } private void DisableItemDisplay(ItemIndex itemIndex) { if (!enabledItemDisplays.Contains(itemIndex)) { return; } enabledItemDisplays.Remove(itemIndex); for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--) { if (parentedPrefabDisplays[num].itemIndex == itemIndex) { parentedPrefabDisplays[num].Undo(); parentedPrefabDisplays.RemoveAt(num); } } for (int num2 = limbMaskDisplays.Count - 1; num2 >= 0; num2--) { if (limbMaskDisplays[num2].itemIndex == itemIndex) { limbMaskDisplays[num2].Undo(this); limbMaskDisplays.RemoveAt(num2); } } } public void UpdateItemDisplay(Inventory inventory) { ItemIndex itemIndex = ItemIndex.Count; for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++) { if (inventory.GetItemCount(itemIndex) > 0) { EnableItemDisplay(itemIndex); } else { DisableItemDisplay(itemIndex); } } } public void HighlightItemDisplay(ItemIndex itemIndex) { if (!enabledItemDisplays.Contains(itemIndex)) { return; } ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(ItemCatalog.GetItemDef(itemIndex).tier); GameObject gameObject = null; gameObject = ((!itemTierDef || !itemTierDef.highlightPrefab) ? LegacyResourcesAPI.Load("Prefabs/UI/HighlightTier1Item") : itemTierDef.highlightPrefab); for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--) { if (parentedPrefabDisplays[num].itemIndex == itemIndex) { GameObject instance = parentedPrefabDisplays[num].instance; if ((bool)instance) { Renderer componentInChildren = instance.GetComponentInChildren(); if ((bool)componentInChildren && (bool)body) { HighlightRect.CreateHighlight(body.gameObject, componentInChildren, gameObject); } } } } } public List GetEquipmentDisplayObjects(EquipmentIndex equipmentIndex) { List list = new List(); for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--) { if (parentedPrefabDisplays[num].equipmentIndex == equipmentIndex) { GameObject instance = parentedPrefabDisplays[num].instance; list.Add(instance); } } return list; } public List GetItemDisplayObjects(ItemIndex itemIndex) { List list = new List(); for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--) { if (parentedPrefabDisplays[num].itemIndex == itemIndex) { GameObject instance = parentedPrefabDisplays[num].instance; list.Add(instance); } } return list; } [InitDuringStartup] private static void InitMaterials() { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matEliteAurelioniteAffixOverlay"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { eliteAurelioniteAffixOverlay = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matRevealedEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { revealedMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matCloakedEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { cloakedMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matGhostEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { ghostMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matGhostParticleReplacement"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { ghostParticleReplacementMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matWolfhatOverlay"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { wolfhatMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matEnergyShield"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { energyShieldMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matBeetleJuice"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { beetleJuiceMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matBrittle"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { brittleMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matFullCrit"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { fullCritMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matClayGooDebuff"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { clayGooMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matSlow80Debuff"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { slow80Material = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matImmune"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { immuneMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matBellBuff"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { bellBuffMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matElitePoisonOverlay"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { elitePoisonOverlayMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matElitePoisonParticleReplacement"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { elitePoisonParticleReplacementMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matEliteHauntedOverlay"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { eliteHauntedOverlayMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matEliteHauntedParticleReplacement"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { eliteHauntedParticleReplacementMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matEliteJustHauntedOverlay"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { eliteJustHauntedOverlayMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matEliteLunarParticleReplacement"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { eliteLunarParticleReplacementMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matDoppelganger"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { doppelgangerMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matWeakOverlay"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { weakMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matPulverizedOverlay"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { pulverizedMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matLunarGolemShield"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { lunarGolemShieldMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matEcho"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { echoMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matGummyClone"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { gummyCloneMaterial = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Materials/matGrowthNectarGlow"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { growthNectarMaterial = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC1/EliteVoid/matEliteVoidParticleReplacement.mat"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { eliteVoidParticleReplacementMaterial = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC1/EliteVoid/matEliteVoidOverlay.mat"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { eliteVoidOverlayMaterial = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC1/VoidSurvivor/matVoidSurvivorCorruptOverlay.mat"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { voidSurvivorCorruptMaterial = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC1/MissileVoid/matEnergyShieldVoid.mat"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { voidShieldMaterial = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC2/Chef/matYesChefOverlay.mat"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { yesChefHeatMaterial = x.Result; }; } private bool UpdateOverlayStates() { oldOverlays = activeOverlays; activeOverlays = 0; if ((bool)body) { bool condition2 = body.HasBuff(RoR2Content.Buffs.ClayGoo); Inventory inventory = body.inventory; isGhost = (object)inventory != null && inventory.GetItemCount(RoR2Content.Items.Ghost) > 0; myEliteIndex = EquipmentCatalog.GetEquipmentDef(inventoryEquipmentIndex)?.passiveBuffDef?.eliteDef?.eliteIndex ?? EliteIndex.None; oldHit = hitFlashValue; oldHeal = healFlashValue; if ((bool)body.healthComponent) { hitFlashValue = Mathf.Clamp01(1f - body.healthComponent.timeSinceLastHit / hitFlashDuration); healFlashValue = Mathf.Pow(Mathf.Clamp01(1f - body.healthComponent.timeSinceLastHeal / healFlashDuration), 0.5f); } eliteChanged = myEliteIndex != oldEliteIndex; int num = 0; SetOverlayFlag(num++, eliteChanged); SetOverlayFlag(num++, hitFlashValue != oldHit || healFlashValue != oldHeal); SetOverlayFlag(num++, isGhost); SetOverlayFlag(num++, condition2); SetOverlayFlag(num++, myEliteIndex == RoR2Content.Elites.Poison.eliteIndex || body.HasBuff(RoR2Content.Buffs.HealingDisabled)); SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.Weak)); SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.FullCrit)); SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.AttackSpeedOnCrit)); SetOverlayFlag(num++, (bool)body.healthComponent && body.healthComponent.shield > 0f); SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.BeetleJuice)); SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.Immune)); SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.Slow80)); SetOverlayFlag(num++, (bool)body.inventory && body.inventory.GetItemCount(RoR2Content.Items.LunarDagger) > 0); SetOverlayFlag(num++, (bool)body.inventory && body.inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0); SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.AffixHaunted)); SetOverlayFlag(num++, body.HasBuff(DLC1Content.Buffs.EliteVoid) && (bool)body.healthComponent && body.healthComponent.alive); SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.Pulverized)); SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.LunarShell)); SetOverlayFlag(num++, (bool)body.inventory && body.inventory.GetItemCount(RoR2Content.Items.SummonedEcho) > 0); SetOverlayFlag(num++, IsGummyClone()); SetOverlayFlag(num++, body.HasBuff(DLC1Content.Buffs.VoidSurvivorCorruptMode)); SetOverlayFlag(num++, IsAurelioniteAffix()); SetOverlayFlag(num++, body.HasBuff(DLC2Content.Buffs.BoostAllStatsBuff)); SetOverlayFlag(num++, body.HasBuff(DLC2Content.Buffs.boostedFireEffect)); for (int i = 0; i < baseRendererInfos.Length; i++) { SetOverlayFlag(num + i, baseRendererInfos[i].ignoreOverlays); } } bool flag = fade != oldFade; oldEliteIndex = myEliteIndex; oldFade = fade; return oldOverlays != activeOverlays || flag; void SetOverlayFlag(int index, bool condition) { if (condition) { activeOverlays |= 1 << index; } } } private void UpdateOverlays() { if (visibility == VisibilityLevel.Invisible || (!UpdateOverlayStates() && !forceUpdate)) { return; } forceUpdate = false; for (int i = 0; i < activeOverlayCount; i++) { currentOverlays[i] = null; } activeOverlayCount = 0; EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(inventoryEquipmentIndex); myEliteIndex = equipmentDef?.passiveBuffDef?.eliteDef?.eliteIndex ?? EliteIndex.None; shaderEliteRampIndex = equipmentDef?.passiveBuffDef?.eliteDef?.shaderEliteRampIndex ?? (-1); bool flag = false; bool flag2 = false; if ((bool)body) { flag = body.HasBuff(RoR2Content.Buffs.ClayGoo); flag2 = body.HasBuff(RoR2Content.Buffs.AffixHauntedRecipient); rtpcEliteEnemy.value = ((myEliteIndex != EliteIndex.None) ? 1f : 0f); rtpcEliteEnemy.FlushIfChanged(); Inventory inventory = body.inventory; isGhost = (object)inventory != null && inventory.GetItemCount(RoR2Content.Items.Ghost) > 0; Inventory inventory2 = body.inventory; isDoppelganger = (object)inventory2 != null && inventory2.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0; Inventory inventory3 = body.inventory; isEcho = (object)inventory3 != null && inventory3.GetItemCount(RoR2Content.Items.SummonedEcho) > 0; Inventory inventory4 = body.inventory; bool flag3 = (object)inventory4 != null && inventory4.GetItemCount(DLC1Content.Items.MissileVoid) > 0; AddOverlay(ghostMaterial, isGhost); AddOverlay(doppelgangerMaterial, isDoppelganger); AddOverlay(clayGooMaterial, flag); AddOverlay(elitePoisonOverlayMaterial, myEliteIndex == RoR2Content.Elites.Poison.eliteIndex || body.HasBuff(RoR2Content.Buffs.HealingDisabled)); AddOverlay(eliteHauntedOverlayMaterial, body.HasBuff(RoR2Content.Buffs.AffixHaunted)); AddOverlay(eliteVoidOverlayMaterial, body.HasBuff(DLC1Content.Buffs.EliteVoid) && (bool)body.healthComponent && body.healthComponent.alive); AddOverlay(pulverizedMaterial, body.HasBuff(RoR2Content.Buffs.Pulverized)); AddOverlay(weakMaterial, body.HasBuff(RoR2Content.Buffs.Weak)); AddOverlay(fullCritMaterial, body.HasBuff(RoR2Content.Buffs.FullCrit)); AddOverlay(wolfhatMaterial, body.HasBuff(RoR2Content.Buffs.AttackSpeedOnCrit)); AddOverlay(flag3 ? voidShieldMaterial : energyShieldMaterial, (bool)body.healthComponent && body.healthComponent.shield > 0f); AddOverlay(beetleJuiceMaterial, body.HasBuff(RoR2Content.Buffs.BeetleJuice)); AddOverlay(immuneMaterial, body.HasBuff(RoR2Content.Buffs.Immune)); AddOverlay(slow80Material, body.HasBuff(RoR2Content.Buffs.Slow80)); AddOverlay(brittleMaterial, (bool)body.inventory && body.inventory.GetItemCount(RoR2Content.Items.LunarDagger) > 0); AddOverlay(lunarGolemShieldMaterial, body.HasBuff(RoR2Content.Buffs.LunarShell)); AddOverlay(echoMaterial, isEcho); AddOverlay(gummyCloneMaterial, IsGummyClone()); AddOverlay(voidSurvivorCorruptMaterial, body.HasBuff(DLC1Content.Buffs.VoidSurvivorCorruptMode)); AddOverlay(growthNectarMaterial, body.HasBuff(DLC2Content.Buffs.BoostAllStatsBuff)); AddOverlay(eliteAurelioniteAffixOverlay, IsAurelioniteAffix()); AddOverlay(lunarGolemShieldMaterial, body.HasBuff(DLC2Content.Buffs.EliteBead)); AddOverlay(brittleMaterial, body.HasBuff(DLC2Content.Buffs.EliteBeadCorruption)); AddOverlay(yesChefHeatMaterial, body.HasBuff(DLC2Content.Buffs.boostedFireEffect)); } if (wasPreviouslyClayGooed && !flag) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(base.gameObject); temporaryOverlayInstance.duration = 0.6f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = clayGooMaterial; temporaryOverlayInstance.AddToCharacterModel(this); } if (wasPreviouslyHaunted != flag2) { TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(base.gameObject); temporaryOverlayInstance2.duration = 0.5f; temporaryOverlayInstance2.animateShaderAlpha = true; temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance2.destroyComponentOnEnd = true; temporaryOverlayInstance2.originalMaterial = eliteJustHauntedOverlayMaterial; temporaryOverlayInstance2.AddToCharacterModel(this); } wasPreviouslyClayGooed = flag; wasPreviouslyHaunted = flag2; for (int j = 0; j < temporaryOverlays.Count; j++) { if (activeOverlayCount >= maxOverlays) { break; } currentOverlays[activeOverlayCount++] = temporaryOverlays[j].materialInstance; } wasPreviouslyClayGooed = flag; wasPreviouslyHaunted = flag2; materialsDirty = true; void AddOverlay(Material overlayMaterial, bool condition) { if (activeOverlayCount < maxOverlays && condition) { currentOverlays[activeOverlayCount++] = overlayMaterial; } } } [InitDuringStartup] private static void InitSharedMaterialsArrays() { sharedMaterialArrays = new Material[maxMaterials + 1][]; if (maxMaterials > 0) { sharedMaterialArrays[0] = Array.Empty(); for (int i = 1; i < sharedMaterialArrays.Length; i++) { sharedMaterialArrays[i] = new Material[i]; } } } private void UpdateRendererMaterials(Renderer renderer, Material defaultMaterial, bool ignoreOverlays) { Material material = null; switch (visibility) { case VisibilityLevel.Invisible: renderer.sharedMaterial = null; return; case VisibilityLevel.Cloaked: if (!ignoreOverlays) { ignoreOverlays = true; material = cloakedMaterial; } break; case VisibilityLevel.Revealed: if (!ignoreOverlays) { material = revealedMaterial; } break; case VisibilityLevel.Visible: material = (ignoreOverlays ? (particleMaterialOverride ? particleMaterialOverride : defaultMaterial) : ((!isDoppelganger) ? ((!isGhost) ? ((!IsGummyClone()) ? ((!IsAurelioniteAffix()) ? defaultMaterial : eliteAurelioniteAffixOverlay) : gummyCloneMaterial) : ghostMaterial) : doppelgangerMaterial)); break; } int num = ((!ignoreOverlays) ? activeOverlayCount : 0); if ((bool)material) { num++; } Material material2 = null; Material[] array = sharedMaterialArrays[num]; int num2 = 0; if ((bool)material) { array[num2++] = material; } if (!ignoreOverlays) { for (int i = 0; i < activeOverlayCount; i++) { array[num2++] = currentOverlays[i]; } } if (material2 != null) { array[num2++] = material2; } if (num2 != array.Length) { UnityEngine.Debug.LogError("Materials are going to be pink or something!?"); } renderer.sharedMaterials = array; } private void UpdateMaterials() { UnityEngine.Color value = UnityEngine.Color.black; if ((bool)body && (bool)body.healthComponent) { float num = Mathf.Clamp01(1f - body.healthComponent.timeSinceLastHit / hitFlashDuration); float num2 = Mathf.Pow(Mathf.Clamp01(1f - body.healthComponent.timeSinceLastHeal / healFlashDuration), 0.5f); value = ((!(num2 > num)) ? (((body.healthComponent.shield > 0f) ? hitFlashShieldColor : hitFlashBaseColor) * num) : (healFlashColor * num2)); } if (visibility == VisibilityLevel.Invisible) { for (int num3 = baseRendererInfos.Length - 1; num3 >= 0; num3--) { RendererInfo rendererInfo = baseRendererInfos[num3]; rendererInfo.renderer.shadowCastingMode = ShadowCastingMode.Off; rendererInfo.renderer.enabled = false; } } else { for (int num4 = baseRendererInfos.Length - 1; num4 >= 0; num4--) { RendererInfo rendererInfo2 = baseRendererInfos[num4]; Renderer renderer = rendererInfo2.renderer; UpdateRendererMaterials(renderer, baseRendererInfos[num4].defaultMaterial, baseRendererInfos[num4].ignoreOverlays); renderer.shadowCastingMode = rendererInfo2.defaultShadowCastingMode; renderer.enabled = true; renderer.GetPropertyBlock(propertyStorage); propertyStorage.SetColor(CommonShaderProperties._FlashColor, value); propertyStorage.SetFloat(CommonShaderProperties._EliteIndex, shaderEliteRampIndex + 1); propertyStorage.SetInt(CommonShaderProperties._LimbPrimeMask, limbFlagSet.materialMaskValue); propertyStorage.SetFloat(CommonShaderProperties._Fade, fade); renderer.SetPropertyBlock(propertyStorage); } } for (int i = 0; i < parentedPrefabDisplays.Count; i++) { ItemDisplay itemDisplay = parentedPrefabDisplays[i].itemDisplay; itemDisplay.SetVisibilityLevel(visibility); for (int j = 0; j < itemDisplay.rendererInfos.Length; j++) { Renderer renderer2 = itemDisplay.rendererInfos[j].renderer; renderer2.GetPropertyBlock(propertyStorage); propertyStorage.SetColor(CommonShaderProperties._FlashColor, value); propertyStorage.SetFloat(CommonShaderProperties._Fade, fade); renderer2.SetPropertyBlock(propertyStorage); } } } private bool IsGummyClone() { CharacterBody characterBody = body; if ((object)characterBody == null) { return false; } return characterBody.inventory?.GetItemCount(DLC1Content.Items.GummyCloneIdentifier) > 0; } private bool IsAurelioniteAffix() { bool result = false; if ((bool)body) { result = body.HasBuff(DLC2Content.Buffs.EliteAurelionite); } return result; } public void OnDeath() { for (int i = 0; i < parentedPrefabDisplays.Count; i++) { parentedPrefabDisplays[i].itemDisplay.OnDeath(); } InstanceUpdate(); UpdateOverlays(); UpdateMaterials(); } } [RequireComponent(typeof(CharacterBody))] public class CharacterMotor : BaseCharacterController, IPhysMotor, ILifeBehavior, IDisplacementReceiver, ICharacterGravityParameterProvider, ICharacterFlightParameterProvider { [Serializable] public struct HitGroundInfo { public UnityEngine.Vector3 velocity; public UnityEngine.Vector3 position; public bool isValidForEffect; public override string ToString() { return $"velocity={velocity} position={position}"; } } public delegate void HitGroundDelegate(ref HitGroundInfo hitGroundInfo); public struct MovementHitInfo { public UnityEngine.Vector3 velocity; public Collider hitCollider; } public delegate void MovementHitDelegate(ref MovementHitInfo movementHitInfo); [HideInInspector] public float walkSpeedPenaltyCoefficient = 1f; [Tooltip("The character direction component to supply a move vector to.")] public CharacterDirection characterDirection; [Tooltip("Whether or not a move vector supplied to this component can cause movement. Use this when the object is driven by root motion.")] public bool muteWalkMotion; [Tooltip("The mass of this character.")] public float mass = 1f; [Tooltip("The air control value of this character as a fraction of ground control.")] public float airControl = 0.25f; [Tooltip("Disables Air Control for things like jumppads")] public bool disableAirControlUntilCollision; [Tooltip("Auto-assigns parameters skin width, slope angle, and step offset as a function of the Character Motor's radius and height")] public bool generateParametersOnAwake = true; [Tooltip("Ignores JumpVolumes")] public bool doNotTriggerJumpVolumes; private NetworkIdentity networkIdentity; private CharacterBody body; private CapsuleCollider capsuleCollider; private static readonly bool enableMotorWithoutAuthority; private bool alive = true; private const float restDuration = 1f; private const float restVelocityThreshold = 0.025f; private const float restVelocityThresholdSqr = 0.00062500004f; public const float slipStartAngle = 70f; public const float slipEndAngle = 55f; private float restStopwatch; private UnityEngine.Vector3 previousPosition; private bool isAirControlForced; [NonSerialized] public int jumpCount; [NonSerialized] public bool netIsGrounded; [NonSerialized] public UnityEngine.Vector3 netGroundNormal; [NonSerialized] public UnityEngine.Vector3 velocity; private UnityEngine.Vector3 lastVelocity; [NonSerialized] public UnityEngine.Vector3 rootMotion; private UnityEngine.Vector3 _moveDirection; private static readonly FloatConVar cvCMotorSafeCollisionStepThreshold; private int _safeCollisionEnableCount; [SerializeField] [Tooltip("Determins how gravity affects this character.")] private CharacterGravityParameters _gravityParameters; [Tooltip("Determines whether this character has three-dimensional or two-dimensional movement capabilities.")] [SerializeField] private CharacterFlightParameters _flightParameters; private static int kRpcRpcApplyForceImpulse; private static int kRpcRpcOnHitGroundSFX; private static int kCmdCmdReportHitGround; public float walkSpeed => body.moveSpeed * walkSpeedPenaltyCoefficient; public float acceleration => body.acceleration; public bool atRest => restStopwatch > 1f; public bool hasEffectiveAuthority { get; private set; } public UnityEngine.Vector3 estimatedGroundNormal { get { if (!hasEffectiveAuthority) { return netGroundNormal; } return base.Motor.GroundingStatus.GroundNormal; } } private bool canWalk { get { if (!muteWalkMotion) { return alive; } return false; } } public bool isGrounded { get { if (!hasEffectiveAuthority) { return netIsGrounded; } return base.Motor.GroundingStatus.IsStableOnGround; } } float IPhysMotor.mass => mass; UnityEngine.Vector3 IPhysMotor.velocity => velocity; UnityEngine.Vector3 IPhysMotor.velocityAuthority { get { return velocity; } set { velocity = value; } } public UnityEngine.Vector3 moveDirection { get { return _moveDirection; } set { _moveDirection = value; } } private float slopeLimit { get { return base.Motor.MaxStableSlopeAngle; } set { base.Motor.MaxStableSlopeAngle = value; } } public float stepOffset { get { return base.Motor.MaxStepHeight; } set { base.Motor.MaxStepHeight = value; } } public float capsuleHeight => capsuleCollider.height; public float capsuleRadius => capsuleCollider.radius; public StepHandlingMethod stepHandlingMethod { get { return base.Motor.StepHandling = StepHandlingMethod.None; } set { base.Motor.StepHandling = value; } } public bool ledgeHandling { get { return base.Motor.LedgeAndDenivelationHandling; } set { base.Motor.LedgeAndDenivelationHandling = value; } } public bool interactiveRigidbodyHandling { get { return base.Motor.InteractiveRigidbodyHandling; } set { base.Motor.InteractiveRigidbodyHandling = value; } } public Run.FixedTimeStamp lastGroundedTime { get; private set; } = Run.FixedTimeStamp.negativeInfinity; public CharacterGravityParameters gravityParameters { get { return _gravityParameters; } set { if (!_gravityParameters.Equals(value)) { _gravityParameters = value; useGravity = _gravityParameters.CheckShouldUseGravity(); } } } public bool useGravity { get; private set; } public CharacterFlightParameters flightParameters { get { return _flightParameters; } set { if (!_flightParameters.Equals(value)) { _flightParameters = value; isFlying = _flightParameters.CheckShouldUseFlight(); } } } public bool isFlying { get; private set; } [Obsolete("Use '.onHitGroundAuthority' instead, which this is just a backwards-compatibility wrapper for. Or, use '.onHitGroundAuthority' if that is more appropriate to your use case.", false)] public event HitGroundDelegate onHitGround { add { onHitGroundAuthority += value; } remove { onHitGroundAuthority -= value; } } public event HitGroundDelegate onHitGroundAuthority; public event Action onMotorStart; public event MovementHitDelegate onMovementHit; private void UpdateInnerMotorEnabled() { base.Motor.enabled = enableMotorWithoutAuthority || hasEffectiveAuthority; } private void UpdateAuthority() { hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject); UpdateInnerMotorEnabled(); } private void Awake() { networkIdentity = GetComponent(); body = GetComponent(); capsuleCollider = GetComponent(); } private void Start() { previousPosition = base.transform.position; if (base.Motor == null) { SetupCharacterMotor(GetComponent()); } if (base.Motor.AttachedRigidbody != null) { base.Motor.AttachedRigidbody.mass = mass; } base.Motor.MaxStableSlopeAngle = 70f; base.Motor.MaxStableDenivelationAngle = 55f; base.Motor.RebuildCollidableLayers(); if (generateParametersOnAwake) { GenerateParameters(); } useGravity = gravityParameters.CheckShouldUseGravity(); isFlying = flightParameters.CheckShouldUseFlight(); UpdateAuthority(); this.onMotorStart?.Invoke(body); } public override void OnStartAuthority() { UpdateAuthority(); } public override void OnStopAuthority() { UpdateAuthority(); } private void OnEnable() { UpdateInnerMotorEnabled(); } private void OnDisable() { base.Motor.enabled = false; } private void PreMove(float deltaTime) { if (!hasEffectiveAuthority) { return; } float num = acceleration; if (isAirControlForced || !isGrounded) { num *= (disableAirControlUntilCollision ? 0f : airControl); } UnityEngine.Vector3 vector = moveDirection; if (!isFlying) { vector.y = 0f; } if (body.isSprinting) { float magnitude = vector.magnitude; if (magnitude < 1f && magnitude > 0f) { float num2 = 1f / vector.magnitude; vector *= num2; } } UnityEngine.Vector3 target = vector * walkSpeed; if (!isFlying) { target.y = velocity.y; } velocity = UnityEngine.Vector3.MoveTowards(velocity, target, num * deltaTime); if (useGravity) { ref float y = ref velocity.y; y += Physics.gravity.y * deltaTime; if (isGrounded) { y = Mathf.Max(y, 0f); } } } public void OnDeathStart() { alive = false; } private void FixedUpdate() { float fixedDeltaTime = Time.fixedDeltaTime; if (fixedDeltaTime != 0f) { UnityEngine.Vector3 position = base.transform.position; if ((previousPosition - position).sqrMagnitude < 0.00062500004f * fixedDeltaTime) { restStopwatch += fixedDeltaTime; } else { restStopwatch = 0f; } previousPosition = position; if (netIsGrounded) { lastGroundedTime = Run.FixedTimeStamp.now; } } } private void GenerateParameters() { slopeLimit = 70f; stepOffset = Mathf.Min(capsuleHeight * 0.1f, 0.2f); stepHandlingMethod = StepHandlingMethod.None; ledgeHandling = false; interactiveRigidbodyHandling = true; } public void ApplyForce(UnityEngine.Vector3 force, bool alwaysApply = false, bool disableAirControlUntilCollision = false) { PhysForceInfo forceInfo = PhysForceInfo.Create(); forceInfo.force = force; forceInfo.ignoreGroundStick = alwaysApply; forceInfo.disableAirControlUntilCollision = disableAirControlUntilCollision; forceInfo.massIsOne = false; ApplyForceImpulse(in forceInfo); } public void ApplyForceImpulse(in PhysForceInfo forceInfo) { if (NetworkServer.active && !hasEffectiveAuthority) { CallRpcApplyForceImpulse(forceInfo); return; } UnityEngine.Vector3 force = forceInfo.force; if (!forceInfo.massIsOne) { _ = force.magnitude; force *= 1f / mass; } if (mass != 0f) { if (force.y < 6f && isGrounded && !forceInfo.ignoreGroundStick) { force.y = 0f; } if (force.y > 0f) { base.Motor.ForceUnground(); } velocity += force; if (forceInfo.disableAirControlUntilCollision) { disableAirControlUntilCollision = true; } } } [ClientRpc] private void RpcApplyForceImpulse(PhysForceInfo physForceInfo) { if (!NetworkServer.active) { ApplyForceImpulse(in physForceInfo); } } public override void UpdateRotation(ref UnityEngine.Quaternion currentRotation, float deltaTime) { currentRotation = UnityEngine.Quaternion.identity; } public override void UpdateVelocity(ref UnityEngine.Vector3 currentVelocity, float deltaTime) { currentVelocity = velocity; } public override void BeforeCharacterUpdate(float deltaTime) { _ = cvCMotorSafeCollisionStepThreshold.value; _ = cvCMotorSafeCollisionStepThreshold.value; if (rootMotion != UnityEngine.Vector3.zero) { UnityEngine.Vector3 vector = rootMotion; rootMotion = UnityEngine.Vector3.zero; base.Motor.MoveCharacter(base.transform.position + vector); } PreMove(deltaTime); _ = (velocity * deltaTime).sqrMagnitude; } public override void PostGroundingUpdate(float deltaTime) { if (base.Motor.GroundingStatus.IsStableOnGround != base.Motor.LastGroundingStatus.IsStableOnGround) { netIsGrounded = base.Motor.GroundingStatus.IsStableOnGround; if (base.Motor.GroundingStatus.IsStableOnGround) { OnLanded(); } else { OnLeaveStableGround(); } } } private void OnLanded() { jumpCount = 0; HitGroundInfo hitGroundInfo = default(HitGroundInfo); hitGroundInfo.velocity = lastVelocity; hitGroundInfo.position = base.Motor.GroundingStatus.GroundPoint; hitGroundInfo.isValidForEffect = Run.FixedTimeStamp.now - lastGroundedTime > 0.2f; HitGroundInfo hitGroundInfo2 = hitGroundInfo; if (hasEffectiveAuthority) { try { this.onHitGroundAuthority?.Invoke(ref hitGroundInfo2); } catch (Exception message) { UnityEngine.Debug.LogError(message); } if (NetworkServer.active) { GlobalEventManager.instance.OnCharacterHitGroundServer(body, hitGroundInfo2); } else { CallCmdReportHitGround(hitGroundInfo2); } } } [ClientRpc] public void RpcOnHitGroundSFX(HitGroundInfo hitGroundInfo, bool tookFallDamage) { if (!NetworkServer.active) { GlobalEventManager.instance.OnCharacterHitGroundSFX(body, hitGroundInfo, tookFallDamage); } } [Command] private void CmdReportHitGround(HitGroundInfo hitGroundInfo) { GlobalEventManager.instance.OnCharacterHitGroundServer(body, hitGroundInfo); } private void OnLeaveStableGround() { if (jumpCount < 1) { jumpCount = 1; } body.SetInLava(b: false); } public override void AfterCharacterUpdate(float deltaTime) { lastVelocity = velocity; velocity = base.Motor.BaseVelocity; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool IsColliderValidForCollisions(Collider coll) { if (!coll.isTrigger) { return coll != base.Motor.Capsule; } return false; } public override void OnGroundHit(Collider hitCollider, UnityEngine.Vector3 hitNormal, UnityEngine.Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { isAirControlForced = false; SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitCollider, hitPoint); if ((bool)objectSurfaceDef) { isAirControlForced = objectSurfaceDef.isSlippery; body.SetInLava(objectSurfaceDef.isLava); } } public override void OnMovementHit(Collider hitCollider, UnityEngine.Vector3 hitNormal, UnityEngine.Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { disableAirControlUntilCollision = false; if (this.onMovementHit != null) { MovementHitInfo movementHitInfo = default(MovementHitInfo); movementHitInfo.velocity = velocity; movementHitInfo.hitCollider = hitCollider; MovementHitInfo movementHitInfo2 = movementHitInfo; this.onMovementHit(ref movementHitInfo2); SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitCollider, hitPoint); if ((bool)objectSurfaceDef) { body.SetInLava(objectSurfaceDef.isLava); } } } public override void ProcessHitStabilityReport(Collider hitCollider, UnityEngine.Vector3 hitNormal, UnityEngine.Vector3 hitPoint, UnityEngine.Vector3 atCharacterPosition, UnityEngine.Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) { } public void Jump(float horizontalMultiplier, float verticalMultiplier, bool vault = false) { UnityEngine.Vector3 vector = moveDirection; if (vault) { velocity = vector; } else { vector.y = 0f; float magnitude = vector.magnitude; if (magnitude > 0f) { vector /= magnitude; } UnityEngine.Vector3 vector2 = vector * body.moveSpeed * horizontalMultiplier; vector2.y = body.jumpPower * verticalMultiplier; velocity = vector2; } base.Motor.ForceUnground(); } public void AddDisplacement(UnityEngine.Vector3 displacement) { rootMotion += displacement; } static CharacterMotor() { enableMotorWithoutAuthority = false; cvCMotorSafeCollisionStepThreshold = new FloatConVar("cmotor_safe_collision_step_threshold", ConVarFlags.Cheat, 1.0833334f.ToString(CultureInfo.InvariantCulture), "How large of a movement in meters/fixedTimeStep is needed to trigger more expensive \"safe\" collisions to prevent tunneling."); kCmdCmdReportHitGround = 1796547162; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterMotor), kCmdCmdReportHitGround, InvokeCmdCmdReportHitGround); kRpcRpcApplyForceImpulse = 1042934326; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMotor), kRpcRpcApplyForceImpulse, InvokeRpcRpcApplyForceImpulse); kRpcRpcOnHitGroundSFX = -1661136052; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMotor), kRpcRpcOnHitGroundSFX, InvokeRpcRpcOnHitGroundSFX); NetworkCRC.RegisterBehaviour("CharacterMotor", 0); } void IPhysMotor.ApplyForceImpulse(in PhysForceInfo physForceInfo) { ApplyForceImpulse(in physForceInfo); } private void UNetVersion() { } protected static void InvokeCmdCmdReportHitGround(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdReportHitGround called on client."); } else { ((CharacterMotor)obj).CmdReportHitGround(GeneratedNetworkCode._ReadHitGroundInfo_CharacterMotor(reader)); } } public void CallCmdReportHitGround(HitGroundInfo hitGroundInfo) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdReportHitGround called on server."); return; } if (base.isServer) { CmdReportHitGround(hitGroundInfo); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdReportHitGround); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WriteHitGroundInfo_CharacterMotor(networkWriter, hitGroundInfo); SendCommandInternal(networkWriter, 0, "CmdReportHitGround"); } protected static void InvokeRpcRpcApplyForceImpulse(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcApplyForceImpulse called on server."); } else { ((CharacterMotor)obj).RpcApplyForceImpulse(GeneratedNetworkCode._ReadPhysForceInfo_None(reader)); } } protected static void InvokeRpcRpcOnHitGroundSFX(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcOnHitGroundSFX called on server."); } else { ((CharacterMotor)obj).RpcOnHitGroundSFX(GeneratedNetworkCode._ReadHitGroundInfo_CharacterMotor(reader), reader.ReadBoolean()); } } public void CallRpcApplyForceImpulse(PhysForceInfo physForceInfo) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcApplyForceImpulse called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcApplyForceImpulse); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WritePhysForceInfo_None(networkWriter, physForceInfo); SendRPCInternal(networkWriter, 0, "RpcApplyForceImpulse"); } public void CallRpcOnHitGroundSFX(HitGroundInfo hitGroundInfo, bool tookFallDamage) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcOnHitGroundSFX called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnHitGroundSFX); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WriteHitGroundInfo_CharacterMotor(networkWriter, hitGroundInfo); networkWriter.Write(tookFallDamage); SendRPCInternal(networkWriter, 0, "RpcOnHitGroundSFX"); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool flag = base.OnSerialize(writer, forceAll); bool flag2 = default(bool); return flag2 || flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { base.OnDeserialize(reader, initialState); } public override void PreStartClient() { base.PreStartClient(); } } public class CharacterSelectSurvivorPreviewDisplayController : MonoBehaviour { [Serializable] public struct SkillChangeResponse { public SkillFamily triggerSkillFamily; public SkillDef triggerSkill; public UnityEvent response; } [Serializable] public struct SkinChangeResponse { public SkinDef triggerSkin; public UnityEvent response; } public GameObject bodyPrefab; public SkillChangeResponse[] skillChangeResponses; public SkinChangeResponse[] skinChangeResponses; private Loadout currentLoadout; public NetworkUser networkUser { get; set; } private void OnEnable() { currentLoadout = Loadout.RequestInstance(); NetworkUser.onLoadoutChangedGlobal += OnLoadoutChangedGlobal; RoR2Application.onNextUpdate += Refresh; RunDefaultResponses(); } private void OnDisable() { NetworkUser.onLoadoutChangedGlobal -= OnLoadoutChangedGlobal; currentLoadout = Loadout.ReturnInstance(currentLoadout); } private static int FindSkillSlotIndex(BodyIndex bodyIndex, SkillFamily skillFamily) { GenericSkill[] bodyPrefabSkillSlots = BodyCatalog.GetBodyPrefabSkillSlots(bodyIndex); for (int i = 0; i < bodyPrefabSkillSlots.Length; i++) { if (bodyPrefabSkillSlots[i].skillFamily == skillFamily) { return i; } } return -1; } private static int FindVariantIndex(SkillFamily skillFamily, SkillDef skillDef) { SkillFamily.Variant[] variants = skillFamily.variants; for (int i = 0; i < variants.Length; i++) { if (variants[i].skillDef == skillDef) { return i; } } return -1; } private static bool HasSkillVariantEnabled(Loadout loadout, BodyIndex bodyIndex, SkillFamily skillFamily, SkillDef skillDef) { int num = FindSkillSlotIndex(bodyIndex, skillFamily); int num2 = FindVariantIndex(skillFamily, skillDef); if (num == -1 || num2 == -1) { return false; } return loadout.bodyLoadoutManager.GetSkillVariant(bodyIndex, num) == num2; } private void Refresh() { if ((bool)this && (bool)networkUser) { OnLoadoutChangedGlobal(networkUser); } } private void OnLoadoutChangedGlobal(NetworkUser changedNetworkUser) { if (changedNetworkUser != networkUser) { return; } Loadout loadout = Loadout.RequestInstance(); changedNetworkUser.networkLoadout.CopyLoadout(loadout); BodyIndex bodyIndex = BodyCatalog.FindBodyIndex(bodyPrefab); if (bodyIndex == BodyIndex.None) { return; } SkillChangeResponse[] array = skillChangeResponses; for (int i = 0; i < array.Length; i++) { SkillChangeResponse skillChangeResponse = array[i]; bool num = HasSkillVariantEnabled(currentLoadout, bodyIndex, skillChangeResponse.triggerSkillFamily, skillChangeResponse.triggerSkill); bool flag = HasSkillVariantEnabled(loadout, bodyIndex, skillChangeResponse.triggerSkillFamily, skillChangeResponse.triggerSkill); if (!num && flag) { skillChangeResponse.response?.Invoke(); } } SkinChangeResponse[] array2 = skinChangeResponses; for (int i = 0; i < array2.Length; i++) { SkinChangeResponse skinChangeResponse = array2[i]; uint num2 = (uint)SkinCatalog.FindLocalSkinIndexForBody(bodyIndex, skinChangeResponse.triggerSkin); uint skinIndex = currentLoadout.bodyLoadoutManager.GetSkinIndex(bodyIndex); uint skinIndex2 = loadout.bodyLoadoutManager.GetSkinIndex(bodyIndex); if (skinIndex != skinIndex2 && skinIndex2 == num2) { skinChangeResponse.response?.Invoke(); } } loadout.Copy(currentLoadout); Loadout.ReturnInstance(loadout); } private void RunDefaultResponses() { BodyIndex bodyIndex = BodyCatalog.FindBodyIndex(bodyPrefab); if (bodyIndex == BodyIndex.None) { return; } SkillChangeResponse[] array = skillChangeResponses; for (int i = 0; i < array.Length; i++) { SkillChangeResponse skillChangeResponse = array[i]; if (HasSkillVariantEnabled(currentLoadout, bodyIndex, skillChangeResponse.triggerSkillFamily, skillChangeResponse.triggerSkill)) { skillChangeResponse.response?.Invoke(); } } SkinChangeResponse[] array2 = skinChangeResponses; for (int i = 0; i < array2.Length; i++) { SkinChangeResponse skinChangeResponse = array2[i]; uint num = (uint)SkinCatalog.FindLocalSkinIndexForBody(bodyIndex, skinChangeResponse.triggerSkin); if (currentLoadout.bodyLoadoutManager.GetSkinIndex(bodyIndex) == num) { skinChangeResponse.response?.Invoke(); } } } } public interface IChestBehavior { bool HasRolledPickup(PickupIndex pickupIndex); void Roll(); void ItemDrop(); } public class ChestBehavior : NetworkBehaviour, IChestBehavior { public PickupDropTable dropTable; public Transform dropTransform; public float dropUpVelocityStrength = 20f; public float dropForwardVelocityStrength = 2f; public int minDropCount = 1; public int maxDropCount = 1; public SerializableEntityStateType openState = new SerializableEntityStateType(typeof(EntityStates.Barrel.Opening)); public SerializableEntityStateType closingState = new SerializableEntityStateType(typeof(Closing)); [Tooltip("Deprecated. Use DropTable instead.")] [Header("Deprecated")] public float tier1Chance = 0.8f; [Tooltip("Deprecated. Use DropTable instead.")] public float tier2Chance = 0.2f; [Tooltip("Deprecated. Use DropTable instead.")] public float tier3Chance = 0.01f; [Tooltip("Deprecated. Use DropTable instead.")] public float lunarChance; [Tooltip("Deprecated. Use DropTable instead.")] public ItemTag requiredItemTag; [Tooltip("Deprecated. Use DropTable instead.")] public float lunarCoinChance; [Tooltip("Deprecated. Use DropTable instead.")] public UnityEvent dropRoller; private Xoroshiro128Plus rng; public int dropCount; [SyncVar] public bool isCommandChest; [SyncVar] private bool isChestOpened; [HideInInspector] public PickupPickerController ppc; private static int kRpcRpcResetChests; private static int kRpcRpcSetDelusionPickupIndex; public PickupIndex dropPickup { get; private set; } = PickupIndex.none; public bool NetworkisCommandChest { get { return isCommandChest; } [param: In] set { SetSyncVar(value, ref isCommandChest, 1u); } } public bool NetworkisChestOpened { get { return isChestOpened; } [param: In] set { SetSyncVar(value, ref isChestOpened, 2u); } } public override int GetNetworkChannel() { return QosChannelIndex.defaultReliable.intVal; } [Server] public void Roll() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::Roll()' called on client"); } else if ((bool)dropTable) { dropPickup = dropTable.GenerateDrop(rng); } else { dropRoller?.Invoke(); } } public PickupIndex GetRandomPickupIndex() { return dropTable.GenerateDrop(rng); } [Server] private void PickFromList(List dropList) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::PickFromList(System.Collections.Generic.List`1)' called on client"); return; } dropPickup = PickupIndex.none; if (dropList != null && dropList.Count > 0) { dropPickup = rng.NextElementUniform(dropList); } } [Server] [Obsolete("Just use a drop table")] public void RollItem() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::RollItem()' called on client"); return; } WeightedSelection> selector = new WeightedSelection>(); List sourceDropList2 = new List { PickupCatalog.FindPickupIndex(RoR2Content.MiscPickups.LunarCoin.miscPickupIndex) }; Add(Run.instance.availableTier1DropList, tier1Chance); Add(Run.instance.availableTier2DropList, tier2Chance); Add(Run.instance.availableTier3DropList, tier3Chance); Add(Run.instance.availableLunarCombinedDropList, lunarChance); Add(sourceDropList2, lunarCoinChance); List dropList = selector.Evaluate(rng.nextNormalizedFloat); PickFromList(dropList); void Add(List sourceDropList, float chance) { if (!(chance <= 0f)) { selector.AddChoice(sourceDropList.Where(PassesFilter).ToList(), chance); } } bool PassesFilter(PickupIndex pickupIndex) { if (requiredItemTag == ItemTag.Any) { return true; } PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef.itemIndex != ItemIndex.None) { return ItemCatalog.GetItemDef(pickupDef.itemIndex).ContainsTag(requiredItemTag); } return true; } } [Server] [Obsolete("Just use a drop table")] public void RollEquipment() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::RollEquipment()' called on client"); } else { PickFromList(Run.instance.availableEquipmentDropList); } } private void Awake() { if (dropTransform == null) { dropTransform = base.transform; } } private void Start() { if (NetworkServer.active) { rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); dropCount = rng.RangeInt(minDropCount, Math.Max(minDropCount + 1, maxDropCount + 1)); Roll(); } } public void OnEnable() { InstanceTracker.Add(this); } public void OnDisable() { InstanceTracker.Remove(this); } [Server] public void Open() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::Open()' called on client"); return; } EntityStateMachine component = GetComponent(); if ((bool)component) { component.SetNextState(EntityStateCatalog.InstantiateState(ref openState)); } } [ClientRpc] public void RpcResetChests() { if (TryGetComponent(out var component) && isChestOpened) { component.ResetChestForDelusion(); } } [ClientRpc] public void RpcSetDelusionPickupIndex(PickupIndex pickupIndex) { if (TryGetComponent(out var component)) { component.DelusionPickupIndex = pickupIndex; } } [Server] public void ItemDrop() { DelusionChestController component; if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::ItemDrop()' called on client"); } else if (DelusionChestController.isDelusionEnable && TryGetComponent(out component) && component.SelectedPickupIndex != PickupIndex.none) { if (component.IsSelectedCorrectly()) { Util.PlaySound("Play_ui_artifact_delusion_success", base.gameObject); DelusionItemDrop(); } else { Util.PlaySound("Play_ui_artifact_delusion_failure", base.gameObject); component.RemoveDelusionChoice(); } } else { BaseItemDrop(); } } private void DelusionItemDrop(DelusionChestController delusionChestController) { if (delusionChestController.isDelusionSelected) { if (delusionChestController.IsSelectedCorrectly()) { UnityEngine.Vector3 velocity = UnityEngine.Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength; GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo); createPickupInfo.pickupIndex = delusionChestController.DelusionPickupIndex; createPickupInfo.position = dropTransform.position + UnityEngine.Vector3.up * 1.5f; createPickupInfo.chest = this; createPickupInfo.artifactFlag = GenericPickupController.PickupArtifactFlag.DELUSION; GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo; PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, velocity); Util.PlaySound("Play_ui_artifact_delusion_success", base.gameObject); } else { Util.PlaySound("Play_ui_artifact_delusion_failure", base.gameObject); delusionChestController.RemoveDelusionChoice(); } } } private void DelusionItemDrop() { if (TryGetComponent(out var component) && component.SelectedPickupIndex == component.DelusionPickupIndex) { UnityEngine.Vector3 velocity = UnityEngine.Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength; PickupDropletController.CreatePickupDroplet(component.DelusionPickupIndex, dropTransform.position + UnityEngine.Vector3.up * 1.5f, velocity); } } private void BaseItemDrop() { if (!(dropPickup == PickupIndex.none) && dropCount >= 1) { float angle = 360f / (float)dropCount; UnityEngine.Vector3 vector = UnityEngine.Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength; UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); GetComponent(); for (int i = 0; i < dropCount; i++) { GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo); createPickupInfo.pickupIndex = dropPickup; createPickupInfo.position = dropTransform.position + UnityEngine.Vector3.up * 1.5f; createPickupInfo.chest = this; createPickupInfo.artifactFlag = (isCommandChest ? GenericPickupController.PickupArtifactFlag.COMMAND : GenericPickupController.PickupArtifactFlag.NONE); GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo; PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, vector); vector = quaternion * vector; Roll(); } dropPickup = PickupIndex.none; NetworkisChestOpened = true; } } public bool HasRolledPickup(PickupIndex pickupIndex) { return dropPickup == pickupIndex; } private void UNetVersion() { } protected static void InvokeRpcRpcResetChests(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcResetChests called on server."); } else { ((ChestBehavior)obj).RpcResetChests(); } } protected static void InvokeRpcRpcSetDelusionPickupIndex(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcSetDelusionPickupIndex called on server."); } else { ((ChestBehavior)obj).RpcSetDelusionPickupIndex(GeneratedNetworkCode._ReadPickupIndex_None(reader)); } } public void CallRpcResetChests() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcResetChests called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcResetChests); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcResetChests"); } public void CallRpcSetDelusionPickupIndex(PickupIndex pickupIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcSetDelusionPickupIndex called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcSetDelusionPickupIndex); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WritePickupIndex_None(networkWriter, pickupIndex); SendRPCInternal(networkWriter, 0, "RpcSetDelusionPickupIndex"); } static ChestBehavior() { kRpcRpcResetChests = -115962472; NetworkBehaviour.RegisterRpcDelegate(typeof(ChestBehavior), kRpcRpcResetChests, InvokeRpcRpcResetChests); kRpcRpcSetDelusionPickupIndex = -2130336578; NetworkBehaviour.RegisterRpcDelegate(typeof(ChestBehavior), kRpcRpcSetDelusionPickupIndex, InvokeRpcRpcSetDelusionPickupIndex); NetworkCRC.RegisterBehaviour("ChestBehavior", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(isCommandChest); writer.Write(isChestOpened); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(isCommandChest); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(isChestOpened); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { isCommandChest = reader.ReadBoolean(); isChestOpened = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { isCommandChest = reader.ReadBoolean(); } if (((uint)num & 2u) != 0) { isChestOpened = reader.ReadBoolean(); } } public override void PreStartClient() { } } public class ChestRevealer : NetworkBehaviour { private struct PendingReveal : IComparable { public GameObject gameObject; public Run.FixedTimeStamp time; public float duration; public int CompareTo(PendingReveal other) { return time.CompareTo(other.time); } } private class RevealedObject : MonoBehaviour { private float lifetime; private static readonly Dictionary currentlyRevealedObjects = new Dictionary(); private PositionIndicator positionIndicator; public static void RevealObject(GameObject gameObject, float duration) { if (!currentlyRevealedObjects.TryGetValue(gameObject, out var value)) { value = gameObject.AddComponent(); } if (value.lifetime < duration) { value.lifetime = duration; } } private void OnEnable() { GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/PositionIndicators/PoiPositionIndicator"), base.transform.position, base.transform.rotation); positionIndicator = gameObject.GetComponent(); positionIndicator.insideViewObject.GetComponent().sprite = PingIndicator.GetInteractableIcon(base.gameObject); positionIndicator.targetTransform = base.transform; currentlyRevealedObjects[base.gameObject] = this; } private void OnDisable() { currentlyRevealedObjects.Remove(base.gameObject); if ((bool)positionIndicator) { UnityEngine.Object.Destroy(positionIndicator.gameObject); } positionIndicator = null; } private void FixedUpdate() { lifetime -= Time.fixedDeltaTime; if (lifetime <= 0f) { UnityEngine.Object.Destroy(this); } } } [SyncVar] public float radius; public float pulseTravelSpeed = 10f; public float revealDuration = 10f; public float pulseInterval = 1f; private Run.FixedTimeStamp nextPulse = Run.FixedTimeStamp.negativeInfinity; public GameObject pulseEffectPrefab; public float pulseEffectScale = 1f; private static readonly List pendingReveals = new List(); private static Type[] typesToCheck; public float Networkradius { get { return radius; } [param: In] set { SetSyncVar(value, ref radius, 1u); } } [InitDuringStartup] private static void Init() { RoR2Application.onFixedUpdate += StaticFixedUpdate; typesToCheck = (from t in typeof(ChestRevealer).Assembly.GetTypes() where typeof(IInteractable).IsAssignableFrom(t) select t).ToArray(); } private static void StaticFixedUpdate() { pendingReveals.Sort(); while (pendingReveals.Count > 0) { PendingReveal pendingReveal = pendingReveals[0]; if (pendingReveal.time.hasPassed) { if ((bool)pendingReveal.gameObject) { RevealedObject.RevealObject(pendingReveal.gameObject, pendingReveal.duration); } pendingReveals.RemoveAt(0); continue; } break; } } public void Pulse() { UnityEngine.Vector3 origin = base.transform.position; float radiusSqr = radius * radius; float invPulseTravelSpeed = 1f / pulseTravelSpeed; Type[] array = typesToCheck; for (int i = 0; i < array.Length; i++) { foreach (MonoBehaviour item2 in InstanceTracker.FindInstancesEnumerable(array[i])) { if (((IInteractable)item2).ShouldShowOnScanner()) { TryAddRevealable(item2.transform); } } } EffectManager.SpawnEffect(pulseEffectPrefab, new EffectData { origin = origin, scale = radius * pulseEffectScale }, transmit: false); void TryAddRevealable(Transform revealableTransform) { float sqrMagnitude = (revealableTransform.position - origin).sqrMagnitude; if (!(sqrMagnitude > radiusSqr)) { float num = Mathf.Sqrt(sqrMagnitude) * invPulseTravelSpeed; PendingReveal pendingReveal = default(PendingReveal); pendingReveal.gameObject = revealableTransform.gameObject; pendingReveal.time = Run.FixedTimeStamp.now + num; pendingReveal.duration = revealDuration; PendingReveal item = pendingReveal; pendingReveals.Add(item); } } } private void FixedUpdate() { if (nextPulse.hasPassed) { Pulse(); nextPulse = Run.FixedTimeStamp.now + pulseInterval; } } 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() { } } public class ChildLocatorMirrorController : MonoBehaviour { private class MirrorPair { public Transform referenceTransform; public Transform targetTransform; } [SerializeField] [Tooltip("The ChildLocator we are using are a reference to GET the transform information")] private ChildLocator _referenceLocator; [SerializeField] [Tooltip("The ChildLocator we are targeting to SET the transform information")] private ChildLocator _targetLocator; private List mirrorPairs = new List(); public ChildLocator referenceLocator { get { return _referenceLocator; } set { _referenceLocator = value; mirrorPairs.Clear(); if ((bool)_referenceLocator && (bool)_targetLocator) { RebuildMirrorPairs(); } } } public ChildLocator targetLocator { get { return _targetLocator; } set { _targetLocator = value; mirrorPairs.Clear(); if ((bool)_referenceLocator && (bool)_targetLocator) { RebuildMirrorPairs(); } } } private void Start() { if ((bool)_referenceLocator && (bool)_targetLocator) { RebuildMirrorPairs(); } } private void FixedUpdate() { foreach (MirrorPair mirrorPair in mirrorPairs) { if ((bool)mirrorPair.referenceTransform && (bool)mirrorPair.targetTransform) { mirrorPair.targetTransform.position = mirrorPair.referenceTransform.position; mirrorPair.targetTransform.rotation = mirrorPair.referenceTransform.rotation; } } } private void RebuildMirrorPairs() { mirrorPairs.Clear(); for (int i = 0; i < _targetLocator.Count; i++) { string childName = _targetLocator.FindChildName(i); Transform transform = _targetLocator.FindChild(i); Transform transform2 = _referenceLocator.FindChild(childName); if ((bool)transform && (bool)transform2) { mirrorPairs.Add(new MirrorPair { targetTransform = transform, referenceTransform = transform2 }); } } } } [RequireComponent(typeof(SceneInfo))] public class ClassicStageInfo : MonoBehaviour { [Serializable] public struct BonusInteractibleCreditObject { public GameObject objectThatGrantsPointsIfEnabled; public int points; } [Serializable] public struct MonsterFamily { [SerializeField] public DirectorCardCategorySelection monsterFamilyCategories; public string familySelectionChatString; public float selectionWeight; public int minimumStageCompletion; public int maximumStageCompletion; } private DirectorCardCategorySelection modifiableMonsterCategories; [Tooltip("We'll select a single DCCS from this pool when we enter the stage to determine which monsters can spawn.")] [SerializeField] private DccsPool monsterDccsPool; [Tooltip("We'll select a single DCCS from this pool when we enter the stage to determine which interactables can spawn.")] [SerializeField] private DccsPool interactableDccsPool; private ulong seedServer; private Xoroshiro128Plus rng; public int sceneDirectorInteractibleCredits = 200; public int sceneDirectorMonsterCredits = 20; public BonusInteractibleCreditObject[] bonusInteractibleCreditObjects; public static float monsterFamilyChance = 0.02f; [SerializeField] [HideInInspector] private DirectorCard[] monsterCards; [SerializeField] [HideInInspector] public DirectorCard[] interactableCards; [CanBeNull] [ShowFieldObsolete] [Tooltip("Deprecated. Use MonsterDccsPool instead.")] public DirectorCardCategorySelection interactableCategories; [ShowFieldObsolete] [CanBeNull] [SerializeField] [Tooltip("Deprecated. Use MonsterDccsPool instead.")] private DirectorCardCategorySelection monsterCategories; [ShowFieldObsolete] [Tooltip("Deprecated. Use MonsterDccsPool instead.")] public MonsterFamily[] possibleMonsterFamilies; public WeightedSelection monsterSelection { get; private set; } public static ClassicStageInfo instance { get; private set; } internal DccsPool GetMonsterDccsPool => monsterDccsPool; internal DccsPool GetInteractableDccsPool => interactableDccsPool; private static void HandleSingleMonsterTypeArtifact(DirectorCardCategorySelection monsterCategories, Xoroshiro128Plus rng) { ScriptableObject.CreateInstance().CopyFrom(monsterCategories); float baseCredits = 40f * Run.instance.difficultyCoefficient; int maximumNumberToSpawnBeforeSkipping = 5; int minimumToSpawn = 1; if (SceneCatalog.mostRecentSceneDef == SceneCatalog.FindSceneDef("arena")) { baseCredits = 50f * Run.instance.difficultyCoefficient; maximumNumberToSpawnBeforeSkipping = 6; minimumToSpawn = 2; } WeightedSelection candidatesSelection = new WeightedSelection(); AddCardsWhichPassCondition(CardIsAffordable); if (candidatesSelection.Count == 0) { AddCardsWhichPassCondition(ReturnTrue); } if (candidatesSelection.Count == 0) { UnityEngine.Debug.LogWarning("Could not collapse director card selection down to one, no cards passed the filters!"); return; } DirectorCard directorCard = candidatesSelection.Evaluate(rng.nextNormalizedFloat); monsterCategories.Clear(); int categoryIndex = monsterCategories.AddCategory("Basic Monsters", 1f); monsterCategories.AddCard(categoryIndex, directorCard); BodyIndex bodyIndex = directorCard.spawnCard.prefab.GetComponent().bodyPrefab.GetComponent().bodyIndex; if ((bool)Stage.instance) { SetStageSingleMonsterType(Stage.instance); } else { Stage.onServerStageBegin += SetStageSingleMonsterType; } void AddCardsWhichPassCondition(Predicate predicate) { for (int i = 0; i < monsterCategories.categories.Length; i++) { ref DirectorCardCategorySelection.Category reference = ref monsterCategories.categories[i]; DirectorCard[] cards = reference.cards; float selectionWeight = reference.selectionWeight; for (int j = 0; j < cards.Length; j++) { DirectorCard directorCard2 = cards[j]; if (predicate(directorCard2)) { candidatesSelection.AddChoice(cards[j], selectionWeight * (float)directorCard2.selectionWeight); } } } } bool CardIsAffordable(DirectorCard card) { return Util.DirectorCardIsReasonableChoice(baseCredits, maximumNumberToSpawnBeforeSkipping, minimumToSpawn, card, CombatDirector.CalcHighestEliteCostMultiplier(card.spawnCard.eliteRules)); } static bool ReturnTrue(DirectorCard card) { return true; } void SetStageSingleMonsterType(Stage stage) { Stage.instance.singleMonsterTypeBodyIndex = bodyIndex; Stage.onServerStageBegin -= SetStageSingleMonsterType; } } private static void HandleMixEnemyArtifact(DirectorCardCategorySelection monsterCategories, Xoroshiro128Plus rng) { monsterCategories.CopyFrom(RoR2Content.mixEnemyMonsterCards); if (monsterCategories.categories.Length == 0) { UnityEngine.Debug.LogError("MixEnemy monster cards are size 0!"); } TrimCategory("Basic Monsters", 3); TrimCategory("Minibosses", 3); TrimCategory("Champions", 3); void TrimCategory(string categoryName, int requiredCount) { DirectorCardCategorySelection.Category[] categories = monsterCategories.categories; for (int j = 0; j < categories.Length; j++) { if (string.CompareOrdinal(categoryName, categories[j].name) == 0) { UnityEngine.Debug.LogFormat("Trimming {0} from {1} to {2}", categoryName, categories[j].cards.Length, requiredCount); TrimSelection(ref categories[j].cards, requiredCount); } } } void TrimSelection(ref DirectorCard[] cards, int requiredCount) { if (cards.Length > requiredCount) { DirectorCard[] array = ArrayUtils.Clone(cards); Util.ShuffleArray(array, rng); int num = array.Length - 1; while (num >= 0 && array.Length > requiredCount) { if (!array[num].IsAvailable()) { ArrayUtils.ArrayRemoveAtAndResize(ref array, num); } num--; } if (array.Length > requiredCount) { Array.Resize(ref array, requiredCount); } cards = array; DirectorCard[] array2 = cards; foreach (DirectorCard directorCard in array2) { UnityEngine.Debug.LogFormat("Selected {0}", directorCard.spawnCard.name); } } } } private static bool DirectorCardDoesNotForbidElite(DirectorCard directorCard) { CharacterSpawnCard characterSpawnCard = directorCard.spawnCard as CharacterSpawnCard; if (!characterSpawnCard) { return true; } return !characterSpawnCard.noElites; } private void Awake() { if (NetworkServer.active) { seedServer = Run.instance.stageRng.nextUlong; rng = new Xoroshiro128Plus(seedServer); } } private void Start() { RebuildCards(); RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled; RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled; } private void OnDestroy() { RunArtifactManager.onArtifactEnabledGlobal -= OnArtifactEnabled; RunArtifactManager.onArtifactDisabledGlobal -= OnArtifactDisabled; if ((bool)modifiableMonsterCategories) { UnityEngine.Object.Destroy(modifiableMonsterCategories); } } public IEnumerator BroadcastFamilySelection(string familySelectionChatString) { yield return new WaitForSeconds(1f); Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = familySelectionChatString }); } private void OnEnable() { instance = this; } private void OnDisable() { instance = null; } private static float CalculateTotalWeight(DirectorCard[] cards) { float num = 0f; foreach (DirectorCard directorCard in cards) { num += (float)directorCard.selectionWeight; } return num; } internal void RebuildCards(DirectorCardCategorySelection forcedMonsterCategory = null, DirectorCardCategorySelection forcedInteractableCategory = null) { Xoroshiro128Plus xoroshiro128Plus = new Xoroshiro128Plus(seedServer); Xoroshiro128Plus xoroshiro128Plus2 = new Xoroshiro128Plus(xoroshiro128Plus.nextUlong); Xoroshiro128Plus xoroshiro128Plus3 = new Xoroshiro128Plus(xoroshiro128Plus.nextUlong); Xoroshiro128Plus xoroshiro128Plus4 = new Xoroshiro128Plus(xoroshiro128Plus.nextUlong); Xoroshiro128Plus xoroshiro128Plus5 = new Xoroshiro128Plus(xoroshiro128Plus.nextUlong); if (forcedInteractableCategory != null) { forcedInteractableCategory.OnSelected(this); interactableCategories = forcedInteractableCategory; } else if ((bool)interactableDccsPool) { DirectorCardCategorySelection directorCardCategorySelection = interactableDccsPool.GenerateWeightedSelection().Evaluate(xoroshiro128Plus5.nextNormalizedFloat); if (directorCardCategorySelection != null) { directorCardCategorySelection.OnSelected(this); interactableCategories = directorCardCategorySelection; } } DirectorCardCategorySelection directorCardCategorySelection2 = null; if ((bool)monsterDccsPool) { DirectorCardCategorySelection directorCardCategorySelection3 = monsterDccsPool.GenerateWeightedSelection().Evaluate(xoroshiro128Plus5.nextNormalizedFloat); if (directorCardCategorySelection3 != null) { directorCardCategorySelection3.OnSelected(this); directorCardCategorySelection2 = UnityEngine.Object.Instantiate(directorCardCategorySelection3); } } else if ((bool)monsterCategories) { directorCardCategorySelection2 = UnityEngine.Object.Instantiate(monsterCategories); } if (!directorCardCategorySelection2) { return; } UnityEngine.Object.Destroy(modifiableMonsterCategories); bool flag = RunArtifactManager.instance?.IsArtifactEnabled(RoR2Content.Artifacts.singleMonsterTypeArtifactDef) ?? false; bool num = RunArtifactManager.instance?.IsArtifactEnabled(RoR2Content.Artifacts.mixEnemyArtifactDef) ?? false; bool flag2 = RunArtifactManager.instance?.IsArtifactEnabled(RoR2Content.Artifacts.eliteOnlyArtifactDef) ?? false; modifiableMonsterCategories = directorCardCategorySelection2; if (num) { HandleMixEnemyArtifact(modifiableMonsterCategories, xoroshiro128Plus3); } else if (forcedMonsterCategory != null) { forcedMonsterCategory.OnSelected(this); modifiableMonsterCategories.CopyFrom(forcedMonsterCategory); } else if (!monsterDccsPool && xoroshiro128Plus4.nextNormalizedFloat <= monsterFamilyChance && possibleMonsterFamilies != null) { Run run = Run.instance; if ((object)run == null || run.canFamilyEventTrigger) { WeightedSelection weightedSelection = new WeightedSelection(); for (int i = 0; i < possibleMonsterFamilies.Length; i++) { MonsterFamily value = possibleMonsterFamilies[i]; if (Run.instance != null && value.minimumStageCompletion <= Run.instance.stageClearCount && value.maximumStageCompletion > Run.instance.stageClearCount) { weightedSelection.AddChoice(value, value.selectionWeight); } } if (weightedSelection.Count > 0) { MonsterFamily monsterFamily = weightedSelection.Evaluate(xoroshiro128Plus.nextNormalizedFloat); modifiableMonsterCategories.CopyFrom(monsterFamily.monsterFamilyCategories); StartCoroutine("BroadcastFamilySelection", monsterFamily.familySelectionChatString); } } } if (flag2) { modifiableMonsterCategories.RemoveCardsThatFailFilter(DirectorCardDoesNotForbidElite); } if (flag) { HandleSingleMonsterTypeArtifact(modifiableMonsterCategories, xoroshiro128Plus2); } monsterSelection = modifiableMonsterCategories.GenerateDirectorCardWeightedSelection(); } private void OnArtifactDisabled([NotNull] RunArtifactManager runArtifactManager, [NotNull] ArtifactDef artifactDef) { if ((object)artifactDef == RoR2Content.Artifacts.mixEnemyArtifactDef || (object)artifactDef == RoR2Content.Artifacts.singleMonsterTypeArtifactDef) { RebuildCards(); } } private void OnArtifactEnabled([NotNull] RunArtifactManager runArtifactManager, [NotNull] ArtifactDef artifactDef) { if ((object)artifactDef == RoR2Content.Artifacts.mixEnemyArtifactDef || (object)artifactDef == RoR2Content.Artifacts.singleMonsterTypeArtifactDef) { RebuildCards(); } } } public class CloverEffect : MonoBehaviour { public GameObject triggerEffect; private CharacterBody characterBody; private GameObject triggerEffectInstance; private bool trigger; private void Start() { CharacterBody body = GetComponentInParent().body; characterBody = body.GetComponent(); } private void FixedUpdate() { if ((bool)characterBody && characterBody.wasLucky) { characterBody.wasLucky = false; EffectData effectData = new EffectData(); effectData.origin = base.transform.position; effectData.rotation = base.transform.rotation; EffectManager.SpawnEffect(triggerEffect, effectData, transmit: true); } } } [RequireComponent(typeof(EffectComponent))] public class CoinBehavior : MonoBehaviour { [Serializable] public struct CoinTier { public ParticleSystem particleSystem; public int valuePerCoin; } public int originalCoinCount; public CoinTier[] coinTiers; private void Start() { originalCoinCount = (int)GetComponent().effectData.genericFloat; int num = originalCoinCount; for (int i = 0; i < coinTiers.Length; i++) { CoinTier coinTier = coinTiers[i]; int num2 = 0; while (num >= coinTier.valuePerCoin) { num -= coinTier.valuePerCoin; num2++; } if (num2 > 0) { ParticleSystem.EmissionModule emission = coinTier.particleSystem.emission; emission.enabled = true; emission.SetBursts(new ParticleSystem.Burst[1] { new ParticleSystem.Burst(0f, num2) }); coinTier.particleSystem.gameObject.SetActive(value: true); } } } } public class CombatDirector : MonoBehaviour { [Serializable] public class OnSpawnedServer : UnityEvent { } public class EliteTierDef { public float costMultiplier; public EliteDef[] eliteTypes; public Func isAvailable = (SpawnCard.EliteRules rules) => true; public bool canSelectWithoutAvailableEliteDef; private List availableDefs = new List(); public bool CanSelect(SpawnCard.EliteRules rules) { if (isAvailable(rules)) { if (!canSelectWithoutAvailableEliteDef) { return HasAnyAvailableEliteDefs(); } return true; } return false; } public bool HasAnyAvailableEliteDefs() { EliteDef[] array = eliteTypes; foreach (EliteDef eliteDef in array) { if ((bool)eliteDef && eliteDef.IsAvailable()) { return true; } } return false; } public EliteDef GetRandomAvailableEliteDef(Xoroshiro128Plus rng) { availableDefs.Clear(); EliteDef[] array = eliteTypes; foreach (EliteDef eliteDef in array) { if ((bool)eliteDef && eliteDef.IsAvailable()) { availableDefs.Add(eliteDef); } } if (availableDefs.Count > 0) { return rng.NextElementUniform(availableDefs); } return null; } } private class DirectorMoneyWave { public float interval; public float timer; public float multiplier; private float accumulatedAward; public float Update(float deltaTime, float difficultyCoefficient) { timer += deltaTime; if (timer > interval) { float num = 0.5f + (float)Run.instance.participatingPlayerCount * 0.5f; timer -= interval; float num2 = 1f; float num3 = 0.4f; accumulatedAward += interval * multiplier * (num2 + num3 * difficultyCoefficient) * num; } float num4 = Mathf.FloorToInt(accumulatedAward); accumulatedAward -= num4; return num4; } } [Header("Core Director Values")] public string customName; public float monsterCredit; [Tooltip("Monster credit that's been refunded from culling non-elite enemies. Can only be used to buy non-elite enemies.")] public float refundedMonsterCredit; public float expRewardCoefficient = 0.2f; public float goldRewardCoefficient = 1f; public float minSeriesSpawnInterval = 0.1f; public float maxSeriesSpawnInterval = 1f; public float minRerollSpawnInterval = 2.3333333f; public float maxRerollSpawnInterval = 4.3333335f; public RangeFloat[] moneyWaveIntervals; public TeamIndex teamIndex = TeamIndex.Monster; [Tooltip("How much to multiply money wave yield by.")] [Header("Optional Behaviors")] public float creditMultiplier = 1f; [Tooltip("The coefficient to multiply spawn distances. Used for combat shrines, to keep spawns nearby.")] public float spawnDistanceMultiplier = 1f; [Tooltip("The maximum distance at which enemies will spawn.")] public float maxSpawnDistance = float.PositiveInfinity; [Tooltip("Ensure that the minimum spawn distance is at least this many units away from the maxSpawnDistance")] public float minSpawnRange; public bool shouldSpawnOneWave; public bool targetPlayers = true; public bool skipSpawnIfTooCheap = true; [Tooltip("If skipSpawnIfTooCheap is true, we'll behave as though it's not set after this many consecutive skips")] public int maxConsecutiveCheapSkips = int.MaxValue; public bool resetMonsterCardIfFailed = true; public int maximumNumberToSpawnBeforeSkipping = 6; public float eliteBias = 1f; public OnSpawnedServer onSpawnedServer; [FormerlySerializedAs("_combatSquad")] public CombatSquad combatSquad; [Tooltip("A special effect for when a monster appears will be instantiated at its position. Used for combat shrine.")] public GameObject spawnEffectPrefab; public bool ignoreTeamSizeLimit; [SerializeField] private DirectorCardCategorySelection _monsterCards; public bool fallBackToStageMonsterCards = true; public static readonly List instancesList = new List(); private bool hasStartedWave; private Xoroshiro128Plus rng; private DirectorCard currentMonsterCard; private EliteTierDef currentActiveEliteTier; private EliteDef currentActiveEliteDef; private int currentMonsterCardCost; private WeightedSelection monsterCardsSelection; private int consecutiveCheapSkips; public GameObject currentSpawnTarget; private float playerRetargetTimer; private static readonly float baseEliteCostMultiplier = 6f; private static EliteTierDef[] eliteTiers; private int spawnCountInCurrentWave; public static readonly BoolConVar cvDirectorCombatDisable = new BoolConVar("director_combat_disable", ConVarFlags.SenderMustBeServer | ConVarFlags.Cheat, "0", "Disables all combat directors."); private static readonly BoolConVar cvDirectorCombatEnableInternalLogs = new BoolConVar("director_combat_enable_internal_logs", ConVarFlags.None, "0", "Enables all combat directors to print internal logging."); private DirectorMoneyWave[] moneyWaves; private bool isHalcyonShrineSpawn; private int shrineHalcyoniteDifficultyLevel; public float monsterSpawnTimer { get; set; } public DirectorCard lastAttemptedMonsterCard { get; set; } public float totalCreditsSpent { get; private set; } private WeightedSelection finalMonsterCardsSelection { get { WeightedSelection monsterSelection = monsterCardsSelection; if (monsterSelection == null) { ClassicStageInfo instance = ClassicStageInfo.instance; if ((object)instance == null) { return null; } monsterSelection = instance.monsterSelection; } return monsterSelection; } } private DirectorCardCategorySelection monsterCards { get { return _monsterCards; } set { if (_monsterCards != value) { _monsterCards = value; monsterCardsSelection = _monsterCards?.GenerateDirectorCardWeightedSelection(); } } } public static float lowestEliteCostMultiplier => eliteTiers[1].costMultiplier; private int mostExpensiveMonsterCostInDeck { get { int num = 0; for (int i = 0; i < finalMonsterCardsSelection.Count; i++) { DirectorCard value = finalMonsterCardsSelection.GetChoice(i).value; int num2 = value.cost; if (!(value.spawnCard as CharacterSpawnCard).noElites) { num2 = (int)((float)num2 * CalcHighestEliteCostMultiplier(value.spawnCard.eliteRules)); } num = Mathf.Max(num, num2); } return num; } } private void Awake() { if (NetworkServer.active) { rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint); moneyWaves = new DirectorMoneyWave[moneyWaveIntervals.Length]; for (int i = 0; i < moneyWaveIntervals.Length; i++) { moneyWaves[i] = new DirectorMoneyWave { interval = rng.RangeFloat(moneyWaveIntervals[i].min, moneyWaveIntervals[i].max), multiplier = creditMultiplier }; } monsterCardsSelection = monsterCards?.GenerateDirectorCardWeightedSelection(); } } private void OnEnable() { instancesList.Add(this); } private void OnDisable() { instancesList.Remove(this); if (NetworkServer.active && instancesList.Count > 0) { float num = 0.4f; CombatDirector combatDirector = rng.NextElementUniform(instancesList); monsterCredit *= num; combatDirector.monsterCredit += monsterCredit; UnityEngine.Debug.LogFormat("Transfered {0} monster credits from {1} to {2}", monsterCredit, base.gameObject, combatDirector.gameObject); monsterCredit = 0f; } } private void GenerateAmbush(UnityEngine.Vector3 victimPosition) { NodeGraph groundNodes = SceneInfo.instance.groundNodes; NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(victimPosition, HullClassification.Human); NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(groundNodes, HullMask.Human); nodeGraphSpider.AddNodeForNextStep(nodeIndex); List list = new List(); int num = 0; List collectedSteps = nodeGraphSpider.collectedSteps; while (nodeGraphSpider.PerformStep() && num < 8) { num++; for (int i = 0; i < collectedSteps.Count; i++) { if (IsAcceptableAmbushSpiderStep(groundNodes, nodeIndex, collectedSteps[i])) { list.Add(collectedSteps[i]); } } collectedSteps.Clear(); } for (int j = 0; j < list.Count; j++) { groundNodes.GetNodePosition(list[j].node, out var position); LegacyResourcesAPI.Load("SpawnCards/scLemurian").DoSpawn(position, UnityEngine.Quaternion.identity, null); } } private static bool IsAcceptableAmbushSpiderStep(NodeGraph nodeGraph, NodeGraph.NodeIndex startNode, NodeGraphSpider.StepInfo stepInfo) { int num = 0; while (stepInfo.previousStep != null) { if (nodeGraph.TestNodeLineOfSight(startNode, stepInfo.node)) { return false; } stepInfo = stepInfo.previousStep; num++; if (num > 2) { return true; } } return false; } public void OverrideCurrentMonsterCard(DirectorCard overrideMonsterCard) { PrepareNewMonsterWave(overrideMonsterCard); } public void SetNextSpawnAsBoss() { WeightedSelection weightedSelection = new WeightedSelection(); int i = 0; for (int count = finalMonsterCardsSelection.Count; i < count; i++) { WeightedSelection.ChoiceInfo choice = finalMonsterCardsSelection.GetChoice(i); SpawnCard spawnCard = choice.value.spawnCard; bool isChampion = spawnCard.prefab.GetComponent().bodyPrefab.GetComponent().isChampion; bool flag = (spawnCard as CharacterSpawnCard)?.forbiddenAsBoss ?? false; if (isChampion && !flag && choice.value.IsAvailable()) { weightedSelection.AddChoice(choice); } } if (weightedSelection.Count > 0) { DirectorCard monsterCard = weightedSelection.Evaluate(rng.nextNormalizedFloat); PrepareNewMonsterWave(monsterCard); } monsterSpawnTimer = -600f; } private void PickPlayerAsSpawnTarget() { ReadOnlyCollection instances = PlayerCharacterMasterController.instances; List list = new List(); foreach (PlayerCharacterMasterController item in instances) { if (item.master.hasBody) { list.Add(item); } } if (list.Count > 0) { currentSpawnTarget = rng.NextElementUniform(list).master.GetBodyObject(); } } public void SpendAllCreditsOnMapSpawns(Transform mapSpawnTarget) { int num = 0; int num2 = 10; while (monsterCredit > 0f) { PrepareNewMonsterWave(finalMonsterCardsSelection.Evaluate(rng.nextNormalizedFloat)); bool flag = false; if ((!mapSpawnTarget) ? AttemptSpawnOnTarget(null, SceneInfo.instance.approximateMapBoundMesh ? DirectorPlacementRule.PlacementMode.RandomNormalized : DirectorPlacementRule.PlacementMode.Random) : AttemptSpawnOnTarget(mapSpawnTarget)) { num = 0; continue; } num++; if (num < num2) { continue; } break; } } public void ToggleAllCombatDirectorsOnThisObject(bool newValue) { CombatDirector[] components = GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].enabled = newValue; } } private void Simulate(float deltaTime) { if (targetPlayers) { playerRetargetTimer -= deltaTime; if (playerRetargetTimer <= 0f) { playerRetargetTimer = rng.RangeFloat(1f, 10f); PickPlayerAsSpawnTarget(); } } monsterSpawnTimer -= deltaTime; if (!(monsterSpawnTimer <= 0f)) { return; } if (AttemptSpawnOnTarget(currentSpawnTarget ? currentSpawnTarget.transform : null)) { if (shouldSpawnOneWave) { hasStartedWave = true; } monsterSpawnTimer += rng.RangeFloat(minSeriesSpawnInterval, maxSeriesSpawnInterval); return; } monsterSpawnTimer += rng.RangeFloat(minRerollSpawnInterval, maxRerollSpawnInterval); if (resetMonsterCardIfFailed) { currentMonsterCard = null; } if (shouldSpawnOneWave && hasStartedWave) { base.enabled = false; } } public static bool IsEliteOnlyArtifactActive() { return RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.eliteOnlyArtifactDef); } private static bool NotEliteOnlyArtifactActive() { return !IsEliteOnlyArtifactActive(); } [SystemInitializer(new Type[] { typeof(EliteCatalog) })] private static void Init() { eliteTiers = new EliteTierDef[6] { new EliteTierDef { costMultiplier = 1f, eliteTypes = new EliteDef[1], isAvailable = (SpawnCard.EliteRules rules) => NotEliteOnlyArtifactActive(), canSelectWithoutAvailableEliteDef = true }, new EliteTierDef { costMultiplier = baseEliteCostMultiplier, eliteTypes = new EliteDef[4] { RoR2Content.Elites.Lightning, RoR2Content.Elites.Ice, RoR2Content.Elites.Fire, DLC1Content.Elites.Earth }, isAvailable = (SpawnCard.EliteRules rules) => NotEliteOnlyArtifactActive() && rules == SpawnCard.EliteRules.Default, canSelectWithoutAvailableEliteDef = false }, new EliteTierDef { costMultiplier = Mathf.LerpUnclamped(1f, baseEliteCostMultiplier, 0.5f), eliteTypes = new EliteDef[4] { RoR2Content.Elites.LightningHonor, RoR2Content.Elites.IceHonor, RoR2Content.Elites.FireHonor, DLC1Content.Elites.EarthHonor }, isAvailable = (SpawnCard.EliteRules rules) => IsEliteOnlyArtifactActive(), canSelectWithoutAvailableEliteDef = false }, new EliteTierDef { costMultiplier = Mathf.LerpUnclamped(1f, baseEliteCostMultiplier, 0.5f), eliteTypes = new EliteDef[5] { RoR2Content.Elites.Lightning, RoR2Content.Elites.Ice, RoR2Content.Elites.Fire, DLC1Content.Elites.Earth, DLC2Content.Elites.Aurelionite }, isAvailable = (SpawnCard.EliteRules rules) => NotEliteOnlyArtifactActive() && rules == SpawnCard.EliteRules.Default && Run.instance.stageClearCount >= 2, canSelectWithoutAvailableEliteDef = false }, new EliteTierDef { costMultiplier = baseEliteCostMultiplier * 6f, eliteTypes = new EliteDef[3] { RoR2Content.Elites.Poison, RoR2Content.Elites.Haunted, DLC2Content.Elites.Bead }, isAvailable = (SpawnCard.EliteRules rules) => Run.instance.loopClearCount > 0 && rules == SpawnCard.EliteRules.Default, canSelectWithoutAvailableEliteDef = false }, new EliteTierDef { costMultiplier = baseEliteCostMultiplier, eliteTypes = new EliteDef[1] { RoR2Content.Elites.Lunar }, isAvailable = (SpawnCard.EliteRules rules) => rules == SpawnCard.EliteRules.Lunar, canSelectWithoutAvailableEliteDef = false } }; } public static float CalcHighestEliteCostMultiplier(SpawnCard.EliteRules eliteRules) { float num = 1f; for (int i = 1; i < eliteTiers.Length; i++) { if (eliteTiers[i].CanSelect(eliteRules)) { num = Mathf.Max(num, eliteTiers[i].costMultiplier); } } return num; } private void ResetEliteType() { currentActiveEliteTier = eliteTiers[0]; for (int i = 0; i < eliteTiers.Length; i++) { if (eliteTiers[i].CanSelect(currentMonsterCard.spawnCard.eliteRules)) { currentActiveEliteTier = eliteTiers[i]; break; } } currentActiveEliteDef = currentActiveEliteTier.GetRandomAvailableEliteDef(rng); } private void PrepareNewMonsterWave(DirectorCard monsterCard) { if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Preparing monster wave {0}", monsterCard.spawnCard); } currentMonsterCard = monsterCard; ResetEliteType(); if (!(currentMonsterCard.spawnCard as CharacterSpawnCard).noElites) { for (int i = 1; i < eliteTiers.Length; i++) { EliteTierDef eliteTierDef = eliteTiers[i]; if (!eliteTierDef.CanSelect(currentMonsterCard.spawnCard.eliteRules)) { if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Elite tier index {0} is unavailable", i); } continue; } float num = (float)currentMonsterCard.cost * eliteTierDef.costMultiplier * eliteBias; if (num <= monsterCredit) { currentActiveEliteTier = eliteTierDef; if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Found valid elite tier index {0}", i); } } else if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Elite tier index {0} is too expensive ({1}/{2})", i, num, monsterCredit); } } } else if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Card {0} cannot be elite. Skipping elite procedure.", currentMonsterCard.spawnCard); } currentActiveEliteDef = currentActiveEliteTier.GetRandomAvailableEliteDef(rng); if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Assigned elite index {0}", currentActiveEliteDef); } lastAttemptedMonsterCard = currentMonsterCard; spawnCountInCurrentWave = 0; } private bool AttemptSpawnOnTarget(Transform spawnTarget, DirectorPlacementRule.PlacementMode placementMode = DirectorPlacementRule.PlacementMode.Approximate) { if (currentMonsterCard == null) { _ = cvDirectorCombatEnableInternalLogs.value; if (finalMonsterCardsSelection == null) { return false; } PrepareNewMonsterWave(finalMonsterCardsSelection.Evaluate(rng.nextNormalizedFloat)); } if (spawnCountInCurrentWave >= maximumNumberToSpawnBeforeSkipping) { spawnCountInCurrentWave = 0; if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Spawn count has hit the max ({0}/{1}). Aborting spawn.", spawnCountInCurrentWave, maximumNumberToSpawnBeforeSkipping); } return false; } int num = currentMonsterCard.cost; int cost = currentMonsterCard.cost; float num2 = 1f; EliteDef eliteDef = currentActiveEliteDef; cost = (int)((float)num * currentActiveEliteTier.costMultiplier); if ((float)cost <= monsterCredit) { num = cost; num2 = currentActiveEliteTier.costMultiplier; } else { ResetEliteType(); eliteDef = currentActiveEliteDef; } if (!currentMonsterCard.IsAvailable()) { if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Spawn card {0} is invalid, aborting spawn.", currentMonsterCard.spawnCard); } return false; } if (monsterCredit < (float)num) { if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Spawn card {0} is too expensive, aborting spawn.", currentMonsterCard.spawnCard); } return false; } if (skipSpawnIfTooCheap && consecutiveCheapSkips < maxConsecutiveCheapSkips && (float)(cost * maximumNumberToSpawnBeforeSkipping) < monsterCredit) { if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Card {0} seems too cheap ({1}/{2}). Comparing against most expensive possible ({3})", currentMonsterCard.spawnCard, num * maximumNumberToSpawnBeforeSkipping, monsterCredit, mostExpensiveMonsterCostInDeck); } if (mostExpensiveMonsterCostInDeck > num) { consecutiveCheapSkips++; if (cvDirectorCombatEnableInternalLogs.value) { UnityEngine.Debug.LogFormat("Spawn card {0} is too cheap, aborting spawn.", currentMonsterCard.spawnCard); } return false; } } SpawnCard spawnCard = currentMonsterCard.spawnCard; if (Spawn(spawnCard, eliteDef, spawnTarget, valueMultiplier: num2, placementMode: placementMode, preventOverhead: currentMonsterCard.preventOverhead, spawnDistance: currentMonsterCard.spawnDistance)) { monsterCredit -= num; totalCreditsSpent += num; spawnCountInCurrentWave++; consecutiveCheapSkips = 0; return true; } return false; } public bool Spawn(SpawnCard spawnCard, EliteDef eliteDef, Transform spawnTarget, DirectorCore.MonsterSpawnDistance spawnDistance, bool preventOverhead, float valueMultiplier = 1f, DirectorPlacementRule.PlacementMode placementMode = DirectorPlacementRule.PlacementMode.Approximate) { DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule { placementMode = placementMode, spawnOnTarget = spawnTarget, preventOverhead = preventOverhead }; DirectorCore.GetMonsterSpawnDistance(spawnDistance, out directorPlacementRule.minDistance, out directorPlacementRule.maxDistance); directorPlacementRule.maxDistance = Mathf.Min(maxSpawnDistance, directorPlacementRule.maxDistance * spawnDistanceMultiplier); directorPlacementRule.minDistance = Mathf.Max(0f, Mathf.Min(directorPlacementRule.maxDistance - minSpawnRange, directorPlacementRule.minDistance * spawnDistanceMultiplier)); DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, directorPlacementRule, rng); directorSpawnRequest.ignoreTeamMemberLimit = ignoreTeamSizeLimit; directorSpawnRequest.teamIndexOverride = teamIndex; directorSpawnRequest.onSpawnedServer = OnCardSpawned; if (!DirectorCore.instance.TrySpawnObject(directorSpawnRequest)) { UnityEngine.Debug.LogFormat("Spawn card {0} failed to spawn. Aborting cost procedures.", spawnCard); return false; } return true; void OnCardSpawned(SpawnCard.SpawnResult result) { if (result.success) { float num = 1f; float num2 = 1f; CharacterMaster component = result.spawnedInstance.GetComponent(); GameObject bodyObject = component.GetBodyObject(); CharacterBody component2 = bodyObject.GetComponent(); if ((bool)component2) { component2.cost = valueMultiplier * (float)spawnCard.directorCreditCost; } if ((bool)combatSquad) { combatSquad.AddMember(component); } num = eliteDef?.healthBoostCoefficient ?? 1f; num2 = eliteDef?.damageBoostCoefficient ?? 1f; if (isHalcyonShrineSpawn) { if (shrineHalcyoniteDifficultyLevel > 20) { shrineHalcyoniteDifficultyLevel = 20 + shrineHalcyoniteDifficultyLevel / 100; } num += (float)shrineHalcyoniteDifficultyLevel * 0.6f; num2 += (float)shrineHalcyoniteDifficultyLevel * 0.25f; eliteDef = DLC2Content.Elites.Aurelionite; } EquipmentIndex equipmentIndex = eliteDef?.eliteEquipmentDef?.equipmentIndex ?? EquipmentIndex.None; if (equipmentIndex != EquipmentIndex.None) { component.inventory.SetEquipmentIndex(equipmentIndex); } if ((bool)combatSquad && combatSquad.grantBonusHealthInMultiplayer) { int livingPlayerCount = Run.instance.livingPlayerCount; num *= Mathf.Pow(livingPlayerCount, 1f); } component.inventory.GiveItem(RoR2Content.Items.BoostHp, Mathf.RoundToInt((num - 1f) * 10f)); component.inventory.GiveItem(RoR2Content.Items.BoostDamage, Mathf.RoundToInt((num2 - 1f) * 10f)); DeathRewards component3 = bodyObject.GetComponent(); if ((bool)component3) { float num3 = (float)spawnCard.directorCreditCost * valueMultiplier * expRewardCoefficient; component3.spawnValue = (int)Mathf.Max(1f, num3); if (num3 > Mathf.Epsilon) { component3.expReward = (uint)Mathf.Max(1f, num3 * Run.instance.compensatedDifficultyCoefficient); component3.goldReward = (uint)Mathf.Max(1f, num3 * goldRewardCoefficient * 2f * Run.instance.compensatedDifficultyCoefficient); } else { component3.expReward = 0u; component3.goldReward = 0u; } } if ((bool)spawnEffectPrefab && NetworkServer.active) { UnityEngine.Vector3 origin = result.position; CharacterBody characterBody = component2; if ((bool)characterBody) { origin = characterBody.corePosition; } EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData { origin = origin }, transmit: true); } onSpawnedServer?.Invoke(result.spawnedInstance); } } } private void FixedUpdate() { if (!cvDirectorCombatDisable.value && NetworkServer.active && (bool)Run.instance) { float compensatedDifficultyCoefficient = Run.instance.compensatedDifficultyCoefficient; for (int i = 0; i < moneyWaves.Length; i++) { float num = moneyWaves[i].Update(Time.fixedDeltaTime, compensatedDifficultyCoefficient); monsterCredit += num; } Simulate(Time.fixedDeltaTime); } } public void CombatShrineActivation(Interactor interactor, float monsterCredit, DirectorCard chosenDirectorCard) { base.enabled = true; this.monsterCredit += monsterCredit; OverrideCurrentMonsterCard(chosenDirectorCard); monsterSpawnTimer = 0f; CharacterMaster component = chosenDirectorCard.spawnCard.prefab.GetComponent(); if ((bool)component) { CharacterBody component2 = component.bodyPrefab.GetComponent(); if ((bool)component2) { Chat.SubjectFormatChatMessage subjectFormatChatMessage = new Chat.SubjectFormatChatMessage(); subjectFormatChatMessage.subjectAsCharacterBody = interactor.GetComponent(); subjectFormatChatMessage.baseToken = "SHRINE_COMBAT_USE_MESSAGE"; subjectFormatChatMessage.paramTokens = new string[1] { component2.baseNameToken }; Chat.SendBroadcastChat(subjectFormatChatMessage); } } } public DirectorCard SelectMonsterCardForCombatShrine(float monsterCredit) { WeightedSelection weightedSelection = Util.CreateReasonableDirectorCardSpawnList(monsterCredit, maximumNumberToSpawnBeforeSkipping, 1); if (weightedSelection.Count == 0) { return null; } return weightedSelection.Evaluate(rng.nextNormalizedFloat); } public void HalcyoniteShrineActivation(float monsterCredit, DirectorCard chosenDirectorCard, int difficultyLevel, Transform shrineTransform) { base.enabled = true; this.monsterCredit += monsterCredit; isHalcyonShrineSpawn = true; shrineHalcyoniteDifficultyLevel = difficultyLevel; OverrideCurrentMonsterCard(chosenDirectorCard); monsterSpawnTimer = 0f; Util.PlaySound("Play_halcyonite_spawn", shrineTransform.gameObject); } public void SetMonsterCredit(float newMonsterCredit) { monsterCredit = newMonsterCredit; } } public class CombatSquad : NetworkBehaviour { private List membersList = new List(); private List memberHistory = new List(); public bool propagateMembershipToSummons; [Tooltip("Grants a bonus health boost to members of the combat squad, depending on the number of players in the game.")] public bool grantBonusHealthInMultiplayer = true; private List onDestroyCallbacksServer; private bool defeatedServer; private const uint membersListDirtyBit = 1u; private const uint allDirtyBits = 1u; [NonSerialized] public Run.FixedTimeStamp awakeTime; public UnityEvent onDefeatedClientLogicEvent; public UnityEvent onDefeatedServerLogicEvent; private static int kRpcRpcOnDefeatedClient; public ReadOnlyCollection readOnlyMembersList { get; private set; } public int memberCount => membersList.Count; public event Action onDefeatedServer; public event Action onMemberDeathServer; public event Action onMemberDefeatedServer; public event Action onMemberAddedServer; public event Action onMemberDiscovered; public event Action onMemberLost; private void Awake() { if (NetworkServer.active) { onDestroyCallbacksServer = new List(); GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathCallback; MasterSummon.onServerMasterSummonGlobal += OnServerMasterSummonGlobal; } readOnlyMembersList = new ReadOnlyCollection(membersList); awakeTime = Run.FixedTimeStamp.now; InstanceTracker.Add(this); } private void OnEnable() { if (NetworkServer.active) { SetDirtyBit(1u); } } private void OnDestroy() { InstanceTracker.Remove(this); if (NetworkServer.active) { GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathCallback; MasterSummon.onServerMasterSummonGlobal -= OnServerMasterSummonGlobal; } for (int num = membersList.Count - 1; num >= 0; num--) { RemoveMemberAt(num); } onDestroyCallbacksServer = null; } [Server] private void OnServerMasterSummonGlobal(MasterSummon.MasterSummonReport report) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::OnServerMasterSummonGlobal(RoR2.MasterSummon/MasterSummonReport)' called on client"); } else if (propagateMembershipToSummons && (bool)report.leaderMasterInstance && HasContainedMember(report.leaderMasterInstance.netId)) { AddMember(report.summonMasterInstance); } } [Server] public void AddMember(CharacterMaster memberMaster) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::AddMember(RoR2.CharacterMaster)' called on client"); return; } if (membersList.Count >= 255) { UnityEngine.Debug.LogFormat("Cannot add character {0} to CombatGroup! Limit of {1} members already reached.", memberMaster, byte.MaxValue); return; } membersList.Add(memberMaster); memberHistory.Add(memberMaster.netId); SetDirtyBit(1u); onDestroyCallbacksServer.Add(OnDestroyCallback.AddCallback(memberMaster.gameObject, OnMemberDestroyedServer)); this.onMemberAddedServer?.Invoke(memberMaster); this.onMemberDiscovered?.Invoke(memberMaster); } [Server] private void OnCharacterDeathCallback(DamageReport damageReport) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::OnCharacterDeathCallback(RoR2.DamageReport)' called on client"); return; } CharacterMaster victimMaster = damageReport.victimMaster; if (!victimMaster) { return; } int num = membersList.IndexOf(victimMaster); if (num < 0) { return; } this.onMemberDeathServer?.Invoke(victimMaster, damageReport); if (victimMaster.IsDeadAndOutOfLivesServer()) { this.onMemberDefeatedServer?.Invoke(victimMaster, damageReport); RemoveMemberAt(num); if (!defeatedServer && membersList.Count == 0) { TriggerDefeat(); } } } [Server] private void RemoveMember(CharacterMaster memberMaster) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::RemoveMember(RoR2.CharacterMaster)' called on client"); return; } int num = membersList.IndexOf(memberMaster); if (num != -1) { RemoveMemberAt(num); } } private void RemoveMemberAt(int memberIndex) { CharacterMaster obj = membersList[memberIndex]; membersList.RemoveAt(memberIndex); if (onDestroyCallbacksServer != null) { onDestroyCallbacksServer.RemoveAt(memberIndex); } SetDirtyBit(1u); this.onMemberLost?.Invoke(obj); } [Server] public void OnMemberDestroyedServer(OnDestroyCallback onDestroyCallback) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::OnMemberDestroyedServer(RoR2.OnDestroyCallback)' called on client"); } else { if (!onDestroyCallback) { return; } GameObject gameObject = onDestroyCallback.gameObject; CharacterMaster characterMaster = (gameObject ? gameObject.GetComponent() : null); for (int i = 0; i < membersList.Count; i++) { if ((object)membersList[i] == characterMaster) { RemoveMemberAt(i); break; } } } } public bool ContainsMember(CharacterMaster master) { for (int i = 0; i < membersList.Count; i++) { if ((object)membersList[i] == master) { return true; } } return false; } public bool HasContainedMember(NetworkInstanceId id) { return memberHistory.Contains(id); } public override bool OnSerialize(NetworkWriter writer, bool initialState) { uint num = base.syncVarDirtyBits; if (initialState) { num = 1u; } bool num2 = (num & 1) != 0; writer.Write((byte)num); if (num2) { writer.Write((byte)membersList.Count); for (int i = 0; i < membersList.Count; i++) { CharacterMaster characterMaster = membersList[i]; GameObject value = (characterMaster ? characterMaster.gameObject : null); writer.Write(value); } } if (!initialState) { return num != 0; } return false; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if ((reader.ReadByte() & 1) == 0) { return; } List list = CollectionPool>.RentCollection(); List list2 = CollectionPool>.RentCollection(); List a = CollectionPool>.RentCollection(); byte b = reader.ReadByte(); for (byte b2 = 0; b2 < b; b2++) { GameObject gameObject = reader.ReadGameObject(); CharacterMaster item = (gameObject ? gameObject.GetComponent() : null); a.Add(item); } ListUtils.FindExclusiveEntriesByReference(membersList, a, list, list2); Util.Swap(ref a, ref membersList); CollectionPool>.ReturnCollection(a); for (int i = 0; i < list.Count; i++) { CharacterMaster characterMaster = list[i]; if ((bool)characterMaster) { try { this.onMemberLost?.Invoke(characterMaster); } catch (Exception message) { UnityEngine.Debug.LogError(message); } } } for (int j = 0; j < list2.Count; j++) { CharacterMaster characterMaster2 = list2[j]; if ((bool)characterMaster2) { try { this.onMemberDiscovered?.Invoke(characterMaster2); } catch (Exception message2) { UnityEngine.Debug.LogError(message2); } } } CollectionPool>.ReturnCollection(list2); CollectionPool>.ReturnCollection(list); } private void FixedUpdate() { if (!NetworkServer.active || defeatedServer || memberHistory.Count <= 0) { return; } bool flag = false; foreach (CharacterMaster members in membersList) { if (members.hasBody || members.IsExtraLifePendingServer()) { flag = true; break; } } if (!flag) { UnityEngine.Debug.LogError("CombatSquad has no living members. Triggering defeat..."); while (membersList.Count > 0) { RemoveMember(membersList[0]); } TriggerDefeat(); } } private void TriggerDefeat() { defeatedServer = true; this.onDefeatedServer?.Invoke(); onDefeatedServerLogicEvent?.Invoke(); membersList?.Clear(); CallRpcOnDefeatedClient(); } [ClientRpc] private void RpcOnDefeatedClient() { onDefeatedClientLogicEvent?.Invoke(); } private void UNetVersion() { } protected static void InvokeRpcRpcOnDefeatedClient(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcOnDefeatedClient called on server."); } else { ((CombatSquad)obj).RpcOnDefeatedClient(); } } public void CallRpcOnDefeatedClient() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcOnDefeatedClient called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnDefeatedClient); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcOnDefeatedClient"); } static CombatSquad() { kRpcRpcOnDefeatedClient = -1235734536; NetworkBehaviour.RegisterRpcDelegate(typeof(CombatSquad), kRpcRpcOnDefeatedClient, InvokeRpcRpcOnDefeatedClient); NetworkCRC.RegisterBehaviour("CombatSquad", 0); } public override void PreStartClient() { } } public class CombineMesh : MonoBehaviour { private void Start() { Renderer component = GetComponent(); MeshFilter[] componentsInChildren = GetComponentsInChildren(); CombineInstance[] array = new CombineInstance[componentsInChildren.Length]; for (int i = 0; i < componentsInChildren.Length; i++) { array[i].mesh = componentsInChildren[i].sharedMesh; array[i].transform = componentsInChildren[i].transform.localToWorldMatrix; componentsInChildren[i].gameObject.SetActive(value: false); } MeshFilter meshFilter = base.gameObject.AddComponent(); meshFilter.mesh = new Mesh(); meshFilter.mesh.CombineMeshes(array, mergeSubMeshes: true, useMatrices: true, hasLightmapData: true); component.material = componentsInChildren[0].GetComponent().sharedMaterial; base.gameObject.SetActive(value: true); } } [Flags] public enum ConVarFlags { None = 0, ExecuteOnServer = 1, SenderMustBeServer = 2, Archive = 4, Cheat = 8, Engine = 0x10 } [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] public class ConCommandAttribute : HG.Reflection.SearchableAttribute { public string commandName; public ConVarFlags flags; public string helpText = ""; } [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public class ConVarProviderAttribute : System.Attribute { } public struct ConCommandArgs { public List userArgs; public NetworkUser sender; public LocalUser localUserSender; public string commandName; public string this[int i] => userArgs[i]; public int Count => userArgs.Count; public GameObject senderMasterObject { get { if (!sender) { return null; } return sender.masterObject; } } public CharacterMaster senderMaster { get { if (!sender) { return null; } return sender.master; } } public CharacterBody senderBody { get { if (!sender) { return null; } return sender.GetCurrentBody(); } } public void CheckArgumentCount(int count) { ConCommandException.CheckArgumentCount(userArgs, count); } public string TryGetArgString(int index) { if ((uint)index < (uint)userArgs.Count) { return userArgs[index]; } return null; } public string GetArgString(int index) { return TryGetArgString(index) ?? throw new ConCommandException($"Argument {index} must be a string."); } public ulong? TryGetArgUlong(int index) { if ((uint)index < (uint)userArgs.Count && TextSerialization.TryParseInvariant(userArgs[index], out ulong result)) { return result; } return null; } public ulong GetArgULong(int index) { ulong? num = TryGetArgUlong(index); if (!num.HasValue) { throw new ConCommandException($"Argument {index} must be an unsigned integer."); } return num.Value; } public int? TryGetArgInt(int index) { if ((uint)index < (uint)userArgs.Count && TextSerialization.TryParseInvariant(userArgs[index], out int result)) { return result; } return null; } public int GetArgInt(int index) { int? num = TryGetArgInt(index); if (!num.HasValue) { throw new ConCommandException($"Argument {index} must be an integer."); } return num.Value; } public bool? TryGetArgBool(int index) { int? num = TryGetArgInt(index); if (num.HasValue) { return num > 0; } return null; } public bool GetArgBool(int index) { int? num = TryGetArgInt(index); if (!num.HasValue) { throw new ConCommandException($"Argument {index} must be a boolean."); } return num.Value > 0; } public float? TryGetArgFloat(int index) { if ((uint)index < (uint)userArgs.Count && TextSerialization.TryParseInvariant(userArgs[index], out float result)) { return result; } return null; } public float GetArgFloat(int index) { float? num = TryGetArgFloat(index); if (!num.HasValue) { throw new ConCommandException($"Argument {index} must be a number."); } return num.Value; } public double? TryGetArgDouble(int index) { if ((uint)index < (uint)userArgs.Count && TextSerialization.TryParseInvariant(userArgs[index], out double result)) { return result; } return null; } public double GetArgDouble(int index) { double? num = TryGetArgDouble(index); if (!num.HasValue) { throw new ConCommandException($"Argument {index} must be a number."); } return num.Value; } public T? TryGetArgEnum(int index) where T : struct { if ((uint)index < (uint)userArgs.Count && Enum.TryParse(userArgs[index], ignoreCase: true, out var result)) { return result; } return null; } public T GetArgEnum(int index) where T : struct { T? val = TryGetArgEnum(index); if (!val.HasValue) { throw new ConCommandException($"Argument {index} must be one of the values of {typeof(T).Name}."); } return val.Value; } public PlatformID? TryGetArgPlatformID(int index) { if ((uint)index < (uint)userArgs.Count && PlatformID.TryParse(userArgs[index], out var result)) { return result; } return null; } public PlatformID GetArgPlatformID(int index) { PlatformID? platformID = TryGetArgPlatformID(index); if (!platformID.HasValue) { throw new ConCommandException($"Argument {index} must be a valid Steam ID."); } return platformID.Value; } public AddressPortPair? TryGetArgAddressPortPair(int index) { if ((uint)index < (uint)userArgs.Count && AddressPortPair.TryParse(userArgs[index], out var addressPortPair)) { return addressPortPair; } return null; } public AddressPortPair GetArgAddressPortPair(int index) { AddressPortPair? addressPortPair = TryGetArgAddressPortPair(index); if (!addressPortPair.HasValue) { throw new ConCommandException($"Argument {index} must be a valid address and port pair in the format \"address:port\" (e.g. \"127.0.0.1:27015\"). Given value: {TryGetArgString(index)}"); } return addressPortPair.Value; } public PickupIndex GetArgPickupIndex(int index) { PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(TryGetArgString(index) ?? string.Empty); if (pickupIndex == PickupIndex.none) { throw new ConCommandException($"Argument {index} must be a valid pickup name."); } return pickupIndex; } public LocalUser GetSenderLocalUser() { return localUserSender ?? throw new ConCommandException($"Command requires a local user that is not available."); } public CharacterBody TryGetSenderBody() { if (!sender) { return null; } return sender.GetCurrentBody(); } public CharacterBody GetSenderBody() { CharacterBody characterBody = TryGetSenderBody(); if ((bool)characterBody) { return characterBody; } throw new ConCommandException("Command requires the sender to have a body."); } public CharacterMaster GetSenderMaster() { if (!senderMaster) { throw new ConCommandException("Command requires the sender to have a CharacterMaster. The game must be in an active run and the sender must be a participating player."); } return senderMaster; } public void Log(string message) { } } [Serializable] public class ConCommandException : Exception { public ConCommandException() { } public ConCommandException(string message) : base(message) { } public ConCommandException(string message, Exception inner) : base(message, inner) { } protected ConCommandException(SerializationInfo info, StreamingContext context) : base(info, context) { } public static void CheckArgumentCount(List args, int requiredArgCount) { if (args.Count < requiredArgCount) { throw new ConCommandException($"{requiredArgCount} argument(s) required, {args.Count} argument(s) provided."); } } } public class Console : MonoBehaviour { public struct Log { public string message; public string stackTrace; public LogType logType; } public delegate void LogReceivedDelegate(Log log); private class Lexer { private enum TokenType { Identifier, NestedString } private string srcString; private int readIndex; private StringBuilder stringBuilder = new StringBuilder(); public Lexer(string srcString) { this.srcString = srcString; readIndex = 0; } private static bool IsIgnorableCharacter(char character) { if (!IsSeparatorCharacter(character) && !IsQuoteCharacter(character) && !IsIdentifierCharacter(character)) { return character != '/'; } return false; } private static bool IsSeparatorCharacter(char character) { if (character != ';') { return character == '\n'; } return true; } private static bool IsQuoteCharacter(char character) { if (character != '\'') { return character == '"'; } return true; } private static bool IsIdentifierCharacter(char character) { if (!char.IsLetterOrDigit(character) && character != '_' && character != '.' && character != '-') { return character == ':'; } return true; } private bool TrimComment() { if (readIndex >= srcString.Length) { return false; } if (srcString[readIndex] == '/') { if (readIndex + 1 < srcString.Length) { char c = srcString[readIndex + 1]; if (c == '/') { while (readIndex < srcString.Length) { if (srcString[readIndex] == '\n') { readIndex++; return true; } readIndex++; } return true; } if (c == '*') { while (readIndex < srcString.Length - 1) { if (srcString[readIndex] == '*' && srcString[readIndex + 1] == '/') { readIndex += 2; return true; } readIndex++; } return true; } } readIndex++; } return false; } private void TrimWhitespace() { while (readIndex < srcString.Length && IsIgnorableCharacter(srcString[readIndex])) { readIndex++; } } private void TrimUnused() { do { TrimWhitespace(); } while (TrimComment()); } private static int UnescapeNext(string srcString, int startPos, out char result) { result = '\\'; int num = startPos; num++; if (num < srcString.Length) { char c = srcString[num]; switch (c) { case '"': case '\'': case '\\': result = c; return 2; case 'n': result = '\n'; return 2; } } return 1; } public string NextToken() { TrimUnused(); if (readIndex == srcString.Length) { return null; } TokenType tokenType = TokenType.Identifier; char c = srcString[readIndex]; char c2 = '\0'; if (IsQuoteCharacter(c)) { tokenType = TokenType.NestedString; c2 = c; readIndex++; } else if (IsSeparatorCharacter(c)) { readIndex++; return ";"; } char result; for (; readIndex < srcString.Length; stringBuilder.Append(result), readIndex++) { result = srcString[readIndex]; switch (tokenType) { case TokenType.Identifier: if (IsIdentifierCharacter(result)) { continue; } break; case TokenType.NestedString: if (result == '\\') { readIndex += UnescapeNext(srcString, readIndex, out result) - 1; continue; } if (result != c2) { continue; } readIndex++; break; default: continue; } break; } string result2 = stringBuilder.ToString(); stringBuilder.Length = 0; return result2; } public Queue GetTokens() { Queue queue = new Queue(); for (string text = NextToken(); text != null; text = NextToken()) { queue.Enqueue(text); } queue.Enqueue(";"); return queue; } } private class Substring { public string srcString; public int startIndex; public int length; public int endIndex => startIndex + length; public string str => srcString.Substring(startIndex, length); public Substring nextToken => new Substring { srcString = srcString, startIndex = startIndex + length, length = 0 }; } private class ConCommand { public ConVarFlags flags; public ConCommandDelegate action; public string helpText; } public delegate void ConCommandDelegate(ConCommandArgs args); private class ConvarClass { public string containerAssemblyName; public List convars = new List(); } public readonly struct CmdSender { public readonly LocalUser localUser; public readonly NetworkUser networkUser; public CmdSender(LocalUser localUser) { this.localUser = localUser; networkUser = localUser?.currentNetworkUser; } public CmdSender(NetworkUser networkUser) { localUser = networkUser?.localUser; this.networkUser = networkUser; } public static implicit operator CmdSender(LocalUser localUser) { return new CmdSender(localUser); } public static implicit operator CmdSender(NetworkUser networkUser) { return new CmdSender(networkUser); } } private enum SystemConsoleType { None, Attach, Alloc } public class AutoComplete { private struct MatchInfo { public string str; public int similarity; } private List searchableStrings = new List(); private string searchString; public List resultsList = new List(); public List GetSearchableStrings => searchableStrings; public AutoComplete(Console console) { HashSet hashSet = new HashSet(); for (int i = 0; i < userCmdHistory.Count; i++) { hashSet.Add(userCmdHistory[i]); } foreach (KeyValuePair allConVar in console.allConVars) { hashSet.Add(allConVar.Key); } foreach (KeyValuePair item in console.concommandCatalog) { hashSet.Add(item.Key); } foreach (string item2 in hashSet) { searchableStrings.Add(item2); } searchableStrings.Sort(); } public bool SetSearchString(string newSearchString) { newSearchString = newSearchString.ToLower(CultureInfo.InvariantCulture); if (newSearchString == searchString) { return false; } searchString = newSearchString; List list = new List(); for (int i = 0; i < searchableStrings.Count; i++) { string text = searchableStrings[i]; int num = Math.Min(text.Length, searchString.Length); int j; for (j = 0; j < num && char.ToLower(text[j]) == searchString[j]; j++) { } if (j > 1) { list.Add(new MatchInfo { str = text, similarity = j }); } } list.Sort(delegate(MatchInfo a, MatchInfo b) { if (a.similarity == b.similarity) { return string.CompareOrdinal(a.str, b.str); } return (a.similarity <= b.similarity) ? 1 : (-1); }); resultsList = new List(); for (int k = 0; k < list.Count; k++) { resultsList.Add(list[k].str); } return true; } } public class CheatsConVar : BaseConVar { public static readonly CheatsConVar instance = new CheatsConVar("cheats", ConVarFlags.ExecuteOnServer, "0", "Enable cheats. Achievements, unlock progression, and stat tracking will be disabled until the application is restarted."); private bool _boolValue; public bool boolValue { get { return _boolValue; } private set { if (_boolValue) { sessionCheatsEnabled = true; } } } public CheatsConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { } public override void SetString(string newValue) { if (TextSerialization.TryParseInvariant(newValue, out int result)) { boolValue = result != 0; } } public override string GetString() { if (!boolValue) { return "0"; } return "1"; } } public static List logs = new List(); private Dictionary vstrs = new Dictionary(); private Dictionary concommandCatalog = new Dictionary(); private Dictionary allConVars; private List archiveConVars; public static List userCmdHistory = new List(); private const int VK_RETURN = 13; private const int WM_KEYDOWN = 256; private static byte[] inputStreamBuffer = new byte[256]; private static Queue stdInQueue = new Queue(); private static Thread stdInReaderThread = null; private static SystemConsoleType systemConsoleType = SystemConsoleType.None; public static bool loadingIsComplete = false; private int maxPassesBeforeYielding = 25; private static readonly StringBuilder sharedStringBuilder = new StringBuilder(); private const string configFolder = "/Config/"; private const string archiveConVarsPath = "/Config/config.cfg"; private static IntConVar maxMessages = new IntConVar("max_messages", ConVarFlags.Archive, "25", "Maximum number of messages that can be held in the console log."); public static Console instance { get; private set; } public static bool sessionCheatsEnabled { get; private set; } = false; public static event LogReceivedDelegate onLogReceived; public static event Action onClear; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void RegisterLogHandler() { Application.logMessageReceived += HandleLog; } private static void HandleLog(string message, string stackTrace, LogType logType) { switch (logType) { case LogType.Error: message = string.Format(CultureInfo.InvariantCulture, "{0}", message); break; case LogType.Warning: message = string.Format(CultureInfo.InvariantCulture, "{0}", message); break; } Log log = default(Log); log.message = message; log.stackTrace = stackTrace; log.logType = logType; Log log2 = log; logs.Add(log2); if (maxMessages.value > 0) { while (logs.Count > maxMessages.value) { logs.RemoveAt(0); } } if (Console.onLogReceived != null) { Console.onLogReceived(log2); } } private string GetVstrValue(LocalUser user, string identifier) { if (user == null) { if (vstrs.TryGetValue(identifier, out var value)) { return value; } return ""; } return ""; } public void CacheConVars() { _ = typeof(BaseConVar).Assembly; List list = new List(); Type[] types = typeof(BaseConVar).Assembly.GetTypes(); foreach (Type type in types) { bool flag = false; FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.FieldType.IsSubclassOf(typeof(BaseConVar))) { continue; } if (fieldInfo.IsStatic) { BaseConVar conVar = (BaseConVar)fieldInfo.GetValue(null); RegisterConVarInternal(conVar); if (!flag) { flag = true; list.Add(new ConvarClass { containerAssemblyName = type.FullName }); } list[list.Count - 1].convars.Add(fieldInfo.Name); } else if (CustomAttributeExtensions.GetCustomAttribute(type) == null) { UnityEngine.Debug.LogErrorFormat("ConVar defined as {0}.{1} could not be registered. ConVars must be static fields.", type.Name, fieldInfo.Name); } } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (CustomAttributeExtensions.GetCustomAttribute(methodInfo) == null) { continue; } UnityEngine.Debug.LogErrorFormat("ConVarProviderAttribute on method {0}.{1}", type.Name, methodInfo.Name); if (methodInfo.ReturnType != typeof(IEnumerable) || methodInfo.GetParameters().Length != 0) { UnityEngine.Debug.LogErrorFormat("ConVar provider {0}.{1} does not match the signature \"static IEnumerable()\".", type.Name, methodInfo.Name); continue; } if (!methodInfo.IsStatic) { UnityEngine.Debug.LogErrorFormat("ConVar provider {0}.{1} could not be invoked. Methods marked with the ConVarProvider attribute must be static.", type.Name, methodInfo.Name); continue; } foreach (BaseConVar item in (IEnumerable)methodInfo.Invoke(null, Array.Empty())) { RegisterConVarInternal(item); } } } if (list.Count <= 0) { return; } StreamWriter streamWriter = new StreamWriter(Application.streamingAssetsPath + "/ConVarNames.txt"); foreach (ConvarClass item2 in list) { streamWriter.WriteLine(item2.containerAssemblyName); streamWriter.WriteLine(item2.convars.Count); foreach (string convar in item2.convars) { streamWriter.WriteLine(convar); } } streamWriter.Close(); } private IEnumerator InternalInitConVarsCoroutine() { CacheConVars(); yield return null; string path = Application.streamingAssetsPath + "/ConVarNames.txt"; string[] fileLines; int curLine; if (File.Exists(path)) { fileLines = File.ReadAllLines(path); curLine = 0; StringBuilder sb = new StringBuilder(256); string assemblyName = typeof(BaseConVar).Assembly.FullName; int currentPass = 0; while (!EndOfStream()) { string text = ReadLine(); if (!string.IsNullOrEmpty(text)) { int num = int.Parse(ReadLine()); sb.Clear(); sb.AppendFormat("{0}, {1}", text, assemblyName); Type type = Type.GetType(sb.ToString()); if (type != null) { for (int i = 0; i < num; i++) { string text2 = ReadLine(); FieldInfo field = type.GetField(text2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { BaseConVar conVar = (BaseConVar)field.GetValue(null); RegisterConVarInternal(conVar); } else { UnityEngine.Debug.LogError("Failed to find convar " + text2); } } } else { UnityEngine.Debug.LogErrorFormat("Failed to get type {0} (Full name: {1})", text, sb.ToString()); for (int j = 0; j < num; j++) { ReadLine(); } } } currentPass++; if (currentPass >= maxPassesBeforeYielding) { currentPass = 0; yield return null; } } } else { UnityEngine.Debug.LogError("ERROR: Failed to load StreamingAssets/ConVarNames.txt"); } bool EndOfStream() { return curLine >= fileLines.Length; } string ReadLine() { return fileLines[curLine++]; } } private void InternalInitConVars() { string path = Application.streamingAssetsPath + "/ConVarNames.txt"; string[] fileLines; int curLine; if (File.Exists(path)) { fileLines = File.ReadAllLines(path); curLine = 0; StringBuilder stringBuilder = new StringBuilder(256); string fullName = typeof(BaseConVar).Assembly.FullName; while (!EndOfStream()) { string text = ReadLine(); if (string.IsNullOrEmpty(text)) { continue; } int num = int.Parse(ReadLine()); stringBuilder.Clear(); stringBuilder.AppendFormat("{0}, {1}", text, fullName); Type type = Type.GetType(stringBuilder.ToString()); if (type != null) { for (int i = 0; i < num; i++) { string text2 = ReadLine(); FieldInfo field = type.GetField(text2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { BaseConVar conVar = (BaseConVar)field.GetValue(null); RegisterConVarInternal(conVar); } else { UnityEngine.Debug.LogError("Failed to find convar " + text2); } } } else { UnityEngine.Debug.LogErrorFormat("Failed to get type {0} (Full name: {1})", text, stringBuilder.ToString()); for (int j = 0; j < num; j++) { ReadLine(); } } } } else { UnityEngine.Debug.LogError("ERROR: Failed to load StreamingAssets/ConVarNames.txt"); } bool EndOfStream() { return curLine >= fileLines.Length; } string ReadLine() { return fileLines[curLine++]; } } public IEnumerator InitConVarsCoroutine() { allConVars = new Dictionary(); archiveConVars = new List(); yield return InternalInitConVarsCoroutine(); int currentPass = 0; foreach (KeyValuePair allConVar in allConVars) { try { BaseConVar value = allConVar.Value; if ((value.flags & ConVarFlags.Engine) != 0) { value.defaultValue = value.GetString(); } else if (value.defaultValue != null) { value.AttemptSetString(value.defaultValue); } } catch (Exception message) { UnityEngine.Debug.LogError(message); } currentPass++; if (currentPass >= maxPassesBeforeYielding) { currentPass = 0; yield return null; } } } public void InitConVars() { allConVars = new Dictionary(); archiveConVars = new List(); InternalInitConVars(); foreach (KeyValuePair allConVar in allConVars) { try { BaseConVar value = allConVar.Value; if ((value.flags & ConVarFlags.Engine) != 0) { value.defaultValue = value.GetString(); } else if (value.defaultValue != null) { value.AttemptSetString(value.defaultValue); } } catch (Exception message) { UnityEngine.Debug.LogError(message); } } } private void RegisterConVarInternal(BaseConVar conVar) { if (conVar == null) { UnityEngine.Debug.LogWarning("Attempted to register null ConVar"); return; } allConVars[conVar.name] = conVar; if ((conVar.flags & ConVarFlags.Archive) != 0) { archiveConVars.Add(conVar); } } public BaseConVar FindConVar(string name) { if (allConVars.TryGetValue(name, out var value)) { return value; } return null; } public void SubmitCmd(NetworkUser sender, string cmd, bool recordSubmit = false) { SubmitCmd((CmdSender)sender, cmd, recordSubmit); } public void SubmitCmd(CmdSender sender, string cmd, bool recordSubmit = false) { if (recordSubmit) { Log log = default(Log); log.message = string.Format(CultureInfo.InvariantCulture, "] {0}", cmd); log.stackTrace = ""; log.logType = LogType.Log; Log log2 = log; logs.Add(log2); if (Console.onLogReceived != null) { Console.onLogReceived(log2); } userCmdHistory.Add(cmd); } Queue tokens = new Lexer(cmd).GetTokens(); List list = new List(); bool flag = false; while (tokens.Count != 0) { string text = tokens.Dequeue(); if (text == ";") { flag = false; if (list.Count > 0) { string concommandName = list[0].ToLower(CultureInfo.InvariantCulture); list.RemoveAt(0); RunCmd(sender, concommandName, list); list.Clear(); } } else { if (flag) { text = GetVstrValue(sender.localUser, text); flag = false; } if (text == "vstr") { flag = true; } else { list.Add(text); } } } } private void ForwardCmdToServer(ConCommandArgs args) { if ((bool)args.sender) { args.sender.CallCmdSendConsoleCommand(args.commandName, args.userArgs.ToArray()); } } public void RunClientCmd(NetworkUser sender, string concommandName, string[] args) { RunCmd(sender, concommandName, new List(args)); } private void RunCmd(CmdSender sender, string concommandName, List userArgs) { bool flag = !(sender.networkUser?.isLocalPlayer ?? true); ConVarFlags conVarFlags = ConVarFlags.None; ConCommand value = null; BaseConVar baseConVar = null; if (concommandCatalog.TryGetValue(concommandName, out value)) { conVarFlags = value.flags; } else { baseConVar = FindConVar(concommandName); if (baseConVar == null) { UnityEngine.Debug.LogFormat("\"{0}\" is not a recognized ConCommand or ConVar.", concommandName); return; } conVarFlags = baseConVar.flags; } bool flag2 = (conVarFlags & ConVarFlags.ExecuteOnServer) != 0; if (!NetworkServer.active && flag2) { ForwardCmdToServer(new ConCommandArgs { sender = sender.networkUser, commandName = concommandName, userArgs = userArgs }); return; } if (flag && (conVarFlags & ConVarFlags.SenderMustBeServer) != 0) { UnityEngine.Debug.LogFormat("Blocked server-only command {0} from remote user {1}.", concommandName, sender.networkUser.userName); return; } if (flag && !flag2) { UnityEngine.Debug.LogFormat("Blocked non-transmittable command {0} from remote user {1}.", concommandName, sender.networkUser.userName); return; } if ((conVarFlags & ConVarFlags.Cheat) != 0 && !CheatsConVar.instance.boolValue) { UnityEngine.Debug.LogFormat("Command \"{0}\" cannot be used while cheats are disabled.", concommandName); return; } if (value != null) { try { value.action(new ConCommandArgs { sender = sender.networkUser, localUserSender = sender.localUser, commandName = concommandName, userArgs = userArgs }); return; } catch (ConCommandException ex) { UnityEngine.Debug.LogFormat("Command \"{0}\" failed: {1}", concommandName, ex.Message); return; } } if (baseConVar != null) { if (userArgs.Count > 0) { baseConVar.AttemptSetString(userArgs[0]); return; } UnityEngine.Debug.LogFormat("\"{0}\" = \"{1}\"\n{2}", concommandName, baseConVar.GetString(), baseConVar.helpText); } } [DllImport("kernel32.dll")] private static extern bool AllocConsole(); [DllImport("kernel32.dll")] private static extern bool FreeConsole(); [DllImport("kernel32.dll")] private static extern bool AttachConsole(int processId); [DllImport("user32.dll")] private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam); [DllImport("kernel32.dll")] private static extern IntPtr GetConsoleWindow(); private static string ReadInputStream() { if (stdInQueue.Count > 0) { return stdInQueue.Dequeue(); } return null; } private static void ThreadedInputQueue() { string item; while (systemConsoleType != 0 && (item = System.Console.ReadLine()) != null) { stdInQueue.Enqueue(item); } } private static void SetupSystemConsole() { bool flag = false; bool flag2 = false; string[] commandLineArgs = Environment.GetCommandLineArgs(); for (int i = 0; i < commandLineArgs.Length; i++) { if (commandLineArgs[i] == "-console") { flag = flag || true; } if (commandLineArgs[i] == "-console_detach") { flag2 = flag2 || true; } } if (flag) { systemConsoleType = SystemConsoleType.Attach; if (flag2) { systemConsoleType = SystemConsoleType.Alloc; } } switch (systemConsoleType) { case SystemConsoleType.Attach: AttachConsole(-1); break; case SystemConsoleType.Alloc: AllocConsole(); break; } if (systemConsoleType != 0) { System.Console.SetIn(new StreamReader(System.Console.OpenStandardInput())); stdInReaderThread = new Thread(ThreadedInputQueue); stdInReaderThread.Start(); } } private void Awake() { instance = this; loadingIsComplete = false; StartCoroutine(AwakeCoroutine()); } private IEnumerator AwakeCoroutine() { SetupSystemConsole(); yield return InitConVarsCoroutine(); List instances = HG.Reflection.SearchableAttribute.GetInstances(); int currentPass = 0; foreach (ConCommandAttribute item in instances) { concommandCatalog[item.commandName.ToLower(CultureInfo.InvariantCulture)] = new ConCommand { flags = item.flags, action = (ConCommandDelegate)Delegate.CreateDelegate(typeof(ConCommandDelegate), item.target as MethodInfo), helpText = item.helpText }; currentPass++; if (currentPass >= maxPassesBeforeYielding) { currentPass = 0; yield return null; } } string[] commandLineArgs = Environment.GetCommandLineArgs(); StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder(); stringBuilder.AppendLine("Launch Parameters: "); for (int i = 0; i < commandLineArgs.Length; i++) { stringBuilder.Append(" arg[").AppendInt(i).Append("]=\"") .Append(commandLineArgs[i]) .Append("\"") .AppendLine(); } HG.StringBuilderPool.ReturnStringBuilder(stringBuilder); MPEventSystemManager.availability.CallWhenAvailable(LoadStartupConfigs); loadingIsComplete = true; } private void LoadStartupConfigs() { try { SubmitCmd(null, "exec config"); SubmitCmd(null, "exec autoexec"); } catch (Exception message) { UnityEngine.Debug.LogError(message); } } private void Update() { string cmd; while ((cmd = ReadInputStream()) != null) { SubmitCmd(null, cmd, recordSubmit: true); } } private void OnDestroy() { if (stdInReaderThread != null) { stdInReaderThread = null; } if (systemConsoleType != 0) { systemConsoleType = SystemConsoleType.None; IntPtr consoleWindow = GetConsoleWindow(); if (consoleWindow != IntPtr.Zero) { PostMessage(consoleWindow, 256u, 13, 0); } if (stdInReaderThread != null) { stdInReaderThread.Join(); stdInReaderThread = null; } FreeConsole(); } } private static string LoadConfig(string fileName) { string text = sharedStringBuilder.Clear().Append("/Config/").Append(fileName) .Append(".cfg") .ToString(); try { return PlatformSystems.textDataManager.GetConfFile(fileName, text); } catch (IOException ex) { UnityEngine.Debug.LogFormat("Could not load config {0}: {1}", text, ex.Message); } return null; } public void SaveArchiveConVars() { using MemoryStream memoryStream = new MemoryStream(); using TextWriter textWriter = new StreamWriter(memoryStream, Encoding.UTF8); for (int i = 0; i < archiveConVars.Count; i++) { BaseConVar baseConVar = archiveConVars[i]; textWriter.Write(baseConVar.name); textWriter.Write(" "); textWriter.Write(baseConVar.GetString()); textWriter.Write(";\r\n"); } textWriter.Write("echo \"Loaded archived convars.\";"); textWriter.Flush(); RoR2Application.fileSystem.CreateDirectory("/Config/"); try { using Stream stream = RoR2Application.fileSystem.OpenFile("/Config/config.cfg", FileMode.Create, FileAccess.Write); if (stream != null) { stream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length); stream.Close(); } } catch (IOException ex) { UnityEngine.Debug.LogFormat("Failed to write archived convars: {0}", ex.Message); } } [ConCommand(commandName = "set_vstr", flags = ConVarFlags.None, helpText = "Sets the specified vstr to the specified value.")] private static void CCSetVstr(ConCommandArgs args) { args.CheckArgumentCount(2); instance.vstrs.Add(args[0], args[1]); } [ConCommand(commandName = "exec", flags = ConVarFlags.None, helpText = "Executes a named config from the \"Config/\" folder.")] private static void CCExec(ConCommandArgs args) { if (args.Count > 0) { string text = LoadConfig(args[0]); if (text != null) { instance.SubmitCmd(args.sender, text); } } } [ConCommand(commandName = "echo", flags = ConVarFlags.None, helpText = "Echoes the given text to the console.")] private static void CCEcho(ConCommandArgs args) { if (args.Count <= 0) { ShowHelpText(args.commandName); } } [ConCommand(commandName = "cvarlist", flags = ConVarFlags.None, helpText = "Print all available convars and concommands.")] private static void CCCvarList(ConCommandArgs args) { List list = new List(); foreach (KeyValuePair allConVar in instance.allConVars) { list.Add(allConVar.Key); } foreach (KeyValuePair item in instance.concommandCatalog) { list.Add(item.Key); } list.Sort(); } [ConCommand(commandName = "help", flags = ConVarFlags.None, helpText = "Show help text for the named convar or concommand.")] private static void CCHelp(ConCommandArgs args) { if (args.Count == 0) { instance.SubmitCmd(args.sender, "find \"*\""); } else { ShowHelpText(args[0]); } } [ConCommand(commandName = "find", flags = ConVarFlags.None, helpText = "Find all concommands and convars with the specified substring.")] private static void CCFind(ConCommandArgs args) { if (args.Count == 0) { ShowHelpText("find"); } else { Find(args[0].ToLower(CultureInfo.InvariantCulture)); } } private static string Find(string searchString) { bool flag = searchString == "*"; List list = new List(); foreach (KeyValuePair allConVar in instance.allConVars) { if (flag || allConVar.Key.ToLower(CultureInfo.InvariantCulture).Contains(searchString) || allConVar.Value.helpText.ToLower(CultureInfo.InvariantCulture).Contains(searchString)) { list.Add(allConVar.Key); } } foreach (KeyValuePair item in instance.concommandCatalog) { if (flag || item.Key.ToLower(CultureInfo.InvariantCulture).Contains(searchString) || item.Value.helpText.ToLower(CultureInfo.InvariantCulture).Contains(searchString)) { list.Add(item.Key); } } list.Sort(); string[] array = new string[list.Count]; for (int i = 0; i < list.Count; i++) { array[i] = GetHelpText(list[i]); } return string.Join("\n", array); } [ConCommand(commandName = "clear", flags = ConVarFlags.None, helpText = "Clears the console output.")] private static void CCClear(ConCommandArgs args) { logs.Clear(); Console.onClear?.Invoke(); } private static string GetHelpText(string commandName) { if (instance.concommandCatalog.TryGetValue(commandName, out var value)) { return string.Format(CultureInfo.InvariantCulture, "\"{0}\"\n- {1}", commandName, value.helpText); } BaseConVar baseConVar = instance.FindConVar(commandName); if (baseConVar != null) { return string.Format(CultureInfo.InvariantCulture, "\"{0}\" = \"{1}\"\n - {2}", commandName, baseConVar.GetString(), baseConVar.helpText); } return Find(commandName) + "\nExact Match not found. Use `find \"" + commandName + "\" instead"; } public static void ShowHelpText(string commandName) { } } public class ConstrainToScreen : MonoBehaviour { private static float boundaryUVSize; private static List instanceTransformsList; static ConstrainToScreen() { boundaryUVSize = 0.05f; instanceTransformsList = new List(); SceneCamera.onSceneCameraPreCull += OnSceneCameraPreCull; } private static void OnSceneCameraPreCull(SceneCamera sceneCamera) { Camera camera = sceneCamera.camera; for (int i = 0; i < instanceTransformsList.Count; i++) { Transform transform = instanceTransformsList[i]; UnityEngine.Vector3 position = camera.WorldToViewportPoint(transform.position); position.x = Mathf.Clamp(position.x, boundaryUVSize, 1f - boundaryUVSize); position.y = Mathf.Clamp(position.y, boundaryUVSize, 1f - boundaryUVSize); transform.position = camera.ViewportToWorldPoint(position); } } private void OnEnable() { instanceTransformsList.Add(base.transform); } private void OnDisable() { instanceTransformsList.Remove(base.transform); } } [RequireComponent(typeof(CharacterBody))] public class ContactDamage : MonoBehaviour { protected static FloatConVar cvContactDamageUpdateInterval = new FloatConVar("contact_damage_update_interval", ConVarFlags.Cheat, "0.1", "Frequency that the contact damage fires."); public float damagePerSecondCoefficient = 2f; [Tooltip("The frequency that this can hurt the same target. Is NOT the frequency that it checks for targets!")] public float damageInterval = 0.25f; public float pushForcePerSecond = 4000f; public HitBoxGroup hitBoxGroup; public DamageTypeCombo damageType; public bool doBlastAttackInstead; private OverlapAttack overlapAttack; private CharacterBody characterBody; private TeamComponent teamComponent; private float refreshTimer; private float fireTimer; private bool hasFiredThisUpdate; private void Start() { characterBody = GetComponent(); teamComponent = GetComponent(); InitOverlapAttack(); } private void FixedUpdate() { if (NetworkServer.active) { hasFiredThisUpdate = false; refreshTimer -= Time.fixedDeltaTime; fireTimer -= Time.fixedDeltaTime; if (refreshTimer <= 0f) { refreshTimer = damageInterval; overlapAttack.ResetIgnoredHealthComponents(); overlapAttack.teamIndex = teamComponent.teamIndex; FireOverlaps(); } if (fireTimer <= 0f) { FireOverlaps(); } } } private void InitOverlapAttack() { overlapAttack = new OverlapAttack { attacker = base.gameObject, inflictor = base.gameObject, hitBoxGroup = hitBoxGroup, teamIndex = teamComponent.teamIndex }; } private void FireOverlaps() { if (!hasFiredThisUpdate) { if (overlapAttack == null) { InitOverlapAttack(); } hasFiredThisUpdate = true; fireTimer = cvContactDamageUpdateInterval.value; overlapAttack.damage = characterBody.damage * damagePerSecondCoefficient * damageInterval; overlapAttack.pushAwayForce = pushForcePerSecond * damageInterval; overlapAttack.damageType = damageType; overlapAttack.Fire(); } } } public class ConvertPlayerMoneyToExperience : MonoBehaviour { private Dictionary burstSizes = new Dictionary(); private float burstTimer; public float burstInterval = 0.25f; public int burstCount = 8; private void Start() { if (!NetworkServer.active) { UnityEngine.Debug.LogErrorFormat("Component {0} can only be added on the server!", GetType().Name); UnityEngine.Object.Destroy(this); } else { burstTimer = 0f; } } private void FixedUpdate() { burstTimer -= Time.fixedDeltaTime; if (!(burstTimer <= 0f)) { return; } bool flag = false; ReadOnlyCollection instances = PlayerCharacterMasterController.instances; for (int i = 0; i < instances.Count; i++) { GameObject gameObject = instances[i].gameObject; CharacterMaster component = gameObject.GetComponent(); if (!burstSizes.TryGetValue(gameObject, out var value)) { value = (uint)Mathf.CeilToInt((float)component.money / (float)burstCount); burstSizes[gameObject] = value; } if (value > component.money) { value = component.money; } component.money -= value; GameObject bodyObject = component.GetBodyObject(); ulong num = (ulong)((float)value / 2f / (float)instances.Count); if (value != 0) { flag = true; } if ((bool)bodyObject) { ExperienceManager.instance.AwardExperience(base.transform.position, bodyObject.GetComponent(), num); } else { TeamManager.instance.GiveTeamExperience(component.teamIndex, num); } } if (flag) { burstTimer = burstInterval; } else if (burstTimer < -2.5f) { UnityEngine.Object.Destroy(this); } } } public class Corpse : MonoBehaviour { private class CorpsesMaxConVar : BaseConVar { private static CorpsesMaxConVar instance = new CorpsesMaxConVar("corpses_max", ConVarFlags.Archive | ConVarFlags.Engine, "25", "The maximum number of corpses allowed."); private CorpsesMaxConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { } public override void SetString(string newValue) { if (TextSerialization.TryParseInvariant(newValue, out int result)) { maxCorpses = result; } } public override string GetString() { return TextSerialization.ToStringInvariant(maxCorpses); } } public enum DisposalMode { Hard, OutOfSight, Soft } private class CorpseDisposalConVar : BaseConVar { private static CorpseDisposalConVar instance = new CorpseDisposalConVar("corpses_disposal", ConVarFlags.Archive | ConVarFlags.Engine, null, "The corpse disposal mode. Choices are Hard and OutOfSight."); private CorpseDisposalConVar(string name, ConVarFlags flags, string defaultValue, string helpText) : base(name, flags, defaultValue, helpText) { } public override void SetString(string newValue) { try { DisposalMode disposalMode = (DisposalMode)Enum.Parse(typeof(DisposalMode), newValue, ignoreCase: true); if (disposalMode == Corpse.disposalMode) { return; } Corpse.disposalMode = disposalMode; if (disposalMode == DisposalMode.Hard || disposalMode != DisposalMode.OutOfSight) { return; } foreach (Corpse instances in instancesList) { instances.CollectRenderers(); } } catch (ArgumentException) { Console.ShowHelpText(name); } } public override string GetString() { return disposalMode.ToString(); } } private static readonly List instancesList = new List(); private Renderer[] renderers; public bool dissolve; public bool forceCulled; public float lifeTime; public static float corpseLifeTime = 6f; public static float dissolveTime = 1f; private CharacterModel dm; private static int maxCorpses = 25; private static DisposalMode disposalMode = DisposalMode.OutOfSight; private static int maxChecksPerUpdate = 3; private static int currentCheckIndex = 0; private void CollectRenderers() { if (renderers == null) { renderers = GetComponentsInChildren(); } } private void OnEnable() { instancesList.Add(this); if (disposalMode != 0) { CollectRenderers(); } } private void OnDisable() { instancesList.Remove(this); } [InitDuringStartup] private static void StaticInit() { RoR2Application.onUpdate += StaticUpdate; } private static void IncrementCurrentCheckIndex() { currentCheckIndex++; if (currentCheckIndex >= instancesList.Count) { currentCheckIndex = 0; } } private static bool CheckCorpseOutOfSight(Corpse corpse) { Renderer[] array = corpse.renderers; foreach (Renderer renderer in array) { if ((bool)renderer && renderer.isVisible) { return false; } } return true; } private void GrabDitherController() { dm = GetComponent(); } public void UpdateDissolve() { lifeTime -= Time.deltaTime; float corpseFade = Mathf.Clamp01(lifeTime / dissolveTime); if ((bool)dm) { dm.corpseFade = corpseFade; } if (lifeTime <= 0f) { DestroyCorpse(this); } } private static void StaticUpdate() { if (maxCorpses < 0) { return; } int num = instancesList.Count - maxCorpses; int num2 = Math.Min(instancesList.Count, maxChecksPerUpdate); if (disposalMode == DisposalMode.OutOfSight) { num2 = Math.Min(num2, num); } switch (disposalMode) { case DisposalMode.Hard: { for (int num3 = num - 1; num3 >= 0; num3--) { DestroyCorpse(instancesList[num3]); } break; } case DisposalMode.OutOfSight: { for (int k = 0; k < num2; k++) { IncrementCurrentCheckIndex(); if (CheckCorpseOutOfSight(instancesList[currentCheckIndex])) { DestroyCorpse(instancesList[currentCheckIndex]); } } break; } case DisposalMode.Soft: { for (int i = 0; i < num2; i++) { IncrementCurrentCheckIndex(); Corpse corpse = instancesList[currentCheckIndex]; if (corpse.forceCulled) { DestroyCorpse(corpse); if (num > 0) { num--; } } else if (!corpse.dissolve) { if (num > 0) { num--; corpse.lifeTime = dissolveTime; } else { corpse.lifeTime = corpseLifeTime; } corpse.dissolve = true; } } for (int j = 0; j < instancesList.Count; j++) { if (instancesList[j].dissolve) { instancesList[j].UpdateDissolve(); } } break; } } } private static void DestroyCorpse(Corpse corpse) { if ((bool)corpse) { UnityEngine.Object.Destroy(corpse.gameObject); } } } public class CostHologramContent : MonoBehaviour { public int displayValue; public TextMeshPro targetTextMesh; public CostTypeIndex costType; private static readonly StringBuilder sharedStringBuilder = new StringBuilder(); private int oldDisplayValue; private void FixedUpdate() { if ((bool)targetTextMesh && oldDisplayValue != displayValue) { oldDisplayValue = displayValue; sharedStringBuilder.Clear(); UnityEngine.Color color = UnityEngine.Color.white; CostTypeDef costTypeDef = CostTypeCatalog.GetCostTypeDef(costType); if (costTypeDef != null) { costTypeDef.BuildCostStringStyled(displayValue, sharedStringBuilder, forWorldDisplay: true, includeColor: false); color = costTypeDef.GetCostColor(forWorldDisplay: true); } targetTextMesh.SetText(sharedStringBuilder); targetTextMesh.color = color; } } } [RequireComponent(typeof(VoteController))] public class CreditsController : MonoBehaviour { private CreditsPanelController creditsPanelController; private VoteController voteController; private static GameObject creditsPanelPrefab => LegacyResourcesAPI.Load("Prefabs/UI/Credits/CreditsPanel"); private void Awake() { voteController = GetComponent(); } private void OnEnable() { creditsPanelController = UnityEngine.Object.Instantiate(creditsPanelPrefab, RoR2Application.instance.mainCanvas.transform).GetComponent(); creditsPanelController.voteInfoPanel.voteController = voteController; creditsPanelController.skipButton.onClick.AddListener(SubmitLocalVotesToEnd); PauseManager.IsAbleToPause = false; } private void OnDisable() { PauseManager.IsAbleToPause = true; if ((bool)creditsPanelController) { UnityEngine.Object.Destroy(creditsPanelController.gameObject); } } private void Update() { if (!creditsPanelController) { SubmitLocalVotesToEnd(); base.enabled = false; } } private void SubmitLocalVotesToEnd() { foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList) { readOnlyLocalPlayers.CallCmdSubmitVote(base.gameObject, 0); } } } public class CrocoDamageTypeController : MonoBehaviour { public SkillDef poisonSkillDef; public SkillDef blightSkillDef; public GenericSkill passiveSkillSlot; public DamageTypeCombo GetDamageType() { if ((bool)passiveSkillSlot) { if (passiveSkillSlot.skillDef == poisonSkillDef) { return DamageType.PoisonOnHit; } if (passiveSkillSlot.skillDef == blightSkillDef) { return DamageType.BlightOnHit; } } return DamageType.Generic; } } public class DamageDisplay : MonoBehaviour { private static List instancesList; private static ReadOnlyCollection _readOnlyInstancesList; public TextMeshPro textMeshComponent; public AnimationCurve magnitudeCurve; public float maxLife = 3f; public float gravity = 9.81f; public float magnitude = 3f; public float offset = 20f; private UnityEngine.Vector3 velocity; public float textMagnitude = 0.01f; private float vel; private float life; private float scale = 1f; [HideInInspector] public UnityEngine.Color baseColor = UnityEngine.Color.white; [HideInInspector] public UnityEngine.Color baseOutlineColor = UnityEngine.Color.gray; private GameObject victim; private GameObject attacker; private TeamIndex victimTeam; private TeamIndex attackerTeam; private bool crit; private bool heal; private UnityEngine.Vector3 internalPosition; public static ReadOnlyCollection readOnlyInstancesList => _readOnlyInstancesList; static DamageDisplay() { instancesList = new List(); _readOnlyInstancesList = new ReadOnlyCollection(instancesList); UICamera.onUICameraPreCull += OnUICameraPreCull; RoR2Application.onUpdate += UpdateAll; } private void Start() { velocity = UnityEngine.Vector3.Normalize(UnityEngine.Vector3.up + new UnityEngine.Vector3(UnityEngine.Random.Range(0f - offset, offset), 0f, UnityEngine.Random.Range(0f - offset, offset))) * magnitude; instancesList.Add(this); internalPosition = base.transform.position; } private void OnDestroy() { instancesList.Remove(this); } public void SetValues(GameObject victim, GameObject attacker, float damage, bool crit, DamageColorIndex damageColorIndex) { victimTeam = TeamIndex.Neutral; attackerTeam = TeamIndex.Neutral; scale = 1f; this.victim = victim; this.attacker = attacker; this.crit = crit; baseColor = DamageColor.FindColor(damageColorIndex); string text = Mathf.CeilToInt(Mathf.Abs(damage)).ToString(); heal = damage < 0f; if (heal) { damage = 0f - damage; base.transform.parent = victim.transform; text = "+" + text; baseColor = DamageColor.FindColor(DamageColorIndex.Heal); baseOutlineColor = baseColor * UnityEngine.Color.gray; } if ((bool)victim) { TeamComponent component = victim.GetComponent(); if ((bool)component) { victimTeam = component.teamIndex; } } if ((bool)attacker) { TeamComponent component2 = attacker.GetComponent(); if ((bool)component2) { attackerTeam = component2.teamIndex; } } if (crit) { text += "!"; baseOutlineColor = UnityEngine.Color.red; } textMeshComponent.text = text; UpdateMagnitude(); } private void UpdateMagnitude() { float fontSize = magnitudeCurve.Evaluate(life / maxLife) * textMagnitude * scale; textMeshComponent.fontSize = fontSize; } private static void UpdateAll() { for (int num = instancesList.Count - 1; num >= 0; num--) { instancesList[num].DoUpdate(); } } private void DoUpdate() { UpdateMagnitude(); life += Time.deltaTime; if (life >= maxLife) { UnityEngine.Object.Destroy(base.gameObject); return; } velocity += gravity * UnityEngine.Vector3.down * Time.deltaTime; internalPosition += velocity * Time.deltaTime; } private static void OnUICameraPreCull(UICamera uiCamera) { GameObject gameObject = null; TeamIndex teamIndex = TeamIndex.Neutral; Camera camera = uiCamera.camera; Camera sceneCam = uiCamera.cameraRigController.sceneCam; gameObject = uiCamera.cameraRigController.target; teamIndex = uiCamera.cameraRigController.targetTeamIndex; for (int i = 0; i < instancesList.Count; i++) { DamageDisplay damageDisplay = instancesList[i]; UnityEngine.Color color = UnityEngine.Color.white; if (!damageDisplay.heal) { if (teamIndex == damageDisplay.victimTeam) { color = new UnityEngine.Color(0.5568628f, 0.29411766f, 0.6039216f); } else if (teamIndex == damageDisplay.attackerTeam && gameObject != damageDisplay.attacker) { color = UnityEngine.Color.gray; } } damageDisplay.textMeshComponent.color = UnityEngine.Color.Lerp(UnityEngine.Color.white, damageDisplay.baseColor * color, damageDisplay.life / 0.2f); damageDisplay.textMeshComponent.outlineColor = UnityEngine.Color.Lerp(UnityEngine.Color.white, damageDisplay.baseOutlineColor * color, damageDisplay.life / 0.2f); UnityEngine.Vector3 position = damageDisplay.internalPosition; UnityEngine.Vector3 position2 = sceneCam.WorldToScreenPoint(position); position2.z = ((position2.z > 0f) ? 1f : (-1f)); UnityEngine.Vector3 position3 = camera.ScreenToWorldPoint(position2); damageDisplay.transform.position = position3; } } } [ExecuteAlways] public class DamageNumberManager : MonoBehaviour { private List customData = new List(); private ParticleSystem ps; private const int maxDamageNums = int.MaxValue; public static DamageNumberManager instance { get; private set; } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); } private void OnDisable() { instance = SingletonHelper.Unassign(instance, this); } private void Awake() { ps = GetComponent(); } private void Update() { } public void SpawnDamageNumber(float amount, UnityEngine.Vector3 position, bool crit, TeamIndex teamIndex, DamageColorIndex damageColorIndex) { UnityEngine.Color color = DamageColor.FindColor(damageColorIndex); UnityEngine.Color color2 = UnityEngine.Color.white; switch (teamIndex) { case TeamIndex.None: color2 = UnityEngine.Color.gray; break; case TeamIndex.Monster: color2 = new UnityEngine.Color(0.5568628f, 0.29411766f, 0.6039216f); break; } ps.Emit(new ParticleSystem.EmitParams { position = position, startColor = color * color2, applyShapeToPosition = true }, 1); ps.GetCustomParticleData(customData, ParticleSystemCustomData.Custom1); customData[customData.Count - 1] = new UnityEngine.Vector4(1f, 0f, amount, crit ? 1f : 0f); ps.SetCustomParticleData(customData, ParticleSystemCustomData.Custom1); } } public class DamageTrail : MonoBehaviour { private struct TrailPoint { public UnityEngine.Vector3 position; public float localStartTime; public float localEndTime; public Transform segmentTransform; } [FormerlySerializedAs("updateInterval")] [Tooltip("How often to drop a new point onto the trail.")] public float pointUpdateInterval = 0.2f; [Tooltip("How often the damage trail should deal damage.")] public float damageUpdateInterval = 0.2f; [Tooltip("How large the radius, or width, of the damage detection should be.")] public float radius = 0.5f; [Tooltip("How large the height of the damage detection should be.")] public float height = 0.5f; [Tooltip("How long a point on the trail should last.")] public float pointLifetime = 3f; [Tooltip("The line renderer to use for display.")] public LineRenderer lineRenderer; public bool active = true; [Tooltip("Prefab to use per segment.")] public GameObject segmentPrefab; public bool destroyTrailSegments; public float damagePerSecond; public GameObject owner; private HashSet ignoredObjects = new HashSet(); private TeamIndex teamIndex; private new Transform transform; private List pointsList; private float localTime; private float nextTrailPointUpdate; private float nextTrailDamageUpdate; private static float optimizedDamageUpdateinterval; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] private static void Init() { RoR2Application.onUpdate += UpdateOptimizedDamageUpdateInterval; } private void Awake() { pointsList = new List(); transform = base.transform; } private void Start() { localTime = 0f; AddPoint(); AddPoint(); } private static void UpdateOptimizedDamageUpdateInterval() { float b = 0.4f; float a = 0.2f; float num = 60f; float num2 = 1f / Time.deltaTime; if (num2 > num) { optimizedDamageUpdateinterval = a; return; } float a2 = (num - num2) / 30f; a2 = Mathf.Min(a2, 1f); optimizedDamageUpdateinterval = Mathf.Lerp(a, b, a2); } private void OnDisable() { if (!EffectManager.UsePools) { return; } for (int num = pointsList.Count - 1; num >= 0; num--) { if ((bool)pointsList[num].segmentTransform) { GameObject gameObject = pointsList[num].segmentTransform.gameObject; EffectManagerHelper component = gameObject.GetComponent(); if (component != null && component.OwningPool != null) { component.OwningPool.ReturnObject(component); } else { UnityEngine.Debug.LogFormat("DamageTrail.OnDestroy: No EFH on {0} ({1})", gameObject.name, gameObject.GetInstanceID()); } } pointsList.RemoveAt(num); } } private void FixedUpdate() { MyFixedUpdate(Time.fixedDeltaTime); } private void MyFixedUpdate(float deltaTime) { localTime += deltaTime; if (localTime >= nextTrailPointUpdate) { nextTrailPointUpdate += pointUpdateInterval; UpdateTrail(active); } if (localTime >= nextTrailDamageUpdate) { nextTrailDamageUpdate += optimizedDamageUpdateinterval; DoDamage(optimizedDamageUpdateinterval); } if (pointsList.Count > 0) { TrailPoint value = pointsList[pointsList.Count - 1]; value.position = transform.position; value.localEndTime = localTime + pointLifetime; pointsList[pointsList.Count - 1] = value; if ((bool)value.segmentTransform) { value.segmentTransform.position = transform.position; } if ((bool)lineRenderer) { lineRenderer.SetPosition(pointsList.Count - 1, value.position); } } if (!segmentPrefab) { return; } UnityEngine.Vector3 position = transform.position; for (int num = pointsList.Count - 1; num >= 0; num--) { Transform segmentTransform = pointsList[num].segmentTransform; if ((bool)segmentTransform) { segmentTransform.LookAt(position, UnityEngine.Vector3.up); UnityEngine.Vector3 vector = pointsList[num].position - position; segmentTransform.position = position + vector * 0.5f; float num2 = Mathf.Clamp01(Mathf.InverseLerp(pointsList[num].localStartTime, pointsList[num].localEndTime, localTime)); UnityEngine.Vector3 localScale = new UnityEngine.Vector3(radius * (1f - num2), radius * (1f - num2), vector.magnitude); segmentTransform.localScale = localScale; position = pointsList[num].position; } } } private void UpdateTrail(bool addPoint) { while (pointsList.Count > 0 && pointsList[0].localEndTime <= localTime) { RemovePoint(0); } if (addPoint) { AddPoint(); } if ((bool)lineRenderer) { UpdateLineRenderer(lineRenderer); } } private void DoDamage(float damageInterval) { if (!NetworkServer.active || pointsList.Count == 0) { return; } UnityEngine.Vector3 vector = pointsList[pointsList.Count - 1].position; ignoredObjects.Clear(); TeamIndex attackerTeamIndex = TeamIndex.Neutral; float damage = damagePerSecond * damageInterval; if ((bool)owner) { ignoredObjects.Add(owner); attackerTeamIndex = TeamComponent.GetObjectTeam(owner); } DamageInfo damageInfo = new DamageInfo(); damageInfo.attacker = owner; damageInfo.inflictor = base.gameObject; damageInfo.crit = false; damageInfo.damage = damage; damageInfo.damageColorIndex = DamageColorIndex.Item; damageInfo.damageType = DamageType.Generic; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.procCoefficient = 0f; for (int num = pointsList.Count - 2; num >= 0; num--) { UnityEngine.Vector3 position = pointsList[num].position; UnityEngine.Vector3 forward = position - vector; UnityEngine.Vector3 halfExtents = new UnityEngine.Vector3(radius, height, forward.magnitude); UnityEngine.Vector3 center = UnityEngine.Vector3.Lerp(position, vector, 0.5f); UnityEngine.Quaternion orientation = Util.QuaternionSafeLookRotation(forward); Collider[] colliders; int num2 = HGPhysics.OverlapBox(out colliders, center, halfExtents, orientation, LayerIndex.entityPrecise.mask); for (int i = 0; i < num2; i++) { HurtBox component = colliders[i].GetComponent(); if (!component) { continue; } HealthComponent healthComponent = component.healthComponent; if ((bool)healthComponent) { GameObject item = healthComponent.gameObject; if (!ignoredObjects.Contains(item) && FriendlyFireManager.ShouldSplashHitProceed(healthComponent, attackerTeamIndex)) { ignoredObjects.Add(item); damageInfo.position = colliders[i].transform.position; healthComponent.TakeDamage(damageInfo); } } } HGPhysics.ReturnResults(colliders); vector = position; } } private void UpdateLineRenderer(LineRenderer lineRenderer) { lineRenderer.positionCount = pointsList.Count; for (int i = 0; i < pointsList.Count; i++) { lineRenderer.SetPosition(i, pointsList[i].position); } } private void AddPoint() { TrailPoint trailPoint = default(TrailPoint); trailPoint.position = transform.position; trailPoint.localStartTime = localTime; trailPoint.localEndTime = localTime + pointLifetime; TrailPoint item = trailPoint; if ((bool)segmentPrefab) { if (!EffectManager.ShouldUsePooledEffect(segmentPrefab)) { item.segmentTransform = UnityEngine.Object.Instantiate(segmentPrefab, transform).transform; } else { EffectManagerHelper andActivatePooledEffect = EffectManager.GetAndActivatePooledEffect(segmentPrefab, transform, inResetLocal: true); item.segmentTransform = andActivatePooledEffect.gameObject.transform; } } pointsList.Add(item); } private void RemovePoint(int pointIndex) { if (destroyTrailSegments) { if ((bool)pointsList[pointIndex].segmentTransform) { if (!EffectManager.UsePools) { UnityEngine.Object.Destroy(pointsList[pointIndex].segmentTransform.gameObject); } else { GameObject gameObject = pointsList[pointIndex].segmentTransform.gameObject; EffectManagerHelper component = gameObject.GetComponent(); if (component != null && component.OwningPool != null) { component.OwningPool.ReturnObject(component); } else { UnityEngine.Debug.LogFormat("DamageTrail.RemovePoint: No EFH on {0} ({1})", gameObject.name, gameObject.GetInstanceID()); UnityEngine.Object.Destroy(gameObject); } } } } else if (EffectManager.UsePools && (bool)pointsList[pointIndex].segmentTransform) { pointsList[pointIndex].segmentTransform.gameObject.transform.SetParent(null); } pointsList.RemoveAt(pointIndex); } private void OnDrawGizmos() { UnityEngine.Vector3 vector = pointsList[pointsList.Count - 1].position; for (int num = pointsList.Count - 2; num >= 0; num--) { UnityEngine.Vector3 position = pointsList[num].position; UnityEngine.Vector3 forward = position - vector; UnityEngine.Vector3 s = new UnityEngine.Vector3(radius, 0.5f, forward.magnitude); UnityEngine.Vector3 pos = UnityEngine.Vector3.Lerp(position, vector, 0.5f); UnityEngine.Quaternion q = Util.QuaternionSafeLookRotation(forward); Gizmos.matrix = UnityEngine.Matrix4x4.TRS(pos, q, s); Gizmos.color = UnityEngine.Color.blue; Gizmos.DrawWireCube(UnityEngine.Vector3.zero, UnityEngine.Vector3.one); Gizmos.matrix = UnityEngine.Matrix4x4.identity; vector = position; } } } [RequireComponent(typeof(CharacterBody))] public class DeathRewards : MonoBehaviour, IOnKilledServerReceiver { [Obsolete("'logUnlockableName' is discontinued. Use 'logUnlockableDef' instead.", true)] [Tooltip("'logUnlockableName' is discontinued. Use 'logUnlockableDef' instead.")] public string logUnlockableName = ""; public UnlockableDef logUnlockableDef; public PickupDropTable bossDropTable; private uint fallbackGold; private CharacterBody characterBody; private static GameObject coinEffectPrefab; private static GameObject logbookPrefab; [Header("Deprecated")] public SerializablePickupIndex bossPickup; public uint goldReward { get { if (!characterBody.master) { return fallbackGold; } return characterBody.master.money; } set { if ((bool)characterBody.master) { characterBody.master.money = value; } else { fallbackGold = value; } } } public uint expReward { get; set; } public int spawnValue { get; set; } [InitDuringStartup] private static void LoadAssets() { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/CoinEmitter"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { coinEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/NetworkedObjects/LogPickup"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { logbookPrefab = x.Result; }; } private void Awake() { characterBody = GetComponent(); } public void OnKilledServer(DamageReport damageReport) { CharacterBody attackerBody = damageReport.attackerBody; if (!attackerBody) { return; } UnityEngine.Vector3 corePosition = characterBody.corePosition; uint num = goldReward; if (Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse6) { num = (uint)((float)num * 0.8f); } TeamManager.instance.GiveTeamMoney(damageReport.attackerTeamIndex, num); EffectManager.SpawnEffect(coinEffectPrefab, new EffectData { origin = corePosition, genericFloat = goldReward, scale = characterBody.radius }, transmit: true); float num2 = 1f + (characterBody.level - 1f) * 0.3f; int num3 = 0; double num4 = 0.0; if (attackerBody.GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff) > 0 && attackerBody.luminousShotReady) { int itemCount = attackerBody.inventory.GetItemCount(DLC2Content.Items.IncreasePrimaryDamage); num3 = attackerBody.GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff); num4 = (float)expReward * num2 * (0.1f * (float)itemCount) * (float)num3; num4 = Math.Round(num4); if (num4 < 1.0) { num4 = 1.0; } _ = expReward; } ExperienceManager.instance.AwardExperience(corePosition, attackerBody, (uint)((double)((float)expReward * num2) + num4)); _ = expReward; if ((bool)logUnlockableDef && Run.instance.CanUnlockableBeGrantedThisRun(logUnlockableDef) && Util.CheckRoll(characterBody.isChampion ? 3f : 1f, damageReport.attackerMaster)) { GameObject obj = UnityEngine.Object.Instantiate(logbookPrefab, corePosition, UnityEngine.Random.rotation); obj.GetComponentInChildren().unlockableDef = logUnlockableDef; obj.GetComponent().teamIndex = TeamIndex.Player; NetworkServer.Spawn(obj); } } [ConCommand(commandName = "migrate_death_rewards_unlockables", flags = ConVarFlags.Cheat, helpText = "Migrates CharacterDeath component .logUnlockableName to .LogUnlockableDef for all instances.")] private static void CCMigrateDeathRewardUnlockables(ConCommandArgs args) { DeathRewards[] array = Resources.FindObjectsOfTypeAll(); foreach (DeathRewards deathRewards in array) { FieldInfo field = typeof(DeathRewards).GetField("logUnlockableName"); string text = ((string)field.GetValue(deathRewards)) ?? string.Empty; UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(text); if (!unlockableDef && text != string.Empty) { args.Log("DeathRewards component on object " + deathRewards.gameObject.name + " has a defined value for 'logUnlockableName' but it doesn't map to any known unlockable. Migration skipped. logUnlockableName='logUnlockableName'"); } else if (deathRewards.logUnlockableDef == unlockableDef) { field.SetValue(deathRewards, string.Empty); EditorUtil.SetDirty(deathRewards); EditorUtil.SetDirty(deathRewards.gameObject); } else if ((bool)deathRewards.logUnlockableDef) { args.Log($"DeathRewards component on object {deathRewards.gameObject.name} has a 'logUnlockableDef' field value which differs from the 'logUnlockableName' lookup. Migration skipped. logUnlockableDef={deathRewards.logUnlockableDef} logUnlockableName={text}"); } else { deathRewards.logUnlockableDef = unlockableDef; field.SetValue(deathRewards, string.Empty); EditorUtil.SetDirty(deathRewards); EditorUtil.SetDirty(deathRewards.gameObject); args.Log($"DeathRewards component on object {deathRewards.gameObject.name} migrated. logUnlockableDef={deathRewards.logUnlockableDef} logUnlockableName={text}"); } } } } internal class DeathZone : MonoBehaviour { public void OnTriggerEnter(Collider other) { if (NetworkServer.active) { HealthComponent component = other.GetComponent(); if ((bool)component) { DamageInfo damageInfo = new DamageInfo(); damageInfo.position = other.transform.position; damageInfo.attacker = null; damageInfo.inflictor = base.gameObject; damageInfo.damage = 999999f; component.TakeDamage(damageInfo); } } } } public class DebuffZone : MonoBehaviour { [Tooltip("The buff type to grant")] public BuffDef buffType; [Tooltip("The buff duration")] public float buffDuration; public string buffApplicationSoundString; public GameObject buffApplicationEffectPrefab; private void Awake() { } private void OnTriggerEnter(Collider other) { if (!NetworkServer.active || !buffType) { return; } CharacterBody component = other.GetComponent(); if ((bool)component) { component.AddTimedBuff(buffType.buffIndex, buffDuration); Util.PlaySound(buffApplicationSoundString, component.gameObject); if ((bool)buffApplicationEffectPrefab) { EffectManager.SpawnEffect(buffApplicationEffectPrefab, new EffectData { origin = component.mainHurtBox.transform.position, scale = component.radius }, transmit: true); } } } } public class DebugOverlay : MonoBehaviour { public class MeshDrawer : IDisposable { private GameObject gameObject; private MeshFilter meshFilter; private MeshRenderer meshRenderer; public bool hasMeshOwnership; public Transform transform { get; private set; } public bool enabled { get { if ((bool)gameObject) { return gameObject.activeSelf; } return false; } set { if ((bool)gameObject) { gameObject.SetActive(value); } } } public Mesh mesh { get { return meshFilter.sharedMesh; } set { if (!(meshFilter.sharedMesh == value)) { if ((bool)meshFilter.sharedMesh && hasMeshOwnership) { UnityEngine.Object.Destroy(meshFilter.sharedMesh); } meshFilter.sharedMesh = value; } } } public Material material { get { return meshRenderer.sharedMaterial; } set { meshRenderer.sharedMaterial = value; } } public MeshDrawer(Transform parent) { gameObject = new GameObject("MeshDrawer"); transform = gameObject.transform; transform.SetParent(parent); meshFilter = gameObject.AddComponent(); meshRenderer = gameObject.AddComponent(); material = defaultWireMaterial; } public void Dispose() { mesh = null; UnityEngine.Object.Destroy(gameObject); gameObject = null; transform = null; meshFilter = null; meshRenderer = null; } } private static DebugOverlay instance; private new Transform transform; public static Material defaultWireMaterial; private void Awake() { transform = base.transform; } [InitDuringStartup] private static void Init() { LegacyResourcesAPI.LoadAsyncCallback("Materials/UI/matDebugUI", delegate(Material operationResult) { defaultWireMaterial = operationResult; }); GameObject obj = new GameObject("DebugOverlay"); instance = obj.AddComponent(); UnityEngine.Object.DontDestroyOnLoad(obj); } public static MeshDrawer GetMeshDrawer() { return new MeshDrawer(instance.transform); } } public class Debug_CombatOptimizationCommands : MonoBehaviour { public void SubmitCombatOptimizationCommands() { Console.instance.SubmitCmd(null, "give_item BleedOnHit 50"); Console.instance.SubmitCmd(null, "give_item BleedOnHitAndExplode 50"); StartCoroutine(GenerateEnemies()); } private IEnumerator GenerateEnemies() { for (int q = 0; q < 12; q++) { Console.instance.SubmitCmd(null, "create_master BeetleMaster"); yield return 0; Console.instance.SubmitCmd(null, "create_master LemurianMaster"); yield return 0; } } } [RequireComponent(typeof(TeamFilter))] public class DelayBlast : MonoBehaviour { [HideInInspector] public UnityEngine.Vector3 position; [HideInInspector] public GameObject attacker; [HideInInspector] public GameObject inflictor; [HideInInspector] public float baseDamage; [HideInInspector] public bool crit; [HideInInspector] public float baseForce; [HideInInspector] public float radius; [HideInInspector] public UnityEngine.Vector3 bonusForce; [HideInInspector] public float maxTimer; [HideInInspector] public DamageColorIndex damageColorIndex; [HideInInspector] public BlastAttack.FalloffModel falloffModel; [HideInInspector] public DamageTypeCombo damageType = DamageType.Generic; [HideInInspector] public float procCoefficient = 1f; public GameObject explosionEffect; public GameObject delayEffect; public float timerStagger; private float timer; private bool hasSpawnedDelayEffect; private TeamFilter teamFilter; private void Awake() { teamFilter = GetComponent(); if (!NetworkServer.active) { base.enabled = false; } } private void FixedUpdate() { if (NetworkServer.active) { timer += Time.fixedDeltaTime; if ((bool)delayEffect && !hasSpawnedDelayEffect && timer > timerStagger) { hasSpawnedDelayEffect = true; EffectManager.SpawnEffect(delayEffect, new EffectData { origin = base.transform.position, rotation = Util.QuaternionSafeLookRotation(base.transform.forward), scale = radius }, transmit: true); } if (timer >= maxTimer + timerStagger) { Detonate(); } } } public void Detonate() { EffectManager.SpawnEffect(explosionEffect, new EffectData { origin = base.transform.position, rotation = Util.QuaternionSafeLookRotation(base.transform.forward), scale = radius }, transmit: true); BlastAttack blastAttack = new BlastAttack(); blastAttack.position = position; blastAttack.baseDamage = baseDamage; blastAttack.baseForce = baseForce; blastAttack.bonusForce = bonusForce; blastAttack.radius = radius; blastAttack.attacker = attacker; blastAttack.inflictor = inflictor; blastAttack.teamIndex = teamFilter.teamIndex; blastAttack.crit = crit; blastAttack.damageColorIndex = damageColorIndex; blastAttack.damageType = damageType; blastAttack.falloffModel = falloffModel; blastAttack.procCoefficient = procCoefficient; blastAttack.Fire(); UnityEngine.Object.Destroy(base.gameObject); } } public class DelusionChestController : MonoBehaviour { private const int DELUSION_PICKUP_INDEXES_NUMBER = 3; public ChestBehavior delusionChest; private PickupIndex _delusionPickupIndex = PickupIndex.none; private Dictionary _delusionPickupIndexesTable; private NetworkUIPromptController _netUIPromptController; private PickupPickerController _pickupPickerController; private PickupIndex _selectedPickupIndex = PickupIndex.none; private Interactor interactor; private Inventory interactorInventory; private Interactor previousInteractor; private bool hasBeenReset; public PickupIndex DelusionPickupIndex { get { return _delusionPickupIndex; } set { _delusionPickupIndex = value; } } public PickupIndex SelectedPickupIndex { get { return _selectedPickupIndex; } set { _selectedPickupIndex = value; } } public bool IsDelusionChoiceReady => _delusionPickupIndex != PickupIndex.none; public bool isDelusionSelected => _selectedPickupIndex != PickupIndex.none; public static bool isDelusionEnable => RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Delusion); private void Start() { delusionChest = GetComponent(); _netUIPromptController = GetComponent(); _pickupPickerController = GetComponent(); _netUIPromptController.enabled = false; _pickupPickerController.enabled = false; _pickupPickerController.SetAvailable(newAvailable: false); _delusionPickupIndexesTable = new Dictionary(); base.enabled = isDelusionEnable; hasBeenReset = false; } public void ResetChestForDelusion() { if (!hasBeenReset) { UnityEngine.Debug.LogError("reset chest for delusion"); EntityStateMachine component = GetComponent(); PurchaseInteraction component2 = GetComponent(); if ((bool)component) { component.SetNextState(new Closing()); UnityEngine.Object.Destroy(component2); _netUIPromptController.enabled = true; _pickupPickerController.enabled = true; _pickupPickerController.SetAvailable(newAvailable: true); Util.PlaySound("Play_ui_artifact_delusion_reset", base.gameObject); hasBeenReset = true; } } } public void GenerateDelusionPickupIndexes(Interactor activator) { if (_delusionPickupIndexesTable.TryGetValue(activator, out var value)) { return; } value = new PickupIndex[3] { _delusionPickupIndex, default(PickupIndex), default(PickupIndex) }; interactorInventory = activator.GetComponent()?.inventory; interactor = activator; if ((bool)interactorInventory) { List availableItems = GetAvailableItems(interactorInventory.itemAcquisitionOrder); if (availableItems.Count < 2) { AppendAvailableItems(ref availableItems); } for (int i = 1; i < 3; i++) { int maxExclusive = availableItems.Count - 1; int index = UnityEngine.Random.Range(0, maxExclusive); value[i] = PickupCatalog.FindPickupIndex(availableItems[index]); availableItems.RemoveAt(index); } GenerateRandomPickupIndexes(value); _delusionPickupIndexesTable[activator] = value; } } private void AppendAvailableItems(ref List availableItems) { for (int i = availableItems.Count; i < 2; i++) { ItemIndex itemIndex = delusionChest.GetRandomPickupIndex().itemIndex; if (IsItemValid(itemIndex)) { availableItems.Add(itemIndex); } } } private List GetRandomAvailableItems() { List list = new List(); for (int i = 0; i < 10; i++) { ItemIndex itemIndex = delusionChest.GetRandomPickupIndex().itemIndex; if (IsItemValid(itemIndex)) { list.Add(itemIndex); } } return list; } private bool IsItemValid(ItemIndex item) { bool flag = false; bool flag2 = true; bool flag3 = false; ItemDef itemDef = ItemCatalog.GetItemDef(item); ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(itemDef.tier); if ((!itemTierDef || itemTierDef.canScrap) && itemDef.canRemove && !itemDef.hidden && itemDef.DoesNotContainTag(ItemTag.Scrap) && itemDef.DoesNotContainTag(ItemTag.WorldUnique) && _delusionPickupIndex.itemIndex != item) { flag = true; } BasicPickupDropTable basicPickupDropTable = delusionChest.dropTable as BasicPickupDropTable; if ((bool)basicPickupDropTable && itemTierDef != null) { if (basicPickupDropTable.IsFilterRequired()) { flag2 = basicPickupDropTable.PassesFilter(PickupCatalog.FindPickupIndex(item)); } if (basicPickupDropTable.tier1Weight != 0f && itemTierDef.tier == ItemTier.Tier1 && Util.CheckRoll(basicPickupDropTable.tier1Weight * 100f)) { flag3 = true; } else if (itemTierDef.tier == ItemTier.Tier2 && Util.CheckRoll(basicPickupDropTable.tier2Weight * 100f)) { flag3 = true; } else if (itemTierDef.tier == ItemTier.Tier3 && Util.CheckRoll(basicPickupDropTable.tier3Weight * 100f)) { flag3 = true; } } return flag && flag2 && flag3; } private List GetAvailableItems(List items) { List list = new List(); for (int i = 0; i < items.Count; i++) { if (IsItemValid(items[i])) { list.Add(items[i]); } } return list; } private void GenerateRandomPickupIndexes(PickupIndex[] indexes) { for (int i = 0; i < 2; i++) { int num = UnityEngine.Random.Range(i, 3); PickupIndex pickupIndex = indexes[i]; indexes[i] = indexes[num]; indexes[num] = pickupIndex; } } public bool IsSelectedCorrectly() { return _delusionPickupIndex == SelectedPickupIndex; } public void RemoveDelusionChoice() { if ((bool)interactorInventory) { GameObject effectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/DelusionItemDissolveVFX"); EffectData effectData = new EffectData { origin = interactor.transform.position, genericFloat = 1.5f, genericUInt = (uint)(_selectedPickupIndex.itemIndex + 1) }; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true); interactorInventory.RemoveItem(_selectedPickupIndex.itemIndex); } } public PickupIndex[] GetPickupIndexes(Interactor activator) { if (_delusionPickupIndexesTable.TryGetValue(activator, out var value)) { return value; } return null; } } public struct DeployableInfo { public Deployable deployable; public DeployableSlot slot; } public enum DeployableSlot { EngiMine, EngiTurret, BeetleGuardAlly, EngiBubbleShield, LoaderPylon, EngiSpiderMine, RoboBallMini, ParentPodAlly, ParentAlly, PowerWard, CrippleWard, DeathProjectile, RoboBallRedBuddy, RoboBallGreenBuddy, GummyClone, RailgunnerBomb, LunarSunBomb, VendingMachine, VoidMegaCrabItem, DroneWeaponsDrone, MinorConstructOnKill, CaptainSupplyDrop, None } public class Deployable : MonoBehaviour { [NonSerialized] public CharacterMaster ownerMaster; public UnityEvent onUndeploy; private void OnDestroy() { if (NetworkServer.active && (bool)ownerMaster) { ownerMaster.RemoveDeployable(this); } } public void DestroyGameObject() { if (NetworkServer.active) { UnityEngine.Object.Destroy(base.gameObject); } } } [RequireComponent(typeof(TeamFilter))] public class DeskPlantController : MonoBehaviour { private abstract class DeskPlantBaseState : BaseState { protected DeskPlantController controller; protected abstract bool showSeedObject { get; } protected abstract bool showPlantObject { get; } protected abstract float CalcScale(); public override void OnEnter() { base.OnEnter(); controller = GetComponent(); controller.seedObject.SetActive(showSeedObject); controller.plantObject.SetActive(showPlantObject); } public override void Update() { base.Update(); if (showPlantObject) { float num = CalcScale(); UnityEngine.Vector3 vector = new UnityEngine.Vector3(num, num, num); Transform transform = controller.plantObject.transform; if (transform.localScale != vector) { transform.localScale = vector; } } } } private class SeedState : DeskPlantBaseState { protected override bool showSeedObject => true; protected override bool showPlantObject => false; protected override float CalcScale() { return 1f; } public override void OnEnter() { base.OnEnter(); Util.PlaySound("Play_item_proc_interstellarDeskPlant_grow", base.gameObject); GetComponent().Play(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= seedDuration) { outer.SetNextState(new SproutState()); } } } private class SproutState : DeskPlantBaseState { protected override bool showSeedObject => false; protected override bool showPlantObject => true; protected override float CalcScale() { float time = Mathf.Clamp01(base.age / scaleDuration); return linearRampUp.Evaluate(time) * easeUp.Evaluate(time); } public override void OnEnter() { base.OnEnter(); Util.PlaySound("Play_item_proc_interstellarDeskPlant_bloom", base.gameObject); } public override void OnExit() { base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= scaleDuration) { outer.SetNextState(new MainState()); } } } private class MainState : DeskPlantBaseState { private GameObject deskplantWard; protected override bool showSeedObject => false; protected override bool showPlantObject => true; protected override float CalcScale() { return 1f; } public override void OnEnter() { base.OnEnter(); if (NetworkServer.active && !deskplantWard) { deskplantWard = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/DeskplantWard"), controller.plantObject.transform.position, UnityEngine.Quaternion.identity); deskplantWard.GetComponent().teamIndex = controller.teamFilter.teamIndex; if ((bool)deskplantWard) { HealingWard component = deskplantWard.GetComponent(); component.healFraction = 0.05f; component.healPoints = 0f; component.Networkradius = controller.healingRadius + controller.radiusIncreasePerStack * (float)controller.itemCount; component.enabled = true; } NetworkServer.Spawn(deskplantWard); } } public override void OnExit() { if ((bool)deskplantWard) { EntityState.Destroy(deskplantWard); } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= mainDuration) { outer.SetNextState(new DeathState()); } } } private class DeathState : DeskPlantBaseState { protected override bool showSeedObject => false; protected override bool showPlantObject => true; protected override float CalcScale() { float time = Mathf.Clamp01(base.age / scaleDuration); return linearRampDown.Evaluate(time) * easeDown.Evaluate(time); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= scaleDuration) { EntityState.Destroy(base.gameObject); } } } public GameObject plantObject; public GameObject seedObject; public GameObject groundFX; public float healingRadius; public float radiusIncreasePerStack = 5f; private static readonly float seedDuration = 5f; private static readonly float mainDuration = 10f; private static readonly float scaleDuration = 0.5f; private static readonly AnimationCurve linearRampUp = AnimationCurve.Linear(0f, 0f, 1f, 1f); private static readonly AnimationCurve linearRampDown = AnimationCurve.Linear(0f, 1f, 1f, 0f); private static readonly AnimationCurve easeUp = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); private static readonly AnimationCurve easeDown = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); public TeamFilter teamFilter { get; private set; } public int itemCount { get; set; } private void Awake() { teamFilter = GetComponent(); plantObject.SetActive(value: false); seedObject.SetActive(value: false); if (NetworkServer.active && Physics.Raycast(base.transform.position, UnityEngine.Vector3.down, out var hitInfo, 500f, LayerIndex.world.mask)) { base.transform.position = hitInfo.point; base.transform.up = hitInfo.normal; } } public void SeedPlanting() { EffectManager.SimpleEffect(groundFX, base.transform.position, UnityEngine.Quaternion.identity, transmit: false); } } public class DestroyOnDestroy : MonoBehaviour { [Tooltip("The GameObject to destroy when this object is destroyed.")] public GameObject target; private void OnDestroy() { UnityEngine.Object.Destroy(target); } } public class DestroyOnTimer : MonoBehaviour { public float duration; public bool resetAgeOnDisable; private float age; private EffectManagerHelper efh; private void Start() { if (!efh) { efh = GetComponent(); } } private void FixedUpdate() { age += Time.fixedDeltaTime; if (age > duration) { if ((bool)efh && efh.OwningPool != null) { efh.OwningPool.ReturnObject(efh); } else { UnityEngine.Object.Destroy(base.gameObject); } } } private void OnDisable() { if (resetAgeOnDisable || ((bool)efh && efh.OwningPool != null)) { age = 0f; } } } public class DestroyOnUnseen : MonoBehaviour { public bool cull; private Renderer rend; private void Start() { rend = GetComponentInChildren(); } private void Update() { if (cull && (bool)rend && !rend.isVisible) { UnityEngine.Object.Destroy(base.gameObject); } } } public class DetachParticleOnDestroyAndEndEmission : MonoBehaviour { public ParticleSystem particleSystem; private void OnDisable() { if ((bool)particleSystem) { ParticleSystem.EmissionModule emission = particleSystem.emission; emission.enabled = false; ParticleSystem.MainModule main = particleSystem.main; main.stopAction = ParticleSystemStopAction.Destroy; particleSystem.Stop(); particleSystem.transform.SetParent(null); if (particleSystem.isStopped) { UnityEngine.Object.Destroy(particleSystem.gameObject); } } } } public class DetachTrailOnDestroy : MonoBehaviour { [FormerlySerializedAs("trail")] public TrailRenderer[] targetTrailRenderers; [SerializeField] [Tooltip("Use this to disable the script from functioning.")] private bool IgnoreDestroy; private void OnDestroy() { if (IgnoreDestroy) { return; } for (int i = 0; i < targetTrailRenderers.Length; i++) { TrailRenderer trailRenderer = targetTrailRenderers[i]; if ((bool)trailRenderer) { trailRenderer.transform.SetParent(null); trailRenderer.autodestruct = true; } } targetTrailRenderers = null; } } public class DirectorSpawnRequest { public SpawnCard spawnCard; public DirectorPlacementRule placementRule; public Xoroshiro128Plus rng; public GameObject summonerBodyObject; public TeamIndex? teamIndexOverride; public bool ignoreTeamMemberLimit; public Action onSpawnedServer; public DirectorSpawnRequest(SpawnCard spawnCard, DirectorPlacementRule placementRule, Xoroshiro128Plus rng) { this.spawnCard = spawnCard; this.placementRule = placementRule; this.rng = rng; } } public class DirectorCore : MonoBehaviour { private struct NodeReference : IEquatable { public readonly NodeGraph nodeGraph; public readonly NodeGraph.NodeIndex nodeIndex; public NodeReference(NodeGraph nodeGraph, NodeGraph.NodeIndex nodeIndex) { this.nodeGraph = nodeGraph; this.nodeIndex = nodeIndex; } public bool Equals(NodeReference other) { if (object.Equals(nodeGraph, other.nodeGraph)) { return nodeIndex.Equals(other.nodeIndex); } return false; } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is NodeReference other) { return Equals(other); } return false; } public override int GetHashCode() { return (((nodeGraph != null) ? nodeGraph.GetHashCode() : 0) * 397) ^ nodeIndex.GetHashCode(); } } public enum MonsterSpawnDistance { Standard, Close, Far } public static List spawnedObjects = new List(); private NodeReference[] occupiedNodes = Array.Empty(); public static DirectorCore instance { get; private set; } public GameObject[] GetObjectsOfTeam(TeamIndex _teamIndex) { List list = new List(); for (int i = 0; i < spawnedObjects.Count; i++) { CharacterMaster component = spawnedObjects[i].GetComponent(); if ((bool)component && component.teamIndex == _teamIndex) { spawnedObjects.Add(spawnedObjects[i]); } } return list.ToArray(); } private void OnEnable() { if (!instance) { instance = this; return; } UnityEngine.Debug.LogErrorFormat(this, "Duplicate instance of singleton class {0}. Only one should exist at a time.", GetType().Name); } private void OnDisable() { if (instance == this) { instance = null; } } public void AddOccupiedNode(NodeGraph nodeGraph, NodeGraph.NodeIndex nodeIndex) { Array.Resize(ref occupiedNodes, occupiedNodes.Length + 1); occupiedNodes[occupiedNodes.Length - 1] = new NodeReference(nodeGraph, nodeIndex); } private bool CheckPositionFree(NodeGraph nodeGraph, NodeGraph.NodeIndex nodeIndex, SpawnCard spawnCard) { if (Array.IndexOf(value: new NodeReference(nodeGraph, nodeIndex), array: occupiedNodes) != -1) { return false; } float num = HullDef.Find(spawnCard.hullSize).radius * 0.7f; nodeGraph.GetNodePosition(nodeIndex, out var position); if (spawnCard.nodeGraphType == MapNodeGroup.GraphType.Ground) { position += UnityEngine.Vector3.up * (num + 0.25f); } return !HGPhysics.DoesOverlapSphere(position, num, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault | (int)LayerIndex.CommonMasks.fakeActorLayers); } public GameObject TrySpawnObject([NotNull] DirectorSpawnRequest directorSpawnRequest) { SpawnCard spawnCard = directorSpawnRequest.spawnCard; DirectorPlacementRule placementRule = directorSpawnRequest.placementRule; Xoroshiro128Plus rng = directorSpawnRequest.rng; NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(spawnCard.nodeGraphType); if (nodeGraph == null) { UnityEngine.Debug.LogError($"Unable to find nodegraph for {SceneInfo.instance.sceneDef.cachedName} of type {spawnCard.nodeGraphType}."); return null; } GameObject result = null; switch (placementRule.placementMode) { case DirectorPlacementRule.PlacementMode.Direct: { UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(0f, rng.nextNormalizedFloat * 360f, 0f); result = spawnCard.DoSpawn(placementRule.spawnOnTarget ? placementRule.spawnOnTarget.position : directorSpawnRequest.placementRule.position, placementRule.spawnOnTarget ? placementRule.spawnOnTarget.rotation : quaternion, directorSpawnRequest).spawnedInstance; break; } case DirectorPlacementRule.PlacementMode.Approximate: { List list = nodeGraph.FindNodesInRangeWithFlagConditions(placementRule.targetPosition, placementRule.minDistance, placementRule.maxDistance, (HullMask)(1 << (int)spawnCard.hullSize), spawnCard.requiredFlags, spawnCard.forbiddenFlags, placementRule.preventOverhead); if (list.Count == 0) { } while (list.Count > 0) { int index = rng.RangeInt(0, list.Count); NodeGraph.NodeIndex nodeIndex4 = list[index]; if (nodeGraph.GetNodePosition(nodeIndex4, out var position4) && CheckPositionFree(nodeGraph, nodeIndex4, spawnCard)) { UnityEngine.Quaternion rotation4 = GetRotationFacingTargetPositionFromPoint(position4); result = spawnCard.DoSpawn(position4, rotation4, directorSpawnRequest).spawnedInstance; if (spawnCard.occupyPosition) { AddOccupiedNode(nodeGraph, nodeIndex4); } break; } list.RemoveAt(index); } break; } case DirectorPlacementRule.PlacementMode.NearestNode: { NodeGraph.NodeIndex nodeIndex3 = nodeGraph.FindClosestNodeWithFlagConditions(placementRule.targetPosition, spawnCard.hullSize, spawnCard.requiredFlags, spawnCard.forbiddenFlags, placementRule.preventOverhead); if (nodeGraph.GetNodePosition(nodeIndex3, out var position3)) { UnityEngine.Quaternion rotation3 = GetRotationFacingTargetPositionFromPoint(position3); result = spawnCard.DoSpawn(position3, rotation3, directorSpawnRequest).spawnedInstance; if (spawnCard.occupyPosition) { AddOccupiedNode(nodeGraph, nodeIndex3); } } break; } case DirectorPlacementRule.PlacementMode.ApproximateSimple: { NodeGraph.NodeIndex nodeIndex2 = nodeGraph.FindClosestNodeWithFlagConditions(placementRule.targetPosition, spawnCard.hullSize, spawnCard.requiredFlags, spawnCard.forbiddenFlags, placementRule.preventOverhead); if (nodeGraph.GetNodePosition(nodeIndex2, out var position2) && CheckPositionFree(nodeGraph, nodeIndex2, spawnCard)) { UnityEngine.Quaternion rotation2 = GetRotationFacingTargetPositionFromPoint(position2); result = spawnCard.DoSpawn(position2, rotation2, directorSpawnRequest).spawnedInstance; if (spawnCard.occupyPosition) { AddOccupiedNode(nodeGraph, nodeIndex2); } } break; } case DirectorPlacementRule.PlacementMode.Random: { List activeNodesForHullMaskWithFlagConditions = nodeGraph.GetActiveNodesForHullMaskWithFlagConditions((HullMask)(1 << (int)spawnCard.hullSize), spawnCard.requiredFlags, spawnCard.forbiddenFlags); if (activeNodesForHullMaskWithFlagConditions.Count == 0) { } while (activeNodesForHullMaskWithFlagConditions.Count > 0) { int index2 = rng.RangeInt(0, activeNodesForHullMaskWithFlagConditions.Count); NodeGraph.NodeIndex nodeIndex5 = activeNodesForHullMaskWithFlagConditions[index2]; if (nodeGraph.GetNodePosition(nodeIndex5, out var position5) && CheckPositionFree(nodeGraph, nodeIndex5, spawnCard)) { UnityEngine.Quaternion rotation5 = UnityEngine.Quaternion.Euler(0f, rng.nextNormalizedFloat * 360f, 0f); result = spawnCard.DoSpawn(position5, rotation5, directorSpawnRequest).spawnedInstance; if (spawnCard.occupyPosition) { AddOccupiedNode(nodeGraph, nodeIndex5); } break; } activeNodesForHullMaskWithFlagConditions.RemoveAt(index2); } break; } case DirectorPlacementRule.PlacementMode.RandomNormalized: { if (SceneInfo.instance.approximateMapBoundMesh == null) { break; } Bounds bounds = SceneInfo.instance.approximateMapBoundMesh.bounds; UnityEngine.Vector3 position = new UnityEngine.Vector3(rng.RangeFloat(bounds.min.x, bounds.max.x), rng.RangeFloat(bounds.min.y, bounds.max.y), rng.RangeFloat(bounds.min.z, bounds.max.z)); NodeGraph.NodeIndex nodeIndex = nodeGraph.FindClosestNodeWithFlagConditions(position, spawnCard.hullSize, spawnCard.requiredFlags, spawnCard.forbiddenFlags, placementRule.preventOverhead); if (nodeGraph.GetNodePosition(nodeIndex, out position) && CheckPositionFree(nodeGraph, nodeIndex, spawnCard)) { UnityEngine.Quaternion rotation = GetRotationFacingTargetPositionFromPoint(position); result = spawnCard.DoSpawn(position, rotation, directorSpawnRequest).spawnedInstance; if (spawnCard.occupyPosition) { AddOccupiedNode(nodeGraph, nodeIndex); } } break; } } return result; UnityEngine.Quaternion GetRotationFacingTargetPositionFromPoint(UnityEngine.Vector3 point) { point.y = placementRule.targetPosition.y; return Util.QuaternionSafeLookRotation(placementRule.targetPosition - point); } } public static void GetMonsterSpawnDistance(MonsterSpawnDistance input, out float minimumDistance, out float maximumDistance) { minimumDistance = 0f; maximumDistance = 0f; switch (input) { case MonsterSpawnDistance.Close: minimumDistance = 8f; maximumDistance = 20f; break; case MonsterSpawnDistance.Standard: minimumDistance = 25f; maximumDistance = 40f; break; case MonsterSpawnDistance.Far: minimumDistance = 70f; maximumDistance = 120f; break; } } } public class DirectorPlacementRule { public enum PlacementMode { Direct, Approximate, ApproximateSimple, NearestNode, Random, RandomNormalized } public Transform spawnOnTarget; public UnityEngine.Vector3 position; public PlacementMode placementMode; public float minDistance; public float maxDistance; public bool preventOverhead; public UnityEngine.Vector3 targetPosition { get { if (!spawnOnTarget) { return position; } return spawnOnTarget.position; } } } [Serializable] public class DirectorCard { public SpawnCard spawnCard; public int selectionWeight; public DirectorCore.MonsterSpawnDistance spawnDistance; public bool preventOverhead; public int minimumStageCompletions; [Tooltip("'requiredUnlockable' will be discontinued. Use 'requiredUnlockableDef' instead.")] [Obsolete("'requiredUnlockable' will be discontinued. Use 'requiredUnlockableDef' instead.", false)] public string requiredUnlockable; [Tooltip("'forbiddenUnlockable' will be discontinued. Use 'forbiddenUnlockableDef' instead.")] [Obsolete("'forbiddenUnlockable' will be discontinued. Use 'forbiddenUnlockableDef' instead.", false)] public string forbiddenUnlockable; public UnlockableDef requiredUnlockableDef; public UnlockableDef forbiddenUnlockableDef; public int cost => spawnCard.directorCreditCost; [Obsolete("'CardIsValid' is confusingly named. Use 'IsAvailable' instead.", false)] public bool CardIsValid() { return IsAvailable(); } public bool IsAvailable() { ref string reference = ref requiredUnlockable; ref string reference2 = ref forbiddenUnlockable; if (!requiredUnlockableDef && !string.IsNullOrEmpty(reference)) { requiredUnlockableDef = UnlockableCatalog.GetUnlockableDef(reference); reference = null; } if (!forbiddenUnlockableDef && !string.IsNullOrEmpty(reference2)) { forbiddenUnlockableDef = UnlockableCatalog.GetUnlockableDef(reference2); reference2 = null; } bool flag = !requiredUnlockableDef || Run.instance.IsUnlockableUnlocked(requiredUnlockableDef); bool flag2 = (bool)forbiddenUnlockableDef && Run.instance.DoesEveryoneHaveThisUnlockableUnlocked(forbiddenUnlockableDef); if ((bool)Run.instance && Run.instance.stageClearCount >= minimumStageCompletions && flag && !flag2 && (bool)spawnCard && (bool)spawnCard.prefab) { ExpansionRequirementComponent component = spawnCard.prefab.GetComponent(); if (!component) { CharacterMaster component2 = spawnCard.prefab.GetComponent(); if ((bool)component2 && (bool)component2.bodyPrefab) { component = component2.bodyPrefab.GetComponent(); } } if ((bool)component) { return Run.instance.IsExpansionEnabled(component.requiredExpansion); } return true; } return false; } } public class DisableCollisionsBetweenColliders : MonoBehaviour { public Collider[] collidersA; public Collider[] collidersB; public void Awake() { Collider[] array = collidersA; foreach (Collider collider in array) { Collider[] array2 = collidersB; foreach (Collider collider2 in array2) { Physics.IgnoreCollision(collider, collider2); } } } } [RequireComponent(typeof(SphereCollider))] public class DisableCollisionsIfInTrigger : MonoBehaviour { public Collider colliderToIgnore; private SphereCollider trigger; public void Awake() { trigger = GetComponent(); } private void OnTriggerEnter(Collider other) { if ((bool)trigger) { UnityEngine.Vector3 position = base.transform.position; UnityEngine.Vector3 position2 = other.transform.position; float num = trigger.radius * Mathf.Max(base.transform.lossyScale.x, base.transform.lossyScale.y, base.transform.lossyScale.z); float num2 = num * num; if ((position - position2).sqrMagnitude < num2) { Physics.IgnoreCollision(colliderToIgnore, other); } } } } public class DisableIfGameModded : MonoBehaviour { public void OnEnable() { if (RoR2Application.isModded) { base.gameObject.SetActive(value: false); } } } public class DisableIfNoExpansion : MonoBehaviour { [SerializeField] private ExpansionDef expansionDef; private void Awake() { EntitlementManager.onEntitlementsUpdated += Reset; Reset(); } private void OnDestroy() { EntitlementManager.onEntitlementsUpdated -= Reset; } private void Reset() { if ((bool)expansionDef && !EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(expansionDef.requiredEntitlement)) { base.gameObject.SetActive(value: false); } else { base.gameObject.SetActive(value: true); } } } public class DisableParticleEmissionAndDestroyOnTimer : MonoBehaviour { [Tooltip("How long to wait before destroying or repooling the object")] public float waitDuration = 3f; [Tooltip("Particle systems to be stopped.")] public List particleSystems; public bool StartParticleEmissionOnEnable = true; private bool countdownStarted; private float timeRemaining; private EffectManagerHelper efh; private void Awake() { efh = GetComponent(); } public void DisableParticlesStartTimer() { countdownStarted = true; timeRemaining = waitDuration; foreach (ParticleSystem particleSystem in particleSystems) { particleSystem.Stop(); } } private void Update() { if (countdownStarted) { timeRemaining -= Time.deltaTime; if (timeRemaining < 0f) { DestroyOrRepoolObject(); } } } private void DestroyOrRepoolObject() { if ((bool)efh && efh.OwningPool != null) { efh.OwningPool.ReturnObject(efh); } else { UnityEngine.Object.Destroy(base.gameObject); } } private void OnEnable() { countdownStarted = false; if (!StartParticleEmissionOnEnable) { return; } foreach (ParticleSystem particleSystem in particleSystems) { particleSystem.Play(); } } } public class DitherModel : MonoBehaviour { [HideInInspector] public float fade = 1f; public float oldFade = 1f; public Collider bounds; public Renderer[] renderers; private MaterialPropertyBlock propertyStorage; private static List instancesList; static DitherModel() { instancesList = new List(); SceneCamera.onSceneCameraPreRender += OnSceneCameraPreRender; } private static void OnSceneCameraPreRender(SceneCamera sceneCamera) { if ((bool)sceneCamera.cameraRigController) { RefreshObstructorsForCamera(sceneCamera.cameraRigController); } } private static void RefreshObstructorsForCamera(CameraRigController cameraRigController) { UnityEngine.Vector3 position = cameraRigController.transform.position; for (int i = 0; i < instancesList.Count; i++) { DitherModel ditherModel = instancesList[i]; if ((bool)ditherModel.bounds) { UnityEngine.Vector3 a = ditherModel.bounds.ClosestPointOnBounds(position); if (cameraRigController.enableFading) { ditherModel.fade = Mathf.Clamp01(Util.Remap(UnityEngine.Vector3.Distance(a, position), cameraRigController.fadeStartDistance, cameraRigController.fadeEndDistance, 0f, 1f)); } else { ditherModel.fade = 1f; } ditherModel.UpdateDither(); } else { UnityEngine.Debug.LogFormat("{0} has missing collider for dither model", ditherModel.gameObject); } } } private void UpdateDither() { if (fade != oldFade) { for (int num = renderers.Length - 1; num >= 0; num--) { Renderer obj = renderers[num]; obj.GetPropertyBlock(propertyStorage); propertyStorage.SetFloat("_Fade", fade); obj.SetPropertyBlock(propertyStorage); } } oldFade = fade; } private void Awake() { propertyStorage = new MaterialPropertyBlock(); } private void OnEnable() { instancesList.Add(this); } private void OnDisable() { instancesList.Remove(this); } } public class DotController : NetworkBehaviour { public enum DotIndex { None = -1, Bleed, Burn, Helfire, PercentBurn, Poison, Blight, SuperBleed, StrongerBurn, Fracture, LunarRuin, Count } public class DotDef { public float interval; public float damageCoefficient; public DamageColorIndex damageColorIndex; public BuffDef associatedBuff; public BuffDef terminalTimedBuff; public float terminalTimedBuffDuration; public bool resetTimerOnAdd; } private class DotStack { public DotIndex dotIndex; public DotDef dotDef; public GameObject attackerObject; public TeamIndex attackerTeam; public float timer; public float damage; public DamageTypeCombo damageType; public void Reset() { dotIndex = DotIndex.Bleed; dotDef = null; attackerObject = null; attackerTeam = TeamIndex.Neutral; timer = 0f; damage = 0f; damageType = default(DamageTypeCombo); } } private sealed class DotStackPool : BasePool { protected override void ResetItem(DotStack item) { item.Reset(); } } private class PendingDamage { public GameObject attackerObject; public float totalDamage; public DamageTypeCombo damageType; public void Reset() { attackerObject = null; totalDamage = 0f; damageType = default(DamageTypeCombo); } } private sealed class PendingDamagePool : BasePool { protected override void ResetItem(PendingDamage item) { item.Reset(); } } public delegate void OnDotInflictedServerGlobalDelegate(DotController dotController, ref InflictDotInfo inflictDotInfo); public const float minDamagePerTick = 1f; private static DotDef[] dotDefs; private static readonly Dictionary dotControllerLocator = new Dictionary(); private static readonly List instancesList = new List(); public static readonly ReadOnlyCollection readOnlyInstancesList = instancesList.AsReadOnly(); public static GameObject FractureImpactEffectPrefab; public static GameObject HelfireIgniteEffectPrefab; public static GameObject DotControllerPrefab; [SyncVar] private NetworkInstanceId victimObjectId; private GameObject _victimObject; private CharacterBody _victimBody; private BurnEffectController burnEffectController; private BurnEffectController strongerBurnEffectController; private BurnEffectController helfireEffectController; private BurnEffectController poisonEffectController; private BurnEffectController blightEffectController; private EffectManagerHelper bleedEffect; private EffectManagerHelper superBleedEffect; private EffectManagerHelper preFractureEffect; [SyncVar] private uint activeDotFlags; private static readonly DotStackPool dotStackPool = new DotStackPool(); private List dotStackList; private float[] dotTimers; private static readonly PendingDamagePool pendingDamagePool = new PendingDamagePool(); private int recordedVictimInstanceId = -1; public GameObject victimObject { get { if (!_victimObject) { if (NetworkServer.active) { _victimObject = NetworkServer.FindLocalObject(victimObjectId); } else if (NetworkClient.active) { _victimObject = ClientScene.FindLocalObject(victimObjectId); } } return _victimObject; } set { NetworkvictimObjectId = value.GetComponent().netId; } } private CharacterBody victimBody { get { if (!_victimBody && (bool)victimObject) { _victimBody = victimObject.GetComponent(); } return _victimBody; } } private HealthComponent victimHealthComponent => victimBody?.healthComponent; private TeamIndex victimTeam { get { if (!victimBody) { return TeamIndex.None; } return victimBody.teamComponent.teamIndex; } } public NetworkInstanceId NetworkvictimObjectId { get { return victimObjectId; } [param: In] set { SetSyncVar(value, ref victimObjectId, 1u); } } public uint NetworkactiveDotFlags { get { return activeDotFlags; } [param: In] set { SetSyncVar(value, ref activeDotFlags, 2u); } } public static event OnDotInflictedServerGlobalDelegate onDotInflictedServerGlobal; public static DotDef GetDotDef(DotIndex dotIndex) { if (dotIndex < DotIndex.Bleed || dotIndex >= DotIndex.Count) { return null; } return dotDefs[(int)dotIndex]; } [SystemInitializer(new Type[] { typeof(BuffCatalog) })] private static void InitDotCatalog() { dotDefs = new DotDef[10]; dotDefs[0] = new DotDef { interval = 0.25f, damageCoefficient = 0.2f, damageColorIndex = DamageColorIndex.Bleed, associatedBuff = RoR2Content.Buffs.Bleeding }; dotDefs[1] = new DotDef { interval = 0.2f, damageCoefficient = 0.1f, damageColorIndex = DamageColorIndex.Item, associatedBuff = RoR2Content.Buffs.OnFire, terminalTimedBuff = RoR2Content.Buffs.OnFire, terminalTimedBuffDuration = 1f }; dotDefs[7] = new DotDef { interval = 0.2f, damageCoefficient = 0.1f, damageColorIndex = DamageColorIndex.Item, associatedBuff = DLC1Content.Buffs.StrongerBurn, terminalTimedBuff = DLC1Content.Buffs.StrongerBurn, terminalTimedBuffDuration = 1f }; dotDefs[3] = new DotDef { interval = 0.2f, damageCoefficient = 0.1f, damageColorIndex = DamageColorIndex.Item, associatedBuff = RoR2Content.Buffs.OnFire }; dotDefs[2] = new DotDef { interval = 0.2f, damageCoefficient = 0.02f, damageColorIndex = DamageColorIndex.Item }; dotDefs[4] = new DotDef { interval = 0.333f, damageCoefficient = 0.333f, damageColorIndex = DamageColorIndex.Poison, associatedBuff = RoR2Content.Buffs.Poisoned }; dotDefs[5] = new DotDef { interval = 0.333f, damageCoefficient = 0.2f, damageColorIndex = DamageColorIndex.Poison, associatedBuff = RoR2Content.Buffs.Blight }; dotDefs[6] = new DotDef { interval = 0.25f, damageCoefficient = 0.333f, damageColorIndex = DamageColorIndex.SuperBleed, associatedBuff = RoR2Content.Buffs.SuperBleed }; dotDefs[8] = new DotDef { interval = 3f, damageCoefficient = 4f, damageColorIndex = DamageColorIndex.Void, associatedBuff = DLC1Content.Buffs.Fracture, resetTimerOnAdd = false }; dotDefs[9] = new DotDef { interval = 3f, damageCoefficient = 0f, damageColorIndex = DamageColorIndex.Default, associatedBuff = DLC2Content.Buffs.lunarruin, resetTimerOnAdd = true }; } public bool HasDotActive(DotIndex dotIndex) { return (activeDotFlags & (1 << (int)dotIndex)) != 0; } private void Awake() { if (NetworkServer.active) { dotStackList = new List(); dotTimers = new float[10]; } instancesList.Add(this); } private void OnDestroy() { if (NetworkServer.active) { for (int num = dotStackList.Count - 1; num >= 0; num--) { RemoveDotStackAtServer(num); } } instancesList.Remove(this); if (recordedVictimInstanceId != -1) { dotControllerLocator.Remove(recordedVictimInstanceId); } } private void FixedUpdate() { if (!victimObject) { if (NetworkServer.active) { HandleDestroy(); } return; } UpdateDotVisuals(); if (!NetworkServer.active) { return; } for (DotIndex dotIndex = DotIndex.Bleed; dotIndex < DotIndex.Count; dotIndex++) { uint num = (uint)(1 << (int)dotIndex); if ((activeDotFlags & num) == 0) { continue; } DotDef dotDef = GetDotDef(dotIndex); float num2 = dotTimers[(int)dotIndex] - Time.fixedDeltaTime; if (num2 <= 0f) { num2 += dotDef.interval; int remainingActive = 0; EvaluateDotStacksForType(dotIndex, dotDef.interval, out remainingActive); NetworkactiveDotFlags = activeDotFlags & ~num; if (remainingActive != 0) { NetworkactiveDotFlags = activeDotFlags | num; } } dotTimers[(int)dotIndex] = num2; } if (dotStackList.Count == 0) { HandleDestroy(); } } private void HandleDestroy() { RepoolEffect(ref bleedEffect); RepoolEffect(ref superBleedEffect); RepoolEffect(ref preFractureEffect); UnityEngine.Object.Destroy(base.gameObject); } private EffectManagerHelper GetPooledEffect(string _path) { return EffectManager.GetAndActivatePooledEffect(LegacyResourcesAPI.Load(_path), base.transform, inResetLocal: true); } private void RepoolEffect(ref EffectManagerHelper emh) { if ((bool)emh) { if (emh.OwningPool != null) { emh.transform.SetParent(null); emh.ReturnToPool(); } else { UnityEngine.Object.Destroy(emh.gameObject); } emh = null; } } private void UpdateDotVisuals() { if (!victimBody) { return; } ModelLocator modelLocator = null; base.transform.position = victimBody.corePosition; if ((activeDotFlags & (true ? 1u : 0u)) != 0) { if (!bleedEffect) { bleedEffect = GetPooledEffect("Prefabs/BleedEffect"); } } else if ((bool)bleedEffect) { RepoolEffect(ref bleedEffect); } if ((activeDotFlags & 2u) != 0 || (activeDotFlags & 8u) != 0) { if (!burnEffectController) { modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent()); if ((bool)modelLocator && (bool)modelLocator.modelTransform) { burnEffectController = base.gameObject.AddComponent(); burnEffectController.effectType = BurnEffectController.normalEffect; burnEffectController.target = modelLocator.modelTransform.gameObject; } } } else if ((bool)burnEffectController) { burnEffectController.HandleDestroy(); burnEffectController = null; } if ((activeDotFlags & 0x80u) != 0) { if (!strongerBurnEffectController) { modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent()); if ((bool)modelLocator && (bool)modelLocator.modelTransform) { strongerBurnEffectController = base.gameObject.AddComponent(); strongerBurnEffectController.effectType = BurnEffectController.strongerBurnEffect; strongerBurnEffectController.target = modelLocator.modelTransform.gameObject; } } } else if ((bool)strongerBurnEffectController) { strongerBurnEffectController.HandleDestroy(); strongerBurnEffectController = null; } if ((activeDotFlags & 4u) != 0) { if (!helfireEffectController) { modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent()); if ((bool)modelLocator && (bool)modelLocator.modelTransform) { helfireEffectController = base.gameObject.AddComponent(); helfireEffectController.effectType = BurnEffectController.helfireEffect; helfireEffectController.target = modelLocator.modelTransform.gameObject; } } } else if ((bool)helfireEffectController) { helfireEffectController.HandleDestroy(); helfireEffectController = null; } if ((activeDotFlags & 0x10u) != 0) { if (!poisonEffectController) { modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent()); if ((bool)modelLocator && (bool)modelLocator.modelTransform) { poisonEffectController = base.gameObject.AddComponent(); poisonEffectController.effectType = BurnEffectController.poisonEffect; poisonEffectController.target = modelLocator.modelTransform.gameObject; } } } else if ((bool)poisonEffectController) { poisonEffectController.HandleDestroy(); poisonEffectController = null; } if ((activeDotFlags & 0x20u) != 0) { if (!blightEffectController) { modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent()); if ((bool)modelLocator && (bool)modelLocator.modelTransform) { blightEffectController = base.gameObject.AddComponent(); blightEffectController.effectType = BurnEffectController.blightEffect; blightEffectController.target = modelLocator.modelTransform.gameObject; } } } else if ((bool)blightEffectController) { blightEffectController.HandleDestroy(); blightEffectController = null; } if ((activeDotFlags & 0x40u) != 0) { if (!superBleedEffect) { superBleedEffect = GetPooledEffect("Prefabs/SuperBleedEffect"); } } else if ((bool)superBleedEffect) { RepoolEffect(ref superBleedEffect); } if ((activeDotFlags & 0x100u) != 0) { if (!preFractureEffect) { preFractureEffect = GetPooledEffect("Prefabs/PreFractureEffect"); } } else if ((bool)preFractureEffect) { RepoolEffect(ref preFractureEffect); } } private void LateUpdate() { if ((bool)victimObject) { base.transform.position = victimObject.transform.position; } } private static void AddPendingDamageEntry(List pendingDamages, GameObject attackerObject, float damage, DamageTypeCombo damageType) { for (int i = 0; i < pendingDamages.Count; i++) { if (pendingDamages[i].attackerObject == attackerObject) { pendingDamages[i].totalDamage += damage; return; } } PendingDamage pendingDamage = pendingDamagePool.Request(); pendingDamage.attackerObject = attackerObject; pendingDamage.totalDamage = damage; pendingDamage.damageType = damageType; pendingDamages.Add(pendingDamage); } private void OnDotStackAddedServer(DotStack dotStack) { DotDef dotDef = dotStack.dotDef; if (dotDef.associatedBuff != null && (bool)victimBody) { victimBody.AddBuff(dotDef.associatedBuff.buffIndex); } } private void OnDotStackRemovedServer(DotStack dotStack) { DotDef dotDef = dotStack.dotDef; if ((bool)victimBody) { if (dotDef.associatedBuff != null) { victimBody.RemoveBuff(dotDef.associatedBuff.buffIndex); } if (dotDef.terminalTimedBuff != null) { victimBody.AddTimedBuff(dotDef.terminalTimedBuff, dotDef.terminalTimedBuffDuration); } } } private void RemoveDotStackAtServer(int i) { DotStack dotStack = dotStackList[i]; dotStackList.RemoveAt(i); OnDotStackRemovedServer(dotStack); dotStackPool.Return(dotStack); } private void EvaluateDotStacksForType(DotIndex dotIndex, float dt, out int remainingActive) { List list = CollectionPool>.RentCollection(); remainingActive = 0; DotDef dotDef = GetDotDef(dotIndex); for (int num = dotStackList.Count - 1; num >= 0; num--) { DotStack dotStack = dotStackList[num]; if (dotStack.dotIndex == dotIndex) { dotStack.timer -= dt; AddPendingDamageEntry(list, dotStack.attackerObject, dotStack.damage, dotStack.damageType); if (dotStack.timer <= 0f) { RemoveDotStackAtServer(num); } else { remainingActive++; } } } if ((bool)victimObject) { if ((bool)victimBody && dotIndex == DotIndex.Fracture && list.Count > 0) { if (FractureImpactEffectPrefab == null) { FractureImpactEffectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/FractureImpactEffect"); } EffectManager.SpawnEffect(FractureImpactEffectPrefab, new EffectData { origin = victimBody.corePosition }, transmit: true); } if ((bool)victimHealthComponent) { UnityEngine.Vector3 corePosition = victimBody.corePosition; for (int i = 0; i < list.Count; i++) { DamageInfo damageInfo = new DamageInfo(); damageInfo.attacker = list[i].attackerObject; damageInfo.crit = false; damageInfo.damage = list[i].totalDamage; damageInfo.force = UnityEngine.Vector3.zero; damageInfo.inflictor = base.gameObject; damageInfo.position = corePosition; damageInfo.procCoefficient = 0f; damageInfo.damageColorIndex = dotDef.damageColorIndex; damageInfo.damageType = list[i].damageType | DamageType.DoT; damageInfo.dotIndex = dotIndex; victimHealthComponent.TakeDamage(damageInfo); } } } for (int j = 0; j < list.Count; j++) { pendingDamagePool.Return(list[j]); } CollectionPool>.ReturnCollection(list); } [Server] private void AddDot(GameObject attackerObject, float duration, DotIndex dotIndex, float damageMultiplier, uint? maxStacksFromAttacker, float? totalDamage, DotIndex? preUpgradeDotIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DotController::AddDot(UnityEngine.GameObject,System.Single,RoR2.DotController/DotIndex,System.Single,System.Nullable`1,System.Nullable`1,System.Nullable`1)' called on client"); return; } TeamIndex attackerTeam = TeamIndex.Neutral; float num = 0f; TeamComponent component = attackerObject.GetComponent(); if ((bool)component) { attackerTeam = component.teamIndex; } CharacterBody component2 = attackerObject.GetComponent(); if ((bool)component2) { num = component2.damage; } DotDef dotDef = dotDefs[(int)dotIndex]; DotStack dotStack = dotStackPool.Request(); dotStack.dotIndex = dotIndex; dotStack.dotDef = dotDef; dotStack.attackerObject = attackerObject; dotStack.attackerTeam = attackerTeam; dotStack.timer = duration; dotStack.damage = dotDef.damageCoefficient * num * damageMultiplier; dotStack.damageType = DamageType.Generic; int num2 = 0; int i = 0; for (int count = dotStackList.Count; i < count; i++) { if (dotStackList[i].dotIndex == dotIndex) { num2++; } } switch (dotIndex) { case DotIndex.Bleed: case DotIndex.SuperBleed: case DotIndex.Fracture: case DotIndex.LunarRuin: { int k = 0; for (int count3 = dotStackList.Count; k < count3; k++) { if (dotStackList[k].dotIndex == dotIndex) { dotStackList[k].timer = Mathf.Max(dotStackList[k].timer, duration); } } break; } case DotIndex.Burn: case DotIndex.StrongerBurn: dotStack.damage = Mathf.Min(dotStack.damage, victimBody.healthComponent.fullCombinedHealth * 0.01f * damageMultiplier); break; case DotIndex.PercentBurn: dotStack.damage = Mathf.Min(dotStack.damage, victimBody.healthComponent.fullCombinedHealth * 0.01f); break; case DotIndex.Helfire: { if (!component2) { return; } HealthComponent healthComponent = component2.healthComponent; if (!healthComponent) { return; } dotStack.damage = Mathf.Min(healthComponent.fullCombinedHealth * 0.01f * damageMultiplier, victimBody.healthComponent.fullCombinedHealth * 0.01f * damageMultiplier); if ((bool)victimBody) { if (HelfireIgniteEffectPrefab == null) { HelfireIgniteEffectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/HelfireIgniteEffect"); } EffectManager.SpawnEffect(HelfireIgniteEffectPrefab, new EffectData { origin = victimBody.corePosition }, transmit: true); } break; } case DotIndex.Poison: { float a = victimHealthComponent.fullCombinedHealth / 100f * 1f * dotDef.interval; dotStack.damage = Mathf.Min(Mathf.Max(a, dotStack.damage), dotStack.damage * 50f); dotStack.damageType = DamageType.NonLethal; int j = 0; for (int count2 = dotStackList.Count; j < count2; j++) { if (dotStackList[j].dotIndex == DotIndex.Poison) { dotStackList[j].timer = Mathf.Max(dotStackList[j].timer, duration); dotStackList[j].damage = dotStack.damage; return; } } if (num2 == 0) { component2?.master?.playerStatsComponent?.currentStats.PushStatValue(StatDef.totalCrocoInfectionsInflicted, 1uL); } break; } } if ((dotIndex == DotIndex.Helfire || (preUpgradeDotIndex.HasValue && preUpgradeDotIndex.Value == DotIndex.Helfire)) && victimObject == attackerObject) { dotStack.damageType |= (DamageTypeCombo)(DamageType.NonLethal | DamageType.Silent); } dotStack.damage = Mathf.Max(1f, dotStack.damage); if (totalDamage.HasValue && dotStack.damage != 0f) { duration = totalDamage.Value * dotDef.interval / dotStack.damage; dotStack.timer = duration; } if (maxStacksFromAttacker.HasValue) { DotStack dotStack2 = null; int num3 = 0; int l = 0; for (int count4 = dotStackList.Count; l < count4; l++) { DotStack dotStack3 = dotStackList[l]; if (dotStack3.dotIndex == dotIndex && dotStack3.attackerObject == attackerObject) { num3++; if (dotStack2 == null || dotStack3.timer < dotStack2.timer) { dotStack2 = dotStack3; } } } if (num3 >= maxStacksFromAttacker.Value && dotStack2 != null) { if (dotStack2.timer < duration) { dotStack2.timer = duration; dotStack2.damage = dotStack.damage; dotStack2.damageType = dotStack.damageType; } return; } } if (num2 == 0 || dotDef.resetTimerOnAdd) { NetworkactiveDotFlags = activeDotFlags | (uint)(1 << (int)dotIndex); dotTimers[(int)dotIndex] = dotDef.interval; } dotStackList.Add(dotStack); OnDotStackAddedServer(dotStack); } [Server] public static void InflictDot(ref InflictDotInfo inflictDotInfo) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DotController::InflictDot(RoR2.InflictDotInfo&)' called on client"); } else { if (inflictDotInfo.dotIndex < DotIndex.Bleed || inflictDotInfo.dotIndex >= DotIndex.Count || ImmuneToDebuffBehavior.OverrideDot(inflictDotInfo) || !inflictDotInfo.victimObject || !inflictDotInfo.attackerObject) { return; } if (!dotControllerLocator.TryGetValue(inflictDotInfo.victimObject.GetInstanceID(), out var value)) { if (DotControllerPrefab == null) { DotControllerPrefab = LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/DotController"); } GameObject obj = UnityEngine.Object.Instantiate(DotControllerPrefab); value = obj.GetComponent(); value.victimObject = inflictDotInfo.victimObject; value.recordedVictimInstanceId = inflictDotInfo.victimObject.GetInstanceID(); dotControllerLocator.Add(value.recordedVictimInstanceId, value); NetworkServer.Spawn(obj); } value.AddDot(inflictDotInfo.attackerObject, inflictDotInfo.duration, inflictDotInfo.dotIndex, inflictDotInfo.damageMultiplier, inflictDotInfo.maxStacksFromAttacker, inflictDotInfo.totalDamage, inflictDotInfo.preUpgradeDotIndex); DotController.onDotInflictedServerGlobal?.Invoke(value, ref inflictDotInfo); } } [Server] public static void InflictDot(GameObject victimObject, GameObject attackerObject, DotIndex dotIndex, float duration = 8f, float damageMultiplier = 1f, uint? maxStacksFromAttacker = null) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DotController::InflictDot(UnityEngine.GameObject,UnityEngine.GameObject,RoR2.DotController/DotIndex,System.Single,System.Single,System.Nullable`1)' called on client"); return; } InflictDotInfo inflictDotInfo = default(InflictDotInfo); inflictDotInfo.victimObject = victimObject; inflictDotInfo.attackerObject = attackerObject; inflictDotInfo.dotIndex = dotIndex; inflictDotInfo.duration = duration; inflictDotInfo.damageMultiplier = damageMultiplier; inflictDotInfo.maxStacksFromAttacker = maxStacksFromAttacker; InflictDotInfo inflictDotInfo2 = inflictDotInfo; InflictDot(ref inflictDotInfo2); } [Server] public static void RemoveAllDots(GameObject victimObject) { DotController value; if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DotController::RemoveAllDots(UnityEngine.GameObject)' called on client"); } else if (dotControllerLocator.TryGetValue(victimObject.GetInstanceID(), out value)) { value.HandleDestroy(); } } [Server] public static DotController FindDotController(GameObject victimObject) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'RoR2.DotController RoR2.DotController::FindDotController(UnityEngine.GameObject)' called on client"); return null; } int i = 0; for (int count = instancesList.Count; i < count; i++) { if ((object)victimObject == instancesList[i]._victimObject) { return instancesList[i]; } } return null; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(victimObjectId); writer.WritePackedUInt32(activeDotFlags); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(victimObjectId); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32(activeDotFlags); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { victimObjectId = reader.ReadNetworkId(); activeDotFlags = reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { victimObjectId = reader.ReadNetworkId(); } if (((uint)num & 2u) != 0) { activeDotFlags = reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public struct InflictDotInfo { public GameObject victimObject; public GameObject attackerObject; public DotController.DotIndex dotIndex; public float duration; public float damageMultiplier; public uint? maxStacksFromAttacker; public float? totalDamage; public DotController.DotIndex? preUpgradeDotIndex; } [RequireComponent(typeof(NetworkIdentity))] public sealed class DummyPingableInteraction : MonoBehaviour, IInteractable, IDisplayNameProvider { public string displayNameToken = "DUMMYINTERACTION_NAME"; public string contextToken = "DUMMYINTERACTION_CONTEXT"; public Interactability interactability = Interactability.ConditionsNotMet; public string GetContextString(Interactor activator) { return Language.GetString(contextToken); } public Interactability GetInteractability(Interactor activator) { return interactability; } public void OnInteractionBegin(Interactor activator) { } public string GetDisplayName() { return Language.GetString(displayNameToken); } public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator) { return true; } public void OnEnable() { InstanceTracker.Add(this); } public void OnDisable() { InstanceTracker.Remove(this); } public bool ShouldShowOnScanner() { return interactability != Interactability.Disabled; } public bool ShouldProximityHighlight() { return false; } } [DisallowMultipleComponent] public class EffectComponent : MonoBehaviour { [HideInInspector] [Tooltip("This is assigned to the prefab automatically by EffectCatalog at runtime. Do not set this value manually.")] public EffectIndex effectIndex = EffectIndex.Invalid; [NonSerialized] public EffectData effectData; [Tooltip("Positions the effect at the transform referenced by the effect data if available.")] public bool positionAtReferencedTransform; [Tooltip("Parents the effect to the transform object referenced by the effect data if available.")] public bool parentToReferencedTransform; [Tooltip("Indicates that this is a special effect that won't use effectdata (mostly used to hide errors and warnings for specific effects that cannot be created with SpawnEffect)")] public bool noEffectData; [Tooltip("Causes this object to adopt the scale received in the effectdata.")] public bool applyScale; [Tooltip("The sound to play whenever this effect is dispatched, regardless of whether or not it actually ends up spawning.")] public string soundName; [Tooltip("Ignore Z scale when adopting scale values from effectdata.")] public bool disregardZScale; private bool didResolveReferencedObject; private GameObject referencedObject; private bool didResolveReferencedChildTransform; private Transform referencedChildTransform; private bool didResolveReferencedHurtBox; private GameObject referencedHurtBoxGameObject; public void Reset() { if (noEffectData || effectData == null) { return; } Transform transform = null; if (positionAtReferencedTransform | parentToReferencedTransform) { transform = effectData.ResolveChildLocatorTransformReference(); } if ((bool)transform) { if (positionAtReferencedTransform) { base.transform.position = transform.position; base.transform.rotation = transform.rotation; } if (parentToReferencedTransform) { base.transform.SetParent(transform, worldPositionStays: true); } } if (applyScale) { float scale = effectData.scale; base.transform.localScale = new UnityEngine.Vector3(scale, scale, scale); } } private void Start() { if (effectData == null) { UnityEngine.Debug.LogErrorFormat(base.gameObject, "Object {0} should not be instantiated by means other than EffectManager.SpawnEffect. This WILL result in an NRE!!! Use EffectManager.SpawnEffect or don't use EffectComponent!!!!!", base.gameObject); } Reset(); } [ContextMenu("Attempt to Upgrade Sfx Setup")] private void AttemptToUpgradeSfxSetup() { AkEvent[] components = GetComponents(); int num = 1281810935; if (components.Length == 1 && components[0].triggerList.Count == 1 && components[0].triggerList[0] == num) { string objectName = components[0].data.WwiseObjectReference.ObjectName; soundName = objectName; UnityEngine.Object.DestroyImmediate(components[0]); UnityEngine.Object.DestroyImmediate(GetComponent()); Rigidbody component = GetComponent(); if (component.isKinematic) { UnityEngine.Object.DestroyImmediate(component); } EditorUtil.SetDirty(this); EditorUtil.SetDirty(base.gameObject); } } private void OnValidate() { if (!Application.isPlaying && effectIndex != EffectIndex.Invalid) { effectIndex = EffectIndex.Invalid; } if (Application.isPlaying) { return; } bool num = GetComponent(); bool flag = GetComponent(); if (num && !flag) { AkEvent[] components = GetComponents(); int item = 1281810935; if (components.Length == 1 && components[0].triggerList.Contains(item)) { UnityEngine.Debug.LogWarningFormat(base.gameObject, "Effect {0} has an attached AkGameObj. You probably want to use the soundName field of its EffectComponent instead.", Util.GetGameObjectHierarchyName(base.gameObject)); } } } public GameObject GetReferencedObject() { if (!didResolveReferencedObject) { referencedObject = effectData.ResolveNetworkedObjectReference(); didResolveReferencedObject = true; } return referencedObject; } public Transform GetReferencedChildTransform() { if (!didResolveReferencedChildTransform) { referencedChildTransform = effectData.ResolveChildLocatorTransformReference(); didResolveReferencedChildTransform = true; } return referencedChildTransform; } public GameObject GetReferencedHurtBoxGameObject() { if (!didResolveReferencedHurtBox) { referencedHurtBoxGameObject = effectData.ResolveHurtBoxReference(); didResolveReferencedHurtBox = true; } return referencedHurtBoxGameObject; } } public class ElementalRingController : MonoBehaviour { public GameObject elementalRingAvailableObject; private CharacterBody characterBody; private void Start() { CharacterModel componentInParent = GetComponentInParent(); if ((bool)componentInParent) { characterBody = componentInParent.body; } } private void FixedUpdate() { if ((bool)characterBody) { bool flag = characterBody.HasBuff(RoR2Content.Buffs.ElementalRingsReady); if (flag != elementalRingAvailableObject.activeSelf) { elementalRingAvailableObject.SetActive(flag); } } } } public class EnableOnMecanimFloat : MonoBehaviour { public Animator animator; [Tooltip("The name of the mecanim variable to compare against")] public string animatorString; [Tooltip("The minimum value at which the objects are enabled")] public float minFloatValue; [Tooltip("The maximum value at which the objects are enabled")] public float maxFloatValue; public GameObject[] objectsToEnable; public GameObject[] objectsToDisable; private bool wasWithinRange; private void Update() { if (!animator) { return; } float @float = animator.GetFloat(animatorString); bool flag = Mathf.Clamp(@float, minFloatValue, maxFloatValue) == @float; if (flag != wasWithinRange) { GameObject[] array = objectsToEnable; for (int i = 0; i < array.Length; i++) { array[i].SetActive(flag); } array = objectsToDisable; for (int i = 0; i < array.Length; i++) { array[i].SetActive(!flag); } wasWithinRange = flag; } } } public class EnableWithPhase : MonoBehaviour { [Serializable] public struct PhaseInfo { public int minimumPhaseThreshold; public int maximumPhaseThreshold; public GameObject[] gameObjectsToEnable; } public PhaseInfo[] phaseInfos; private void FixedUpdate() { if (!PhaseCounter.instance) { return; } int phase = PhaseCounter.instance.phase; for (int i = 0; i < phaseInfos.Length; i++) { bool active = true; PhaseInfo phaseInfo = phaseInfos[i]; if (phaseInfo.minimumPhaseThreshold > phase || phaseInfo.maximumPhaseThreshold < phase) { active = false; } GameObject[] gameObjectsToEnable = phaseInfo.gameObjectsToEnable; for (int j = 0; j < gameObjectsToEnable.Length; j++) { gameObjectsToEnable[j].SetActive(active); } } } } [RequireComponent(typeof(TeamFilter))] [RequireComponent(typeof(Inventory))] public class EnemyInfoPanelInventoryProvider : MonoBehaviour { private static bool isDirty; public Inventory inventory { get; private set; } public TeamFilter teamFilter { get; private set; } public static event Action onInventoriesChanged; private void Awake() { inventory = GetComponent(); teamFilter = GetComponent(); inventory.onInventoryChanged += OnInventoryChanged; } private void OnInventoryChanged() { MarkAsDirty(); } private void OnEnable() { InstanceTracker.Add(this); MarkAsDirty(); } private void OnDisable() { MarkAsDirty(); InstanceTracker.Remove(this); } private void MarkAsDirty() { if (!isDirty) { isDirty = true; RoR2Application.onNextUpdate += Refresh; } } private void Refresh() { EnemyInfoPanelInventoryProvider.onInventoriesChanged?.Invoke(); isDirty = false; } } public class EngiMineAnimator : MonoBehaviour { private Transform projectileTransform; public Animator animator; private EntityStateMachine armingStateMachine; private void Start() { ProjectileGhostController component = GetComponent(); if ((bool)component) { projectileTransform = component.authorityTransform; if ((bool)projectileTransform) { armingStateMachine = EntityStateMachine.FindByCustomName(projectileTransform.gameObject, "Arming"); } } } private bool IsArmed() { return ((armingStateMachine?.state as BaseMineArmingState)?.damageScale ?? 0f) > 1f; } private void Update() { if (IsArmed()) { animator.SetTrigger("Arming"); } } } [DisallowMultipleComponent] public class EntityLocator : MonoBehaviour { [Tooltip("The root gameobject of the entity.")] public GameObject entity; [SerializeField] private int entityZoneIndex; public int EntityZoneIndex => entityZoneIndex; public static bool HasEntityLocator(GameObject gameObject, out EntityLocator foundLocator) { if (gameObject == null) { foundLocator = null; return false; } foundLocator = gameObject.GetComponent(); if (!foundLocator) { return false; } return true; } public static GameObject GetEntity(GameObject gameObject) { if (gameObject == null) { return null; } EntityLocator component = gameObject.GetComponent(); if (!component) { return null; } return component.entity; } } public class EntityStateMachine : MonoBehaviour, IManagedMonoBehaviour { public struct CommonComponentCache { public readonly Transform transform; public readonly CharacterBody characterBody; public readonly CharacterMotor characterMotor; public readonly CharacterDirection characterDirection; public readonly Rigidbody rigidbody; public readonly RigidbodyMotor rigidbodyMotor; public readonly RigidbodyDirection rigidbodyDirection; public readonly RailMotor railMotor; public readonly ModelLocator modelLocator; public readonly InputBankTest inputBank; public readonly TeamComponent teamComponent; public readonly HealthComponent healthComponent; public readonly SkillLocator skillLocator; public readonly CharacterEmoteDefinitions characterEmoteDefinitions; public readonly CameraTargetParams cameraTargetParams; public readonly SfxLocator sfxLocator; public readonly BodyAnimatorSmoothingParameters bodyAnimatorSmoothingParameters; public readonly ProjectileController projectileController; public CommonComponentCache(GameObject gameObject) { transform = gameObject.transform; characterBody = gameObject.GetComponent(); characterMotor = gameObject.GetComponent(); characterDirection = gameObject.GetComponent(); rigidbody = gameObject.GetComponent(); rigidbodyMotor = gameObject.GetComponent(); rigidbodyDirection = gameObject.GetComponent(); railMotor = gameObject.GetComponent(); modelLocator = gameObject.GetComponent(); inputBank = gameObject.GetComponent(); teamComponent = gameObject.GetComponent(); healthComponent = gameObject.GetComponent(); skillLocator = gameObject.GetComponent(); characterEmoteDefinitions = gameObject.GetComponent(); cameraTargetParams = gameObject.GetComponent(); sfxLocator = gameObject.GetComponent(); bodyAnimatorSmoothingParameters = gameObject.GetComponent(); projectileController = gameObject.GetComponent(); } } public delegate void ModifyNextStateDelegate(EntityStateMachine entityStateMachine, ref EntityState newNextState); private EntityState nextState; [Tooltip("The name of this state machine.")] public string customName; [Tooltip("The type of the state to enter when this component is first activated.")] public SerializableEntityStateType initialStateType = new SerializableEntityStateType(typeof(TestState1)); [Tooltip("The preferred main state of this state machine.")] public SerializableEntityStateType mainStateType; public CommonComponentCache commonComponents; [NonSerialized] public int networkIndex = -1; [NonSerialized] public bool AllowStartWithoutNetworker; [NonSerialized] public bool ShouldStateTransitionOnUpdate; public ModifyNextStateDelegate nextStateModifier; public bool debug; public EntityState state { get; private set; } public NetworkStateMachine networker { get; set; } public NetworkIdentity networkIdentity { get; set; } public bool AlwaysUpdate => false; public bool destroying { get; private set; } public void SetNextState(EntityState newNextState) { nextStateModifier?.Invoke(this, ref newNextState); nextState = newNextState; } public void SetNextStateToMain() { SetNextState(EntityStateCatalog.InstantiateState(ref mainStateType)); } public bool CanInterruptState(InterruptPriority interruptPriority) { return (nextState ?? state).GetMinimumInterruptPriority() <= interruptPriority; } public bool SetInterruptState(EntityState newNextState, InterruptPriority interruptPriority) { if (CanInterruptState(interruptPriority)) { _ = debug; SetNextState(newNextState); return true; } return false; } public bool HasPendingState() { return nextState != null; } public bool IsInMainState() { if (state != null) { return state.GetType() == mainStateType.stateType; } return false; } public bool IsInInitialState() { if (state != null) { return state.GetType() == initialStateType.stateType; } return false; } public void SetState([NotNull] EntityState newState) { nextState = null; newState.outer = this; if (state == null) { UnityEngine.Debug.LogErrorFormat("State machine {0} on object {1} does not have a state!", customName, base.gameObject); } state.ModifyNextState(newState); state.OnExit(); _ = debug; state = newState; state.OnEnter(); if (networkIndex != -1) { if (!networker) { UnityEngine.Debug.LogErrorFormat("State machine {0} on object {1} does not have a networker assigned!", customName, base.gameObject); } networker.SendSetEntityState(networkIndex); } } private void Awake() { if (!networker) { networker = GetComponent(); } if (!networkIdentity) { networkIdentity = GetComponent(); } commonComponents = new CommonComponentCache(base.gameObject); state = new Uninitialized(); state.outer = this; } private void Start() { if (nextState != null && (AllowStartWithoutNetworker || ((bool)networker && !networker.hasAuthority))) { SetState(nextState); return; } Type stateType = initialStateType.stateType; if (state is Uninitialized && stateType != null && stateType.IsSubclassOf(typeof(EntityState))) { SetState(EntityStateCatalog.InstantiateState(stateType)); } } public void Update() { ManagedUpdate(); } public void FixedUpdate() { ManagedFixedUpdate(Time.deltaTime); } public void ManagedUpdate() { state.Update(); if (ShouldStateTransitionOnUpdate) { TryStateTransition(); } } public void ManagedFixedUpdate(float deltaTime) { if (!destroying) { if (!ShouldStateTransitionOnUpdate) { TryStateTransition(); } state.FixedUpdate(); } } private void TryStateTransition() { if (nextState != null) { SetState(nextState); } } private void OnDestroy() { destroying = true; if (state != null) { state.OnExit(); state = null; } } private void OnValidate() { if (!(mainStateType.stateType == null)) { return; } if (customName == "Body") { if ((bool)GetComponent()) { mainStateType = new SerializableEntityStateType(typeof(GenericCharacterMain)); } else if ((bool)GetComponent()) { mainStateType = new SerializableEntityStateType(typeof(FlyState)); } } else if (customName == "Weapon") { mainStateType = new SerializableEntityStateType(typeof(EntityStates.Idle)); } else if (customName == "AI") { BaseAI component = GetComponent(); if ((bool)component) { mainStateType = component.scanState; } } } public static EntityStateMachine FindByCustomName(GameObject gameObject, string customName) { List gameObjectComponents = GetComponentsCache.GetGameObjectComponents(gameObject); EntityStateMachine result = null; int i = 0; for (int count = gameObjectComponents.Count; i < count; i++) { if (string.CompareOrdinal(customName, gameObjectComponents[i].customName) == 0) { result = gameObjectComponents[i]; break; } } GetComponentsCache.ReturnBuffer(gameObjectComponents); return result; } } [RequireComponent(typeof(CharacterBody))] public class EquipmentSlot : NetworkBehaviour { private struct UserTargetInfo { public readonly HurtBox hurtBox; public readonly GameObject rootObject; public readonly GenericPickupController pickupController; public readonly Transform transformToIndicateAt; public UserTargetInfo(HurtBox source) { hurtBox = source; rootObject = (hurtBox ? hurtBox.healthComponent.gameObject : null); pickupController = null; transformToIndicateAt = (hurtBox ? hurtBox.transform : null); } public UserTargetInfo(GenericPickupController source) { pickupController = source; hurtBox = null; rootObject = (pickupController ? pickupController.gameObject : null); transformToIndicateAt = (pickupController ? pickupController.pickupDisplay.transform : null); } } private Inventory inventory; private Run.FixedTimeStamp _rechargeTime; private bool hasEffectiveAuthority; private Xoroshiro128Plus rng; private HealthComponent healthComponent; private InputBankTest inputBank; private TeamComponent teamComponent; private const float fullCritDuration = 8f; private static readonly float tonicBuffDuration; public static string equipmentActivateString; private float missileTimer; private float bfgChargeTimer; private float subcooldownTimer; private const float missileInterval = 0.125f; private int remainingMissiles; private HealingFollowerController passiveHealingFollower; private GameObject goldgatControllerObject; private static int activeParamHash; private static int activeDurationParamHash; private static int activeStopwatchParamHash; private Indicator targetIndicator; private BullseyeSearch targetFinder = new BullseyeSearch(); private UserTargetInfo currentTarget; private PickupSearch pickupSearch; private Transform sproutSpawnTransform; private GameObject playerRespawnEffectPrefab; private bool sproutIsSpawned; private GameObject sprout; private static int kRpcRpcOnClientEquipmentActivationRecieved; private static int kCmdCmdExecuteIfReady; private static int kCmdCmdOnEquipmentExecuted; public byte activeEquipmentSlot { get; private set; } public EquipmentIndex equipmentIndex { get; private set; } public int stock { get; private set; } public int maxStock { get; private set; } private bool equipmentDisabled { get { if (!inventory) { return false; } return inventory.GetEquipmentDisabled(); } } public CharacterBody characterBody { get; private set; } public float cooldownTimer => _rechargeTime.timeUntil; public static event Action onServerEquipmentActivated; public override void OnStartServer() { base.OnStartServer(); UpdateAuthority(); } public override void OnStartAuthority() { base.OnStartAuthority(); UpdateAuthority(); } public override void OnStopAuthority() { base.OnStopAuthority(); UpdateAuthority(); } private void UpdateAuthority() { hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject); } private void UpdateInventory() { inventory = characterBody.inventory; if ((bool)inventory) { activeEquipmentSlot = inventory.activeEquipmentSlot; equipmentIndex = inventory.GetEquipmentIndex(); stock = inventory.GetEquipment(inventory.activeEquipmentSlot).charges; maxStock = inventory.GetActiveEquipmentMaxCharges(); _rechargeTime = inventory.GetEquipment(inventory.activeEquipmentSlot).chargeFinishTime; } else { activeEquipmentSlot = 0; equipmentIndex = EquipmentIndex.None; stock = 0; maxStock = 0; _rechargeTime = Run.FixedTimeStamp.positiveInfinity; } } [Server] private void UpdateGoldGat() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.EquipmentSlot::UpdateGoldGat()' called on client"); return; } bool flag = equipmentIndex == RoR2Content.Equipment.GoldGat.equipmentIndex; if (flag != (bool)goldgatControllerObject) { if (flag) { goldgatControllerObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/GoldGatController")); goldgatControllerObject.GetComponent().AttachToGameObjectAndSpawn(base.gameObject); } else { UnityEngine.Object.Destroy(goldgatControllerObject); } } } public Transform FindActiveEquipmentDisplay() { ModelLocator component = GetComponent(); if ((bool)component) { Transform modelTransform = component.modelTransform; if ((bool)modelTransform) { CharacterModel component2 = modelTransform.GetComponent(); if ((bool)component2) { List equipmentDisplayObjects = component2.GetEquipmentDisplayObjects(equipmentIndex); if (equipmentDisplayObjects.Count > 0) { return equipmentDisplayObjects[0].transform; } } } } return null; } [ClientRpc] private void RpcOnClientEquipmentActivationRecieved() { Util.PlaySound(equipmentActivateString, base.gameObject); EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); if (equipmentDef == RoR2Content.Equipment.DroneBackup) { Util.PlaySound("Play_item_use_radio", base.gameObject); } else if (equipmentDef == RoR2Content.Equipment.BFG) { Transform transform = FindActiveEquipmentDisplay(); if ((bool)transform) { Animator componentInChildren = transform.GetComponentInChildren(); if ((bool)componentInChildren) { componentInChildren.SetTrigger("Fire"); } } } else if (equipmentDef == RoR2Content.Equipment.Blackhole) { Transform transform2 = FindActiveEquipmentDisplay(); if ((bool)transform2) { GravCubeController component = transform2.GetComponent(); if ((bool)component) { component.ActivateCube(9f); } } } else if (equipmentDef == RoR2Content.Equipment.CritOnUse) { Transform transform3 = FindActiveEquipmentDisplay(); if ((bool)transform3) { Animator componentInChildren2 = transform3.GetComponentInChildren(); if ((bool)componentInChildren2) { componentInChildren2.SetBool(activeParamHash, value: true); componentInChildren2.SetFloat(activeDurationParamHash, 8f); componentInChildren2.SetFloat(activeStopwatchParamHash, 0f); } } } else if (equipmentDef == RoR2Content.Equipment.GainArmor) { Util.PlaySound("Play_item_use_gainArmor", base.gameObject); } } private void Start() { characterBody = GetComponent(); healthComponent = GetComponent(); inputBank = GetComponent(); teamComponent = GetComponent(); targetIndicator = new Indicator(base.gameObject, null); rng = new Xoroshiro128Plus(Run.instance.seed ^ (ulong)Run.instance.stageClearCount); } private void OnDestroy() { if (targetIndicator != null) { targetIndicator.active = false; } } private void FixedUpdate() { MyFixedUpdate(Time.fixedDeltaTime); } private void MyFixedUpdate(float deltaTime) { UpdateInventory(); if (NetworkServer.active && !equipmentDisabled) { EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); subcooldownTimer -= deltaTime; if (missileTimer > 0f) { missileTimer = Mathf.Max(missileTimer - deltaTime, 0f); } if (missileTimer == 0f && remainingMissiles > 0) { remainingMissiles--; missileTimer = 0.125f; FireMissile(); } UpdateGoldGat(); if (bfgChargeTimer > 0f) { bfgChargeTimer -= deltaTime; if (bfgChargeTimer < 0f) { _ = base.transform.position; Ray aimRay = GetAimRay(); Transform transform = FindActiveEquipmentDisplay(); if ((bool)transform) { ChildLocator componentInChildren = transform.GetComponentInChildren(); if ((bool)componentInChildren) { Transform transform2 = componentInChildren.FindChild("Muzzle"); if ((bool)transform2) { aimRay.origin = transform2.position; } } } healthComponent.TakeDamageForce(aimRay.direction * -1500f, alwaysApply: true); ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load("Prefabs/Projectiles/BeamSphere"), aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, characterBody.damage * 2f, 0f, Util.CheckRoll(characterBody.crit, characterBody.master), DamageColorIndex.Item); bfgChargeTimer = 0f; } } if (equipmentDef == RoR2Content.Equipment.PassiveHealing != (bool)passiveHealingFollower) { if (!passiveHealingFollower) { GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/HealingFollower"), base.transform.position, UnityEngine.Quaternion.identity); passiveHealingFollower = gameObject.GetComponent(); passiveHealingFollower.NetworkownerBodyObject = base.gameObject; NetworkServer.Spawn(gameObject); } else { UnityEngine.Object.Destroy(passiveHealingFollower.gameObject); passiveHealingFollower = null; } } } bool num = inputBank.activateEquipment.justPressed || (inventory?.GetItemCount(RoR2Content.Items.AutoCastEquipment) ?? 0) > 0; bool isEquipmentActivationAllowed = characterBody.isEquipmentActivationAllowed; if (num && isEquipmentActivationAllowed && hasEffectiveAuthority) { if (NetworkServer.active) { ExecuteIfReady(); } else { CallCmdExecuteIfReady(); } } } [Command] private void CmdExecuteIfReady() { ExecuteIfReady(); } [Server] public bool ExecuteIfReady() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.EquipmentSlot::ExecuteIfReady()' called on client"); return false; } if (equipmentIndex != EquipmentIndex.None && stock > 0) { Execute(); return true; } return false; } [Server] private void Execute() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.EquipmentSlot::Execute()' called on client"); return; } EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); if ((object)equipmentDef != null && subcooldownTimer <= 0f && PerformEquipmentAction(equipmentDef)) { OnEquipmentExecuted(); } } [Command] public void CmdOnEquipmentExecuted() { OnEquipmentExecuted(); } [Server] public void OnEquipmentExecuted() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.EquipmentSlot::OnEquipmentExecuted()' called on client"); return; } EquipmentIndex arg = this.equipmentIndex; inventory.DeductEquipmentCharges(activeEquipmentSlot, 1); UpdateInventory(); CallRpcOnClientEquipmentActivationRecieved(); EquipmentSlot.onServerEquipmentActivated?.Invoke(this, arg); if (!characterBody || !inventory) { return; } int itemCount = inventory.GetItemCount(RoR2Content.Items.EnergizedOnEquipmentUse); if (itemCount > 0) { characterBody.AddTimedBuff(RoR2Content.Buffs.Energized, 8 + 4 * (itemCount - 1)); } int itemCount2 = inventory.GetItemCount(DLC1Content.Items.RandomEquipmentTrigger); if (itemCount2 <= 0 || EquipmentCatalog.randomTriggerEquipmentList.Count <= 0) { return; } List list = new List(EquipmentCatalog.randomTriggerEquipmentList); if (inventory.currentEquipmentIndex != EquipmentIndex.None) { list.Remove(inventory.currentEquipmentIndex); } Util.ShuffleList(list, rng); if (inventory.currentEquipmentIndex != EquipmentIndex.None) { list.Add(inventory.currentEquipmentIndex); } int num = 0; bool flag = false; bool flag2 = false; for (int i = 0; i < itemCount2; i++) { if (flag2) { break; } EquipmentIndex equipmentIndex = EquipmentIndex.None; do { if (num >= list.Count) { if (!flag) { flag2 = true; break; } flag = false; num %= list.Count; } equipmentIndex = list[num]; num++; } while (!PerformEquipmentAction(EquipmentCatalog.GetEquipmentDef(equipmentIndex))); if (equipmentIndex == RoR2Content.Equipment.BFG.equipmentIndex) { ModelLocator component = GetComponent(); if ((bool)component) { Transform modelTransform = component.modelTransform; if ((bool)modelTransform) { CharacterModel component2 = modelTransform.GetComponent(); if ((bool)component2) { List itemDisplayObjects = component2.GetItemDisplayObjects(DLC1Content.Items.RandomEquipmentTrigger.itemIndex); if (itemDisplayObjects.Count > 0) { UnityEngine.Object.Instantiate(Addressables.LoadAssetAsync("RoR2/Base/BFG/ChargeBFG.prefab").WaitForCompletion(), itemDisplayObjects[0].transform); } } } } } flag = true; } EffectData effectData = new EffectData(); effectData.origin = characterBody.corePosition; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/RandomEquipmentTriggerProcEffect"), effectData, transmit: true); } private void FireMissile() { GameObject projectilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/MissileProjectile"); float num = 3f; bool isCrit = Util.CheckRoll(characterBody.crit, characterBody.master); MissileUtils.FireMissile(characterBody.corePosition, characterBody, default(ProcChainMask), null, characterBody.damage * num, isCrit, projectilePrefab, DamageColorIndex.Item, addMissileProc: false); } [Server] private bool PerformEquipmentAction(EquipmentDef equipmentDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.EquipmentSlot::PerformEquipmentAction(RoR2.EquipmentDef)' called on client"); return false; } if (equipmentDisabled) { return false; } Func func = null; if (equipmentDef == RoR2Content.Equipment.CommandMissile) { func = FireCommandMissile; } else if (equipmentDef == RoR2Content.Equipment.Fruit) { func = FireFruit; } else if (equipmentDef == RoR2Content.Equipment.DroneBackup) { func = FireDroneBackup; } else if (equipmentDef == RoR2Content.Equipment.Meteor) { func = FireMeteor; } else if (equipmentDef == RoR2Content.Equipment.Blackhole) { func = FireBlackhole; } else if (equipmentDef == RoR2Content.Equipment.Saw) { func = FireSaw; } else if (equipmentDef == JunkContent.Equipment.OrbitalLaser) { func = FireOrbitalLaser; } else if (equipmentDef == JunkContent.Equipment.GhostGun) { func = FireGhostGun; } else if (equipmentDef == RoR2Content.Equipment.CritOnUse) { func = FireCritOnUse; } else if (equipmentDef == RoR2Content.Equipment.BFG) { func = FireBfg; } else if (equipmentDef == RoR2Content.Equipment.Jetpack) { func = FireJetpack; } else if (equipmentDef == RoR2Content.Equipment.Lightning) { func = FireLightning; } else if (equipmentDef == RoR2Content.Equipment.PassiveHealing) { func = FirePassiveHealing; } else if (equipmentDef == RoR2Content.Equipment.BurnNearby) { func = FireBurnNearby; } else if (equipmentDef == JunkContent.Equipment.SoulCorruptor) { func = FireSoulCorruptor; } else if (equipmentDef == RoR2Content.Equipment.Scanner) { func = FireScanner; } else if (equipmentDef == RoR2Content.Equipment.CrippleWard) { func = FireCrippleWard; } else if (equipmentDef == RoR2Content.Equipment.Gateway) { func = FireGateway; } else if (equipmentDef == RoR2Content.Equipment.Tonic) { func = FireTonic; } else if (equipmentDef == RoR2Content.Equipment.Cleanse) { func = FireCleanse; } else if (equipmentDef == RoR2Content.Equipment.FireBallDash) { func = FireFireBallDash; } else if (equipmentDef == RoR2Content.Equipment.Recycle) { func = FireRecycle; } else if (equipmentDef == RoR2Content.Equipment.GainArmor) { func = FireGainArmor; } else if (equipmentDef == RoR2Content.Equipment.LifestealOnHit) { func = FireLifeStealOnHit; } else if (equipmentDef == RoR2Content.Equipment.TeamWarCry) { func = FireTeamWarCry; } else if (equipmentDef == RoR2Content.Equipment.DeathProjectile) { func = FireDeathProjectile; } else if (equipmentDef == DLC1Content.Equipment.Molotov) { func = FireMolotov; } else if (equipmentDef == DLC1Content.Equipment.VendingMachine) { func = FireVendingMachine; } else if (equipmentDef == DLC1Content.Equipment.BossHunter) { func = FireBossHunter; } else if (equipmentDef == DLC1Content.Equipment.BossHunterConsumed) { func = FireBossHunterConsumed; } else if (equipmentDef == DLC1Content.Equipment.GummyClone) { func = FireGummyClone; } else if (equipmentDef == DLC1Content.Equipment.LunarPortalOnUse) { func = FireLunarPortalOnUse; } else if (equipmentDef == DLC2Content.Equipment.HealAndRevive) { func = FireHealAndRevive; } else if (equipmentDef == DLC2Content.Equipment.HealAndReviveConsumed) { func = FireSproutOfLife; } return func?.Invoke() ?? false; } private Ray GetAimRay() { Ray result = default(Ray); result.direction = inputBank.aimDirection; result.origin = inputBank.aimOrigin; return result; } [CanBeNull] [Server] private CharacterMaster SummonMaster([NotNull] GameObject masterPrefab, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterMaster RoR2.EquipmentSlot::SummonMaster(UnityEngine.GameObject,UnityEngine.Vector3,UnityEngine.Quaternion)' called on client"); return null; } return new MasterSummon { masterPrefab = masterPrefab, position = position, rotation = rotation, summonerBodyObject = base.gameObject, ignoreTeamMemberLimit = false }.Perform(); } private void ConfigureTargetFinderBase() { targetFinder.teamMaskFilter = TeamMask.allButNeutral; targetFinder.teamMaskFilter.RemoveTeam(teamComponent.teamIndex); targetFinder.sortMode = BullseyeSearch.SortMode.Angle; targetFinder.filterByLoS = true; float extraRaycastDistance; Ray ray = CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance); targetFinder.searchOrigin = ray.origin; targetFinder.searchDirection = ray.direction; targetFinder.maxAngleFilter = 10f; targetFinder.viewer = characterBody; } private void ConfigureTargetFinderForEnemies() { ConfigureTargetFinderBase(); targetFinder.teamMaskFilter = TeamMask.GetUnprotectedTeams(teamComponent.teamIndex); targetFinder.RefreshCandidates(); targetFinder.FilterOutGameObject(base.gameObject); } private void ConfigureTargetFinderForBossesWithRewards() { ConfigureTargetFinderBase(); targetFinder.teamMaskFilter = TeamMask.GetUnprotectedTeams(teamComponent.teamIndex); targetFinder.RefreshCandidates(); targetFinder.FilterOutGameObject(base.gameObject); } private void ConfigureTargetFinderForFriendlies() { ConfigureTargetFinderBase(); targetFinder.teamMaskFilter = TeamMask.none; targetFinder.teamMaskFilter.AddTeam(teamComponent.teamIndex); targetFinder.RefreshCandidates(); targetFinder.FilterOutGameObject(base.gameObject); } private void InvalidateCurrentTarget() { currentTarget = default(UserTargetInfo); } private void UpdateTargets(EquipmentIndex targetingEquipmentIndex, bool userShouldAnticipateTarget) { bool flag = targetingEquipmentIndex == DLC1Content.Equipment.BossHunter.equipmentIndex; bool flag2 = (targetingEquipmentIndex == RoR2Content.Equipment.Lightning.equipmentIndex || targetingEquipmentIndex == JunkContent.Equipment.SoulCorruptor.equipmentIndex || flag) && userShouldAnticipateTarget; bool flag3 = targetingEquipmentIndex == RoR2Content.Equipment.PassiveHealing.equipmentIndex && userShouldAnticipateTarget; bool num = flag2 || flag3; bool flag4 = targetingEquipmentIndex == RoR2Content.Equipment.Recycle.equipmentIndex; if (num) { if (flag2) { ConfigureTargetFinderForEnemies(); } if (flag3) { ConfigureTargetFinderForFriendlies(); } HurtBox source = null; if (flag) { foreach (HurtBox result in targetFinder.GetResults()) { if ((bool)result && (bool)result.healthComponent && (bool)result.healthComponent.body) { DeathRewards component = result.healthComponent.body.gameObject.GetComponent(); if ((bool)component && (bool)component.bossDropTable && !result.healthComponent.body.HasBuff(RoR2Content.Buffs.Immune)) { source = result; break; } } } } else { source = targetFinder.GetResults().FirstOrDefault(); } currentTarget = new UserTargetInfo(source); } else if (flag4) { currentTarget = new UserTargetInfo(FindPickupController(GetAimRay(), 10f, 30f, requireLoS: true, targetingEquipmentIndex == RoR2Content.Equipment.Recycle.equipmentIndex)); } else { currentTarget = default(UserTargetInfo); } GenericPickupController pickupController = currentTarget.pickupController; bool flag5 = currentTarget.transformToIndicateAt; if (flag5) { if (targetingEquipmentIndex == RoR2Content.Equipment.Lightning.equipmentIndex) { targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load("Prefabs/LightningIndicator"); } else if (targetingEquipmentIndex == RoR2Content.Equipment.PassiveHealing.equipmentIndex) { targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load("Prefabs/WoodSpriteIndicator"); } else if (targetingEquipmentIndex == RoR2Content.Equipment.Recycle.equipmentIndex) { if (!pickupController.Recycled) { targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load("Prefabs/RecyclerIndicator"); } else { targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load("Prefabs/RecyclerBadIndicator"); } } else if (targetingEquipmentIndex == DLC1Content.Equipment.BossHunter.equipmentIndex) { targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load("Prefabs/BossHunterIndicator"); } else { targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load("Prefabs/LightningIndicator"); } } targetIndicator.active = flag5; targetIndicator.targetTransform = (flag5 ? currentTarget.transformToIndicateAt : null); } private GenericPickupController FindPickupController(Ray aimRay, float maxAngle, float maxDistance, bool requireLoS, bool requireTransmutable) { if (pickupSearch == null) { pickupSearch = new PickupSearch(); } aimRay = CameraRigController.ModifyAimRayIfApplicable(aimRay, base.gameObject, out var extraRaycastDistance); pickupSearch.searchOrigin = aimRay.origin; pickupSearch.searchDirection = aimRay.direction; pickupSearch.minAngleFilter = 0f; pickupSearch.maxAngleFilter = maxAngle; pickupSearch.minDistanceFilter = 0f; pickupSearch.maxDistanceFilter = maxDistance + extraRaycastDistance; pickupSearch.filterByDistinctEntity = false; pickupSearch.filterByLoS = requireLoS; pickupSearch.sortMode = SortMode.DistanceAndAngle; pickupSearch.requireTransmutable = requireTransmutable; return pickupSearch.SearchCandidatesForSingleTarget(InstanceTracker.GetInstancesList()); } private void Update() { if (!equipmentDisabled) { UpdateTargets(equipmentIndex, stock > 0); } } private bool FireCommandMissile() { remainingMissiles += 12; return true; } private bool FireFruit() { if ((bool)healthComponent) { EffectData effectData = new EffectData(); effectData.origin = base.transform.position; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/FruitHealEffect"), effectData, transmit: true); healthComponent.HealFraction(0.5f, default(ProcChainMask)); } return true; } private bool FireDroneBackup() { int sliceCount = 4; float num = 25f; if (NetworkServer.active) { float y = UnityEngine.Quaternion.LookRotation(GetAimRay().direction).eulerAngles.y; float num2 = 3f; foreach (float item in new DegreeSlices(sliceCount, 0.5f)) { UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(-30f, y + item, 0f); UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(0f, y + item + 180f, 0f); UnityEngine.Vector3 position = base.transform.position + quaternion * (UnityEngine.Vector3.forward * num2); CharacterMaster characterMaster = SummonMaster(LegacyResourcesAPI.Load("Prefabs/CharacterMasters/DroneBackupMaster"), position, rotation); if ((bool)characterMaster) { characterMaster.gameObject.AddComponent().lifeTimer = num + UnityEngine.Random.Range(0f, 3f); } } } subcooldownTimer = 0.5f; return true; } private bool FireMeteor() { MeteorStormController component = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/MeteorStorm"), characterBody.corePosition, UnityEngine.Quaternion.identity).GetComponent(); component.owner = base.gameObject; component.ownerDamage = characterBody.damage; component.isCrit = Util.CheckRoll(characterBody.crit, characterBody.master); NetworkServer.Spawn(component.gameObject); return true; } private bool FireBlackhole() { UnityEngine.Vector3 position = base.transform.position; Ray aimRay = GetAimRay(); ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load("Prefabs/Projectiles/GravSphere"), position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, 0f, 0f, crit: false); return true; } private bool FireSaw() { Ray aimRay = GetAimRay(); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.LookRotation(aimRay.direction); float num = 15f; FireSingleSaw(characterBody, aimRay.origin, quaternion * UnityEngine.Quaternion.Euler(0f, 0f - num, 0f)); FireSingleSaw(characterBody, aimRay.origin, quaternion); FireSingleSaw(characterBody, aimRay.origin, quaternion * UnityEngine.Quaternion.Euler(0f, num, 0f)); return true; void FireSingleSaw(CharacterBody firingCharacterBody, UnityEngine.Vector3 origin, UnityEngine.Quaternion rotation) { GameObject projectilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/Sawmerang"); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.crit = characterBody.RollCrit(); fireProjectileInfo.damage = characterBody.damage; fireProjectileInfo.damageColorIndex = DamageColorIndex.Item; fireProjectileInfo.force = 0f; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.position = origin; fireProjectileInfo.rotation = rotation; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } } private bool FireOrbitalLaser() { UnityEngine.Vector3 position = base.transform.position; if (Physics.Raycast(GetAimRay(), out var hitInfo, 900f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault)) { position = hitInfo.point; } GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/OrbitalLaser"), position, UnityEngine.Quaternion.identity); obj.GetComponent().ownerBody = characterBody; NetworkServer.Spawn(obj); return true; } private bool FireGhostGun() { GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/GhostGun"), base.transform.position, UnityEngine.Quaternion.identity); obj.GetComponent().owner = base.gameObject; NetworkServer.Spawn(obj); return true; } private bool FireCritOnUse() { characterBody.AddTimedBuff(RoR2Content.Buffs.FullCrit, 8f); return true; } private bool FireBfg() { bfgChargeTimer = 2f; subcooldownTimer = 2.2f; return true; } private bool FireJetpack() { JetpackController jetpackController = JetpackController.FindJetpackController(base.gameObject); if (!jetpackController) { UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/BodyAttachments/JetpackController")).GetComponent().AttachToGameObjectAndSpawn(base.gameObject); } else { jetpackController.ResetTimer(); } return true; } private bool FireLightning() { UpdateTargets(RoR2Content.Equipment.Lightning.equipmentIndex, userShouldAnticipateTarget: true); HurtBox hurtBox = currentTarget.hurtBox; if ((bool)hurtBox) { subcooldownTimer = 0.2f; OrbManager.instance.AddOrb(new LightningStrikeOrb { attacker = base.gameObject, damageColorIndex = DamageColorIndex.Item, damageValue = characterBody.damage * 30f, isCrit = Util.CheckRoll(characterBody.crit, characterBody.master), procChainMask = default(ProcChainMask), procCoefficient = 1f, target = hurtBox }); InvalidateCurrentTarget(); return true; } return false; } private bool FireBossHunter() { UpdateTargets(DLC1Content.Equipment.BossHunter.equipmentIndex, userShouldAnticipateTarget: true); HurtBox hurtBox = currentTarget.hurtBox; DeathRewards deathRewards = hurtBox?.healthComponent?.body?.gameObject?.GetComponent(); if ((bool)hurtBox && (bool)deathRewards) { UnityEngine.Vector3 vector = (hurtBox.transform ? hurtBox.transform.position : UnityEngine.Vector3.zero); UnityEngine.Vector3 normalized = (vector - characterBody.corePosition).normalized; PickupDropletController.CreatePickupDroplet(deathRewards.bossDropTable.GenerateDrop(rng), vector, normalized * 15f); if ((bool)hurtBox?.healthComponent?.body?.master) { hurtBox.healthComponent.body.master.TrueKill(base.gameObject); } CharacterModel component = hurtBox.hurtBoxGroup.GetComponent(); if ((bool)component) { TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(component.gameObject); temporaryOverlayInstance.duration = 0.1f; temporaryOverlayInstance.animateShaderAlpha = true; temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance.destroyComponentOnEnd = true; temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load("Materials/matHuntressFlashBright"); temporaryOverlayInstance.AddToCharacterModel(component); TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(component.gameObject); temporaryOverlayInstance2.duration = 1.2f; temporaryOverlayInstance2.animateShaderAlpha = true; temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f); temporaryOverlayInstance2.destroyComponentOnEnd = true; temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load("Materials/matGhostEffect"); temporaryOverlayInstance2.AddToCharacterModel(component); } DamageInfo damageInfo = new DamageInfo(); damageInfo.attacker = base.gameObject; damageInfo.force = -normalized * 2500f; healthComponent.TakeDamageForce(damageInfo, alwaysApply: true); GameObject effectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/BossHunterKillEffect"); UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(normalized, UnityEngine.Vector3.up); EffectManager.SpawnEffect(effectPrefab, new EffectData { origin = vector, rotation = rotation }, transmit: true); CharacterModel characterModel = base.gameObject.GetComponent()?.modelTransform?.GetComponent(); if ((bool)characterModel) { foreach (GameObject equipmentDisplayObject in characterModel.GetEquipmentDisplayObjects(DLC1Content.Equipment.BossHunter.equipmentIndex)) { if (equipmentDisplayObject.name.Contains("DisplayTricorn")) { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/BossHunterHatEffect"), new EffectData { origin = equipmentDisplayObject.transform.position, rotation = equipmentDisplayObject.transform.rotation, scale = equipmentDisplayObject.transform.localScale.x }, transmit: true); } else { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/BossHunterGunEffect"), new EffectData { origin = equipmentDisplayObject.transform.position, rotation = Util.QuaternionSafeLookRotation(vector - equipmentDisplayObject.transform.position, UnityEngine.Vector3.up), scale = equipmentDisplayObject.transform.localScale.x }, transmit: true); } } } if ((bool)characterBody?.inventory) { CharacterMasterNotificationQueue.SendTransformNotification(characterBody.master, characterBody.inventory.currentEquipmentIndex, DLC1Content.Equipment.BossHunterConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default); characterBody.inventory.SetEquipmentIndex(DLC1Content.Equipment.BossHunterConsumed.equipmentIndex); } InvalidateCurrentTarget(); return true; } return false; } private bool FireBossHunterConsumed() { if ((bool)characterBody) { Chat.SendBroadcastChat(new Chat.BodyChatMessage { bodyObject = characterBody.gameObject, token = "EQUIPMENT_BOSSHUNTERCONSUMED_CHAT" }); subcooldownTimer = 1f; } return true; } private bool FirePassiveHealing() { UpdateTargets(RoR2Content.Equipment.PassiveHealing.equipmentIndex, userShouldAnticipateTarget: true); CharacterBody characterBody = currentTarget.rootObject?.GetComponent() ?? this.characterBody; if ((bool)characterBody) { EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load("Prefabs/Effects/WoodSpriteHeal"), characterBody.corePosition, UnityEngine.Vector3.up, transmit: true); characterBody.healthComponent?.HealFraction(0.1f, default(ProcChainMask)); } if ((bool)passiveHealingFollower) { passiveHealingFollower.AssignNewTarget(currentTarget.rootObject); InvalidateCurrentTarget(); } return true; } private bool FireBurnNearby() { if ((bool)characterBody) { characterBody.AddHelfireDuration(12f); } return true; } private bool FireSoulCorruptor() { UpdateTargets(JunkContent.Equipment.SoulCorruptor.equipmentIndex, userShouldAnticipateTarget: true); HurtBox hurtBox = currentTarget.hurtBox; if (!hurtBox) { return false; } if (!hurtBox.healthComponent || hurtBox.healthComponent.combinedHealthFraction > 0.25f) { return false; } Util.TryToCreateGhost(hurtBox.healthComponent.body, characterBody, 30); hurtBox.healthComponent.Suicide(base.gameObject); InvalidateCurrentTarget(); return true; } private bool FireScanner() { NetworkServer.Spawn(UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/ChestScanner"), characterBody.corePosition, UnityEngine.Quaternion.identity)); return true; } private bool FireCrippleWard() { characterBody.master.GetDeployableCount(DeployableSlot.PowerWard); Ray aimRay = GetAimRay(); float maxDistance = 1000f; if (Physics.Raycast(aimRay, out var hitInfo, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/CrippleWard"), hitInfo.point, Util.QuaternionSafeLookRotation(hitInfo.normal, UnityEngine.Vector3.forward)); Deployable component = obj.GetComponent(); characterBody.master.AddDeployable(component, DeployableSlot.CrippleWard); NetworkServer.Spawn(obj); return true; } return true; } private bool FireTonic() { characterBody.AddTimedBuff(RoR2Content.Buffs.TonicBuff, tonicBuffDuration); if (!Util.CheckRoll(80f, characterBody.master)) { characterBody.pendingTonicAfflictionCount++; } return true; } private bool FireCleanse() { UnityEngine.Vector3 corePosition = characterBody.corePosition; EffectData effectData = new EffectData { origin = corePosition }; effectData.SetHurtBoxReference(characterBody.mainHurtBox); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/CleanseEffect"), effectData, transmit: true); Util.CleanseBody(characterBody, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: true, removeDots: true, removeStun: true, removeNearbyProjectiles: true); return true; } private bool FireFireBallDash() { Ray aimRay = GetAimRay(); GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/FireballVehicle"), aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction)); gameObject.GetComponent().AssignPassenger(base.gameObject); NetworkUser networkUser = characterBody?.master?.playerCharacterMasterController?.networkUser; if ((bool)networkUser) { NetworkServer.SpawnWithClientAuthority(gameObject, networkUser.gameObject); } else { NetworkServer.Spawn(gameObject); } subcooldownTimer = 2f; return true; } private bool FireGainArmor() { characterBody.AddTimedBuff(RoR2Content.Buffs.ElephantArmorBoost, 5f); return true; } private bool FireRecycle() { UpdateTargets(RoR2Content.Equipment.Recycle.equipmentIndex, userShouldAnticipateTarget: false); GenericPickupController pickupController = currentTarget.pickupController; if ((bool)pickupController && !pickupController.Recycled) { PickupIndex initialPickupIndex = pickupController.pickupIndex; subcooldownTimer = 0.2f; PickupIndex[] array = (from pickupIndex in PickupTransmutationManager.GetAvailableGroupFromPickupIndex(pickupController.pickupIndex) where pickupIndex != initialPickupIndex select pickupIndex).ToArray(); if (array == null) { return false; } if (array.Length == 0) { return false; } pickupController.NetworkpickupIndex = Run.instance.treasureRng.NextElementUniform(array); EffectManager.SimpleEffect(LegacyResourcesAPI.Load("Prefabs/Effects/OmniEffect/OmniRecycleEffect"), pickupController.pickupDisplay.transform.position, UnityEngine.Quaternion.identity, transmit: true); pickupController.NetworkRecycled = true; InvalidateCurrentTarget(); return true; } return false; } private bool FireGateway() { _ = characterBody.footPosition; Ray aimRay = GetAimRay(); float num = 2f; float num2 = num * 2f; float maxDistance = 1000f; Rigidbody component = GetComponent(); if (!component) { return false; } UnityEngine.Vector3 position = base.transform.position; if (Physics.Raycast(aimRay, out var hitInfo, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { UnityEngine.Vector3 vector = hitInfo.point + hitInfo.normal * num; UnityEngine.Vector3 vector2 = vector - position; UnityEngine.Vector3 normalized = vector2.normalized; UnityEngine.Vector3 pointBPosition = vector; if (component.SweepTest(normalized, out var hitInfo2, vector2.magnitude)) { if (hitInfo2.distance < num2) { return false; } pointBPosition = position + normalized * hitInfo2.distance; } GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/Zipline")); ZiplineController component2 = obj.GetComponent(); component2.SetPointAPosition(position + normalized * num); component2.SetPointBPosition(pointBPosition); obj.AddComponent().duration = 30f; NetworkServer.Spawn(obj); return true; } return false; } private bool FireLifeStealOnHit() { EffectData effectData = new EffectData { origin = characterBody.corePosition }; effectData.SetHurtBoxReference(characterBody.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/LifeStealOnHitActivation"), effectData, transmit: false); characterBody.AddTimedBuff(RoR2Content.Buffs.LifeSteal, 8f); return true; } private bool FireTeamWarCry() { Util.PlaySound("Play_teamWarCry_activate", characterBody.gameObject); UnityEngine.Vector3 corePosition = characterBody.corePosition; EffectData effectData = new EffectData { origin = corePosition }; effectData.SetNetworkedObjectReference(characterBody.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/TeamWarCryActivation"), effectData, transmit: true); characterBody.AddTimedBuff(RoR2Content.Buffs.TeamWarCry, 7f); TeamComponent[] array = UnityEngine.Object.FindObjectsOfType(); for (int i = 0; i < array.Length; i++) { if (array[i].teamIndex == teamComponent.teamIndex) { array[i].GetComponent().AddTimedBuff(RoR2Content.Buffs.TeamWarCry, 7f); } } return true; } private bool FireDeathProjectile() { CharacterMaster master = characterBody.master; if (!master) { return false; } if (master.IsDeployableLimited(DeployableSlot.DeathProjectile)) { return false; } Ray aimRay = GetAimRay(); UnityEngine.Quaternion rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction); GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Projectiles/DeathProjectile"); gameObject.GetComponent().teamIndex = teamComponent.teamIndex; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = gameObject; fireProjectileInfo.crit = characterBody.RollCrit(); fireProjectileInfo.damage = characterBody.damage; fireProjectileInfo.damageColorIndex = DamageColorIndex.Item; fireProjectileInfo.force = 0f; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.position = aimRay.origin; fireProjectileInfo.rotation = rotation; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); return true; } private bool FireMolotov() { Ray aimRay = GetAimRay(); GameObject prefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/MolotovClusterProjectile"); ProjectileManager.instance.FireProjectile(prefab, aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction), base.gameObject, characterBody.damage, 0f, Util.CheckRoll(characterBody.crit, characterBody.master)); return true; } private bool FireVendingMachine() { Ray ray = new Ray(GetAimRay().origin, UnityEngine.Vector3.down); if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo, 1000f, LayerIndex.world.mask, QueryTriggerInteraction.UseGlobal)) { GameObject prefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/VendingMachineProjectile"); ProjectileManager.instance.FireProjectile(prefab, hitInfo.point, UnityEngine.Quaternion.identity, base.gameObject, characterBody.damage, 0f, Util.CheckRoll(characterBody.crit, characterBody.master)); subcooldownTimer = 0.5f; return true; } return false; } private bool FireGummyClone() { CharacterMaster characterMaster = characterBody?.master; if (!characterMaster || characterMaster.IsDeployableLimited(DeployableSlot.GummyClone)) { return false; } Ray aimRay = GetAimRay(); UnityEngine.Quaternion rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction); GameObject projectilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/GummyCloneProjectile"); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.crit = characterBody.RollCrit(); fireProjectileInfo.damage = 0f; fireProjectileInfo.damageColorIndex = DamageColorIndex.Item; fireProjectileInfo.force = 0f; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.position = aimRay.origin; fireProjectileInfo.rotation = rotation; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); return true; } private bool FireLunarPortalOnUse() { TeleporterInteraction.instance.shouldAttemptToSpawnShopPortal = true; return true; } private bool FireHealAndRevive() { bool flag = false; foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { CharacterMaster master = instance.master; if (!instance.isConnected || !master.IsDeadAndOutOfLivesServer()) { continue; } flag = true; UnityEngine.Vector3 deathFootPosition = master.deathFootPosition; master.Respawn(deathFootPosition, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f)); CharacterBody body = master.GetBody(); if ((bool)body) { body.AddTimedBuff(RoR2Content.Buffs.Immune, 3f); EntityStateMachine[] components = body.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } playerRespawnEffectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/fxHealAndReviveGold"); if ((bool)playerRespawnEffectPrefab) { EffectManager.SpawnEffect(playerRespawnEffectPrefab, new EffectData { origin = deathFootPosition, rotation = body.transform.rotation }, transmit: true); Util.PlaySound("Play_item_use_healAndRevive_activate", base.gameObject); } } } if (flag) { bool flag2 = false; if (characterBody?.equipmentSlot != null && characterBody?.equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex) { flag2 = true; } if ((bool)characterBody?.inventory && flag2) { CharacterMasterNotificationQueue.SendTransformNotification(characterBody.master, characterBody.inventory.currentEquipmentIndex, DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default); characterBody.inventory.SetEquipmentIndex(DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex); } } if (!flag) { return false; } return true; } private bool FireSproutOfLife() { if (sproutIsSpawned && (bool)sprout) { sproutIsSpawned = false; NetworkServer.Destroy(sprout); } Ray aimRay = GetAimRay(); UnityEngine.Quaternion.LookRotation(aimRay.direction); sproutSpawnTransform = characterBody.transform; UnityEngine.Vector3 position = characterBody.transform.position; characterBody.transform.TransformDirection(UnityEngine.Vector3.forward); new UnityEngine.Quaternion(0f, UnityEngine.Random.Range(0f, 360f), 0f, 1f); if (Physics.Raycast(position, aimRay.direction, out var hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { sproutSpawnTransform.position = hitInfo.point; sproutSpawnTransform.up = hitInfo.normal; sprout = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/SproutOfLifeHealing"), sproutSpawnTransform.position, UnityEngine.Quaternion.identity); sprout.transform.up = sproutSpawnTransform.up; sprout.transform.rotation *= UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 360f), UnityEngine.Vector3.up); NetworkServer.Spawn(sprout); sproutIsSpawned = true; return true; } return false; } static EquipmentSlot() { tonicBuffDuration = 20f; equipmentActivateString = "Play_UI_equipment_activate"; activeParamHash = Animator.StringToHash("active"); activeDurationParamHash = Animator.StringToHash("activeDuration"); activeStopwatchParamHash = Animator.StringToHash("activeStopwatch"); kCmdCmdExecuteIfReady = -303452611; NetworkBehaviour.RegisterCommandDelegate(typeof(EquipmentSlot), kCmdCmdExecuteIfReady, InvokeCmdCmdExecuteIfReady); kCmdCmdOnEquipmentExecuted = 1725820338; NetworkBehaviour.RegisterCommandDelegate(typeof(EquipmentSlot), kCmdCmdOnEquipmentExecuted, InvokeCmdCmdOnEquipmentExecuted); kRpcRpcOnClientEquipmentActivationRecieved = 1342577121; NetworkBehaviour.RegisterRpcDelegate(typeof(EquipmentSlot), kRpcRpcOnClientEquipmentActivationRecieved, InvokeRpcRpcOnClientEquipmentActivationRecieved); NetworkCRC.RegisterBehaviour("EquipmentSlot", 0); } private void UNetVersion() { } protected static void InvokeCmdCmdExecuteIfReady(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdExecuteIfReady called on client."); } else { ((EquipmentSlot)obj).CmdExecuteIfReady(); } } protected static void InvokeCmdCmdOnEquipmentExecuted(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdOnEquipmentExecuted called on client."); } else { ((EquipmentSlot)obj).CmdOnEquipmentExecuted(); } } public void CallCmdExecuteIfReady() { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdExecuteIfReady called on server."); return; } if (base.isServer) { CmdExecuteIfReady(); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdExecuteIfReady); networkWriter.Write(GetComponent().netId); SendCommandInternal(networkWriter, 0, "CmdExecuteIfReady"); } public void CallCmdOnEquipmentExecuted() { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdOnEquipmentExecuted called on server."); return; } if (base.isServer) { CmdOnEquipmentExecuted(); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdOnEquipmentExecuted); networkWriter.Write(GetComponent().netId); SendCommandInternal(networkWriter, 0, "CmdOnEquipmentExecuted"); } protected static void InvokeRpcRpcOnClientEquipmentActivationRecieved(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcOnClientEquipmentActivationRecieved called on server."); } else { ((EquipmentSlot)obj).RpcOnClientEquipmentActivationRecieved(); } } public void CallRpcOnClientEquipmentActivationRecieved() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcOnClientEquipmentActivationRecieved called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnClientEquipmentActivationRecieved); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcOnClientEquipmentActivationRecieved"); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class EscapeSequenceController : NetworkBehaviour { [Serializable] public struct ScheduledEvent { public float minSecondsRemaining; public float maxSecondsRemaining; public UnityEvent onEnter; public UnityEvent onExit; [NonSerialized] public bool inEvent; } public class EscapeSequenceBaseState : BaseState { protected EscapeSequenceController escapeSequenceController { get; private set; } public override void OnEnter() { base.OnEnter(); escapeSequenceController = GetComponent(); } } public class EscapeSequenceMainState : EscapeSequenceBaseState { private Run.FixedTimeStamp startTime; private Run.FixedTimeStamp endTime; public override void OnEnter() { base.OnEnter(); if (base.isAuthority) { startTime = Run.FixedTimeStamp.now; endTime = startTime + base.escapeSequenceController.countdownDuration; } base.escapeSequenceController.onEnterMainEscapeSequence?.Invoke(); } public override void OnExit() { foreach (HUD readOnlyInstance in HUD.readOnlyInstanceList) { base.escapeSequenceController.SetHudCountdownEnabled(readOnlyInstance, shouldEnableCountdownPanel: false); } base.OnExit(); } public override void Update() { base.Update(); foreach (HUD readOnlyInstance in HUD.readOnlyInstanceList) { base.escapeSequenceController.SetHudCountdownEnabled(readOnlyInstance, readOnlyInstance.targetBodyObject); } base.escapeSequenceController.SetCountdownTime(endTime.timeUntilClamped); } public override void FixedUpdate() { base.FixedUpdate(); base.escapeSequenceController.UpdateScheduledEvents(endTime.timeUntil); if (base.isAuthority && endTime.hasPassed && !SceneExitController.isRunning) { outer.SetNextState(new EscapeSequenceFailureState()); } } public override void OnSerialize(NetworkWriter writer) { base.OnSerialize(writer); writer.Write(startTime); writer.Write(endTime); } public override void OnDeserialize(NetworkReader reader) { base.OnDeserialize(reader); startTime = reader.ReadFixedTimeStamp(); endTime = reader.ReadFixedTimeStamp(); } } public class EscapeSequenceFailureState : EscapeSequenceBaseState { public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { base.escapeSequenceController.onFailEscapeSequenceServer?.Invoke(); } } } public class EscapeSequenceSuccessState : EscapeSequenceBaseState { public override void OnEnter() { base.OnEnter(); if (NetworkServer.active) { base.escapeSequenceController.onCompleteEscapeSequenceServer?.Invoke(); } } } public EntityStateMachine mainStateMachine; [Tooltip("How long the player has to escape, in seconds.")] public float countdownDuration; public UnityEvent onEnterMainEscapeSequence; public UnityEvent onCompleteEscapeSequenceServer; public UnityEvent onFailEscapeSequenceServer; public ScheduledEvent[] scheduledEvents; private Dictionary hudPanels; public void BeginEscapeSequence() { if (Util.HasEffectiveAuthority(base.gameObject)) { mainStateMachine.SetNextState(new EscapeSequenceMainState()); } } public void CompleteEscapeSequence() { if (Util.HasEffectiveAuthority(base.gameObject)) { mainStateMachine.SetNextState(new EscapeSequenceSuccessState()); } } private void UpdateScheduledEvents(float secondsRemaining) { for (int i = 0; i < scheduledEvents.Length; i++) { ref ScheduledEvent reference = ref scheduledEvents[i]; bool flag = reference.minSecondsRemaining <= secondsRemaining && secondsRemaining <= reference.maxSecondsRemaining; if (flag != reference.inEvent) { if (flag) { reference.onEnter?.Invoke(); } else { reference.onExit?.Invoke(); } reference.inEvent = flag; } } } private void SetHudCountdownEnabled(HUD hud, bool shouldEnableCountdownPanel) { shouldEnableCountdownPanel &= base.enabled; hudPanels.TryGetValue(hud, out var value); if ((bool)value == shouldEnableCountdownPanel) { return; } if (shouldEnableCountdownPanel) { RectTransform rectTransform = hud.GetComponent().FindChild("TopCenterCluster") as RectTransform; if ((bool)rectTransform) { GameObject value2 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/UI/HudModules/HudCountdownPanel"), rectTransform); hudPanels[hud] = value2; } } else { UnityEngine.Object.Destroy(value); hudPanels.Remove(hud); } } private void SetCountdownTime(double secondsRemaining) { foreach (KeyValuePair hudPanel in hudPanels) { hudPanel.Value.GetComponent().seconds = secondsRemaining; } AkSoundEngine.SetRTPCValue("EscapeTimer", Util.Remap((float)secondsRemaining, 0f, countdownDuration, 0f, 100f)); } private void OnEnable() { hudPanels = new Dictionary(); } private void OnDisable() { foreach (HUD readOnlyInstance in HUD.readOnlyInstanceList) { SetHudCountdownEnabled(readOnlyInstance, shouldEnableCountdownPanel: false); } hudPanels = null; } public void DestroyAllBodies() { List list = new List(CharacterBody.readOnlyInstancesList); for (int i = 0; i < list.Count; i++) { CharacterBody characterBody = list[i]; if ((bool)characterBody) { UnityEngine.Object.Destroy(characterBody.gameObject); } } } public void KillAllCharacters() { List list = new List(CharacterMaster.readOnlyInstancesList); for (int i = 0; i < list.Count; i++) { CharacterMaster characterMaster = list[i]; if ((bool)characterMaster) { characterMaster.TrueKill(null, null, DamageType.Silent | DamageType.VoidDeath); } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class EscapeSequenceExtractionZone : MonoBehaviour { private class EscapeSequenceExtractionZoneObjectiveTracker : ObjectivePanelController.ObjectiveTracker { private int cachedLivingPlayersCount; private int cachedPlayersInRadiusCount; private EscapeSequenceExtractionZone extractionZone => (EscapeSequenceExtractionZone)sourceDescriptor.source; public override string ToString() { cachedLivingPlayersCount = extractionZone.livingPlayerCount; cachedPlayersInRadiusCount = extractionZone.playersInRadius.Count; string text = Language.GetString(extractionZone.objectiveToken); if (cachedLivingPlayersCount >= 1) { text = Language.GetStringFormatted("OBJECTIVE_FRACTION_PROGRESS_FORMAT", text, cachedPlayersInRadiusCount, cachedLivingPlayersCount); } return text; } protected override bool IsDirty() { if (cachedLivingPlayersCount != extractionZone.livingPlayerCount) { return cachedPlayersInRadiusCount != extractionZone.playersInRadius.Count; } return false; } } public float radius; public string objectiveToken; public GameEndingDef successEnding; private int livingPlayerCount; private List playersInRadius; private TeamIndex teamIndex = TeamIndex.Player; private void Awake() { playersInRadius = new List(); } private void FixedUpdate() { livingPlayerCount = CountLivingPlayers(teamIndex); playersInRadius.Clear(); GetPlayersInRadius(base.transform.position, radius * radius, teamIndex, playersInRadius); if (NetworkServer.active && livingPlayerCount > 0 && playersInRadius.Count >= livingPlayerCount) { HandleEndingServer(); } } private void OnEnable() { if (InstanceTracker.GetInstancesList().Count == 0) { ObjectivePanelController.collectObjectiveSources += ReportObjectives; } InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); if (InstanceTracker.GetInstancesList().Count == 0) { ObjectivePanelController.collectObjectiveSources -= ReportObjectives; } } private void OnDrawGizmos() { Gizmos.color = UnityEngine.Color.yellow; Gizmos.DrawSphere(base.transform.position, radius); } public void KillAllStragglers() { List list = new List(CharacterMaster.readOnlyInstancesList); for (int i = 0; i < list.Count; i++) { CharacterMaster characterMaster = list[i]; if ((bool)characterMaster && !playersInRadius.Contains(characterMaster.GetBody())) { characterMaster.TrueKill(null, null, DamageType.Silent | DamageType.VoidDeath); } } } public void HandleEndingServer() { if (!Run.instance.isGameOverServer) { KillAllStragglers(); if (playersInRadius.Count > 0) { Run.instance.BeginGameOver(successEnding); } } } private static void ReportObjectives(CharacterMaster characterMaster, List dest) { List instancesList = InstanceTracker.GetInstancesList(); for (int i = 0; i < instancesList.Count; i++) { EscapeSequenceExtractionZone escapeSequenceExtractionZone = instancesList[i]; if (characterMaster.teamIndex == escapeSequenceExtractionZone.teamIndex) { ObjectivePanelController.ObjectiveSourceDescriptor objectiveSourceDescriptor = default(ObjectivePanelController.ObjectiveSourceDescriptor); objectiveSourceDescriptor.master = characterMaster; objectiveSourceDescriptor.objectiveType = typeof(EscapeSequenceExtractionZoneObjectiveTracker); objectiveSourceDescriptor.source = escapeSequenceExtractionZone; } } } private static bool IsPointInRadius(UnityEngine.Vector3 origin, float chargingRadiusSqr, UnityEngine.Vector3 point) { if ((point - origin).sqrMagnitude <= chargingRadiusSqr) { return true; } return false; } private static bool IsBodyInRadius(UnityEngine.Vector3 origin, float chargingRadiusSqr, CharacterBody characterBody) { return IsPointInRadius(origin, chargingRadiusSqr, characterBody.corePosition); } private static int CountLivingPlayers(TeamIndex teamIndex) { int num = 0; ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamIndex); for (int i = 0; i < teamMembers.Count; i++) { if (teamMembers[i].body.isPlayerControlled) { num++; } } return num; } public int CountPlayersInRadius(UnityEngine.Vector3 origin, float chargingRadiusSqr, TeamIndex teamIndex) { int num = 0; ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamIndex); for (int i = 0; i < teamMembers.Count; i++) { TeamComponent teamComponent = teamMembers[i]; if (teamComponent.body.isPlayerControlled && IsBodyInRadius(origin, chargingRadiusSqr, teamComponent.body)) { num++; } } return num; } private int GetPlayersInRadius(UnityEngine.Vector3 origin, float chargingRadiusSqr, TeamIndex teamIndex, List dest) { int result = 0; ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamIndex); for (int i = 0; i < teamMembers.Count; i++) { TeamComponent teamComponent = teamMembers[i]; if (teamComponent.body.isPlayerControlled && IsBodyInRadius(origin, chargingRadiusSqr, teamComponent.body)) { dest.Add(teamComponent.body); } } return result; } public bool IsBodyInRadius(CharacterBody body) { if (!body) { return false; } return IsBodyInRadius(base.transform.position, radius * radius, body); } } public class EventFunctions : MonoBehaviour { public void DestroySelf() { UnityEngine.Object.Destroy(base.gameObject); } public void DestroyGameObject(GameObject obj) { UnityEngine.Object.Destroy(obj); } public void UnparentTransform(Transform transform) { if ((bool)transform) { transform.SetParent(null); } } public void ToggleGameObjectActive(GameObject obj) { obj.SetActive(!obj.activeSelf); } public void CreateLocalEffect(GameObject effectObj) { EffectData effectData = new EffectData(); effectData.origin = base.transform.position; EffectManager.SpawnEffect(effectObj, effectData, transmit: false); } public void CreateNetworkedEffect(GameObject effectObj) { EffectData effectData = new EffectData(); effectData.origin = base.transform.position; EffectManager.SpawnEffect(effectObj, effectData, transmit: true); } public void OpenURL(string url) { Application.OpenURL(url); } public void PlaySound(string soundString) { Util.PlaySound(soundString, base.gameObject); } public void PlayUISound(string soundString) { Util.PlaySound(soundString, RoR2Application.instance.gameObject); } public void PlayNetworkedUISound(NetworkSoundEventDef nseDef) { if ((bool)nseDef) { EffectManager.SimpleSoundEffect(nseDef.index, UnityEngine.Vector3.zero, transmit: true); } } public void RunSetFlag(string flagName) { if (NetworkServer.active) { Run.instance?.SetEventFlag(flagName); } } public void RunResetFlag(string flagName) { if (NetworkServer.active) { Run.instance?.ResetEventFlag(flagName); } } public void DisableAllChildren() { for (int num = base.transform.childCount - 1; num >= 0; num--) { base.transform.GetChild(num).gameObject.SetActive(value: false); } } public void DisableAllChildrenExcept(GameObject objectToEnable) { for (int num = base.transform.childCount - 1; num >= 0; num--) { GameObject gameObject = base.transform.GetChild(num).gameObject; if (!(gameObject == objectToEnable)) { gameObject.SetActive(value: false); } } objectToEnable.SetActive(value: true); } public void BeginEnding(GameEndingDef gameEndingDef) { if (NetworkServer.active) { Run.instance.BeginGameOver(gameEndingDef); } } } public class EventOnBodyDeaths : MonoBehaviour { public string[] bodyNames; private int currentDeathCount; public int targetDeathCount; public UnityEvent onAchieved; private void OnEnable() { GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath; } private void OnDisable() { GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath; } private void OnCharacterDeath(DamageReport damageReport) { if ((bool)damageReport.victimBody) { for (int i = 0; i < bodyNames.Length; i++) { if (damageReport.victimBody.name.Contains(bodyNames[i])) { currentDeathCount++; break; } } } if (currentDeathCount >= targetDeathCount) { onAchieved?.Invoke(); } } } public class ExperienceManager : MonoBehaviour { [Serializable] private struct TimedExpAward { public float awardTime; public ulong awardAmount; public TeamIndex recipient; } private class CreateExpEffectMessage : MessageBase { public UnityEngine.Vector3 origin; public GameObject targetBody; public ulong awardAmount; public override void Serialize(NetworkWriter writer) { writer.Write(origin); writer.Write(targetBody); writer.WritePackedUInt64(awardAmount); } public override void Deserialize(NetworkReader reader) { origin = reader.ReadVector3(); targetBody = reader.ReadGameObject(); awardAmount = reader.ReadPackedUInt64(); } } private static GameObject experienceOrbPrefab; private float localTime; private List pendingAwards = new List(); private float nextAward; private bool shouldPool; private const float minOrbTravelTime = 0.5f; public const float maxOrbTravelTime = 2f; public static readonly float[] orbTimeOffsetSequence = new float[16] { 0.841f, 0.394f, 0.783f, 0.799f, 0.912f, 0.197f, 0.335f, 0.768f, 0.278f, 0.554f, 0.477f, 0.629f, 0.365f, 0.513f, 0.953f, 0.917f }; private static CreateExpEffectMessage currentOutgoingCreateExpEffectMessage = new CreateExpEffectMessage(); private static CreateExpEffectMessage currentIncomingCreateExpEffectMessage = new CreateExpEffectMessage(); public static ExperienceManager instance { get; private set; } private static float CalcOrbTravelTime(float timeOffset) { return 0.5f + 1.5f * timeOffset; } private void OnEnable() { if ((bool)instance && instance != this) { UnityEngine.Debug.LogError("Only one ExperienceManager can exist at a time."); return; } instance = this; if (!experienceOrbPrefab) { LegacyResourcesAPI.LoadAsyncCallback("Prefabs/ExpOrb", delegate(GameObject x) { experienceOrbPrefab = x; shouldPool = EffectManager.ShouldUsePooledEffect(experienceOrbPrefab); }); } } private void OnDisable() { if (instance == this) { instance = null; } } private void Start() { localTime = 0f; nextAward = float.PositiveInfinity; } private void FixedUpdate() { localTime += Time.fixedDeltaTime; if (pendingAwards.Count <= 0 || !(nextAward <= localTime)) { return; } nextAward = float.PositiveInfinity; for (int num = pendingAwards.Count - 1; num >= 0; num--) { if (pendingAwards[num].awardTime <= localTime) { if ((bool)TeamManager.instance) { TeamManager.instance.GiveTeamExperience(pendingAwards[num].recipient, pendingAwards[num].awardAmount); } pendingAwards.RemoveAt(num); } else if (pendingAwards[num].awardTime < nextAward) { nextAward = pendingAwards[num].awardTime; } } } public void AwardExperience(UnityEngine.Vector3 origin, CharacterBody body, ulong amount) { CharacterMaster master = body.master; if (!master) { return; } TeamIndex teamIndex = master.teamIndex; List list = CalculateDenominations(amount); uint num = 0u; for (int i = 0; i < list.Count; i++) { AddPendingAward(localTime + 0.5f + 1.5f * orbTimeOffsetSequence[num], teamIndex, list[i]); num++; if (num >= orbTimeOffsetSequence.Length) { num = 0u; } } currentOutgoingCreateExpEffectMessage.awardAmount = amount; currentOutgoingCreateExpEffectMessage.origin = origin; currentOutgoingCreateExpEffectMessage.targetBody = body.gameObject; NetworkServer.SendToAll(55, currentOutgoingCreateExpEffectMessage); } private void AddPendingAward(float awardTime, TeamIndex recipient, ulong awardAmount) { pendingAwards.Add(new TimedExpAward { awardTime = awardTime, recipient = recipient, awardAmount = awardAmount }); if (nextAward > awardTime) { nextAward = awardTime; } } public List CalculateDenominations(ulong total) { List list = new List(); while (total != 0) { ulong num = (ulong)Math.Pow(6.0, Mathf.Floor(Mathf.Log(total, 6f))); total = Math.Max(total - num, 0uL); list.Add(num); } return list; } [NetworkMessageHandler(msgType = 55, client = true)] private static void HandleCreateExpEffect(NetworkMessage netMsg) { if ((bool)instance) { instance.HandleCreateExpEffectInternal(netMsg); } } private void HandleCreateExpEffectInternal(NetworkMessage netMsg) { netMsg.ReadMessage(currentIncomingCreateExpEffectMessage); if (!SettingsConVars.cvExpAndMoneyEffects.value) { return; } GameObject targetBody = currentIncomingCreateExpEffectMessage.targetBody; if (!targetBody) { return; } HurtBox hurtBox = Util.FindBodyMainHurtBox(targetBody); Transform targetTransform = (hurtBox ? hurtBox.transform : targetBody.transform); List list = CalculateDenominations(currentIncomingCreateExpEffectMessage.awardAmount); uint num = 0u; ExperienceOrbBehavior experienceOrbBehavior = null; for (int i = 0; i < list.Count; i++) { if (!shouldPool) { experienceOrbBehavior = UnityEngine.Object.Instantiate(experienceOrbPrefab, currentIncomingCreateExpEffectMessage.origin, UnityEngine.Quaternion.identity).GetComponent(); } else { EffectManagerHelper pooledEffect = EffectManager.GetPooledEffect(experienceOrbPrefab, currentIncomingCreateExpEffectMessage.origin, UnityEngine.Quaternion.identity); experienceOrbBehavior = pooledEffect.GetComponent(); pooledEffect.Reset(inActivate: true); pooledEffect.gameObject.SetActive(value: true); pooledEffect.ResetPostActivate(); } experienceOrbBehavior.targetTransform = targetTransform; experienceOrbBehavior.travelTime = CalcOrbTravelTime(orbTimeOffsetSequence[num]); experienceOrbBehavior.exp = list[i]; experienceOrbBehavior.SetupStartingValues(); num++; if (num >= orbTimeOffsetSequence.Length) { num = 0u; } } } } public class ExperienceOrbBehavior : MonoBehaviour { public GameObject hitEffectPrefab; private EffectManagerHelper efh; private new Transform transform; private TrailRenderer trail; private Light light; private float localTime; private UnityEngine.Vector3 startPos; private UnityEngine.Vector3 previousPos; private UnityEngine.Vector3 initialVelocity; private float scale; private bool consumed; private static readonly string expSoundString = "Play_UI_xp_gain"; public Transform targetTransform { get; set; } public float travelTime { get; set; } public ulong exp { get; set; } private void Awake() { transform = base.transform; trail = GetComponent(); light = GetComponent(); efh = GetComponent(); } private void Start() { SetupStartingValues(); } public void SetupStartingValues() { localTime = 0f; consumed = false; startPos = transform.position; previousPos = startPos; scale = 2f * Mathf.Log((float)exp + 1f, 6f); initialVelocity = (UnityEngine.Vector3.up * 4f + UnityEngine.Random.insideUnitSphere * 1f) * scale; transform.localScale = new UnityEngine.Vector3(scale, scale, scale); if ((bool)trail) { trail.startWidth = 0.05f * scale; } if ((bool)light) { light.range = 1f * scale; } } private void Update() { localTime += Time.deltaTime; if (!targetTransform) { HandleEnd(); return; } float num = Mathf.Clamp01(localTime / travelTime); previousPos = transform.position; transform.position = CalculatePosition(startPos, initialVelocity, targetTransform.position, num); if (num >= 1f) { OnHitTarget(); } } private static UnityEngine.Vector3 CalculatePosition(UnityEngine.Vector3 startPos, UnityEngine.Vector3 initialVelocity, UnityEngine.Vector3 targetPos, float t) { UnityEngine.Vector3 a = startPos + initialVelocity * t; float t2 = t * t * t; return UnityEngine.Vector3.LerpUnclamped(a, targetPos, t2); } private void OnTriggerStay(Collider other) { if (other.transform == targetTransform) { OnHitTarget(); } } private void OnHitTarget() { if (!consumed) { consumed = true; Util.PlaySound(expSoundString, targetTransform.gameObject); GameObject gameObject; if (!EffectManager.ShouldUsePooledEffect(hitEffectPrefab)) { gameObject = UnityEngine.Object.Instantiate(hitEffectPrefab, transform.position, Util.QuaternionSafeLookRotation(previousPos - startPos)); } else { EffectManagerHelper pooledEffect = EffectManager.GetPooledEffect(hitEffectPrefab, transform.position, Util.QuaternionSafeLookRotation(previousPos - startPos)); pooledEffect.Reset(inActivate: true); gameObject = pooledEffect.gameObject; gameObject.SetActive(value: true); pooledEffect.ResetPostActivate(); } gameObject.transform.localScale *= scale; HandleEnd(); } } private void HandleEnd() { if (efh != null) { efh.ReturnToPool(); } else { UnityEngine.Object.Destroy(base.gameObject); } } } public class ExplodeRigidbodiesOnStart : MonoBehaviour { public Rigidbody[] bodies; public float force; public float explosionRadius; private void Start() { UnityEngine.Vector3 position = base.transform.position; for (int i = 0; i < bodies.Length; i++) { bodies[i].AddExplosionForce(force, position, explosionRadius); } } } public class EyeFlare : MonoBehaviour { [Tooltip("The transform whose forward vector will be tested against the camera angle to determine scaling. This is usually the parent, and never this object since billboarding will affect the direction.")] public Transform directionSource; public float localScale = 1f; private static List instancesList; private new Transform transform; static EyeFlare() { instancesList = new List(); SceneCamera.onSceneCameraPreCull += OnSceneCameraPreCull; } private void OnEnable() { instancesList.Add(this); } private void OnDisable() { instancesList.Remove(this); } private static void OnSceneCameraPreCull(SceneCamera sceneCamera) { Transform obj = Camera.current.transform; UnityEngine.Quaternion rotation = obj.rotation; UnityEngine.Vector3 forward = obj.forward; for (int i = 0; i < instancesList.Count; i++) { EyeFlare eyeFlare = instancesList[i]; float num = eyeFlare.localScale; if ((bool)eyeFlare.directionSource) { float num2 = UnityEngine.Vector3.Dot(forward, eyeFlare.directionSource.forward) * -0.5f + 0.5f; num *= num2 * num2; } eyeFlare.transform.localScale = new UnityEngine.Vector3(num, num, num); eyeFlare.transform.rotation = rotation; } } private void Awake() { transform = base.transform; } } public class FadeToBlackOffset : MonoBehaviour { public float value; private void OnEnable() { InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); } } public class FallBootsLights : MonoBehaviour { public GameObject readyEffect; public GameObject triggerEffect; public GameObject chargingEffect; private GameObject readyEffectInstance; private GameObject triggerEffectInstance; private GameObject chargingEffectInstance; private bool isReady; private bool isTriggered; private bool isCharging; private CharacterModel characterModel; private EntityStateMachine sourceStateMachine; private void Start() { characterModel = GetComponentInParent(); FindSourceStateMachine(); } private void FindSourceStateMachine() { if ((bool)characterModel && (bool)characterModel.body) { sourceStateMachine = BaseHeadstompersState.FindForBody(characterModel.body)?.outer; } } private void Update() { if (!sourceStateMachine) { FindSourceStateMachine(); } bool flag = (bool)sourceStateMachine && !(sourceStateMachine.state is HeadstompersCooldown); if (flag != isReady) { if (flag) { readyEffectInstance = UnityEngine.Object.Instantiate(readyEffect, base.transform.position, base.transform.rotation, base.transform); Util.PlaySound("Play_item_proc_fallboots_activate", base.gameObject); } else if ((bool)readyEffectInstance) { UnityEngine.Object.Destroy(readyEffectInstance); } isReady = flag; } bool flag2 = (bool)sourceStateMachine && sourceStateMachine.state is HeadstompersFall; if (flag2 != isTriggered) { if (flag2) { triggerEffectInstance = UnityEngine.Object.Instantiate(triggerEffect, base.transform.position, base.transform.rotation, base.transform); Util.PlaySound("Play_item_proc_fallboots_activate", base.gameObject); } else if ((bool)triggerEffectInstance) { UnityEngine.Object.Destroy(triggerEffectInstance); } isTriggered = flag2; } bool flag3 = (bool)sourceStateMachine && sourceStateMachine.state is HeadstompersCharge; if (flag3 != isCharging) { if (flag3) { chargingEffectInstance = UnityEngine.Object.Instantiate(chargingEffect, base.transform.position, base.transform.rotation, base.transform); } else if ((bool)chargingEffectInstance) { UnityEngine.Object.Destroy(chargingEffectInstance); } isCharging = flag3; } } } public class FireAuraController : NetworkBehaviour { private const float fireAttackRadiusMin = 0.5f; private const float fireAttackRadiusMax = 6f; private const float fireDamageCoefficient = 1f; private const float fireProcCoefficient = 0.1f; private const float maxTimer = 8f; private float timer; private float attackStopwatch; [SyncVar] public GameObject owner; private NetworkInstanceId ___ownerNetId; public GameObject Networkowner { get { return owner; } [param: In] set { SetSyncVarGameObject(value, ref owner, 1u, ref ___ownerNetId); } } private void FixedUpdate() { timer += Time.fixedDeltaTime; CharacterBody characterBody = null; float num = 0f; if ((bool)owner) { characterBody = owner.GetComponent(); num = (characterBody ? Mathf.Lerp(characterBody.radius * 0.5f, characterBody.radius * 6f, 1f - Mathf.Abs(-1f + 2f * timer / 8f)) : 0f); base.transform.position = owner.transform.position; base.transform.localScale = new UnityEngine.Vector3(num, num, num); } if (!NetworkServer.active) { return; } if (!owner) { UnityEngine.Object.Destroy(base.gameObject); return; } attackStopwatch += Time.fixedDeltaTime; if ((bool)characterBody && attackStopwatch >= 0.25f) { attackStopwatch = 0f; BlastAttack obj = new BlastAttack { attacker = owner, inflictor = base.gameObject }; obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker); obj.position = base.transform.position; obj.procCoefficient = 0.1f; obj.radius = num; obj.baseForce = 0f; obj.baseDamage = 1f * characterBody.damage; obj.bonusForce = UnityEngine.Vector3.zero; obj.crit = false; obj.damageType = DamageType.Generic; obj.attackerFiltering = AttackerFiltering.NeverHitSelf; obj.Fire(); } if (timer >= 8f) { UnityEngine.Object.Destroy(base.gameObject); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(owner); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(owner); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { ___ownerNetId = reader.ReadNetworkId(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { owner = reader.ReadGameObject(); } } public override void PreStartClient() { if (!___ownerNetId.IsEmpty()) { Networkowner = ClientScene.FindLocalObject(___ownerNetId); } } } [RequireComponent(typeof(VehicleSeat))] [RequireComponent(typeof(Rigidbody))] public class FireballVehicle : MonoBehaviour, ICameraStateProvider { [Header("Vehicle Parameters")] public float duration = 3f; public float initialSpeed = 120f; public float targetSpeed = 40f; public float acceleration = 20f; public float cameraLerpTime = 1f; [Header("Blast Parameters")] public bool detonateOnCollision; public GameObject explosionEffectPrefab; public float blastDamageCoefficient; public float blastRadius; public float blastForce; public BlastAttack.FalloffModel blastFalloffModel; public DamageTypeCombo blastDamageType; public UnityEngine.Vector3 blastBonusForce; public float blastProcCoefficient; public string explosionSoundString; [Header("Overlap Parameters")] public float overlapDamageCoefficient; public float overlapProcCoefficient; public float overlapForce; public float overlapFireFrequency; public float overlapResetFrequency; public float overlapVehicleDurationBonusPerHit; public GameObject overlapHitEffectPrefab; private float age; private bool hasDetonatedServer; private VehicleSeat vehicleSeat; private Rigidbody rigidbody; private OverlapAttack overlapAttack; private float overlapFireAge; private float overlapResetAge; private void Awake() { vehicleSeat = GetComponent(); vehicleSeat.onPassengerEnter += OnPassengerEnter; vehicleSeat.onPassengerExit += OnPassengerExit; rigidbody = GetComponent(); } private void OnPassengerExit(GameObject passenger) { if (NetworkServer.active) { DetonateServer(); } foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList) { if (readOnlyInstances.target == passenger) { readOnlyInstances.SetOverrideCam(this, 0f); readOnlyInstances.SetOverrideCam(null, cameraLerpTime); } } } private void OnPassengerEnter(GameObject passenger) { if ((bool)vehicleSeat.currentPassengerInputBank) { UnityEngine.Vector3 aimDirection = vehicleSeat.currentPassengerInputBank.aimDirection; rigidbody.rotation = UnityEngine.Quaternion.LookRotation(aimDirection); rigidbody.velocity = aimDirection * initialSpeed; CharacterBody currentPassengerBody = vehicleSeat.currentPassengerBody; overlapAttack = new OverlapAttack { attacker = currentPassengerBody.gameObject, damage = overlapDamageCoefficient * currentPassengerBody.damage, pushAwayForce = overlapForce, isCrit = currentPassengerBody.RollCrit(), damageColorIndex = DamageColorIndex.Item, inflictor = base.gameObject, procChainMask = default(ProcChainMask), procCoefficient = overlapProcCoefficient, teamIndex = currentPassengerBody.teamComponent.teamIndex, hitBoxGroup = base.gameObject.GetComponent(), hitEffectPrefab = overlapHitEffectPrefab }; } } private void DetonateServer() { if (!hasDetonatedServer) { hasDetonatedServer = true; CharacterBody currentPassengerBody = vehicleSeat.currentPassengerBody; if ((bool)currentPassengerBody) { EffectData effectData = new EffectData { origin = base.transform.position, scale = blastRadius }; EffectManager.SpawnEffect(explosionEffectPrefab, effectData, transmit: true); BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = currentPassengerBody.gameObject; blastAttack.baseDamage = blastDamageCoefficient * currentPassengerBody.damage; blastAttack.baseForce = blastForce; blastAttack.bonusForce = blastBonusForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = currentPassengerBody.RollCrit(); blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.damageType = blastDamageType; blastAttack.falloffModel = blastFalloffModel; blastAttack.inflictor = base.gameObject; blastAttack.position = base.transform.position; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = blastProcCoefficient; blastAttack.radius = blastRadius; blastAttack.teamIndex = currentPassengerBody.teamComponent.teamIndex; blastAttack.Fire(); } Util.PlaySound(explosionSoundString, base.gameObject); UnityEngine.Object.Destroy(base.gameObject); } } private void FixedUpdate() { if (!vehicleSeat || !vehicleSeat.currentPassengerInputBank) { return; } age += Time.fixedDeltaTime; overlapFireAge += Time.fixedDeltaTime; overlapResetAge += Time.fixedDeltaTime; if (NetworkServer.active) { if (overlapFireAge > 1f / overlapFireFrequency) { if (overlapAttack.Fire()) { age = Mathf.Max(0f, age - overlapVehicleDurationBonusPerHit); } overlapFireAge = 0f; } if (overlapResetAge >= 1f / overlapResetFrequency) { overlapAttack.ResetIgnoredHealthComponents(); overlapResetAge = 0f; } } Ray aimRay = vehicleSeat.currentPassengerInputBank.GetAimRay(); aimRay = CameraRigController.ModifyAimRayIfApplicable(aimRay, base.gameObject, out var _); UnityEngine.Vector3 velocity = rigidbody.velocity; UnityEngine.Vector3 target = aimRay.direction * targetSpeed; UnityEngine.Vector3 vector = UnityEngine.Vector3.MoveTowards(velocity, target, acceleration * Time.fixedDeltaTime); rigidbody.MoveRotation(UnityEngine.Quaternion.LookRotation(aimRay.direction)); rigidbody.AddForce(vector - velocity, ForceMode.VelocityChange); if (NetworkServer.active && duration <= age) { DetonateServer(); } } private void OnCollisionEnter(Collision collision) { if (detonateOnCollision && NetworkServer.active) { DetonateServer(); } } public void GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState) { } public bool IsUserLookAllowed(CameraRigController cameraRigController) { return true; } public bool IsUserControlAllowed(CameraRigController cameraRigController) { return true; } public bool IsHudAllowed(CameraRigController cameraRigController) { return true; } } public class FireworkLauncher : MonoBehaviour { public GameObject projectilePrefab; public float launchInterval = 0.1f; public float damageCoefficient = 3f; public float coneAngle = 10f; public float randomCircleRange; [HideInInspector] public GameObject owner; [HideInInspector] public TeamIndex team; [HideInInspector] public int remaining; [HideInInspector] public bool crit; private float nextFireTimer; private void FixedUpdate() { if (!NetworkServer.active) { return; } if (remaining <= 0 || !owner) { UnityEngine.Object.Destroy(base.gameObject); return; } nextFireTimer -= Time.fixedDeltaTime; if (nextFireTimer <= 0f) { remaining--; nextFireTimer += launchInterval; FireMissile(); } } private void FireMissile() { CharacterBody component = owner.GetComponent(); if ((bool)component) { ProcChainMask procChainMask = default(ProcChainMask); UnityEngine.Vector2 vector = UnityEngine.Random.insideUnitCircle * randomCircleRange; MissileUtils.FireMissile(base.transform.position + new UnityEngine.Vector3(vector.x, 0f, vector.y), component, procChainMask, null, component.damage * damageCoefficient, crit, projectilePrefab, DamageColorIndex.Item, addMissileProc: false); } } } public class FlashEmission : MonoBehaviour { [Tooltip("The strength of a single flash (off,on,off)")] [SerializeField] private AnimationCurve flashCurve; [Tooltip("The duration of a single flash (off,on,off)")] [SerializeField] private float flashDuration; [SerializeField] private Renderer targetRenderer; private Material[] materials; [HideInInspector] public float time; private MaterialPropertyBlock propBlock; private bool active; private void OnEnable() { Initialize(); } private void OnDisable() { active = false; } private void Initialize() { if (targetRenderer == null) { targetRenderer = GetComponent(); } if (targetRenderer == null) { UnityEngine.Debug.LogWarning("FlashEmission on " + base.gameObject.name + " couldn't find a Renderer, shutting down."); base.enabled = false; } else if (materials == null) { materials = targetRenderer.materials; } } private void Update() { if (!active) { return; } float deltaTime = Time.deltaTime; if (deltaTime != 0f) { time = (time + deltaTime) % flashDuration; float value = flashCurve.Evaluate(time / flashDuration); Material[] array = materials; for (int i = 0; i < array.Length; i++) { _ = array[i]; propBlock = new MaterialPropertyBlock(); targetRenderer.GetPropertyBlock(propBlock); propBlock.SetFloat("_EmPower", value); targetRenderer.SetPropertyBlock(propBlock); } } } public void StartFlash() { active = true; } public void StopFlash() { active = false; } } public class FlickerLight : MonoBehaviour { public Light light; public Wave[] sinWaves; private float initialLightIntensity; private float workingLightIntensity; private float stopwatch; private float randomPhase; private void Start() { initialLightIntensity = light.intensity; workingLightIntensity = initialLightIntensity; randomPhase = UnityEngine.Random.Range(0f, MathF.PI * 2f); for (int i = 0; i < sinWaves.Length; i++) { sinWaves[i].cycleOffset += randomPhase; } } private void OnEnable() { workingLightIntensity = initialLightIntensity; } private void Update() { stopwatch += Time.deltaTime; float num = workingLightIntensity; for (int i = 0; i < sinWaves.Length; i++) { num *= 1f + sinWaves[i].Evaluate(stopwatch); } light.intensity = num; } public void UpdateLightIntensityMultiplier(float multiplier) { workingLightIntensity = initialLightIntensity * multiplier; } } public class FogDamageController : NetworkBehaviour { [Tooltip("Used to control which teams to damage. If it's null, it damages ALL teams")] [SerializeField] private TeamFilter teamFilter; [Tooltip("If true, it damages all OTHER teams than the one specified. If false, it damages the specified team.")] [SerializeField] private bool invertTeamFilter; [Tooltip("The period in seconds in between each tick")] [SerializeField] private float tickPeriodSeconds; [Range(0f, 1f)] [SerializeField] [Tooltip("The fraction of combined health to deduct per second. Note that damage is actually applied per tick, not per second.")] private float healthFractionPerSecond; [SerializeField] [Tooltip("The coefficient to increase the damage by, for every tick they take outside the zone.")] private float healthFractionRampCoefficientPerSecond; [Tooltip("The buff to apply when in danger, i.e not in the safe zone.")] [SerializeField] private BuffDef dangerBuffDef; [SerializeField] private float dangerBuffDuration; [Tooltip("An initial list of safe zones behaviors which protect bodies from the fog")] [SerializeField] private BaseZoneBehavior[] initialSafeZones; private float dictionaryValidationTimer; private float damageTimer; private List safeZones = new List(); private Dictionary characterBodyToStacks = new Dictionary(); private void Start() { BaseZoneBehavior[] array = initialSafeZones; foreach (BaseZoneBehavior zone in array) { AddSafeZone(zone); } } public void AddSafeZone(IZone zone) { safeZones.Add(zone); } public void RemoveSafeZone(IZone zone) { safeZones.Remove(zone); } private void FixedUpdate() { MyFixedUpdate(Time.fixedDeltaTime); } private void MyFixedUpdate(float deltaTime) { if (!NetworkServer.active) { return; } damageTimer += deltaTime; dictionaryValidationTimer += deltaTime; if (dictionaryValidationTimer > 60f) { dictionaryValidationTimer = 0f; CharacterBody[] array = new CharacterBody[characterBodyToStacks.Keys.Count]; characterBodyToStacks.Keys.CopyTo(array, 0); for (int i = 0; i < array.Length; i++) { if (!array[i]) { characterBodyToStacks.Remove(array[i]); } } } while (damageTimer > tickPeriodSeconds) { damageTimer -= tickPeriodSeconds; if ((bool)teamFilter) { if (invertTeamFilter) { for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++) { if (teamIndex != teamFilter.teamIndex && teamIndex != TeamIndex.None && teamIndex != 0) { EvaluateTeam(teamIndex); } } } else { EvaluateTeam(teamFilter.teamIndex); } } else { for (TeamIndex teamIndex2 = TeamIndex.Neutral; teamIndex2 < TeamIndex.Count; teamIndex2++) { EvaluateTeam(teamIndex2); } } foreach (KeyValuePair characterBodyToStack in characterBodyToStacks) { CharacterBody key = characterBodyToStack.Key; if (!key || !key.transform || !key.healthComponent) { continue; } int num = characterBodyToStack.Value - 1; float num2 = healthFractionPerSecond * (1f + (float)num * healthFractionRampCoefficientPerSecond * tickPeriodSeconds) * tickPeriodSeconds * key.healthComponent.fullCombinedHealth; if (num2 > 0f) { if (key.master != null && (bool)key.master.GetComponent()) { num2 *= 0.5f; } key.healthComponent.TakeDamage(new DamageInfo { damage = num2, position = key.corePosition, damageType = (DamageType.BypassArmor | DamageType.BypassBlock), damageColorIndex = DamageColorIndex.Void }); } if ((bool)dangerBuffDef) { key.AddTimedBuff(dangerBuffDef, dangerBuffDuration); } } } } public IEnumerable GetAffectedBodies() { TeamIndex currentTeam; if ((bool)teamFilter) { if (invertTeamFilter) { currentTeam = TeamIndex.Neutral; while (currentTeam < TeamIndex.Count) { IEnumerable affectedBodiesOnTeam = GetAffectedBodiesOnTeam(currentTeam); foreach (CharacterBody item in affectedBodiesOnTeam) { yield return item; } TeamIndex teamIndex = currentTeam + 1; currentTeam = teamIndex; } yield break; } IEnumerable affectedBodiesOnTeam2 = GetAffectedBodiesOnTeam(teamFilter.teamIndex); foreach (CharacterBody item2 in affectedBodiesOnTeam2) { yield return item2; } yield break; } currentTeam = TeamIndex.Neutral; while (currentTeam < TeamIndex.Count) { IEnumerable affectedBodiesOnTeam3 = GetAffectedBodiesOnTeam(currentTeam); foreach (CharacterBody item3 in affectedBodiesOnTeam3) { yield return item3; } TeamIndex teamIndex = currentTeam + 1; currentTeam = teamIndex; } } public IEnumerable GetAffectedBodiesOnTeam(TeamIndex teamIndex) { foreach (TeamComponent teamMember in TeamComponent.GetTeamMembers(teamIndex)) { CharacterBody body = teamMember.body; bool flag = false; foreach (IZone safeZone in safeZones) { if (safeZone.IsInBounds(teamMember.transform.position)) { flag = true; break; } } if (!flag) { yield return body; } } } private void EvaluateTeam(TeamIndex teamIndex) { foreach (TeamComponent teamMember in TeamComponent.GetTeamMembers(teamIndex)) { CharacterBody body = teamMember.body; bool flag = characterBodyToStacks.ContainsKey(body); bool flag2 = false; foreach (IZone safeZone in safeZones) { if (safeZone.IsInBounds(teamMember.transform.position)) { flag2 = true; break; } } if (flag2) { if (flag) { characterBodyToStacks.Remove(body); } } else if (!flag) { characterBodyToStacks.Add(body, 1); } else { characterBodyToStacks[body]++; } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class FollowerItemDisplayComponent : MonoBehaviour { public Transform target; public UnityEngine.Vector3 localPosition; public UnityEngine.Quaternion localRotation; public UnityEngine.Vector3 localScale; private new Transform transform; private void Awake() { transform = base.transform; } private void LateUpdate() { if (!target) { UnityEngine.Object.Destroy(base.gameObject); return; } UnityEngine.Quaternion rotation = target.rotation; transform.position = target.position + rotation * localPosition; transform.rotation = rotation * localRotation; transform.localScale = localScale; } } [RequireComponent(typeof(ChildLocator))] public class FootstepHandler : MonoBehaviour { public string baseFootstepString; public string baseFootliftString; public string sprintFootstepOverrideString; public string sprintFootliftOverrideString; public bool enableFootstepDust; public GameObject footstepDustPrefab; private ChildLocator childLocator; private Inventory bodyInventory; private Animator animator; private Transform footstepDustInstanceTransform; private ParticleSystem footstepDustInstanceParticleSystem; private ShakeEmitter footstepDustInstanceShakeEmitter; private CharacterBody body; public bool inLava; private void Start() { childLocator = GetComponent(); if ((bool)GetComponent()) { body = GetComponent().body; bodyInventory = (body ? body.inventory : null); } animator = GetComponent(); if (enableFootstepDust) { footstepDustInstanceTransform = UnityEngine.Object.Instantiate(footstepDustPrefab, base.transform).transform; footstepDustInstanceParticleSystem = footstepDustInstanceTransform.GetComponent(); footstepDustInstanceShakeEmitter = footstepDustInstanceTransform.GetComponent(); } } public void Update() { } public void Footstep(AnimationEvent animationEvent) { if ((double)animationEvent.animatorClipInfo.weight > 0.5) { Footstep(animationEvent.stringParameter, (GameObject)animationEvent.objectReferenceParameter); } } public void Footstep(string childName, GameObject footstepEffect) { if (!body) { return; } Transform transform = childLocator.FindChild(childName); int childIndex = childLocator.FindChildIndex(childName); if ((bool)transform) { UnityEngine.Color color = UnityEngine.Color.gray; RaycastHit hitInfo = default(RaycastHit); UnityEngine.Vector3 position = transform.position; position.y += 1.5f; if (Physics.Raycast(new Ray(position, UnityEngine.Vector3.down), out hitInfo, 4f, (int)LayerIndex.world.mask | (int)LayerIndex.water.mask, QueryTriggerInteraction.Collide)) { if ((bool)bodyInventory && bodyInventory.GetItemCount(RoR2Content.Items.Hoof) > 0 && childName == "FootR") { Util.PlaySound("Play_item_proc_hoof", body.gameObject); } if ((bool)footstepEffect) { EffectData effectData = new EffectData(); effectData.origin = hitInfo.point; effectData.rotation = Util.QuaternionSafeLookRotation(hitInfo.normal); effectData.SetChildLocatorTransformReference(body.gameObject, childIndex); EffectManager.SpawnEffect(footstepEffect, effectData, transmit: false); } SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitInfo.collider, hitInfo.point); bool flag = false; if ((bool)objectSurfaceDef) { body.surfaceSpeedBoost = objectSurfaceDef.speedBoost; color = objectSurfaceDef.approximateColor; if ((bool)objectSurfaceDef.footstepEffectPrefab) { EffectManager.SpawnEffect(objectSurfaceDef.footstepEffectPrefab, new EffectData { origin = hitInfo.point, scale = body.radius }, transmit: false); flag = true; } if (!string.IsNullOrEmpty(objectSurfaceDef.materialSwitchString)) { AkSoundEngine.SetSwitch("material", objectSurfaceDef.materialSwitchString, body.gameObject); } } else { inLava = false; } if ((bool)footstepDustInstanceTransform && !flag) { footstepDustInstanceTransform.position = hitInfo.point; ParticleSystem.MainModule main = footstepDustInstanceParticleSystem.main; main.startColor = color; footstepDustInstanceParticleSystem.Play(); if ((bool)footstepDustInstanceShakeEmitter) { footstepDustInstanceShakeEmitter.StartShake(); } } } Util.PlaySound((!string.IsNullOrEmpty(sprintFootstepOverrideString) && body.isSprinting) ? sprintFootstepOverrideString : baseFootstepString, body.gameObject); } else { UnityEngine.Debug.LogWarningFormat("Object {0} lacks ChildLocator entry \"{1}\" to handle Footstep event!", base.gameObject.name, childName); } } public void Footlift(AnimationEvent animationEvent) { if ((double)animationEvent.animatorClipInfo.weight > 0.5) { Footlift(); } } public void Footlift() { Util.PlaySound((!string.IsNullOrEmpty(sprintFootliftOverrideString) && body.isSprinting) ? sprintFootliftOverrideString : baseFootliftString, body.gameObject); } } public class ForcedCamera : MonoBehaviour, ICameraStateProvider { public float entryLerpDuration = 1f; public float exitLerpDuration = 1f; public float fovOverride; public bool allowUserLook; public bool allowUserHud; private void Update() { ReadOnlyCollection readOnlyInstancesList = CameraRigController.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { CameraRigController cameraRigController = readOnlyInstancesList[i]; if (!cameraRigController.hasOverride) { cameraRigController.SetOverrideCam(this, entryLerpDuration); } } } private void OnDisable() { ReadOnlyCollection readOnlyInstancesList = CameraRigController.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { CameraRigController cameraRigController = readOnlyInstancesList[i]; if (cameraRigController.IsOverrideCam(this)) { cameraRigController.SetOverrideCam(null, exitLerpDuration); } } } public void GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState) { cameraState.position = base.transform.position; cameraState.rotation = base.transform.rotation; if (fovOverride > 0f) { cameraState.fov = fovOverride; } } public bool IsUserLookAllowed(CameraRigController cameraRigController) { return allowUserLook; } public bool IsUserControlAllowed(CameraRigController cameraRigController) { return false; } public bool IsHudAllowed(CameraRigController cameraRigController) { return allowUserHud; } private void OnDrawGizmosSelected() { UnityEngine.Color color = Gizmos.color; UnityEngine.Matrix4x4 matrix = Gizmos.matrix; Gizmos.color = UnityEngine.Color.yellow; UnityEngine.Matrix4x4 identity = UnityEngine.Matrix4x4.identity; identity.SetTRS(base.transform.position, base.transform.rotation, UnityEngine.Vector3.one); Gizmos.matrix = identity; Gizmos.DrawFrustum(UnityEngine.Vector3.zero, (fovOverride > 0f) ? fovOverride : 60f, 10f, 0.1f, 1.7777778f); Gizmos.matrix = matrix; Gizmos.color = color; } } public class ForceSpectate : NetworkBehaviour { [SyncVar] public GameObject target; private NetworkInstanceId ___targetNetId; public GameObject Networktarget { get { return target; } [param: In] set { SetSyncVarGameObject(value, ref target, 1u, ref ___targetNetId); } } private void OnEnable() { InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(target); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(target); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { ___targetNetId = reader.ReadNetworkId(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { target = reader.ReadGameObject(); } } public override void PreStartClient() { if (!___targetNetId.IsEmpty()) { Networktarget = ClientScene.FindLocalObject(___targetNetId); } } } public class FrogController : MonoBehaviour { [SerializeField] private int maxPets; [SerializeField] private PortalSpawner portalSpawner; [SerializeField] private PurchaseInteraction purchaseInteraction; [SerializeField] private string petChatToken; private int petCount; public void Pet(Interactor interactor) { petCount++; if (!string.IsNullOrEmpty(petChatToken)) { Chat.SendBroadcastChat(new SubjectChatMessage { subjectAsCharacterBody = interactor.GetComponent(), baseToken = petChatToken }); } if (petCount >= maxPets && (bool)portalSpawner) { portalSpawner.AttemptSpawnPortalServer(); } } } public class GameEndingController : NetworkBehaviour { private class GameEndingControllerBaseState : BaseState { protected GameEndingController gameEndingController { get; private set; } public override void OnEnter() { base.OnEnter(); gameEndingController = GetComponent(); } } private class EndingCutsceneState : GameEndingControllerBaseState { } private class CreditsState : GameEndingControllerBaseState { } private class PostGameReportState : GameEndingControllerBaseState { } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class EclipseRun : Run { public static int minEclipseLevel = 1; public static int maxEclipseLevel = 8; private static Dictionary> survivorToEclipseUnlockables = new Dictionary>(); public static int minUnlockableEclipseLevel => minEclipseLevel + 1; public static DifficultyIndex GetEclipseDifficultyIndex(int eclipseLevel) { return (DifficultyIndex)(DifficultyCatalog.standardDifficultyCount - 1 + eclipseLevel); } private static List GetEclipseLevelUnlockablesForSurvivor(SurvivorDef survivorDef) { if (!survivorToEclipseUnlockables.TryGetValue(survivorDef, out var value)) { value = new List(); survivorToEclipseUnlockables[survivorDef] = value; if (BodyCatalog.GetBodyName(BodyCatalog.FindBodyIndex(survivorDef.bodyPrefab)) != null) { int num = minUnlockableEclipseLevel; StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder(); while (true) { stringBuilder.Clear(); stringBuilder.Append("Eclipse.").Append(survivorDef.cachedName).Append(".") .AppendInt(num); UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(stringBuilder.ToString()); if (!unlockableDef) { break; } value.Add(unlockableDef); num++; } HG.StringBuilderPool.ReturnStringBuilder(stringBuilder); } } return value; } public static int GetLocalUserSurvivorCompletedEclipseLevel(LocalUser localUser, SurvivorDef survivorDef) { List eclipseLevelUnlockablesForSurvivor = GetEclipseLevelUnlockablesForSurvivor(survivorDef); int num = 1; for (int i = 0; i < eclipseLevelUnlockablesForSurvivor.Count && localUser.userProfile.HasUnlockable(eclipseLevelUnlockablesForSurvivor[i]); i++) { num = minUnlockableEclipseLevel + i; } return Mathf.Clamp(num - 1, 0, maxEclipseLevel); } public static int GetNetworkUserSurvivorCompletedEclipseLevel(NetworkUser networkUser, SurvivorDef survivorDef) { List eclipseLevelUnlockablesForSurvivor = GetEclipseLevelUnlockablesForSurvivor(survivorDef); int num = 1; for (int i = 0; i < eclipseLevelUnlockablesForSurvivor.Count && networkUser.unlockables.Contains(eclipseLevelUnlockablesForSurvivor[i]); i++) { num = minUnlockableEclipseLevel + i; } return Mathf.Clamp(num - 1, 0, maxEclipseLevel); } public static int GetEclipseLevelFromRuleBook(RuleBook ruleBook) { return (int)(ruleBook.FindDifficulty() - DifficultyCatalog.standardDifficultyCount + 1); } public override void OnClientGameOver(RunReport runReport) { base.OnClientGameOver(runReport); if (!runReport.gameEnding.isWin) { return; } int num = GetEclipseLevelFromRuleBook(base.ruleBook) + 1; ReadOnlyCollection instances = PlayerCharacterMasterController.instances; for (int i = 0; i < instances.Count; i++) { _ = instances[i]; NetworkUser networkUser = instances[i].networkUser; if (!networkUser) { continue; } LocalUser localUser = networkUser.localUser; if (localUser == null) { continue; } SurvivorDef survivorPreference = networkUser.GetSurvivorPreference(); if ((bool)survivorPreference) { UnlockableDef safe = ListUtils.GetSafe(GetEclipseLevelUnlockablesForSurvivor(survivorPreference), num - minUnlockableEclipseLevel); if ((bool)safe) { localUser.userProfile.GrantUnlockable(safe); } } } } public override void OverrideRuleChoices(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong runSeed) { base.OverrideRuleChoices(mustInclude, mustExclude, base.seed); int num = 0; ReadOnlyCollection readOnlyInstancesList = NetworkUser.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { NetworkUser networkUser = readOnlyInstancesList[i]; SurvivorDef survivorPreference = networkUser.GetSurvivorPreference(); if ((bool)survivorPreference) { int num2 = GetNetworkUserSurvivorCompletedEclipseLevel(networkUser, survivorPreference) + 1; num = ((num > 0) ? Math.Min(num, num2) : num2); } } num = Math.Min(num, maxEclipseLevel); ForceChoice(mustInclude, mustExclude, $"Difficulty.{GetEclipseDifficultyIndex(num).ToString()}"); ForceChoice(mustInclude, mustExclude, "Items." + RoR2Content.Items.LunarTrinket.name + ".Off"); for (int j = 0; j < ArtifactCatalog.artifactCount; j++) { ForceChoice(mustInclude, mustExclude, FindRuleForArtifact((ArtifactIndex)j).FindChoice("Off")); } static RuleDef FindRuleForArtifact(ArtifactIndex artifactIndex) { ArtifactDef artifactDef = ArtifactCatalog.GetArtifactDef(artifactIndex); return RuleCatalog.FindRuleDef("Artifacts." + artifactDef.cachedName); } } protected override void HandlePostRunDestination() { Console.instance.SubmitCmd(null, "transition_command \"disconnect\";"); } protected new void Start() { base.Start(); if (NetworkServer.active) { SetEventFlag("NoArtifactWorld"); SetEventFlag("NoMysterySpace"); SetEventFlag("NoVoidStage"); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool flag = base.OnSerialize(writer, forceAll); bool flag2 = default(bool); return flag2 || flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { base.OnDeserialize(reader, initialState); } public override void PreStartClient() { base.PreStartClient(); } } public class InfiniteTowerRun : Run { [Serializable] public struct EnemyItemEntry { public PickupDropTable dropTable; public int stacks; } private const ulong waveRngSalt = 14312uL; private const ulong enemyItemRngSalt = 1535uL; private const ulong safeWardRngSalt = 769876uL; [SerializeField] [Header("Infinite Tower Settings")] [Tooltip("If all else fails, use this wave prefab")] private GameObject defaultWavePrefab; [Tooltip("Selects a wave from the first available category in this list")] [SerializeField] private InfiniteTowerWaveCategory[] waveCategories; [Tooltip("Use this indicator for enemies by default")] [SerializeField] private GameObject defaultWaveEnemyIndicatorPrefab; [Tooltip("The repeating pattern of drop tables to use when selecting items for the enemy team")] [SerializeField] private EnemyItemEntry[] enemyItemPattern; [SerializeField] [Tooltip("The number of waves before you give the enemy team the next item in the pattern (e.g., \"every Nth wave\")")] private int enemyItemPeriod; [SerializeField] [Tooltip("The reference inventory we use to store which items enemies should get")] private Inventory enemyInventory; [Tooltip("The number of waves before you transition to the next stage (e.g., \"every Nth wave\").")] [SerializeField] private int stageTransitionPeriod; [Tooltip("Spawn card for the stage transition portal")] [SerializeField] private InteractableSpawnCard stageTransitionPortalCard; [Tooltip("Maximum spawn distance for the stage transition portal.")] [SerializeField] private float stageTransitionPortalMaxDistance; [Tooltip("The chat message that's broadcasted when spawning the stage transition portal.")] [SerializeField] private string stageTransitionChatToken; [Tooltip("The prefab with the FogDamageController attached")] [SerializeField] private GameObject fogDamagePrefab; [SerializeField] [Tooltip("The maximum distance to spawn players from the safe ward")] private float spawnMaxRadius; [Tooltip("Spawn card for the safe ward that is spawned at the beginning of the run")] [SerializeField] private InteractableSpawnCard initialSafeWardCard; [Tooltip("Spawn card for the safe wards (after the first one)")] [SerializeField] private InteractableSpawnCard safeWardCard; [Tooltip("The effect to spawn when a player is revived at the end of a wave")] [SerializeField] private GameObject playerRespawnEffectPrefab; [Tooltip("The number of credits the SceneDirector uses to spawn interactables")] [SerializeField] private int interactableCredits; [Tooltip("Remove all items with these tags from the item pools")] [SerializeField] private ItemTag[] blacklistedTags; [Tooltip("Remove these items from the pool")] [SerializeField] private ItemDef[] blacklistedItems; [SyncVar] private int _waveIndex; [SyncVar] private NetworkInstanceId waveInstanceId; private InfiniteTowerWaveController _waveController; private Xoroshiro128Plus waveRng; private Xoroshiro128Plus enemyItemRng; private Xoroshiro128Plus safeWardRng; private int enemyItemPatternIndex; private InfiniteTowerSafeWardController safeWardController; private FogDamageController fogDamageController; public int waveIndex => _waveIndex; public InfiniteTowerWaveController waveController => _waveController; public override bool spawnWithPod => false; public override bool canFamilyEventTrigger => false; public override bool autoGenerateSpawnPoints => false; public GameObject waveInstance => Util.FindNetworkObject(waveInstanceId); public int Network_waveIndex { get { return _waveIndex; } [param: In] set { SetSyncVar(value, ref _waveIndex, 64u); } } public NetworkInstanceId NetworkwaveInstanceId { get { return waveInstanceId; } [param: In] set { SetSyncVar(value, ref waveInstanceId, 128u); } } public static event Action onWaveInitialized; public static event Action onAllEnemiesDefeatedServer; public override GameObject InstantiateUi(Transform uiRoot) { GameObject gameObject = base.InstantiateUi(uiRoot); if ((bool)_waveController) { _waveController.InstantiateUi(gameObject.transform); } return gameObject; } public override void OverrideRuleChoices(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong runSeed) { base.OverrideRuleChoices(mustInclude, mustExclude, base.seed); ItemIndex itemIndex = ItemIndex.Count; for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++) { ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); bool flag = Array.IndexOf(blacklistedItems, itemDef) != -1; if (!flag) { ItemTag[] array = blacklistedTags; foreach (ItemTag itemTag in array) { if (itemDef.ContainsTag(itemTag)) { flag = true; break; } } } if (flag) { RuleChoiceDef ruleChoiceDef = RuleCatalog.FindRuleDef("Items." + itemDef.name)?.FindChoice("Off"); if (ruleChoiceDef != null) { ForceChoice(mustInclude, mustExclude, ruleChoiceDef); } } } } [Server] public void ResetSafeWard() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::ResetSafeWard()' called on client"); return; } if ((bool)safeWardController) { if ((bool)fogDamageController) { fogDamageController.RemoveSafeZone(safeWardController.safeZone); } safeWardController.SelfDestruct(); } SpawnSafeWard(safeWardCard, new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Random }); } [Server] public void MoveSafeWard() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::MoveSafeWard()' called on client"); } else if ((bool)safeWardController) { safeWardController.RandomizeLocation(safeWardRng); safeWardController.onActivated += OnSafeWardActivated; } } public bool IsStageTransitionWave() { if (stageTransitionPeriod != 0) { return waveIndex % stageTransitionPeriod == 0; } return true; } public override UnityEngine.Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination) { if ((bool)safeWardController && !targetDestination) { return base.FindSafeTeleportPosition(characterBody, safeWardController.transform); } return base.FindSafeTeleportPosition(characterBody, targetDestination); } public override UnityEngine.Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination, float idealMinDistance, float idealMaxDistance) { if ((bool)safeWardController && !targetDestination) { return base.FindSafeTeleportPosition(characterBody, safeWardController.transform, idealMinDistance, idealMaxDistance); } return base.FindSafeTeleportPosition(characterBody, targetDestination, idealMinDistance, idealMaxDistance); } [Server] private void OnSafeWardActivated(InfiniteTowerSafeWardController safeWard) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::OnSafeWardActivated(RoR2.InfiniteTowerSafeWardController)' called on client"); return; } safeWardController.onActivated -= OnSafeWardActivated; if ((bool)_waveController) { _waveController.ForceFinish(); CleanUpCurrentWave(); } BeginNextWave(); } [Server] private void AdvanceWave() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::AdvanceWave()' called on client"); return; } Network_waveIndex = _waveIndex + 1; if (_waveIndex % enemyItemPeriod != 0) { return; } EnemyItemEntry enemyItemEntry = enemyItemPattern[enemyItemPatternIndex++ % enemyItemPattern.Length]; if (!enemyItemEntry.dropTable) { return; } PickupIndex pickupIndex = enemyItemEntry.dropTable.GenerateDrop(enemyItemRng); if (pickupIndex != PickupIndex.none) { PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef != null) { enemyInventory.GiveItem(pickupDef.itemIndex, enemyItemEntry.stacks); Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage { baseToken = "INFINITETOWER_ADD_ITEM", pickupToken = pickupDef.nameToken, pickupColor = pickupDef.baseColor }); } } } [Server] private void BeginNextWave() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::BeginNextWave()' called on client"); return; } AdvanceWave(); GameObject original = defaultWavePrefab; InfiniteTowerWaveCategory[] array = waveCategories; foreach (InfiniteTowerWaveCategory infiniteTowerWaveCategory in array) { if (infiniteTowerWaveCategory.IsAvailable(this)) { original = infiniteTowerWaveCategory.SelectWavePrefab(this, waveRng); break; } } GameObject gameObject = UnityEngine.Object.Instantiate(original, base.transform); NetworkServer.Spawn(gameObject); NetworkwaveInstanceId = gameObject.GetComponent().netId; RecalculateDifficultyCoefficentInternal(); } protected override void Start() { Stage.onServerStageBegin += OnServerStageBegin; Stage.onServerStageComplete += OnServerStageComplete; SceneDirector.onPrePopulateSceneServer += OnPrePopulateSceneServer; base.Start(); } protected override void OnDestroy() { Stage.onServerStageBegin -= OnServerStageBegin; Stage.onServerStageComplete -= OnServerStageComplete; SceneDirector.onPrePopulateSceneServer -= OnPrePopulateSceneServer; if ((bool)safeWardController) { UnityEngine.Object.Destroy(safeWardController.gameObject); safeWardController = null; } CleanUpCurrentWave(); base.OnDestroy(); } private void OnServerStageBegin(Stage stage) { } private void OnServerStageComplete(Stage stage) { PerformStageCleanUp(); } private void OnPrePopulateSceneServer(SceneDirector sceneDirector) { PerformStageCleanUp(); if ((bool)fogDamagePrefab) { GameObject gameObject = UnityEngine.Object.Instantiate(fogDamagePrefab, Stage.instance.transform); NetworkServer.Spawn(gameObject); fogDamageController = gameObject.GetComponent(); } sceneDirector.interactableCredit = interactableCredits; DirectorPlacementRule placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Random }; SpawnSafeWard(initialSafeWardCard, placementRule); if (!safeWardController) { return; } UnityEngine.Vector3 position = safeWardController.transform.position; NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); foreach (NodeGraph.NodeIndex item in nodeGraph.FindNodesInRangeWithFlagConditions(position, 0f, spawnMaxRadius, HullMask.Human, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false)) { if (nodeGraph.GetNodePosition(item, out var position2)) { SpawnPoint.AddSpawnPoint(position2, UnityEngine.Quaternion.LookRotation(position, UnityEngine.Vector3.up)); } } } protected override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && (bool)waveInstance && (bool)waveController && waveController.isFinished && !IsStageTransitionWave()) { CleanUpCurrentWave(); BeginNextWave(); } if ((bool)waveInstance) { if (!_waveController) { InitializeWaveController(); } } else { _waveController = null; } } protected override void RecalculateDifficultyCoefficentInternal() { DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(base.selectedDifficulty); float num = 1.5f * (float)waveIndex; float num2 = 0.0506f * difficultyDef.scalingValue; float num3 = Mathf.Pow(1.02f, waveIndex); difficultyCoefficient = (1f + num2 * num) * num3; compensatedDifficultyCoefficient = difficultyCoefficient; base.ambientLevel = Mathf.Min((difficultyCoefficient - 1f) / 0.33f + 1f, 9999f); int num4 = base.ambientLevelFloor; base.ambientLevelFloor = Mathf.FloorToInt(base.ambientLevel); if (num4 != base.ambientLevelFloor && num4 != 0 && base.ambientLevelFloor > num4) { OnAmbientLevelUp(); } } private void InitializeWaveController() { _waveController = waveInstance.GetComponent(); if (!_waveController) { return; } if (NetworkServer.active) { _waveController.Initialize(_waveIndex, enemyInventory, safeWardController.gameObject); } foreach (GameObject uiInstance in base.uiInstances) { _waveController.InstantiateUi(uiInstance.transform); } _waveController.PlayBeginSound(); _waveController.defaultEnemyIndicatorPrefab = defaultWaveEnemyIndicatorPrefab; _waveController.onAllEnemiesDefeatedServer += OnWaveAllEnemiesDefeatedServer; InfiniteTowerRun.onWaveInitialized?.Invoke(_waveController); } private void OnWaveAllEnemiesDefeatedServer(InfiniteTowerWaveController wc) { InfiniteTowerRun.onAllEnemiesDefeatedServer?.Invoke(wc); if (base.isGameOverServer) { return; } foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { CharacterMaster master = instance.master; if (!instance.isConnected || !master.IsDeadAndOutOfLivesServer()) { continue; } UnityEngine.Vector3 vector = master.deathFootPosition; if ((bool)safeWardController) { vector = TeleportHelper.FindSafeTeleportDestination(safeWardController.transform.position, master.bodyPrefab.GetComponent(), RoR2Application.rng) ?? vector; } master.Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f)); CharacterBody body = master.GetBody(); if ((bool)body) { body.AddTimedBuff(RoR2Content.Buffs.Immune, 3f); EntityStateMachine[] components = body.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } if ((bool)playerRespawnEffectPrefab) { EffectManager.SpawnEffect(playerRespawnEffectPrefab, new EffectData { origin = vector, rotation = body.transform.rotation }, transmit: true); } } } if (IsStageTransitionWave()) { PickNextStageSceneFromCurrentSceneDestinations(); DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(stageTransitionPortalCard, new DirectorPlacementRule { minDistance = 0f, maxDistance = stageTransitionPortalMaxDistance, placementMode = DirectorPlacementRule.PlacementMode.Approximate, position = safeWardController.transform.position, spawnOnTarget = safeWardController.transform }, safeWardRng)); Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = stageTransitionChatToken }); if ((bool)safeWardController) { safeWardController.WaitForPortal(); } } } protected override bool ShouldUpdateRunStopwatch() { return true; } protected override void OnSeedSet() { waveRng = new Xoroshiro128Plus(base.seed ^ 0x37E8); enemyItemRng = new Xoroshiro128Plus(base.seed ^ 0x5FF); safeWardRng = new Xoroshiro128Plus(base.seed ^ 0xBBF54); } private void CleanUpCurrentWave() { if ((bool)_waveController) { _waveController.onAllEnemiesDefeatedServer -= OnWaveAllEnemiesDefeatedServer; _waveController = null; } if ((bool)waveInstance) { UnityEngine.Object.Destroy(waveInstance); } NetworkwaveInstanceId = NetworkInstanceId.Invalid; } private void SpawnSafeWard(InteractableSpawnCard spawnCard, DirectorPlacementRule placementRule) { GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, placementRule, safeWardRng)); if ((bool)gameObject) { NetworkServer.Spawn(gameObject); safeWardController = gameObject.GetComponent(); if ((bool)safeWardController) { safeWardController.onActivated += OnSafeWardActivated; } HoldoutZoneController component = gameObject.GetComponent(); if ((bool)component) { component.calcAccumulatedCharge += CalcHoldoutZoneCharge; } if ((bool)fogDamageController) { fogDamageController.AddSafeZone(safeWardController.safeZone); } } else { UnityEngine.Debug.LogError("Unable to spawn safe ward instance. Are there any ground nodes?"); } } private void CalcHoldoutZoneCharge(ref float charge) { if ((bool)waveController) { float num = waveController.GetNormalizedProgress(); if (waveController.GetSquadCount() > 0) { num = Mathf.Min(num, 0.99f); } charge = num; } else { charge = 0f; } } [Server] public override void HandlePlayerFirstEntryAnimation(CharacterBody body, UnityEngine.Vector3 spawnPosition, UnityEngine.Quaternion spawnRotation) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::HandlePlayerFirstEntryAnimation(RoR2.CharacterBody,UnityEngine.Vector3,UnityEngine.Quaternion)' called on client"); } else { body.SetBodyStateToPreferredInitialState(); } } private void PerformStageCleanUp() { safeWardController = null; if ((bool)fogDamageController) { UnityEngine.Object.Destroy(fogDamageController.gameObject); } CleanUpCurrentWave(); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool flag = base.OnSerialize(writer, forceAll); if (forceAll) { writer.WritePackedUInt32((uint)_waveIndex); writer.Write(waveInstanceId); return true; } bool flag2 = false; if ((base.syncVarDirtyBits & 0x40u) != 0) { if (!flag2) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag2 = true; } writer.WritePackedUInt32((uint)_waveIndex); } if ((base.syncVarDirtyBits & 0x80u) != 0) { if (!flag2) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag2 = true; } writer.Write(waveInstanceId); } if (!flag2) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag2 || flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { base.OnDeserialize(reader, initialState); if (initialState) { _waveIndex = (int)reader.ReadPackedUInt32(); waveInstanceId = reader.ReadNetworkId(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & 0x40u) != 0) { _waveIndex = (int)reader.ReadPackedUInt32(); } if (((uint)num & 0x80u) != 0) { waveInstanceId = reader.ReadNetworkId(); } } public override void PreStartClient() { base.PreStartClient(); } } [DisallowMultipleComponent] [RequireComponent(typeof(NetworkRuleBook))] [RequireComponent(typeof(RunArtifactManager))] public class Run : NetworkBehaviour { [Serializable] public struct RunStopwatch : IEquatable { public float offsetFromFixedTime; public bool isPaused; public bool Equals(RunStopwatch other) { if (offsetFromFixedTime.Equals(other.offsetFromFixedTime)) { return isPaused == other.isPaused; } return false; } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is RunStopwatch other) { return Equals(other); } return false; } public override int GetHashCode() { return (offsetFromFixedTime.GetHashCode() * 397) ^ isPaused.GetHashCode(); } } [Serializable] public struct TimeStamp : IEquatable, IComparable { public readonly float t; private static float tNow; public static readonly TimeStamp zero; public static readonly TimeStamp positiveInfinity; public static readonly TimeStamp negativeInfinity; public float timeUntil => t - tNow; public float timeSince => tNow - t; public float timeUntilClamped => Mathf.Max(timeUntil, 0f); public float timeSinceClamped => Mathf.Max(timeSince, 0f); public bool hasPassed => t <= tNow; public bool isInfinity => float.IsInfinity(t); public bool isPositiveInfinity => float.IsPositiveInfinity(t); public bool isNegativeInfinity => float.IsNegativeInfinity(t); public static TimeStamp now => new TimeStamp(tNow); public override int GetHashCode() { return t.GetHashCode(); } public static void Update() { tNow = instance.time; } private TimeStamp(float t) { this.t = t; } public bool Equals(TimeStamp other) { return t.Equals(other.t); } public override bool Equals(object obj) { if (obj is TimeStamp) { return Equals((TimeStamp)obj); } return false; } public int CompareTo(TimeStamp other) { return t.CompareTo(other.t); } public static TimeStamp operator +(TimeStamp a, float b) { return new TimeStamp(a.t + b); } public static TimeStamp operator -(TimeStamp a, float b) { return new TimeStamp(a.t - b); } public static float operator -(TimeStamp a, TimeStamp b) { return a.t - b.t; } public static bool operator <(TimeStamp a, TimeStamp b) { return a.t < b.t; } public static bool operator >(TimeStamp a, TimeStamp b) { return a.t > b.t; } public static bool operator <=(TimeStamp a, TimeStamp b) { return a.t <= b.t; } public static bool operator >=(TimeStamp a, TimeStamp b) { return a.t >= b.t; } public static bool operator ==(TimeStamp a, TimeStamp b) { return a.Equals(b); } public static bool operator !=(TimeStamp a, TimeStamp b) { return !a.Equals(b); } public static float operator -(TimeStamp a, FixedTimeStamp b) { return a.t - b.t; } public static TimeStamp Deserialize(NetworkReader reader) { return new TimeStamp(reader.ReadSingle()); } public static void Serialize(NetworkWriter writer, TimeStamp timeStamp) { writer.Write(timeStamp.t); } public static void ToXml(XElement element, TimeStamp src) { element.Value = TextSerialization.ToStringInvariant(src.t); } public static bool FromXml(XElement element, ref TimeStamp dest) { if (TextSerialization.TryParseInvariant(element.Value, out float result)) { dest = new TimeStamp(result); return true; } return false; } static TimeStamp() { zero = new TimeStamp(0f); positiveInfinity = new TimeStamp(float.PositiveInfinity); negativeInfinity = new TimeStamp(float.NegativeInfinity); HGXml.Register(ToXml, FromXml); } } [Serializable] public struct FixedTimeStamp : IEquatable, IComparable { public readonly float t; private static float tNow; public static readonly FixedTimeStamp zero; public static readonly FixedTimeStamp positiveInfinity; public static readonly FixedTimeStamp negativeInfinity; public float timeUntil => t - tNow; public float timeSince => tNow - t; public float timeUntilClamped => Mathf.Max(timeUntil, 0f); public float timeSinceClamped => Mathf.Max(timeSince, 0f); public bool hasPassed => t <= tNow; public bool isInfinity => float.IsInfinity(t); public bool isPositiveInfinity => float.IsPositiveInfinity(t); public bool isNegativeInfinity => float.IsNegativeInfinity(t); public static FixedTimeStamp now => new FixedTimeStamp(tNow); public override int GetHashCode() { return t.GetHashCode(); } public static void Update() { tNow = instance.fixedTime; } private FixedTimeStamp(float t) { this.t = t; } public bool Equals(FixedTimeStamp other) { return t.Equals(other.t); } public override bool Equals(object obj) { if (obj is FixedTimeStamp) { return Equals((FixedTimeStamp)obj); } return false; } public int CompareTo(FixedTimeStamp other) { return t.CompareTo(other.t); } public static FixedTimeStamp operator +(FixedTimeStamp a, float b) { return new FixedTimeStamp(a.t + b); } public static FixedTimeStamp operator -(FixedTimeStamp a, float b) { return new FixedTimeStamp(a.t - b); } public static float operator -(FixedTimeStamp a, FixedTimeStamp b) { return a.t - b.t; } public static bool operator <(FixedTimeStamp a, FixedTimeStamp b) { return a.t < b.t; } public static bool operator >(FixedTimeStamp a, FixedTimeStamp b) { return a.t > b.t; } public static bool operator <=(FixedTimeStamp a, FixedTimeStamp b) { return a.t <= b.t; } public static bool operator >=(FixedTimeStamp a, FixedTimeStamp b) { return a.t >= b.t; } public static bool operator ==(FixedTimeStamp a, FixedTimeStamp b) { return a.Equals(b); } public static bool operator !=(FixedTimeStamp a, FixedTimeStamp b) { return !a.Equals(b); } public static FixedTimeStamp Deserialize(NetworkReader reader) { return new FixedTimeStamp(reader.ReadSingle()); } public static void Serialize(NetworkWriter writer, FixedTimeStamp timeStamp) { writer.Write(timeStamp.t); } public static void ToXml(XElement element, FixedTimeStamp src) { element.Value = TextSerialization.ToStringInvariant(src.t); } public static bool FromXml(XElement element, ref FixedTimeStamp dest) { if (TextSerialization.TryParseInvariant(element.Value, out float result)) { dest = new FixedTimeStamp(result); return true; } return false; } static FixedTimeStamp() { zero = new FixedTimeStamp(0f); positiveInfinity = new FixedTimeStamp(float.PositiveInfinity); negativeInfinity = new FixedTimeStamp(float.NegativeInfinity); HGXml.Register(ToXml, FromXml); } } private NetworkRuleBook networkRuleBookComponent; [Tooltip("This is assigned to the prefab automatically by GameModeCatalog at runtime. Do not set this value manually.")] [HideInInspector] public GameModeIndex gameModeIndex = GameModeIndex.Invalid; public string nameToken = ""; [Tooltip("Whether or not the user can select this game mode for play in the game mode selector UI.")] public bool userPickable = true; [Tooltip("Dictates items given when rebirth is active when the user doesn't have a stored item.")] public PickupDropTable rebirthDropTable; public static int stagesPerLoop = 5; public static float baseGravity = -30f; [SyncVar] private NetworkGuid _uniqueId; [SyncVar] private NetworkDateTime startTimeUtc; [ShowFieldObsolete] [Obsolete("Use startingSceneGroup instead.")] [Tooltip("The pool of scenes to select the first scene of the run from.")] public SceneDef[] startingScenes = Array.Empty(); [Tooltip("The pool of scenes to select the first scene of the run from.")] public SceneCollection startingSceneGroup; public ItemMask availableItems; public ItemMask expansionLockedItems; public EquipmentMask availableEquipment; public EquipmentMask expansionLockedEquipment; public bool isRunWeekly; [SyncVar] public float fixedTime; public float time; [HideInInspector] public bool isRunning; [SyncVar] private RunStopwatch runStopwatch; [SyncVar] public int stageClearCount; public SceneDef nextStageScene; public SceneDef[] blacklistedScenesForFirstScene = Array.Empty(); public GameObject gameOverPrefab; public GameObject lobbyBackgroundPrefab; public GameObject uiPrefab; private ulong _seed; public Xoroshiro128Plus runRNG; public Xoroshiro128Plus nextStageRng; public Xoroshiro128Plus stageRngGenerator; public Xoroshiro128Plus stageRng; public Xoroshiro128Plus bossRewardRng; public Xoroshiro128Plus treasureRng; public Xoroshiro128Plus spawnRng; public Xoroshiro128Plus randomSurvivorOnRespawnRng; public float difficultyCoefficient = 1f; public float compensatedDifficultyCoefficient = 1f; public float oneOverCompensatedDifficultyCoefficientSquared = 1f; [SyncVar] private int selectedDifficultyInternal = 1; public int shopPortalCount; private static int ambientLevelCap = 99; private bool lowerPricedChestsTimerOn; private float lowerPricedChestsTimer; private float lowerPricedChestsDuration = 10f; private static readonly StringConVar cvRunSceneOverride = new StringConVar("run_scene_override", ConVarFlags.Cheat, "", "Overrides the first scene to enter in a run."); private readonly HashSet unlockablesUnlockedByAnyUser = new HashSet(); private readonly HashSet unlockablesUnlockedByAllUsers = new HashSet(); private readonly HashSet unlockablesAlreadyFullyObtained = new HashSet(); private bool shutdown; private Dictionary userMasters = new Dictionary(); private bool allowNewParticipants; public readonly List availableTier1DropList = new List(); public readonly List availableTier2DropList = new List(); public readonly List availableTier3DropList = new List(); public readonly List availableEquipmentDropList = new List(); public readonly List availableLunarEquipmentDropList = new List(); public readonly List availableLunarItemDropList = new List(); public readonly List availableLunarCombinedDropList = new List(); public readonly List availableBossDropList = new List(); public readonly List availableVoidTier1DropList = new List(); public readonly List availableVoidTier2DropList = new List(); public readonly List availableVoidTier3DropList = new List(); public readonly List availableVoidBossDropList = new List(); public WeightedSelection> smallChestDropTierSelector = new WeightedSelection>(); public WeightedSelection> mediumChestDropTierSelector = new WeightedSelection>(); public WeightedSelection> largeChestDropTierSelector = new WeightedSelection>(); private readonly HashSet eventFlags = new HashSet(); public static Run instance { get; private set; } public RuleBook ruleBook => networkRuleBookComponent.ruleBook; public bool isRunStopwatchPaused => runStopwatch.isPaused; public virtual int loopClearCount => stageClearCount / stagesPerLoop; public virtual bool spawnWithPod => instance.stageClearCount == 0; public virtual bool autoGenerateSpawnPoints => true; public virtual bool canFamilyEventTrigger => true; public IList uiInstances { get; protected set; } = new List(); public ulong seed { get { return _seed; } set { _seed = value; OnSeedSet(); } } public DifficultyIndex selectedDifficulty { get { return (DifficultyIndex)selectedDifficultyInternal; } set { NetworkselectedDifficultyInternal = (int)value; } } public int livingPlayerCount => PlayerCharacterMasterController.GetPlayersWithBodiesCount(); public int participatingPlayerCount => PlayerCharacterMasterController.instances.Count; public float ambientLevel { get; protected set; } public int ambientLevelFloor { get; protected set; } public float teamlessDamageCoefficient => difficultyCoefficient; public bool isGameOverServer { get; private set; } public NetworkGuid Network_uniqueId { get { return _uniqueId; } [param: In] set { SetSyncVar(value, ref _uniqueId, 1u); } } public NetworkDateTime NetworkstartTimeUtc { get { return startTimeUtc; } [param: In] set { SetSyncVar(value, ref startTimeUtc, 2u); } } public float NetworkfixedTime { get { return fixedTime; } [param: In] set { SetSyncVar(value, ref fixedTime, 4u); } } public RunStopwatch NetworkrunStopwatch { get { return runStopwatch; } [param: In] set { SetSyncVar(value, ref runStopwatch, 8u); } } public int NetworkstageClearCount { get { return stageClearCount; } [param: In] set { SetSyncVar(value, ref stageClearCount, 16u); } } public int NetworkselectedDifficultyInternal { get { return selectedDifficultyInternal; } [param: In] set { SetSyncVar(value, ref selectedDifficultyInternal, 32u); } } public static event Action onServerRunSetRuleBookGlobal; public static event Action onRunSetRuleBookGlobal; public static event Action onRunAmbientLevelUp; public static event Action onPlayerFirstCreatedServer; public static event Action onServerGameOver; public static event Action onClientGameOverGlobal; public static event Action onRunStartGlobal; public static event Action onRunDestroyGlobal; public static event Action onAvailablePickupsModified; protected virtual void OnEnable() { instance = SingletonHelper.Assign(instance, this); } protected virtual void OnDisable() { instance = SingletonHelper.Unassign(instance, this); if (instance == null) { RewiredIntegrationManager.RefreshAfterRunFinish(); } } protected void Awake() { networkRuleBookComponent = GetComponent(); networkRuleBookComponent.onRuleBookUpdated += OnRuleBookUpdated; availableItems = ItemMask.Rent(); expansionLockedItems = ItemMask.Rent(); availableEquipment = EquipmentMask.Rent(); expansionLockedEquipment = EquipmentMask.Rent(); if (NetworkServer.active) { Network_uniqueId = (NetworkGuid)Guid.NewGuid(); NetworkstartTimeUtc = (NetworkDateTime)DateTime.UtcNow; } } [Server] public void SetRuleBook(RuleBook newRuleBook) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetRuleBook(RoR2.RuleBook)' called on client"); } else { networkRuleBookComponent.SetRuleBook(newRuleBook); } } private void OnRuleBookUpdated(NetworkRuleBook networkRuleBookComponent) { RuleBook ruleBook = networkRuleBookComponent.ruleBook; selectedDifficulty = ruleBook.FindDifficulty(); ruleBook.GenerateItemMask(availableItems); ruleBook.GenerateEquipmentMask(availableEquipment); expansionLockedItems.Clear(); foreach (ItemDef allItemDef in ItemCatalog.allItemDefs) { if ((bool)allItemDef && (bool)allItemDef.requiredExpansion && !IsExpansionEnabled(allItemDef.requiredExpansion)) { expansionLockedItems.Add(allItemDef.itemIndex); } } expansionLockedEquipment.Clear(); foreach (EquipmentIndex item in EquipmentCatalog.allEquipment) { EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(item); if ((bool)equipmentDef && (bool)equipmentDef.requiredExpansion && !IsExpansionEnabled(equipmentDef.requiredExpansion)) { expansionLockedEquipment.Add(equipmentDef.equipmentIndex); } } if (NetworkServer.active) { Run.onServerRunSetRuleBookGlobal?.Invoke(this, ruleBook); } Run.onRunSetRuleBookGlobal?.Invoke(this, ruleBook); } public Guid GetUniqueId() { return (Guid)_uniqueId; } public DateTime GetStartTimeUtc() { return (DateTime)startTimeUtc; } [Server] private void SetRunStopwatchPaused(bool isPaused) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetRunStopwatchPaused(System.Boolean)' called on client"); } else if (isPaused != runStopwatch.isPaused) { RunStopwatch networkrunStopwatch = runStopwatch; networkrunStopwatch.isPaused = isPaused; float num = GetRunStopwatch(); if (isPaused) { networkrunStopwatch.offsetFromFixedTime = num; } else { networkrunStopwatch.offsetFromFixedTime = num - fixedTime; } NetworkrunStopwatch = networkrunStopwatch; } } public float GetRunStopwatch() { if (runStopwatch.isPaused) { return runStopwatch.offsetFromFixedTime; } return fixedTime + runStopwatch.offsetFromFixedTime; } [Server] public void SetRunStopwatch(float t) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetRunStopwatch(System.Single)' called on client"); return; } RunStopwatch networkrunStopwatch = runStopwatch; if (networkrunStopwatch.isPaused) { networkrunStopwatch.offsetFromFixedTime = t; } else { networkrunStopwatch.offsetFromFixedTime = t - fixedTime; } NetworkrunStopwatch = networkrunStopwatch; } public virtual GameObject InstantiateUi(Transform uiRoot) { GameObject gameObject = null; if ((bool)uiRoot && (bool)uiPrefab) { gameObject = UnityEngine.Object.Instantiate(uiPrefab, uiRoot); uiInstances.Add(gameObject); } return gameObject; } public void UnregisterUi(GameObject uiInstance) { uiInstances.Remove(uiInstance); } private void GenerateStageRNG() { stageRng = new Xoroshiro128Plus(stageRngGenerator.nextUlong); bossRewardRng = new Xoroshiro128Plus(stageRng.nextUlong); treasureRng = new Xoroshiro128Plus(stageRng.nextUlong); spawnRng = new Xoroshiro128Plus(stageRng.nextUlong); randomSurvivorOnRespawnRng = new Xoroshiro128Plus(stageRng.nextUlong); } protected void OnAmbientLevelUp() { Run.onRunAmbientLevelUp?.Invoke(this); } protected virtual void FixedUpdate() { NetworkfixedTime = fixedTime + Time.fixedDeltaTime; FixedTimeStamp.Update(); if (NetworkServer.active) { SetRunStopwatchPaused(!ShouldUpdateRunStopwatch()); } OnFixedUpdate(); } public void RecalculateDifficultyCoefficent() { RecalculateDifficultyCoefficentInternal(); } protected virtual void RecalculateDifficultyCoefficentInternal() { float num = GetRunStopwatch(); DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(selectedDifficulty); float num2 = Mathf.Floor(num * (1f / 60f)); float num3 = (float)participatingPlayerCount * 0.3f; float num4 = 0.7f + num3; float num5 = 0.7f + num3; float num6 = Mathf.Pow(participatingPlayerCount, 0.2f); float num7 = 0.0506f * difficultyDef.scalingValue * num6; float num8 = 0.0506f * difficultyDef.scalingValue * num6; float num9 = Mathf.Pow(1.15f, stageClearCount); compensatedDifficultyCoefficient = (num5 + num8 * num2) * num9; difficultyCoefficient = (num4 + num7 * num2) * num9; oneOverCompensatedDifficultyCoefficientSquared = 1f / (compensatedDifficultyCoefficient * compensatedDifficultyCoefficient); float num10 = (num4 + num7 * (num * (1f / 60f))) * Mathf.Pow(1.15f, stageClearCount); ambientLevel = Mathf.Min((num10 - num4) / 0.33f + 1f, ambientLevelCap); int num11 = ambientLevelFloor; ambientLevelFloor = Mathf.FloorToInt(ambientLevel); if (num11 != ambientLevelFloor && num11 != 0 && ambientLevelFloor > num11) { OnAmbientLevelUp(); } } private void InitializeTimeStamps() { NetworkfixedTime = 0f; time = 0f; FixedTimeStamp.Update(); TimeStamp.Update(); } protected virtual void OnFixedUpdate() { RecalculateDifficultyCoefficent(); } public bool GetLowerPricedChestsTimer() { return lowerPricedChestsTimerOn; } protected void Update() { time = Mathf.Clamp(time + Time.deltaTime, fixedTime, fixedTime + Time.fixedDeltaTime); TimeStamp.Update(); if ((double)GetRunStopwatch() - Math.Floor(GetRunStopwatch() * (1f / 60f)) * 60.0 <= 0.1 && !lowerPricedChestsTimerOn) { lowerPricedChestsTimerOn = true; } if (lowerPricedChestsTimerOn) { lowerPricedChestsTimer += Time.fixedDeltaTime; } if (lowerPricedChestsTimer >= lowerPricedChestsDuration) { lowerPricedChestsTimerOn = false; lowerPricedChestsTimer = 0f; } } protected virtual bool ShouldUpdateRunStopwatch() { SceneDef mostRecentSceneDef = SceneCatalog.mostRecentSceneDef; if (mostRecentSceneDef.sceneType != SceneType.Stage && mostRecentSceneDef.sceneType != SceneType.TimedIntermission) { return false; } return livingPlayerCount > 0; } [Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)] [Server] public bool CanUnlockableBeGrantedThisRun(string unlockableName) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::CanUnlockableBeGrantedThisRun(System.String)' called on client"); return false; } return CanUnlockableBeGrantedThisRun(UnlockableCatalog.GetUnlockableDef(unlockableName)); } [Server] public virtual bool CanUnlockableBeGrantedThisRun(UnlockableDef unlockableDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::CanUnlockableBeGrantedThisRun(RoR2.UnlockableDef)' called on client"); return false; } return !unlockablesAlreadyFullyObtained.Contains(unlockableDef); } [Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)] [Server] public void GrantUnlockToAllParticipatingPlayers(string unlockableName) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::GrantUnlockToAllParticipatingPlayers(System.String)' called on client"); } else { GrantUnlockToAllParticipatingPlayers(UnlockableCatalog.GetUnlockableDef(unlockableName)); } } [Server] public void GrantUnlockToAllParticipatingPlayers(UnlockableDef unlockableDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::GrantUnlockToAllParticipatingPlayers(RoR2.UnlockableDef)' called on client"); } else { if (!unlockableDef || unlockableDef.index == UnlockableIndex.None || unlockablesAlreadyFullyObtained.Contains(unlockableDef)) { return; } unlockablesAlreadyFullyObtained.Add(unlockableDef); foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { if (readOnlyInstances.isParticipating) { readOnlyInstances.ServerHandleUnlock(unlockableDef); } } } } [Server] [Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)] public void GrantUnlockToSinglePlayer(string unlockableName, CharacterBody body) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::GrantUnlockToSinglePlayer(System.String,RoR2.CharacterBody)' called on client"); } else { GrantUnlockToSinglePlayer(UnlockableCatalog.GetUnlockableDef(unlockableName), body); } } [Server] public void GrantUnlockToSinglePlayer(UnlockableDef unlockableDef, CharacterBody body) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::GrantUnlockToSinglePlayer(RoR2.UnlockableDef,RoR2.CharacterBody)' called on client"); } else if ((bool)unlockableDef && unlockableDef.index != UnlockableIndex.None && (bool)body) { NetworkUser networkUser = Util.LookUpBodyNetworkUser(body); if ((bool)networkUser) { networkUser.ServerHandleUnlock(unlockableDef); } } } [Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)] [Server] public bool IsUnlockableUnlocked(string unlockableName) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::IsUnlockableUnlocked(System.String)' called on client"); return false; } return IsUnlockableUnlocked(UnlockableCatalog.GetUnlockableDef(unlockableName)); } [Server] public virtual bool IsUnlockableUnlocked(UnlockableDef unlockableDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::IsUnlockableUnlocked(RoR2.UnlockableDef)' called on client"); return false; } return unlockablesUnlockedByAnyUser.Contains(unlockableDef); } [Server] [Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)] public bool DoesEveryoneHaveThisUnlockableUnlocked(string unlockableName) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::DoesEveryoneHaveThisUnlockableUnlocked(System.String)' called on client"); return false; } return DoesEveryoneHaveThisUnlockableUnlocked(UnlockableCatalog.GetUnlockableDef(unlockableName)); } [Server] public virtual bool DoesEveryoneHaveThisUnlockableUnlocked(UnlockableDef unlockableDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::DoesEveryoneHaveThisUnlockableUnlocked(RoR2.UnlockableDef)' called on client"); return false; } return unlockablesUnlockedByAllUsers.Contains(unlockableDef); } [Server] [Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)] public void ForceUnlockImmediate(string unlockableName) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::ForceUnlockImmediate(System.String)' called on client"); } else { ForceUnlockImmediate(UnlockableCatalog.GetUnlockableDef(unlockableName)); } } [Server] public void ForceUnlockImmediate(UnlockableDef unlockableDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::ForceUnlockImmediate(RoR2.UnlockableDef)' called on client"); } else { unlockablesUnlockedByAnyUser.Add(unlockableDef); } } public void PickNextStageSceneFromCurrentSceneDestinations() { WeightedSelection weightedSelection = new WeightedSelection(); SceneCatalog.mostRecentSceneDef.AddDestinationsToWeightedSelection(weightedSelection, CanPickStage); PickNextStageScene(weightedSelection); } public bool CanPickStage(SceneDef sceneDef) { if ((bool)sceneDef.requiredExpansion) { return IsExpansionEnabled(sceneDef.requiredExpansion); } return true; } public void PickNextStageScene(WeightedSelection choices) { if (choices.Count != 0) { if (ruleBook.stageOrder == StageOrder.Normal) { nextStageScene = choices.Evaluate(nextStageRng.nextNormalizedFloat); return; } SceneDef[] array = SceneCatalog.allStageSceneDefs.Where(IsValidNextStage).ToArray(); nextStageScene = nextStageRng.NextElementUniform(array); } bool IsValidNextStage(SceneDef sceneDef) { if (nextStageScene != null && nextStageScene.baseSceneName == sceneDef.baseSceneName) { return false; } if (!sceneDef.hasAnyDestinations) { return false; } if (stageClearCount == 0 && blacklistedScenesForFirstScene.Contains(sceneDef)) { return false; } return sceneDef.validForRandomSelection; } } public virtual ulong GenerateSeedForNewRun() { return RoR2Application.rng.nextUlong; } [Server] public void RefreshUnlockAvailability() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::RefreshUnlockAvailability()' called on client"); } else { BuildUnlockAvailability(); } } protected virtual void BuildUnlockAvailability() { unlockablesUnlockedByAnyUser.Clear(); unlockablesUnlockedByAllUsers.Clear(); unlockablesAlreadyFullyObtained.Clear(); int num = 0; Dictionary dictionary = new Dictionary(); foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { if (!readOnlyInstances.isParticipating) { continue; } num++; foreach (UnlockableDef unlockable in readOnlyInstances.unlockables) { unlockablesUnlockedByAnyUser.Add(unlockable); if (!dictionary.ContainsKey(unlockable)) { dictionary.Add(unlockable, 0); } UnlockableDef key = unlockable; int value = dictionary[key] + 1; dictionary[key] = value; } } if (num <= 0) { return; } foreach (KeyValuePair item in dictionary) { if (item.Value == num) { unlockablesUnlockedByAllUsers.Add(item.Key); unlockablesAlreadyFullyObtained.Add(item.Key); } } } protected virtual void Start() { InitializeTimeStamps(); OnRuleBookUpdated(networkRuleBookComponent); if (NetworkServer.active) { runRNG = new Xoroshiro128Plus(seed); nextStageRng = new Xoroshiro128Plus(runRNG.nextUlong); stageRngGenerator = new Xoroshiro128Plus(runRNG.nextUlong); GenerateStageRNG(); } allowNewParticipants = true; UnityEngine.Object.DontDestroyOnLoad(base.gameObject); ReadOnlyCollection readOnlyInstancesList = NetworkUser.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { OnUserAdded(readOnlyInstancesList[i]); } allowNewParticipants = false; if (NetworkServer.active) { WeightedSelection weightedSelection = new WeightedSelection(); string @string = cvRunSceneOverride.GetString(); if (@string != "") { weightedSelection.AddChoice(SceneCatalog.GetSceneDefFromSceneName(@string), 1f); } else if ((bool)startingSceneGroup) { startingSceneGroup.AddToWeightedSelection(weightedSelection, CanPickStage); } else { for (int j = 0; j < startingScenes.Length; j++) { if (CanPickStage(startingScenes[j])) { weightedSelection.AddChoice(startingScenes[j], 1f); } } } PickNextStageScene(weightedSelection); if (!nextStageScene) { UnityEngine.Debug.LogError("Cannot set next scene. nextStageScene is null!"); } NetworkManager.singleton.ServerChangeScene(nextStageScene.cachedName); } BuildUnlockAvailability(); BuildDropTable(); isRunning = true; Run.onRunStartGlobal?.Invoke(this); if (NetworkServer.active && RunArtifactManager.instance.IsArtifactEnabled(DLC2Content.Artifacts.Rebirth)) { ServerGiveRebirthItems(); } if (!NetworkClient.active || !RunArtifactManager.instance.IsArtifactEnabled(DLC2Content.Artifacts.Rebirth)) { return; } foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { if (readOnlyInstances.isLocalPlayer) { readOnlyInstances.localUser.userProfile.RebirthItem = null; break; } } } protected virtual void OnDestroy() { Run.onRunDestroyGlobal?.Invoke(this); if ((bool)GameOverController.instance) { UnityEngine.Object.Destroy(GameOverController.instance.gameObject); } ReadOnlyCollection readOnlyInstancesList = CharacterBody.readOnlyInstancesList; for (int num = readOnlyInstancesList.Count - 1; num >= 0; num--) { if ((bool)readOnlyInstancesList[num]) { UnityEngine.Object.Destroy(readOnlyInstancesList[num].gameObject); } } ReadOnlyCollection readOnlyInstancesList2 = CharacterMaster.readOnlyInstancesList; for (int num2 = readOnlyInstancesList2.Count - 1; num2 >= 0; num2--) { if ((bool)readOnlyInstancesList2[num2]) { UnityEngine.Object.Destroy(readOnlyInstancesList2[num2].gameObject); } } if ((bool)Stage.instance) { UnityEngine.Object.Destroy(Stage.instance.gameObject); } Chat.Clear(); if (!shutdown && PlatformSystems.networkManager.isNetworkActive) { HandlePostRunDestination(); } ItemMask.Return(availableItems); ItemMask.Return(expansionLockedItems); EquipmentMask.Return(availableEquipment); EquipmentMask.Return(expansionLockedEquipment); PlatformSystems.saveSystem.SaveLoggedInUserProfiles(); } [Server] private void ServerGiveRebirthItems() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::ServerGiveRebirthItems()' called on client"); } else { if (!NetworkServer.active) { return; } ItemIndex itemIndex = ItemIndex.None; foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { Inventory inventory = instance.master.inventory; NetworkUser networkUser = instance.networkUser; if (networkUser.rebirthItem != ItemIndex.None) { if ((bool)inventory) { itemIndex = networkUser.rebirthItem; networkUser.NetworkrebirthItem = ItemIndex.None; } } else if (rebirthDropTable != null) { Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); itemIndex = PickupCatalog.GetPickupDef(rebirthDropTable.GenerateDrop(rng)).itemIndex; } if ((bool)inventory) { inventory.GiveItem(itemIndex); } } } } protected virtual void HandlePostRunDestination() { if (NetworkServer.active) { NetworkManager.singleton.ServerChangeScene("lobby"); } } protected void OnApplicationQuit() { shutdown = true; } [Server] public CharacterMaster GetUserMaster(NetworkUserId networkUserId) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterMaster RoR2.Run::GetUserMaster(RoR2.NetworkUserId)' called on client"); return null; } userMasters.TryGetValue(networkUserId, out var value); return value; } [Server] public void OnServerSceneChanged(string sceneName) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::OnServerSceneChanged(System.String)' called on client"); return; } BeginStage(); isGameOverServer = false; } [Server] private void BeginStage() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::BeginStage()' called on client"); } else { NetworkServer.Spawn(UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/Stage"))); } } [Server] private void EndStage() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::EndStage()' called on client"); } else if ((bool)Stage.instance) { UnityEngine.Object.Destroy(Stage.instance); } } public void OnUserAdded(NetworkUser user) { if (NetworkServer.active) { SetupUserCharacterMaster(user); } } public void OnUserRemoved(NetworkUser user) { } public virtual bool ShouldAllowNewParticipant(NetworkUser user) { if (!allowNewParticipants) { return (bool)ruleBook.GetRuleChoice(RuleCatalog.FindRuleDef("Misc.AllowDropIn"))?.extraData; } return true; } [Server] private void SetupUserCharacterMaster(NetworkUser user) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetupUserCharacterMaster(RoR2.NetworkUser)' called on client"); } else if (!user) { UnityEngine.Debug.LogError("SetupUserCharacterMaster user is null"); } else { if ((bool)user.masterObject) { return; } CharacterMaster characterMaster = GetUserMaster(user.id); bool flag = !characterMaster && ShouldAllowNewParticipant(user); if (flag) { characterMaster = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/CharacterMasters/CommandoMaster"), UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity).GetComponent(); if ((bool)characterMaster) { userMasters[user.id] = characterMaster; if (ruleBook != null) { characterMaster.GiveMoney(ruleBook.startingMoney); } else { UnityEngine.Debug.LogError("Can't give new master money because there's no rulebook"); } DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(selectedDifficulty); if ((bool)characterMaster.inventory) { if (selectedDifficulty == DifficultyIndex.Easy) { characterMaster.inventory.GiveItem(RoR2Content.Items.DrizzlePlayerHelper); } else if (difficultyDef.countsAsHardMode) { characterMaster.inventory.GiveItem(RoR2Content.Items.MonsoonPlayerHelper); } } else { UnityEngine.Debug.LogError("Instantiated master has no inventory"); } NetworkServer.Spawn(characterMaster.gameObject); } else { UnityEngine.Debug.LogError("Instantiated master object has no CharacterMaster"); } } if ((bool)characterMaster) { PlayerCharacterMasterController component = characterMaster.GetComponent(); if ((bool)component) { component.LinkToNetworkUserServer(user); } else { UnityEngine.Debug.LogError("CharacterMaster has no PlayerCharacterMasterController"); } if (flag) { Run.onPlayerFirstCreatedServer?.Invoke(this, component); } } } } [Server] public virtual void HandlePlayerFirstEntryAnimation(CharacterBody body, UnityEngine.Vector3 spawnPosition, UnityEngine.Quaternion spawnRotation) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::HandlePlayerFirstEntryAnimation(RoR2.CharacterBody,UnityEngine.Vector3,UnityEngine.Quaternion)' called on client"); } else if ((bool)body) { if ((bool)body.preferredPodPrefab) { GameObject gameObject = UnityEngine.Object.Instantiate(body.preferredPodPrefab, body.transform.position, spawnRotation); VehicleSeat component = gameObject.GetComponent(); if ((bool)component) { component.AssignPassenger(body.gameObject); } else { UnityEngine.Debug.LogError("Body " + body.name + " has preferred pod " + body.preferredPodPrefab.name + ", but that object has no VehicleSeat."); } NetworkServer.Spawn(gameObject); } else { body.SetBodyStateToPreferredInitialState(); } } else { UnityEngine.Debug.LogError("Can't handle player first entry animation for null body."); } } public virtual void OnServerBossAdded(BossGroup bossGroup, CharacterMaster characterMaster) { } public virtual void OnServerBossDefeated(BossGroup bossGroup) { } public virtual void OnServerCharacterBodySpawned(CharacterBody characterBody) { } public virtual void OnServerTeleporterPlaced(SceneDirector sceneDirector, GameObject teleporter) { } public virtual void OnPlayerSpawnPointsPlaced(SceneDirector sceneDirector) { } public virtual GameObject GetTeleportEffectPrefab(GameObject objectToTeleport) { return LegacyResourcesAPI.Load("Prefabs/Effects/TeleportOutBoom"); } public int GetDifficultyScaledCost(int baseCost, float difficultyCoefficient) { return (int)((float)baseCost * Mathf.Pow(difficultyCoefficient, 1.25f)); } public int GetDifficultyScaledCost(int baseCost) { return GetDifficultyScaledCost(baseCost, instance.difficultyCoefficient); } public void BuildDropTable() { availableTier1DropList.Clear(); availableTier2DropList.Clear(); availableTier3DropList.Clear(); availableLunarItemDropList.Clear(); availableEquipmentDropList.Clear(); availableBossDropList.Clear(); availableLunarEquipmentDropList.Clear(); availableVoidTier1DropList.Clear(); availableVoidTier2DropList.Clear(); availableVoidTier3DropList.Clear(); availableVoidBossDropList.Clear(); ItemIndex itemIndex = ItemIndex.Count; for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++) { if (availableItems.Contains(itemIndex)) { ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); List list = null; switch (itemDef.tier) { case ItemTier.Tier1: list = availableTier1DropList; break; case ItemTier.Tier2: list = availableTier2DropList; break; case ItemTier.Tier3: list = availableTier3DropList; break; case ItemTier.Lunar: list = availableLunarItemDropList; break; case ItemTier.Boss: list = availableBossDropList; break; case ItemTier.VoidTier1: list = availableVoidTier1DropList; break; case ItemTier.VoidTier2: list = availableVoidTier2DropList; break; case ItemTier.VoidTier3: list = availableVoidTier3DropList; break; case ItemTier.VoidBoss: list = availableVoidBossDropList; break; } if (list != null && itemDef.DoesNotContainTag(ItemTag.WorldUnique)) { list.Add(PickupCatalog.FindPickupIndex(itemIndex)); } } } EquipmentIndex equipmentIndex = (EquipmentIndex)0; for (EquipmentIndex equipmentCount = (EquipmentIndex)EquipmentCatalog.equipmentCount; equipmentIndex < equipmentCount; equipmentIndex++) { if (!availableEquipment.Contains(equipmentIndex)) { continue; } EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); if (equipmentDef.canDrop) { if (!equipmentDef.isLunar) { availableEquipmentDropList.Add(PickupCatalog.FindPickupIndex(equipmentIndex)); } else { availableLunarEquipmentDropList.Add(PickupCatalog.FindPickupIndex(equipmentIndex)); } } } smallChestDropTierSelector.Clear(); smallChestDropTierSelector.AddChoice(availableTier1DropList, 0.8f); smallChestDropTierSelector.AddChoice(availableTier2DropList, 0.2f); smallChestDropTierSelector.AddChoice(availableTier3DropList, 0.01f); mediumChestDropTierSelector.Clear(); mediumChestDropTierSelector.AddChoice(availableTier2DropList, 0.8f); mediumChestDropTierSelector.AddChoice(availableTier3DropList, 0.2f); largeChestDropTierSelector.Clear(); RefreshLunarCombinedDropList(); } public bool IsItemAvailable(ItemIndex itemIndex) { return availableItems.Contains(itemIndex); } public bool IsEquipmentAvailable(EquipmentIndex equipmentIndex) { return availableEquipment.Contains(equipmentIndex); } public bool IsItemExpansionLocked(ItemIndex itemIndex) { return expansionLockedItems.Contains(itemIndex); } public bool IsEquipmentExpansionLocked(EquipmentIndex equipmentIndex) { return expansionLockedEquipment.Contains(equipmentIndex); } public bool IsPickupAvailable(PickupIndex pickupIndex) { PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef.itemIndex != ItemIndex.None) { return IsItemAvailable(pickupDef.itemIndex); } if (pickupDef.equipmentIndex != EquipmentIndex.None) { return IsEquipmentAvailable(pickupDef.equipmentIndex); } return true; } [Server] public void DisablePickupDrop(PickupIndex pickupIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::DisablePickupDrop(RoR2.PickupIndex)' called on client"); return; } PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef.itemIndex != ItemIndex.None) { DisableItemDrop(pickupDef.itemIndex); } if (pickupDef.equipmentIndex != EquipmentIndex.None) { DisableEquipmentDrop(pickupDef.equipmentIndex); } } [Server] public void DisableItemDrop(ItemIndex itemIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::DisableItemDrop(RoR2.ItemIndex)' called on client"); return; } ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); List list = null; bool flag = false; switch (itemDef.tier) { case ItemTier.Tier1: list = availableTier1DropList; break; case ItemTier.Tier2: list = availableTier2DropList; break; case ItemTier.Tier3: list = availableTier3DropList; break; case ItemTier.Lunar: list = availableLunarItemDropList; break; case ItemTier.Boss: list = availableBossDropList; break; case ItemTier.VoidTier1: list = availableVoidTier1DropList; break; case ItemTier.VoidTier2: list = availableVoidTier2DropList; break; case ItemTier.VoidTier3: list = availableVoidTier3DropList; break; case ItemTier.VoidBoss: list = availableVoidBossDropList; break; } PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(itemIndex); if (list != null && pickupIndex != PickupIndex.none) { list.Remove(pickupIndex); if (flag) { RefreshLunarCombinedDropList(); } Run.onAvailablePickupsModified?.Invoke(this); } } [Server] public void DisableEquipmentDrop(EquipmentIndex equipmentIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::DisableEquipmentDrop(RoR2.EquipmentIndex)' called on client"); return; } PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(equipmentIndex); if (!(pickupIndex != PickupIndex.none)) { return; } List list = null; bool flag = false; if (PickupCatalog.GetPickupDef(pickupIndex).isLunar) { flag = true; list = availableLunarEquipmentDropList; } else { list = availableEquipmentDropList; } if (list.Contains(pickupIndex)) { list.Remove(pickupIndex); if (flag) { RefreshLunarCombinedDropList(); } Run.onAvailablePickupsModified?.Invoke(this); } } [Server] public void EnablePickupDrop(PickupIndex pickupIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::EnablePickupDrop(RoR2.PickupIndex)' called on client"); return; } PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef.itemIndex != ItemIndex.None) { EnableItemDrop(pickupDef.itemIndex); } if (pickupDef.equipmentIndex != EquipmentIndex.None) { EnableEquipmentDrop(pickupDef.equipmentIndex); } } [Server] public void EnableItemDrop(ItemIndex itemIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::EnableItemDrop(RoR2.ItemIndex)' called on client"); return; } ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); List list = null; bool flag = false; switch (itemDef.tier) { case ItemTier.Tier1: list = availableTier1DropList; break; case ItemTier.Tier2: list = availableTier2DropList; break; case ItemTier.Tier3: list = availableTier3DropList; break; case ItemTier.Lunar: list = availableLunarItemDropList; break; case ItemTier.Boss: list = availableBossDropList; break; case ItemTier.VoidTier1: list = availableVoidTier1DropList; break; case ItemTier.VoidTier2: list = availableVoidTier2DropList; break; case ItemTier.VoidTier3: list = availableVoidTier3DropList; break; case ItemTier.VoidBoss: list = availableVoidBossDropList; break; } PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(itemIndex); if (list != null && pickupIndex != PickupIndex.none && !list.Contains(pickupIndex)) { list.Add(pickupIndex); if (flag) { RefreshLunarCombinedDropList(); } Run.onAvailablePickupsModified?.Invoke(this); } } [Server] public void EnableEquipmentDrop(EquipmentIndex equipmentIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::EnableEquipmentDrop(RoR2.EquipmentIndex)' called on client"); return; } PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(equipmentIndex); if (!(pickupIndex != PickupIndex.none)) { return; } List list = null; bool flag = false; list = ((!PickupCatalog.GetPickupDef(pickupIndex).isLunar) ? availableEquipmentDropList : availableLunarEquipmentDropList); if (!list.Contains(pickupIndex)) { list.Add(pickupIndex); if (flag) { RefreshLunarCombinedDropList(); } Run.onAvailablePickupsModified?.Invoke(this); } } [Server] private void RefreshLunarCombinedDropList() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::RefreshLunarCombinedDropList()' called on client"); return; } availableLunarCombinedDropList.Clear(); availableLunarCombinedDropList.AddRange(availableLunarEquipmentDropList); availableLunarCombinedDropList.AddRange(availableLunarItemDropList); } [ConCommand(commandName = "run_end", flags = ConVarFlags.SenderMustBeServer, helpText = "Ends the current run.")] private static void CCRunEnd(ConCommandArgs args) { if ((bool)instance) { UnityEngine.Object.Destroy(instance.gameObject); } } [ConCommand(commandName = "run_print_unlockables", flags = ConVarFlags.SenderMustBeServer, helpText = "Prints all unlockables available in this run.")] private static void CCRunPrintUnlockables(ConCommandArgs args) { if (!instance) { throw new ConCommandException("No run is currently in progress."); } List list = new List(); foreach (UnlockableDef item in instance.unlockablesUnlockedByAnyUser) { list.Add(item.cachedName); } } [ConCommand(commandName = "run_print_seed", flags = ConVarFlags.None, helpText = "Prints the seed of the current run.")] private static void CCRunPrintSeed(ConCommandArgs args) { if (!instance) { throw new ConCommandException("No run is currently in progress."); } UnityEngine.Debug.LogFormat("Current run seed: {0}", instance.seed); } [ConCommand(commandName = "run_set_stages_cleared", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "Sets the current number of stages cleared in the run.")] private static void CCRunSetStagesCleared(ConCommandArgs args) { if (!instance) { throw new ConCommandException("No run is currently in progress."); } instance.NetworkstageClearCount = args.GetArgInt(0); } public virtual void AdvanceStage(SceneDef nextScene) { if ((bool)Stage.instance) { Stage.instance.CompleteServer(); SceneType sceneType = SceneCatalog.GetSceneDefForCurrentScene().sceneType; if (sceneType == SceneType.Stage || sceneType == SceneType.UntimedStage) { NetworkstageClearCount = stageClearCount + 1; } } GenerateStageRNG(); RecalculateDifficultyCoefficent(); NetworkManager.singleton.ServerChangeScene(nextScene.cachedName); } public void BeginGameOver([NotNull] GameEndingDef gameEndingDef) { if (isGameOverServer) { return; } if ((bool)Stage.instance && gameEndingDef.isWin) { Stage.instance.CompleteServer(); } isGameOverServer = true; if (gameEndingDef.lunarCoinReward != 0) { for (int i = 0; i < NetworkUser.readOnlyInstancesList.Count; i++) { NetworkUser networkUser = NetworkUser.readOnlyInstancesList[i]; if ((bool)networkUser && networkUser.isParticipating) { networkUser.AwardLunarCoins(gameEndingDef.lunarCoinReward); } } } StatManager.ForceUpdate(); GameObject obj = UnityEngine.Object.Instantiate(gameOverPrefab); GameOverController component = obj.GetComponent(); component.SetRunReport(RunReport.Generate(this, gameEndingDef)); Run.onServerGameOver?.Invoke(this, gameEndingDef); NetworkServer.Spawn(obj); isRunning = false; component.CallRpcClientGameOver(); } public virtual void OnClientGameOver(RunReport runReport) { isRunning = false; Run.onClientGameOverGlobal?.Invoke(this, runReport); } public virtual void OverrideRuleChoices(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong runSeed) { ForceChoice(mustInclude, mustExclude, "Misc.KeepMoneyBetweenStages.Off"); } protected void ForceChoice(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, RuleChoiceDef choiceDef) { foreach (RuleChoiceDef choice in choiceDef.ruleDef.choices) { mustInclude[choice.globalIndex] = false; mustExclude[choice.globalIndex] = true; } mustInclude[choiceDef.globalIndex] = true; mustExclude[choiceDef.globalIndex] = false; } protected void ForceChoice(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, string choiceDefGlobalName) { ForceChoice(mustInclude, mustExclude, RuleCatalog.FindChoiceDef(choiceDefGlobalName)); } public virtual UnityEngine.Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination) { return FindSafeTeleportPosition(characterBody, targetDestination, float.NegativeInfinity, float.NegativeInfinity); } public virtual UnityEngine.Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination, float idealMinDistance, float idealMaxDistance) { UnityEngine.Vector3 vector = (targetDestination ? targetDestination.position : characterBody.transform.position); SpawnCard spawnCard = ScriptableObject.CreateInstance(); spawnCard.hullSize = characterBody.hullClassification; spawnCard.nodeGraphType = MapNodeGroup.GraphType.Ground; spawnCard.prefab = LegacyResourcesAPI.Load("SpawnCards/HelperPrefab"); UnityEngine.Vector3 result = vector; GameObject gameObject = null; if (idealMaxDistance > 0f && idealMinDistance < idealMaxDistance) { gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = idealMinDistance, maxDistance = idealMaxDistance, position = vector }, RoR2Application.rng)); } if (!gameObject) { gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.NearestNode, position = vector }, RoR2Application.rng)); if ((bool)gameObject) { result = gameObject.transform.position; } } if ((bool)gameObject) { UnityEngine.Object.Destroy(gameObject); } UnityEngine.Object.Destroy(spawnCard); return result; } [Server] public void SetEventFlag(string name) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetEventFlag(System.String)' called on client"); } else { eventFlags.Add(name); } } [Server] public bool GetEventFlag(string name) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::GetEventFlag(System.String)' called on client"); return false; } return eventFlags.Contains(name); } [Server] public void ResetEventFlag(string name) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::ResetEventFlag(System.String)' called on client"); } else { eventFlags.Remove(name); } } public virtual bool ShouldAllowNonChampionBossSpawn() { return stageClearCount > 0; } public bool IsExpansionEnabled([NotNull] ExpansionDef expansionDef) { if (expansionDef.enabledChoice != null) { return ruleBook.IsChoiceActive(expansionDef.enabledChoice); } return false; } protected virtual void OnSeedSet() { } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { GeneratedNetworkCode._WriteNetworkGuid_None(writer, _uniqueId); GeneratedNetworkCode._WriteNetworkDateTime_None(writer, startTimeUtc); writer.Write(fixedTime); GeneratedNetworkCode._WriteRunStopwatch_Run(writer, runStopwatch); writer.WritePackedUInt32((uint)stageClearCount); writer.WritePackedUInt32((uint)selectedDifficultyInternal); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WriteNetworkGuid_None(writer, _uniqueId); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WriteNetworkDateTime_None(writer, startTimeUtc); } if ((base.syncVarDirtyBits & 4u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(fixedTime); } if ((base.syncVarDirtyBits & 8u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WriteRunStopwatch_Run(writer, runStopwatch); } if ((base.syncVarDirtyBits & 0x10u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)stageClearCount); } if ((base.syncVarDirtyBits & 0x20u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)selectedDifficultyInternal); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { _uniqueId = GeneratedNetworkCode._ReadNetworkGuid_None(reader); startTimeUtc = GeneratedNetworkCode._ReadNetworkDateTime_None(reader); fixedTime = reader.ReadSingle(); runStopwatch = GeneratedNetworkCode._ReadRunStopwatch_Run(reader); stageClearCount = (int)reader.ReadPackedUInt32(); selectedDifficultyInternal = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { _uniqueId = GeneratedNetworkCode._ReadNetworkGuid_None(reader); } if (((uint)num & 2u) != 0) { startTimeUtc = GeneratedNetworkCode._ReadNetworkDateTime_None(reader); } if (((uint)num & 4u) != 0) { fixedTime = reader.ReadSingle(); } if (((uint)num & 8u) != 0) { runStopwatch = GeneratedNetworkCode._ReadRunStopwatch_Run(reader); } if (((uint)num & 0x10u) != 0) { stageClearCount = (int)reader.ReadPackedUInt32(); } if (((uint)num & 0x20u) != 0) { selectedDifficultyInternal = (int)reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public class WeeklyRun : Run { private Xoroshiro128Plus bossAffixRng; public static readonly DateTime startDate = new DateTime(2018, 8, 27, 0, 0, 0, 0, DateTimeKind.Utc); public const int cycleLength = 3; private string leaderboardName; [SyncVar] private uint serverSeedCycle; private EquipmentIndex[] bossAffixes = Array.Empty(); public SpawnCard crystalSpawnCard; public uint crystalCount = 3u; public uint crystalRewardValue = 50u; public uint crystalsRequiredToKill = 3u; private List crystalActiveList = new List(); public SpawnCard equipmentBarrelSpawnCard; public uint equipmentBarrelCount = 3u; public float equipmentBarrelRadius = 10f; public static DateTime now => Util.UnixTimeStampToDateTimeUtc(Client.Instance.Utils.GetServerRealTime()); public uint crystalsKilled => (uint)(crystalCount - crystalActiveList.Count); public uint NetworkserverSeedCycle { get { return serverSeedCycle; } [param: In] set { SetSyncVar(value, ref serverSeedCycle, 64u); } } public static uint GetCurrentSeedCycle() { return (uint)((now - startDate).Days / 3); } public static DateTime GetSeedCycleStartDateTime(uint seedCycle) { return startDate.AddDays(seedCycle * 3); } public static DateTime GetSeedCycleStartDateTime() { return GetSeedCycleStartDateTime(GetCurrentSeedCycle()); } public static DateTime GetSeedCycleEndDateTime() { return GetSeedCycleStartDateTime(GetCurrentSeedCycle() + 1); } protected new void Start() { base.Start(); if (NetworkServer.active) { bossAffixRng = new Xoroshiro128Plus(runRNG.nextUlong); NetworkserverSeedCycle = GetCurrentSeedCycle(); } isRunWeekly = true; bossAffixes = new EquipmentIndex[2] { RoR2Content.Equipment.AffixRed.equipmentIndex, RoR2Content.Equipment.AffixBlue.equipmentIndex }; } protected override void OnFixedUpdate() { base.OnFixedUpdate(); if (!TeleporterInteraction.instance) { return; } bool flag = crystalsRequiredToKill > crystalsKilled; if (flag == TeleporterInteraction.instance.locked) { return; } if (flag) { if (NetworkServer.active) { TeleporterInteraction.instance.locked = true; } return; } if (NetworkServer.active) { TeleporterInteraction.instance.locked = false; } ChildLocator component = TeleporterInteraction.instance.GetComponent().modelTransform.GetComponent(); if ((bool)component) { Transform transform = component.FindChild("TimeCrystalBeaconBlocker"); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/TimeCrystalDeath"), new EffectData { origin = transform.transform.position }, transmit: false); transform.gameObject.SetActive(value: false); } } public override ulong GenerateSeedForNewRun() { return (ulong)GetCurrentSeedCycle() << 32; } public override void HandlePlayerFirstEntryAnimation(CharacterBody body, UnityEngine.Vector3 spawnPosition, UnityEngine.Quaternion spawnRotation) { } public override void AdvanceStage(SceneDef nextScene) { if (stageClearCount == 1 && SceneInfo.instance.countsAsStage) { BeginGameOver(RoR2Content.GameEndings.PrismaticTrialEnding); } else { base.AdvanceStage(nextScene); } } public override void OnClientGameOver(RunReport runReport) { base.OnClientGameOver(runReport); ClientSubmitLeaderboardScore(runReport); } public override void OnServerBossAdded(BossGroup bossGroup, CharacterMaster characterMaster) { base.OnServerBossAdded(bossGroup, characterMaster); if (stageClearCount >= 1) { if (characterMaster.inventory.GetEquipmentIndex() == EquipmentIndex.None) { characterMaster.inventory.SetEquipmentIndex(bossAffixRng.NextElementUniform(bossAffixes)); } characterMaster.inventory.GiveItem(RoR2Content.Items.BoostHp, 5); characterMaster.inventory.GiveItem(RoR2Content.Items.BoostDamage); } } public override void OnServerBossDefeated(BossGroup bossGroup) { base.OnServerBossDefeated(bossGroup); if ((bool)TeleporterInteraction.instance) { TeleporterInteraction.instance.holdoutZoneController.FullyChargeHoldoutZone(); } } public override GameObject GetTeleportEffectPrefab(GameObject objectToTeleport) { return LegacyResourcesAPI.Load("Prefabs/Effects/TeleportOutCrystalBoom"); } public override void OnServerTeleporterPlaced(SceneDirector sceneDirector, GameObject teleporter) { base.OnServerTeleporterPlaced(sceneDirector, teleporter); DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule(); directorPlacementRule.placementMode = DirectorPlacementRule.PlacementMode.Random; for (int i = 0; i < crystalCount; i++) { GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(crystalSpawnCard, directorPlacementRule, stageRng)); if ((bool)gameObject) { DeathRewards component2 = gameObject.GetComponent(); if ((bool)component2) { component2.goldReward = crystalRewardValue; } } crystalActiveList.Add(OnDestroyCallback.AddCallback(gameObject, delegate(OnDestroyCallback component) { crystalActiveList.Remove(component); })); } if ((bool)TeleporterInteraction.instance) { ChildLocator component3 = TeleporterInteraction.instance.GetComponent().modelTransform.GetComponent(); if ((bool)component3) { component3.FindChild("TimeCrystalProps").gameObject.SetActive(value: true); component3.FindChild("TimeCrystalBeaconBlocker").gameObject.SetActive(value: true); } } } public override void OnPlayerSpawnPointsPlaced(SceneDirector sceneDirector) { if (stageClearCount != 0) { return; } SpawnPoint spawnPoint = SpawnPoint.readOnlyInstancesList[0]; if ((bool)spawnPoint) { float num = 360f / (float)equipmentBarrelCount; for (int i = 0; i < equipmentBarrelCount; i++) { UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(num * (float)i, UnityEngine.Vector3.up) * (UnityEngine.Vector3.forward * equipmentBarrelRadius); DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule(); directorPlacementRule.minDistance = 0f; directorPlacementRule.maxDistance = 3f; directorPlacementRule.placementMode = DirectorPlacementRule.PlacementMode.NearestNode; directorPlacementRule.position = spawnPoint.transform.position + vector; DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(equipmentBarrelSpawnCard, directorPlacementRule, stageRng)); } } } public static string GetLeaderboardName(int playerCount, uint seedCycle) { if (Console.sessionCheatsEnabled) { return null; } return string.Format(CultureInfo.InvariantCulture, "weekly{0}p{1}", playerCount, seedCycle); } protected void ClientSubmitLeaderboardScore(RunReport runReport) { UnityEngine.Debug.LogFormat("Attempting to submit leaderboard score."); if (!runReport.gameEnding.isWin) { return; } bool flag = false; foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList) { if (readOnlyLocalPlayers.isParticipating) { flag = true; break; } } if (!flag) { return; } int num = PlayerCharacterMasterController.instances.Count; switch (num) { default: return; case 3: case 4: num = 4; break; case 1: case 2: break; } string value = GetLeaderboardName(num, serverSeedCycle); if (string.IsNullOrEmpty(value)) { return; } int[] subScores = new int[64]; GameObject bodyPrefab = BodyCatalog.GetBodyPrefab(NetworkUser.readOnlyLocalPlayersList[0].bodyIndexPreference); if (!bodyPrefab) { return; } SurvivorDef survivorDef = SurvivorCatalog.FindSurvivorDefFromBody(bodyPrefab); if (!(survivorDef == null)) { subScores[1] = (int)survivorDef.survivorIndex; Leaderboard leaderboard = Client.Instance.GetLeaderboard(value, Client.LeaderboardSortMethod.Ascending, Client.LeaderboardDisplayType.TimeMilliSeconds); leaderboard.OnBoardInformation = delegate { leaderboard.AddScore(onlyIfBeatsOldScore: true, (int)Math.Ceiling((double)runReport.runStopwatchValue * 1000.0), subScores); }; } } public override void OverrideRuleChoices(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong runSeed) { base.OverrideRuleChoices(mustInclude, mustExclude, base.seed); ForceChoice(mustInclude, mustExclude, "Difficulty.Normal"); ForceChoice(mustInclude, mustExclude, "Misc.StartingMoney.50"); ForceChoice(mustInclude, mustExclude, "Misc.StageOrder.Random"); ForceChoice(mustInclude, mustExclude, "Misc.KeepMoneyBetweenStages.Off"); for (int i = 0; i < ArtifactCatalog.artifactCount; i++) { ForceChoice(mustInclude, mustExclude, FindRuleForArtifact((ArtifactIndex)i).FindChoice("Off")); } Xoroshiro128Plus xoroshiro128Plus = new Xoroshiro128Plus(runSeed); UnityEngine.Debug.LogFormat("Weekly Run Seed: {0}", runSeed); if (xoroshiro128Plus.nextNormalizedFloat < 1f) { int num = xoroshiro128Plus.RangeInt(2, 7); ArtifactIndex[] array = new ArtifactIndex[ArtifactCatalog.artifactCount]; for (int j = 0; j < array.Length; j++) { array[j] = (ArtifactIndex)j; } Util.ShuffleArray(array, xoroshiro128Plus); for (int k = 0; k < num; k++) { if (ArtifactCatalog.GetArtifactDef(array[k]) != RoR2Content.Artifacts.randomSurvivorOnRespawnArtifactDef) { ForceChoice(mustInclude, mustExclude, FindRuleForArtifact(array[k]).FindChoice("On")); } } } ItemIndex itemIndex = ItemIndex.Count; for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++) { ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); RuleChoiceDef ruleChoiceDef = RuleCatalog.FindRuleDef("Items." + itemDef.name)?.FindChoice("On"); if (ruleChoiceDef != null) { ForceChoice(mustInclude, mustExclude, ruleChoiceDef); } } EquipmentIndex equipmentIndex = (EquipmentIndex)0; for (EquipmentIndex equipmentCount = (EquipmentIndex)EquipmentCatalog.equipmentCount; equipmentIndex < equipmentCount; equipmentIndex++) { EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); RuleChoiceDef ruleChoiceDef2 = RuleCatalog.FindRuleDef("Equipment." + equipmentDef.name)?.FindChoice("On"); if (ruleChoiceDef2 != null) { ForceChoice(mustInclude, mustExclude, ruleChoiceDef2); } } foreach (ExpansionDef expansionDef in ExpansionCatalog.expansionDefs) { RuleChoiceDef ruleChoiceDef3 = RuleCatalog.FindRuleDef("Expansions." + expansionDef.name)?.FindChoice("On"); if (ruleChoiceDef3 != null) { ForceChoice(mustInclude, mustExclude, ruleChoiceDef3); } } static RuleDef FindRuleForArtifact(ArtifactIndex artifactIndex) { ArtifactDef artifactDef = ArtifactCatalog.GetArtifactDef(artifactIndex); return RuleCatalog.FindRuleDef("Artifacts." + artifactDef.cachedName); } } public override bool IsUnlockableUnlocked(UnlockableDef unlockableDef) { return true; } public override bool CanUnlockableBeGrantedThisRun(UnlockableDef unlockableDef) { return false; } public override bool DoesEveryoneHaveThisUnlockableUnlocked(UnlockableDef unlockableDef) { return true; } protected override void HandlePostRunDestination() { Console.instance.SubmitCmd(null, "transition_command \"disconnect\";"); } protected override bool ShouldUpdateRunStopwatch() { return base.livingPlayerCount > 0; } public override bool ShouldAllowNonChampionBossSpawn() { return true; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool flag = base.OnSerialize(writer, forceAll); if (forceAll) { writer.WritePackedUInt32(serverSeedCycle); return true; } bool flag2 = false; if ((base.syncVarDirtyBits & 0x40u) != 0) { if (!flag2) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag2 = true; } writer.WritePackedUInt32(serverSeedCycle); } if (!flag2) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag2 || flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { base.OnDeserialize(reader, initialState); if (initialState) { serverSeedCycle = reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & 0x40u) != 0) { serverSeedCycle = reader.ReadPackedUInt32(); } } public override void PreStartClient() { base.PreStartClient(); } } public class GameObjectUnlockableFilter : NetworkBehaviour { [Tooltip("'requiredUnlockable' will be discontinued. Use 'requiredUnlockableDef' instead.")] [Obsolete("'requiredUnlockable' will be discontinued. Use 'requiredUnlockableDef' instead.", false)] public string requiredUnlockable; [Tooltip("'forbiddenUnlockable' will be discontinued. Use 'forbiddenUnlockableDef' instead.")] [Obsolete("'forbiddenUnlockable' will be discontinued. Use 'forbiddenUnlockableDef' instead.", false)] public string forbiddenUnlockable; public UnlockableDef requiredUnlockableDef; public UnlockableDef forbiddenUnlockableDef; [Tooltip("If all users have this achievement, disable")] public string AchievementToDisable; [SyncVar] private bool active; public bool Networkactive { get { return active; } [param: In] set { SetSyncVar(value, ref active, 1u); } } private void Start() { if (NetworkServer.active) { Run.instance?.RefreshUnlockAvailability(); Networkactive = ShouldShowGameObject(); base.gameObject.SetActive(active); } } private bool ShouldShowGameObject() { if ((bool)Run.instance) { ref string reference = ref requiredUnlockable; ref string reference2 = ref forbiddenUnlockable; if (!requiredUnlockableDef && !string.IsNullOrEmpty(reference)) { requiredUnlockableDef = UnlockableCatalog.GetUnlockableDef(reference); reference = null; } if (!forbiddenUnlockableDef && !string.IsNullOrEmpty(reference2)) { forbiddenUnlockableDef = UnlockableCatalog.GetUnlockableDef(reference2); reference2 = null; } if (AchievementToDisable != null) { bool flag = false; foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (!instance.networkUser.localUser.userProfile.HasAchievement(AchievementToDisable)) { flag = true; break; } } UnityEngine.Debug.LogFormat("GameObjectUnlockableFilter: Do all users have achievement {0}? : {1}", AchievementToDisable, flag); return flag; } bool flag2 = !requiredUnlockableDef || Run.instance.IsUnlockableUnlocked(requiredUnlockableDef); bool flag3 = !forbiddenUnlockableDef || Run.instance.DoesEveryoneHaveThisUnlockableUnlocked(forbiddenUnlockableDef); UnityEngine.Debug.LogFormat("GameObjectUnlockableFilter: requiredUnlockableIsUnlocked {0}; forbiddenUnlockableIsUnlocked {1}", flag2, flag3); if (flag2) { return !flag3; } return false; } return true; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(active); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(active); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { active = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { active = reader.ReadBoolean(); } } public override void PreStartClient() { } } [RequireComponent(typeof(VoteController))] public class GameOverController : NetworkBehaviour { [Tooltip("The prefab to use for the end-of-game report panel.")] public GameObject gameEndReportPanelPrefab; public float appearanceDelay = 1f; private VoteController voteController; private bool _shouldDisplayGameEndReportPanels; private Dictionary reportPanels = new Dictionary(); private const uint runReportDirtyBit = 1u; private const uint allDirtyBits = 1u; private static int kRpcRpcClientGameOver; public static GameOverController instance { get; private set; } public bool shouldDisplayGameEndReportPanels { get { return _shouldDisplayGameEndReportPanels; } set { _shouldDisplayGameEndReportPanels = value; if (_shouldDisplayGameEndReportPanels) { UpdateReportScreens(); } else { CleanupReportPanels(); } } } public RunReport runReport { get; private set; } [Server] public void SetRunReport([NotNull] RunReport newRunReport) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GameOverController::SetRunReport(RoR2.RunReport)' called on client"); return; } SetDirtyBit(1u); runReport = newRunReport; if ((bool)runReport.gameEnding) { EntityStateMachine.FindByCustomName(base.gameObject, "Main").initialStateType = runReport.gameEnding.gameOverControllerState; } } private int FindPlayerIndex(LocalUser localUser) { int i = 0; for (int playerInfoCount = runReport.playerInfoCount; i < playerInfoCount; i++) { if (runReport.GetPlayerInfo(i).localUser == localUser) { return i; } } return 0; } private void UpdateReportScreens() { if (!shouldDisplayGameEndReportPanels) { return; } int i = 0; for (int count = HUD.readOnlyInstanceList.Count; i < count; i++) { HUD hUD = HUD.readOnlyInstanceList[i]; if (!reportPanels.ContainsKey(hUD)) { reportPanels[hUD] = GenerateReportScreen(hUD); } } } private void CleanupReportPanels() { List list = CollectionPool>.RentCollection(); foreach (HUD key in reportPanels.Keys) { if (!key || !shouldDisplayGameEndReportPanels) { list.Add(key); } } int i = 0; for (int count = list.Count; i < count; i++) { reportPanels.Remove(list[i]); } CollectionPool>.ReturnCollection(list); } private GameEndReportPanelController GenerateReportScreen(HUD hud) { LocalUser localUser = hud.localUserViewer; GameObject obj = UnityEngine.Object.Instantiate(gameEndReportPanelPrefab, hud.transform); obj.transform.parent = hud.transform; obj.GetComponent().eventSystem = localUser.eventSystem; GameEndReportPanelController component = obj.GetComponent(); runReport.SortByLocalPlayers(); GameEndReportPanelController.DisplayData displayData = default(GameEndReportPanelController.DisplayData); displayData.runReport = runReport; displayData.playerIndex = FindPlayerIndex(localUser); GameEndReportPanelController.DisplayData displayData2 = displayData; component.SetDisplayData(displayData2); component.SetContinueButtonAction(delegate { if ((bool)localUser.currentNetworkUser) { localUser.currentNetworkUser.CallCmdSubmitVote(voteController.gameObject, 0); } }); GameObject obj2 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/UI/VoteInfoPanel"), (RectTransform)component.continueButton.transform.parent); obj2.transform.SetAsFirstSibling(); obj2.GetComponent().voteController = voteController; return component; } private void Awake() { runReport = new RunReport(); voteController = GetComponent(); } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); CameraRigController.OnHUDUpdated = (Action)Delegate.Combine(CameraRigController.OnHUDUpdated, new Action(UpdateReportScreens)); } private void OnDisable() { instance = SingletonHelper.Unassign(instance, this); CameraRigController.OnHUDUpdated = (Action)Delegate.Remove(CameraRigController.OnHUDUpdated, new Action(UpdateReportScreens)); } public override bool OnSerialize(NetworkWriter writer, bool initialState) { uint num = base.syncVarDirtyBits; if (initialState) { num = 1u; } bool num2 = (num & 1) != 0; if (!initialState) { writer.Write((byte)num); } if (num2) { runReport.Write(writer); } if (!initialState) { return num != 0; } return false; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (((uint)(initialState ? 1 : reader.ReadByte()) & (true ? 1u : 0u)) != 0) { runReport.Read(reader); } } [ClientRpc] public void RpcClientGameOver() { if ((bool)Run.instance) { Run.instance.OnClientGameOver(runReport); } } private void UNetVersion() { } protected static void InvokeRpcRpcClientGameOver(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcClientGameOver called on server."); } else { ((GameOverController)obj).RpcClientGameOver(); } } public void CallRpcClientGameOver() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcClientGameOver called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcClientGameOver); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcClientGameOver"); } static GameOverController() { kRpcRpcClientGameOver = 1518660169; NetworkBehaviour.RegisterRpcDelegate(typeof(GameOverController), kRpcRpcClientGameOver, InvokeRpcRpcClientGameOver); NetworkCRC.RegisterBehaviour("GameOverController", 0); } public override void PreStartClient() { } } public class GauntletMissionController : NetworkBehaviour { public class GauntletMissionBaseState : EntityState { protected GauntletMissionController gauntletMissionController => instance; } public class MissionCompleted : GauntletMissionBaseState { public override void OnEnter() { base.OnEnter(); base.gauntletMissionController.clearedEffect.SetActive(value: true); } } [Header("Behavior Values")] public float dleayBeforeStart; public float timeLimit; public float degenTickFrequency; public float percentDegenPerSecond; [Header("Cached Components")] private EntityStateMachine mainStateMachine; public GameObject[] gauntletShards; public GameObject clearedEffect; public GameObject gauntletPortal; private bool gauntletEnd; private bool slowDeathEffectActive; private float degenTimer; public static GauntletMissionController instance { get; private set; } public static event Action onInstanceChangedGlobal; private void Awake() { mainStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Main"); } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); GauntletMissionController.onInstanceChangedGlobal?.Invoke(); } private void OnDisable() { instance = SingletonHelper.Unassign(instance, this); GauntletMissionController.onInstanceChangedGlobal?.Invoke(); } public void GauntletMissionTimesUp() { gauntletEnd = true; mainStateMachine.SetNextState(new MissionCompleted()); } private void OnPreGeneratePlayerSpawnPointsServer(SceneDirector sceneDirector, ref Action generationMethod) { generationMethod = GenerateGauntletShards; } private void GenerateGauntletShards() { _ = gauntletShards.LongLength; } private void FixedUpdate() { if (NetworkServer.active) { FixedUpdateServer(); } } [Server] private void FixedUpdateServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GauntletMissionController::FixedUpdateServer()' called on client"); } else { if (!gauntletEnd) { return; } degenTimer += Time.fixedDeltaTime; if (!(degenTimer > 1f / degenTickFrequency)) { return; } degenTimer -= 1f / degenTickFrequency; foreach (TeamComponent teamMember in TeamComponent.GetTeamMembers(TeamIndex.Player)) { float damage = percentDegenPerSecond / 100f / degenTickFrequency * teamMember.body.healthComponent.combinedHealth; teamMember.body.healthComponent.TakeDamage(new DamageInfo { damage = damage, position = teamMember.body.corePosition, damageType = DamageType.Silent }); } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class GenericDisplayNameProvider : MonoBehaviour, IDisplayNameProvider { public string displayToken; public string GetDisplayName() { return Language.GetString(displayToken); } public void SetDisplayToken(string newDisplayToken) { displayToken = newDisplayToken; } } public class GenericEnergyComponent : NetworkBehaviour { [SerializeField] private float _capacity = 1f; [SerializeField] private float _chargeRate = 1f; [SyncVar] private Run.FixedTimeStamp referenceTime; private float _internalChargeRate; public bool hasEffectiveAuthority { get; private set; } public float energy { get { if (internalChargeRate == 0f) { return (referenceTime - Run.FixedTimeStamp.zero) * capacity; } return Mathf.Clamp01(referenceTime.timeSince * internalChargeRate) * capacity; } set { float num = (capacity.Equals(0f) ? 0f : Mathf.Clamp01(value / capacity)); if (internalChargeRate == 0f) { NetworkreferenceTime = Run.FixedTimeStamp.zero + num; } else { NetworkreferenceTime = Run.FixedTimeStamp.now - num / internalChargeRate; } } } public float normalizedEnergy { get { if (capacity == 0f) { return 0f; } return Mathf.Clamp01(energy / capacity); } } private float internalChargeRate { get { return _internalChargeRate; } set { if (_internalChargeRate != value) { float num = energy; _internalChargeRate = value; energy = num; } } } public float chargeRate { get { return _chargeRate; } set { if (_chargeRate != value) { float num = energy; _chargeRate = value; internalChargeRate = ((capacity != 0f) ? (_chargeRate / capacity) : 0f); energy = num; } } } public float normalizedChargeRate { get { if (capacity == 0f) { return 0f; } return chargeRate / capacity; } set { chargeRate = ((capacity != 0f) ? (value * capacity) : 0f); } } public float capacity { get { return _capacity; } set { if (value != _capacity) { float num = energy; _capacity = value; energy = num; } } } public Run.FixedTimeStamp NetworkreferenceTime { get { return referenceTime; } [param: In] set { SetSyncVar(value, ref referenceTime, 1u); } } private void UpdateAuthority() { hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject); } private void Awake() { UpdateAuthority(); internalChargeRate = ((capacity != 0f) ? (chargeRate / capacity) : 0f); if (NetworkServer.active) { energy = capacity; } } public override void OnStartAuthority() { base.OnStartAuthority(); UpdateAuthority(); } public override void OnStopAuthority() { base.OnStopAuthority(); UpdateAuthority(); } private void OnEnable() { internalChargeRate = ((capacity != 0f) ? (chargeRate / capacity) : 0f); } private void OnDisable() { internalChargeRate = 0f; } [Server] public bool TakeEnergy(float amount) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.GenericEnergyComponent::TakeEnergy(System.Single)' called on client"); return false; } if (amount > energy) { return false; } energy -= amount; return true; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { GeneratedNetworkCode._WriteFixedTimeStamp_Run(writer, referenceTime); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WriteFixedTimeStamp_Run(writer, referenceTime); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { referenceTime = GeneratedNetworkCode._ReadFixedTimeStamp_Run(reader); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { referenceTime = GeneratedNetworkCode._ReadFixedTimeStamp_Run(reader); } } public override void PreStartClient() { } } public sealed class GenericInteraction : NetworkBehaviour, IInteractable { [Serializable] public class InteractorUnityEvent : UnityEvent { } [SyncVar] public Interactability interactability = Interactability.Available; public bool shouldIgnoreSpherecastForInteractibility; public string contextToken; public bool shouldProximityHighlight = true; public InteractorUnityEvent onActivation; public bool shouldShowOnScanner = true; public Interactability Networkinteractability { get { return interactability; } [param: In] set { ulong newValueAsUlong = (ulong)value; ulong fieldValueAsUlong = (ulong)interactability; SetSyncVarEnum(value, newValueAsUlong, ref interactability, fieldValueAsUlong, 1u); } } [Server] public void SetInteractabilityAvailable() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericInteraction::SetInteractabilityAvailable()' called on client"); } else { Networkinteractability = Interactability.Available; } } [Server] public void SetInteractabilityConditionsNotMet() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericInteraction::SetInteractabilityConditionsNotMet()' called on client"); } else { Networkinteractability = Interactability.ConditionsNotMet; } } [Server] public void SetInteractabilityDisabled() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericInteraction::SetInteractabilityDisabled()' called on client"); } else { Networkinteractability = Interactability.Disabled; } } string IInteractable.GetContextString(Interactor activator) { if (contextToken == "") { return null; } return Language.GetString(contextToken); } public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator) { return shouldIgnoreSpherecastForInteractibility; } Interactability IInteractable.GetInteractability(Interactor activator) { return interactability; } void IInteractable.OnInteractionBegin(Interactor activator) { onActivation.Invoke(activator); } private void OnEnable() { InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); } public bool ShouldShowOnScanner() { if (shouldShowOnScanner) { return interactability != Interactability.Disabled; } return false; } public bool ShouldProximityHighlight() { return shouldProximityHighlight; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write((int)interactability); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write((int)interactability); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { interactability = (Interactability)reader.ReadInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { interactability = (Interactability)reader.ReadInt32(); } } public override void PreStartClient() { } } public class GenericObjectiveProvider : MonoBehaviour { private class GenericObjectiveTracker : ObjectivePanelController.ObjectiveTracker { private string previousToken; protected override bool shouldConsiderComplete { get { if (retired) { return ((GenericObjectiveProvider)sourceDescriptor.source).markCompletedOnRetired; } return false; } } protected override string GenerateString() { GenericObjectiveProvider genericObjectiveProvider = (GenericObjectiveProvider)sourceDescriptor.source; previousToken = genericObjectiveProvider.objectiveToken; return Language.GetString(genericObjectiveProvider.objectiveToken); } protected override bool IsDirty() { return ((GenericObjectiveProvider)sourceDescriptor.source).objectiveToken != previousToken; } } public string objectiveToken; public bool markCompletedOnRetired = true; private static readonly Action> collectObjectiveSourcesDelegate = CollectObjectiveSources; private void OnEnable() { if (!InstanceTracker.Any()) { ObjectivePanelController.collectObjectiveSources += collectObjectiveSourcesDelegate; } InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); if (!InstanceTracker.Any()) { ObjectivePanelController.collectObjectiveSources -= collectObjectiveSourcesDelegate; } } private static void CollectObjectiveSources(CharacterMaster viewer, List dest) { foreach (GenericObjectiveProvider instances in InstanceTracker.GetInstancesList()) { dest.Add(new ObjectivePanelController.ObjectiveSourceDescriptor { master = viewer, objectiveType = typeof(GenericObjectiveTracker), source = instances }); } } } public class GenericOwnership : NetworkBehaviour { [SyncVar(hook = "SetOwnerClient")] private NetworkInstanceId ownerInstanceId; private GameObject cachedOwnerObject; public GameObject ownerObject { get { return cachedOwnerObject; } [Server] set { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericOwnership::set_ownerObject(UnityEngine.GameObject)' called on client"); return; } if (!value) { value = null; } if ((object)cachedOwnerObject != value) { cachedOwnerObject = value; NetworkownerInstanceId = cachedOwnerObject?.GetComponent()?.netId ?? NetworkInstanceId.Invalid; this.onOwnerChanged?.Invoke(cachedOwnerObject); } } } public NetworkInstanceId NetworkownerInstanceId { get { return ownerInstanceId; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SetOwnerClient(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref ownerInstanceId, 1u); } } public event Action onOwnerChanged; private void SetOwnerClient(NetworkInstanceId id) { if (!NetworkServer.active) { cachedOwnerObject = ClientScene.FindLocalObject(id); this.onOwnerChanged?.Invoke(cachedOwnerObject); } } public override void OnStartClient() { base.OnStartClient(); SetOwnerClient(ownerInstanceId); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(ownerInstanceId); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(ownerInstanceId); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { ownerInstanceId = reader.ReadNetworkId(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { SetOwnerClient(reader.ReadNetworkId()); } } public override void PreStartClient() { } } public sealed class GenericPickupController : NetworkBehaviour, IInteractable, IInspectable, IInspectInfoProvider, IDisplayNameProvider { private class PickupMessage : MessageBase { public GameObject masterGameObject; public PickupIndex pickupIndex; public uint pickupQuantity; public void Reset() { masterGameObject = null; pickupIndex = PickupIndex.none; pickupQuantity = 0u; } public override void Serialize(NetworkWriter writer) { writer.Write(masterGameObject); GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex); writer.WritePackedUInt32(pickupQuantity); } public override void Deserialize(NetworkReader reader) { masterGameObject = reader.ReadGameObject(); pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader); pickupQuantity = reader.ReadPackedUInt32(); } } public enum PickupArtifactFlag { NONE, COMMAND, DELUSION } public struct CreatePickupInfo { public UnityEngine.Vector3 position; public UnityEngine.Quaternion rotation; private PickupIndex? _pickupIndex; public PickupPickerController.Option[] pickerOptions; public GameObject prefabOverride; public ChestBehavior chest; public PickupArtifactFlag artifactFlag; public ItemIndex delusionItemIndex; public ItemIndex falseChoice1; public ItemIndex falseChoice2; public PickupIndex pickupIndex { get { if (!_pickupIndex.HasValue) { return PickupIndex.none; } return _pickupIndex.Value; } set { _pickupIndex = value; } } } public PickupDisplay pickupDisplay; public ChestBehavior chestGeneratedFrom; [SyncVar(hook = "SyncPickupIndex")] public PickupIndex pickupIndex = PickupIndex.none; [SyncVar(hook = "SyncRecycled")] public bool Recycled; public bool selfDestructIfPickupIndexIsNotIdeal; public SerializablePickupIndex idealPickupIndex; private static readonly PickupMessage pickupMessageInstance = new PickupMessage(); public float waitDuration = 0.5f; private Run.FixedTimeStamp waitStartTime; private bool consumed; public const string pickupSoundString = "Play_UI_item_pickup"; private static GameObject pickupPrefab; public PickupIndex NetworkpickupIndex { get { return pickupIndex; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SyncPickupIndex(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref pickupIndex, 1u); } } public bool NetworkRecycled { get { return Recycled; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SyncRecycled(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref Recycled, 2u); } } private void SyncPickupIndex(PickupIndex newPickupIndex) { NetworkpickupIndex = newPickupIndex; UpdatePickupDisplay(); } private void SyncRecycled(bool isRecycled) { NetworkRecycled = isRecycled; } [Server] public static void SendPickupMessage(CharacterMaster master, PickupIndex pickupIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericPickupController::SendPickupMessage(RoR2.CharacterMaster,RoR2.PickupIndex)' called on client"); return; } uint pickupQuantity = 1u; if ((bool)master.inventory) { ItemIndex itemIndex = PickupCatalog.GetPickupDef(pickupIndex)?.itemIndex ?? ItemIndex.None; if (itemIndex != ItemIndex.None) { pickupQuantity = (uint)master.inventory.GetItemCount(itemIndex); } } try { PickupMessage msg = new PickupMessage { masterGameObject = master.gameObject, pickupIndex = pickupIndex, pickupQuantity = pickupQuantity }; NetworkServer.SendByChannelToAll(57, msg, QosChannelIndex.chat.intVal); } catch (Exception arg) { UnityEngine.Debug.Log($"Failed to send pickupMessage for pickupIndex {pickupIndex} - gameObject {master.gameObject.name}\r\n{arg}"); } } [NetworkMessageHandler(msgType = 57, client = true)] private static void HandlePickupMessage(NetworkMessage netMsg) { PickupMessage pickupMessage = pickupMessageInstance; netMsg.ReadMessage(pickupMessage); GameObject masterGameObject = pickupMessage.masterGameObject; PickupIndex pickupIndex = pickupMessage.pickupIndex; PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); uint pickupQuantity = pickupMessage.pickupQuantity; pickupMessage.Reset(); if (!masterGameObject) { return; } CharacterMaster component = masterGameObject.GetComponent(); if (!component) { return; } PlayerCharacterMasterController component2 = component.GetComponent(); if ((bool)component2) { NetworkUser networkUser = component2.networkUser; if ((bool)networkUser) { networkUser.localUser?.userProfile.DiscoverPickup(pickupIndex); } } CharacterBody body = component.GetBody(); _ = (bool)body; ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef?.itemIndex ?? ItemIndex.None); if (itemDef != null && itemDef.hidden) { return; } if (pickupIndex != PickupIndex.none) { ItemIndex transformedItemIndex = ContagiousItemManager.GetTransformedItemIndex(itemDef?.itemIndex ?? ItemIndex.None); if (itemDef == null || transformedItemIndex == ItemIndex.None || component.inventory.GetItemCount(transformedItemIndex) <= 0) { CharacterMasterNotificationQueue.PushPickupNotification(component, pickupIndex); } } Chat.AddPickupMessage(body, pickupDef?.nameToken ?? PickupCatalog.invalidPickupToken, pickupDef?.baseColor ?? UnityEngine.Color.black, pickupQuantity); if ((bool)body) { Util.PlaySound("Play_UI_item_pickup", body.gameObject); } } public void StartWaitTime() { waitStartTime = Run.FixedTimeStamp.now; } private void OnTriggerStay(Collider other) { if (!NetworkServer.active || !(waitStartTime.timeSince >= waitDuration) || consumed) { return; } CharacterBody component = other.GetComponent(); if (!component) { return; } PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); ItemIndex itemIndex = pickupDef?.itemIndex ?? ItemIndex.None; if (itemIndex != ItemIndex.None) { ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(ItemCatalog.GetItemDef(itemIndex).tier); if ((bool)itemTierDef && (itemTierDef.pickupRules == ItemTierDef.PickupRules.ConfirmAll || (itemTierDef.pickupRules == ItemTierDef.PickupRules.ConfirmFirst && (bool)component.inventory && component.inventory.GetItemCount(itemIndex) <= 0))) { return; } } EquipmentIndex equipmentIndex = pickupDef?.equipmentIndex ?? EquipmentIndex.None; if ((equipmentIndex == EquipmentIndex.None || (!EquipmentCatalog.GetEquipmentDef(equipmentIndex).isLunar && (!component.inventory || component.inventory.currentEquipmentIndex == EquipmentIndex.None))) && (pickupDef == null || pickupDef.coinValue == 0) && BodyHasPickupPermission(component)) { AttemptGrant(component); } } private static bool BodyHasPickupPermission(CharacterBody body) { if ((bool)(body.masterObject ? body.masterObject.GetComponent() : null)) { return body.inventory; } return false; } public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator) { return false; } public string GetContextString(Interactor activator) { return string.Format(Language.GetString(PickupCatalog.GetPickupDef(pickupIndex)?.interactContextToken ?? string.Empty), GetDisplayName()); } private void UpdatePickupDisplay() { if (!pickupDisplay) { return; } pickupDisplay.SetPickupIndex(pickupIndex); if ((bool)pickupDisplay.modelRenderer) { Highlight component = GetComponent(); if ((bool)component) { component.targetRenderer = pickupDisplay.modelRenderer; component.ResetHighlight(); } } } [Server] private void AttemptGrant(CharacterBody body) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericPickupController::AttemptGrant(RoR2.CharacterBody)' called on client"); return; } TeamComponent component = body.GetComponent(); if (!component || component.teamIndex != TeamIndex.Player) { return; } PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if ((bool)body.inventory && pickupDef != null) { PickupDef.GrantContext grantContext = default(PickupDef.GrantContext); grantContext.body = body; grantContext.controller = this; PickupDef.GrantContext context = grantContext; pickupDef.attemptGrant?.Invoke(ref context); consumed = context.shouldDestroy; if (context.shouldNotify) { SendPickupMessage(body.master, pickupDef.pickupIndex); } if ((bool)chestGeneratedFrom && DelusionChestController.isDelusionEnable) { chestGeneratedFrom.CallRpcSetDelusionPickupIndex(pickupIndex); } if (context.shouldDestroy) { UnityEngine.Object.Destroy(base.gameObject); } } } private void Start() { waitStartTime = Run.FixedTimeStamp.now; consumed = false; UpdatePickupDisplay(); } private void OnEnable() { InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); } public Interactability GetInteractability(Interactor activator) { if (!base.enabled) { return Interactability.Disabled; } if (waitStartTime.timeSince < waitDuration || consumed) { return Interactability.Disabled; } CharacterBody component = activator.GetComponent(); if ((bool)component) { if (!BodyHasPickupPermission(component)) { return Interactability.Disabled; } return Interactability.Available; } return Interactability.Disabled; } public void OnInteractionBegin(Interactor activator) { AttemptGrant(activator.GetComponent()); } public bool ShouldShowOnScanner() { return true; } public bool ShouldProximityHighlight() { return true; } public string GetDisplayName() { return Language.GetString(PickupCatalog.GetPickupDef(pickupIndex)?.nameToken ?? PickupCatalog.invalidPickupToken); } public void SetPickupIndexFromString(string pickupString) { if (NetworkServer.active) { PickupIndex networkpickupIndex = PickupCatalog.FindPickupIndex(pickupString); NetworkpickupIndex = networkpickupIndex; } } [InitDuringStartup] private static void Init() { LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/GenericPickup", delegate(GameObject operationResult) { pickupPrefab = operationResult; }); } public static GenericPickupController CreatePickup(in CreatePickupInfo createPickupInfo) { GameObject gameObject = UnityEngine.Object.Instantiate(createPickupInfo.prefabOverride ?? pickupPrefab, createPickupInfo.position, createPickupInfo.rotation); GenericPickupController component = gameObject.GetComponent(); if ((bool)component) { component.NetworkpickupIndex = createPickupInfo.pickupIndex; component.chestGeneratedFrom = createPickupInfo.chest; } else { PickupDisplay componentInChildren = gameObject.GetComponentInChildren(); if ((bool)componentInChildren) { GameObject modelObjectOverride = gameObject.GetComponentInChildren().gameObject; componentInChildren.RebuildModel(modelObjectOverride); } } PickupIndexNetworker component2 = gameObject.GetComponent(); if ((bool)component2) { component2.NetworkpickupIndex = createPickupInfo.pickupIndex; } PickupPickerController component3 = gameObject.GetComponent(); if ((bool)component3 && createPickupInfo.pickerOptions != null) { component3.SetOptionsServer(createPickupInfo.pickerOptions); } NetworkServer.Spawn(gameObject); return component; } [ContextMenu("Print Pickup Index")] private void PrintPickupIndex() { UnityEngine.Debug.LogFormat("pickupIndex={0}", PickupCatalog.GetPickupDef(pickupIndex)?.internalName ?? "Invalid"); } public IInspectInfoProvider GetInspectInfoProvider() { return this; } public bool CanBeInspected() { if (pickupIndex != PickupIndex.none) { return pickupIndex.isValid; } return false; } public InspectInfo GetInfo() { return PickupCatalog.GetPickupDef(pickupIndex) ?? throw new InvalidOperationException("Attempted to get info for invalid pickup. Should be impossible. Investigate me."); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex); writer.Write(Recycled); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(Recycled); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader); Recycled = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { SyncPickupIndex(GeneratedNetworkCode._ReadPickupIndex_None(reader)); } if (((uint)num & 2u) != 0) { SyncRecycled(reader.ReadBoolean()); } } public override void PreStartClient() { } } [RequireComponent(typeof(CharacterBody))] public sealed class GenericSkill : MonoBehaviour, ILifeBehavior, IManagedMonoBehaviour { public class SkillOverride : IEquatable { public readonly object source; public readonly SkillDef skillDef; public readonly SkillOverridePriority priority; public int stock; public float rechargeStopwatch; public SkillOverride(object source, SkillDef skillDef, SkillOverridePriority priority) { this.source = source; this.skillDef = skillDef; this.priority = priority; stock = 0; rechargeStopwatch = 0f; } public bool Equals(SkillOverride other) { if (object.Equals(source, other.source) && object.Equals(skillDef, other.skillDef)) { return priority == other.priority; } return false; } public override bool Equals(object obj) { if (obj is SkillOverride other) { return Equals(other); } return false; } public override int GetHashCode() { return (((((source != null) ? source.GetHashCode() : 0) * 397) ^ ((skillDef != null) ? skillDef.GetHashCode() : 0)) * 397) ^ (int)priority; } } public enum SkillOverridePriority { Default, Loadout, Upgrade, Replacement, Contextual, Network } public class SkillOverrideHandle : IDisposable { public readonly object source; public readonly SkillDef skill; public readonly GenericSkill skillSlot; public readonly SkillOverridePriority priority; public void Dispose() { } } public delegate void StateMachineResolver(GenericSkill genericSkill, SkillDef skillDef, ref EntityStateMachine targetStateMachine); [SerializeField] private SkillFamily _skillFamily; public string skillName; public bool hideInCharacterSelect; private static readonly List stateMachineLookupBuffer = new List(); private SkillOverride[] skillOverrides = Array.Empty(); private int currentSkillOverride = -1; private int bonusStockFromBody; public int baseStock; private float finalRechargeInterval; private float _cooldownScale = 1f; private float _flatCooldownReduction = 1f; private float _temporaryCooldownPenalty; public float baseRechargeStopwatch; [HideInInspector] public bool hasExecutedSuccessfully; public SkillDef skillDef { get; private set; } public SkillFamily skillFamily => _skillFamily; public SkillDef baseSkill { get; private set; } public string skillNameToken => skillDef.GetCurrentNameToken(this); public string skillDescriptionToken => skillDef.GetCurrentDescriptionToken(this); public float baseRechargeInterval => skillDef.GetRechargeInterval(this); public int rechargeStock => skillDef.GetRechargeStock(this); public bool beginSkillCooldownOnSkillEnd => skillDef.beginSkillCooldownOnSkillEnd; public SerializableEntityStateType activationState => skillDef.activationState; public InterruptPriority interruptPriority => skillDef.interruptPriority; public bool isCombatSkill => skillDef.isCombatSkill; public bool mustKeyPress => skillDef.mustKeyPress; public Sprite icon => skillDef.GetCurrentIcon(this); [CanBeNull] public EntityStateMachine stateMachine { get; private set; } [CanBeNull] public SkillDef.BaseSkillInstanceData skillInstanceData { get; set; } public CharacterBody characterBody { get; private set; } public SkillDef defaultSkillDef { get; private set; } public int maxStock { get; private set; } = 1; public int stock { get { if (currentSkillOverride >= 0 && currentSkillOverride < skillOverrides.Length) { return skillOverrides[currentSkillOverride].stock; } return baseStock; } set { if (currentSkillOverride >= 0 && currentSkillOverride < skillOverrides.Length) { skillOverrides[currentSkillOverride].stock = value; } else { baseStock = value; } } } public float cooldownScale { get { return _cooldownScale; } set { if (_cooldownScale != value) { _cooldownScale = value; RecalculateFinalRechargeInterval(); } } } public float flatCooldownReduction { get { return _flatCooldownReduction; } set { if (_flatCooldownReduction != value) { _flatCooldownReduction = value; RecalculateFinalRechargeInterval(); } } } public float temporaryCooldownPenalty { get { return _temporaryCooldownPenalty; } set { if (_temporaryCooldownPenalty != value) { _temporaryCooldownPenalty = value; RecalculateFinalRechargeInterval(); } } } public float rechargeStopwatch { get { if (currentSkillOverride >= 0 && currentSkillOverride < skillOverrides.Length) { return skillOverrides[currentSkillOverride].rechargeStopwatch; } return baseRechargeStopwatch; } set { if (currentSkillOverride >= 0 && currentSkillOverride < skillOverrides.Length) { skillOverrides[currentSkillOverride].rechargeStopwatch = value; } else { baseRechargeStopwatch = value; } } } public float cooldownRemaining { get { if (stock != maxStock && rechargeStock != 0) { return finalRechargeInterval - rechargeStopwatch; } return 0f; } } public event Action onSkillChanged; private event StateMachineResolver _customStateMachineResolver; public event StateMachineResolver customStateMachineResolver { add { _customStateMachineResolver += value; PickTargetStateMachine(); } remove { _customStateMachineResolver -= value; PickTargetStateMachine(); } } private int FindSkillOverrideIndex(ref SkillOverride skillOverride) { for (int i = 0; i < skillOverrides.Length; i++) { if (skillOverrides[i].Equals(skillOverride)) { return i; } } return -1; } public void SetSkillOverride(object source, SkillDef skillDef, SkillOverridePriority priority) { SkillOverride skillOverride = new SkillOverride(source, skillDef, priority); if (FindSkillOverrideIndex(ref skillOverride) == -1) { ArrayUtils.ArrayAppend(ref skillOverrides, in skillOverride); PickCurrentOverride(); } } public void UnsetSkillOverride(object source, SkillDef skillDef, SkillOverridePriority priority) { SkillOverride skillOverride = new SkillOverride(source, skillDef, priority); int num = FindSkillOverrideIndex(ref skillOverride); if (num != -1) { ArrayUtils.ArrayRemoveAtAndResize(ref skillOverrides, num); PickCurrentOverride(); } } public bool HasSkillOverrideOfPriority(SkillOverridePriority priority) { for (int i = 0; i < skillOverrides.Length; i++) { if (priority == skillOverrides[i].priority) { return true; } } return false; } private void PickCurrentOverride() { currentSkillOverride = -1; SkillOverridePriority skillOverridePriority = SkillOverridePriority.Default; for (int i = 0; i < skillOverrides.Length; i++) { SkillOverridePriority priority = skillOverrides[i].priority; if (skillOverridePriority <= priority) { currentSkillOverride = i; skillOverridePriority = priority; } } if (currentSkillOverride == -1) { SetSkillInternal(baseSkill); } else { SetSkillInternal(skillOverrides[currentSkillOverride].skillDef); } } private void SetSkillInternal(SkillDef newSkillDef) { if (!(skillDef == newSkillDef)) { UnassignSkill(); AssignSkill(newSkillDef); this.onSkillChanged?.Invoke(this); } } public void SetBaseSkill(SkillDef newSkillDef) { baseSkill = newSkillDef; PickCurrentOverride(); } private void UnassignSkill() { if ((object)skillDef != null) { skillDef.OnUnassigned(this); skillInstanceData = null; skillDef = null; } } private void AssignSkill(SkillDef newSkillDef) { skillDef = newSkillDef; if ((object)skillDef != null) { PickTargetStateMachine(); RecalculateMaxStock(); if (skillDef.fullRestockOnAssign && stock < maxStock) { stock = maxStock; } if (skillDef.dontAllowPastMaxStocks) { stock = Mathf.Min(maxStock, stock); } skillInstanceData = skillDef.OnAssigned(this); RecalculateFinalRechargeInterval(); } } public void SetBonusStockFromBody(int newBonusStockFromBody) { bonusStockFromBody = newBonusStockFromBody; RecalculateMaxStock(); } private void RecalculateMaxStock() { if (skillDef != null) { maxStock = skillDef.GetMaxStock(this) + bonusStockFromBody; } else { maxStock = 1; } } private void Awake() { defaultSkillDef = skillFamily.defaultSkillDef; baseSkill = defaultSkillDef; characterBody = GetComponent(); AssignSkill(defaultSkillDef); } private void OnDestroy() { UnassignSkill(); } private void Start() { RecalculateMaxStock(); stock = maxStock; } private void FixedUpdate() { ManagedFixedUpdate(Time.fixedDeltaTime); } public void ManagedFixedUpdate(float deltaTime) { skillDef?.OnFixedUpdate(this, deltaTime); } public void OnDeathStart() { base.enabled = false; } public bool CanExecute() { return skillDef?.CanExecute(this) ?? false; } public bool IsReady() { return skillDef?.IsReady(this) ?? false; } public bool ExecuteIfReady() { hasExecutedSuccessfully = CanExecute(); if (hasExecutedSuccessfully) { OnExecute(); return true; } return false; } public void RunRecharge(float dt) { if (stock < maxStock) { if (!beginSkillCooldownOnSkillEnd || !(stateMachine.state.GetType() == activationState.stateType)) { rechargeStopwatch += dt; } if (skillDef != null && skillDef.attackSpeedBuffsRestockSpeed) { RecalculateFinalRechargeInterval(); } if (rechargeStopwatch >= finalRechargeInterval) { temporaryCooldownPenalty = 0f; RestockSteplike(); } } } public void Reset() { rechargeStopwatch = 0f; stock = maxStock; } public bool CanApplyAmmoPack() { if (stock < maxStock) { return true; } return false; } public void ApplyAmmoPack() { if (stock < maxStock) { stock += rechargeStock; if (stock > maxStock) { stock = maxStock; } } } public void AddOneStock() { int num = stock + 1; stock = num; rechargeStopwatch = 0f; } public void RemoveAllStocks() { stock = 0; rechargeStopwatch = 0f; } public void DeductStock(int count) { stock = Mathf.Max(0, stock - count); } private void OnExecute() { skillDef.OnExecute(this); } public void RechargeBaseSkill(float dt) { if (baseSkill == null) { return; } float rechargeInterval = baseSkill.GetRechargeInterval(this); float num = Mathf.Min(rechargeInterval, Mathf.Max(0.5f, rechargeInterval * cooldownScale - flatCooldownReduction)) + temporaryCooldownPenalty; int baseMaxStock = GetBaseMaxStock(); if (num == 0f) { baseStock = baseMaxStock; baseRechargeStopwatch = 0f; return; } baseRechargeStopwatch += dt; int num2 = baseSkill.GetRechargeStock(this); int num3 = Mathf.FloorToInt(baseRechargeStopwatch / num * (float)num2); baseStock += num3; if (baseStock >= baseMaxStock) { baseStock = baseMaxStock; baseRechargeStopwatch = 0f; } else { baseRechargeStopwatch -= (float)num3 * num; } } public int GetBaseStock() { return baseStock; } public int GetBaseMaxStock() { if (baseSkill == null) { return 1; } return baseSkill.GetMaxStock(this) + bonusStockFromBody; } private void RestockContinuous() { if (finalRechargeInterval == 0f) { stock = maxStock; rechargeStopwatch = 0f; return; } int num = Mathf.FloorToInt(rechargeStopwatch / finalRechargeInterval * (float)rechargeStock); stock += num; if (stock >= maxStock) { stock = maxStock; rechargeStopwatch = 0f; } else { rechargeStopwatch -= (float)num * finalRechargeInterval; } } public void RestockSteplike() { stock += rechargeStock; if (stock >= maxStock) { stock = maxStock; } rechargeStopwatch = 0f; } public float CalculateFinalRechargeInterval() { return Mathf.Min(baseRechargeInterval, Mathf.Max(0.5f, baseRechargeInterval * cooldownScale - flatCooldownReduction)) + temporaryCooldownPenalty; } private void RecalculateFinalRechargeInterval() { finalRechargeInterval = CalculateFinalRechargeInterval(); } public void RecalculateValues() { RecalculateMaxStock(); RecalculateFinalRechargeInterval(); } private void PickTargetStateMachine() { EntityStateMachine targetStateMachine = stateMachine; if (!string.Equals(stateMachine?.customName, skillDef.activationStateMachineName, StringComparison.Ordinal)) { targetStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, skillDef.activationStateMachineName); } this._customStateMachineResolver?.Invoke(this, skillDef, ref targetStateMachine); stateMachine = targetStateMachine; } [AssetCheck(typeof(GenericSkill))] private static void CheckGenericSkillStateMachine(AssetCheckArgs args) { if (((GenericSkill)args.asset).stateMachine.customName == string.Empty) { args.LogError("Unnamed state machine.", ((GenericSkill)args.asset).gameObject); } } } public class GhostGunController : MonoBehaviour { public GameObject owner; public float interval; public float maxRange = 20f; public float turnSpeed = 180f; public UnityEngine.Vector3 localOffset = UnityEngine.Vector3.zero; public float positionSmoothTime = 0.05f; public float timeout = 2f; private float fireTimer; private float timeoutTimer; private int ammo; private int kills; private GameObject target; private UnityEngine.Vector3 velocity; private void Start() { fireTimer = 0f; ammo = 6; kills = 0; timeoutTimer = timeout; } private void Fire(UnityEngine.Vector3 origin, UnityEngine.Vector3 aimDirection) { BulletAttack obj = new BulletAttack { aimVector = aimDirection, bulletCount = 1u, damage = CalcDamage(), force = 2400f, maxSpread = 0f, minSpread = 0f, muzzleName = "muzzle", origin = origin, owner = owner, procCoefficient = 0f, tracerEffectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/Tracers/TracerSmokeChase"), hitEffectPrefab = LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/Hitspark1"), damageColorIndex = DamageColorIndex.Item }; GlobalEventManager.onCharacterDeathGlobal += CheckForKill; obj.Fire(); GlobalEventManager.onCharacterDeathGlobal -= CheckForKill; } private void CheckForKill(DamageReport damageReport) { if (damageReport.damageInfo.inflictor == base.gameObject) { kills++; } } private float CalcDamage() { float damage = owner.GetComponent().damage; return 5f * Mathf.Pow(2f, kills) * damage; } private bool HasLoS(GameObject target) { Ray ray = new Ray(base.transform.position, target.transform.position - base.transform.position); RaycastHit hitInfo = default(RaycastHit); if (Physics.Raycast(ray, out hitInfo, maxRange, (int)LayerIndex.CommonMasks.characterBodiesOrDefault | (int)LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { return hitInfo.collider.gameObject == target; } return true; } private bool WillHit(GameObject target) { Ray ray = new Ray(base.transform.position, base.transform.forward); RaycastHit hitInfo = default(RaycastHit); if (Physics.Raycast(ray, out hitInfo, maxRange, (int)LayerIndex.entityPrecise.mask | (int)LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { HurtBox component = hitInfo.collider.GetComponent(); if ((bool)component) { HealthComponent healthComponent = component.healthComponent; if ((bool)healthComponent) { return healthComponent.gameObject == target; } } } return false; } private GameObject FindTarget() { TeamIndex teamA = TeamIndex.Neutral; TeamComponent component = owner.GetComponent(); if ((bool)component) { teamA = component.teamIndex; } UnityEngine.Vector3 position = base.transform.position; float num = CalcDamage(); float num2 = maxRange * maxRange; GameObject gameObject = null; GameObject result = null; float num3 = 0f; float num4 = float.PositiveInfinity; for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++) { if (TeamManager.IsTeamEnemy(teamA, teamIndex)) { ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamIndex); for (int i = 0; i < teamMembers.Count; i++) { GameObject gameObject2 = teamMembers[i].gameObject; if (!((gameObject2.transform.position - position).sqrMagnitude <= num2)) { continue; } HealthComponent component2 = teamMembers[i].GetComponent(); if (!component2) { continue; } if (component2.health <= num) { if (component2.health > num3 && HasLoS(gameObject2)) { gameObject = gameObject2; num3 = component2.health; } } else if (component2.health < num4 && HasLoS(gameObject2)) { result = gameObject2; num4 = component2.health; } } } } if (!gameObject) { return result; } return gameObject; } private void FixedUpdate() { if (!NetworkServer.active) { return; } if (!owner) { UnityEngine.Object.Destroy(base.gameObject); return; } InputBankTest component = owner.GetComponent(); UnityEngine.Vector3 vector = (component ? component.aimDirection : base.transform.forward); if ((bool)target) { vector = (target.transform.position - base.transform.position).normalized; } base.transform.forward = UnityEngine.Vector3.RotateTowards(base.transform.forward, vector, MathF.PI / 180f * turnSpeed * Time.fixedDeltaTime, 0f); UnityEngine.Vector3 vector2 = owner.transform.position + base.transform.rotation * localOffset; base.transform.position = UnityEngine.Vector3.SmoothDamp(base.transform.position, vector2, ref velocity, positionSmoothTime, float.PositiveInfinity, Time.fixedDeltaTime); fireTimer -= Time.fixedDeltaTime; timeoutTimer -= Time.fixedDeltaTime; if (fireTimer <= 0f) { target = FindTarget(); fireTimer = interval; } if ((bool)target && WillHit(target)) { UnityEngine.Vector3 normalized = (target.transform.position - base.transform.position).normalized; Fire(base.transform.position, normalized); ammo--; target = null; timeoutTimer = timeout; } if (ammo <= 0 || timeoutTimer <= 0f) { UnityEngine.Object.Destroy(base.gameObject); } } } [RequireComponent(typeof(Inventory))] public class GivePickupsOnStart : MonoBehaviour { [Serializable] public struct ItemInfo { public string itemString; public int count; } [Serializable] public struct ItemDefInfo { public ItemDef itemDef; public int count; public bool dontExceedCount; } public EquipmentDef equipmentDef; [ShowFieldObsolete] public string equipmentString; public bool overwriteEquipment = true; public ItemDefInfo[] itemDefInfos; [ShowFieldObsolete] public ItemInfo[] itemInfos; private Inventory inventory; private void Start() { if (!NetworkServer.active) { return; } inventory = GetComponent(); if (overwriteEquipment || inventory.currentEquipmentIndex == EquipmentIndex.None) { if ((bool)equipmentDef) { inventory.SetEquipmentIndex(equipmentDef.equipmentIndex); } else if (!string.IsNullOrEmpty(equipmentString)) { inventory.GiveEquipmentString(equipmentString); } } ItemDefInfo[] array = itemDefInfos; for (int i = 0; i < array.Length; i++) { ItemDefInfo itemDefInfo = array[i]; if ((bool)itemDefInfo.itemDef) { int num = itemDefInfo.count; if (itemDefInfo.dontExceedCount) { num = Math.Max(itemDefInfo.count - inventory.GetItemCount(itemDefInfo.itemDef), 0); } if (num != 0) { inventory.GiveItem(itemDefInfo.itemDef, num); } } } for (int j = 0; j < itemInfos.Length; j++) { ItemInfo itemInfo = itemInfos[j]; inventory.GiveItemString(itemInfo.itemString, itemInfo.count); } } } [ExecuteAlways] public class GlassesSize : MonoBehaviour { public Transform glassesModelBase; public Transform glassesBridgeLeft; public Transform glassesBridgeRight; public float bridgeOffsetScale; public UnityEngine.Vector3 offsetVector = UnityEngine.Vector3.right; private void Start() { } private void Update() { UpdateGlasses(); } private void UpdateGlasses() { UnityEngine.Vector3 localScale = base.transform.localScale; float num = Mathf.Max(localScale.y, localScale.z); UnityEngine.Vector3 localScale2 = new UnityEngine.Vector3(1f / localScale.x * num, 1f / localScale.y * num, 1f / localScale.z * num); if ((bool)glassesModelBase) { glassesModelBase.transform.localScale = localScale2; } if ((bool)glassesBridgeLeft && (bool)glassesBridgeRight) { float num2 = (localScale.x / num - 1f) * bridgeOffsetScale; glassesBridgeLeft.transform.localPosition = offsetVector * (0f - num2); glassesBridgeRight.transform.localPosition = offsetVector * num2; } } } public class GlobalDeathRewards : MonoBehaviour { [Serializable] public struct PickupReward { [SerializeField] public PickupDropTable dropTable; [EnumMask(typeof(CharacterBody.BodyFlags))] [SerializeField] public CharacterBody.BodyFlags requiredBodyFlags; [SerializeField] [Range(0f, 1f)] public float chance; [SerializeField] public UnityEngine.Vector3 velocity; } [SerializeField] private bool requirePlayerAttacker; [SerializeField] private PickupReward[] pickupRewards; private Xoroshiro128Plus rng; private void Start() { if (NetworkServer.active) { rng = new Xoroshiro128Plus(Run.instance.runRNG.nextUlong); } } private void OnEnable() { GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal; } private void OnDisable() { GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal; } private void OnCharacterDeathGlobal(DamageReport damageReport) { if (!NetworkServer.active) { return; } bool flag = true; if (requirePlayerAttacker) { flag = (bool)damageReport.attackerMaster && (bool)damageReport.attackerMaster.GetComponent(); } if (!flag) { return; } PickupReward[] array = pickupRewards; for (int i = 0; i < array.Length; i++) { PickupReward pickupReward = array[i]; if ((damageReport.victimBody.bodyFlags & pickupReward.requiredBodyFlags) == pickupReward.requiredBodyFlags && (bool)pickupReward.dropTable && rng.nextNormalizedFloat <= pickupReward.chance) { PickupDropletController.CreatePickupDroplet(pickupReward.dropTable.GenerateDrop(rng), damageReport.victim.transform.position, pickupReward.velocity); } } } } public class GlobalEventManager : MonoBehaviour { private static class CommonAssets { public static CharacterMaster wispSoulMasterPrefabMasterComponent; public static GameObject igniteOnKillExplosionEffectPrefab; public static GameObject missilePrefab; public static GameObject explodeOnDeathPrefab; public static GameObject daggerPrefab; public static GameObject bleedOnHitAndExplodeImpactEffect; public static GameObject bleedOnHitAndExplodeBlastEffect; public static GameObject minorConstructOnKillProjectile; public static GameObject knockbackFinEffect; public static GameObject runicMeteorEffect; public static GameObject missileVoidPrefab; public static GameObject eliteEarthHealerMaster; public static PickupDropTable dtSonorousEchoPath; public static GameObject loseCoinsImpactEffectPrefab; public static void Load() { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/CharacterMasters/WispSoulMaster"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { wispSoulMasterPrefabMasterComponent = x.Result.GetComponent(); }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/IgniteExplosionVFX"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { igniteOnKillExplosionEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Projectiles/MissileProjectile"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { missilePrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Projectiles/DaggerProjectile"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { daggerPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/BleedOnHitAndExplode_Impact"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { bleedOnHitAndExplodeImpactEffect = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/NetworkedObjects/BleedOnHitAndExplodeDelay"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { bleedOnHitAndExplodeBlastEffect = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Projectiles/MissileVoidProjectile"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { missileVoidPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/KnockBackHitEnemiesImpact"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { knockbackFinEffect = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/RunicMeteorStrikePredictionEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { runicMeteorEffect = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC1/EliteEarth/AffixEarthHealerMaster.prefab"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { eliteEarthHealerMaster = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/Base/ExplodeOnDeath/WilloWispDelay.prefab"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { explodeOnDeathPrefab = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/DLC1/MinorConstructOnKill/MinorConstructOnKillProjectile.prefab"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { minorConstructOnKillProjectile = x.Result; }; AsyncOperationHandle asyncOperationHandle2 = Addressables.LoadAssetAsync("RoR2/DLC2/Items/ResetChests/dtSonorousEcho.asset"); asyncOperationHandle2.Completed += delegate(AsyncOperationHandle x) { dtSonorousEchoPath = x.Result; }; asyncOperationHandle = Addressables.LoadAssetAsync("RoR2/Base/Common/VFX/CoinImpact.prefab"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { loseCoinsImpactEffectPrefab = x.Result; }; } } public static GlobalEventManager instance; [Obsolete("Transform of the global event manager should not be used! You probably meant something else instead.", true)] private new Transform transform; [Obsolete("GameObject of the global event manager should not be used! You probably meant something else instead.", true)] private new GameObject gameObject; private static readonly string[] standardDeathQuoteTokens = (from i in Enumerable.Range(0, 37) select "PLAYER_DEATH_QUOTE_" + TextSerialization.ToStringInvariant(i)).ToArray(); private static readonly string[] fallDamageDeathQuoteTokens = (from i in Enumerable.Range(0, 5) select "PLAYER_DEATH_QUOTE_FALLDAMAGE_" + TextSerialization.ToStringInvariant(i)).ToArray(); private static readonly SphereSearch igniteOnKillSphereSearch = new SphereSearch(); private static readonly List igniteOnKillHurtBoxBuffer = new List(); public static event Action onCharacterDeathGlobal; public static event Action onTeamLevelUp; public static event Action onCharacterLevelUp; public static event Action OnInteractionsGlobal; public static event Action onClientDamageNotified; public static event Action onServerDamageDealt; public static event Action onServerCharacterExecuted; [InitDuringStartup] private static void Init() { CommonAssets.Load(); } private void OnEnable() { if ((bool)instance) { UnityEngine.Debug.LogError("Only one GlobalEventManager can exist at a time."); } else { instance = this; } } private void OnDisable() { if (instance == this) { instance = null; } } public void OnHitEnemy([NotNull] DamageInfo damageInfo, [NotNull] GameObject victim) { ProcessHitEnemy(damageInfo, victim); } private void ProcessHitEnemy([NotNull] DamageInfo damageInfo, [NotNull] GameObject victim) { if (damageInfo.procCoefficient == 0f || damageInfo.rejected || !NetworkServer.active) { return; } if (damageInfo.attacker == null) { HandleDamageWithNoAttacker(damageInfo, victim); } if (!damageInfo.attacker || !(damageInfo.procCoefficient > 0f)) { return; } uint? maxStacksFromAttacker = null; if ((bool)damageInfo?.inflictor) { ProjectileDamage component = damageInfo.inflictor.GetComponent(); if ((bool)component && component.useDotMaxStacksFromAttacker) { maxStacksFromAttacker = component.dotMaxStacksFromAttacker; } } CharacterBody component2 = damageInfo.attacker.GetComponent(); CharacterBody characterBody = (victim ? victim.GetComponent() : null); if ((ulong)(damageInfo.damageType & DamageType.LunarRuin) != 0) { if ((ulong)(damageInfo.damageType & DamageTypeExtended.ApplyBuffPermanently) != 0L) { characterBody.AddTimedBuff(DLC2Content.Buffs.lunarruin, 420f); } else { DotController.InflictDot(characterBody.gameObject, damageInfo.attacker, DotController.DotIndex.LunarRuin, 5f); } } if ((ulong)(damageInfo.damageType & DamageTypeExtended.DisableAllSkills) != 0L) { if ((ulong)(damageInfo.damageType & DamageTypeExtended.ApplyBuffPermanently) != 0L) { UnityEngine.Debug.LogFormat("Adding DisableAllSkills"); characterBody.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 420f); } else { UnityEngine.Debug.LogFormat("Adding DisableAllSkills for 5s"); characterBody.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 5f); } } if (!component2) { return; } if ((ulong)(damageInfo.damageType & DamageType.PoisonOnHit) != 0) { DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Poison, 10f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker); } CharacterMaster master = component2.master; if (!master) { return; } Inventory inventory = master.inventory; TeamComponent component3 = component2.GetComponent(); TeamIndex teamIndex = (component3 ? component3.teamIndex : TeamIndex.Neutral); UnityEngine.Vector3 aimOrigin = component2.aimOrigin; if (damageInfo.crit) { instance.OnCrit(component2, damageInfo, master, damageInfo.procCoefficient, damageInfo.procChainMask); } if (!damageInfo.procChainMask.HasProc(ProcType.HealOnHit)) { int itemCount = inventory.GetItemCount(RoR2Content.Items.Seed); if (itemCount > 0) { HealthComponent component4 = component2.GetComponent(); if ((bool)component4) { ProcChainMask procChainMask = damageInfo.procChainMask; procChainMask.AddProc(ProcType.HealOnHit); component4.Heal((float)itemCount * damageInfo.procCoefficient, procChainMask); } } } if (!damageInfo.procChainMask.HasProc(ProcType.BleedOnHit)) { bool flag = (ulong)(damageInfo.damageType & DamageType.BleedOnHit) != 0 || (inventory.GetItemCount(RoR2Content.Items.BleedOnHitAndExplode) > 0 && damageInfo.crit); if ((component2.bleedChance > 0f || flag) && (flag || Util.CheckRoll(damageInfo.procCoefficient * component2.bleedChance, master))) { ProcChainMask procChainMask2 = damageInfo.procChainMask; procChainMask2.AddProc(ProcType.BleedOnHit); DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Bleed, 3f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker); } } if (!damageInfo.procChainMask.HasProc(ProcType.FractureOnHit)) { int itemCount2 = inventory.GetItemCount(DLC1Content.Items.BleedOnHitVoid); itemCount2 += (component2.HasBuff(DLC1Content.Buffs.EliteVoid) ? 10 : 0); if (itemCount2 > 0 && Util.CheckRoll(damageInfo.procCoefficient * (float)itemCount2 * 10f, master)) { ProcChainMask procChainMask3 = damageInfo.procChainMask; procChainMask3.AddProc(ProcType.FractureOnHit); DotController.DotDef dotDef = DotController.GetDotDef(DotController.DotIndex.Fracture); DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Fracture, dotDef.interval, 1f, maxStacksFromAttacker); } } bool flag2 = (ulong)(damageInfo.damageType & DamageType.BlightOnHit) != 0; if (flag2 && flag2) { _ = damageInfo.procChainMask; DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Blight, 5f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker); } if ((ulong)(damageInfo.damageType & DamageType.WeakOnHit) != 0) { characterBody.AddTimedBuff(RoR2Content.Buffs.Weak, 6f * damageInfo.procCoefficient); } if ((ulong)(damageInfo.damageType & DamageType.IgniteOnHit) != 0 || component2.HasBuff(RoR2Content.Buffs.AffixRed)) { float num = 0.5f; InflictDotInfo inflictDotInfo = default(InflictDotInfo); inflictDotInfo.attackerObject = damageInfo.attacker; inflictDotInfo.victimObject = victim; inflictDotInfo.totalDamage = damageInfo.damage * num; inflictDotInfo.damageMultiplier = 1f; inflictDotInfo.dotIndex = DotController.DotIndex.Burn; inflictDotInfo.maxStacksFromAttacker = maxStacksFromAttacker; InflictDotInfo dotInfo = inflictDotInfo; StrengthenBurnUtils.CheckDotForUpgrade(inventory, ref dotInfo); DotController.InflictDot(ref dotInfo); } int num2 = (component2.HasBuff(RoR2Content.Buffs.AffixWhite) ? 1 : 0); num2 += (component2.HasBuff(RoR2Content.Buffs.AffixHaunted) ? 2 : 0); if (num2 > 0 && (bool)characterBody) { EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/AffixWhiteImpactEffect"), damageInfo.position, UnityEngine.Vector3.up, transmit: true); characterBody.AddTimedBuff(RoR2Content.Buffs.Slow80, 1.5f * damageInfo.procCoefficient * (float)num2); } int itemCount3 = master.inventory.GetItemCount(RoR2Content.Items.SlowOnHit); if (itemCount3 > 0 && (bool)characterBody) { characterBody.AddTimedBuff(RoR2Content.Buffs.Slow60, 2f * (float)itemCount3); } int itemCount4 = master.inventory.GetItemCount(DLC1Content.Items.SlowOnHitVoid); if (itemCount4 > 0 && (bool)characterBody && Util.CheckRoll(Util.ConvertAmplificationPercentageIntoReductionPercentage(5f * (float)itemCount4 * damageInfo.procCoefficient), master)) { characterBody.AddTimedBuff(RoR2Content.Buffs.Nullified, 1f * (float)itemCount4); } if ((component2.HasBuff(RoR2Content.Buffs.AffixPoison) ? 1 : 0) > 0 && (bool)characterBody) { characterBody.AddTimedBuff(RoR2Content.Buffs.HealingDisabled, 8f * damageInfo.procCoefficient); } int itemCount5 = inventory.GetItemCount(RoR2Content.Items.GoldOnHit); if (itemCount5 > 0 && Util.CheckRoll(30f * damageInfo.procCoefficient, master)) { GoldOrb goldOrb = new GoldOrb(); goldOrb.origin = damageInfo.position; goldOrb.target = component2.mainHurtBox; goldOrb.goldAmount = (uint)((float)itemCount5 * 2f * Run.instance.difficultyCoefficient); OrbManager.instance.AddOrb(goldOrb); EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/CoinImpact"), damageInfo.position, UnityEngine.Vector3.up, transmit: true); } if (!damageInfo.procChainMask.HasProc(ProcType.Missile)) { int itemCount6 = inventory.GetItemCount(RoR2Content.Items.Missile); if (itemCount6 > 0) { if (Util.CheckRoll(10f * damageInfo.procCoefficient, master)) { float damageCoefficient = 3f * (float)itemCount6; float missileDamage = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient); MissileUtils.FireMissile(component2.corePosition, component2, damageInfo.procChainMask, victim, missileDamage, damageInfo.crit, CommonAssets.missilePrefab, DamageColorIndex.Item, addMissileProc: true); } } else { itemCount6 = inventory.GetItemCount(DLC1Content.Items.MissileVoid); if (itemCount6 > 0 && component2.healthComponent.shield > 0f) { int valueOrDefault = (component2?.inventory?.GetItemCount(DLC1Content.Items.MoreMissile)).GetValueOrDefault(); float num3 = Mathf.Max(1f, 1f + 0.5f * (float)(valueOrDefault - 1)); float damageCoefficient2 = 0.4f * (float)itemCount6; float damageValue = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient2) * num3; int num4 = ((valueOrDefault <= 0) ? 1 : 3); for (int i = 0; i < num4; i++) { MissileVoidOrb missileVoidOrb = new MissileVoidOrb(); missileVoidOrb.origin = aimOrigin; missileVoidOrb.damageValue = damageValue; missileVoidOrb.isCrit = damageInfo.crit; missileVoidOrb.teamIndex = teamIndex; missileVoidOrb.attacker = damageInfo.attacker; missileVoidOrb.procChainMask = damageInfo.procChainMask; missileVoidOrb.procChainMask.AddProc(ProcType.Missile); missileVoidOrb.procCoefficient = 0.2f; missileVoidOrb.damageColorIndex = DamageColorIndex.Void; HurtBox mainHurtBox = characterBody.mainHurtBox; if ((bool)mainHurtBox) { missileVoidOrb.target = mainHurtBox; OrbManager.instance.AddOrb(missileVoidOrb); } } } } } if (component2.HasBuff(JunkContent.Buffs.LoaderPylonPowered) && !damageInfo.procChainMask.HasProc(ProcType.LoaderLightning)) { float damageCoefficient3 = 0.3f; float damageValue2 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient3); LightningOrb lightningOrb = new LightningOrb(); lightningOrb.origin = damageInfo.position; lightningOrb.damageValue = damageValue2; lightningOrb.isCrit = damageInfo.crit; lightningOrb.bouncesRemaining = 3; lightningOrb.teamIndex = teamIndex; lightningOrb.attacker = damageInfo.attacker; lightningOrb.bouncedObjects = new List { victim.GetComponent() }; lightningOrb.procChainMask = damageInfo.procChainMask; lightningOrb.procChainMask.AddProc(ProcType.LoaderLightning); lightningOrb.procCoefficient = 0f; lightningOrb.lightningType = LightningOrb.LightningType.Loader; lightningOrb.damageColorIndex = DamageColorIndex.Item; lightningOrb.range = 20f; HurtBox hurtBox = lightningOrb.PickNextTarget(damageInfo.position); if ((bool)hurtBox) { lightningOrb.target = hurtBox; OrbManager.instance.AddOrb(lightningOrb); } } int itemCount7 = inventory.GetItemCount(RoR2Content.Items.ChainLightning); float num5 = 25f; if (itemCount7 > 0 && !damageInfo.procChainMask.HasProc(ProcType.ChainLightning) && Util.CheckRoll(num5 * damageInfo.procCoefficient, master)) { float damageCoefficient4 = 0.8f; float damageValue3 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient4); LightningOrb lightningOrb2 = new LightningOrb(); lightningOrb2.origin = damageInfo.position; lightningOrb2.damageValue = damageValue3; lightningOrb2.isCrit = damageInfo.crit; lightningOrb2.bouncesRemaining = 2 * itemCount7; lightningOrb2.teamIndex = teamIndex; lightningOrb2.attacker = damageInfo.attacker; lightningOrb2.bouncedObjects = new List { victim.GetComponent() }; lightningOrb2.procChainMask = damageInfo.procChainMask; lightningOrb2.procChainMask.AddProc(ProcType.ChainLightning); lightningOrb2.procCoefficient = 0.2f; lightningOrb2.lightningType = LightningOrb.LightningType.Ukulele; lightningOrb2.damageColorIndex = DamageColorIndex.Item; lightningOrb2.range += 2 * itemCount7; HurtBox hurtBox2 = lightningOrb2.PickNextTarget(damageInfo.position); if ((bool)hurtBox2) { lightningOrb2.target = hurtBox2; OrbManager.instance.AddOrb(lightningOrb2); } } int itemCount8 = inventory.GetItemCount(DLC1Content.Items.ChainLightningVoid); float num6 = 25f; if (itemCount8 > 0 && !damageInfo.procChainMask.HasProc(ProcType.ChainLightning) && Util.CheckRoll(num6 * damageInfo.procCoefficient, master)) { float damageCoefficient5 = 0.6f; float damageValue4 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient5); VoidLightningOrb voidLightningOrb = new VoidLightningOrb(); voidLightningOrb.origin = damageInfo.position; voidLightningOrb.damageValue = damageValue4; voidLightningOrb.isCrit = damageInfo.crit; voidLightningOrb.totalStrikes = 3 * itemCount8; voidLightningOrb.teamIndex = teamIndex; voidLightningOrb.attacker = damageInfo.attacker; voidLightningOrb.procChainMask = damageInfo.procChainMask; voidLightningOrb.procChainMask.AddProc(ProcType.ChainLightning); voidLightningOrb.procCoefficient = 0.2f; voidLightningOrb.damageColorIndex = DamageColorIndex.Void; voidLightningOrb.secondsPerStrike = 0.1f; HurtBox mainHurtBox2 = characterBody.mainHurtBox; if ((bool)mainHurtBox2) { voidLightningOrb.target = mainHurtBox2; OrbManager.instance.AddOrb(voidLightningOrb); } } int itemCount9 = inventory.GetItemCount(RoR2Content.Items.BounceNearby); if (itemCount9 > 0) { float num7 = (1f - 100f / (100f + 20f * (float)itemCount9)) * 100f; if (!damageInfo.procChainMask.HasProc(ProcType.BounceNearby) && Util.CheckRoll(num7 * damageInfo.procCoefficient, master)) { List list = CollectionPool>.RentCollection(); int maxTargets = 5 + itemCount9 * 5; BullseyeSearch search = new BullseyeSearch(); List list2 = CollectionPool>.RentCollection(); if ((bool)component2 && (bool)component2.healthComponent) { list2.Add(component2.healthComponent); } if ((bool)characterBody && (bool)characterBody.healthComponent) { list2.Add(characterBody.healthComponent); } BounceOrb.SearchForTargets(search, teamIndex, damageInfo.position, 30f, maxTargets, list, list2); CollectionPool>.ReturnCollection(list2); List bouncedObjects = new List { victim.GetComponent() }; float damageCoefficient6 = 1f; float damageValue5 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient6); int j = 0; for (int count = list.Count; j < count; j++) { HurtBox hurtBox3 = list[j]; if ((bool)hurtBox3) { BounceOrb bounceOrb = new BounceOrb(); bounceOrb.origin = damageInfo.position; bounceOrb.damageValue = damageValue5; bounceOrb.isCrit = damageInfo.crit; bounceOrb.teamIndex = teamIndex; bounceOrb.attacker = damageInfo.attacker; bounceOrb.procChainMask = damageInfo.procChainMask; bounceOrb.procChainMask.AddProc(ProcType.BounceNearby); bounceOrb.procCoefficient = 0.33f; bounceOrb.damageColorIndex = DamageColorIndex.Item; bounceOrb.bouncedObjects = bouncedObjects; bounceOrb.target = hurtBox3; OrbManager.instance.AddOrb(bounceOrb); } } CollectionPool>.ReturnCollection(list); } } int itemCount10 = inventory.GetItemCount(RoR2Content.Items.StickyBomb); if (itemCount10 > 0 && Util.CheckRoll(5f * (float)itemCount10 * damageInfo.procCoefficient, master) && (bool)characterBody) { bool alive = characterBody.healthComponent.alive; float num8 = 5f; UnityEngine.Vector3 position = damageInfo.position; UnityEngine.Vector3 forward = characterBody.corePosition - position; float magnitude = forward.magnitude; UnityEngine.Quaternion rotation = ((magnitude != 0f) ? Util.QuaternionSafeLookRotation(forward) : UnityEngine.Random.rotationUniform); float damageCoefficient7 = 1.8f; float damage = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient7); ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load("Prefabs/Projectiles/StickyBomb"), position, rotation, damageInfo.attacker, damage, 100f, damageInfo.crit, DamageColorIndex.Item, null, alive ? (magnitude * num8) : (-1f)); } if (!damageInfo.procChainMask.HasProc(ProcType.Rings) && damageInfo.damage / component2.damage >= 4f) { if (component2.HasBuff(RoR2Content.Buffs.ElementalRingsReady)) { int itemCount11 = inventory.GetItemCount(RoR2Content.Items.IceRing); int itemCount12 = inventory.GetItemCount(RoR2Content.Items.FireRing); component2.RemoveBuff(RoR2Content.Buffs.ElementalRingsReady); for (int k = 1; (float)k <= 10f; k++) { component2.AddTimedBuff(RoR2Content.Buffs.ElementalRingsCooldown, k); } ProcChainMask procChainMask4 = damageInfo.procChainMask; procChainMask4.AddProc(ProcType.Rings); UnityEngine.Vector3 position2 = damageInfo.position; if (itemCount11 > 0) { float damageCoefficient8 = 2.5f * (float)itemCount11; float damage2 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient8); DamageInfo damageInfo2 = new DamageInfo { damage = damage2, damageColorIndex = DamageColorIndex.Item, damageType = DamageType.Generic, attacker = damageInfo.attacker, crit = damageInfo.crit, force = UnityEngine.Vector3.zero, inflictor = null, position = position2, procChainMask = procChainMask4, procCoefficient = 1f }; EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/IceRingExplosion"), position2, UnityEngine.Vector3.up, transmit: true); characterBody.AddTimedBuff(RoR2Content.Buffs.Slow80, 3f * (float)itemCount11); characterBody.healthComponent.TakeDamage(damageInfo2); } if (itemCount12 > 0) { GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Projectiles/FireTornado"); float resetInterval = gameObject.GetComponent().resetInterval; float lifetime = gameObject.GetComponent().lifetime; float damageCoefficient9 = 3f * (float)itemCount12; float damage3 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient9) / lifetime * resetInterval; float speedOverride = 0f; UnityEngine.Quaternion rotation2 = UnityEngine.Quaternion.identity; UnityEngine.Vector3 vector = position2 - aimOrigin; vector.y = 0f; if (vector != UnityEngine.Vector3.zero) { speedOverride = -1f; rotation2 = Util.QuaternionSafeLookRotation(vector, UnityEngine.Vector3.up); } ProjectileManager.instance.FireProjectile(new FireProjectileInfo { damage = damage3, crit = damageInfo.crit, damageColorIndex = DamageColorIndex.Item, position = position2, procChainMask = procChainMask4, force = 0f, owner = damageInfo.attacker, projectilePrefab = gameObject, rotation = rotation2, speedOverride = speedOverride, target = null }); } } else if (component2.HasBuff(DLC1Content.Buffs.ElementalRingVoidReady)) { int itemCount13 = inventory.GetItemCount(DLC1Content.Items.ElementalRingVoid); component2.RemoveBuff(DLC1Content.Buffs.ElementalRingVoidReady); for (int l = 1; (float)l <= 20f; l++) { component2.AddTimedBuff(DLC1Content.Buffs.ElementalRingVoidCooldown, l); } ProcChainMask procChainMask5 = damageInfo.procChainMask; procChainMask5.AddProc(ProcType.Rings); if (itemCount13 > 0) { GameObject projectilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/ElementalRingVoidBlackHole"); float damageCoefficient10 = 1f * (float)itemCount13; float damage4 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient10); ProjectileManager.instance.FireProjectile(new FireProjectileInfo { damage = damage4, crit = damageInfo.crit, damageColorIndex = DamageColorIndex.Void, position = damageInfo.position, procChainMask = procChainMask5, force = 6000f, owner = damageInfo.attacker, projectilePrefab = projectilePrefab, rotation = UnityEngine.Quaternion.identity, target = null }); } } } int itemCount14 = master.inventory.GetItemCount(RoR2Content.Items.DeathMark); int num9 = 0; if (itemCount14 >= 1 && !characterBody.HasBuff(RoR2Content.Buffs.DeathMark)) { BuffIndex[] debuffBuffIndices = BuffCatalog.debuffBuffIndices; foreach (BuffIndex buffType in debuffBuffIndices) { if (characterBody.HasBuff(buffType)) { num9++; } } DotController dotController = DotController.FindDotController(victim.gameObject); if ((bool)dotController) { for (DotController.DotIndex dotIndex = DotController.DotIndex.Bleed; dotIndex < DotController.DotIndex.Count; dotIndex++) { if (dotController.HasDotActive(dotIndex)) { num9++; } } } if (num9 >= 4) { characterBody.AddTimedBuff(RoR2Content.Buffs.DeathMark, 7f * (float)itemCount14); } } if (damageInfo != null && damageInfo.inflictor != null && damageInfo.inflictor.GetComponent() != null && !damageInfo.procChainMask.HasProc(ProcType.BleedOnHit)) { int num10 = 0; if (inventory.GetEquipmentIndex() == RoR2Content.Equipment.Saw.equipmentIndex) { num10 = 1; } bool flag3 = (ulong)(damageInfo.damageType & DamageType.BleedOnHit) != 0; if ((num10 > 0 || flag3) && (flag3 || Util.CheckRoll(100f, master))) { ProcChainMask procChainMask6 = damageInfo.procChainMask; procChainMask6.AddProc(ProcType.BleedOnHit); DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Bleed, 4f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker); } } if (damageInfo.crit && (ulong)(damageInfo.damageType & DamageType.SuperBleedOnCrit) != 0L) { DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.SuperBleed, 15f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker); } if (component2.HasBuff(RoR2Content.Buffs.LifeSteal)) { float amount = damageInfo.damage * 0.2f; component2.healthComponent.Heal(amount, damageInfo.procChainMask); } int itemCount15 = inventory.GetItemCount(RoR2Content.Items.FireballsOnHit); if (itemCount15 > 0 && !damageInfo.procChainMask.HasProc(ProcType.Meatball)) { InputBankTest component5 = component2.GetComponent(); UnityEngine.Vector3 vector2 = (characterBody.characterMotor ? (victim.transform.position + UnityEngine.Vector3.up * (characterBody.characterMotor.capsuleHeight * 0.5f + 2f)) : (victim.transform.position + UnityEngine.Vector3.up * 2f)); UnityEngine.Vector3 vector3 = (component5 ? component5.aimDirection : victim.transform.forward); vector3 = UnityEngine.Vector3.up; float num11 = 20f; if (Util.CheckRoll(10f * damageInfo.procCoefficient, master)) { EffectData effectData = new EffectData { scale = 1f, origin = vector2 }; EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/MuzzleFlashes/MuzzleflashFireMeatBall"), effectData, transmit: true); int num12 = 3; float damageCoefficient11 = 3f * (float)itemCount15; float damage5 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient11); float maxInclusive = 30f; ProcChainMask procChainMask7 = damageInfo.procChainMask; procChainMask7.AddProc(ProcType.Meatball); float speedOverride2 = UnityEngine.Random.Range(15f, maxInclusive); float num13 = 360 / num12; _ = num13 / 360f; float num14 = 1f; float num15 = num13; for (int n = 0; n < num12; n++) { float num16 = (float)n * MathF.PI * 2f / (float)num12; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/FireMeatBall"); fireProjectileInfo.position = vector2 + new UnityEngine.Vector3(num14 * Mathf.Sin(num16), 0f, num14 * Mathf.Cos(num16)); fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(vector3); fireProjectileInfo.procChainMask = procChainMask7; fireProjectileInfo.target = victim; fireProjectileInfo.owner = component2.gameObject; fireProjectileInfo.damage = damage5; fireProjectileInfo.crit = damageInfo.crit; fireProjectileInfo.force = 200f; fireProjectileInfo.damageColorIndex = DamageColorIndex.Item; fireProjectileInfo.speedOverride = speedOverride2; fireProjectileInfo.useSpeedOverride = true; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; num15 += num13; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); vector3.x += Mathf.Sin(num16 + UnityEngine.Random.Range(0f - num11, num11)); vector3.z += Mathf.Cos(num16 + UnityEngine.Random.Range(0f - num11, num11)); } } } int itemCount16 = inventory.GetItemCount(RoR2Content.Items.LightningStrikeOnHit); if (itemCount16 > 0 && !damageInfo.procChainMask.HasProc(ProcType.LightningStrikeOnHit) && Util.CheckRoll(10f * damageInfo.procCoefficient, master)) { float damageValue6 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, 5f * (float)itemCount16); ProcChainMask procChainMask8 = damageInfo.procChainMask; procChainMask8.AddProc(ProcType.LightningStrikeOnHit); HurtBox target = characterBody.mainHurtBox; if ((bool)characterBody.hurtBoxGroup) { target = characterBody.hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, characterBody.hurtBoxGroup.hurtBoxes.Length)]; } OrbManager.instance.AddOrb(new SimpleLightningStrikeOrb { attacker = component2.gameObject, damageColorIndex = DamageColorIndex.Item, damageValue = damageValue6, isCrit = Util.CheckRoll(component2.crit, master), procChainMask = procChainMask8, procCoefficient = 1f, target = target }); } if ((ulong)(damageInfo.damageType & DamageType.LunarSecondaryRootOnHit) != 0L && (bool)characterBody) { int itemCount17 = master.inventory.GetItemCount(RoR2Content.Items.LunarSecondaryReplacement); characterBody.AddTimedBuff(RoR2Content.Buffs.LunarSecondaryRoot, 3f * (float)itemCount17); } if ((ulong)(damageInfo.damageType & DamageType.FruitOnHit) != 0L && (bool)characterBody) { characterBody.AddTimedBuff(RoR2Content.Buffs.Fruiting, 10f); } if (inventory.GetItemCount(DLC1Content.Items.DroneWeaponsBoost) > 0) { DroneWeaponsBoostBehavior component6 = component2.GetComponent(); if ((bool)component6) { component6.OnEnemyHit(damageInfo, characterBody); } } if (victim.tag != "Player" && inventory.GetItemCount(DLC2Content.Items.IncreaseDamageOnMultiKill) > 0) { component2.AddIncreasedDamageMultiKillTime(); } if (component2.luminousShotReady) { DamageInfo damageInfo3 = new DamageInfo { damage = component2.luminousShotDamage, damageColorIndex = DamageColorIndex.Luminous, damageType = DamageType.Generic, attacker = component2.gameObject, position = characterBody.transform.position, crit = damageInfo.crit, force = UnityEngine.Vector3.zero, inflictor = null, procCoefficient = 1f }; characterBody.healthComponent.TakeDamage(damageInfo3); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/IncreasePrimaryDamageImpact"), new EffectData { origin = characterBody.transform.position }, transmit: true); component2.IncreasePrimaryDamageReset(); Util.PlaySound("Play_item_proc_increasePrimaryDamage", characterBody.gameObject); } if (component2.HasBuff(DLC2Content.Buffs.CookingRolling)) { characterBody.AddBuff(DLC2Content.Buffs.CookingRolled); } else if (component2.HasBuff(DLC2Content.Buffs.CookingSearing)) { characterBody.AddBuff(DLC2Content.Buffs.CookingRoasted); } if (characterBody.HasBuff(DLC2Content.Buffs.CookingOiled) && component2.HasBuff(DLC2Content.Buffs.CookingSearing)) { characterBody.AddBuff(DLC2Content.Buffs.CookingFlambe); characterBody.RemoveBuff(DLC2Content.Buffs.CookingOiled); } if (characterBody.HasBuff(DLC2Content.Buffs.CookingFlambe) && (DamageTypeExtended)damageInfo.damageType == DamageTypeExtended.ChefSearDamage) { float num17 = 0.75f; InflictDotInfo inflictDotInfo = default(InflictDotInfo); inflictDotInfo.attackerObject = damageInfo.attacker; inflictDotInfo.victimObject = victim; inflictDotInfo.totalDamage = component2.damage * num17; inflictDotInfo.damageMultiplier = 1f; inflictDotInfo.dotIndex = DotController.DotIndex.StrongerBurn; inflictDotInfo.maxStacksFromAttacker = maxStacksFromAttacker; InflictDotInfo dotInfo2 = inflictDotInfo; StrengthenBurnUtils.CheckDotForUpgrade(inventory, ref dotInfo2); for (int num18 = 0; num18 < 3; num18++) { DotController.InflictDot(ref dotInfo2); } } int itemCount18 = inventory.GetItemCount(DLC2Content.Items.MeteorAttackOnHighDamage); if (itemCount18 > 0 && !damageInfo.procChainMask.HasProc(ProcType.MeteorAttackOnHighDamage)) { float num19 = 0f; float num20 = (int)(damageInfo.damage / component2.damage); num19 = 5f + 1f * num20 * (float)itemCount18; if (num19 > 50f) { num19 = 50f; } if (Util.CheckRoll(num19 * damageInfo.procCoefficient, master)) { ProcChainMask procChainMask9 = damageInfo.procChainMask; procChainMask9.AddProc(ProcType.MeteorAttackOnHighDamage); float num21 = 20f + 0.5f * (float)itemCount18 * num20; if (num21 > 75f) { num21 = 75f; } num21 *= component2.damage; UnityEngine.Vector3 vector4 = damageInfo.position; float num22 = 10f; float blastForce = 5000f; UnityEngine.Vector3 origin = vector4 + UnityEngine.Vector3.up * 6f; UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere; onUnitSphere.y = -1f; if (Physics.Raycast(origin, onUnitSphere, out var hitInfo, 12f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { vector4 = hitInfo.point; } else if (Physics.Raycast(vector4, UnityEngine.Vector3.down, out hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { vector4 = hitInfo.point; } if (!component2.runicLensMeteorReady) { Util.PlaySound("Play_item_proc_meteorAttackOnHighDamage", component2.gameObject); EffectManager.SpawnEffect(CommonAssets.runicMeteorEffect, new EffectData { origin = vector4, scale = num22 }, transmit: true); new EffectData().origin = vector4; component2.runicLensUpdateVariables(num21, vector4, damageInfo, blastForce, num22); } } } int itemCount19 = inventory.GetItemCount(DLC2Content.Items.KnockBackHitEnemies); if (itemCount19 > 0 && !characterBody.isBoss) { CharacterMotor component7 = victim.GetComponent(); victim.GetComponent(); if ((bool)component7 && component7.isGrounded && !characterBody.isChampion && (characterBody.bodyFlags & CharacterBody.BodyFlags.IgnoreFallDamage) == 0 && !characterBody.HasBuff(DLC2Content.Buffs.KnockUpHitEnemies) && Util.CheckRoll(Util.ConvertAmplificationPercentageIntoReductionPercentage(7.5f * (float)itemCount19 * damageInfo.procCoefficient))) { Ray aimRay = component2.inputBank.GetAimRay(); characterBody.AddTimedBuff(DLC2Content.Buffs.KnockUpHitEnemies, 5f); float scale = 1f; switch (characterBody.hullClassification) { case HullClassification.Human: scale = 1f; break; case HullClassification.Golem: scale = 5f; break; case HullClassification.BeetleQueen: scale = 10f; break; } EffectManager.SpawnEffect(CommonAssets.knockbackFinEffect, new EffectData { origin = characterBody.gameObject.transform.position, scale = scale }, transmit: true); if (!characterBody.mainHurtBox) { _ = characterBody.transform; } else { _ = characterBody.mainHurtBox.transform; } UnityEngine.Vector3 vector5 = new UnityEngine.Vector3(0f, 1f, 0f); float num23 = component7.mass * 20f; float num24 = num23 + num23 / 10f * (float)(itemCount19 - 1); component7.ApplyForce(num24 * vector5); component7.ApplyForce(num24 / 2f * aimRay.direction); Util.PlaySound("Play_item_proc_knockBackHitEnemies", component2.gameObject); } } int itemCount20 = inventory.GetItemCount(DLC2Content.Items.StunAndPierce); if (itemCount20 > 0 && !damageInfo.procChainMask.HasProc(ProcType.StunAndPierceDamage) && Util.CheckRoll(15f * damageInfo.procCoefficient, master)) { float damage6 = component2.damage * 0.3f * (float)itemCount20; ProcChainMask procChainMask10 = damageInfo.procChainMask; procChainMask10.AddProc(ProcType.StunAndPierceDamage); UnityEngine.Quaternion rotation3 = UnityEngine.Quaternion.LookRotation(new Ray(component2.inputBank.aimOrigin, component2.inputBank.aimDirection).direction); GameObject projectilePrefab2 = LegacyResourcesAPI.Load("Prefabs/Projectiles/StunAndPierceBoomerang"); FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab2; fireProjectileInfo.crit = component2.RollCrit(); fireProjectileInfo.damage = damage6; fireProjectileInfo.damageColorIndex = DamageColorIndex.Item; fireProjectileInfo.force = 0f; fireProjectileInfo.owner = component2.gameObject; fireProjectileInfo.position = aimOrigin; fireProjectileInfo.rotation = rotation3; FireProjectileInfo fireProjectileInfo3 = fireProjectileInfo; fireProjectileInfo3.procChainMask = procChainMask10; ProjectileManager.instance.FireProjectile(fireProjectileInfo3); } if (characterBody.HasBuff(DLC2Content.Buffs.EliteBeadCorruption) && !component2.HasBuff(DLC2Content.Buffs.EliteBead) && !damageInfo.procChainMask.HasProc(ProcType.Thorns)) { float damageValue7 = component2.maxHealth * 0.025f; component2.RollCrit(); _ = characterBody.teamComponent.teamIndex; LightningOrb lightningOrb3 = new LightningOrb(); lightningOrb3.attacker = characterBody.gameObject; lightningOrb3.bouncedObjects = null; lightningOrb3.bouncesRemaining = 0; lightningOrb3.damageCoefficientPerBounce = 1f; lightningOrb3.damageColorIndex = DamageColorIndex.WeakPoint; lightningOrb3.damageValue = damageValue7; lightningOrb3.isCrit = false; lightningOrb3.lightningType = LightningOrb.LightningType.BeadDamage; lightningOrb3.origin = characterBody.transform.position; lightningOrb3.procChainMask = default(ProcChainMask); lightningOrb3.procChainMask.AddProc(ProcType.Thorns); lightningOrb3.procCoefficient = 0.3f; lightningOrb3.range = 0f; lightningOrb3.target = component2.mainHurtBox; OrbManager.instance.AddOrb(lightningOrb3); } if (component2.HasBuff(DLC2Content.Buffs.EliteAurelionite)) { CharacterMaster master2 = component2.master; int baseCost = 2; int difficultyScaledCost = Run.instance.GetDifficultyScaledCost(baseCost); uint money = master2.money; master2.money = (uint)Mathf.Max(0f, (float)master2.money - (float)difficultyScaledCost); if (money - master2.money != 0) { GoldOrb goldOrb2 = new GoldOrb(); goldOrb2.origin = damageInfo.position; goldOrb2.target = (component2 ? component2.mainHurtBox : characterBody.mainHurtBox); goldOrb2.goldAmount = (uint)difficultyScaledCost + (uint)((float)difficultyScaledCost * 0.2f); OrbManager.instance.AddOrb(goldOrb2); EffectManager.SimpleImpactEffect(CommonAssets.loseCoinsImpactEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true); } } } private void HandleDamageWithNoAttacker([NotNull] DamageInfo damageInfo, [NotNull] GameObject victim) { CharacterBody characterBody = (victim ? victim.GetComponent() : null); if (characterBody == null) { return; } if ((ulong)(damageInfo.damageType & DamageType.LunarRuin) != 0) { if ((ulong)(damageInfo.damageType & DamageTypeExtended.ApplyBuffPermanently) != 0L) { characterBody.AddTimedBuff(DLC2Content.Buffs.lunarruin, 420f); } else { DotController.InflictDot(characterBody.gameObject, damageInfo.attacker, DotController.DotIndex.LunarRuin, 5f); } } if ((ulong)(damageInfo.damageType & DamageTypeExtended.DisableAllSkills) != 0L) { if ((ulong)(damageInfo.damageType & DamageTypeExtended.ApplyBuffPermanently) != 0L) { UnityEngine.Debug.LogFormat("Adding DisableAllSkills"); characterBody.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 420f); } else { UnityEngine.Debug.LogFormat("Adding DisableAllSkills for 5s"); characterBody.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 5f); } } } public void OnCharacterHitGroundServer(CharacterBody characterBody, CharacterMotor.HitGroundInfo hitGroundInfo) { bool flag = RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.weakAssKneesArtifactDef); float num = Mathf.Abs(hitGroundInfo.velocity.y); Inventory inventory = characterBody.inventory; _ = characterBody.master; CharacterMotor characterMotor = characterBody.characterMotor; bool tookFallDamage = false; if ((((bool)inventory && inventory.GetItemCount(RoR2Content.Items.FallBoots) != 0) ? 1 : 0) <= (false ? 1 : 0) && (characterBody.bodyFlags & CharacterBody.BodyFlags.IgnoreFallDamage) == 0) { float num2 = Mathf.Max(num - (characterBody.jumpPower + 20f), 0f); if (num2 > 0f) { HealthComponent component = characterBody.GetComponent(); if ((bool)component) { tookFallDamage = true; float num3 = num2 / 60f; DamageInfo damageInfo = new DamageInfo { attacker = null, inflictor = null, crit = false, damage = num3 * characterBody.maxHealth, damageType = (DamageType.NonLethal | DamageType.FallDamage), force = UnityEngine.Vector3.zero, position = characterBody.footPosition, procCoefficient = 0f }; if (flag || (characterBody.teamComponent.teamIndex == TeamIndex.Player && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse3)) { damageInfo.damage *= 2f; damageInfo.damageType &= (DamageTypeCombo)(~DamageType.NonLethal); damageInfo.damageType |= (DamageTypeCombo)DamageType.BypassOneShotProtection; } component.TakeDamage(damageInfo); } } } OnCharacterHitGroundSFX(characterBody, hitGroundInfo, tookFallDamage); characterMotor.CallRpcOnHitGroundSFX(hitGroundInfo, tookFallDamage); } public void OnCharacterHitGroundSFX(CharacterBody characterBody, CharacterMotor.HitGroundInfo hitGroundInfo, bool tookFallDamage) { CharacterMotor characterMotor = characterBody.characterMotor; if (!characterMotor || (!hitGroundInfo.isValidForEffect && !(Run.FixedTimeStamp.now - characterMotor.lastGroundedTime > 0.2f))) { return; } UnityEngine.Vector3 footPosition = characterBody.footPosition; float radius = characterBody.radius; if (!Physics.Raycast(new Ray(footPosition + UnityEngine.Vector3.up * 1.5f, UnityEngine.Vector3.down), out var hitInfo, 4f, (int)LayerIndex.world.mask | (int)LayerIndex.water.mask, QueryTriggerInteraction.Collide)) { return; } SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitInfo.collider, hitInfo.point); if (!objectSurfaceDef) { return; } if (NetworkServer.active) { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/CharacterLandImpact"), new EffectData { origin = footPosition, scale = radius, color = objectSurfaceDef.approximateColor }, transmit: true); } if ((bool)objectSurfaceDef.footstepEffectPrefab) { EffectManager.SpawnEffect(objectSurfaceDef.footstepEffectPrefab, new EffectData { origin = hitInfo.point, scale = radius * 3f }, transmit: false); } SfxLocator component = characterBody.GetComponent(); if ((bool)component) { if (objectSurfaceDef.materialSwitchString != null && objectSurfaceDef.materialSwitchString.Length > 0) { AkSoundEngine.SetSwitch("material", objectSurfaceDef.materialSwitchString, characterBody.gameObject); } else { AkSoundEngine.SetSwitch("material", "dirt", characterBody.gameObject); } Util.PlaySound(component.landingSound, characterBody.gameObject); if (tookFallDamage) { Util.PlaySound(component.fallDamageSound, characterBody.gameObject); } } } [Obsolete("Use OnCharacterHitGroundServer instead, which this is just a backwards-compatibility wrapper for.", false)] public void OnCharacterHitGround(CharacterBody characterBody, UnityEngine.Vector3 impactVelocity) { OnCharacterHitGroundServer(characterBody, new CharacterMotor.HitGroundInfo { velocity = impactVelocity }); } private void OnPlayerCharacterDeath(DamageReport damageReport, NetworkUser victimNetworkUser) { if ((bool)victimNetworkUser) { CharacterBody victimBody = damageReport.victimBody; string text = (((ulong)(damageReport.damageInfo.damageType & DamageType.VoidDeath) != 0L) ? "PLAYER_DEATH_QUOTE_VOIDDEATH" : (damageReport.isFallDamage ? fallDamageDeathQuoteTokens[UnityEngine.Random.Range(0, fallDamageDeathQuoteTokens.Length)] : ((!victimBody || !victimBody.inventory || victimBody.inventory.GetItemCount(RoR2Content.Items.LunarDagger) <= 0) ? standardDeathQuoteTokens[UnityEngine.Random.Range(0, standardDeathQuoteTokens.Length)] : "PLAYER_DEATH_QUOTE_BRITTLEDEATH"))); if ((bool)victimNetworkUser.masterController) { victimNetworkUser.masterController.finalMessageTokenServer = text; } Chat.SendBroadcastChat(new Chat.PlayerDeathChatMessage { subjectAsNetworkUser = victimNetworkUser, baseToken = text }); } } private static void ProcIgniteOnKill(DamageReport damageReport, int igniteOnKillCount, CharacterBody victimBody, TeamIndex attackerTeamIndex) { float num = 8f + 4f * (float)igniteOnKillCount; float radius = victimBody.radius; float num2 = num + radius; float num3 = 1.5f; float baseDamage = damageReport.attackerBody.damage * num3; UnityEngine.Vector3 corePosition = victimBody.corePosition; igniteOnKillSphereSearch.origin = corePosition; igniteOnKillSphereSearch.mask = LayerIndex.entityPrecise.mask; igniteOnKillSphereSearch.radius = num2; igniteOnKillSphereSearch.RefreshCandidates(); igniteOnKillSphereSearch.FilterCandidatesByHurtBoxTeam(TeamMask.GetUnprotectedTeams(attackerTeamIndex)); igniteOnKillSphereSearch.FilterCandidatesByDistinctHurtBoxEntities(); igniteOnKillSphereSearch.OrderCandidatesByDistance(); igniteOnKillSphereSearch.GetHurtBoxes(igniteOnKillHurtBoxBuffer); igniteOnKillSphereSearch.ClearCandidates(); float value = (float)(1 + igniteOnKillCount) * 0.75f * damageReport.attackerBody.damage; for (int i = 0; i < igniteOnKillHurtBoxBuffer.Count; i++) { HurtBox hurtBox = igniteOnKillHurtBoxBuffer[i]; if ((bool)hurtBox.healthComponent) { InflictDotInfo inflictDotInfo = default(InflictDotInfo); inflictDotInfo.victimObject = hurtBox.healthComponent.gameObject; inflictDotInfo.attackerObject = damageReport.attacker; inflictDotInfo.totalDamage = value; inflictDotInfo.dotIndex = DotController.DotIndex.Burn; inflictDotInfo.damageMultiplier = 1f; InflictDotInfo dotInfo = inflictDotInfo; if ((bool)damageReport?.attackerMaster?.inventory) { StrengthenBurnUtils.CheckDotForUpgrade(damageReport.attackerMaster.inventory, ref dotInfo); } DotController.InflictDot(ref dotInfo); } } igniteOnKillHurtBoxBuffer.Clear(); BlastAttack blastAttack = new BlastAttack(); blastAttack.radius = num2; blastAttack.baseDamage = baseDamage; blastAttack.procCoefficient = 0f; blastAttack.crit = Util.CheckRoll(damageReport.attackerBody.crit, damageReport.attackerMaster); blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.attackerFiltering = AttackerFiltering.Default; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.attacker = damageReport.attacker; blastAttack.teamIndex = attackerTeamIndex; blastAttack.position = corePosition; blastAttack.Fire(); EffectManager.SpawnEffect(CommonAssets.igniteOnKillExplosionEffectPrefab, new EffectData { origin = corePosition, scale = num2, rotation = Util.QuaternionSafeLookRotation(damageReport.damageInfo.force) }, transmit: true); } public void OnCharacterDeath(DamageReport damageReport) { if (!NetworkServer.active || damageReport == null) { return; } DamageInfo damageInfo = damageReport.damageInfo; GameObject gameObject = null; if ((bool)damageReport.victim) { gameObject = damageReport.victim.gameObject; } CharacterBody victimBody = damageReport.victimBody; TeamComponent teamComponent = null; CharacterMaster victimMaster = damageReport.victimMaster; TeamIndex teamIndex = damageReport.victimTeamIndex; UnityEngine.Vector3 vector = UnityEngine.Vector3.zero; UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.identity; UnityEngine.Vector3 vector2 = UnityEngine.Vector3.zero; Transform transform = gameObject.transform; if ((bool)transform) { vector = transform.position; quaternion = transform.rotation; vector2 = vector; } InputBankTest inputBankTest = null; EquipmentIndex equipmentIndex = EquipmentIndex.None; EquipmentDef equipmentDef = null; if ((bool)victimBody) { teamComponent = victimBody.teamComponent; inputBankTest = victimBody.inputBank; vector2 = victimBody.corePosition; if ((bool)victimBody.equipmentSlot) { equipmentIndex = victimBody.equipmentSlot.equipmentIndex; equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); } } Ray ray = (inputBankTest ? inputBankTest.GetAimRay() : new Ray(vector, quaternion * UnityEngine.Vector3.forward)); GameObject attacker = damageReport.attacker; CharacterBody attackerBody = damageReport.attackerBody; CharacterMaster attackerMaster = damageReport.attackerMaster; Inventory inventory = (attackerMaster ? attackerMaster.inventory : null); TeamIndex attackerTeamIndex = damageReport.attackerTeamIndex; if ((bool)teamComponent) { teamIndex = teamComponent.teamIndex; } if ((bool)victimBody && (bool)victimMaster) { PlayerCharacterMasterController playerCharacterMasterController = victimMaster.playerCharacterMasterController; if ((bool)playerCharacterMasterController) { NetworkUser networkUser = playerCharacterMasterController.networkUser; if ((bool)networkUser) { OnPlayerCharacterDeath(damageReport, networkUser); } } if (victimBody.HasBuff(RoR2Content.Buffs.AffixWhite)) { UnityEngine.Vector3 position = vector2; GameObject gameObject2 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/GenericDelayBlast"), position, UnityEngine.Quaternion.identity); float num = 12f + victimBody.radius; gameObject2.transform.localScale = new UnityEngine.Vector3(num, num, num); DelayBlast component = gameObject2.GetComponent(); if ((bool)component) { component.position = position; component.baseDamage = victimBody.damage * 1.5f; component.baseForce = 2300f; component.attacker = gameObject; component.radius = num; component.crit = Util.CheckRoll(victimBody.crit, victimMaster); component.procCoefficient = 0.75f; component.maxTimer = 2f; component.falloffModel = BlastAttack.FalloffModel.None; component.explosionEffect = LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/AffixWhiteExplosion"); component.delayEffect = LegacyResourcesAPI.Load("Prefabs/Effects/AffixWhiteDelayEffect"); component.damageType = DamageType.Freeze2s; TeamFilter component2 = gameObject2.GetComponent(); if ((bool)component2) { component2.teamIndex = TeamComponent.GetObjectTeam(component.attacker); } } } if (victimBody.HasBuff(RoR2Content.Buffs.AffixPoison)) { UnityEngine.Vector3 position2 = vector2; UnityEngine.Quaternion rotation = UnityEngine.Quaternion.LookRotation(ray.direction); GameObject gameObject3 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/CharacterMasters/UrchinTurretMaster"), position2, rotation); CharacterMaster component3 = gameObject3.GetComponent(); if ((bool)component3) { component3.teamIndex = teamIndex; NetworkServer.Spawn(gameObject3); component3.SpawnBodyHere(); } } if (RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.wispOnDeath) && teamIndex == TeamIndex.Monster && victimMaster.masterIndex != CommonAssets.wispSoulMasterPrefabMasterComponent.masterIndex) { MasterSummon masterSummon = new MasterSummon(); masterSummon.position = vector2; masterSummon.ignoreTeamMemberLimit = true; masterSummon.masterPrefab = CommonAssets.wispSoulMasterPrefabMasterComponent.gameObject; masterSummon.summonerBodyObject = gameObject; masterSummon.rotation = UnityEngine.Quaternion.LookRotation(ray.direction); masterSummon.Perform(); } if (victimBody.HasBuff(RoR2Content.Buffs.Fruiting) || (damageReport.damageInfo != null && (ulong)(damageReport.damageInfo.damageType & DamageType.FruitOnHit) != 0)) { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/TreebotFruitDeathEffect.prefab"), new EffectData { origin = vector, rotation = UnityEngine.Random.rotation }, transmit: true); int num2 = Mathf.Min(Math.Max(1, (int)(victimBody.bestFitRadius * 2f)), 8); GameObject original = LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/TreebotFruitPack"); for (int i = 0; i < num2; i++) { GameObject obj = UnityEngine.Object.Instantiate(original, vector + UnityEngine.Random.insideUnitSphere * victimBody.radius * 0.5f, UnityEngine.Random.rotation); TeamFilter component4 = obj.GetComponent(); if ((bool)component4) { component4.teamIndex = attackerTeamIndex; } obj.GetComponentInChildren(); obj.transform.localScale = new UnityEngine.Vector3(1f, 1f, 1f); NetworkServer.Spawn(obj); } } if (victimBody.HasBuff(DLC1Content.Buffs.EliteEarth)) { MasterSummon masterSummon2 = new MasterSummon(); masterSummon2.position = vector2; masterSummon2.ignoreTeamMemberLimit = true; masterSummon2.masterPrefab = CommonAssets.eliteEarthHealerMaster; masterSummon2.summonerBodyObject = gameObject; masterSummon2.rotation = UnityEngine.Quaternion.LookRotation(ray.direction); masterSummon2.Perform(); } if (victimBody.HasBuff(DLC1Content.Buffs.EliteVoid) && (!victimMaster || victimMaster.IsDeadAndOutOfLivesServer())) { UnityEngine.Vector3 position3 = vector2; GameObject gameObject4 = UnityEngine.Object.Instantiate(Addressables.LoadAssetAsync("RoR2/DLC1/EliteVoid/VoidInfestorMaster.prefab").WaitForCompletion(), position3, UnityEngine.Quaternion.identity); CharacterMaster component5 = gameObject4.GetComponent(); if ((bool)component5) { component5.teamIndex = TeamIndex.Void; NetworkServer.Spawn(gameObject4); component5.SpawnBodyHere(); } } } if ((bool)attackerBody) { attackerBody.HandleOnKillEffectsServer(damageReport); if ((bool)attackerMaster && (bool)inventory) { int itemCount = inventory.GetItemCount(RoR2Content.Items.IgniteOnKill); if (itemCount > 0) { ProcIgniteOnKill(damageReport, itemCount, victimBody, attackerTeamIndex); } int itemCount2 = inventory.GetItemCount(RoR2Content.Items.ExplodeOnDeath); if (itemCount2 > 0) { UnityEngine.Vector3 position4 = vector2; float damageCoefficient = 3.5f * (1f + (float)(itemCount2 - 1) * 0.8f); float baseDamage = Util.OnKillProcDamage(attackerBody.damage, damageCoefficient); GameObject obj2 = UnityEngine.Object.Instantiate(CommonAssets.explodeOnDeathPrefab, position4, UnityEngine.Quaternion.identity); DelayBlast component6 = obj2.GetComponent(); if ((bool)component6) { component6.position = position4; component6.baseDamage = baseDamage; component6.baseForce = 2000f; component6.bonusForce = UnityEngine.Vector3.up * 1000f; component6.radius = 12f + 2.4f * ((float)itemCount2 - 1f); component6.attacker = damageInfo.attacker; component6.inflictor = null; component6.crit = Util.CheckRoll(attackerBody.crit, attackerMaster); component6.maxTimer = 0.5f; component6.damageColorIndex = DamageColorIndex.Item; component6.falloffModel = BlastAttack.FalloffModel.SweetSpot; } TeamFilter component7 = obj2.GetComponent(); if ((bool)component7) { component7.teamIndex = attackerTeamIndex; } NetworkServer.Spawn(obj2); } int itemCount3 = inventory.GetItemCount(RoR2Content.Items.Dagger); if (itemCount3 > 0) { float damageCoefficient2 = 1.5f * (float)itemCount3; UnityEngine.Vector3 vector3 = vector + UnityEngine.Vector3.up * 1.8f; for (int j = 0; j < 3; j++) { ProjectileManager.instance.FireProjectile(CommonAssets.daggerPrefab, vector3 + UnityEngine.Random.insideUnitSphere * 0.5f, Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up + UnityEngine.Random.insideUnitSphere * 0.1f), attackerBody.gameObject, Util.OnKillProcDamage(attackerBody.damage, damageCoefficient2), 200f, Util.CheckRoll(attackerBody.crit, attackerMaster), DamageColorIndex.Item); } } int itemCount4 = inventory.GetItemCount(RoR2Content.Items.Tooth); if (itemCount4 > 0) { float num3 = Mathf.Pow(itemCount4, 0.25f); GameObject obj3 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/HealPack"), vector, UnityEngine.Random.rotation); TeamFilter component8 = obj3.GetComponent(); if ((bool)component8) { component8.teamIndex = attackerTeamIndex; } HealthPickup componentInChildren = obj3.GetComponentInChildren(); if ((bool)componentInChildren) { componentInChildren.flatHealing = 8f; componentInChildren.fractionalHealing = 0.02f * (float)itemCount4; } obj3.transform.localScale = new UnityEngine.Vector3(num3, num3, num3); NetworkServer.Spawn(obj3); } float num4 = 0f; float num5 = 0f; float num6 = 0f; float num7 = 0f; if (victimBody.HasBuff(DLC2Content.Buffs.CookingChopped)) { num4 += 1f; num5 += 2f; num6 += 0.04f; num7 += 0.75f; } if (victimBody.HasBuff(DLC2Content.Buffs.CookingOiled)) { num4 += 1f; num5 += 2f; num6 += 0.04f; num7 += 0.75f; } if (victimBody.HasBuff(DLC2Content.Buffs.CookingRoasted)) { num4 += 1f; num5 += 2f; num6 += 0.04f; num7 += 0.75f; } if (victimBody.HasBuff(DLC2Content.Buffs.CookingRolled)) { num4 += 1f; num5 += 2f; num6 += 0.04f; num7 += 0.75f; } if (victimBody.HasBuff(DLC2Content.Buffs.CookingFlambe)) { num4 += 1f; num5 += 2f; num6 += 0.04f; num7 += 0.75f; } if (num4 > 1f) { GameObject obj4 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Chef/ChefFoodPickup"), vector, UnityEngine.Random.rotation); TeamFilter component9 = obj4.GetComponent(); if ((bool)component9) { component9.teamIndex = attackerTeamIndex; } HealthPickup componentInChildren2 = obj4.GetComponentInChildren(); if ((bool)componentInChildren2) { componentInChildren2.flatHealing = num5; componentInChildren2.fractionalHealing = num6; } obj4.transform.localScale = new UnityEngine.Vector3(num7, num7, num7); NetworkServer.Spawn(obj4); } int itemCount5 = inventory.GetItemCount(RoR2Content.Items.Infusion); if (itemCount5 > 0) { int num8 = itemCount5 * 100; if (inventory.infusionBonus < num8) { InfusionOrb infusionOrb = new InfusionOrb(); infusionOrb.origin = vector; infusionOrb.target = Util.FindBodyMainHurtBox(attackerBody); infusionOrb.maxHpValue = itemCount5; OrbManager.instance.AddOrb(infusionOrb); } } if ((DamageType)(damageInfo.damageType & DamageType.ResetCooldownsOnKill) == DamageType.ResetCooldownsOnKill) { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/Bandit2ResetEffect"), new EffectData { origin = damageInfo.position }, transmit: true); SkillLocator skillLocator = attackerBody.skillLocator; if ((bool)skillLocator) { skillLocator.ResetSkills(); } } if ((DamageType)(damageInfo.damageType & DamageType.GiveSkullOnKill) == DamageType.GiveSkullOnKill && (bool)victimMaster) { EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/Bandit2KillEffect"), new EffectData { origin = damageInfo.position }, transmit: true); attackerBody.AddBuff(RoR2Content.Buffs.BanditSkull); } int itemCount6 = inventory.GetItemCount(RoR2Content.Items.Talisman); if (itemCount6 > 0 && (bool)attackerBody.equipmentSlot) { inventory.DeductActiveEquipmentCooldown(2f + (float)itemCount6 * 2f); } int itemCount7 = inventory.GetItemCount(JunkContent.Items.TempestOnKill); if (itemCount7 > 0 && Util.CheckRoll(25f, attackerMaster)) { GameObject obj5 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/TempestWard"), victimBody.footPosition, UnityEngine.Quaternion.identity); TeamFilter component10 = obj5.GetComponent(); if ((bool)component10) { component10.teamIndex = attackerTeamIndex; } BuffWard component11 = obj5.GetComponent(); if ((bool)component11) { component11.expireDuration = 2f + 6f * (float)itemCount7; } NetworkServer.Spawn(obj5); } int itemCount8 = inventory.GetItemCount(RoR2Content.Items.Bandolier); if (itemCount8 > 0 && Util.CheckRoll((1f - 1f / Mathf.Pow(itemCount8 + 1, 0.33f)) * 100f, attackerMaster)) { GameObject obj6 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/AmmoPack"), vector, UnityEngine.Random.rotation); TeamFilter component12 = obj6.GetComponent(); if ((bool)component12) { component12.teamIndex = attackerTeamIndex; } NetworkServer.Spawn(obj6); } if ((bool)victimBody && damageReport.victimIsElite) { int itemCount9 = inventory.GetItemCount(RoR2Content.Items.HeadHunter); int itemCount10 = inventory.GetItemCount(RoR2Content.Items.KillEliteFrenzy); if (itemCount9 > 0) { float duration = 3f + 5f * (float)itemCount9; for (int k = 0; k < BuffCatalog.eliteBuffIndices.Length; k++) { BuffIndex buffIndex = BuffCatalog.eliteBuffIndices[k]; if (victimBody.HasBuff(buffIndex)) { attackerBody.AddTimedBuff(buffIndex, duration); } } } if (itemCount10 > 0) { attackerBody.AddTimedBuff(RoR2Content.Buffs.NoCooldowns, (float)itemCount10 * 4f); } } int itemCount11 = inventory.GetItemCount(RoR2Content.Items.GhostOnKill); if (itemCount11 > 0 && (bool)victimBody && Util.CheckRoll(7f, attackerMaster)) { Util.TryToCreateGhost(victimBody, attackerBody, itemCount11 * 30); } if (inventory.GetItemCount(DLC1Content.Items.MinorConstructOnKill) > 0 && (bool)victimBody && victimBody.isElite && !attackerMaster.IsDeployableLimited(DeployableSlot.MinorConstructOnKill)) { UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * UnityEngine.Quaternion.AngleAxis(-80f, UnityEngine.Vector3.right) * UnityEngine.Vector3.forward; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = CommonAssets.minorConstructOnKillProjectile; fireProjectileInfo.position = vector; fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(forward); fireProjectileInfo.procChainMask = default(ProcChainMask); fireProjectileInfo.target = gameObject; fireProjectileInfo.owner = attackerBody.gameObject; fireProjectileInfo.damage = 0f; fireProjectileInfo.crit = false; fireProjectileInfo.force = 0f; fireProjectileInfo.damageColorIndex = DamageColorIndex.Item; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } int itemCount12 = inventory.GetItemCount(DLC1Content.Items.MoveSpeedOnKill); if (itemCount12 > 0) { int num9 = itemCount12 - 1; int num10 = 5; float num11 = 1f + (float)num9 * 0.5f; attackerBody.ClearTimedBuffs(DLC1Content.Buffs.KillMoveSpeed); for (int l = 0; l < num10; l++) { attackerBody.AddTimedBuff(DLC1Content.Buffs.KillMoveSpeed, num11 * (float)(l + 1) / (float)num10); } EffectData effectData = new EffectData(); effectData.origin = attackerBody.corePosition; CharacterMotor characterMotor = attackerBody.characterMotor; bool flag = false; if ((bool)characterMotor) { UnityEngine.Vector3 moveDirection = characterMotor.moveDirection; if (moveDirection != UnityEngine.Vector3.zero) { effectData.rotation = Util.QuaternionSafeLookRotation(moveDirection); flag = true; } } if (!flag) { effectData.rotation = attackerBody.transform.rotation; } EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/MoveSpeedOnKillActivate"), effectData, transmit: true); } if ((bool)equipmentDef && Util.CheckRoll(equipmentDef.dropOnDeathChance * 100f, attackerMaster) && (bool)victimBody) { PickupDropletController.CreatePickupDroplet(PickupCatalog.FindPickupIndex(equipmentIndex), vector + UnityEngine.Vector3.up * 1.5f, UnityEngine.Vector3.up * 20f + ray.direction * 2f); } int itemCount13 = inventory.GetItemCount(RoR2Content.Items.BarrierOnKill); if (itemCount13 > 0 && (bool)attackerBody.healthComponent) { attackerBody.healthComponent.AddBarrier(15f * (float)itemCount13); } int itemCount14 = inventory.GetItemCount(RoR2Content.Items.BonusGoldPackOnKill); if (itemCount14 > 0 && Util.CheckRoll(4f * (float)itemCount14, attackerMaster)) { GameObject obj7 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/BonusMoneyPack"), vector, UnityEngine.Random.rotation); TeamFilter component13 = obj7.GetComponent(); if ((bool)component13) { component13.teamIndex = attackerTeamIndex; } NetworkServer.Spawn(obj7); } int itemCount15 = inventory.GetItemCount(RoR2Content.Items.Plant); if (itemCount15 > 0) { GameObject obj8 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/InterstellarDeskPlant"), victimBody.footPosition, UnityEngine.Quaternion.identity); DeskPlantController component14 = obj8.GetComponent(); if ((bool)component14) { if ((bool)component14.teamFilter) { component14.teamFilter.teamIndex = attackerTeamIndex; } component14.itemCount = itemCount15; } NetworkServer.Spawn(obj8); } int incubatorOnKillCount = attackerMaster.inventory.GetItemCount(JunkContent.Items.Incubator); if (incubatorOnKillCount > 0 && attackerMaster.GetDeployableCount(DeployableSlot.ParentPodAlly) + attackerMaster.GetDeployableCount(DeployableSlot.ParentAlly) < incubatorOnKillCount && Util.CheckRoll(7f + 1f * (float)incubatorOnKillCount, attackerMaster)) { DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load("SpawnCards/CharacterSpawnCards/cscParentPod"), new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = 3f, maxDistance = 20f, spawnOnTarget = transform }, RoR2Application.rng); directorSpawnRequest.summonerBodyObject = attacker; directorSpawnRequest.onSpawnedServer = (Action)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action)delegate(SpawnCard.SpawnResult spawnResult) { if (spawnResult.success) { Inventory inventory2 = spawnResult.spawnedInstance.GetComponent().inventory; if ((bool)inventory2) { inventory2.GiveItem(RoR2Content.Items.BoostDamage, 30); inventory2.GiveItem(RoR2Content.Items.BoostHp, 10 * incubatorOnKillCount); } } }); DirectorCore.instance.TrySpawnObject(directorSpawnRequest); } int itemCount16 = inventory.GetItemCount(RoR2Content.Items.BleedOnHitAndExplode); if (itemCount16 > 0 && (bool)victimBody && (victimBody.HasBuff(RoR2Content.Buffs.Bleeding) || victimBody.HasBuff(RoR2Content.Buffs.SuperBleed))) { Util.PlaySound("Play_bleedOnCritAndExplode_explode", gameObject); UnityEngine.Vector3 position5 = vector2; float damageCoefficient3 = 4f * (float)(1 + (itemCount16 - 1)); float num12 = 0.15f * (float)(1 + (itemCount16 - 1)); float baseDamage2 = Util.OnKillProcDamage(attackerBody.damage, damageCoefficient3) + victimBody.maxHealth * num12; GameObject obj9 = UnityEngine.Object.Instantiate(CommonAssets.bleedOnHitAndExplodeBlastEffect, position5, UnityEngine.Quaternion.identity); DelayBlast component15 = obj9.GetComponent(); component15.position = position5; component15.baseDamage = baseDamage2; component15.baseForce = 0f; component15.radius = 16f; component15.attacker = damageInfo.attacker; component15.inflictor = null; component15.crit = Util.CheckRoll(attackerBody.crit, attackerMaster); component15.maxTimer = 0f; component15.damageColorIndex = DamageColorIndex.Item; component15.falloffModel = BlastAttack.FalloffModel.SweetSpot; obj9.GetComponent().teamIndex = attackerTeamIndex; NetworkServer.Spawn(obj9); } if (attackerMaster.inventory.GetItemCount(DLC2Content.Items.ResetChests) > 0) { int itemCount17 = attackerMaster.inventory.GetItemCount(DLC2Content.Items.ResetChests); if (victimBody.isChampion && Util.CheckRoll(100f, attackerMaster) && (bool)victimBody) { PickupDropletController.CreatePickupDroplet(CommonAssets.dtSonorousEchoPath.GenerateDrop(Run.instance.runRNG), vector + UnityEngine.Vector3.up * 1.5f, UnityEngine.Vector3.up * 20f + ray.direction * 2f); } if (victimBody.isElite && Util.CheckRoll(2f + 1f * (float)itemCount17, attackerMaster) && (bool)victimBody) { PickupDropletController.CreatePickupDroplet(CommonAssets.dtSonorousEchoPath.GenerateDrop(Run.instance.runRNG), vector + UnityEngine.Vector3.up * 1.5f, UnityEngine.Vector3.up * 20f + ray.direction * 2f); } } } } GlobalEventManager.onCharacterDeathGlobal?.Invoke(damageReport); } public void OnHitAll(DamageInfo damageInfo, GameObject hitObject) { OnHitAllProcess(damageInfo, hitObject); } private void OnHitAllProcess(DamageInfo damageInfo, GameObject hitObject) { if (damageInfo.procCoefficient == 0f || damageInfo.rejected) { return; } _ = NetworkServer.active; if (!damageInfo.attacker) { return; } CharacterBody component = damageInfo.attacker.GetComponent(); if (!component) { return; } CharacterMaster master = component.master; if (!master) { return; } Inventory inventory = master.inventory; if (!master.inventory) { return; } if (!damageInfo.procChainMask.HasProc(ProcType.Behemoth)) { int itemCount = inventory.GetItemCount(RoR2Content.Items.Behemoth); if (itemCount > 0 && damageInfo.procCoefficient != 0f) { float num = (1.5f + 2.5f * (float)itemCount) * damageInfo.procCoefficient; float damageCoefficient = 0.6f; float baseDamage = Util.OnHitProcDamage(damageInfo.damage, component.damage, damageCoefficient); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/OmniEffect/OmniExplosionVFXQuick"), new EffectData { origin = damageInfo.position, scale = num, rotation = Util.QuaternionSafeLookRotation(damageInfo.force) }, transmit: true); BlastAttack obj = new BlastAttack { position = damageInfo.position, baseDamage = baseDamage, baseForce = 0f, radius = num, attacker = damageInfo.attacker, inflictor = null }; obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker); obj.crit = damageInfo.crit; obj.procChainMask = damageInfo.procChainMask; obj.procCoefficient = 0f; obj.damageColorIndex = DamageColorIndex.Item; obj.falloffModel = BlastAttack.FalloffModel.None; obj.damageType = damageInfo.damageType; obj.Fire(); } } if ((component.HasBuff(RoR2Content.Buffs.AffixBlue) ? 1 : 0) > 0) { float damageCoefficient2 = 0.5f; float damage = Util.OnHitProcDamage(damageInfo.damage, component.damage, damageCoefficient2); float force = 0f; UnityEngine.Vector3 position = damageInfo.position; ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load("Prefabs/Projectiles/LightningStake"), position, UnityEngine.Quaternion.identity, damageInfo.attacker, damage, force, damageInfo.crit, DamageColorIndex.Item); } } public void OnCrit(CharacterBody body, DamageInfo damageInfo, CharacterMaster master, float procCoefficient, ProcChainMask procChainMask) { UnityEngine.Vector3 hitPos = body.corePosition; GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/Critspark"); if ((bool)body) { if (body.critMultiplier > 2f) { gameObject = LegacyResourcesAPI.Load("Prefabs/Effects/ImpactEffects/CritsparkHeavy"); } if ((bool)body && procCoefficient > 0f && (bool)master && (bool)master.inventory) { Inventory inventory = master.inventory; if (!procChainMask.HasProc(ProcType.HealOnCrit)) { procChainMask.AddProc(ProcType.HealOnCrit); int itemCount = inventory.GetItemCount(RoR2Content.Items.HealOnCrit); if (itemCount > 0 && (bool)body.healthComponent) { Util.PlaySound("Play_item_proc_crit_heal", body.gameObject); if (NetworkServer.active) { body.healthComponent.Heal((4f + (float)itemCount * 4f) * procCoefficient, procChainMask); } } } if (inventory.GetItemCount(RoR2Content.Items.AttackSpeedOnCrit) > 0) { body.AddTimedBuff(RoR2Content.Buffs.AttackSpeedOnCrit, 3f * procCoefficient); } int itemCount2 = inventory.GetItemCount(JunkContent.Items.CooldownOnCrit); if (itemCount2 > 0) { Util.PlaySound("Play_item_proc_crit_cooldown", body.gameObject); SkillLocator component = body.GetComponent(); if ((bool)component) { float dt = (float)itemCount2 * procCoefficient; if ((bool)component.primary) { component.primary.RunRecharge(dt); } if ((bool)component.secondary) { component.secondary.RunRecharge(dt); } if ((bool)component.utility) { component.utility.RunRecharge(dt); } if ((bool)component.special) { component.special.RunRecharge(dt); } } } } } if (damageInfo != null) { hitPos = damageInfo.position; } if ((bool)gameObject) { EffectManager.SimpleImpactEffect(gameObject, hitPos, UnityEngine.Vector3.up, transmit: true); } } public static void OnTeamLevelUp(TeamIndex teamIndex) { GlobalEventManager.onTeamLevelUp?.Invoke(teamIndex); } public static void OnCharacterLevelUp(CharacterBody characterBody) { GlobalEventManager.onCharacterLevelUp?.Invoke(characterBody); } public void OnInteractionBegin(Interactor interactor, IInteractable interactable, GameObject interactableObject) { if (!interactor) { UnityEngine.Debug.LogError("OnInteractionBegin invalid interactor!"); return; } if (interactable == null) { UnityEngine.Debug.LogError("OnInteractionBegin invalid interactable!"); return; } if (!interactableObject) { UnityEngine.Debug.LogError("OnInteractionBegin invalid interactableObject!"); return; } GlobalEventManager.OnInteractionsGlobal?.Invoke(interactor, interactable, interactableObject); CharacterBody component = interactor.GetComponent(); UnityEngine.Vector3 vector = UnityEngine.Vector3.zero; UnityEngine.Quaternion rotation = UnityEngine.Quaternion.identity; Transform transform = interactableObject.transform; if ((bool)transform) { vector = transform.position; rotation = transform.rotation; } if (!component) { return; } Inventory inventory = component.inventory; if (!inventory) { return; } InteractionProcFilter interactionProcFilter = interactableObject.GetComponent(); int itemCount = inventory.GetItemCount(RoR2Content.Items.Firework); if (itemCount > 0 && InteractableIsPermittedForSpawn((MonoBehaviour)interactable)) { Transform transform2 = interactableObject.GetComponent()?.modelTransform?.GetComponent()?.FindChild("FireworkOrigin"); UnityEngine.Vector3 position = (transform2 ? transform2.position : (interactableObject.transform.position + UnityEngine.Vector3.up * 2f)); int remaining = 4 + itemCount * 4; FireworkLauncher component2 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/FireworkLauncher"), position, UnityEngine.Quaternion.identity).GetComponent(); component2.owner = interactor.gameObject; component2.crit = Util.CheckRoll(component.crit, component.master); component2.remaining = remaining; } int squidStacks = inventory.GetItemCount(RoR2Content.Items.Squid); if (squidStacks > 0 && InteractableIsPermittedForSpawn((MonoBehaviour)interactable)) { CharacterSpawnCard spawnCard = LegacyResourcesAPI.Load("SpawnCards/CharacterSpawnCards/cscSquidTurret"); DirectorPlacementRule placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = 5f, maxDistance = 25f, position = interactableObject.transform.position }; DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, placementRule, RoR2Application.rng); directorSpawnRequest.teamIndexOverride = TeamIndex.Player; directorSpawnRequest.summonerBodyObject = interactor.gameObject; directorSpawnRequest.onSpawnedServer = (Action)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action)delegate(SpawnCard.SpawnResult result) { if (result.success && (bool)result.spawnedInstance) { CharacterMaster component5 = result.spawnedInstance.GetComponent(); if ((bool)component5 && (bool)component5.inventory) { component5.inventory.GiveItem(RoR2Content.Items.HealthDecay, 30); component5.inventory.GiveItem(RoR2Content.Items.BoostAttackSpeed, 10 * (squidStacks - 1)); } } }); DirectorCore.instance.TrySpawnObject(directorSpawnRequest); } int itemCount2 = inventory.GetItemCount(RoR2Content.Items.MonstersOnShrineUse); if (itemCount2 <= 0) { return; } PurchaseInteraction component3 = interactableObject.GetComponent(); if (!component3 || !component3.isShrine || (bool)interactableObject.GetComponent()) { return; } GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/Encounters/MonstersOnShrineUseEncounter"); if (!gameObject) { return; } GameObject gameObject2 = UnityEngine.Object.Instantiate(gameObject, vector, UnityEngine.Quaternion.identity); NetworkServer.Spawn(gameObject2); CombatDirector component4 = gameObject2.GetComponent(); if ((bool)component4 && (bool)Stage.instance) { float monsterCredit = 40f * Stage.instance.entryDifficultyCoefficient * (float)itemCount2; DirectorCard directorCard = component4.SelectMonsterCardForCombatShrine(monsterCredit); if (directorCard != null) { component4.CombatShrineActivation(interactor, monsterCredit, directorCard); EffectData effectData = new EffectData { origin = vector, rotation = rotation }; EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/MonstersOnShrineUse"), effectData, transmit: true); } else { NetworkServer.Destroy(gameObject2); } } bool InteractableIsPermittedForSpawn(MonoBehaviour interactableAsMonoBehaviour) { if (!interactableAsMonoBehaviour) { return false; } if ((bool)interactionProcFilter) { return interactionProcFilter.shouldAllowOnInteractionBeginProc; } if ((bool)interactableAsMonoBehaviour.GetComponent()) { if (interactableAsMonoBehaviour.GetComponent().enabled) { return false; } return true; } if ((bool)interactableAsMonoBehaviour.GetComponent()) { return false; } if ((bool)interactableAsMonoBehaviour.GetComponent()) { return false; } if ((bool)interactableAsMonoBehaviour.GetComponent()) { return false; } return true; } } public static void ClientDamageNotified(DamageDealtMessage damageDealtMessage) { GlobalEventManager.onClientDamageNotified?.Invoke(damageDealtMessage); } public static void ServerDamageDealt(DamageReport damageReport) { GlobalEventManager.onServerDamageDealt?.Invoke(damageReport); } public static void ServerCharacterExecuted(DamageReport damageReport, float executionHealthLost) { GlobalEventManager.onServerCharacterExecuted?.Invoke(damageReport, executionHealthLost); } } public class GoldshoresMissionController : MonoBehaviour { public Xoroshiro128Plus rng; public EntityStateMachine entityStateMachine; public GameObject beginTransitionIntoBossFightEffect; public GameObject exitTransitionIntoBossFightEffect; public Transform bossSpawnPosition; [SerializeField] public ExpansionDef requiredExpansion; public List beaconInstanceList = new List(); public int beaconsRequiredToSpawnBoss; public int beaconsToSpawnOnMap; public InteractableSpawnCard beaconSpawnCard; public static GoldshoresMissionController instance { get; private set; } public int beaconsActive => EntityStates.Interactables.GoldBeacon.Ready.count; public int beaconCount => EntityStates.Interactables.GoldBeacon.Ready.count + NotReady.count; private void OnEnable() { instance = SingletonHelper.Assign(instance, this); } private void OnDisable() { instance = SingletonHelper.Unassign(instance, this); } private void Awake() { if (NetworkServer.active) { rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint); } beginTransitionIntoBossFightEffect.SetActive(value: false); exitTransitionIntoBossFightEffect.SetActive(value: false); } public void SpawnBeacons() { if (!NetworkServer.active) { return; } for (int i = 0; i < beaconsToSpawnOnMap; i++) { GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(beaconSpawnCard, new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Random }, rng)); if ((bool)gameObject) { beaconInstanceList.Add(gameObject); } } beaconsToSpawnOnMap = beaconInstanceList.Count; } public void BeginTransitionIntoBossfight() { beginTransitionIntoBossFightEffect.SetActive(value: true); exitTransitionIntoBossFightEffect.SetActive(value: false); } public void ExitTransitionIntoBossfight() { beginTransitionIntoBossFightEffect.SetActive(value: false); exitTransitionIntoBossFightEffect.SetActive(value: true); } } [RequireComponent(typeof(TeamFilter))] [RequireComponent(typeof(GenericOwnership))] public class GrandParentSunController : MonoBehaviour { private TeamFilter teamFilter; private GenericOwnership ownership; public BuffDef buffDef; [UnityEngine.Min(0.001f)] public float cycleInterval = 1f; [UnityEngine.Min(0.001f)] public float nearBuffDuration = 1f; [UnityEngine.Min(0.001f)] public float maxDistance = 1f; public int minimumStacksBeforeApplyingBurns = 4; public float burnDuration = 5f; public GameObject buffApplyEffect; [SerializeField] private LoopSoundDef activeLoopDef; [SerializeField] private LoopSoundDef damageLoopDef; [SerializeField] private string stopSoundName; private Run.FixedTimeStamp previousCycle = Run.FixedTimeStamp.negativeInfinity; private int cycleIndex; private List cycleTargets = new List(); private BullseyeSearch bullseyeSearch = new BullseyeSearch(); private bool isLocalPlayerDamaged; private void Awake() { teamFilter = GetComponent(); ownership = GetComponent(); } private void Start() { if ((bool)activeLoopDef) { Util.PlaySound(activeLoopDef.startSoundName, base.gameObject); } } private void OnDestroy() { if ((bool)activeLoopDef) { Util.PlaySound(activeLoopDef.stopSoundName, base.gameObject); } if ((bool)damageLoopDef) { Util.PlaySound(damageLoopDef.stopSoundName, base.gameObject); } if (stopSoundName != null) { Util.PlaySound(stopSoundName, base.gameObject); } } private void FixedUpdate() { if (NetworkServer.active) { ServerFixedUpdate(); } if (!damageLoopDef) { return; } bool flag = isLocalPlayerDamaged; isLocalPlayerDamaged = false; foreach (HurtBox cycleTarget in cycleTargets) { CharacterBody characterBody = null; if ((bool)cycleTarget && (bool)cycleTarget.healthComponent) { characterBody = cycleTarget.healthComponent.body; } if ((bool)characterBody && (characterBody.bodyFlags & CharacterBody.BodyFlags.OverheatImmune) != 0 && characterBody.hasEffectiveAuthority) { UnityEngine.Vector3 position = base.transform.position; UnityEngine.Vector3 corePosition = characterBody.corePosition; if (!Physics.Linecast(position, corePosition, out var _, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { isLocalPlayerDamaged = true; } } } if (isLocalPlayerDamaged && !flag) { Util.PlaySound(damageLoopDef.startSoundName, base.gameObject); } else if (!isLocalPlayerDamaged && flag) { Util.PlaySound(damageLoopDef.stopSoundName, base.gameObject); } } private void ServerFixedUpdate() { float num = Mathf.Clamp01(previousCycle.timeSince / cycleInterval); int num2 = ((num == 1f) ? cycleTargets.Count : Mathf.FloorToInt((float)cycleTargets.Count * num)); UnityEngine.Vector3 position = base.transform.position; while (cycleIndex < num2) { HurtBox hurtBox = cycleTargets[cycleIndex]; if ((bool)hurtBox && (bool)hurtBox.healthComponent) { CharacterBody body = hurtBox.healthComponent.body; if ((body.bodyFlags & CharacterBody.BodyFlags.OverheatImmune) == 0) { UnityEngine.Vector3 corePosition = body.corePosition; Ray ray = new Ray(position, corePosition - position); if (!Physics.Linecast(position, corePosition, out var hitInfo, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { float num3 = Mathf.Max(1f, hitInfo.distance); body.AddTimedBuff(buffDef, nearBuffDuration / num3); if ((bool)buffApplyEffect) { EffectData effectData = new EffectData { origin = corePosition, rotation = Util.QuaternionSafeLookRotation(-ray.direction), scale = body.bestFitRadius }; effectData.SetHurtBoxReference(hurtBox); EffectManager.SpawnEffect(buffApplyEffect, effectData, transmit: true); } int num4 = body.GetBuffCount(buffDef) - minimumStacksBeforeApplyingBurns; if (num4 > 0) { InflictDotInfo dotInfo = default(InflictDotInfo); dotInfo.dotIndex = DotController.DotIndex.Burn; dotInfo.attackerObject = ownership.ownerObject; dotInfo.victimObject = body.gameObject; dotInfo.damageMultiplier = 1f; CharacterBody characterBody = ownership?.ownerObject?.GetComponent(); if ((bool)characterBody && (bool)characterBody.inventory) { dotInfo.totalDamage = 0.5f * characterBody.damage * burnDuration * (float)num4; StrengthenBurnUtils.CheckDotForUpgrade(characterBody.inventory, ref dotInfo); } DotController.InflictDot(ref dotInfo); } } } } cycleIndex++; } if (previousCycle.timeSince >= cycleInterval) { previousCycle = Run.FixedTimeStamp.now; cycleIndex = 0; cycleTargets.Clear(); SearchForTargets(cycleTargets); } } private void SearchForTargets(List dest) { bullseyeSearch.searchOrigin = base.transform.position; bullseyeSearch.minAngleFilter = 0f; bullseyeSearch.maxAngleFilter = 180f; bullseyeSearch.maxDistanceFilter = maxDistance; bullseyeSearch.filterByDistinctEntity = true; bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance; bullseyeSearch.viewer = null; bullseyeSearch.RefreshCandidates(); dest.AddRange(bullseyeSearch.GetResults()); } } [RequireComponent(typeof(ItemFollower))] public class GravCubeController : MonoBehaviour { private ItemFollower itemFollower; private float activeTimer; private Animator itemFollowerAnimator; private static int activeParamHash = Animator.StringToHash("active"); private void Start() { itemFollower = GetComponent(); } public void ActivateCube(float duration) { activeTimer = duration; } private void Update() { if ((bool)itemFollower && (bool)itemFollower.followerInstance) { if (!itemFollowerAnimator) { itemFollowerAnimator = itemFollower.followerInstance.GetComponentInChildren(); } activeTimer -= Time.deltaTime; itemFollowerAnimator.SetBool(activeParamHash, activeTimer > 0f); } } } public class GravitatePickup : MonoBehaviour { private Transform gravitateTarget; [Tooltip("The rigidbody to set the velocity of.")] public Rigidbody rigidbody; [Tooltip("The TeamFilter which controls which team can activate this trigger.")] public TeamFilter teamFilter; public float acceleration; public float maxSpeed; public bool gravitateAtFullHealth = true; private void Start() { } private void OnTriggerEnter(Collider other) { if (NetworkServer.active && !gravitateTarget && teamFilter.teamIndex != TeamIndex.None) { HealthComponent component = other.gameObject.GetComponent(); if (TeamComponent.GetObjectTeam(other.gameObject) == teamFilter.teamIndex && (gravitateAtFullHealth || !component || component.health < component.fullHealth)) { gravitateTarget = other.gameObject.transform; } } } private void FixedUpdate() { if ((bool)gravitateTarget) { rigidbody.velocity = UnityEngine.Vector3.MoveTowards(rigidbody.velocity, (gravitateTarget.transform.position - base.transform.position).normalized * maxSpeed, acceleration); } } } [RequireComponent(typeof(GenericOwnership))] public class HealBeamController : NetworkBehaviour { public Transform startPointTransform; public Transform endPointTransform; public float tickInterval = 1f; public bool breakOnTargetFullyHealed; public LineRenderer lineRenderer; public float lingerAfterBrokenDuration; [SyncVar(hook = "OnSyncTarget")] private HurtBoxReference netTarget; private float stopwatchServer; private bool broken; private HurtBoxReference previousHurtBoxReference; private HurtBox cachedHurtBox; private float scaleFactorVelocity; private float maxLineWidth = 0.3f; private float smoothTime = 0.1f; private float scaleFactor; public GenericOwnership ownership { get; private set; } public HurtBox target { get { return cachedHurtBox; } [Server] set { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealBeamController::set_target(RoR2.HurtBox)' called on client"); return; } NetworknetTarget = HurtBoxReference.FromHurtBox(value); UpdateCachedHurtBox(); } } public float healRate { get; set; } public HurtBoxReference NetworknetTarget { get { return netTarget; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; OnSyncTarget(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref netTarget, 1u); } } private void Awake() { ownership = GetComponent(); startPointTransform.SetParent(null, worldPositionStays: true); endPointTransform.SetParent(null, worldPositionStays: true); } public override void OnStartClient() { base.OnStartClient(); UpdateCachedHurtBox(); } private void OnDestroy() { if ((bool)startPointTransform) { UnityEngine.Object.Destroy(startPointTransform.gameObject); } if ((bool)endPointTransform) { UnityEngine.Object.Destroy(endPointTransform.gameObject); } } private void OnEnable() { InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); } private void LateUpdate() { UpdateHealBeamVisuals(); } private void OnSyncTarget(HurtBoxReference newValue) { NetworknetTarget = newValue; UpdateCachedHurtBox(); } private void FixedUpdate() { if (NetworkServer.active) { FixedUpdateServer(); } } private void FixedUpdateServer() { if (!cachedHurtBox) { BreakServer(); } else if (tickInterval > 0f) { stopwatchServer += Time.fixedDeltaTime; while (stopwatchServer >= tickInterval) { stopwatchServer -= tickInterval; OnTickServer(); } } } private void OnTickServer() { if (!cachedHurtBox || !cachedHurtBox.healthComponent) { BreakServer(); return; } cachedHurtBox.healthComponent.Heal(healRate * tickInterval, default(ProcChainMask)); if (breakOnTargetFullyHealed && cachedHurtBox.healthComponent.health >= cachedHurtBox.healthComponent.fullHealth) { BreakServer(); } } private void UpdateCachedHurtBox() { if (!previousHurtBoxReference.Equals(netTarget)) { cachedHurtBox = netTarget.ResolveHurtBox(); previousHurtBoxReference = netTarget; } } public static bool HealBeamAlreadyExists(GameObject owner, HurtBox target) { return HealBeamAlreadyExists(owner, target.healthComponent); } public static bool HealBeamAlreadyExists(GameObject owner, HealthComponent targetHealthComponent) { List instancesList = InstanceTracker.GetInstancesList(); int i = 0; for (int count = instancesList.Count; i < count; i++) { HealBeamController healBeamController = instancesList[i]; if ((object)healBeamController.target?.healthComponent == targetHealthComponent && (object)healBeamController.ownership.ownerObject == owner) { return true; } } return false; } public static int GetHealBeamCountForOwner(GameObject owner) { int num = 0; List instancesList = InstanceTracker.GetInstancesList(); int i = 0; for (int count = instancesList.Count; i < count; i++) { if ((object)instancesList[i].ownership.ownerObject == owner) { num++; } } return num; } private void UpdateHealBeamVisuals() { float num = (target ? 1f : 0f); scaleFactor = Mathf.SmoothDamp(scaleFactor, num, ref scaleFactorVelocity, smoothTime); UnityEngine.Vector3 localScale = new UnityEngine.Vector3(scaleFactor, scaleFactor, scaleFactor); startPointTransform.SetPositionAndRotation(base.transform.position, base.transform.rotation); startPointTransform.localScale = localScale; if ((bool)cachedHurtBox) { endPointTransform.position = cachedHurtBox.transform.position; } endPointTransform.localScale = localScale; lineRenderer.widthMultiplier = scaleFactor * maxLineWidth; } [Server] public void BreakServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealBeamController::BreakServer()' called on client"); } else if (!broken) { broken = true; target = null; base.transform.SetParent(null); ownership.ownerObject = null; UnityEngine.Object.Destroy(base.gameObject, lingerAfterBrokenDuration); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { GeneratedNetworkCode._WriteHurtBoxReference_None(writer, netTarget); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WriteHurtBoxReference_None(writer, netTarget); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { netTarget = GeneratedNetworkCode._ReadHurtBoxReference_None(reader); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { OnSyncTarget(GeneratedNetworkCode._ReadHurtBoxReference_None(reader)); } } public override void PreStartClient() { } } [RequireComponent(typeof(TeamFilter))] public class HealingWard : NetworkBehaviour { [SyncVar] [Tooltip("The area of effect.")] public float radius; [Tooltip("How long between heal pulses in the area of effect.")] public float interval = 1f; [Tooltip("How many hit points to restore each pulse.")] public float healPoints; [Tooltip("What fraction of the healee max health to restore each pulse.")] public float healFraction; [Tooltip("The child range indicator object. Will be scaled to the radius.")] public Transform rangeIndicator; [Tooltip("Should the ward be floored on start")] public bool floorWard; private TeamFilter teamFilter; private float healTimer; private float rangeIndicatorScaleVelocity; public float Networkradius { get { return radius; } [param: In] set { SetSyncVar(value, ref radius, 1u); } } private void Awake() { teamFilter = GetComponent(); if (NetworkServer.active && floorWard && Physics.Raycast(base.transform.position, UnityEngine.Vector3.down, out var hitInfo, 500f, LayerIndex.world.mask)) { base.transform.position = hitInfo.point; base.transform.up = hitInfo.normal; } } private void Update() { if ((bool)rangeIndicator) { float num = Mathf.SmoothDamp(rangeIndicator.localScale.x, radius, ref rangeIndicatorScaleVelocity, 0.2f); rangeIndicator.localScale = new UnityEngine.Vector3(num, num, num); } } private void FixedUpdate() { healTimer -= Time.fixedDeltaTime; if (healTimer <= 0f && NetworkServer.active) { healTimer = interval; HealOccupants(); } } private void HealOccupants() { ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamFilter.teamIndex); float num = radius * radius; UnityEngine.Vector3 position = base.transform.position; for (int i = 0; i < teamMembers.Count; i++) { if (!((teamMembers[i].transform.position - position).sqrMagnitude <= num)) { continue; } HealthComponent component = teamMembers[i].GetComponent(); if ((bool)component) { float num2 = healPoints + component.fullHealth * healFraction; if (num2 > 0f) { component.Heal(num2, default(ProcChainMask)); } } } } 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() { } } [RequireComponent(typeof(NetworkedBodyAttachment))] public class HealNearbyController : NetworkBehaviour { [SyncVar] public float radius; public float damagePerSecondCoefficient; [UnityEngine.Min(float.Epsilon)] public float tickRate = 1f; [SyncVar] public int maxTargets; public TetherVfxOrigin tetherVfxOrigin; public GameObject activeVfx; protected new Transform transform; protected NetworkedBodyAttachment networkedBodyAttachment; protected SphereSearch sphereSearch; protected float timer; private bool isTetheredToAtLeastOneObject; public float Networkradius { get { return radius; } [param: In] set { SetSyncVar(value, ref radius, 1u); } } public int NetworkmaxTargets { get { return maxTargets; } [param: In] set { SetSyncVar(value, ref maxTargets, 2u); } } protected void Awake() { transform = base.transform; networkedBodyAttachment = GetComponent(); sphereSearch = new SphereSearch(); timer = 0f; } protected void FixedUpdate() { timer -= Time.fixedDeltaTime; if (timer <= 0f) { timer += 1f / tickRate; Tick(); } } protected void Tick() { if (!networkedBodyAttachment || !networkedBodyAttachment.attachedBody || !networkedBodyAttachment.attachedBodyObject) { return; } List list = CollectionPool>.RentCollection(); SearchForTargets(list); float amount = damagePerSecondCoefficient * networkedBodyAttachment.attachedBody.damage / tickRate; List list2 = CollectionPool>.RentCollection(); for (int i = 0; i < list.Count; i++) { HurtBox hurtBox = list[i]; if ((bool)hurtBox && (bool)hurtBox.healthComponent && networkedBodyAttachment.attachedBody.healthComponent.alive && hurtBox.healthComponent.health < hurtBox.healthComponent.fullHealth && !hurtBox.healthComponent.body.HasBuff(DLC1Content.Buffs.EliteEarth)) { HealthComponent healthComponent = hurtBox.healthComponent; if (hurtBox.healthComponent.body == networkedBodyAttachment.attachedBody) { continue; } Transform item = healthComponent.body?.coreTransform ?? hurtBox.transform; list2.Add(item); if (NetworkServer.active) { healthComponent.Heal(amount, default(ProcChainMask)); } } if (list2.Count >= maxTargets) { break; } } isTetheredToAtLeastOneObject = (float)list2.Count > 0f; if ((bool)tetherVfxOrigin) { tetherVfxOrigin.SetTetheredTransforms(list2); } if ((bool)activeVfx) { activeVfx.SetActive(isTetheredToAtLeastOneObject); } CollectionPool>.ReturnCollection(list2); CollectionPool>.ReturnCollection(list); } protected void SearchForTargets(List dest) { TeamMask none = TeamMask.none; none.AddTeam(networkedBodyAttachment.attachedBody.teamComponent.teamIndex); sphereSearch.mask = LayerIndex.entityPrecise.mask; sphereSearch.origin = transform.position; sphereSearch.radius = radius + networkedBodyAttachment.attachedBody.radius; sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal; sphereSearch.RefreshCandidates(); sphereSearch.FilterCandidatesByHurtBoxTeam(none); sphereSearch.OrderCandidatesByDistance(); sphereSearch.FilterCandidatesByDistinctHurtBoxEntities(); sphereSearch.GetHurtBoxes(dest); sphereSearch.ClearCandidates(); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(radius); writer.WritePackedUInt32((uint)maxTargets); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(radius); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)maxTargets); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { radius = reader.ReadSingle(); maxTargets = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { radius = reader.ReadSingle(); } if (((uint)num & 2u) != 0) { maxTargets = (int)reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public interface IOnIncomingDamageServerReceiver { void OnIncomingDamageServer(DamageInfo damageInfo); } public interface IOnTakeDamageServerReceiver { void OnTakeDamageServer(DamageReport damageReport); } public interface IOnKilledServerReceiver { void OnKilledServer(DamageReport damageReport); } public interface IOnDamageDealtServerReceiver { void OnDamageDealtServer(DamageReport damageReport); } public interface IOnDamageInflictedServerReceiver { void OnDamageInflictedServer(DamageReport damageReport); } public interface IOnKilledOtherServerReceiver { void OnKilledOtherServer(DamageReport damageReport); } [DisallowMultipleComponent] [RequireComponent(typeof(CharacterBody))] public class HealthComponent : NetworkBehaviour, IManagedMonoBehaviour { private static class AssetReferences { public static GameObject bearEffectPrefab; public static GameObject bearVoidEffectPrefab; public static GameObject executeEffectPrefab; public static GameObject critGlassesVoidExecuteEffectPrefab; public static GameObject shieldBreakEffectPrefab; public static GameObject loseCoinsImpactEffectPrefab; public static GameObject gainCoinsImpactEffectPrefab; public static GameObject damageRejectedPrefab; public static GameObject bossDamageBonusImpactEffectPrefab; public static GameObject pulverizedEffectPrefab; public static GameObject diamondDamageBonusImpactEffectPrefab; public static GameObject crowbarImpactEffectPrefab; public static GameObject captainBodyArmorBlockEffectPrefab; public static GameObject mercExposeConsumeEffectPrefab; public static GameObject explodeOnDeathVoidExplosionPrefab; public static GameObject fragileDamageBonusBreakEffectPrefab; public static GameObject healthOrbPrefab; public static GameObject permanentDebuffEffectPrefab; public static void Resolve() { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/BearProc"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { bearEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/BearVoidProc"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { bearVoidEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/OmniEffect/OmniImpactExecute"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { executeEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ShieldBreakEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { shieldBreakEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/CoinImpact"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { loseCoinsImpactEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/GainCoinsImpact"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { gainCoinsImpactEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/DamageRejected"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { damageRejectedPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/ImpactBossDamageBonus"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { bossDamageBonusImpactEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/PulverizedEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { pulverizedEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/DiamondDamageBonusEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { diamondDamageBonusImpactEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/ImpactCrowbar"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { crowbarImpactEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/CaptainBodyArmorBlockEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { captainBodyArmorBlockEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/PermanentDebuffEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { permanentDebuffEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/MercExposeConsumeEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { mercExposeConsumeEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/CritGlassesVoidExecuteEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { critGlassesVoidExecuteEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/NetworkedObjects/ExplodeOnDeathVoidExplosion"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { explodeOnDeathVoidExplosionPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/ImpactEffects/DelicateWatchProcEffect"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { fragileDamageBonusBreakEffectPrefab = x.Result; }; asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/NetworkedObjects/TreebotFruitPack"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { healthOrbPrefab = x.Result; }; } } private class HealMessage : MessageBase { public GameObject target; public float amount; public override void Serialize(NetworkWriter writer) { writer.Write(target); writer.Write(amount); } public override void Deserialize(NetworkReader reader) { target = reader.ReadGameObject(); amount = reader.ReadSingle(); } } private struct ItemCounts { public int bear; public int armorPlate; public int goldOnHit; public int goldOnHurt; public int phasing; public int thorns; public int invadingDoppelganger; public int medkit; public int parentEgg; public int fragileDamageBonus; public int minHealthPercentage; public int noxiousThorn; public int antlerShield; public int increaseHealing; public int barrierOnOverHeal; public int repeatHeal; public int novaOnHeal; public int adaptiveArmor; public int healingPotion; public int infusion; public int missileVoid; public int unstableTransmitter; public ItemCounts([NotNull] Inventory src) { bear = src.GetItemCount(RoR2Content.Items.Bear); armorPlate = src.GetItemCount(RoR2Content.Items.ArmorPlate); goldOnHit = src.GetItemCount(RoR2Content.Items.GoldOnHit); goldOnHurt = src.GetItemCount(DLC1Content.Items.GoldOnHurt); phasing = src.GetItemCount(RoR2Content.Items.Phasing); thorns = src.GetItemCount(RoR2Content.Items.Thorns); invadingDoppelganger = src.GetItemCount(RoR2Content.Items.InvadingDoppelganger); medkit = src.GetItemCount(RoR2Content.Items.Medkit); fragileDamageBonus = src.GetItemCount(DLC1Content.Items.FragileDamageBonus); minHealthPercentage = src.GetItemCount(RoR2Content.Items.MinHealthPercentage); increaseHealing = src.GetItemCount(RoR2Content.Items.IncreaseHealing); barrierOnOverHeal = src.GetItemCount(RoR2Content.Items.BarrierOnOverHeal); repeatHeal = src.GetItemCount(RoR2Content.Items.RepeatHeal); novaOnHeal = src.GetItemCount(RoR2Content.Items.NovaOnHeal); adaptiveArmor = src.GetItemCount(RoR2Content.Items.AdaptiveArmor); healingPotion = src.GetItemCount(DLC1Content.Items.HealingPotion); infusion = src.GetItemCount(RoR2Content.Items.Infusion); parentEgg = src.GetItemCount(RoR2Content.Items.ParentEgg); missileVoid = src.GetItemCount(DLC1Content.Items.MissileVoid); unstableTransmitter = src.GetItemCount(DLC2Content.Items.TeleportOnLowHealth); noxiousThorn = src.GetItemCount(DLC2Content.Items.TriggerEnemyDebuffs); antlerShield = src.GetItemCount(DLC2Content.Items.NegateAttack); } } public struct HealthBarValues { public bool hasInfusion; public bool hasVoidShields; public bool isVoid; public bool isElite; public bool isBoss; public float cullFraction; public float healthFraction; public float shieldFraction; public float barrierFraction; public float magneticFraction; public float curseFraction; public float ospFraction; public int healthDisplayValue; public int maxHealthDisplayValue; } private class RepeatHealComponent : MonoBehaviour { private float reserve; private float timer; private const float interval = 0.2f; public float healthFractionToRestorePerSecond = 0.1f; public HealthComponent healthComponent; private void FixedUpdate() { timer -= Time.fixedDeltaTime; if (timer <= 0f) { timer = 0.2f; if (reserve > 0f) { float num = Mathf.Min(healthComponent.fullHealth * healthFractionToRestorePerSecond * 0.2f, reserve); reserve -= num; ProcChainMask procChainMask = default(ProcChainMask); procChainMask.AddProc(ProcType.RepeatHeal); healthComponent.Heal(num, procChainMask); } } } public void AddReserve(float amount, float max) { reserve = Mathf.Min(reserve + amount, max); } } public static readonly float lowHealthFraction; [SyncVar] [HideInInspector] [Tooltip("How much health this object has.")] public float health = 100f; [HideInInspector] [Tooltip("How much shield this object has.")] [SyncVar] public float shield; [HideInInspector] [SyncVar(hook = "SetBarrier")] [Tooltip("How much barrier this object has.")] public float barrier; [SyncVar] [HideInInspector] public float magnetiCharge; public bool dontShowHealthbar; private const float recentlyTookDamageCoyoteTimer_Duration = 0.2f; [NonSerialized] public float recentlyTookDamageCoyoteTimer; public float globalDeathEventChanceCoefficient = 1f; [SyncVar] private uint _killingDamageType; public CharacterBody body; private ModelLocator modelLocator; private IPainAnimationHandler painAnimationHandler; private IOnIncomingDamageServerReceiver[] onIncomingDamageReceivers; private IOnTakeDamageServerReceiver[] onTakeDamageReceivers; public ScreenDamageCalculator screenDamageCalculator; public const float frozenExecuteThreshold = 0.3f; private const float adaptiveArmorPerOnePercentTaken = 30f; private const float adaptiveArmorDecayPerSecond = 40f; private const float adaptiveArmorCap = 400f; public const float medkitActivationDelay = 2f; private const float devilOrbMaxTimer = 0.1f; private float devilOrbHealPool; private float devilOrbTimer; private float regenAccumulator; private bool wasAlive = true; private float adaptiveArmorValue; private bool isShieldRegenForced; public bool forceCulled; private float ospTimer; private const float ospBufferDuration = 0.1f; private float serverDamageTakenThisUpdate; private RepeatHealComponent repeatHealComponent; private ItemCounts itemCounts; private EquipmentIndex currentEquipmentIndex; private static int kCmdCmdHealFull; private static int kCmdCmdRechargeShieldFull; private static int kCmdCmdAddBarrier; private static int kCmdCmdForceShieldRegen; public bool recentlyTookDamage { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return recentlyTookDamageCoyoteTimer > 0f; } } public DamageTypeCombo killingDamageType { get { return _killingDamageType; } private set { Network_killingDamageType = (uint)(ulong)value; } } public bool alive => health > 0f; public float fullHealth => body.maxHealth; public float fullShield => body.maxShield; public float fullBarrier => body.maxBarrier; public float combinedHealth => health + shield + barrier; public float fullCombinedHealth => fullHealth + fullShield; public float combinedHealthFraction => combinedHealth / fullCombinedHealth; public float missingCombinedHealth => fullCombinedHealth - (combinedHealth - barrier); public Run.FixedTimeStamp lastHitTime { get; private set; } public Run.FixedTimeStamp lastHealTime { get; private set; } public GameObject lastHitAttacker { get; private set; } public float timeSinceLastHit => lastHitTime.timeSince; public float timeSinceLastHeal => lastHealTime.timeSince; public bool godMode { get; set; } public float potionReserve { get; private set; } public bool isInFrozenState { get; set; } public bool isHealthLow => (health + shield) / fullCombinedHealth <= lowHealthFraction; public float Networkhealth { get { return health; } [param: In] set { SetSyncVar(value, ref health, 1u); } } public float Networkshield { get { return shield; } [param: In] set { SetSyncVar(value, ref shield, 2u); } } public float Networkbarrier { get { return barrier; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SetBarrier(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref barrier, 4u); } } public float NetworkmagnetiCharge { get { return magnetiCharge; } [param: In] set { SetSyncVar(value, ref magnetiCharge, 8u); } } public uint Network_killingDamageType { get { return _killingDamageType; } [param: In] set { SetSyncVar(value, ref _killingDamageType, 16u); } } public static event Action onCharacterHealServer; private void SetBarrier(float newBarrier) { float num = barrier; Networkbarrier = newBarrier; if (barrier <= 0f && num > 0f) { body.MarkAllStatsDirty(); } } public void OnValidate() { if (base.gameObject.GetComponents().Length > 1) { UnityEngine.Debug.LogErrorFormat(base.gameObject, "{0} has multiple health components!!", base.gameObject); } } public float Heal(float amount, ProcChainMask procChainMask, bool nonRegen = true) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Single RoR2.HealthComponent::Heal(System.Single, RoR2.ProcChainMask, System.Boolean)' called on client"); return 0f; } if (!alive || amount <= 0f || body.HasBuff(RoR2Content.Buffs.HealingDisabled)) { return 0f; } recentlyTookDamageCoyoteTimer = 0.2f; float num = health; bool flag = false; if (currentEquipmentIndex == RoR2Content.Equipment.LunarPotion.equipmentIndex && !procChainMask.HasProc(ProcType.LunarPotionActivation)) { potionReserve += amount; return amount; } if (nonRegen && !procChainMask.HasProc(ProcType.CritHeal) && Util.CheckRoll(body.critHeal, body.master)) { procChainMask.AddProc(ProcType.CritHeal); flag = true; } if (flag) { amount *= 2f; } if (itemCounts.increaseHealing > 0) { amount *= 1f + (float)itemCounts.increaseHealing; } if (body.teamComponent.teamIndex == TeamIndex.Player && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse5) { amount /= 2f; } if (nonRegen && (bool)repeatHealComponent && !procChainMask.HasProc(ProcType.RepeatHeal)) { repeatHealComponent.healthFractionToRestorePerSecond = 0.1f / (float)itemCounts.repeatHeal; repeatHealComponent.AddReserve(amount * (float)(1 + itemCounts.repeatHeal), fullHealth); return 0f; } if (body.HasBuff(DLC2Content.Buffs.lunarruin)) { amount *= 0.8f; } if (body.HasBuff(DLC2Content.Buffs.SojournHealing)) { int buffCount = body.GetBuffCount(DLC2Content.Buffs.SojournHealing); float num2 = 1f - (float)buffCount * 0.1f; if (num2 < 0f) { num2 = 0f; } amount *= num2; } float num3 = amount; if (health < fullHealth) { float num4 = Mathf.Max(Mathf.Min(amount, fullHealth - health), 0f); num3 = amount - num4; Networkhealth = health + num4; } if (num3 > 0f && nonRegen && itemCounts.barrierOnOverHeal > 0) { float value = num3 * ((float)itemCounts.barrierOnOverHeal * 0.5f); AddBarrier(value); } if (nonRegen) { lastHealTime = Run.FixedTimeStamp.now; SendHeal(base.gameObject, amount, flag); if (itemCounts.novaOnHeal > 0 && !procChainMask.HasProc(ProcType.HealNova)) { devilOrbHealPool = Mathf.Min(devilOrbHealPool + amount * (float)itemCounts.novaOnHeal, fullCombinedHealth); } } if (flag) { GlobalEventManager.instance.OnCrit(body, null, body.master, amount / fullHealth * 10f, procChainMask); } if (nonRegen) { HealthComponent.onCharacterHealServer?.Invoke(this, amount, procChainMask); } if ((bool)body.inventory && body.inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage) > 0 && alive) { body.UpdateLowerHealthHigherDamage(); } return health - num; } public void UsePotion() { ProcChainMask procChainMask = default(ProcChainMask); procChainMask.AddProc(ProcType.LunarPotionActivation); Heal(potionReserve, procChainMask); } public float HealFraction(float fraction, ProcChainMask procChainMask) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Single RoR2.HealthComponent::HealFraction(System.Single, RoR2.ProcChainMask)' called on client"); return 0f; } return Heal(fraction * fullHealth, procChainMask); } public void SetCurrentHealthLevel() { } public float GetNormalizedHealth() { return health / fullHealth; } [Command] public void CmdHealFull() { HealFraction(1f, default(ProcChainMask)); } [Server] public void RechargeShieldFull() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::RechargeShieldFull()' called on client"); } else if (shield < fullShield) { Networkshield = fullShield; } } [Command] public void CmdRechargeShieldFull() { RechargeShieldFull(); } [Server] public void RechargeShield(float value) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::RechargeShield(System.Single)' called on client"); } else if (shield < fullShield) { Networkshield = shield + value; if (shield > fullShield) { Networkshield = fullShield; } } } [Server] public void AddBarrier(float value) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::AddBarrier(System.Single)' called on client"); } else if (alive && barrier < fullBarrier) { Networkbarrier = Mathf.Min(barrier + value, fullBarrier); } } [Server] public void AddCharge(float value) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::AddCharge(System.Single)' called on client"); } else if (alive && magnetiCharge < fullHealth) { NetworkmagnetiCharge = Mathf.Min(barrier + value, fullBarrier); } } [Command] private void CmdAddBarrier(float value) { AddBarrier(value); } public void AddBarrierAuthority(float value) { if (NetworkServer.active) { AddBarrier(value); } else { CallCmdAddBarrier(value); } } [Command] private void CmdForceShieldRegen() { ForceShieldRegen(); } public void ForceShieldRegen() { if (NetworkServer.active) { isShieldRegenForced = true; } else { CallCmdForceShieldRegen(); } } [Server] public void Die(bool noCorpse = false) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::Die(System.Boolean)' called on client"); return; } Networkhealth = 0f; modelLocator.forceCulled = noCorpse; if ((bool)body && body.cost > 0f && CombatDirector.instancesList.Count > 0) { CombatDirector combatDirector = CombatDirector.instancesList[0]; if (body.isElite || CombatDirector.IsEliteOnlyArtifactActive()) { combatDirector.monsterCredit += body.cost; } else { combatDirector.refundedMonsterCredit += body.cost; } UnityEngine.Debug.LogError("Refunded CombatDirector " + body.cost + " credits"); } } [Server] public void TakeDamageForce(DamageInfo damageInfo, bool alwaysApply = false, bool disableAirControlUntilCollision = false) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::TakeDamageForce(RoR2.DamageInfo,System.Boolean,System.Boolean)' called on client"); } else if (!body.HasBuff(RoR2Content.Buffs.EngiShield) || !(shield > 0f)) { CharacterMotor component = GetComponent(); if ((bool)component) { component.ApplyForce(damageInfo.force, alwaysApply, disableAirControlUntilCollision); } Rigidbody component2 = GetComponent(); if ((bool)component2) { component2.AddForce(damageInfo.force, ForceMode.Impulse); } } } [Server] public void TakeDamageForce(UnityEngine.Vector3 force, bool alwaysApply = false, bool disableAirControlUntilCollision = false) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::TakeDamageForce(UnityEngine.Vector3,System.Boolean,System.Boolean)' called on client"); } else if (!body.HasBuff(RoR2Content.Buffs.EngiShield) || !(shield > 0f)) { CharacterMotor component = GetComponent(); if ((bool)component) { component.ApplyForce(force, alwaysApply, disableAirControlUntilCollision); } Rigidbody component2 = GetComponent(); if ((bool)component2) { component2.AddForce(force, ForceMode.Impulse); } } } [Server] public void TakeDamage(DamageInfo damageInfo) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::TakeDamage(RoR2.DamageInfo)' called on client"); } else { TakeDamageProcess(damageInfo); } } private void TakeDamageProcess(DamageInfo damageInfo) { if (body.HasBuff(DLC2Content.Buffs.HiddenRejectAllDamage)) { return; } if (!damageInfo.canRejectForce) { TakeDamageForce(damageInfo); } if (!alive || godMode || ospTimer > 0f) { return; } CharacterMaster characterMaster = null; CharacterBody characterBody = null; TeamIndex teamIndex = TeamIndex.None; UnityEngine.Vector3 vector = UnityEngine.Vector3.zero; float num = combinedHealth; if ((bool)damageInfo.attacker) { characterBody = damageInfo.attacker.GetComponent(); if ((bool)characterBody) { teamIndex = characterBody.teamComponent.teamIndex; vector = characterBody.corePosition - damageInfo.position; } } if ((DamageTypeExtended)(damageInfo.damageType & DamageTypeExtended.DamagePercentOfMaxHealth) == DamageTypeExtended.DamagePercentOfMaxHealth) { damageInfo.damage = fullHealth * 0.1f; } bool flag = (ulong)(damageInfo.damageType & DamageType.BypassArmor) != 0; bool flag2 = (ulong)(damageInfo.damageType & DamageType.BypassBlock) != 0; if (!flag2 && itemCounts.bear > 0 && Util.CheckRoll(Util.ConvertAmplificationPercentageIntoReductionPercentage(15f * (float)itemCounts.bear))) { EffectData effectData = new EffectData { origin = damageInfo.position, rotation = Util.QuaternionSafeLookRotation((damageInfo.force != UnityEngine.Vector3.zero) ? damageInfo.force : UnityEngine.Random.onUnitSphere) }; EffectManager.SpawnEffect(AssetReferences.bearEffectPrefab, effectData, transmit: true); damageInfo.rejected = true; } if (!flag2 && body.HasBuff(DLC1Content.Buffs.BearVoidReady) && damageInfo.damage > 0f) { EffectData effectData2 = new EffectData { origin = damageInfo.position, rotation = Util.QuaternionSafeLookRotation((damageInfo.force != UnityEngine.Vector3.zero) ? damageInfo.force : UnityEngine.Random.onUnitSphere) }; EffectManager.SpawnEffect(AssetReferences.bearVoidEffectPrefab, effectData2, transmit: true); damageInfo.rejected = true; body.RemoveBuff(DLC1Content.Buffs.BearVoidReady); int itemCount = body.inventory.GetItemCount(DLC1Content.Items.BearVoid); Mathf.CeilToInt(15f * Mathf.Pow(0.9f, itemCount)); body.AddTimedBuff(DLC1Content.Buffs.BearVoidCooldown, 15f * Mathf.Pow(0.9f, itemCount)); } if (body.HasBuff(RoR2Content.Buffs.HiddenInvincibility) && !flag) { damageInfo.rejected = true; } if (((ulong)(damageInfo.damageType & DamageTypeExtended.SojournVehicleDamage) == 0) & body.HasBuff(DLC2Content.Buffs.SojournVehicle)) { damageInfo.rejected = true; } if (body.HasBuff(RoR2Content.Buffs.Immune) && (!characterBody || !characterBody.HasBuff(JunkContent.Buffs.GoldEmpowered))) { EffectManager.SpawnEffect(AssetReferences.damageRejectedPrefab, new EffectData { origin = damageInfo.position }, transmit: true); damageInfo.rejected = true; } if (!damageInfo.rejected && body.HasBuff(JunkContent.Buffs.BodyArmor)) { body.RemoveBuff(JunkContent.Buffs.BodyArmor); EffectData effectData3 = new EffectData { origin = damageInfo.position, rotation = Util.QuaternionSafeLookRotation((damageInfo.force != UnityEngine.Vector3.zero) ? damageInfo.force : UnityEngine.Random.onUnitSphere) }; EffectManager.SpawnEffect(AssetReferences.captainBodyArmorBlockEffectPrefab, effectData3, transmit: true); damageInfo.rejected = true; } IOnIncomingDamageServerReceiver[] array = onIncomingDamageReceivers; for (int i = 0; i < array.Length; i++) { array[i].OnIncomingDamageServer(damageInfo); } if (damageInfo.rejected) { return; } if (body.HasBuff(DLC2Content.Buffs.lunarruin)) { float num2 = (float)body.GetBuffCount(DLC2Content.Buffs.lunarruin) * 0.1f; float num3 = damageInfo.damage * num2; damageInfo.damage += num3; } float num4 = damageInfo.damage; if (teamIndex == body.teamComponent.teamIndex) { TeamDef teamDef = TeamCatalog.GetTeamDef(teamIndex); if (teamDef != null) { num4 *= teamDef.friendlyFireScaling; } } if (num4 > 0f) { if ((bool)characterBody) { if (characterBody.canPerformBackstab && (DamageType)(damageInfo.damageType & DamageType.DoT) != DamageType.DoT && (damageInfo.procChainMask.HasProc(ProcType.Backstab) || BackstabManager.IsBackstab(-vector, body))) { damageInfo.crit = true; damageInfo.procChainMask.AddProc(ProcType.Backstab); if ((bool)BackstabManager.backstabImpactEffectPrefab) { EffectManager.SimpleImpactEffect(BackstabManager.backstabImpactEffectPrefab, damageInfo.position, -damageInfo.force, transmit: true); } } characterMaster = characterBody.master; if ((bool)characterMaster && (bool)characterMaster.inventory) { if (num >= fullCombinedHealth * 0.9f) { int itemCount2 = characterMaster.inventory.GetItemCount(RoR2Content.Items.Crowbar); if (itemCount2 > 0) { num4 *= 1f + 0.75f * (float)itemCount2; EffectManager.SimpleImpactEffect(AssetReferences.crowbarImpactEffectPrefab, damageInfo.position, -damageInfo.force, transmit: true); } } if (num >= fullCombinedHealth && !damageInfo.rejected) { int itemCount3 = characterMaster.inventory.GetItemCount(DLC1Content.Items.ExplodeOnDeathVoid); if (itemCount3 > 0) { UnityEngine.Vector3 corePosition = Util.GetCorePosition(body); float damageCoefficient = 2.6f * (1f + (float)(itemCount3 - 1) * 0.6f); float baseDamage = Util.OnKillProcDamage(characterBody.damage, damageCoefficient); GameObject obj = UnityEngine.Object.Instantiate(AssetReferences.explodeOnDeathVoidExplosionPrefab, corePosition, UnityEngine.Quaternion.identity); DelayBlast component = obj.GetComponent(); component.position = corePosition; component.baseDamage = baseDamage; component.baseForce = 1000f; component.radius = 12f + 2.4f * ((float)itemCount3 - 1f); component.attacker = damageInfo.attacker; component.inflictor = null; component.crit = Util.CheckRoll(characterBody.crit, characterMaster); component.maxTimer = 0.2f; component.damageColorIndex = DamageColorIndex.Void; component.falloffModel = BlastAttack.FalloffModel.SweetSpot; obj.GetComponent().teamIndex = teamIndex; NetworkServer.Spawn(obj); } } int itemCount4 = characterMaster.inventory.GetItemCount(RoR2Content.Items.NearbyDamageBonus); if (itemCount4 > 0 && vector.sqrMagnitude <= 169f) { damageInfo.damageColorIndex = DamageColorIndex.Nearby; num4 *= 1f + (float)itemCount4 * 0.2f; EffectManager.SimpleImpactEffect(AssetReferences.diamondDamageBonusImpactEffectPrefab, damageInfo.position, vector, transmit: true); } int itemCount5 = characterMaster.inventory.GetItemCount(DLC1Content.Items.FragileDamageBonus); if (itemCount5 > 0) { num4 *= 1f + (float)itemCount5 * 0.2f; } if (characterMaster.GetBody().HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff)) { int itemCount6 = characterMaster.inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage); num4 *= 1f + (float)itemCount6 * 0.2f; } if (damageInfo.procCoefficient > 0f) { int itemCount7 = characterMaster.inventory.GetItemCount(RoR2Content.Items.ArmorReductionOnHit); if (itemCount7 > 0 && !body.HasBuff(RoR2Content.Buffs.Pulverized)) { body.AddTimedBuff(RoR2Content.Buffs.PulverizeBuildup, 2f * damageInfo.procCoefficient); if (body.GetBuffCount(RoR2Content.Buffs.PulverizeBuildup) >= 5) { body.ClearTimedBuffs(RoR2Content.Buffs.PulverizeBuildup); body.AddTimedBuff(RoR2Content.Buffs.Pulverized, 8f * (float)itemCount7); EffectManager.SpawnEffect(AssetReferences.pulverizedEffectPrefab, new EffectData { origin = body.corePosition, scale = body.radius }, transmit: true); } } int itemCount8 = characterMaster.inventory.GetItemCount(DLC1Content.Items.PermanentDebuffOnHit); bool flag3 = false; for (int j = 0; j < itemCount8; j++) { if (Util.CheckRoll(100f * damageInfo.procCoefficient, characterMaster)) { body.AddBuff(DLC1Content.Buffs.PermanentDebuff); flag3 = true; } } if (flag3) { EffectManager.SpawnEffect(AssetReferences.permanentDebuffEffectPrefab, new EffectData { origin = damageInfo.position, scale = itemCount8 }, transmit: true); } if (body.HasBuff(RoR2Content.Buffs.MercExpose) && (bool)characterBody && characterBody.bodyIndex == BodyCatalog.FindBodyIndex("MercBody")) { body.RemoveBuff(RoR2Content.Buffs.MercExpose); float num5 = characterBody.damage * 3.5f; num4 += num5; damageInfo.damage += num5; SkillLocator skillLocator = characterBody.skillLocator; if ((bool)skillLocator) { skillLocator.DeductCooldownFromAllSkillsServer(1f); } EffectManager.SimpleImpactEffect(AssetReferences.mercExposeConsumeEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true); } } if (body.isBoss) { int itemCount9 = characterMaster.inventory.GetItemCount(RoR2Content.Items.BossDamageBonus); if (itemCount9 > 0) { num4 *= 1f + 0.2f * (float)itemCount9; damageInfo.damageColorIndex = DamageColorIndex.WeakPoint; EffectManager.SimpleImpactEffect(AssetReferences.bossDamageBonusImpactEffectPrefab, damageInfo.position, -damageInfo.force, transmit: true); } } } if (damageInfo.crit) { num4 *= characterBody.critMultiplier; } } if ((ulong)(damageInfo.damageType & DamageType.WeakPointHit) != 0L) { num4 *= 1.5f; damageInfo.damageColorIndex = DamageColorIndex.WeakPoint; } if (body.HasBuff(RoR2Content.Buffs.DeathMark)) { num4 *= 1.5f; damageInfo.damageColorIndex = DamageColorIndex.DeathMark; } if (!flag) { float armor = body.armor; armor += adaptiveArmorValue; bool flag4 = (ulong)(damageInfo.damageType & DamageType.AOE) != 0; if ((body.bodyFlags & CharacterBody.BodyFlags.ResistantToAOE) != 0 && flag4) { armor += 300f; } float num6 = ((armor >= 0f) ? (1f - armor / (armor + 100f)) : (2f - 100f / (100f - armor))); num4 = Mathf.Max(1f, num4 * num6); if (itemCounts.armorPlate > 0) { num4 = Mathf.Max(1f, num4 - 5f * (float)itemCounts.armorPlate); EntitySoundManager.EmitSoundServer(LegacyResourcesAPI.Load("NetworkSoundEventDefs/nseArmorPlateBlock").index, base.gameObject); } if (itemCounts.parentEgg > 0) { Heal((float)itemCounts.parentEgg * 15f, default(ProcChainMask)); EntitySoundManager.EmitSoundServer(LegacyResourcesAPI.Load("NetworkSoundEventDefs/nseParentEggHeal").index, base.gameObject); } } if (body.hasOneShotProtection && (DamageType)(damageInfo.damageType & DamageType.BypassOneShotProtection) != DamageType.BypassOneShotProtection) { float num7 = (fullCombinedHealth + barrier) * (1f - body.oneShotProtectionFraction); float b = Mathf.Max(0f, num7 - serverDamageTakenThisUpdate); float num8 = num4; num4 = Mathf.Min(num4, b); if (num4 != num8) { TriggerOneShotProtection(); } } if ((ulong)(damageInfo.damageType & DamageType.BonusToLowHealth) != 0) { float num9 = Mathf.Lerp(3f, 1f, combinedHealthFraction); num4 *= num9; } if (body.HasBuff(RoR2Content.Buffs.LunarShell) && num4 > fullHealth * 0.1f) { num4 = fullHealth * 0.1f; } if (itemCounts.minHealthPercentage > 0) { float num10 = fullCombinedHealth * ((float)itemCounts.minHealthPercentage / 100f); num4 = Mathf.Max(0f, Mathf.Min(num4, combinedHealth - num10)); } } if ((ulong)(damageInfo.damageType & DamageType.SlowOnHit) != 0L) { body.AddTimedBuff(RoR2Content.Buffs.Slow50, 2f); } if ((ulong)(damageInfo.damageType & DamageType.ClayGoo) != 0L && (body.bodyFlags & CharacterBody.BodyFlags.ImmuneToGoo) == 0) { body.AddTimedBuff(RoR2Content.Buffs.ClayGoo, 2f); } if ((ulong)(damageInfo.damageType & DamageType.Nullify) != 0L) { body.AddTimedBuff(RoR2Content.Buffs.NullifyStack, 8f); } if ((ulong)(damageInfo.damageType & DamageType.CrippleOnHit) != 0L || ((bool)characterBody && characterBody.HasBuff(RoR2Content.Buffs.AffixLunar))) { body.AddTimedBuff(RoR2Content.Buffs.Cripple, 3f); } if ((ulong)(damageInfo.damageType & DamageType.ApplyMercExpose) != 0L) { UnityEngine.Debug.LogFormat("Adding expose"); body.AddBuff(RoR2Content.Buffs.MercExpose); } CharacterMaster master = body.master; if ((bool)master) { if (itemCounts.goldOnHit > 0) { uint num11 = (uint)(num4 / fullCombinedHealth * (float)master.money * (float)itemCounts.goldOnHit); uint money = master.money; master.money = (uint)Mathf.Max(0f, (float)master.money - (float)num11); if (money - master.money != 0) { GoldOrb goldOrb = new GoldOrb(); goldOrb.origin = damageInfo.position; goldOrb.target = (characterBody ? characterBody.mainHurtBox : body.mainHurtBox); goldOrb.goldAmount = 0u; OrbManager.instance.AddOrb(goldOrb); EffectManager.SimpleImpactEffect(AssetReferences.loseCoinsImpactEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true); } } if (itemCounts.goldOnHurt > 0 && characterBody != body && characterBody != null) { int num12 = 3; GoldOrb goldOrb2 = new GoldOrb(); goldOrb2.origin = damageInfo.position; goldOrb2.target = body.mainHurtBox; goldOrb2.goldAmount = (uint)((float)(itemCounts.goldOnHurt * num12) * Run.instance.difficultyCoefficient); OrbManager.instance.AddOrb(goldOrb2); EffectManager.SimpleImpactEffect(AssetReferences.gainCoinsImpactEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true); } } if (itemCounts.adaptiveArmor > 0) { float num13 = num4 / fullCombinedHealth * 100f * 30f * (float)itemCounts.adaptiveArmor; adaptiveArmorValue = Mathf.Min(adaptiveArmorValue + num13, 400f); } float num14 = num4; if (num14 > 0f) { isShieldRegenForced = false; } if (body.teamComponent.teamIndex == TeamIndex.Player && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse8) { float num15 = num14 / fullCombinedHealth * 100f; float num16 = 0.4f; int num17 = Mathf.FloorToInt(num15 * num16); for (int k = 0; k < num17; k++) { body.AddBuff(RoR2Content.Buffs.PermanentCurse); } } if (num14 > 0f && barrier > 0f) { if (num14 <= barrier) { Networkbarrier = barrier - num14; num14 = 0f; } else { num14 -= barrier; Networkbarrier = 0f; } } if (num14 > 0f && shield > 0f) { if (num14 <= shield) { Networkshield = shield - num14; num14 = 0f; } else { num14 -= shield; Networkshield = 0f; float scale = 1f; if ((bool)body) { scale = body.radius; } EffectManager.SpawnEffect(AssetReferences.shieldBreakEffectPrefab, new EffectData { origin = base.transform.position, scale = scale }, transmit: true); } } if (!flag2 && body.HasBuff(DLC2Content.Buffs.DelayedDamageBuff) && damageInfo.damage > 0f && !damageInfo.delayedDamageSecondHalf && !damageInfo.rejected) { Transform transform = (body.mainHurtBox ? body.mainHurtBox.transform : base.transform); UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/Effects/DelayedDamageIndicator"), transform.position, UnityEngine.Quaternion.identity, transform); Util.PlaySound("Play_item_proc_delayedDamage", body.gameObject); num14 *= 0.5f; num4 = num14; DamageInfo damageInfo2 = new DamageInfo { crit = damageInfo.crit, damage = num14, damageType = DamageType.BypassArmor, attacker = damageInfo.attacker, position = damageInfo.position, inflictor = damageInfo.inflictor, damageColorIndex = damageInfo.damageColorIndex, delayedDamageSecondHalf = true }; damageInfo2.damageType |= damageInfo.damageType & DamageType.NonLethal; body.SecondHalfOfDelayedDamage(damageInfo2); } bool flag5 = (ulong)(damageInfo.damageType & DamageType.VoidDeath) != 0L && (body.bodyFlags & CharacterBody.BodyFlags.ImmuneToVoidDeath) == 0; float executionHealthLost = 0f; GameObject gameObject = null; if (num14 > 0f) { float num18 = health - num14; if (num18 < 1f && (ulong)(damageInfo.damageType & DamageType.NonLethal) != 0L && health >= 1f) { num18 = 1f; } Networkhealth = num18; recentlyTookDamageCoyoteTimer = 0.2f; } if (health > 0f && body.teamComponent.teamIndex == TeamIndex.Player && (bool)body.inventory && body.inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage) > 0) { body.UpdateLowerHealthHigherDamage(); } float num19 = float.NegativeInfinity; bool flag6 = (body.bodyFlags & CharacterBody.BodyFlags.ImmuneToExecutes) != 0; if (!flag5 && !flag6) { if (isInFrozenState && num19 < 0.3f) { num19 = 0.3f; gameObject = FrozenState.executeEffectPrefab; } if ((bool)characterBody) { if (body.isElite) { float executeEliteHealthFraction = characterBody.executeEliteHealthFraction; if (num19 < executeEliteHealthFraction) { num19 = executeEliteHealthFraction; gameObject = AssetReferences.executeEffectPrefab; } } if (!body.isBoss && (bool)characterBody.inventory && Util.CheckRoll((float)characterBody.inventory.GetItemCount(DLC1Content.Items.CritGlassesVoid) * 0.5f * damageInfo.procCoefficient, characterBody.master)) { flag5 = true; gameObject = AssetReferences.critGlassesVoidExecuteEffectPrefab; damageInfo.damageType |= (DamageTypeCombo)DamageType.VoidDeath; } } } if (flag5 || (num19 > 0f && combinedHealthFraction <= num19)) { flag5 = true; executionHealthLost = Mathf.Max(combinedHealth, 0f); if (health > 0f) { Networkhealth = 0f; } if (shield > 0f) { Networkshield = 0f; } if (barrier > 0f) { Networkbarrier = 0f; } } if (damageInfo.canRejectForce) { TakeDamageForce(damageInfo); } DamageReport damageReport = new DamageReport(damageInfo, this, num4, num); IOnTakeDamageServerReceiver[] array2 = onTakeDamageReceivers; for (int i = 0; i < array2.Length; i++) { array2[i].OnTakeDamageServer(damageReport); } if (num4 > 0f) { SendDamageDealt(damageReport); } UpdateLastHitTime(damageReport.damageDealt, damageInfo.position, (ulong)(damageInfo.damageType & DamageType.Silent) != 0, damageInfo.attacker); if ((bool)damageInfo.attacker) { List gameObjectComponents = GetComponentsCache.GetGameObjectComponents(damageInfo.attacker); foreach (IOnDamageDealtServerReceiver item in gameObjectComponents) { item.OnDamageDealtServer(damageReport); } GetComponentsCache.ReturnBuffer(gameObjectComponents); } if ((bool)damageInfo.inflictor) { List gameObjectComponents2 = GetComponentsCache.GetGameObjectComponents(damageInfo.inflictor); foreach (IOnDamageInflictedServerReceiver item2 in gameObjectComponents2) { item2.OnDamageInflictedServer(damageReport); } GetComponentsCache.ReturnBuffer(gameObjectComponents2); } GlobalEventManager.ServerDamageDealt(damageReport); if (!alive) { killingDamageType = damageInfo.damageType; if (flag5) { GlobalEventManager.ServerCharacterExecuted(damageReport, executionHealthLost); if ((object)gameObject != null) { EffectManager.SpawnEffect(gameObject, new EffectData { origin = body.corePosition, scale = (body ? body.radius : 1f) }, transmit: true); } } IOnKilledServerReceiver[] components = GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].OnKilledServer(damageReport); } if ((bool)damageInfo.attacker) { IOnKilledOtherServerReceiver[] components2 = damageInfo.attacker.GetComponents(); for (int i = 0; i < components2.Length; i++) { components2[i].OnKilledOtherServer(damageReport); } } if (Util.CheckRoll(globalDeathEventChanceCoefficient * 100f)) { GlobalEventManager.instance.OnCharacterDeath(damageReport); } } else { if (!(num4 > 0f)) { return; } int a = 5 + 2 * (itemCounts.thorns - 1); if (itemCounts.thorns > 0 && !damageReport.damageInfo.procChainMask.HasProc(ProcType.Thorns)) { bool flag7 = itemCounts.invadingDoppelganger > 0; float radius = 25f + 10f * (float)(itemCounts.thorns - 1); bool isCrit = body.RollCrit(); float damageValue = 1.6f * body.damage; TeamIndex teamIndex2 = body.teamComponent.teamIndex; HurtBox[] hurtBoxes = new SphereSearch { origin = damageReport.damageInfo.position, radius = radius, mask = LayerIndex.entityPrecise.mask, queryTriggerInteraction = QueryTriggerInteraction.UseGlobal }.RefreshCandidates().FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(teamIndex2)).OrderCandidatesByDistance() .FilterCandidatesByDistinctHurtBoxEntities() .GetHurtBoxes(); for (int l = 0; l < Mathf.Min(a, hurtBoxes.Length); l++) { LightningOrb lightningOrb = new LightningOrb(); lightningOrb.attacker = base.gameObject; lightningOrb.bouncedObjects = null; lightningOrb.bouncesRemaining = 0; lightningOrb.damageCoefficientPerBounce = 1f; lightningOrb.damageColorIndex = DamageColorIndex.Item; lightningOrb.damageValue = damageValue; lightningOrb.isCrit = isCrit; lightningOrb.lightningType = LightningOrb.LightningType.RazorWire; lightningOrb.origin = damageReport.damageInfo.position; lightningOrb.procChainMask = default(ProcChainMask); lightningOrb.procChainMask.AddProc(ProcType.Thorns); lightningOrb.procCoefficient = (flag7 ? 0f : 0.5f); lightningOrb.range = 0f; lightningOrb.teamIndex = teamIndex2; lightningOrb.target = hurtBoxes[l]; OrbManager.instance.AddOrb(lightningOrb); } } if (!flag2 && itemCounts.antlerShield > 0 && characterBody != null && !damageInfo.delayedDamageSecondHalf && damageInfo.attacker.GetComponent().teamIndex != body.teamComponent.teamIndex && Util.CheckRoll(50f + 5f * (float)(itemCounts.antlerShield - 1))) { bool flag8 = itemCounts.invadingDoppelganger > 0; float damageValue2 = damageInfo.damage / 10f * (float)itemCounts.antlerShield; bool isCrit2 = body.RollCrit(); TeamIndex teamIndex3 = body.teamComponent.teamIndex; LightningOrb lightningOrb2 = new LightningOrb(); lightningOrb2.attacker = base.gameObject; lightningOrb2.bouncedObjects = null; lightningOrb2.bouncesRemaining = 0; lightningOrb2.damageCoefficientPerBounce = 1f; lightningOrb2.damageColorIndex = DamageColorIndex.Item; lightningOrb2.damageValue = damageValue2; lightningOrb2.isCrit = isCrit2; lightningOrb2.lightningType = LightningOrb.LightningType.AntlerShield; lightningOrb2.origin = damageReport.damageInfo.position; lightningOrb2.procChainMask = default(ProcChainMask); lightningOrb2.procChainMask.AddProc(ProcType.Thorns); lightningOrb2.procCoefficient = (flag8 ? 0f : 0.3f); lightningOrb2.range = 0f; lightningOrb2.teamIndex = teamIndex3; lightningOrb2.target = characterBody.mainHurtBox; OrbManager.instance.AddOrb(lightningOrb2); Util.PlaySound("Play_item_proc_negateAttack", body.gameObject); } if (!flag2 && itemCounts.noxiousThorn > 0 && Util.CheckRoll(25f)) { body.TriggerEnemyDebuffs(damageInfo); } if (!body.HasBuff(DLC2Content.Buffs.AurelioniteBlessing)) { return; } int baseCost = 1; int difficultyScaledCost = Run.instance.GetDifficultyScaledCost(baseCost); uint money2 = characterMaster.money; characterMaster.money = (uint)Mathf.Max(0f, (float)characterMaster.money - (float)difficultyScaledCost); if (money2 - characterMaster.money != 0 || !characterBody.isPlayerControlled) { GoldOrb goldOrb3 = new GoldOrb(); goldOrb3.origin = characterBody.transform.position; goldOrb3.target = (body ? body.mainHurtBox : characterBody.mainHurtBox); goldOrb3.goldAmount = (uint)difficultyScaledCost; OrbManager.instance.AddOrb(goldOrb3); EffectManager.SimpleImpactEffect(AssetReferences.loseCoinsImpactEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true); if (!characterBody.isPlayerControlled) { characterMaster.money = money2; } } } } [Server] private void TriggerOneShotProtection() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::TriggerOneShotProtection()' called on client"); return; } ospTimer = 0.1f; if (body.GetBuffCount(DLC2Content.Buffs.DelayedDamageDebuff) > 0) { body.protectFromOneShot = true; } } [Server] public void Suicide(GameObject killerOverride = null, GameObject inflictorOverride = null, DamageTypeCombo damageType = default(DamageTypeCombo)) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::Suicide(UnityEngine.GameObject,UnityEngine.GameObject,RoR2.DamageTypeCombo)' called on client"); } else if (alive && !godMode) { float combinedHealthBeforeDamage = combinedHealth; DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = combinedHealth; damageInfo.position = base.transform.position; damageInfo.damageType = damageType; damageInfo.procCoefficient = 1f; if ((bool)killerOverride) { damageInfo.attacker = killerOverride; } if ((bool)inflictorOverride) { damageInfo.inflictor = inflictorOverride; } Networkhealth = 0f; DamageReport damageReport = new DamageReport(damageInfo, this, damageInfo.damage, combinedHealthBeforeDamage); killingDamageType = damageInfo.damageType; IOnKilledServerReceiver[] components = GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].OnKilledServer(damageReport); } GlobalEventManager.instance.OnCharacterDeath(damageReport); } } public void UpdateLastHitTime(float damageValue, UnityEngine.Vector3 damagePosition, bool damageIsSilent, GameObject attacker) { if (NetworkServer.active && (bool)body && damageValue > 0f) { if (itemCounts.medkit > 0) { body.AddTimedBuff(RoR2Content.Buffs.MedkitHeal, 2f); } if (itemCounts.healingPotion > 0 && isHealthLow) { body.inventory.RemoveItem(DLC1Content.Items.HealingPotion); body.inventory.GiveItem(DLC1Content.Items.HealingPotionConsumed); CharacterMasterNotificationQueue.SendTransformNotification(body.master, DLC1Content.Items.HealingPotion.itemIndex, DLC1Content.Items.HealingPotionConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); HealFraction(0.75f, default(ProcChainMask)); EffectData effectData = new EffectData { origin = base.transform.position }; effectData.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/HealingPotionEffect"), effectData, transmit: true); } if (body.GetBuffCount(DLC2Content.Buffs.RevitalizeBuff) > 0 && isHealthLow) { body.RemoveBuff(DLC2Content.Buffs.RevitalizeBuff); HealFraction(0.5f, default(ProcChainMask)); EffectData effectData2 = new EffectData { origin = base.transform.position }; effectData2.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Seeker/RevitalizeBuffVFXConsumed"), effectData2, transmit: true); } float num = 120f; if (isHealthLow && body.HasBuff(DLC2Content.Buffs.TeleportOnLowHealth) && itemCounts.unstableTransmitter > 0) { body.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealth); float duration = Mathf.Max(num - num * ((float)(itemCounts.unstableTransmitter - 1) * 0.2f), 15f); body.AddTimedBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown, duration); body.hasTeleported = true; body.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 2f); body.CallRpcTeleportCharacterToSafety(); } if (itemCounts.fragileDamageBonus > 0 && isHealthLow) { body.inventory.GiveItem(DLC1Content.Items.FragileDamageBonusConsumed, itemCounts.fragileDamageBonus); body.inventory.RemoveItem(DLC1Content.Items.FragileDamageBonus, itemCounts.fragileDamageBonus); CharacterMasterNotificationQueue.SendTransformNotification(body.master, DLC1Content.Items.FragileDamageBonus.itemIndex, DLC1Content.Items.FragileDamageBonusConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); EffectData effectData3 = new EffectData { origin = base.transform.position }; effectData3.SetNetworkedObjectReference(base.gameObject); EffectManager.SpawnEffect(AssetReferences.fragileDamageBonusBreakEffectPrefab, effectData3, transmit: true); } } if (damageIsSilent) { return; } lastHitTime = Run.FixedTimeStamp.now; lastHitAttacker = attacker; serverDamageTakenThisUpdate += damageValue; if ((bool)modelLocator) { Transform modelTransform = modelLocator.modelTransform; if ((bool)modelTransform) { Animator component = modelTransform.GetComponent(); if ((bool)component) { string layerName = "Flinch"; int layerIndex = component.GetLayerIndex(layerName); if (layerIndex >= 0) { component.SetLayerWeight(layerIndex, 1f + Mathf.Clamp01(damageValue / fullCombinedHealth * 10f) * 3f); component.Play("FlinchStart", layerIndex); } } } } painAnimationHandler?.HandlePain(damageValue, damagePosition); } [InitDuringStartup] private static void Init() { AssetReferences.Resolve(); } private void Awake() { body = GetComponent(); modelLocator = GetComponent(); painAnimationHandler = GetComponent(); onIncomingDamageReceivers = GetComponents(); onTakeDamageReceivers = GetComponents(); lastHitTime = Run.FixedTimeStamp.negativeInfinity; lastHealTime = Run.FixedTimeStamp.negativeInfinity; body.onInventoryChanged += OnInventoryChanged; } private void OnDestroy() { body.onInventoryChanged -= OnInventoryChanged; } public void FixedUpdate() { ManagedFixedUpdate(Time.fixedDeltaTime); } public void ManagedFixedUpdate(float deltaTime) { if (NetworkServer.active) { ServerFixedUpdate(deltaTime); } if (!alive && wasAlive) { wasAlive = false; if ((bool)modelLocator) { modelLocator.forceCulled = forceCulled; } GetComponent()?.OnDeath(); } } private void ServerFixedUpdate(float deltaTime) { if (recentlyTookDamageCoyoteTimer > 0f) { recentlyTookDamageCoyoteTimer -= deltaTime; } if (!alive) { return; } regenAccumulator += body.regen * deltaTime; if (barrier > 0f) { Networkbarrier = Mathf.Max(barrier - body.barrierDecayRate * deltaTime, 0f); if (barrier <= 0f) { body.MarkAllStatsDirty(); } } else if (barrier <= 0f && body.HasBuff(DLC2Content.Buffs.GeodeBuff)) { body.RemoveBuff(DLC2Content.Buffs.GeodeBuff); } if (regenAccumulator > 1f) { float num = Mathf.Floor(regenAccumulator); regenAccumulator -= num; Heal(num, default(ProcChainMask), nonRegen: false); } if (regenAccumulator < -1f) { float num2 = Mathf.Ceil(regenAccumulator); regenAccumulator -= num2; Networkhealth = health + num2; if (health <= 0f) { Suicide(); } } float num3 = shield; bool flag = num3 >= body.maxShield; if ((body.outOfDanger || isShieldRegenForced) && !flag) { num3 += body.maxShield * 0.5f * deltaTime; if (num3 > body.maxShield) { num3 = body.maxShield; } } if (num3 >= body.maxShield && !flag) { Util.PlaySound("Play_item_proc_personal_shield_end", base.gameObject); } if (!num3.Equals(shield)) { Networkshield = num3; } if (devilOrbHealPool > 0f) { devilOrbTimer -= deltaTime; if (devilOrbTimer <= 0f) { devilOrbTimer += 0.1f; float scale = 1f; float num4 = fullCombinedHealth / 10f; float num5 = 2.5f; devilOrbHealPool -= num4; DevilOrb devilOrb = new DevilOrb(); devilOrb.origin = body.aimOriginTransform.position; devilOrb.damageValue = num4 * num5; devilOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject); devilOrb.attacker = base.gameObject; devilOrb.damageColorIndex = DamageColorIndex.Poison; devilOrb.scale = scale; devilOrb.procChainMask.AddProc(ProcType.HealNova); devilOrb.effectType = DevilOrb.EffectType.Skull; HurtBox hurtBox = devilOrb.PickNextTarget(devilOrb.origin, 40f); if ((bool)hurtBox) { devilOrb.target = hurtBox; devilOrb.isCrit = Util.CheckRoll(body.crit, body.master); OrbManager.instance.AddOrb(devilOrb); } } } adaptiveArmorValue = Mathf.Max(0f, adaptiveArmorValue - 40f * deltaTime); serverDamageTakenThisUpdate = 0f; ospTimer -= deltaTime; } private static void SendDamageDealt(DamageReport damageReport) { DamageInfo damageInfo = damageReport.damageInfo; DamageDealtMessage damageDealtMessage = new DamageDealtMessage(); damageDealtMessage.victim = damageReport.victim.gameObject; damageDealtMessage.damage = damageReport.damageDealt; damageDealtMessage.attacker = damageInfo.attacker; damageDealtMessage.position = damageInfo.position; damageDealtMessage.crit = damageInfo.crit; damageDealtMessage.damageType = damageInfo.damageType; damageDealtMessage.damageColorIndex = damageInfo.damageColorIndex; damageDealtMessage.hitLowHealth = damageReport.hitLowHealth; NetworkServer.SendToAll(60, damageDealtMessage); } [NetworkMessageHandler(msgType = 60, client = true)] private static void HandleDamageDealt(NetworkMessage netMsg) { DamageDealtMessage damageDealtMessage = netMsg.ReadMessage(); if ((bool)damageDealtMessage.victim) { HealthComponent component = damageDealtMessage.victim.GetComponent(); if ((bool)component && !NetworkServer.active) { component.UpdateLastHitTime(damageDealtMessage.damage, damageDealtMessage.position, damageDealtMessage.isSilent, damageDealtMessage.attacker); } } if (SettingsConVars.enableDamageNumbers.value && (bool)DamageNumberManager.instance) { TeamComponent teamComponent = null; if ((bool)damageDealtMessage.attacker) { teamComponent = damageDealtMessage.attacker.GetComponent(); } DamageNumberManager.instance.SpawnDamageNumber(damageDealtMessage.damage, damageDealtMessage.position, damageDealtMessage.crit, teamComponent ? teamComponent.teamIndex : TeamIndex.None, damageDealtMessage.damageColorIndex); } GlobalEventManager.ClientDamageNotified(damageDealtMessage); } private static void SendHeal(GameObject target, float amount, bool isCrit) { HealMessage healMessage = new HealMessage(); healMessage.target = target; healMessage.amount = (isCrit ? (0f - amount) : amount); NetworkServer.SendToAll(61, healMessage); } [NetworkMessageHandler(msgType = 61, client = true)] private static void HandleHeal(NetworkMessage netMsg) { HealMessage healMessage = netMsg.ReadMessage(); if (SettingsConVars.enableDamageNumbers.value && (bool)healMessage.target) { if ((bool)DamageNumberManager.instance) { DamageNumberManager.instance.SpawnDamageNumber(healMessage.amount, Util.GetCorePosition(healMessage.target), healMessage.amount < 0f, TeamIndex.Player, DamageColorIndex.Heal); } HealthComponent component = healMessage.target.GetComponent(); if ((bool)component && !NetworkServer.active) { component.lastHealTime = Run.FixedTimeStamp.now; } } } private void OnInventoryChanged() { itemCounts = default(ItemCounts); Inventory inventory = body.inventory; itemCounts = (inventory ? new ItemCounts(inventory) : default(ItemCounts)); currentEquipmentIndex = (inventory ? inventory.currentEquipmentIndex : EquipmentIndex.None); if (!NetworkServer.active) { return; } bool flag = itemCounts.repeatHeal != 0; if (flag != (bool)repeatHealComponent) { if (flag) { repeatHealComponent = base.gameObject.AddComponent(); repeatHealComponent.healthComponent = this; } else { UnityEngine.Object.Destroy(repeatHealComponent); repeatHealComponent = null; } } } public HealthBarValues GetHealthBarValues() { float num = 1f - 1f / body.cursePenalty; float num2 = (1f - num) / fullCombinedHealth; float num3 = body.oneShotProtectionFraction * fullCombinedHealth - missingCombinedHealth; HealthBarValues result = default(HealthBarValues); result.hasInfusion = (float)itemCounts.infusion > 0f; result.hasVoidShields = (float)itemCounts.missileVoid > 0f; result.isElite = body.isElite; result.isBoss = body.isBoss; result.isVoid = (body.bodyFlags & CharacterBody.BodyFlags.Void) != 0; result.cullFraction = ((isInFrozenState && (body.bodyFlags & CharacterBody.BodyFlags.ImmuneToExecutes) == 0) ? Mathf.Clamp01(0.3f * fullCombinedHealth * num2) : 0f); result.healthFraction = Mathf.Clamp01(health * num2); result.shieldFraction = Mathf.Clamp01(shield * num2); result.barrierFraction = Mathf.Clamp01(barrier * num2); result.magneticFraction = Mathf.Clamp01(magnetiCharge * num2); result.curseFraction = num; result.ospFraction = num3 * num2; result.healthDisplayValue = (int)combinedHealth; result.maxHealthDisplayValue = (int)fullHealth; return result; } static HealthComponent() { lowHealthFraction = 0.25f; kCmdCmdHealFull = -290141736; NetworkBehaviour.RegisterCommandDelegate(typeof(HealthComponent), kCmdCmdHealFull, InvokeCmdCmdHealFull); kCmdCmdRechargeShieldFull = -833942624; NetworkBehaviour.RegisterCommandDelegate(typeof(HealthComponent), kCmdCmdRechargeShieldFull, InvokeCmdCmdRechargeShieldFull); kCmdCmdAddBarrier = -1976809257; NetworkBehaviour.RegisterCommandDelegate(typeof(HealthComponent), kCmdCmdAddBarrier, InvokeCmdCmdAddBarrier); kCmdCmdForceShieldRegen = -1029271894; NetworkBehaviour.RegisterCommandDelegate(typeof(HealthComponent), kCmdCmdForceShieldRegen, InvokeCmdCmdForceShieldRegen); NetworkCRC.RegisterBehaviour("HealthComponent", 0); } private void UNetVersion() { } protected static void InvokeCmdCmdHealFull(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdHealFull called on client."); } else { ((HealthComponent)obj).CmdHealFull(); } } protected static void InvokeCmdCmdRechargeShieldFull(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdRechargeShieldFull called on client."); } else { ((HealthComponent)obj).CmdRechargeShieldFull(); } } protected static void InvokeCmdCmdAddBarrier(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdAddBarrier called on client."); } else { ((HealthComponent)obj).CmdAddBarrier(reader.ReadSingle()); } } protected static void InvokeCmdCmdForceShieldRegen(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdForceShieldRegen called on client."); } else { ((HealthComponent)obj).CmdForceShieldRegen(); } } public void CallCmdHealFull() { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdHealFull called on server."); return; } if (base.isServer) { CmdHealFull(); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdHealFull); networkWriter.Write(GetComponent().netId); SendCommandInternal(networkWriter, 0, "CmdHealFull"); } public void CallCmdRechargeShieldFull() { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdRechargeShieldFull called on server."); return; } if (base.isServer) { CmdRechargeShieldFull(); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdRechargeShieldFull); networkWriter.Write(GetComponent().netId); SendCommandInternal(networkWriter, 0, "CmdRechargeShieldFull"); } public void CallCmdAddBarrier(float value) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdAddBarrier called on server."); return; } if (base.isServer) { CmdAddBarrier(value); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdAddBarrier); networkWriter.Write(GetComponent().netId); networkWriter.Write(value); SendCommandInternal(networkWriter, 0, "CmdAddBarrier"); } public void CallCmdForceShieldRegen() { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdForceShieldRegen called on server."); return; } if (base.isServer) { CmdForceShieldRegen(); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdForceShieldRegen); networkWriter.Write(GetComponent().netId); SendCommandInternal(networkWriter, 0, "CmdForceShieldRegen"); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(health); writer.Write(shield); writer.Write(barrier); writer.Write(magnetiCharge); writer.WritePackedUInt32(_killingDamageType); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(health); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(shield); } if ((base.syncVarDirtyBits & 4u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(barrier); } if ((base.syncVarDirtyBits & 8u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(magnetiCharge); } if ((base.syncVarDirtyBits & 0x10u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32(_killingDamageType); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { health = reader.ReadSingle(); shield = reader.ReadSingle(); barrier = reader.ReadSingle(); magnetiCharge = reader.ReadSingle(); _killingDamageType = reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { health = reader.ReadSingle(); } if (((uint)num & 2u) != 0) { shield = reader.ReadSingle(); } if (((uint)num & 4u) != 0) { SetBarrier(reader.ReadSingle()); } if (((uint)num & 8u) != 0) { magnetiCharge = reader.ReadSingle(); } if (((uint)num & 0x10u) != 0) { _killingDamageType = reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public class DamageDealtMessage : MessageBase { public GameObject victim; public float damage; public GameObject attacker; public UnityEngine.Vector3 position; public bool crit; public DamageTypeCombo damageType; public DamageColorIndex damageColorIndex; public bool hitLowHealth; public bool isSilent => (ulong)(damageType & DamageType.Silent) != 0; public override void Serialize(NetworkWriter writer) { base.Serialize(writer); writer.Write(victim); writer.Write(damage); writer.Write(attacker); writer.Write(position); writer.Write(crit); writer.WriteDamageType(damageType); writer.Write(damageColorIndex); writer.Write(hitLowHealth); } public override void Deserialize(NetworkReader reader) { base.Deserialize(reader); victim = reader.ReadGameObject(); damage = reader.ReadSingle(); attacker = reader.ReadGameObject(); position = reader.ReadVector3(); crit = reader.ReadBoolean(); damageType = reader.ReadDamageType(); damageColorIndex = reader.ReadDamageColorIndex(); hitLowHealth = reader.ReadBoolean(); } } public class HealthPickup : MonoBehaviour { [Tooltip("The base object to destroy when this pickup is consumed.")] public GameObject baseObject; [Tooltip("The team filter object which determines who can pick up this pack.")] public TeamFilter teamFilter; public GameObject pickupEffect; public float flatHealing; public float fractionalHealing; private bool alive = true; private void OnTriggerStay(Collider other) { if (!NetworkServer.active || !alive || TeamComponent.GetObjectTeam(other.gameObject) != teamFilter.teamIndex) { return; } CharacterBody component = other.GetComponent(); if ((bool)component) { HealthComponent healthComponent = component.healthComponent; if ((bool)healthComponent) { component.healthComponent.Heal(flatHealing + healthComponent.fullHealth * fractionalHealing, default(ProcChainMask)); EffectManager.SpawnEffect(pickupEffect, new EffectData { origin = base.transform.position }, transmit: true); } UnityEngine.Object.Destroy(baseObject); } } } [RequireComponent(typeof(NetworkedBodyAttachment))] public class HelfireController : NetworkBehaviour { [SyncVar] public int stack = 1; [FormerlySerializedAs("radius")] public float baseRadius; public float dotDuration; public float interval; [Range(0f, 1f)] public float healthFractionPerSecond = 0.05f; public float allyDamageScalar = 0.5f; public float enemyDamageScalar = 24f; public Transform auraEffectTransform; private float timer; private float radius; private CameraTargetParams.AimRequest aimRequest; private CameraTargetParams cameraTargetParams; public NetworkedBodyAttachment networkedBodyAttachment { get; private set; } public int Networkstack { get { return stack; } [param: In] set { SetSyncVar(value, ref stack, 1u); } } private void Awake() { networkedBodyAttachment = GetComponent(); auraEffectTransform.SetParent(null); } private void OnDestroy() { if ((bool)auraEffectTransform) { UnityEngine.Object.Destroy(auraEffectTransform.gameObject); auraEffectTransform = null; } aimRequest?.Dispose(); } private void FixedUpdate() { radius = baseRadius * (1f + (float)(stack - 1) * 0.5f); if (NetworkServer.active) { ServerFixedUpdate(); } } private void ServerFixedUpdate() { timer -= Time.fixedDeltaTime; if (!(timer <= 0f)) { return; } timer = interval; float num = healthFractionPerSecond * dotDuration * networkedBodyAttachment.attachedBody.healthComponent.fullCombinedHealth; float num2 = 1f; TeamDef teamDef = TeamCatalog.GetTeamDef(networkedBodyAttachment.attachedBody.teamComponent.teamIndex); if (teamDef != null && teamDef.friendlyFireScaling > 0f) { num2 = 1f / teamDef.friendlyFireScaling; } Collider[] colliders; int num3 = HGPhysics.OverlapSphere(out colliders, base.transform.position, radius, LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Collide); GameObject[] array = new GameObject[colliders.Length]; int count = 0; for (int i = 0; i < num3; i++) { CharacterBody characterBody = Util.HurtBoxColliderToBody(colliders[i]); GameObject gameObject = (characterBody ? characterBody.gameObject : null); if (!gameObject || Array.IndexOf(array, gameObject, 0, count) != -1) { continue; } float num4 = num; float num5 = 1f; if (networkedBodyAttachment.attachedBody.teamComponent.teamIndex == characterBody.teamComponent.teamIndex) { num4 *= num2; num5 *= num2; if ((object)networkedBodyAttachment.attachedBody != characterBody) { num4 *= allyDamageScalar; num5 *= allyDamageScalar; } } else { num4 *= enemyDamageScalar; num5 *= enemyDamageScalar; } InflictDotInfo inflictDotInfo = default(InflictDotInfo); inflictDotInfo.attackerObject = networkedBodyAttachment.attachedBodyObject; inflictDotInfo.victimObject = gameObject; inflictDotInfo.totalDamage = num4; inflictDotInfo.damageMultiplier = num5; inflictDotInfo.dotIndex = DotController.DotIndex.Helfire; inflictDotInfo.maxStacksFromAttacker = 1u; InflictDotInfo dotInfo = inflictDotInfo; StrengthenBurnUtils.CheckDotForUpgrade(networkedBodyAttachment.attachedBody.inventory, ref dotInfo); DotController.InflictDot(ref dotInfo); array[count++] = gameObject; } HGPhysics.ReturnResults(colliders); } private void LateUpdate() { CharacterBody attachedBody = networkedBodyAttachment.attachedBody; if ((bool)attachedBody) { auraEffectTransform.position = networkedBodyAttachment.attachedBody.corePosition; auraEffectTransform.localScale = new UnityEngine.Vector3(radius, radius, radius); if (!cameraTargetParams) { cameraTargetParams = attachedBody.GetComponent(); } else if (aimRequest == null) { aimRequest = cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt32((uint)stack); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)stack); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { stack = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { stack = (int)reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public class Highlight : MonoBehaviour { public enum HighlightColor { interactive, teleporter, pickup, custom, unavailable } private static List highlightList = new List(); private static ReadOnlyCollection _readonlyHighlightList = new ReadOnlyCollection(highlightList); private IDisplayNameProvider displayNameProvider; [HideInInspector] public PickupIndex pickupIndex; public Renderer targetRenderer; public float strength = 1f; public HighlightColor highlightColor; public UnityEngine.Color CustomColor = UnityEngine.Color.magenta; public bool isOn; public static ReadOnlyCollection readonlyHighlightList => _readonlyHighlightList; private void Awake() { displayNameProvider = GetComponent(); } private void RemoveHighlightIfInactive() { if (targetRenderer != null && !targetRenderer.gameObject.activeInHierarchy && highlightList.Contains(this)) { highlightList.Remove(this); } } public UnityEngine.Color GetColor() { return highlightColor switch { HighlightColor.interactive => ColorCatalog.GetColor(ColorCatalog.ColorIndex.Interactable), HighlightColor.teleporter => ColorCatalog.GetColor(ColorCatalog.ColorIndex.Teleporter), HighlightColor.pickup => PickupCatalog.GetPickupDef(pickupIndex)?.baseColor ?? PickupCatalog.invalidPickupColor, HighlightColor.custom => CustomColor, _ => UnityEngine.Color.magenta, }; } private void Update() { RemoveHighlightIfInactive(); } public void OnDisable() { highlightList.Remove(this); } public void OnEnable() { highlightList.Add(this); } public void ResetHighlight() { } } public class HitBox : MonoBehaviour { } public class HitBoxGroup : MonoBehaviour { [Tooltip("The name of this hitbox group.")] public string groupName; [Tooltip("The hitbox objects in this group.")] public HitBox[] hitBoxes; public static HitBoxGroup FindByGroupName(GameObject gameObject, string groupName) { List gameObjectComponents = GetComponentsCache.GetGameObjectComponents(gameObject); HitBoxGroup result = null; int i = 0; for (int count = gameObjectComponents.Count; i < count; i++) { if (string.CompareOrdinal(groupName, gameObjectComponents[i].groupName) == 0) { result = gameObjectComponents[i]; break; } } GetComponentsCache.ReturnBuffer(gameObjectComponents); return result; } } public class HoldoutZoneController : BaseZoneBehavior { public enum HoldoutZoneShape { Sphere, VerticalTube, Count } public delegate void CalcRadiusDelegate(ref float radius); public delegate void CalcChargeRateDelegate(ref float rate); public delegate void CalcAccumulatedChargeDelegate(ref float charge); public delegate void CalcColorDelegate(ref UnityEngine.Color color); [Serializable] public class HoldoutZoneControllerChargedUnityEvent : UnityEvent { } private class ChargeHoldoutZoneObjectiveTracker : ObjectivePanelController.ObjectiveTracker { private int lastPercent = -1; private HoldoutZoneController holdoutZoneController => (HoldoutZoneController)sourceDescriptor.source; private bool ShouldBeFlashing() { bool flag = true; if ((bool)sourceDescriptor.master && (bool)holdoutZoneController) { flag = holdoutZoneController.IsBodyInChargingRadius(sourceDescriptor.master.GetBody()); } return !flag; } protected override string GenerateString() { lastPercent = holdoutZoneController.displayChargePercent; string text = string.Format(Language.GetString(holdoutZoneController.inBoundsObjectiveToken), lastPercent); if (ShouldBeFlashing()) { text = string.Format(Language.GetString(holdoutZoneController.outOfBoundsObjectiveToken), lastPercent); if ((int)(Time.time * 12f) % 2 == 0) { text = $"{text}"; } } return text; } protected override bool IsDirty() { return true; } } private class FocusConvergenceController : MonoBehaviour { private static readonly float convergenceRadiusDivisor = 2f; private static readonly float convergenceChargeRateBonus = 0.3f; private static readonly UnityEngine.Color convergenceMaterialColor = new UnityEngine.Color(0f, 3.9411764f, 5f, 1f); private static readonly float rampUpTime = 5f; private static readonly float startupDelay = 3f; private static readonly int cap = 3; private float currentValue; private HoldoutZoneController holdoutZoneController; private int currentFocusConvergenceCount; private Run.FixedTimeStamp enabledTime; private static readonly AnimationCurve colorCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); private void Awake() { holdoutZoneController = GetComponent(); } private void OnEnable() { enabledTime = Run.FixedTimeStamp.now; holdoutZoneController.calcRadius += ApplyRadius; holdoutZoneController.calcChargeRate += ApplyRate; holdoutZoneController.calcColor += ApplyColor; } private void OnDisable() { holdoutZoneController.calcColor -= ApplyColor; holdoutZoneController.calcChargeRate -= ApplyRate; holdoutZoneController.calcRadius -= ApplyRadius; } private void ApplyRadius(ref float radius) { if (currentFocusConvergenceCount > 0) { radius /= convergenceRadiusDivisor * (float)currentFocusConvergenceCount; } } private void ApplyColor(ref UnityEngine.Color color) { color = UnityEngine.Color.Lerp(color, convergenceMaterialColor, colorCurve.Evaluate(currentValue)); } private void ApplyRate(ref float rate) { if (currentFocusConvergenceCount > 0) { rate *= 1f + convergenceChargeRateBonus * (float)currentFocusConvergenceCount; } } private void Update() { DoUpdate(Time.deltaTime); } private void DoUpdate(float deltaTime) { currentFocusConvergenceCount = Util.GetItemCountForTeam(holdoutZoneController.chargingTeam, RoR2Content.Items.FocusConvergence.itemIndex, requiresAlive: true, requiresConnected: false); if (enabledTime.timeSince < startupDelay) { currentFocusConvergenceCount = 0; } currentFocusConvergenceCount = Mathf.Min(currentFocusConvergenceCount, cap); float target = (((float)currentFocusConvergenceCount > 0f) ? 1f : 0f); float num = Mathf.MoveTowards(currentValue, target, rampUpTime * deltaTime); if (currentValue <= 0f && num > 0f) { Util.PlaySound("Play_item_lunar_focusedConvergence", base.gameObject); } currentValue = num; } } public HoldoutZoneShape holdoutZoneShape; [Tooltip("The base radius of this charging sphere. Players must be within this radius to charge this zone.")] public float baseRadius; [Tooltip("No modifiers can reduce the radius below this size")] public float minimumRadius; [Tooltip("The overall change to the radius from 0% charge to 100% charge.")] public float chargeRadiusDelta; [Tooltip("How long it takes for this zone to finish charging without any modifiers.")] public float baseChargeDuration; [Tooltip("Approximately how long it should take to change from any given radius to the desired one.")] public float radiusSmoothTime; [Tooltip("An object instance which will be used to represent the clear radius.")] public Renderer radiusIndicator; [Tooltip("The child object to enable when healing nova should be active.")] public GameObject healingNovaItemEffect; public Transform healingNovaRoot; public string inBoundsObjectiveToken = "OBJECTIVE_CHARGE_TELEPORTER"; public string outOfBoundsObjectiveToken = "OBJECTIVE_CHARGE_TELEPORTER_OOB"; public bool showObjective = true; public bool applyFocusConvergence; public bool applyHealingNova = true; public bool applyDevotedEvolution; public bool applyDelusionResetChests; [Range(0f, float.MaxValue)] public float playerCountScaling = 1f; [Tooltip("If the zone is empty, this is the rate at which the charge decreases (a negative value will increase charge)")] public float dischargeRate; public HoldoutZoneControllerChargedUnityEvent onCharged; private BuffWard buffWard; private static MaterialPropertyBlock sharedColorPropertyBlock; private UnityEngine.Color baseIndicatorColor; private float radiusVelocity; private bool wasCharged; private GameObject[] healingNovaGeneratorsByTeam = new GameObject[5]; [SyncVar] private float _charge; public float currentRadius { get; private set; } public bool isAnyoneCharging { get; private set; } public TeamIndex chargingTeam { get; set; } = TeamIndex.Player; public int displayChargePercent => Mathf.Clamp(Mathf.FloorToInt(charge * 99f), 0, 99); public float charge { get { return _charge; } private set { Network_charge = value; } } public float Network_charge { get { return _charge; } [param: In] set { SetSyncVar(value, ref _charge, 1u); } } public event CalcRadiusDelegate calcRadius; public event CalcChargeRateDelegate calcChargeRate; public event CalcAccumulatedChargeDelegate calcAccumulatedCharge; public event CalcColorDelegate calcColor; [InitDuringStartup] private static void Init() { sharedColorPropertyBlock = new MaterialPropertyBlock(); ObjectivePanelController.collectObjectiveSources += OnCollectObjectiveSources; } private void Awake() { if ((bool)radiusIndicator) { baseIndicatorColor = radiusIndicator.sharedMaterial.GetColor("_TintColor"); } buffWard = GetComponent(); } private void Start() { if (applyFocusConvergence) { base.gameObject.AddComponent(); } } private void OnEnable() { if ((bool)radiusIndicator) { radiusIndicator.enabled = true; radiusIndicator.gameObject.SetActive(value: true); } currentRadius = 0f; InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); currentRadius = 0f; if ((bool)radiusIndicator) { radiusIndicator.enabled = false; radiusIndicator.gameObject.SetActive(value: false); } } private void UpdateHealingNovas(bool isCharging) { if (!applyHealingNova) { return; } bool flag = false; for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++) { bool flag2 = Util.GetItemCountForTeam(teamIndex, RoR2Content.Items.TPHealingNova.itemIndex, requiresAlive: false) > 0 && isCharging; flag = flag || flag2; if (NetworkServer.active) { ref GameObject reference = ref healingNovaGeneratorsByTeam[(int)teamIndex]; if (flag2 != (bool)reference) { if (flag2) { reference = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/TeleporterHealNovaGenerator"), healingNovaRoot ?? base.transform); reference.GetComponent().teamIndex = teamIndex; NetworkServer.Spawn(reference); } else { UnityEngine.Object.Destroy(reference); reference = null; } } } } if ((bool)healingNovaItemEffect) { healingNovaItemEffect.SetActive(flag); } } private void Update() { DoUpdate(Time.deltaTime); } private void DoUpdate(float deltaTime) { int num = CountLivingPlayers(chargingTeam); int num2 = CountPlayersInRadius(this, base.transform.position, currentRadius * currentRadius, chargingTeam); isAnyoneCharging = num2 > 0; if ((bool)Run.instance) { float radius = baseRadius + charge * chargeRadiusDelta; if (Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse2) { radius *= 0.5f; } this.calcRadius?.Invoke(ref radius); currentRadius = Mathf.Max(Mathf.SmoothDamp(currentRadius, radius, ref radiusVelocity, radiusSmoothTime, float.PositiveInfinity, deltaTime), minimumRadius); } if ((bool)radiusIndicator) { float num3 = 2f * currentRadius; radiusIndicator.transform.localScale = new UnityEngine.Vector3(num3, num3, num3); } if (NetworkServer.active && (bool)buffWard) { buffWard.Networkradius = currentRadius; } if (NetworkServer.active) { float num4 = baseChargeDuration; float rate = ((!isAnyoneCharging || num <= 0) ? (0f - dischargeRate) : (Mathf.Pow((float)num2 / (float)num, playerCountScaling) / num4)); this.calcChargeRate?.Invoke(ref rate); charge = Mathf.Clamp01(charge + rate * deltaTime); float num5 = charge; this.calcAccumulatedCharge?.Invoke(ref num5); charge = num5; } UnityEngine.Color color = baseIndicatorColor; this.calcColor?.Invoke(ref color); sharedColorPropertyBlock.SetColor("_TintColor", color); if ((bool)radiusIndicator) { radiusIndicator.SetPropertyBlock(sharedColorPropertyBlock); } bool flag = charge >= 1f; if (wasCharged != flag) { wasCharged = flag; if (flag) { onCharged?.Invoke(this); if (applyDevotedEvolution) { UpdateDevotedLumerains(chargingTeam); } if (applyDelusionResetChests && RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Delusion)) { foreach (ChestBehavior instances in InstanceTracker.GetInstancesList()) { instances.CallRpcResetChests(); } } } } UpdateHealingNovas(isAnyoneCharging); } private void OnDrawGizmos() { UnityEngine.Matrix4x4 matrix = Gizmos.matrix; UnityEngine.Color color = Gizmos.color; Gizmos.matrix = base.transform.localToWorldMatrix; Gizmos.color = new UnityEngine.Color(0.75f, 0f, 0f, 0.5f); Gizmos.DrawWireSphere(UnityEngine.Vector3.zero, baseRadius); Gizmos.color = color; Gizmos.matrix = matrix; } private static bool IsPointInChargingRadius(HoldoutZoneController holdoutZoneController, UnityEngine.Vector3 origin, float chargingRadiusSqr, UnityEngine.Vector3 point) { switch (holdoutZoneController.holdoutZoneShape) { case HoldoutZoneShape.Sphere: if ((point - origin).sqrMagnitude <= chargingRadiusSqr) { return true; } break; case HoldoutZoneShape.VerticalTube: point.y = 0f; origin.y = 0f; if ((point - origin).sqrMagnitude <= chargingRadiusSqr) { return true; } break; } return false; } private static bool IsBodyInChargingRadius(HoldoutZoneController holdoutZoneController, UnityEngine.Vector3 origin, float chargingRadiusSqr, CharacterBody characterBody) { return IsPointInChargingRadius(holdoutZoneController, origin, chargingRadiusSqr, characterBody.corePosition); } private static int CountLivingPlayers(TeamIndex teamIndex) { int num = 0; ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamIndex); for (int i = 0; i < teamMembers.Count; i++) { if (teamMembers[i].body.isPlayerControlled) { num++; } } return num; } public static int CountPlayersInRadius(HoldoutZoneController holdoutZoneController, UnityEngine.Vector3 origin, float chargingRadiusSqr, TeamIndex teamIndex) { int num = 0; ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamIndex); for (int i = 0; i < teamMembers.Count; i++) { TeamComponent teamComponent = teamMembers[i]; if (teamComponent.body.isPlayerControlled && IsBodyInChargingRadius(holdoutZoneController, origin, chargingRadiusSqr, teamComponent.body)) { num++; } } return num; } public bool IsBodyInChargingRadius(CharacterBody body) { if (!body) { return false; } return IsBodyInChargingRadius(this, base.transform.position, currentRadius * currentRadius, body); } [Server] public void FullyChargeHoldoutZone() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HoldoutZoneController::FullyChargeHoldoutZone()' called on client"); } else { charge = 1f; } } private static void OnCollectObjectiveSources(CharacterMaster master, List objectiveSourcesList) { List instancesList = InstanceTracker.GetInstancesList(); int i = 0; for (int count = instancesList.Count; i < count; i++) { HoldoutZoneController holdoutZoneController = instancesList[i]; if (holdoutZoneController.showObjective && holdoutZoneController.chargingTeam == master.teamIndex) { objectiveSourcesList.Add(new ObjectivePanelController.ObjectiveSourceDescriptor { master = master, objectiveType = typeof(ChargeHoldoutZoneObjectiveTracker), source = holdoutZoneController }); } } } public override bool IsInBounds(UnityEngine.Vector3 position) { return IsPointInChargingRadius(this, base.transform.position, currentRadius * currentRadius, position); } private void UpdateDevotedLumerains(TeamIndex teamIndex) { ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamIndex); for (int i = 0; i < teamMembers.Count; i++) { TeamComponent teamComponent = teamMembers[i]; if (teamComponent.body.isPlayerControlled && (bool)teamComponent.body.master.devotionInventoryPrefab) { teamComponent.body.master.devotionInventoryPrefab.GetComponent().ActivateDevotedEvolution(); } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool flag = base.OnSerialize(writer, forceAll); if (forceAll) { writer.Write(_charge); return true; } bool flag2 = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag2) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag2 = true; } writer.Write(_charge); } if (!flag2) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag2 || flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { base.OnDeserialize(reader, initialState); if (initialState) { _charge = reader.ReadSingle(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { _charge = reader.ReadSingle(); } } public override void PreStartClient() { base.PreStartClient(); } } [RequireComponent(typeof(PostProcessVolume))] public class HookLightingIntoPostProcessVolume : MonoBehaviour { [Header("Required Values")] public PostProcessVolume volume; [ColorUsage(true, true)] public UnityEngine.Color overrideAmbientColor; [Header("Optional Values")] public Light directionalLight; public UnityEngine.Color overrideDirectionalColor; public ParticleSystem particleSystem; public float overrideParticleSystemMultiplier; private Collider[] volumeColliders; private UnityEngine.Color defaultAmbientColor; private UnityEngine.Color defaultDirectionalColor; private float defaultParticleSystemMultiplier; private bool hasCachedInitialValues; private void OnEnable() { volumeColliders = GetComponents(); if (!hasCachedInitialValues) { defaultAmbientColor = RenderSettings.ambientLight; if ((bool)directionalLight) { defaultDirectionalColor = directionalLight.color; } if ((bool)particleSystem) { defaultParticleSystemMultiplier = particleSystem.emission.rateOverTimeMultiplier; } hasCachedInitialValues = true; } SceneCamera.onSceneCameraPreRender += OnPreRenderSceneCam; } private void OnDisable() { SceneCamera.onSceneCameraPreRender -= OnPreRenderSceneCam; } private void OnPreRenderSceneCam(SceneCamera sceneCam) { float interpFactor = GetInterpFactor(sceneCam.camera.transform.position); RenderSettings.ambientLight = UnityEngine.Color.Lerp(defaultAmbientColor, overrideAmbientColor, interpFactor); if ((bool)directionalLight) { directionalLight.color = UnityEngine.Color.Lerp(defaultDirectionalColor, overrideDirectionalColor, interpFactor); } if ((bool)particleSystem) { ParticleSystem.EmissionModule emission = particleSystem.emission; emission.rateOverTimeMultiplier = Mathf.Lerp(defaultParticleSystemMultiplier, overrideParticleSystemMultiplier, interpFactor); } } private float GetInterpFactor(UnityEngine.Vector3 triggerPos) { if (!volume.enabled || volume.weight <= 0f) { return 0f; } if (volume.isGlobal) { return 1f; } float num = 0f; Collider[] array = volumeColliders; foreach (Collider collider in array) { float num2 = float.PositiveInfinity; if (collider.enabled) { float sqrMagnitude = ((collider.ClosestPoint(triggerPos) - triggerPos) / 2f).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; } float num3 = volume.blendDistance * volume.blendDistance; if (!(num2 > num3) && num3 > 0f) { num = Mathf.Max(num, 1f - num2 / num3); } } } return num; } } public class HoverEngine : MonoBehaviour { public Rigidbody engineRigidbody; public Transform wheelVisual; public float hoverForce = 65f; public float hoverHeight = 3.5f; public float hoverDamping = 0.1f; public float hoverRadius; [HideInInspector] public float forceStrength; private Ray castRay; private UnityEngine.Vector3 castPosition; [HideInInspector] public RaycastHit raycastHit; public float compression; public UnityEngine.Vector3 offsetVector = UnityEngine.Vector3.zero; public bool isGrounded; private void OnDrawGizmos() { Gizmos.color = UnityEngine.Color.yellow; Gizmos.DrawWireSphere(base.transform.TransformPoint(offsetVector), hoverRadius); Gizmos.DrawRay(castRay); if (isGrounded) { Gizmos.DrawSphere(raycastHit.point, hoverRadius); } } private void FixedUpdate() { float num = Mathf.Clamp01(UnityEngine.Vector3.Dot(-base.transform.up, UnityEngine.Vector3.down)); castPosition = base.transform.TransformPoint(offsetVector); castRay = new Ray(castPosition, -base.transform.up); isGrounded = false; forceStrength = 0f; compression = 0f; UnityEngine.Vector3 position = castRay.origin + castRay.direction * hoverHeight; if (Physics.SphereCast(castRay, hoverRadius, out raycastHit, hoverHeight, LayerIndex.world.mask)) { isGrounded = true; float num2 = (hoverHeight - raycastHit.distance) / hoverHeight; UnityEngine.Vector3 vector = UnityEngine.Vector3.up * (num2 * hoverForce); UnityEngine.Vector3 vector2 = UnityEngine.Vector3.Project(engineRigidbody.GetPointVelocity(castPosition), -base.transform.up) * hoverDamping; forceStrength = (vector - vector2).magnitude; engineRigidbody.AddForceAtPosition(UnityEngine.Vector3.Project(vector - vector2, -base.transform.up), castPosition, ForceMode.Acceleration); compression = Mathf.Clamp01(num2 * num); position = raycastHit.point; } wheelVisual.position = position; _ = isGrounded; } } public class HoverEngineDisplay : MonoBehaviour { public HoverEngine hoverEngine; [Tooltip("The local pitch at zero engine strength")] public float minPitch = -20f; [Tooltip("The local pitch at max engine strength")] public float maxPitch = 60f; public float smoothTime = 0.2f; public float forceScale = 1f; private float smoothVelocity; private void FixedUpdate() { UnityEngine.Vector3 localEulerAngles = base.transform.localEulerAngles; float x = Mathf.SmoothDampAngle(target: Mathf.LerpAngle(t: Mathf.Clamp01(hoverEngine.forceStrength / hoverEngine.hoverForce * forceScale), a: minPitch, b: maxPitch), current: localEulerAngles.x, currentVelocity: ref smoothVelocity, smoothTime: smoothTime); base.transform.localRotation = UnityEngine.Quaternion.Euler(x, 0f, 0f); } } [RequireComponent(typeof(Rigidbody))] public class HoverVehicleMotor : MonoBehaviour { private enum WheelLateralAxis { Left, Right } public enum WheelLongitudinalAxis { Front, Back } [Serializable] public struct AxleGroup { public HoverEngine leftWheel; public HoverEngine rightWheel; public WheelLongitudinalAxis wheelLongitudinalAxis; public bool isDriven; public AnimationCurve slidingTractionCurve; } [HideInInspector] public UnityEngine.Vector3 targetSteerVector; public UnityEngine.Vector3 centerOfMassOffset; public AxleGroup[] staticAxles; public AxleGroup[] steerAxles; public float wheelWellDepth; public float wheelBase; public float trackWidth; public float rollingFrictionCoefficient; public float slidingTractionCoefficient; public float motorForce; public float maxSteerAngle; public float maxTurningRadius; public float hoverForce = 33f; public float hoverHeight = 2f; public float hoverDamping = 0.5f; public float hoverRadius = 0.5f; public UnityEngine.Vector3 hoverOffsetVector = UnityEngine.Vector3.up; private InputBankTest inputBank; private UnityEngine.Vector3 steerVector = UnityEngine.Vector3.forward; private Rigidbody rigidbody; private void Start() { inputBank = GetComponent(); rigidbody = GetComponent(); } private void ApplyWheelForces(HoverEngine wheel, float gas, bool driveWheel, AnimationCurve slidingWheelTractionCurve) { if (wheel.isGrounded) { float num = 0.005f; Transform transform = wheel.transform; float num2 = 1f; UnityEngine.Vector3 position = transform.position; UnityEngine.Vector3 pointVelocity = rigidbody.GetPointVelocity(position); UnityEngine.Vector3 vector = UnityEngine.Vector3.Project(pointVelocity, transform.right); UnityEngine.Vector3 vector2 = UnityEngine.Vector3.Project(pointVelocity, transform.forward); UnityEngine.Vector3 up = UnityEngine.Vector3.up; UnityEngine.Debug.DrawRay(position, pointVelocity, UnityEngine.Color.blue); UnityEngine.Vector3 vector3 = UnityEngine.Vector3.zero; if (driveWheel) { vector3 = transform.forward * gas * motorForce; rigidbody.AddForceAtPosition(transform.forward * gas * motorForce * num2, position); UnityEngine.Debug.DrawRay(position, vector3 * num, UnityEngine.Color.yellow); } UnityEngine.Vector3 vector4 = UnityEngine.Vector3.ProjectOnPlane(-vector2 * rollingFrictionCoefficient * num2, up); rigidbody.AddForceAtPosition(vector4, position); UnityEngine.Debug.DrawRay(position, vector4 * num, UnityEngine.Color.red); UnityEngine.Vector3 vector5 = UnityEngine.Vector3.ProjectOnPlane(-vector * slidingWheelTractionCurve.Evaluate(pointVelocity.magnitude) * slidingTractionCoefficient * num2, up); rigidbody.AddForceAtPosition(vector5, position); UnityEngine.Debug.DrawRay(position, vector5 * num, UnityEngine.Color.red); UnityEngine.Debug.DrawRay(position, (vector3 + vector4 + vector5) * num, UnityEngine.Color.green); } } private void UpdateCenterOfMass() { rigidbody.ResetCenterOfMass(); rigidbody.centerOfMass += centerOfMassOffset; } private void UpdateWheelParameter(HoverEngine wheel, WheelLateralAxis wheelLateralAxis, WheelLongitudinalAxis wheelLongitudinalAxis) { wheel.hoverForce = hoverForce; wheel.hoverDamping = hoverDamping; wheel.hoverHeight = hoverHeight; wheel.offsetVector = hoverOffsetVector; wheel.hoverRadius = hoverRadius; UnityEngine.Vector3 zero = UnityEngine.Vector3.zero; zero.y = 0f - wheelWellDepth; switch (wheelLateralAxis) { case WheelLateralAxis.Left: zero.x = (0f - trackWidth) / 2f; break; case WheelLateralAxis.Right: zero.x = trackWidth / 2f; break; } switch (wheelLongitudinalAxis) { case WheelLongitudinalAxis.Front: zero.z = wheelBase / 2f; break; case WheelLongitudinalAxis.Back: zero.z = (0f - wheelBase) / 2f; break; } wheel.transform.localPosition = zero; } private void UpdateAllWheelParameters() { AxleGroup[] array = staticAxles; for (int i = 0; i < array.Length; i++) { AxleGroup axleGroup = array[i]; HoverEngine leftWheel = axleGroup.leftWheel; HoverEngine rightWheel = axleGroup.rightWheel; UpdateWheelParameter(leftWheel, WheelLateralAxis.Left, axleGroup.wheelLongitudinalAxis); UpdateWheelParameter(rightWheel, WheelLateralAxis.Right, axleGroup.wheelLongitudinalAxis); } array = steerAxles; for (int i = 0; i < array.Length; i++) { AxleGroup axleGroup2 = array[i]; HoverEngine leftWheel2 = axleGroup2.leftWheel; HoverEngine rightWheel2 = axleGroup2.rightWheel; UpdateWheelParameter(leftWheel2, WheelLateralAxis.Left, axleGroup2.wheelLongitudinalAxis); UpdateWheelParameter(rightWheel2, WheelLateralAxis.Right, axleGroup2.wheelLongitudinalAxis); } } private void FixedUpdate() { UpdateCenterOfMass(); UpdateAllWheelParameters(); if (!inputBank) { return; } UnityEngine.Vector3 moveVector = inputBank.moveVector; UnityEngine.Vector3 normalized = UnityEngine.Vector3.ProjectOnPlane(inputBank.aimDirection, base.transform.up).normalized; float num = Mathf.Clamp(Util.AngleSigned(base.transform.forward, normalized, base.transform.up), 0f - maxSteerAngle, maxSteerAngle); float magnitude = moveVector.magnitude; AxleGroup[] array = staticAxles; for (int i = 0; i < array.Length; i++) { AxleGroup axleGroup = array[i]; HoverEngine leftWheel = axleGroup.leftWheel; HoverEngine rightWheel = axleGroup.rightWheel; ApplyWheelForces(leftWheel, magnitude, axleGroup.isDriven, axleGroup.slidingTractionCurve); ApplyWheelForces(rightWheel, magnitude, axleGroup.isDriven, axleGroup.slidingTractionCurve); } array = steerAxles; for (int i = 0; i < array.Length; i++) { AxleGroup axleGroup2 = array[i]; HoverEngine leftWheel2 = axleGroup2.leftWheel; HoverEngine rightWheel2 = axleGroup2.rightWheel; float num2 = maxTurningRadius / Mathf.Abs(num / maxSteerAngle); float num3 = Mathf.Atan(wheelBase / (num2 - trackWidth / 2f)) * 57.29578f; float num4 = Mathf.Atan(wheelBase / (num2 + trackWidth / 2f)) * 57.29578f; UnityEngine.Quaternion localRotation = UnityEngine.Quaternion.Euler(0f, num3 * Mathf.Sign(num), 0f); UnityEngine.Quaternion localRotation2 = UnityEngine.Quaternion.Euler(0f, num4 * Mathf.Sign(num), 0f); if (num <= 0f) { leftWheel2.transform.localRotation = localRotation; rightWheel2.transform.localRotation = localRotation2; } else { leftWheel2.transform.localRotation = localRotation2; rightWheel2.transform.localRotation = localRotation; } ApplyWheelForces(leftWheel2, magnitude, axleGroup2.isDriven, axleGroup2.slidingTractionCurve); ApplyWheelForces(rightWheel2, magnitude, axleGroup2.isDriven, axleGroup2.slidingTractionCurve); } UnityEngine.Debug.DrawRay(base.transform.position, normalized * 5f, UnityEngine.Color.blue); } private void OnDrawGizmos() { if ((bool)rigidbody) { Gizmos.color = UnityEngine.Color.red; Gizmos.DrawSphere(base.transform.TransformPoint(rigidbody.centerOfMass), 0.3f); } } } [RequireComponent(typeof(CharacterBody))] [RequireComponent(typeof(TeamComponent))] [RequireComponent(typeof(InputBankTest))] public class HuntressTracker : MonoBehaviour { public GameObject trackingPrefab; public float maxTrackingDistance = 20f; public float maxTrackingAngle = 20f; public float trackerUpdateFrequency = 10f; private HurtBox trackingTarget; private CharacterBody characterBody; private TeamComponent teamComponent; private InputBankTest inputBank; private float trackerUpdateStopwatch; private Indicator indicator; private readonly BullseyeSearch search = new BullseyeSearch(); private void Awake() { if (trackingPrefab == null) { trackingPrefab = LegacyResourcesAPI.Load("Prefabs/HuntressTrackingIndicator"); } indicator = new Indicator(base.gameObject, trackingPrefab); } private void Start() { characterBody = GetComponent(); inputBank = GetComponent(); teamComponent = GetComponent(); } public HurtBox GetTrackingTarget() { return trackingTarget; } private void OnEnable() { indicator.active = true; } private void OnDisable() { indicator.active = false; } private void FixedUpdate() { MyFixedUpdate(Time.fixedDeltaTime); } private void MyFixedUpdate(float deltaTime) { trackerUpdateStopwatch += deltaTime; if (trackerUpdateStopwatch >= 1f / trackerUpdateFrequency) { trackerUpdateStopwatch -= 1f / trackerUpdateFrequency; _ = trackingTarget; Ray aimRay = new Ray(inputBank.aimOrigin, inputBank.aimDirection); SearchForTarget(aimRay); indicator.targetTransform = (trackingTarget ? trackingTarget.transform : null); } } private void SearchForTarget(Ray aimRay) { search.teamMaskFilter = TeamMask.all; search.teamMaskFilter.RemoveTeam(teamComponent.teamIndex); search.filterByLoS = true; search.searchOrigin = aimRay.origin; search.searchDirection = aimRay.direction; search.sortMode = BullseyeSearch.SortMode.Distance; search.maxDistanceFilter = maxTrackingDistance; search.maxAngleFilter = maxTrackingAngle; search.RefreshCandidates(); search.FilterOutGameObject(base.gameObject); trackingTarget = search.GetResults().FirstOrDefault(); } } [RequireComponent(typeof(Collider))] public class HurtBox : MonoBehaviour { public enum DamageModifier { Normal, [Obsolete] SniperTarget, Weak, Barrier } [StructLayout(LayoutKind.Sequential, Size = 1)] public struct EntityEqualityComparer : IEqualityComparer { public bool Equals(HurtBox a, HurtBox b) { return HurtBoxesShareEntity(a, b); } public int GetHashCode(HurtBox hurtBox) { return FindEntityObject(hurtBox).GetHashCode(); } } [Tooltip("The health component to which this hurtbox belongs.")] public HealthComponent healthComponent; [Tooltip("Whether or not this hurtbox is considered a bullseye. Do not change this at runtime!")] public bool isBullseye; [Tooltip("Whether or not this hurtbox is considered a sniper target. Do not change this at runtime!")] public bool isSniperTarget; public DamageModifier damageModifier; [SerializeField] [HideInInspector] public HurtBoxGroup hurtBoxGroup; [SerializeField] [HideInInspector] public short indexInGroup = -1; private bool isInBullseyeList; private bool isInSniperTargetList; private static readonly List bullseyesList = new List(); public static readonly ReadOnlyCollection readOnlyBullseyesList = bullseyesList.AsReadOnly(); private static readonly List sniperTargetsList = new List(); public static readonly float sniperTargetRadius = 1f; public static readonly float sniperTargetRadiusSqr = sniperTargetRadius * sniperTargetRadius; public TeamIndex teamIndex { get; set; } = TeamIndex.None; public Collider collider { get; private set; } public float volume { get; private set; } public UnityEngine.Vector3 randomVolumePoint => Util.RandomColliderVolumePoint(collider); public static IReadOnlyList readOnlySniperTargetsList => sniperTargetsList; private void Awake() { collider = GetComponent(); collider.isTrigger = false; Rigidbody rigidbody = GetComponent(); if (!rigidbody) { rigidbody = base.gameObject.AddComponent(); } rigidbody.isKinematic = true; UnityEngine.Vector3 lossyScale = base.transform.lossyScale; volume = lossyScale.x * 2f * (lossyScale.y * 2f) * (lossyScale.z * 2f); } private void OnEnable() { if (isBullseye) { bullseyesList.Add(this); isInBullseyeList = true; } if (isSniperTarget) { sniperTargetsList.Add(this); isInSniperTargetList = true; } } private void OnDisable() { if (isInSniperTargetList) { isInSniperTargetList = false; sniperTargetsList.Remove(this); } if (isInBullseyeList) { isInBullseyeList = false; bullseyesList.Remove(this); } } public static GameObject FindEntityObject([NotNull] HurtBox hurtBox) { if (!hurtBox.healthComponent) { return null; } return hurtBox.healthComponent.gameObject; } public static bool HurtBoxesShareEntity([NotNull] HurtBox a, [NotNull] HurtBox b) { return (object)FindEntityObject(a) == FindEntityObject(b); } } public class BullseyeSearch { private struct CandidateInfo { public HurtBox hurtBox; public UnityEngine.Vector3 position; public float dot; public float distanceSqr; } public enum SortMode { None, Distance, Angle, DistanceAndAngle } private delegate CandidateInfo Selector(HurtBox hurtBox); public CharacterBody viewer; public UnityEngine.Vector3 searchOrigin; public UnityEngine.Vector3 searchDirection; private float minThetaDot = -1f; private float maxThetaDot = 1f; public float minDistanceFilter; public float maxDistanceFilter = float.PositiveInfinity; public TeamMask teamMaskFilter = TeamMask.allButNeutral; public bool filterByLoS = true; public bool filterByDistinctEntity; public QueryTriggerInteraction queryTriggerInteraction; public SortMode sortMode = SortMode.Distance; private List candidatesEnumerable; private HashSet DistinctEntityHash = new HashSet(); public float minAngleFilter { set { maxThetaDot = Mathf.Cos(Mathf.Clamp(value, 0f, 180f) * (MathF.PI / 180f)); } } public float maxAngleFilter { set { minThetaDot = Mathf.Cos(Mathf.Clamp(value, 0f, 180f) * (MathF.PI / 180f)); } } private bool filterByDistance { get { if (!(minDistanceFilter > 0f) && !(maxDistanceFilter < float.PositiveInfinity)) { if ((bool)viewer) { return viewer.visionDistance < float.PositiveInfinity; } return false; } return true; } } private bool filterByAngle { get { if (!(minThetaDot > -1f)) { return maxThetaDot < 1f; } return true; } } private Func GetSelector() { bool getDot = filterByAngle; bool getDistanceSqr = filterByDistance; getDistanceSqr |= sortMode == SortMode.Distance || sortMode == SortMode.DistanceAndAngle; getDot |= sortMode == SortMode.Angle || sortMode == SortMode.DistanceAndAngle; bool getDifference = getDot || getDistanceSqr; bool getPosition = getDot || getDistanceSqr || filterByLoS; return delegate(HurtBox hurtBox) { CandidateInfo candidateInfo = default(CandidateInfo); candidateInfo.hurtBox = hurtBox; CandidateInfo result = candidateInfo; if (getPosition) { result.position = hurtBox.transform.position; } UnityEngine.Vector3 vector = default(UnityEngine.Vector3); if (getDifference) { vector = result.position - searchOrigin; } if (getDot) { result.dot = UnityEngine.Vector3.Dot(searchDirection, vector.normalized); } if (getDistanceSqr) { result.distanceSqr = vector.sqrMagnitude; } return result; }; } public void RefreshCandidates() { Func selector = GetSelector(); int count = HurtBox.readOnlyBullseyesList.Count; List list = (candidatesEnumerable = new List(count)); bool flag = filterByAngle; bool flag2 = filterByDistance; float minDistanceSqr = 0f; float maxDistanceSqr = 0f; if (flag2) { float num = maxDistanceFilter; if ((bool)viewer) { num = Mathf.Min(num, viewer.visionDistance); } minDistanceSqr = minDistanceFilter * minDistanceFilter; maxDistanceSqr = num * num; } for (int i = 0; i < count; i++) { HurtBox hurtBox = HurtBox.readOnlyBullseyesList[i]; int item = 0; if (filterByDistinctEntity) { item = hurtBox.healthComponent.GetInstanceID(); if (DistinctEntityHash.Contains(item)) { continue; } } if (!teamMaskFilter.HasTeam(hurtBox.teamIndex)) { continue; } CandidateInfo candidateInfo2 = selector(hurtBox); if ((!flag || DotOkay(candidateInfo2)) && (!flag2 || DistanceOkay(candidateInfo2))) { if (filterByDistinctEntity) { DistinctEntityHash.Add(item); } list.Add(candidateInfo2); } } Func sorter = GetSorter(); if (sorter != null) { Comparison comparison = (CandidateInfo x, CandidateInfo y) => sorter(x).CompareTo(sorter(y)); list.Sort(comparison); } if (filterByDistinctEntity) { DistinctEntityHash.Clear(); } bool DistanceOkay(CandidateInfo candidateInfo) { if (candidateInfo.distanceSqr >= minDistanceSqr) { return candidateInfo.distanceSqr <= maxDistanceSqr; } return false; } bool DotOkay(CandidateInfo candidateInfo) { if (minThetaDot <= candidateInfo.dot) { return candidateInfo.dot <= maxThetaDot; } return false; } } private Func GetSorter() { return sortMode switch { SortMode.Distance => (CandidateInfo candidateInfo) => candidateInfo.distanceSqr, SortMode.Angle => (CandidateInfo candidateInfo) => 0f - candidateInfo.dot, SortMode.DistanceAndAngle => (CandidateInfo candidateInfo) => (0f - candidateInfo.dot) * candidateInfo.distanceSqr, _ => null, }; } public void FilterCandidatesByHealthFraction(float minHealthFraction = 0f, float maxHealthFraction = 1f) { if (minHealthFraction > 0f) { if (maxHealthFraction < 1f) { candidatesEnumerable.RemoveAll(delegate(CandidateInfo v) { float combinedHealthFraction = v.hurtBox.healthComponent.combinedHealthFraction; return combinedHealthFraction < minHealthFraction || maxHealthFraction < combinedHealthFraction; }); } else { candidatesEnumerable.RemoveAll((CandidateInfo v) => v.hurtBox.healthComponent.combinedHealthFraction < minHealthFraction); } } else if (maxHealthFraction < 1f) { candidatesEnumerable.RemoveAll((CandidateInfo v) => v.hurtBox.healthComponent.combinedHealthFraction > maxHealthFraction); } } public void FilterOutGameObject(GameObject gameObject) { candidatesEnumerable.RemoveAll((CandidateInfo v) => v.hurtBox.healthComponent.gameObject == gameObject); } public IEnumerable GetResults() { _ = candidatesEnumerable; if (filterByLoS) { candidatesEnumerable.RemoveAll((CandidateInfo candidateInfo) => !CheckLoS(candidateInfo.position)); } if ((bool)viewer) { candidatesEnumerable.RemoveAll((CandidateInfo candidateInfo) => !CheckVisible(candidateInfo.hurtBox.healthComponent.gameObject)); } int count = candidatesEnumerable.Count; HurtBox[] array = new HurtBox[count]; for (int i = 0; i < count; i++) { array[i] = candidatesEnumerable[i].hurtBox; } return array; } public bool CheckLoS(UnityEngine.Vector3 targetPosition) { UnityEngine.Vector3 direction = targetPosition - searchOrigin; RaycastHit hitInfo; return !Physics.Raycast(searchOrigin, direction, out hitInfo, direction.magnitude, LayerIndex.world.mask, queryTriggerInteraction); } public bool CheckVisible(GameObject gameObject) { CharacterBody component = gameObject.GetComponent(); if ((bool)component) { return component.GetVisibilityLevel(viewer) >= VisibilityLevel.Revealed; } return true; } public void Reset() { viewer = null; searchOrigin = UnityEngine.Vector3.zero; searchDirection = UnityEngine.Vector3.zero; minThetaDot = -1f; minDistanceFilter = 0f; maxDistanceFilter = float.PositiveInfinity; teamMaskFilter = TeamMask.allButNeutral; filterByLoS = true; queryTriggerInteraction = QueryTriggerInteraction.UseGlobal; sortMode = SortMode.Distance; } } [Serializable] public struct HurtBoxReference : IEquatable { public GameObject rootObject; public byte hurtBoxIndexPlusOne; public static HurtBoxReference FromHurtBox(HurtBox hurtBox) { if (!hurtBox) { return default(HurtBoxReference); } HurtBoxReference result = default(HurtBoxReference); result.rootObject = (hurtBox.healthComponent ? hurtBox.healthComponent.gameObject : null); result.hurtBoxIndexPlusOne = (byte)(hurtBox.indexInGroup + 1); return result; } public static HurtBoxReference FromRootObject(GameObject rootObject) { HurtBoxReference result = default(HurtBoxReference); result.rootObject = rootObject; result.hurtBoxIndexPlusOne = 0; return result; } public GameObject ResolveGameObject() { if (hurtBoxIndexPlusOne == 0) { return rootObject; } if ((bool)rootObject) { ModelLocator component = rootObject.GetComponent(); if ((bool)component && (bool)component.modelTransform) { HurtBoxGroup component2 = component.modelTransform.GetComponent(); if ((bool)component2 && component2.hurtBoxes != null) { int num = hurtBoxIndexPlusOne - 1; if (num < component2.hurtBoxes.Length) { return component2.hurtBoxes[num].gameObject; } } } } return null; } public HurtBox ResolveHurtBox() { GameObject gameObject = ResolveGameObject(); if (!gameObject) { return null; } return gameObject.GetComponent(); } public void Write(NetworkWriter writer) { writer.Write(rootObject); writer.Write(hurtBoxIndexPlusOne); } public void Read(NetworkReader reader) { rootObject = reader.ReadGameObject(); hurtBoxIndexPlusOne = reader.ReadByte(); } public bool Equals(HurtBoxReference other) { if (object.Equals(rootObject, other.rootObject)) { return hurtBoxIndexPlusOne == other.hurtBoxIndexPlusOne; } return false; } public override bool Equals(object obj) { if (obj is HurtBoxReference other) { return Equals(other); } return false; } public override int GetHashCode() { return (((rootObject != null) ? rootObject.GetHashCode() : 0) * 397) ^ hurtBoxIndexPlusOne.GetHashCode(); } } public class HurtBoxGroup : MonoBehaviour, ILifeBehavior { public class VolumeDistribution { private HurtBox[] hurtBoxes; public float totalVolume { get; private set; } public UnityEngine.Vector3 randomVolumePoint { get { float num = UnityEngine.Random.Range(0f, totalVolume); HurtBox hurtBox = hurtBoxes[0]; float num2 = 0f; for (int i = 0; i < hurtBoxes.Length; i++) { num2 += hurtBoxes[i].volume; if (num2 <= num) { hurtBox = hurtBoxes[i]; break; } } return hurtBox.randomVolumePoint; } } public VolumeDistribution(HurtBox[] hurtBoxes) { totalVolume = 0f; for (int i = 0; i < hurtBoxes.Length; i++) { totalVolume += hurtBoxes[i].volume; } this.hurtBoxes = (HurtBox[])hurtBoxes.Clone(); } } [Tooltip("The hurtboxes in this group. This really shouldn't be set manually.")] public HurtBox[] hurtBoxes; [Tooltip("The most important hurtbox in this group, usually a good center-of-mass target like the chest.")] public HurtBox mainHurtBox; [HideInInspector] public int bullseyeCount; private int _hurtBoxesDeactivatorCounter; public int hurtBoxesDeactivatorCounter { get { return _hurtBoxesDeactivatorCounter; } set { bool num = _hurtBoxesDeactivatorCounter <= 0; bool flag = value <= 0; _hurtBoxesDeactivatorCounter = value; if (num != flag) { SetHurtboxesActive(flag); } } } public void OnDeathStart() { int num = hurtBoxesDeactivatorCounter + 1; hurtBoxesDeactivatorCounter = num; } private void SetHurtboxesActive(bool active) { for (int i = 0; i < hurtBoxes.Length; i++) { hurtBoxes[i].gameObject.SetActive(active); } } public void OnValidate() { int num = 0; if (hurtBoxes == null) { hurtBoxes = Array.Empty(); } for (short num2 = 0; num2 < hurtBoxes.Length; num2++) { if (!hurtBoxes[num2]) { UnityEngine.Debug.LogWarningFormat("Object {0} HurtBoxGroup hurtbox #{1} is missing.", Util.GetGameObjectHierarchyName(base.gameObject), num2); } else { hurtBoxes[num2].hurtBoxGroup = this; hurtBoxes[num2].indexInGroup = num2; if (hurtBoxes[num2].isBullseye) { num++; } } } if (bullseyeCount != num) { bullseyeCount = num; } if (!mainHurtBox) { IEnumerable source = from v in hurtBoxes where v where v.isBullseye select v; IEnumerable source2 = source.Where((HurtBox v) => v.transform.parent.name.ToLower(CultureInfo.InvariantCulture) == "chest"); mainHurtBox = source2.FirstOrDefault() ?? source.FirstOrDefault(); } } public VolumeDistribution GetVolumeDistribution() { return new VolumeDistribution(hurtBoxes); } } public interface IBarrier { void BlockedDamage(DamageInfo damageInfo, float actualDamageBlocked); } public interface ICharacterFlightParameterProvider { CharacterFlightParameters flightParameters { get; set; } bool isFlying { get; } } [Serializable] public struct CharacterFlightParameters : IEquatable { public int channeledFlightGranterCount; public bool Equals(CharacterFlightParameters other) { return channeledFlightGranterCount == other.channeledFlightGranterCount; } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is CharacterFlightParameters other) { return Equals(other); } return false; } public override int GetHashCode() { return channeledFlightGranterCount; } public bool CheckShouldUseFlight() { return channeledFlightGranterCount > 0; } } public interface ICharacterGravityParameterProvider { CharacterGravityParameters gravityParameters { get; set; } bool useGravity { get; } bool isFlying { get; } } [Serializable] public struct CharacterGravityParameters : IEquatable { [Tooltip("AntiGravity granted by Zero-G environments. Provides AntiGravity if greater than zero and takes precedence over all other parameters.")] public int environmentalAntiGravityGranterCount; [Tooltip("AntiGravity neutralizers, like debuffs. Neutralizes non-environmental AntiGravity if greater than zero.")] public int antiGravityNeutralizerCount; [Tooltip("AntiGravity granted by body, skills, and items. Provides AntiGravity if greater than zero.")] public int channeledAntiGravityGranterCount; public bool Equals(CharacterGravityParameters other) { if (environmentalAntiGravityGranterCount == other.environmentalAntiGravityGranterCount && antiGravityNeutralizerCount == other.antiGravityNeutralizerCount) { return channeledAntiGravityGranterCount == other.channeledAntiGravityGranterCount; } return false; } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is CharacterGravityParameters other) { return Equals(other); } return false; } public override int GetHashCode() { return (((environmentalAntiGravityGranterCount * 397) ^ antiGravityNeutralizerCount) * 397) ^ channeledAntiGravityGranterCount; } public bool CheckShouldUseGravity() { if (environmentalAntiGravityGranterCount > 0) { return false; } if (antiGravityNeutralizerCount > 0) { return true; } if (channeledAntiGravityGranterCount > 0) { return false; } return true; } } public class IcicleAuraController : NetworkBehaviour { private struct OwnerInfo { public readonly GameObject gameObject; public readonly Transform transform; public readonly CharacterBody characterBody; public readonly CameraTargetParams cameraTargetParams; public OwnerInfo(GameObject gameObject) { this.gameObject = gameObject; if ((bool)gameObject) { transform = gameObject.transform; characterBody = gameObject.GetComponent(); cameraTargetParams = gameObject.GetComponent(); } else { transform = null; characterBody = null; cameraTargetParams = null; } } } public float baseIcicleAttackInterval = 0.25f; public float icicleBaseRadius = 10f; public float icicleRadiusPerIcicle = 2f; public float icicleDamageCoefficientPerTick = 2f; public float icicleDamageCoefficientPerTickPerIcicle = 1f; public float icicleDuration = 5f; public float icicleProcCoefficientPerTick = 0.2f; public int icicleCountOnFirstKill = 2; public int baseIcicleMax = 6; public int icicleMaxPerStack = 3; public BuffWard buffWard; private CameraTargetParams.AimRequest aimRequest; private List icicleLifetimes = new List(); private float attackStopwatch; private int lastIcicleCount; [SyncVar] private int finalIcicleCount; [SyncVar] public GameObject owner; private OwnerInfo cachedOwnerInfo; public ParticleSystem[] auraParticles; public ParticleSystem[] procParticles; private new Transform transform; private float actualRadius; private float scaleVelocity; private NetworkInstanceId ___ownerNetId; private int maxIcicleCount { get { int num = 1; if ((bool)cachedOwnerInfo.characterBody.inventory) { num = cachedOwnerInfo.characterBody.inventory.GetItemCount(RoR2Content.Items.Icicle); } return baseIcicleMax + (num - 1) * icicleMaxPerStack; } } public int NetworkfinalIcicleCount { get { return finalIcicleCount; } [param: In] set { SetSyncVar(value, ref finalIcicleCount, 1u); } } public GameObject Networkowner { get { return owner; } [param: In] set { SetSyncVarGameObject(value, ref owner, 2u, ref ___ownerNetId); } } private void Awake() { transform = base.transform; if ((bool)buffWard) { buffWard.interval = baseIcicleAttackInterval; } } private void FixedUpdate() { if (cachedOwnerInfo.gameObject != owner) { cachedOwnerInfo = new OwnerInfo(owner); } UpdateRadius(); if (NetworkServer.active) { if (!owner) { UnityEngine.Object.Destroy(base.gameObject); return; } for (int num = icicleLifetimes.Count - 1; num >= 0; num--) { icicleLifetimes[num] -= Time.fixedDeltaTime; if (icicleLifetimes[num] <= 0f) { icicleLifetimes.RemoveAt(num); } } NetworkfinalIcicleCount = Mathf.Min((icicleLifetimes.Count > 0) ? (icicleCountOnFirstKill + icicleLifetimes.Count) : 0, maxIcicleCount); attackStopwatch += Time.fixedDeltaTime; } if ((bool)cachedOwnerInfo.characterBody) { if (finalIcicleCount > 0) { if (lastIcicleCount == 0) { OnIciclesActivated(); } if (lastIcicleCount < finalIcicleCount) { OnIcicleGained(); } } else if (lastIcicleCount > 0) { OnIciclesDeactivated(); } lastIcicleCount = finalIcicleCount; } if (NetworkServer.active && (bool)cachedOwnerInfo.characterBody && finalIcicleCount > 0 && attackStopwatch >= baseIcicleAttackInterval) { attackStopwatch = 0f; BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = owner; blastAttack.inflictor = base.gameObject; blastAttack.teamIndex = cachedOwnerInfo.characterBody.teamComponent.teamIndex; blastAttack.position = transform.position; blastAttack.procCoefficient = icicleProcCoefficientPerTick; blastAttack.radius = actualRadius; blastAttack.baseForce = 0f; blastAttack.baseDamage = cachedOwnerInfo.characterBody.damage * (icicleDamageCoefficientPerTick + icicleDamageCoefficientPerTickPerIcicle * (float)finalIcicleCount); blastAttack.bonusForce = UnityEngine.Vector3.zero; blastAttack.crit = false; blastAttack.damageType = DamageType.Generic; blastAttack.falloffModel = BlastAttack.FalloffModel.None; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.Fire(); } if ((bool)buffWard) { buffWard.Networkradius = actualRadius; } } private void UpdateRadius() { if ((bool)owner) { if (finalIcicleCount > 0) { actualRadius = (cachedOwnerInfo.characterBody ? (cachedOwnerInfo.characterBody.radius + icicleBaseRadius + icicleRadiusPerIcicle * (float)finalIcicleCount) : 0f); } else { actualRadius = 0f; } } } private void UpdateVisuals() { if ((bool)cachedOwnerInfo.gameObject) { transform.position = (cachedOwnerInfo.characterBody ? cachedOwnerInfo.characterBody.corePosition : cachedOwnerInfo.transform.position); } float num = Mathf.SmoothDamp(transform.localScale.x, actualRadius, ref scaleVelocity, 0.5f); transform.localScale = new UnityEngine.Vector3(num, num, num); } private void OnIciclesDeactivated() { Util.PlaySound("Stop_item_proc_icicle", base.gameObject); ParticleSystem[] array = auraParticles; for (int i = 0; i < array.Length; i++) { ParticleSystem.MainModule main = array[i].main; main.loop = false; } aimRequest?.Dispose(); } private void OnIciclesActivated() { Util.PlaySound("Play_item_proc_icicle", base.gameObject); if ((bool)cachedOwnerInfo.cameraTargetParams) { aimRequest = cachedOwnerInfo.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura); } ParticleSystem[] array = auraParticles; foreach (ParticleSystem obj in array) { ParticleSystem.MainModule main = obj.main; main.loop = true; obj.Play(); } } private void OnIcicleGained() { ParticleSystem[] array = procParticles; for (int i = 0; i < array.Length; i++) { array[i].Play(); } } private void LateUpdate() { UpdateVisuals(); } public void OnOwnerKillOther() { icicleLifetimes.Add(icicleDuration); } public void OnDestroy() { OnIciclesDeactivated(); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt32((uint)finalIcicleCount); writer.Write(owner); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)finalIcicleCount); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(owner); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { finalIcicleCount = (int)reader.ReadPackedUInt32(); ___ownerNetId = reader.ReadNetworkId(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { finalIcicleCount = (int)reader.ReadPackedUInt32(); } if (((uint)num & 2u) != 0) { owner = reader.ReadGameObject(); } } public override void PreStartClient() { if (!___ownerNetId.IsEmpty()) { Networkowner = ClientScene.FindLocalObject(___ownerNetId); } } } public interface IDisplacementReceiver { void AddDisplacement(UnityEngine.Vector3 displacement); } public interface IDisplayNameProvider { string GetDisplayName(); } public interface IHologramContentProvider { bool ShouldDisplayHologram(GameObject viewer); GameObject GetHologramContentPrefab(); void UpdateHologramContent(GameObject hologramContentObject, Transform viewerBody); } public interface IIKTargetBehavior { void UpdateIKTargetPosition(); void UpdateIKState(int targetState); } public enum Interactability { Disabled, ConditionsNotMet, Available } public interface IInteractable { [CanBeNull] string GetContextString([NotNull] Interactor activator); Interactability GetInteractability([NotNull] Interactor activator); void OnInteractionBegin([NotNull] Interactor activator); bool ShouldIgnoreSpherecastForInteractibility([NotNull] Interactor activator); bool ShouldShowOnScanner(); bool ShouldProximityHighlight(); } public class IKSetWeightFromAnimatorFloat : MonoBehaviour { public Animator animator; public string animatorFloat; public InverseKinematics ik; private void Update() { float @float = animator.GetFloat(animatorFloat); Core.Chain[] otherChains = ik.otherChains; for (int i = 0; i < otherChains.Length; i++) { otherChains[i].weight = @float; } } } public class IKSimpleChain : MonoBehaviour { public enum InnerAxis { Left, Right, Forward, Backward } public float scale = 1f; public int maxIterations = 100; public float positionAccuracy = 0.001f; private float posAccuracy = 0.001f; public float bendingLow; public float bendingHigh; public int chainResolution; private int startBone; private bool minIsFound; private bool bendMore; private UnityEngine.Vector3 targetPosition; public float legLength; public float poleAngle; public InnerAxis innerAxis = InnerAxis.Right; private Transform tmpBone; public Transform ikPole; public Transform[] boneList; private bool firstRun = true; private IIKTargetBehavior ikTarget; private void Start() { ikTarget = GetComponent(); } private void LateUpdate() { if (firstRun) { tmpBone = boneList[startBone]; } if (ikTarget != null) { ikTarget.UpdateIKTargetPosition(); } targetPosition = base.transform.position; legLength = CalculateLegLength(boneList); Solve(boneList, targetPosition); firstRun = false; } public bool LegTooShort(float legScale = 1f) { bool result = false; if ((targetPosition - boneList[0].transform.position).sqrMagnitude >= legLength * legLength * legScale * legScale) { result = true; } return result; } private float CalculateLegLength(Transform[] bones) { float[] array = new float[bones.Length - 1]; float num = 0f; for (int i = startBone; i < bones.Length - 1; i++) { array[i] = (bones[i + 1].position - bones[i].position).magnitude; num += array[i]; } return num; } public void Solve(Transform[] bones, UnityEngine.Vector3 target) { Transform transform = bones[^1]; UnityEngine.Vector3[] array = new UnityEngine.Vector3[bones.Length - 2]; float[] array2 = new float[bones.Length - 2]; UnityEngine.Quaternion[] array3 = new UnityEngine.Quaternion[bones.Length - 2]; for (int i = startBone; i < bones.Length - 2; i++) { array[i] = UnityEngine.Vector3.Cross(bones[i + 1].position - bones[i].position, bones[i + 2].position - bones[i + 1].position); array[i] = UnityEngine.Quaternion.Inverse(bones[i].rotation) * array[i]; array[i] = array[i].normalized; array2[i] = UnityEngine.Vector3.Angle(bones[i + 1].position - bones[i].position, bones[i + 1].position - bones[i + 2].position); array3[i] = bones[i + 1].localRotation; } positionAccuracy = legLength * posAccuracy; float magnitude = (transform.position - bones[startBone].position).magnitude; float magnitude2 = (target - bones[startBone].position).magnitude; minIsFound = false; bendMore = false; if (magnitude2 >= magnitude) { minIsFound = true; bendingHigh = 1f; bendingLow = 0f; } else { bendMore = true; bendingHigh = 1f; bendingLow = 0f; } _ = array3.Length; int num = 0; while (Mathf.Abs(magnitude - magnitude2) > positionAccuracy && num < maxIterations) { num++; float num2 = (minIsFound ? ((bendingLow + bendingHigh) / 2f) : bendingHigh); for (int j = startBone; j < bones.Length - 2; j++) { float num3 = (bendMore ? (array2[j] * (1f - num2) + (array2[j] - 30f) * num2) : Mathf.Lerp(180f, array2[j], num2)); UnityEngine.Quaternion localRotation = UnityEngine.Quaternion.AngleAxis(array2[j] - num3, array[j]) * array3[j]; bones[j + 1].localRotation = localRotation; } magnitude = (transform.position - bones[startBone].position).magnitude; if (magnitude2 > magnitude) { minIsFound = true; } if (minIsFound) { if (magnitude2 > magnitude) { bendingHigh = num2; } else { bendingLow = num2; } if (bendingHigh < 0.01f) { break; } } else { bendingLow = bendingHigh; bendingHigh += 1f; } } if (firstRun) { tmpBone.rotation = bones[startBone].rotation; } bones[startBone].rotation = UnityEngine.Quaternion.AngleAxis(UnityEngine.Vector3.Angle(transform.position - bones[startBone].position, target - bones[startBone].position), UnityEngine.Vector3.Cross(transform.position - bones[startBone].position, target - bones[startBone].position)) * bones[startBone].rotation; if ((bool)ikPole) { UnityEngine.Vector3 position = bones[startBone].position; UnityEngine.Vector3 up = bones[startBone].transform.up; UnityEngine.Vector3 position2 = transform.position; UnityEngine.Vector3 vector = UnityEngine.Vector3.Cross(rhs: ikPole.position - position, lhs: position2 - position); UnityEngine.Vector3 vector2 = UnityEngine.Vector3.Cross(vector, up); UnityEngine.Vector3 vecU = UnityEngine.Vector3.zero; switch (innerAxis) { case InnerAxis.Right: vecU = bones[startBone].transform.right; break; case InnerAxis.Left: vecU = -bones[startBone].transform.right; break; case InnerAxis.Forward: vecU = bones[startBone].transform.forward; break; case InnerAxis.Backward: vecU = -bones[startBone].transform.forward; break; } float num4 = SignedAngle(vecU, vector2, up); num4 += poleAngle; bones[startBone].rotation = UnityEngine.Quaternion.AngleAxis(num4, transform.position - bones[startBone].position) * bones[startBone].rotation; UnityEngine.Debug.DrawLine(transform.position, bones[startBone].position, UnityEngine.Color.red); UnityEngine.Debug.DrawRay(bones[startBone].position, vector, UnityEngine.Color.blue); UnityEngine.Debug.DrawRay(bones[startBone].position, vector2, UnityEngine.Color.yellow); } tmpBone = bones[startBone]; } private float SignedAngle(UnityEngine.Vector3 vecU, UnityEngine.Vector3 vecV, UnityEngine.Vector3 normal) { float num = UnityEngine.Vector3.Angle(vecU, vecV); if (UnityEngine.Vector3.Angle(UnityEngine.Vector3.Cross(vecU, vecV), normal) < 1f) { num *= -1f; } return 0f - num; } private float AngleDir(UnityEngine.Vector3 fwd, UnityEngine.Vector3 targetDir, UnityEngine.Vector3 up) { float num = UnityEngine.Vector3.Dot(UnityEngine.Vector3.Cross(fwd, targetDir), up); if (num > 0f) { return 1f; } if (num < 0f) { return -1f; } return 0f; } } public class IKTargetPassive : MonoBehaviour, IIKTargetBehavior { private float smoothedTargetHeightOffset; private float targetHeightOffset; private float smoothdampVelocity; public float minHeight = -0.3f; public float maxHeight = 1f; public float dampTime = 0.1f; public float baseOffset; [Tooltip("The IK weight float parameter if used")] public string animatorIKWeightFloat = ""; public Animator animator; [Tooltip("The target transform will plant without any calls from external IK chains")] public bool selfPlant; public float selfPlantFrequency = 5f; [Tooltip("Whether or not to cache where the raycast begins. Used when not attached to bones, who reset themselves via animator.")] public bool cacheFirstPosition; private UnityEngine.Vector3 cachedLocalPosition; private float selfPlantTimer; public void UpdateIKState(int targetState) { } private void Awake() { if (cacheFirstPosition) { cachedLocalPosition = base.transform.localPosition; } } private void LateUpdate() { selfPlantTimer -= Time.deltaTime; if (selfPlant && selfPlantTimer <= 0f) { selfPlantTimer = 1f / selfPlantFrequency; UpdateIKTargetPosition(); } UpdateYOffset(); } public void UpdateIKTargetPosition() { ResetTransformToCachedPosition(); if (Physics.Raycast(base.transform.position + UnityEngine.Vector3.up * (0f - minHeight), UnityEngine.Vector3.down, out var hitInfo, maxHeight - minHeight, LayerIndex.world.mask)) { targetHeightOffset = hitInfo.point.y - base.transform.position.y; } else { targetHeightOffset = 0f; } targetHeightOffset += baseOffset; } public void UpdateYOffset() { float t = 1f; if ((bool)animator && animatorIKWeightFloat.Length > 0) { t = animator.GetFloat(animatorIKWeightFloat); } smoothedTargetHeightOffset = Mathf.SmoothDamp(smoothedTargetHeightOffset, targetHeightOffset, ref smoothdampVelocity, dampTime, float.PositiveInfinity, Time.deltaTime); ResetTransformToCachedPosition(); base.transform.position = new UnityEngine.Vector3(base.transform.position.x, base.transform.position.y + Mathf.Lerp(0f, smoothedTargetHeightOffset, t), base.transform.position.z); } private void ResetTransformToCachedPosition() { if (cacheFirstPosition) { base.transform.localPosition = new UnityEngine.Vector3(cachedLocalPosition.x, cachedLocalPosition.y, cachedLocalPosition.z); } } } public class IKTargetPlant : MonoBehaviour, IIKTargetBehavior { public enum IKState { Plant, Reset } [Tooltip("The max offset to step up")] public float minHeight = -0.3f; [Tooltip("The max offset to step down")] public float maxHeight = 1f; [Tooltip("The strength of the IK as a lerp (0-1)")] public float ikWeight = 1f; [Tooltip("The time to restep")] public float timeToReset = 0.6f; [Tooltip("The max positional IK error before restepping")] public float maxXZPositionalError = 4f; public GameObject plantEffect; public Animator animator; [Tooltip("The IK weight float parameter if used")] public string animatorIKWeightFloat; [Tooltip("The lift animation trigger string if used")] public string animatorLiftTrigger; [Tooltip("The scale of the leg for calculating if the leg is too short to reach the IK target")] public float legScale = 1f; [Tooltip("The height of the step arc")] public float arcHeight = 1f; [Tooltip("The smoothing duration for the IK. Higher will be smoother but will be delayed.")] public float smoothDampTime = 0.1f; [Tooltip("Spherecasts will have more hits but take higher performance.")] public bool useSpherecast; public float spherecastRadius = 0.5f; public IKState ikState; private bool isPlanted; private UnityEngine.Vector3 lastTransformPosition; private UnityEngine.Vector3 smoothDampRefVelocity; private UnityEngine.Vector3 targetPosition; private UnityEngine.Vector3 plantPosition; private IKSimpleChain ikChain; private float resetTimer; private void Awake() { ikChain = GetComponent(); } public void UpdateIKState(int targetState) { if (ikState != IKState.Reset) { ikState = (IKState)targetState; } } public UnityEngine.Vector3 GetArcPosition(UnityEngine.Vector3 start, UnityEngine.Vector3 end, float arcHeight, float t) { return UnityEngine.Vector3.Lerp(start, end, Mathf.Sin(t * MathF.PI * 0.5f)) + new UnityEngine.Vector3(0f, Mathf.Sin(t * MathF.PI) * arcHeight, 0f); } public void UpdateIKTargetPosition() { if ((bool)animator) { ikWeight = animator.GetFloat(animatorIKWeightFloat); } else { ikWeight = 1f; } switch (ikState) { case IKState.Reset: resetTimer += Time.deltaTime; isPlanted = false; RaycastIKTarget(base.transform.position); base.transform.position = GetArcPosition(plantPosition, targetPosition, arcHeight, resetTimer / timeToReset); if (resetTimer >= timeToReset) { ikState = IKState.Plant; isPlanted = true; plantPosition = targetPosition; UnityEngine.Object.Instantiate(plantEffect, plantPosition, UnityEngine.Quaternion.identity); } break; case IKState.Plant: { UnityEngine.Vector3 position = base.transform.position; RaycastIKTarget(position); if (!isPlanted) { plantPosition = targetPosition; base.transform.position = plantPosition; isPlanted = true; if ((bool)plantEffect) { UnityEngine.Object.Instantiate(plantEffect, plantPosition, UnityEngine.Quaternion.identity); } } else { base.transform.position = UnityEngine.Vector3.Lerp(position, plantPosition, ikWeight); } UnityEngine.Vector3 vector = position - base.transform.position; vector.y = 0f; if (ikChain.LegTooShort(legScale) || vector.sqrMagnitude >= maxXZPositionalError * maxXZPositionalError) { plantPosition = base.transform.position; ikState = IKState.Reset; if ((bool)animator) { animator.SetTrigger(animatorLiftTrigger); } resetTimer = 0f; } break; } } base.transform.position = UnityEngine.Vector3.SmoothDamp(lastTransformPosition, base.transform.position, ref smoothDampRefVelocity, smoothDampTime); lastTransformPosition = base.transform.position; } public void RaycastIKTarget(UnityEngine.Vector3 position) { RaycastHit hitInfo; if (useSpherecast) { Physics.SphereCast(position + UnityEngine.Vector3.up * (0f - minHeight), spherecastRadius, UnityEngine.Vector3.down, out hitInfo, maxHeight - minHeight, LayerIndex.world.mask); } else { Physics.Raycast(position + UnityEngine.Vector3.up * (0f - minHeight), UnityEngine.Vector3.down, out hitInfo, maxHeight - minHeight, LayerIndex.world.mask); } if ((bool)hitInfo.collider) { targetPosition = hitInfo.point; } else { targetPosition = position; } } } public interface ILifeBehavior { void OnDeathStart(); } [RequireComponent(typeof(EffectComponent))] internal class ImpactEffect : MonoBehaviour { public ParticleSystem[] particleSystems = Array.Empty(); private void Start() { EffectComponent component = GetComponent(); UnityEngine.Color color = ((component.effectData != null) ? ((UnityEngine.Color)component.effectData.color) : UnityEngine.Color.white); for (int i = 0; i < particleSystems.Length; i++) { ParticleSystem.MainModule main = particleSystems[i].main; main.startColor = color; particleSystems[i].Play(); } } } public class InfiniteTowerSafeWardController : MonoBehaviour { [SerializeField] private EntityStateMachine wardStateMachine; [SerializeField] private VerticalTubeZone _safeZone; [SerializeField] private GameObject positionIndicatorPrefab; [SerializeField] private HoldoutZoneController holdoutZoneController; private PositionIndicator positionIndicator; private ChargeIndicatorController chargeIndicatorController; public IZone safeZone => _safeZone; public bool isAwaitingInteraction { get { if ((bool)wardStateMachine) { return wardStateMachine.state is AwaitingActivation; } return false; } } public event Action onActivated; private void Awake() { if (!positionIndicatorPrefab) { return; } GameObject gameObject = UnityEngine.Object.Instantiate(positionIndicatorPrefab, base.transform.position, UnityEngine.Quaternion.identity); if ((bool)gameObject) { positionIndicator = gameObject.GetComponent(); if ((bool)positionIndicator) { positionIndicator.targetTransform = base.transform; } chargeIndicatorController = gameObject.GetComponent(); if ((bool)chargeIndicatorController) { chargeIndicatorController.holdoutZoneController = holdoutZoneController; } gameObject.SetActive(value: false); } } public void Activate() { if ((bool)wardStateMachine && wardStateMachine.state is AwaitingActivation awaitingActivation) { awaitingActivation.Activate(); this.onActivated?.Invoke(this); } } public void SelfDestruct() { if ((bool)wardStateMachine && wardStateMachine.state is EntityStates.InfiniteTowerSafeWard.Active active) { active.SelfDestruct(); } } public void RandomizeLocation(Xoroshiro128Plus rng) { if ((bool)wardStateMachine) { wardStateMachine.SetNextState(new Unburrow(rng)); } } public void WaitForPortal() { if ((bool)wardStateMachine) { wardStateMachine.SetNextState(new AwaitingPortalUse()); } } public void SetIndicatorEnabled(bool enabled) { if ((bool)positionIndicator) { positionIndicator.gameObject.SetActive(enabled); } } } public class InfiniteTowerBossWaveController : InfiniteTowerWaveController { [SerializeField] [Tooltip("The interactable spawner to activate when the player defeats all enemies")] private InteractableSpawner rewardInteractableSpawner; [SerializeField] [Tooltip("If true, it ensures that the combat director gets enough credits to spawn the initially selected champion spawn card.")] private bool guaranteeInitialChampion; [SerializeField] [Tooltip("If true, clear the pickups when this wave finishes")] private bool clearPickupsOnFinish; [Server] public override void Initialize(int waveIndex, Inventory enemyInventory, GameObject spawnTarget) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerBossWaveController::Initialize(System.Int32,RoR2.Inventory,UnityEngine.GameObject)' called on client"); return; } base.Initialize(waveIndex, enemyInventory, spawnTarget); combatDirector.SetNextSpawnAsBoss(); if (guaranteeInitialChampion && combatDirector.monsterCredit < (float)combatDirector.lastAttemptedMonsterCard.cost) { combatDirector.monsterCredit = combatDirector.lastAttemptedMonsterCard.cost; } } protected override void OnAllEnemiesDefeatedServer() { base.OnAllEnemiesDefeatedServer(); if ((bool)rewardInteractableSpawner) { rewardInteractableSpawner.Spawn(new Xoroshiro128Plus(Run.instance.seed ^ (ulong)waveIndex)); } if (RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Delusion)) { foreach (ChestBehavior instances in InstanceTracker.GetInstancesList()) { instances.CallRpcResetChests(); } } InfiniteTowerRun infiniteTowerRun = Run.instance as InfiniteTowerRun; if ((bool)infiniteTowerRun && !infiniteTowerRun.IsStageTransitionWave()) { infiniteTowerRun.MoveSafeWard(); } } protected override void OnFinishedServer() { base.OnFinishedServer(); if ((bool)rewardInteractableSpawner) { rewardInteractableSpawner.DestroySpawnedInteractables(); } if (!clearPickupsOnFinish) { return; } foreach (GenericPickupController item in new List(InstanceTracker.GetInstancesList())) { PickupDef pickupDef = PickupCatalog.GetPickupDef(item.pickupIndex); if (pickupDef.itemIndex != ItemIndex.None || pickupDef.equipmentIndex != EquipmentIndex.None) { UnityEngine.Object.Destroy(item.gameObject); } } } protected override void OnTimerExpire() { } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool flag = base.OnSerialize(writer, forceAll); bool flag2 = default(bool); return flag2 || flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { base.OnDeserialize(reader, initialState); } public override void PreStartClient() { base.PreStartClient(); } } public class InfiniteTowerExplicitSpawnWaveController : InfiniteTowerWaveController { [Serializable] private struct SpawnInfo { [SerializeField] public int count; [SerializeField] public CharacterSpawnCard spawnCard; [SerializeField] public EliteDef eliteDef; [SerializeField] public bool preventOverhead; [SerializeField] public DirectorCore.MonsterSpawnDistance spawnDistance; } [Tooltip("The information for all of the characters to spawn.")] [SerializeField] private SpawnInfo[] spawnList; [Server] public override void Initialize(int waveIndex, Inventory enemyInventory, GameObject spawnTargetObject) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerExplicitSpawnWaveController::Initialize(System.Int32,RoR2.Inventory,UnityEngine.GameObject)' called on client"); return; } base.Initialize(waveIndex, enemyInventory, spawnTargetObject); SpawnInfo[] array = spawnList; for (int i = 0; i < array.Length; i++) { SpawnInfo spawnInfo = array[i]; for (int j = 0; j < spawnInfo.count; j++) { combatDirector.Spawn(spawnInfo.spawnCard, spawnInfo.eliteDef, spawnTarget.transform, preventOverhead: spawnInfo.preventOverhead, spawnDistance: spawnInfo.spawnDistance); } } } protected override void OnAllEnemiesDefeatedServer() { base.OnAllEnemiesDefeatedServer(); InfiniteTowerRun infiniteTowerRun = Run.instance as InfiniteTowerRun; if ((bool)infiniteTowerRun && !infiniteTowerRun.IsStageTransitionWave()) { infiniteTowerRun.MoveSafeWard(); } } protected override void OnTimerExpire() { } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool flag = base.OnSerialize(writer, forceAll); bool flag2 = default(bool); return flag2 || flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { base.OnDeserialize(reader, initialState); } public override void PreStartClient() { base.PreStartClient(); } } [DisallowMultipleComponent] public class InfiniteTowerWaveController : NetworkBehaviour { [Serializable] public struct OverlayEntry { [Tooltip("The overlay prefab to instantiate")] [SerializeField] public GameObject prefab; [Tooltip("The overaly prefab to instantiate")] [SerializeField] public string hudChildName; } private const float minimumDistributedCreditsFraction = 0.1f; [Tooltip("Should the enemies in this wave count as bosses?")] [SerializeField] private bool isBossWave; [Tooltip("The combat director for this wave")] [SerializeField] protected CombatDirector combatDirector; [Tooltip("The combat squad for this wave")] [SerializeField] protected CombatSquad combatSquad; [Tooltip("The base total number of credits to give to the CombatDirector for this wave. Wave 1 gets this many credits.")] [SerializeField] protected float baseCredits; [Tooltip("The number of additional credits to give to the CombatDirector for each wave you've completed. This doesn't affect Wave 1.")] [SerializeField] protected float linearCreditsPerWave; [SerializeField] [Tooltip("The period (in seconds) over which we give the CombatDirector its credits.")] protected float wavePeriodSeconds; [SerializeField] [Tooltip("The number of seconds (after the last enemy is spawned) before the radius begins constricting")] protected float secondsBeforeSuddenDeath = 60f; [SerializeField] [Tooltip("If there's ever a period of this many seconds with no enemies, end the wave")] protected float secondsBeforeFailsafe = 60f; [Range(0f, 1f)] [Tooltip("The zone radius percentage is reduced by this amount each second")] [SerializeField] protected float suddenDeathRadiusConstrictingPerSecond = 0.05f; [Tooltip("Broadcast this message at the beginning of sudden death")] [SerializeField] protected string suddenDeathChatToken = "INFINITETOWER_SUDDEN_DEATH"; [Range(0f, 1f)] [Tooltip("The normalized fraction of the total credits to give to the CombatDirector immediately")] [SerializeField] protected float immediateCreditsFraction; [SerializeField] [Tooltip("The maximum number of members in the combat squad before we stop giving the CombatDirector credits. If the squad size is reduced below this number, we resume giving the director credits.")] protected int maxSquadSize; [SerializeField] [Tooltip("The time (in seconds) after completing the wave before the next wave begins")] public int secondsAfterWave; [Tooltip("The time (in seconds) after completing the wave before the next wave begins")] [SerializeField] protected float squadDefeatGracePeriod = 1f; [Tooltip("The prefab to instantiate on the UI.")] [SerializeField] protected GameObject uiPrefab; [Tooltip("The overlays to add for this wave")] [SerializeField] protected OverlayEntry[] overlayEntries; [Tooltip("If true, convert all player gold to experience at the end of the wave")] [SerializeField] protected bool convertGoldOnWaveFinish; [Tooltip("The multiplier to use when converting gold to experience (only used if convertGoldOnWaveFinish is true).")] [SerializeField] protected float goldToExpConversionRatio; [SerializeField] [Tooltip("The drop table to use for the end of wave rewards")] protected PickupDropTable rewardDropTable; [Tooltip("Use this tier to get a pickup index for the reward. The droplet's visuals will correspond to this.")] [SerializeField] protected ItemTier rewardDisplayTier; [Tooltip("The number of options to display when the player interacts with the reward pickup.")] [SerializeField] protected int rewardOptionCount; [Tooltip("The prefab to use for the reward pickup.")] [SerializeField] protected GameObject rewardPickupPrefab; [Tooltip("Where to spawn the reward droplets relative to the spawn target (the center of the safe ward).")] [SerializeField] protected UnityEngine.Vector3 rewardOffset; [Tooltip("Broadcast this message at the beginning of the wave.")] [SerializeField] protected string beginChatToken = "INFINITETOWER_WAVE_BEGIN"; [Tooltip("Play this sound at the beginning of the wave.")] [SerializeField] protected string beginSoundString; [Tooltip("Play this sound when all enemies are defeated.")] [SerializeField] protected string onAllEnemiesDefeatedSoundString; [SyncVar] private float _totalWaveCredits; [SyncVar] private float _totalCreditsSpent; [SyncVar] private float _timerStart; [SyncVar] private float _failsafeTimer; [SyncVar] protected float _suddenDeathTimerStart; [SyncVar] private bool _isFinished; [SyncVar] private bool _isTimerActive; [SyncVar] private float _zoneRadiusPercentage = 1f; [SyncVar] protected int waveIndex; [SyncVar] private int squadCount; [SyncVar] private bool haveAllEnemiesBeenDefeated; protected float creditsPerSecond; protected GameObject uiInstance; protected bool hasEnabledEnemyIndicators; protected float squadDefeatTimer; private Inventory enemyInventory; private bool hasTimerExpired; protected GameObject spawnTarget; private Xoroshiro128Plus rng; private List overlayControllerList = new List(); private bool hasNotifiedSuddenDeath; private bool hasPlayedEnemiesDefeatedSound; private int clearMemoryEveryXRounds = 5; public GameObject defaultEnemyIndicatorPrefab { get; set; } public bool isFinished { get { return _isFinished; } private set { Network_isFinished = value; } } public bool isTimerActive { get { return _isTimerActive; } private set { Network_isTimerActive = value; } } public float totalWaveCredits { get { return _totalWaveCredits; } protected set { Network_totalWaveCredits = value; } } public float totalCreditsSpent { get { return _totalCreditsSpent; } protected set { Network_totalCreditsSpent = value; } } public float zoneRadiusPercentage { get { return _zoneRadiusPercentage; } protected set { Network_zoneRadiusPercentage = value; } } public float secondsRemaining { get { if ((bool)Run.instance && _timerStart > 0f) { return Mathf.Max(0f, (float)secondsAfterWave - (Run.instance.GetRunStopwatch() - _timerStart)); } return secondsAfterWave; } } public bool isInSuddenDeath { get { if ((bool)Run.instance && _suddenDeathTimerStart > 0f) { if (!haveAllEnemiesBeenDefeated && HasFullProgress()) { return secondsBeforeSuddenDeath - (Run.instance.GetRunStopwatch() - _suddenDeathTimerStart) < 0f; } return false; } return false; } } public float Network_totalWaveCredits { get { return _totalWaveCredits; } [param: In] set { SetSyncVar(value, ref _totalWaveCredits, 1u); } } public float Network_totalCreditsSpent { get { return _totalCreditsSpent; } [param: In] set { SetSyncVar(value, ref _totalCreditsSpent, 2u); } } public float Network_timerStart { get { return _timerStart; } [param: In] set { SetSyncVar(value, ref _timerStart, 4u); } } public float Network_failsafeTimer { get { return _failsafeTimer; } [param: In] set { SetSyncVar(value, ref _failsafeTimer, 8u); } } public float Network_suddenDeathTimerStart { get { return _suddenDeathTimerStart; } [param: In] set { SetSyncVar(value, ref _suddenDeathTimerStart, 16u); } } public bool Network_isFinished { get { return _isFinished; } [param: In] set { SetSyncVar(value, ref _isFinished, 32u); } } public bool Network_isTimerActive { get { return _isTimerActive; } [param: In] set { SetSyncVar(value, ref _isTimerActive, 64u); } } public float Network_zoneRadiusPercentage { get { return _zoneRadiusPercentage; } [param: In] set { SetSyncVar(value, ref _zoneRadiusPercentage, 128u); } } public int NetworkwaveIndex { get { return waveIndex; } [param: In] set { SetSyncVar(value, ref waveIndex, 256u); } } public int NetworksquadCount { get { return squadCount; } [param: In] set { SetSyncVar(value, ref squadCount, 512u); } } public bool NetworkhaveAllEnemiesBeenDefeated { get { return haveAllEnemiesBeenDefeated; } [param: In] set { SetSyncVar(value, ref haveAllEnemiesBeenDefeated, 1024u); } } public event Action onAllEnemiesDefeatedServer; [Server] public virtual void Initialize(int waveIndex, Inventory enemyInventory, GameObject spawnTarget) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::Initialize(System.Int32,RoR2.Inventory,UnityEngine.GameObject)' called on client"); return; } totalWaveCredits = (baseCredits + linearCreditsPerWave * (float)(waveIndex - 1)) * Run.instance.difficultyCoefficient; creditsPerSecond = Mathf.Max(0.1f, 1f - immediateCreditsFraction) * totalWaveCredits / wavePeriodSeconds; if ((bool)combatDirector) { combatDirector.monsterCredit += immediateCreditsFraction * totalWaveCredits; combatDirector.currentSpawnTarget = spawnTarget; } NetworkwaveIndex = waveIndex; this.enemyInventory = enemyInventory; this.spawnTarget = spawnTarget; rng = new Xoroshiro128Plus((ulong)waveIndex ^ Run.instance.seed); if (!string.IsNullOrEmpty(beginChatToken)) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = beginChatToken }); } } public void InstantiateUi(Transform uiRoot) { if ((bool)uiRoot && (bool)uiPrefab) { uiInstance = UnityEngine.Object.Instantiate(uiPrefab, uiRoot); } OverlayEntry[] array = overlayEntries; for (int i = 0; i < array.Length; i++) { OverlayEntry overlayEntry = array[i]; OverlayCreationParams overlayCreationParams = default(OverlayCreationParams); overlayCreationParams.prefab = overlayEntry.prefab; overlayCreationParams.childLocatorEntry = overlayEntry.hudChildName; OverlayController item = HudOverlayManager.AddGlobalOverlay(overlayCreationParams); overlayControllerList.Add(item); } } public void PlayBeginSound() { Util.PlaySound(beginSoundString, RoR2Application.instance.gameObject); } public void PlayAllEnemiesDefeatedSound() { hasPlayedEnemiesDefeatedSound = true; Util.PlaySound(onAllEnemiesDefeatedSoundString, RoR2Application.instance.gameObject); } public int GetSquadCount() { if (NetworkServer.active) { if ((bool)combatSquad) { return combatSquad.memberCount; } return 0; } return squadCount; } public virtual float GetNormalizedProgress() { if (totalWaveCredits != 0f) { return totalCreditsSpent / totalWaveCredits; } return 1f; } public virtual bool HasFullProgress() { return totalCreditsSpent >= totalWaveCredits; } [Server] public virtual void ForceFinish() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::ForceFinish()' called on client"); return; } KillSquad(); if ((bool)combatDirector) { combatDirector.monsterCredit = 0f; } MarkAsFinished(); } [Server] private void KillSquad() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::KillSquad()' called on client"); } else { if (!combatSquad) { return; } foreach (CharacterMaster item in new List(combatSquad.readOnlyMembersList)) { item.TrueKill(); } } } [Server] protected void MarkAsFinished() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::MarkAsFinished()' called on client"); return; } isFinished = true; OnFinishedServer(); } [Server] protected void StartTimer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::StartTimer()' called on client"); return; } Network_isTimerActive = true; Network_timerStart = Run.instance.GetRunStopwatch(); } [Server] protected virtual void OnAllEnemiesDefeatedServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::OnAllEnemiesDefeatedServer()' called on client"); return; } DropRewards(); this.onAllEnemiesDefeatedServer?.Invoke(this); } [Server] protected virtual void OnTimerExpire() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::OnTimerExpire()' called on client"); } else { MarkAsFinished(); } } [Server] protected virtual void OnFinishedServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::OnFinishedServer()' called on client"); } else { if (!convertGoldOnWaveFinish) { return; } ReadOnlyCollection instances = PlayerCharacterMasterController.instances; for (int i = 0; i < instances.Count; i++) { CharacterMaster component = instances[i].gameObject.GetComponent(); uint num = Math.Max(component.money, (uint)Mathf.CeilToInt(component.money)); ulong num2 = (ulong)((float)num * goldToExpConversionRatio / (float)instances.Count); component.money -= num; GameObject bodyObject = component.GetBodyObject(); if ((bool)bodyObject) { ExperienceManager.instance.AwardExperience(base.transform.position, bodyObject.GetComponent(), num2); } else { TeamManager.instance.GiveTeamExperience(component.teamIndex, num2); } } } } private void FixedUpdate() { if (haveAllEnemiesBeenDefeated && !hasPlayedEnemiesDefeatedSound) { PlayAllEnemiesDefeatedSound(); if (waveIndex % clearMemoryEveryXRounds == 0) { Resources.UnloadUnusedAssets(); } } if (NetworkServer.active) { if ((bool)combatDirector) { NetworksquadCount = GetSquadCount(); Network_totalCreditsSpent = combatDirector.totalCreditsSpent; } if (!isFinished) { if ((bool)combatSquad && combatSquad.memberCount == 0 && !haveAllEnemiesBeenDefeated) { Network_failsafeTimer = _failsafeTimer + Time.fixedDeltaTime; if (_failsafeTimer > secondsBeforeFailsafe) { UnityEngine.Debug.LogError($"Failsafe detected! Ending wave {waveIndex}"); totalWaveCredits = 0f; if ((bool)combatDirector) { combatDirector.monsterCredit = 0f; } } } else { Network_failsafeTimer = 0f; } if (isInSuddenDeath) { if (!hasNotifiedSuddenDeath) { if (!string.IsNullOrEmpty(suddenDeathChatToken)) { Chat.SendBroadcastChat(new Chat.SimpleChatMessage { baseToken = suddenDeathChatToken }); } hasNotifiedSuddenDeath = true; } Network_zoneRadiusPercentage = Math.Max(0f, _zoneRadiusPercentage - suddenDeathRadiusConstrictingPerSecond * Time.fixedDeltaTime); } else { Network_zoneRadiusPercentage = 1f; } if (!isTimerActive) { if ((bool)combatDirector) { if (combatDirector.totalCreditsSpent < totalWaveCredits) { if (combatSquad.memberCount < maxSquadSize) { float num = Time.fixedDeltaTime * creditsPerSecond; combatDirector.monsterCredit += num; } } else { if (_suddenDeathTimerStart == 0f) { Network_suddenDeathTimerStart = Run.instance.GetRunStopwatch(); } combatDirector.monsterCredit = 0f; if (combatSquad.memberCount == 0) { if (squadDefeatTimer <= 0f) { NetworkhaveAllEnemiesBeenDefeated = true; StartTimer(); OnAllEnemiesDefeatedServer(); } else { squadDefeatTimer -= Time.fixedDeltaTime; } } } } } else { Network_zoneRadiusPercentage = 1f; if (!hasTimerExpired && secondsRemaining <= 0f) { hasTimerExpired = true; OnTimerExpire(); } } } else { Network_zoneRadiusPercentage = 1f; } } if (hasEnabledEnemyIndicators || !combatSquad || !HasFullProgress()) { return; } hasEnabledEnemyIndicators = true; foreach (CharacterMaster readOnlyMembers in combatSquad.readOnlyMembersList) { RequestIndicatorForMaster(readOnlyMembers); } } private void OnDestroy() { if ((bool)uiInstance) { UnityEngine.Object.Destroy(uiInstance); } foreach (OverlayController overlayController in overlayControllerList) { HudOverlayManager.RemoveGlobalOverlay(overlayController); } } private void OnEnable() { if ((bool)combatSquad) { combatSquad.onMemberDiscovered += OnCombatSquadMemberDiscovered; } squadDefeatTimer = squadDefeatGracePeriod; } private void OnDisable() { if ((bool)combatSquad) { combatSquad.onMemberDiscovered -= OnCombatSquadMemberDiscovered; } } protected virtual void OnCombatSquadMemberDiscovered(CharacterMaster master) { if (hasEnabledEnemyIndicators) { RequestIndicatorForMaster(master); } squadDefeatTimer = squadDefeatGracePeriod; if (NetworkServer.active) { master.inventory.AddItemsFrom(enemyInventory); } master.isBoss = isBossWave; } protected virtual void RequestIndicatorForMaster(CharacterMaster master) { GameObject bodyObject = master.GetBodyObject(); if ((bool)bodyObject) { TeamComponent component = bodyObject.GetComponent(); if ((bool)component) { component.RequestDefaultIndicator(defaultEnemyIndicatorPrefab); } } } [Server] private void DropRewards() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::DropRewards()' called on client"); return; } int participatingPlayerCount = Run.instance.participatingPlayerCount; if (participatingPlayerCount > 0 && (bool)spawnTarget && (bool)rewardDropTable) { int num = participatingPlayerCount; float angle = 360f / (float)num; UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up); UnityEngine.Vector3 position = spawnTarget.transform.position + rewardOffset; int num2 = 0; while (num2 < num) { GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo); createPickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier); createPickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(rewardOptionCount, rewardDropTable, rng); createPickupInfo.rotation = UnityEngine.Quaternion.identity; createPickupInfo.prefabOverride = rewardPickupPrefab; createPickupInfo.position = position; GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo; PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, vector); num2++; vector = quaternion * vector; } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(_totalWaveCredits); writer.Write(_totalCreditsSpent); writer.Write(_timerStart); writer.Write(_failsafeTimer); writer.Write(_suddenDeathTimerStart); writer.Write(_isFinished); writer.Write(_isTimerActive); writer.Write(_zoneRadiusPercentage); writer.WritePackedUInt32((uint)waveIndex); writer.WritePackedUInt32((uint)squadCount); writer.Write(haveAllEnemiesBeenDefeated); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_totalWaveCredits); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_totalCreditsSpent); } if ((base.syncVarDirtyBits & 4u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_timerStart); } if ((base.syncVarDirtyBits & 8u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_failsafeTimer); } if ((base.syncVarDirtyBits & 0x10u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_suddenDeathTimerStart); } if ((base.syncVarDirtyBits & 0x20u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_isFinished); } if ((base.syncVarDirtyBits & 0x40u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_isTimerActive); } if ((base.syncVarDirtyBits & 0x80u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_zoneRadiusPercentage); } if ((base.syncVarDirtyBits & 0x100u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)waveIndex); } if ((base.syncVarDirtyBits & 0x200u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)squadCount); } if ((base.syncVarDirtyBits & 0x400u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(haveAllEnemiesBeenDefeated); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { _totalWaveCredits = reader.ReadSingle(); _totalCreditsSpent = reader.ReadSingle(); _timerStart = reader.ReadSingle(); _failsafeTimer = reader.ReadSingle(); _suddenDeathTimerStart = reader.ReadSingle(); _isFinished = reader.ReadBoolean(); _isTimerActive = reader.ReadBoolean(); _zoneRadiusPercentage = reader.ReadSingle(); waveIndex = (int)reader.ReadPackedUInt32(); squadCount = (int)reader.ReadPackedUInt32(); haveAllEnemiesBeenDefeated = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { _totalWaveCredits = reader.ReadSingle(); } if (((uint)num & 2u) != 0) { _totalCreditsSpent = reader.ReadSingle(); } if (((uint)num & 4u) != 0) { _timerStart = reader.ReadSingle(); } if (((uint)num & 8u) != 0) { _failsafeTimer = reader.ReadSingle(); } if (((uint)num & 0x10u) != 0) { _suddenDeathTimerStart = reader.ReadSingle(); } if (((uint)num & 0x20u) != 0) { _isFinished = reader.ReadBoolean(); } if (((uint)num & 0x40u) != 0) { _isTimerActive = reader.ReadBoolean(); } if (((uint)num & 0x80u) != 0) { _zoneRadiusPercentage = reader.ReadSingle(); } if (((uint)num & 0x100u) != 0) { waveIndex = (int)reader.ReadPackedUInt32(); } if (((uint)num & 0x200u) != 0) { squadCount = (int)reader.ReadPackedUInt32(); } if (((uint)num & 0x400u) != 0) { haveAllEnemiesBeenDefeated = reader.ReadBoolean(); } } public override void PreStartClient() { } } [RequireComponent(typeof(CharacterBody))] public class InputBankTest : MonoBehaviour { private struct CachedRaycastInfo { public float time; public float fixedTime; public bool didHit; public RaycastHit hitInfo; public float maxDistance; public static readonly CachedRaycastInfo empty = new CachedRaycastInfo { time = float.NegativeInfinity, fixedTime = float.NegativeInfinity, didHit = false, maxDistance = 0f }; } public struct ButtonState { public bool down; public bool wasDown; public bool hasPressBeenClaimed; public bool justReleased { get { if (!down) { return wasDown; } return false; } } public bool justPressed { get { if (down) { return !wasDown; } return false; } } public void PushState(bool newState) { hasPressBeenClaimed &= newState; wasDown = down; down = newState; } } private CharacterBody characterBody; private UnityEngine.Vector3 _aimDirection; private float lastRaycastTime = float.NegativeInfinity; private float lastFixedRaycastTime = float.NegativeInfinity; private bool didLastRaycastHit; private RaycastHit lastHitInfo; private float lastMaxDistance; private CachedRaycastInfo cachedRaycast = CachedRaycastInfo.empty; public UnityEngine.Vector3 moveVector; public ButtonState skill1; public ButtonState skill2; public ButtonState skill3; public ButtonState skill4; public ButtonState interact; public ButtonState jump; public ButtonState sprint; public ButtonState activateEquipment; public ButtonState ping; public ButtonState rawMoveUp; public ButtonState rawMoveDown; public ButtonState rawMoveRight; public ButtonState rawMoveLeft; public UnityEngine.Vector2 rawMoveData; public UnityEngine.Vector3 aimDirection { get { if (!(_aimDirection != UnityEngine.Vector3.zero)) { return base.transform.forward; } return _aimDirection; } set { _aimDirection = value.normalized; } } public UnityEngine.Vector3 aimOrigin { get { if (!characterBody.aimOriginTransform) { return base.transform.position; } return characterBody.aimOriginTransform.position; } } public int emoteRequest { get; set; } = -1; public Ray GetAimRay() { return new Ray(aimOrigin, aimDirection); } public bool GetAimRaycast(float maxDistance, out RaycastHit hitInfo) { float time = Time.time; float fixedTime = Time.fixedTime; if (!cachedRaycast.time.Equals(time) || !cachedRaycast.fixedTime.Equals(fixedTime) || (!(cachedRaycast.maxDistance >= maxDistance) && !cachedRaycast.didHit)) { float extraRaycastDistance = 0f; Ray ray = CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance); cachedRaycast = CachedRaycastInfo.empty; cachedRaycast.time = time; cachedRaycast.fixedTime = fixedTime; cachedRaycast.maxDistance = maxDistance; cachedRaycast.didHit = Util.CharacterRaycast(base.gameObject, ray, maxDistance: maxDistance + extraRaycastDistance, layerMask: (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, hitInfo: out cachedRaycast.hitInfo, queryTriggerInteraction: QueryTriggerInteraction.Ignore); } bool flag = cachedRaycast.didHit; hitInfo = cachedRaycast.hitInfo; if (flag && hitInfo.distance > maxDistance) { flag = false; hitInfo = default(RaycastHit); } return flag; } public void SetRawMoveStates(UnityEngine.Vector2 _rawMoveData) { float num = 0.9f; float num2 = 0.1f; rawMoveUp.PushState((_rawMoveData.y > num && !rawMoveUp.down) || (_rawMoveData.y > num2 && rawMoveUp.down)); rawMoveDown.PushState((_rawMoveData.y < 0f - num && !rawMoveDown.down) || (_rawMoveData.y < 0f - num2 && rawMoveDown.down)); rawMoveLeft.PushState((_rawMoveData.x < 0f - num && !rawMoveLeft.down) || (_rawMoveData.x < 0f - num2 && rawMoveLeft.down)); rawMoveRight.PushState((_rawMoveData.x > num && !rawMoveRight.down) || (_rawMoveData.x > num2 && rawMoveRight.down)); rawMoveData = _rawMoveData; } public bool CheckAnyButtonDown() { if (!skill1.down && !skill2.down && !skill3.down && !skill4.down && !interact.down && !jump.down && !sprint.down && !activateEquipment.down) { return ping.down; } return true; } private void Awake() { characterBody = GetComponent(); } private void Start() { if (characterBody.hasEffectiveAuthority) { if ((bool)characterBody.characterDirection) { aimDirection = characterBody.characterDirection.forward; } else { aimDirection = base.transform.forward; } } } } public class InputResponse : MonoBehaviour { public string[] inputActionNames; public UnityEvent onPress; private void Update() { foreach (Player player in ReInput.players.Players) { for (int i = 0; i < inputActionNames.Length; i++) { if (player.GetButtonDown(inputActionNames[i])) { onPress?.Invoke(); break; } } } } } public class InstantiatePrefabBehavior : MonoBehaviour { [Tooltip("The prefab to instantiate.")] public GameObject prefab; [Tooltip("The object upon which the prefab will be positioned.")] public Transform targetTransform; [Tooltip("The transform upon which to instantiate the prefab.")] public bool copyTargetRotation; [Tooltip("Whether or not to parent the instantiated prefab to the specified transform.")] public bool parentToTarget; [Tooltip("Whether or not this is a networked prefab. If so, this will only run on the server, and will be spawned over the network.")] public bool networkedPrefab; [Tooltip("Whether or not to instantiate this prefab. If so, this will only run on the server, and will be spawned over the network.")] public bool instantiateOnStart = true; [Tooltip("Whether or not to force this prefab to be active, even if the prefab itself is inactive.")] public bool forceActivate; public void Start() { if (instantiateOnStart) { InstantiatePrefab(); } } public void InstantiatePrefab() { if (!networkedPrefab || NetworkServer.active) { UnityEngine.Vector3 position = (targetTransform ? targetTransform.position : UnityEngine.Vector3.zero); UnityEngine.Quaternion rotation = (copyTargetRotation ? targetTransform.rotation : UnityEngine.Quaternion.identity); Transform parent = (parentToTarget ? targetTransform : null); GameObject gameObject = UnityEngine.Object.Instantiate(prefab, position, rotation, parent); if (forceActivate) { gameObject.SetActive(value: true); } if (networkedPrefab) { NetworkServer.Spawn(gameObject); } } } } public class InteractableSpawner : NetworkBehaviour { [SerializeField] [Tooltip("The selection of director cards to use when spawning stuff")] private DirectorCardCategorySelection interactableCards; [Tooltip("How much stuff should this thing spawn")] [SerializeField] private float creditsToSpawn; private List spawnedObjects = new List(); [Server] public void Spawn(Xoroshiro128Plus rng) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InteractableSpawner::Spawn(Xoroshiro128Plus)' called on client"); return; } WeightedSelection weightedSelection = interactableCards.GenerateDirectorCardWeightedSelection(); float num = creditsToSpawn; while (num > 0f) { DirectorCard directorCard = weightedSelection.Evaluate(rng.nextNormalizedFloat); if (directorCard == null) { break; } if (!directorCard.IsAvailable()) { num -= 1f; continue; } num -= (float)directorCard.cost; for (int i = 0; i < 10; i++) { DirectorPlacementRule placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Random }; GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(directorCard.spawnCard, placementRule, rng)); if ((bool)gameObject) { PurchaseInteraction component = gameObject.GetComponent(); if ((bool)component && component.costType == CostTypeIndex.Money) { component.Networkcost = Run.instance.GetDifficultyScaledCost(component.cost); } spawnedObjects.Add(gameObject); break; } } } } [Server] public void DestroySpawnedInteractables() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InteractableSpawner::DestroySpawnedInteractables()' called on client"); return; } foreach (GameObject spawnedObject in spawnedObjects) { UnityEngine.Object.Destroy(spawnedObject); } spawnedObjects.Clear(); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } [RequireComponent(typeof(Interactor))] [RequireComponent(typeof(InputBankTest))] public class InteractionDriver : MonoBehaviour, ILifeBehavior { public bool highlightInteractor; public UnityEngine.Vector3 aimOffset; public bool useAimOffset; public bool drawDebugRay; public float debugRayLength = 5f; private bool inputReceived; private NetworkIdentity networkIdentity; private InputBankTest inputBank; private CharacterBody characterBody; private EquipmentSlot equipmentSlot; [NonSerialized] public GameObject interactableOverride; private const float interactableCooldownDuration = 0.25f; private float interactableCooldown; private const float interactableCheckCooldownDuration = 0f; private float interactableCheckCooldown; private GameObject saleStarEffect; [NonSerialized] public GameObject currentInteractable; public Interactor interactor { get; private set; } private void Awake() { networkIdentity = GetComponent(); interactor = GetComponent(); inputBank = GetComponent(); characterBody = GetComponent(); equipmentSlot = (characterBody ? characterBody.equipmentSlot : null); } private void FixedUpdate() { MyFixedUpdate(Time.deltaTime); } private void MyFixedUpdate(float deltaTime) { if (networkIdentity.hasAuthority) { interactableCooldown -= deltaTime; interactableCheckCooldown -= deltaTime; inputReceived = inputBank.interact.justPressed || (inputBank.interact.down && interactableCooldown <= 0f); if (inputBank.interact.justReleased) { inputReceived = false; interactableCooldown = 0f; } currentInteractable = FindBestInteractableObject(); } if (inputReceived && (bool)currentInteractable) { interactor.AttemptInteraction(currentInteractable); interactableCooldown = 0.25f; } if ((bool)currentInteractable) { if (characterBody.inventory.GetItemCount(DLC2Content.Items.LowerPricedChests) > 0) { PurchaseInteraction component = currentInteractable.GetComponent(); if ((object)component != null && component.saleStarCompatible) { if ((bool)currentInteractable.GetComponent() && currentInteractable.GetComponent().CanBeAffordedByInteractor(GetComponent()) && !saleStarEffect) { saleStarEffect = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/Effects/LowerPricedChestsGlow"), currentInteractable.transform.position, UnityEngine.Quaternion.identity, currentInteractable.transform); } return; } } if ((bool)saleStarEffect) { UnityEngine.Object.Destroy(saleStarEffect); } } else if ((bool)saleStarEffect) { UnityEngine.Object.Destroy(saleStarEffect); } } public GameObject FindBestInteractableObject() { if ((bool)interactableOverride) { return interactableOverride; } if (interactableCheckCooldown > 0f) { return currentInteractable; } interactableCheckCooldown = 0f; float extraRaycastDistance = 0f; float num = interactor.maxInteractionDistance; if ((bool)equipmentSlot && equipmentSlot.equipmentIndex == RoR2Content.Equipment.Recycle.equipmentIndex) { num *= 2f; } UnityEngine.Vector3 vector = inputBank.aimOrigin; UnityEngine.Vector3 vector2 = inputBank.aimDirection; if (useAimOffset) { UnityEngine.Vector3 vector3 = vector + vector2 * num; vector = inputBank.aimOrigin + aimOffset; vector2 = (vector3 - vector) / num; } Ray originalAimRay = new Ray(vector, vector2); if (drawDebugRay) { UnityEngine.Debug.DrawLine(vector, vector + vector2 * debugRayLength, UnityEngine.Color.green, 0.5f); } Ray raycastRay = CameraRigController.ModifyAimRayIfApplicable(originalAimRay, base.gameObject, out extraRaycastDistance); return interactor.FindBestInteractableObject(raycastRay, num + extraRaycastDistance, originalAimRay.origin, num); } static InteractionDriver() { OutlineHighlight.onPreRenderOutlineHighlight = (Action)Delegate.Combine(OutlineHighlight.onPreRenderOutlineHighlight, new Action(OnPreRenderOutlineHighlight)); } private static void OnPreRenderOutlineHighlight(OutlineHighlight outlineHighlight) { if (!outlineHighlight.sceneCamera || !outlineHighlight.sceneCamera.cameraRigController) { return; } GameObject target = outlineHighlight.sceneCamera.cameraRigController.target; if (!target) { return; } InteractionDriver component = target.GetComponent(); if (!component) { return; } GameObject gameObject = component.currentInteractable; if (!gameObject) { return; } IInteractable component2 = gameObject.GetComponent(); Highlight component3 = gameObject.GetComponent(); if ((bool)component3) { UnityEngine.Color color = component3.GetColor(); if (component2 != null && ((MonoBehaviour)component2).isActiveAndEnabled && component2.GetInteractability(component.interactor) == Interactability.ConditionsNotMet) { color = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Unaffordable); } outlineHighlight.highlightQueue.Enqueue(new OutlineHighlight.HighlightInfo { renderer = component3.targetRenderer, color = color * component3.strength }); } } public void OnDeathStart() { base.enabled = false; } } public class InteractionProcFilter : MonoBehaviour { [Tooltip("Whether or not OnInteractionBegin for this object should trigger extra gameplay effects like Fireworks and Squid Polyp.")] public bool shouldAllowOnInteractionBeginProc = true; } public class Interactor : NetworkBehaviour { public float maxInteractionDistance = 1f; private static int kCmdCmdInteract; private static int kRpcRpcInteractionResult; public GameObject FindBestInteractableObject(Ray raycastRay, float maxRaycastDistance, UnityEngine.Vector3 overlapPosition, float overlapRadius) { LayerMask interactable = LayerIndex.CommonMasks.interactable; if (Physics.Raycast(raycastRay, out var hitInfo, maxRaycastDistance, interactable, QueryTriggerInteraction.Collide) && EntityLocator.HasEntityLocator(hitInfo.collider.gameObject, out var foundLocator)) { GameObject entity = foundLocator.entity; IInteractable component = entity.GetComponent(); if (component != null && ((MonoBehaviour)component).isActiveAndEnabled && component.GetInteractability(this) != 0) { entity.GetComponent()?.SetInspectInfoProvider(foundLocator.EntityZoneIndex); return entity; } } Collider[] colliders; int num = HGPhysics.OverlapSphere(out colliders, overlapPosition, overlapRadius, interactable, QueryTriggerInteraction.Collide); GameObject gameObject = null; EntityLocator entityLocator = null; float num2 = 0f; for (int i = 0; i < num; i++) { Collider collider = colliders[i]; if (!EntityLocator.HasEntityLocator(collider.gameObject, out var foundLocator2)) { continue; } GameObject entity2 = foundLocator2.entity; IInteractable component2 = entity2.GetComponent(); if (component2 != null && ((MonoBehaviour)component2).isActiveAndEnabled && component2.GetInteractability(this) != 0 && !component2.ShouldIgnoreSpherecastForInteractibility(this)) { float num3 = UnityEngine.Vector3.Dot((collider.transform.position - overlapPosition).normalized, raycastRay.direction); if (num3 > num2) { num2 = num3; gameObject = entity2.gameObject; entityLocator = foundLocator2; } } } HGPhysics.ReturnResults(colliders); if ((bool)gameObject) { gameObject.GetComponent()?.SetInspectInfoProvider(entityLocator.EntityZoneIndex); } return gameObject; } [Command] public void CmdInteract(GameObject interactableObject) { PerformInteraction(interactableObject); } [Server] private void PerformInteraction(GameObject interactableObject) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Interactor::PerformInteraction(UnityEngine.GameObject)' called on client"); } else { if (!interactableObject) { return; } bool flag = false; bool anyInteractionSucceeded = false; IInteractable[] components = interactableObject.GetComponents(); foreach (IInteractable interactable in components) { Interactability interactability = interactable.GetInteractability(this); if (interactability == Interactability.Available) { interactable.OnInteractionBegin(this); GlobalEventManager.instance.OnInteractionBegin(this, interactable, interactableObject); anyInteractionSucceeded = true; } flag = flag || interactability != Interactability.Disabled; } if (flag) { CallRpcInteractionResult(anyInteractionSucceeded); } } } [ClientRpc] private void RpcInteractionResult(bool anyInteractionSucceeded) { if (!anyInteractionSucceeded && CameraRigController.IsObjectSpectatedByAnyCamera(base.gameObject)) { Util.PlaySound("Play_UI_insufficient_funds", RoR2Application.instance.gameObject); } } public void AttemptInteraction(GameObject interactableObject) { if (NetworkServer.active) { PerformInteraction(interactableObject); } else { CallCmdInteract(interactableObject); } } private void UNetVersion() { } protected static void InvokeCmdCmdInteract(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdInteract called on client."); } else { ((Interactor)obj).CmdInteract(reader.ReadGameObject()); } } public void CallCmdInteract(GameObject interactableObject) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdInteract called on server."); return; } if (base.isServer) { CmdInteract(interactableObject); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdInteract); networkWriter.Write(GetComponent().netId); networkWriter.Write(interactableObject); SendCommandInternal(networkWriter, 0, "CmdInteract"); } protected static void InvokeRpcRpcInteractionResult(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcInteractionResult called on server."); } else { ((Interactor)obj).RpcInteractionResult(reader.ReadBoolean()); } } public void CallRpcInteractionResult(bool anyInteractionSucceeded) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcInteractionResult called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcInteractionResult); networkWriter.Write(GetComponent().netId); networkWriter.Write(anyInteractionSucceeded); SendRPCInternal(networkWriter, 0, "RpcInteractionResult"); } static Interactor() { kCmdCmdInteract = 591229007; NetworkBehaviour.RegisterCommandDelegate(typeof(Interactor), kCmdCmdInteract, InvokeCmdCmdInteract); kRpcRpcInteractionResult = 804118976; NetworkBehaviour.RegisterRpcDelegate(typeof(Interactor), kRpcRpcInteractionResult, InvokeRpcRpcInteractionResult); NetworkCRC.RegisterBehaviour("Interactor", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class IntroCutsceneController : MonoBehaviour { private static BoolConVar cvIntroSkip = new BoolConVar("intro_skip", ConVarFlags.Archive, "0", "Whether or not to skip the opening cutscene."); private static bool _shouldSkip = false; private static bool skipRequested = false; public static bool shouldSkip { get { if (!_shouldSkip) { return cvIntroSkip.value; } return true; } set { if (value != _shouldSkip) { _shouldSkip = value; if (_shouldSkip) { IntroCutsceneController.onShouldSkipEnabled?.Invoke(); } } } } private static event Action onShouldSkipEnabled; public void Start() { RoR2Application.instance.PushThreadPriority(UnityEngine.ThreadPriority.Normal); onShouldSkipEnabled += delegate { if (RoR2Application.loadFinished) { Finish(); } else { RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(Finish)); } }; } public void Finish() { RoR2Application.instance.PopThreadPriority(); if (!skipRequested) { if (RoR2Application.loadFinished) { TransitionToTitle(); } else { RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(TransitionToTitle)); } } } public void TransitionToTitle() { Console.instance.SubmitCmd(null, "set_scene title"); skipRequested = true; } } public class Inventory : NetworkBehaviour { private int[] itemStacks = ItemCatalog.RequestItemStackArray(); public readonly List itemAcquisitionOrder = new List(); private const uint itemListDirtyBit = 1u; private const uint infusionBonusDirtyBit = 4u; private const uint itemAcquisitionOrderDirtyBit = 8u; private const uint equipmentDirtyBit = 16u; private const uint allDirtyBits = 29u; private EquipmentState[] equipmentStateSlots = Array.Empty(); private bool equipmentDisabled; [HideInInspector] public float beadAppliedHealth; [HideInInspector] public float beadAppliedShield; [HideInInspector] public float beadAppliedRegen; [HideInInspector] public float beadAppliedDamage; public static readonly Func defaultItemCopyFilterDelegate; private static int kRpcRpcItemAdded; private static int kRpcRpcClientEquipmentChanged; public EquipmentIndex currentEquipmentIndex => currentEquipmentState.equipmentIndex; public EquipmentState currentEquipmentState => GetEquipment(activeEquipmentSlot); public EquipmentIndex alternateEquipmentIndex => alternateEquipmentState.equipmentIndex; public EquipmentState alternateEquipmentState { get { for (uint num = 0u; num < GetEquipmentSlotCount(); num++) { if (num != activeEquipmentSlot) { return GetEquipment(num); } } return EquipmentState.empty; } } public byte activeEquipmentSlot { get; private set; } public uint infusionBonus { get; private set; } private bool spawnedOverNetwork => base.isServer; public event Action onInventoryChanged; public event Action onEquipmentExternalRestockServer; public static event Action onInventoryChangedGlobal; public static event Action onServerItemGiven; public event Action onItemAddedClient; public event Action onEquipmentChangedClient; private bool SetEquipmentInternal(EquipmentState equipmentState, uint slot) { if (!Run.instance || Run.instance.IsEquipmentExpansionLocked(equipmentState.equipmentIndex)) { return false; } if (equipmentStateSlots.Length <= slot) { int num = equipmentStateSlots.Length; Array.Resize(ref equipmentStateSlots, (int)(slot + 1)); for (int i = num; i < equipmentStateSlots.Length; i++) { equipmentStateSlots[i] = EquipmentState.empty; } } if (equipmentStateSlots[slot].Equals(equipmentState)) { return false; } equipmentStateSlots[slot] = equipmentState; return true; } [Server] public void SetEquipment(EquipmentState equipmentState, uint slot) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetEquipment(RoR2.EquipmentState,System.UInt32)' called on client"); } else if (SetEquipmentInternal(equipmentState, slot)) { if (NetworkServer.active) { SetDirtyBit(16u); } HandleInventoryChanged(); if (spawnedOverNetwork) { CallRpcClientEquipmentChanged(equipmentState.equipmentIndex, slot); } } } public EquipmentState GetEquipment(uint slot) { if (slot >= equipmentStateSlots.Length) { return EquipmentState.empty; } return equipmentStateSlots[slot]; } [Server] public void SetActiveEquipmentSlot(byte slotIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetActiveEquipmentSlot(System.Byte)' called on client"); return; } activeEquipmentSlot = slotIndex; SetDirtyBit(16u); HandleInventoryChanged(); } [Server] public void SetEquipmentDisabled(bool _active) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetEquipmentDisabled(System.Boolean)' called on client"); return; } equipmentDisabled = _active; SetDirtyBit(16u); HandleInventoryChanged(); } public bool GetEquipmentDisabled() { return equipmentDisabled; } public int GetEquipmentSlotCount() { return equipmentStateSlots.Length; } [Server] public void SetEquipmentIndex(EquipmentIndex newEquipmentIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetEquipmentIndex(RoR2.EquipmentIndex)' called on client"); } else { SetEquipmentIndexForSlot(newEquipmentIndex, activeEquipmentSlot); } } [Server] public void SetEquipmentIndexForSlot(EquipmentIndex newEquipmentIndex, uint slot) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetEquipmentIndexForSlot(RoR2.EquipmentIndex,System.UInt32)' called on client"); } else { if (Run.instance.IsEquipmentExpansionLocked(newEquipmentIndex)) { return; } EquipmentState equipment = GetEquipment(slot); if (equipment.equipmentIndex != newEquipmentIndex) { byte charges = equipment.charges; Run.FixedTimeStamp chargeFinishTime = equipment.chargeFinishTime; if (equipment.equipmentIndex == EquipmentIndex.None && chargeFinishTime.isNegativeInfinity) { charges = 1; chargeFinishTime = Run.FixedTimeStamp.now; } EquipmentState equipmentState = new EquipmentState(newEquipmentIndex, chargeFinishTime, charges); SetEquipment(equipmentState, slot); } } } public EquipmentIndex GetEquipmentIndex() { return currentEquipmentIndex; } [Server] public void DeductEquipmentCharges(byte slot, int deduction) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::DeductEquipmentCharges(System.Byte,System.Int32)' called on client"); return; } EquipmentState equipment = GetEquipment(slot); byte charges = equipment.charges; Run.FixedTimeStamp chargeFinishTime = equipment.chargeFinishTime; charges = (byte)((charges >= deduction) ? ((byte)(charges - (byte)deduction)) : 0); SetEquipment(new EquipmentState(equipment.equipmentIndex, chargeFinishTime, charges), slot); UpdateEquipment(); } public int GetEquipmentRestockableChargeCount(byte slot) { EquipmentState equipment = GetEquipment(slot); if (equipment.equipmentIndex == EquipmentIndex.None) { return 0; } return HGMath.ByteSafeSubtract((byte)GetEquipmentSlotMaxCharges(slot), equipment.charges); } [Server] public void RestockEquipmentCharges(byte slot, int amount) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::RestockEquipmentCharges(System.Byte,System.Int32)' called on client"); return; } amount = Math.Min(amount, GetEquipmentRestockableChargeCount(slot)); if (amount > 0) { EquipmentState equipment = GetEquipment(slot); byte charges = HGMath.ByteSafeAdd(equipment.charges, (byte)Math.Min(amount, 255)); SetEquipment(new EquipmentState(equipment.equipmentIndex, equipment.chargeFinishTime, charges), slot); this.onEquipmentExternalRestockServer?.Invoke(); } } [Server] public void DeductActiveEquipmentCooldown(float seconds) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::DeductActiveEquipmentCooldown(System.Single)' called on client"); return; } EquipmentState equipment = GetEquipment(activeEquipmentSlot); SetEquipment(new EquipmentState(equipment.equipmentIndex, equipment.chargeFinishTime - seconds, equipment.charges), activeEquipmentSlot); } public int GetEquipmentSlotMaxCharges(byte slot) { return Math.Min(1 + GetItemCount(RoR2Content.Items.EquipmentMagazine), 255); } public int GetActiveEquipmentMaxCharges() { return GetEquipmentSlotMaxCharges(activeEquipmentSlot); } [Server] private void UpdateEquipment() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::UpdateEquipment()' called on client"); return; } Run.FixedTimeStamp now = Run.FixedTimeStamp.now; byte b = (byte)Mathf.Min(1 + GetItemCount(RoR2Content.Items.EquipmentMagazine), 255); for (uint num = 0u; num < equipmentStateSlots.Length; num++) { EquipmentState equipmentState = equipmentStateSlots[num]; if (equipmentState.equipmentIndex == EquipmentIndex.None) { continue; } if (equipmentState.charges < b) { Run.FixedTimeStamp fixedTimeStamp = equipmentState.chargeFinishTime; byte b2 = equipmentState.charges; if (!fixedTimeStamp.isPositiveInfinity) { b2++; } if (fixedTimeStamp.isInfinity) { fixedTimeStamp = now; } if (fixedTimeStamp.hasPassed) { float num2 = equipmentState.equipmentDef.cooldown * CalculateEquipmentCooldownScale(); SetEquipment(new EquipmentState(equipmentState.equipmentIndex, fixedTimeStamp + num2, b2), num); } } if (equipmentState.charges >= b && !equipmentState.chargeFinishTime.isPositiveInfinity) { SetEquipment(new EquipmentState(equipmentState.equipmentIndex, Run.FixedTimeStamp.positiveInfinity, b), num); } } } private float CalculateEquipmentCooldownScale() { int itemCount = GetItemCount(RoR2Content.Items.EquipmentMagazine); int itemCount2 = GetItemCount(RoR2Content.Items.AutoCastEquipment); int itemCount3 = GetItemCount(RoR2Content.Items.BoostEquipmentRecharge); float num = Mathf.Pow(0.85f, itemCount); if (itemCount2 > 0) { num *= 0.5f * Mathf.Pow(0.85f, itemCount2 - 1); } if (itemCount3 > 0) { num *= Mathf.Pow(0.9f, itemCount3); } return num; } private void HandleInventoryChanged() { this.onInventoryChanged?.Invoke(); Inventory.onInventoryChangedGlobal?.Invoke(this); } private void FixedUpdate() { MyFixedUpdate(Time.deltaTime); } private void MyFixedUpdate(float deltaTime) { if (NetworkServer.active) { UpdateEquipment(); } } [Server] public void AddInfusionBonus(uint value) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddInfusionBonus(System.UInt32)' called on client"); } else if (value != 0) { infusionBonus += value; SetDirtyBit(4u); HandleInventoryChanged(); } } [Server] public void GiveItemString(string itemString) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveItemString(System.String)' called on client"); } else { GiveItem(ItemCatalog.FindItemIndex(itemString)); } } [Server] public void GiveItemString(string itemString, int count) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveItemString(System.String,System.Int32)' called on client"); } else { GiveItem(ItemCatalog.FindItemIndex(itemString), count); } } [Server] public void GiveEquipmentString(string equipmentString) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveEquipmentString(System.String)' called on client"); } else { SetEquipmentIndex(EquipmentCatalog.FindEquipmentIndex(equipmentString)); } } [Server] public void GiveRandomItems(int count, bool lunarEnabled, bool voidEnabled) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveRandomItems(System.Int32,System.Boolean,System.Boolean)' called on client"); return; } try { if (count > 0) { WeightedSelection> weightedSelection = new WeightedSelection>(); weightedSelection.AddChoice(Run.instance.availableTier1DropList, 100f); weightedSelection.AddChoice(Run.instance.availableTier2DropList, 60f); weightedSelection.AddChoice(Run.instance.availableTier3DropList, 4f); if (lunarEnabled) { weightedSelection.AddChoice(Run.instance.availableLunarItemDropList, 4f); } if (voidEnabled) { weightedSelection.AddChoice(Run.instance.availableVoidTier1DropList, 4f); weightedSelection.AddChoice(Run.instance.availableVoidTier1DropList, 2.3999999f); weightedSelection.AddChoice(Run.instance.availableVoidTier1DropList, 0.16f); } for (int i = 0; i < count; i++) { List list = weightedSelection.Evaluate(UnityEngine.Random.value); GiveItem(PickupCatalog.GetPickupDef(list[UnityEngine.Random.Range(0, list.Count)])?.itemIndex ?? ItemIndex.None); } } } catch (ArgumentException) { } } [Server] public void GiveRandomEquipment() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveRandomEquipment()' called on client"); return; } PickupIndex pickupIndex = Run.instance.availableEquipmentDropList[UnityEngine.Random.Range(0, Run.instance.availableEquipmentDropList.Count)]; SetEquipmentIndex(PickupCatalog.GetPickupDef(pickupIndex)?.equipmentIndex ?? EquipmentIndex.None); } [Server] public void GiveRandomEquipment(Xoroshiro128Plus rng) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveRandomEquipment(Xoroshiro128Plus)' called on client"); return; } PickupIndex pickupIndex = rng.NextElementUniform(Run.instance.availableEquipmentDropList); SetEquipmentIndex(PickupCatalog.GetPickupDef(pickupIndex)?.equipmentIndex ?? EquipmentIndex.None); } [Server] public void GiveItem(ItemIndex itemIndex, int count = 1) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveItem(RoR2.ItemIndex,System.Int32)' called on client"); } else { if (((bool)Run.instance && Run.instance.IsItemExpansionLocked(itemIndex)) || (uint)itemIndex >= itemStacks.Length || itemIndex == ItemIndex.None) { return; } if (count <= 0) { if (count < 0) { RemoveItem(itemIndex, -count); } return; } SetDirtyBit(1u); if ((itemStacks[(int)itemIndex] += count) == count) { itemAcquisitionOrder.Add(itemIndex); SetDirtyBit(8u); } HandleInventoryChanged(); Inventory.onServerItemGiven?.Invoke(this, itemIndex, count); if (spawnedOverNetwork) { CallRpcItemAdded(itemIndex); } } } [Server] public void GiveItem(ItemDef itemDef, int count = 1) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveItem(RoR2.ItemDef,System.Int32)' called on client"); } else { GiveItem(itemDef?.itemIndex ?? ItemIndex.None, count); } } [ClientRpc] private void RpcItemAdded(ItemIndex itemIndex) { this.onItemAddedClient?.Invoke(itemIndex); } [ClientRpc] private void RpcClientEquipmentChanged(EquipmentIndex newEquipIndex, uint slot) { this.onEquipmentChangedClient?.Invoke(newEquipIndex, slot); } [Server] public void RemoveItem(ItemIndex itemIndex, int count = 1) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::RemoveItem(RoR2.ItemIndex,System.Int32)' called on client"); } else { if ((uint)itemIndex >= itemStacks.Length) { return; } if (count <= 0) { if (count < 0) { GiveItem(itemIndex, -count); } return; } int num = itemStacks[(int)itemIndex]; count = Math.Min(count, num); if (count != 0) { if ((itemStacks[(int)itemIndex] = num - count) == 0) { itemAcquisitionOrder.Remove(itemIndex); SetDirtyBit(8u); } SetDirtyBit(1u); HandleInventoryChanged(); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Server] public void RemoveItem(ItemDef itemDef, int count = 1) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::RemoveItem(RoR2.ItemDef,System.Int32)' called on client"); } else { RemoveItem(itemDef?.itemIndex ?? ItemIndex.None, count); } } [Server] public void ResetItem(ItemIndex itemIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::ResetItem(RoR2.ItemIndex)' called on client"); } else if ((uint)itemIndex < itemStacks.Length) { ref int reference = ref itemStacks[(int)itemIndex]; if (reference > 0) { reference = 0; SetDirtyBit(1u); SetDirtyBit(8u); HandleInventoryChanged(); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Server] public void ResetItem(ItemDef itemDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::ResetItem(RoR2.ItemDef)' called on client"); } else { ResetItem(itemDef?.itemIndex ?? ItemIndex.None); } } [Server] public void CopyEquipmentFrom(Inventory other) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::CopyEquipmentFrom(RoR2.Inventory)' called on client"); return; } for (int i = 0; i < other.equipmentStateSlots.Length; i++) { SetEquipment(new EquipmentState(other.equipmentStateSlots[i].equipmentIndex, Run.FixedTimeStamp.negativeInfinity, 1), (uint)i); } } private static bool DefaultItemCopyFilter(ItemIndex itemIndex) { return !ItemCatalog.GetItemDef(itemIndex).ContainsTag(ItemTag.CannotCopy); } [Server] public void AddItemsFrom([NotNull] Inventory other) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddItemsFrom(RoR2.Inventory)' called on client"); } else { AddItemsFrom(other, defaultItemCopyFilterDelegate); } } [Server] public void AddItemsFrom([NotNull] Inventory other, [NotNull] Func filter) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddItemsFrom(RoR2.Inventory,System.Func`2)' called on client"); } else { AddItemsFrom(other.itemStacks, filter); } } [Server] public void AddItemsFrom([NotNull] int[] otherItemStacks, [NotNull] Func filter) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddItemsFrom(System.Int32[],System.Func`2)' called on client"); return; } for (ItemIndex itemIndex = ItemIndex.Count; (int)itemIndex < itemStacks.Length; itemIndex++) { int num = otherItemStacks[(int)itemIndex]; if (num > 0 && filter(itemIndex)) { ref int reference = ref itemStacks[(int)itemIndex]; if (reference == 0) { itemAcquisitionOrder.Add(itemIndex); } reference += num; } } SetDirtyBit(1u); SetDirtyBit(8u); HandleInventoryChanged(); } [Server] private void AddItemAcquisitionOrderFrom([NotNull] List otherItemAcquisitionOrder) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddItemAcquisitionOrderFrom(System.Collections.Generic.List`1)' called on client"); return; } int[] array = ItemCatalog.RequestItemStackArray(); for (int i = 0; i < itemAcquisitionOrder.Count; i++) { ItemIndex itemIndex = itemAcquisitionOrder[i]; array[(int)itemIndex] = 1; } int j = 0; for (int count = otherItemAcquisitionOrder.Count; j < count; j++) { ItemIndex itemIndex2 = otherItemAcquisitionOrder[j]; ref int reference = ref array[(int)itemIndex2]; if (reference == 0) { reference = 1; itemAcquisitionOrder.Add(itemIndex2); } } ItemCatalog.ReturnItemStackArray(array); } [Server] public void CopyItemsFrom([NotNull] Inventory other) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::CopyItemsFrom(RoR2.Inventory)' called on client"); } else { CopyItemsFrom(other, defaultItemCopyFilterDelegate); } } [Server] public void CopyItemsFrom([NotNull] Inventory other, [NotNull] Func filter) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::CopyItemsFrom(RoR2.Inventory,System.Func`2)' called on client"); return; } itemAcquisitionOrder.Clear(); int[] array = itemStacks; int value = 0; ArrayUtils.SetAll(array, in value); AddItemsFrom(other); } [Server] public void CleanInventory() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::CleanInventory()' called on client"); return; } itemAcquisitionOrder.Clear(); itemStacks = ItemCatalog.RequestItemStackArray(); SetDirtyBit(8u); SetDirtyBit(1u); HandleInventoryChanged(); } [Server] public void ShrineRestackInventory([NotNull] Xoroshiro128Plus rng) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::ShrineRestackInventory(Xoroshiro128Plus)' called on client"); return; } List list = new List(); bool flag = false; foreach (ItemTierDef allItemTierDef in ItemTierCatalog.allItemTierDefs) { if (!allItemTierDef.canRestack) { continue; } int num = 0; list.Clear(); for (int i = 0; i < itemStacks.Length; i++) { if (itemStacks[i] > 0) { ItemIndex itemIndex = (ItemIndex)i; ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); if (allItemTierDef.tier == itemDef.tier) { num += itemStacks[i]; list.Add(itemIndex); itemAcquisitionOrder.Remove(itemIndex); ResetItem(itemIndex); } } } if (list.Count > 0) { GiveItem(rng.NextElementUniform(list), num); flag = true; } } if (flag) { SetDirtyBit(8u); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int GetItemCount(ItemIndex itemIndex) { return ArrayUtils.GetSafe(itemStacks, (int)itemIndex); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int GetItemCount(ItemDef itemDef) { return GetItemCount(itemDef?.itemIndex ?? ItemIndex.None); } public bool HasAtLeastXTotalItemsOfTier(ItemTier itemTier, int x) { int num = 0; ItemIndex itemIndex = ItemIndex.Count; for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++) { if (ItemCatalog.GetItemDef(itemIndex).tier == itemTier) { num += GetItemCount(itemIndex); if (num >= x) { return true; } } } return false; } public int GetTotalItemCountOfTier(ItemTier itemTier) { int num = 0; ItemIndex itemIndex = ItemIndex.Count; for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++) { if (ItemCatalog.GetItemDef(itemIndex).tier == itemTier) { num += GetItemCount(itemIndex); } } return num; } public void WriteItemStacks(int[] output) { Array.Copy(itemStacks, output, output.Length); } public override int GetNetworkChannel() { return QosChannelIndex.defaultReliable.intVal; } public override void OnDeserialize(NetworkReader reader, bool initialState) { byte num = reader.ReadByte(); bool flag = (num & 1) != 0; bool flag2 = (num & 4) != 0; bool flag3 = (num & 8) != 0; bool flag4 = (num & 0x10) != 0; if (flag) { reader.ReadItemStacks(itemStacks); } if (flag2) { infusionBonus = reader.ReadPackedUInt32(); } if (flag3) { uint num2 = reader.ReadPackedUInt32(); itemAcquisitionOrder.Clear(); itemAcquisitionOrder.Capacity = (int)num2; for (uint num3 = 0u; num3 < num2; num3++) { ItemIndex item = (ItemIndex)reader.ReadPackedUInt32(); itemAcquisitionOrder.Add(item); } } if (flag4) { equipmentDisabled = reader.ReadBoolean(); uint num4 = reader.ReadByte(); for (uint num5 = 0u; num5 < num4; num5++) { SetEquipmentInternal(EquipmentState.Deserialize(reader), num5); } activeEquipmentSlot = reader.ReadByte(); } if (flag || flag4 || flag2) { HandleInventoryChanged(); } } public override bool OnSerialize(NetworkWriter writer, bool initialState) { uint num = base.syncVarDirtyBits; if (initialState) { num = 29u; } for (int i = 0; i < equipmentStateSlots.Length; i++) { if (equipmentStateSlots[i].dirty) { num |= 0x10u; break; } } bool num2 = (num & 1) != 0; bool flag = (num & 4) != 0; bool flag2 = (num & 8) != 0; bool flag3 = (num & 0x10) != 0; writer.Write((byte)num); if (num2) { writer.WriteItemStacks(itemStacks); } if (flag) { writer.WritePackedUInt32(infusionBonus); } if (flag2) { int count = itemAcquisitionOrder.Count; writer.WritePackedUInt32((uint)count); for (int j = 0; j < count; j++) { writer.WritePackedUInt32((uint)itemAcquisitionOrder[j]); } } if (flag3) { writer.Write(equipmentDisabled); writer.Write((byte)equipmentStateSlots.Length); for (int k = 0; k < equipmentStateSlots.Length; k++) { EquipmentState.Serialize(writer, equipmentStateSlots[k]); } writer.Write(activeEquipmentSlot); } if (!initialState) { for (int l = 0; l < equipmentStateSlots.Length; l++) { equipmentStateSlots[l].dirty = false; } } if (!initialState) { return num != 0; } return false; } static Inventory() { defaultItemCopyFilterDelegate = DefaultItemCopyFilter; kRpcRpcItemAdded = 1978705787; NetworkBehaviour.RegisterRpcDelegate(typeof(Inventory), kRpcRpcItemAdded, InvokeRpcRpcItemAdded); kRpcRpcClientEquipmentChanged = 1435548707; NetworkBehaviour.RegisterRpcDelegate(typeof(Inventory), kRpcRpcClientEquipmentChanged, InvokeRpcRpcClientEquipmentChanged); NetworkCRC.RegisterBehaviour("Inventory", 0); } private void UNetVersion() { } protected static void InvokeRpcRpcItemAdded(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcItemAdded called on server."); } else { ((Inventory)obj).RpcItemAdded((ItemIndex)reader.ReadInt32()); } } protected static void InvokeRpcRpcClientEquipmentChanged(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcClientEquipmentChanged called on server."); } else { ((Inventory)obj).RpcClientEquipmentChanged((EquipmentIndex)reader.ReadInt32(), reader.ReadPackedUInt32()); } } public void CallRpcItemAdded(ItemIndex itemIndex) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcItemAdded called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcItemAdded); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)itemIndex); SendRPCInternal(networkWriter, 0, "RpcItemAdded"); } public void CallRpcClientEquipmentChanged(EquipmentIndex newEquipIndex, uint slot) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcClientEquipmentChanged called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcClientEquipmentChanged); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)newEquipIndex); networkWriter.WritePackedUInt32(slot); SendRPCInternal(networkWriter, 0, "RpcClientEquipmentChanged"); } public override void PreStartClient() { } } public struct EquipmentState : IEquatable { public readonly EquipmentIndex equipmentIndex; public readonly Run.FixedTimeStamp chargeFinishTime; public readonly byte charges; public bool isDisabled; public bool dirty; [CanBeNull] public readonly EquipmentDef equipmentDef; public static readonly EquipmentState empty = new EquipmentState(EquipmentIndex.None, Run.FixedTimeStamp.negativeInfinity, 0); public bool isPerfomingRecharge => !chargeFinishTime.isPositiveInfinity; public EquipmentState(EquipmentIndex equipmentIndex, Run.FixedTimeStamp chargeFinishTime, byte charges, bool isDisabled = false) { this.equipmentIndex = equipmentIndex; this.chargeFinishTime = chargeFinishTime; this.charges = charges; this.isDisabled = isDisabled; dirty = true; equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); } public bool Equals(EquipmentState other) { if (equipmentIndex == other.equipmentIndex && chargeFinishTime.Equals(other.chargeFinishTime)) { return charges == other.charges; } return false; } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is EquipmentState) { return Equals((EquipmentState)obj); } return false; } public override int GetHashCode() { return ((int)equipmentIndex * 397) ^ chargeFinishTime.GetHashCode(); } public static EquipmentState Deserialize(NetworkReader reader) { EquipmentIndex num = reader.ReadEquipmentIndex(); Run.FixedTimeStamp fixedTimeStamp = reader.ReadFixedTimeStamp(); byte b = reader.ReadByte(); return new EquipmentState(num, fixedTimeStamp, b); } public static void Serialize(NetworkWriter writer, EquipmentState equipmentState) { writer.Write(equipmentState.equipmentIndex); writer.Write(equipmentState.chargeFinishTime); writer.Write(equipmentState.charges); } } public interface IPainAnimationHandler { void HandlePain(float damage, UnityEngine.Vector3 position); } public interface IPhysMotor { float mass { get; } UnityEngine.Vector3 velocity { get; } UnityEngine.Vector3 velocityAuthority { get; set; } void ApplyForceImpulse(in PhysForceInfo physForceInfo); } public interface ITeleportHandler : IEventSystemHandler { void OnTeleport(UnityEngine.Vector3 oldPosition, UnityEngine.Vector3 newPosition); } public class AffixAurelioniteBehavior : CharacterBody.ItemBehavior { private float timer; private float duration = 20f; private float durationModifier = 5f; public int goldTransfer = 25; private void Start() { if (NetworkServer.active) { goldTransfer = Run.instance.GetDifficultyScaledCost(goldTransfer); } timer = UnityEngine.Random.Range(5f, 15f); } private void Update() { if (NetworkServer.active) { timer -= Time.deltaTime; if (timer <= 0f && stack > 0) { timer = duration; AurelioniteBlessing(); } } } private void AurelioniteBlessing() { body.AddTimedBuff(DLC2Content.Buffs.AurelioniteBlessing, 5f); } private void OnDisable() { if (body.HasBuff(DLC2Content.Buffs.AurelioniteBlessing)) { body.RemoveBuff(DLC2Content.Buffs.AurelioniteBlessing); } } } public class AffixBeadBehavior : CharacterBody.ItemBehavior { private GameObject affixBeadWard; public GameObject affixBeadWardReference; private GameObject beadHolderVFX; public GameObject beadHolderVFXReference; private void Update() { if (!NetworkServer.active) { return; } bool flag = stack > 0; if ((bool)affixBeadWard != flag) { if (flag) { affixBeadWard = UnityEngine.Object.Instantiate(affixBeadWardReference); affixBeadWard.GetComponent().teamIndex = body.teamComponent.teamIndex; affixBeadWard.GetComponent().Networkradius = 30f + body.radius; affixBeadWard.GetComponent().AttachToGameObjectAndSpawn(body.gameObject); beadHolderVFX = UnityEngine.Object.Instantiate(beadHolderVFXReference); beadHolderVFX.GetComponent().AttachToGameObjectAndSpawn(body.gameObject, "Head"); beadHolderVFX.transform.localScale *= body.modelLocator.modelScaleCompensation; } else { UnityEngine.Object.Destroy(affixBeadWard); affixBeadWard = null; UnityEngine.Object.Destroy(beadHolderVFX); beadHolderVFX = null; } } } private void OnEnable() { beadHolderVFXReference = Addressables.LoadAssetAsync("RoR2/DLC2/Elites/EliteBead/EliteBeadFire.prefab").WaitForCompletion(); affixBeadWardReference = Addressables.LoadAssetAsync("RoR2/DLC2/Elites/EliteBead/AffixBeadWard.prefab").WaitForCompletion(); } private void OnDisable() { if ((bool)affixBeadWard) { UnityEngine.Object.Destroy(affixBeadWard); } if ((bool)beadHolderVFX) { UnityEngine.Object.Destroy(beadHolderVFX); } } } public class AffixEarthBehavior : CharacterBody.ItemBehavior { private const float baseOrbitDegreesPerSecond = 90f; private const float baseOrbitRadius = 3f; private const string projectilePath = "Prefabs/Projectiles/AffixEarthProjectile"; private GameObject affixEarthAttachment; private GameObject projectilePrefab; private int maxProjectiles; private static GameObject attachmentPrefab; [InitDuringStartup] private static void Init() { AsyncOperationHandle asyncOperationHandle = Addressables.LoadAssetAsync("112bf5913df2135478a9785e0bc18477"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { attachmentPrefab = x.Result; }; } private void Start() { } private void FixedUpdate() { if (!NetworkServer.active) { return; } bool flag = stack > 0; if ((bool)affixEarthAttachment != flag) { if (flag) { affixEarthAttachment = UnityEngine.Object.Instantiate(attachmentPrefab); affixEarthAttachment.GetComponent().AttachToGameObjectAndSpawn(body.gameObject); } else { UnityEngine.Object.Destroy(affixEarthAttachment); affixEarthAttachment = null; } } } private void OnDisable() { if ((bool)affixEarthAttachment) { UnityEngine.Object.Destroy(affixEarthAttachment); } } } public class AffixVoidBehavior : CharacterBody.ItemBehavior { private const string sdStateMachineName = "Weapon"; private bool wasVoidBody; private EntityStateMachine sdStateMachine; private HealthComponent healthComponent; private bool hasEffectiveAuthority; private bool hasBegunSelfDestruct; private void Awake() { base.enabled = false; sdStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Weapon"); healthComponent = GetComponent(); hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject); hasBegunSelfDestruct = false; } private void OnEnable() { if ((bool)body) { wasVoidBody = (body.bodyFlags & CharacterBody.BodyFlags.Void) != 0; body.bodyFlags |= CharacterBody.BodyFlags.Void; } } private void OnDisable() { if ((bool)body) { if (body.HasBuff(DLC1Content.Buffs.BearVoidReady)) { body.RemoveBuff(DLC1Content.Buffs.BearVoidReady); } if (body.HasBuff(DLC1Content.Buffs.BearVoidCooldown)) { body.RemoveBuff(DLC1Content.Buffs.BearVoidCooldown); } if (!wasVoidBody) { body.bodyFlags &= ~CharacterBody.BodyFlags.Void; } } } private void FixedUpdate() { if (NetworkServer.active && (bool)body && !body.HasBuff(DLC1Content.Buffs.BearVoidReady) && !body.HasBuff(DLC1Content.Buffs.BearVoidCooldown)) { body.AddBuff(DLC1Content.Buffs.BearVoidReady); } } } public class BearVoidBehavior : CharacterBody.ItemBehavior { private void Awake() { base.enabled = false; } private void OnEnable() { } private void OnDisable() { if ((bool)body) { if (body.HasBuff(DLC1Content.Buffs.BearVoidReady)) { body.RemoveBuff(DLC1Content.Buffs.BearVoidReady); } if (body.HasBuff(DLC1Content.Buffs.BearVoidCooldown)) { body.RemoveBuff(DLC1Content.Buffs.BearVoidCooldown); } } } private void FixedUpdate() { if ((bool)body && !body.HasBuff(DLC1Content.Buffs.BearVoidReady) && !body.HasBuff(DLC1Content.Buffs.BearVoidCooldown)) { body.AddBuff(DLC1Content.Buffs.BearVoidReady); } } } public class DroneWeaponsBehavior : CharacterBody.ItemBehavior { private const float display2Chance = 0.1f; private int previousStack; private CharacterSpawnCard droneSpawnCard; private Xoroshiro128Plus rng; private DirectorPlacementRule placementRule; private const float minSpawnDist = 3f; private const float maxSpawnDist = 40f; private const float spawnRetryDelay = 1f; private bool hasSpawnedDrone; private float spawnDelay; private void OnEnable() { ulong seed = Run.instance.seed ^ (ulong)Run.instance.stageClearCount; rng = new Xoroshiro128Plus(seed); droneSpawnCard = Addressables.LoadAssetAsync("RoR2/DLC1/DroneCommander/cscDroneCommander.asset").WaitForCompletion(); placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = 3f, maxDistance = 40f, spawnOnTarget = base.transform }; UpdateAllMinions(stack); MasterSummon.onServerMasterSummonGlobal += OnServerMasterSummonGlobal; } private void OnDisable() { MasterSummon.onServerMasterSummonGlobal -= OnServerMasterSummonGlobal; UpdateAllMinions(0); } private void FixedUpdate() { if (previousStack != stack) { UpdateAllMinions(stack); } spawnDelay -= Time.fixedDeltaTime; if (!hasSpawnedDrone && (bool)body && spawnDelay <= 0f) { TrySpawnDrone(); } } private void OnServerMasterSummonGlobal(MasterSummon.MasterSummonReport summonReport) { if (!body || !body.master || !(body.master == summonReport.leaderMasterInstance)) { return; } CharacterMaster summonMasterInstance = summonReport.summonMasterInstance; if ((bool)summonMasterInstance) { CharacterBody characterBody = summonMasterInstance.GetBody(); if ((bool)characterBody) { UpdateMinionInventory(summonMasterInstance.inventory, characterBody.bodyFlags, stack); } } } private void UpdateAllMinions(int newStack) { if (!body || !(body?.master)) { return; } MinionOwnership.MinionGroup minionGroup = MinionOwnership.MinionGroup.FindGroup(body.master.netId); if (minionGroup == null) { return; } MinionOwnership[] members = minionGroup.members; foreach (MinionOwnership minionOwnership in members) { if (!minionOwnership) { continue; } CharacterMaster component = minionOwnership.GetComponent(); if ((bool)component && (bool)component.inventory) { CharacterBody characterBody = component.GetBody(); if ((bool)characterBody) { UpdateMinionInventory(component.inventory, characterBody.bodyFlags, newStack); } } } previousStack = newStack; } private void UpdateMinionInventory(Inventory inventory, CharacterBody.BodyFlags bodyFlags, int newStack) { if (((bool)inventory && newStack > 0 && (bodyFlags & CharacterBody.BodyFlags.Mechanical) != 0) || (bodyFlags & CharacterBody.BodyFlags.Devotion) != 0) { int itemCount = inventory.GetItemCount(DLC1Content.Items.DroneWeaponsBoost); int itemCount2 = inventory.GetItemCount(DLC1Content.Items.DroneWeaponsDisplay1); int itemCount3 = inventory.GetItemCount(DLC1Content.Items.DroneWeaponsDisplay2); if (itemCount < stack) { inventory.GiveItem(DLC1Content.Items.DroneWeaponsBoost, stack - itemCount); } else if (itemCount > stack) { inventory.RemoveItem(DLC1Content.Items.DroneWeaponsBoost, itemCount - stack); } if (itemCount2 + itemCount3 <= 0) { ItemDef itemDef = DLC1Content.Items.DroneWeaponsDisplay1; if (UnityEngine.Random.value < 0.1f) { itemDef = DLC1Content.Items.DroneWeaponsDisplay2; } inventory.GiveItem(itemDef); } } else { inventory.ResetItem(DLC1Content.Items.DroneWeaponsBoost); inventory.ResetItem(DLC1Content.Items.DroneWeaponsDisplay1); inventory.ResetItem(DLC1Content.Items.DroneWeaponsDisplay2); } } private void TrySpawnDrone() { if (!body.master.IsDeployableLimited(DeployableSlot.DroneWeaponsDrone)) { spawnDelay = 1f; DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(droneSpawnCard, placementRule, rng); directorSpawnRequest.summonerBodyObject = base.gameObject; directorSpawnRequest.onSpawnedServer = OnMasterSpawned; DirectorCore.instance.TrySpawnObject(directorSpawnRequest); } } private void OnMasterSpawned(SpawnCard.SpawnResult spawnResult) { hasSpawnedDrone = true; GameObject spawnedInstance = spawnResult.spawnedInstance; if (!spawnedInstance) { return; } CharacterMaster component = spawnedInstance.GetComponent(); if ((bool)component) { Deployable component2 = component.GetComponent(); if ((bool)component2) { body.master.AddDeployable(component2, DeployableSlot.DroneWeaponsDrone); } } } } public class DroneWeaponsBoostBehavior : CharacterBody.ItemBehavior { private const string controllerPrefabPath = "Prefabs/NetworkedObjects/DroneWeaponsChainGunController"; private const string missileMuzzleChildName = "MissileMuzzle"; private const float microMissileDamageCoefficient = 3f; private const float microMissileProcCoefficient = 1f; private Transform missileMuzzleTransform; private GameObject chainGunController; public void Start() { GetComponent(); ModelLocator component = GetComponent(); if ((bool)component) { Transform modelTransform = component.modelTransform; if ((bool)modelTransform) { CharacterModel component2 = modelTransform.GetComponent(); if ((bool)component2) { List itemDisplayObjects = component2.GetItemDisplayObjects(DLC1Content.Items.DroneWeaponsDisplay1.itemIndex); itemDisplayObjects.AddRange(component2.GetItemDisplayObjects(DLC1Content.Items.DroneWeaponsDisplay2.itemIndex)); foreach (GameObject item in itemDisplayObjects) { ChildLocator component3 = item.GetComponent(); if ((bool)component3) { Transform transform = component3.FindChild("MissileMuzzle"); if ((bool)transform) { missileMuzzleTransform = transform; break; } } } } } } chainGunController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/DroneWeaponsChainGunController")); chainGunController.GetComponent().AttachToGameObjectAndSpawn(base.gameObject); } public void OnDestroy() { UnityEngine.Object.Destroy(chainGunController); } public void OnEnemyHit(DamageInfo damageInfo, CharacterBody victimBody) { CharacterBody component = damageInfo.attacker.GetComponent(); CharacterMaster characterMaster = component?.master; if ((bool)characterMaster && !damageInfo.procChainMask.HasProc(ProcType.MicroMissile) && Util.CheckRoll(10f, characterMaster)) { ProcChainMask procChainMask = damageInfo.procChainMask; procChainMask.AddProc(ProcType.MicroMissile); HurtBox hurtBox = victimBody.mainHurtBox; if ((bool)victimBody.hurtBoxGroup) { hurtBox = victimBody.hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, victimBody.hurtBoxGroup.hurtBoxes.Length)]; } if ((bool)hurtBox) { MicroMissileOrb microMissileOrb = new MicroMissileOrb(); microMissileOrb.damageValue = component.damage * 3f; microMissileOrb.isCrit = Util.CheckRoll(component.crit, characterMaster); microMissileOrb.teamIndex = TeamComponent.GetObjectTeam(component.gameObject); microMissileOrb.attacker = component.gameObject; microMissileOrb.procCoefficient = 1f; microMissileOrb.procChainMask = procChainMask; microMissileOrb.origin = (missileMuzzleTransform ? missileMuzzleTransform.position : component.corePosition); microMissileOrb.target = hurtBox; microMissileOrb.damageColorIndex = DamageColorIndex.Item; OrbManager.instance.AddOrb(microMissileOrb); } } } } public class ElementalRingVoidBehavior : CharacterBody.ItemBehavior { private void Awake() { base.enabled = false; } private void OnEnable() { } private void OnDisable() { if ((bool)body) { if (body.HasBuff(DLC1Content.Buffs.ElementalRingVoidReady)) { body.RemoveBuff(DLC1Content.Buffs.ElementalRingVoidReady); } if (body.HasBuff(DLC1Content.Buffs.ElementalRingVoidCooldown)) { body.RemoveBuff(DLC1Content.Buffs.ElementalRingVoidCooldown); } } } private void FixedUpdate() { if ((bool)body && !body.HasBuff(DLC1Content.Buffs.ElementalRingVoidReady) && !body.HasBuff(DLC1Content.Buffs.ElementalRingVoidCooldown)) { body.AddBuff(DLC1Content.Buffs.ElementalRingVoidReady); } } } public class LunarSunBehavior : CharacterBody.ItemBehavior { private const float secondsPerTransform = 60f; private const float secondsPerProjectile = 3f; private const string projectilePath = "Prefabs/Projectiles/LunarSunProjectile"; private const int baseMaxProjectiles = 2; private const int maxProjectilesPerStack = 1; private const float baseOrbitDegreesPerSecond = 180f; private const float orbitDegreesPerSecondFalloff = 0.9f; private const float baseOrbitRadius = 2f; private const float orbitRadiusPerStack = 0.25f; private const float maxInclinationDegrees = 0f; private const float baseDamageCoefficient = 3.6f; private float projectileTimer; private float transformTimer; private GameObject projectilePrefab; private Xoroshiro128Plus transformRng; public event Action onDisabled; public static int GetMaxProjectiles(Inventory inventory) { return 2 + inventory.GetItemCount(DLC1Content.Items.LunarSun); } public void InitializeOrbiter(ProjectileOwnerOrbiter orbiter, LunarSunProjectileController controller) { float num = body.radius + 2f + UnityEngine.Random.Range(0.25f, 0.25f * (float)stack); float num2 = num / 2f; num2 *= num2; float degreesPerSecond = 180f * Mathf.Pow(0.9f, num2); UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 360f), UnityEngine.Vector3.up); UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 0f), UnityEngine.Vector3.forward); UnityEngine.Vector3 planeNormal = quaternion * quaternion2 * UnityEngine.Vector3.up; float initialDegreesFromOwnerForward = UnityEngine.Random.Range(0f, 360f); orbiter.Initialize(planeNormal, num, degreesPerSecond, initialDegreesFromOwnerForward); onDisabled += DestroyOrbiter; void DestroyOrbiter(LunarSunBehavior lunarSunBehavior) { if ((bool)controller) { controller.Detonate(); } } } private void Awake() { base.enabled = false; projectilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/LunarSunProjectile"); ulong seed = Run.instance.seed ^ (ulong)Run.instance.stageClearCount; transformRng = new Xoroshiro128Plus(seed); } private void OnEnable() { } private void OnDisable() { this.onDisabled?.Invoke(this); this.onDisabled = null; } private void FixedUpdate() { projectileTimer += Time.fixedDeltaTime; if (!body.master.IsDeployableLimited(DeployableSlot.LunarSunBomb) && projectileTimer > 3f / (float)stack) { projectileTimer = 0f; FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo); fireProjectileInfo.projectilePrefab = projectilePrefab; fireProjectileInfo.crit = body.RollCrit(); fireProjectileInfo.damage = body.damage * 3.6f; fireProjectileInfo.damageColorIndex = DamageColorIndex.Item; fireProjectileInfo.force = 0f; fireProjectileInfo.owner = base.gameObject; fireProjectileInfo.position = body.transform.position; fireProjectileInfo.rotation = UnityEngine.Quaternion.identity; FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo; ProjectileManager.instance.FireProjectile(fireProjectileInfo2); } transformTimer += Time.fixedDeltaTime; if (!(transformTimer > 60f)) { return; } transformTimer = 0f; if (!body.master || !body.inventory) { return; } List list = new List(body.inventory.itemAcquisitionOrder); ItemIndex itemIndex = ItemIndex.None; Util.ShuffleList(list, transformRng); foreach (ItemIndex item in list) { if (item != DLC1Content.Items.LunarSun.itemIndex) { ItemDef itemDef = ItemCatalog.GetItemDef(item); if ((bool)itemDef && itemDef.tier != ItemTier.NoTier) { itemIndex = item; break; } } } if (itemIndex != ItemIndex.None) { body.inventory.RemoveItem(itemIndex); body.inventory.GiveItem(DLC1Content.Items.LunarSun); CharacterMasterNotificationQueue.SendTransformNotification(body.master, itemIndex, DLC1Content.Items.LunarSun.itemIndex, CharacterMasterNotificationQueue.TransformationType.LunarSun); } } } public class MushroomVoidBehavior : CharacterBody.ItemBehavior { private const float healPercentagePerStack = 0.01f; private const float healPeriodSeconds = 0.5f; private bool wasSprinting; private HealthComponent healthComponent; private float healTimer; private void Awake() { base.enabled = false; } private void OnEnable() { if ((bool)body) { wasSprinting = body.GetBuffCount(DLC1Content.Buffs.MushroomVoidActive) > 0; healthComponent = body.GetComponent(); } healTimer = 0f; } private void OnDisable() { if ((bool)body && wasSprinting) { body.RemoveBuff(DLC1Content.Buffs.MushroomVoidActive); } healthComponent = null; } private void FixedUpdate() { if ((bool)body) { if (body.isSprinting) { healTimer += Time.fixedDeltaTime; if (!wasSprinting) { wasSprinting = true; body.AddBuff(DLC1Content.Buffs.MushroomVoidActive); } } else if (wasSprinting) { body.RemoveBuff(DLC1Content.Buffs.MushroomVoidActive); wasSprinting = false; } } while (healTimer > 0.5f) { healthComponent.HealFraction(0.01f * (float)stack, default(ProcChainMask)); healTimer -= 0.5f; } } } internal class OutOfCombatArmorBehavior : CharacterBody.ItemBehavior { private bool providingBuff; private void SetProvidingBuff(bool shouldProvideBuff) { if (shouldProvideBuff != providingBuff) { providingBuff = shouldProvideBuff; if (providingBuff) { body.AddBuff(DLC1Content.Buffs.OutOfCombatArmorBuff); } else { body.RemoveBuff(DLC1Content.Buffs.OutOfCombatArmorBuff); } } } private void OnDisable() { SetProvidingBuff(shouldProvideBuff: false); } private void FixedUpdate() { SetProvidingBuff(body.outOfDanger); } } public class PrimarySkillShurikenBehavior : CharacterBody.ItemBehavior { private const float minSpreadDegrees = 0f; private const float rangeSpreadDegrees = 1f; private const int numShurikensPerStack = 1; private const int numShurikensBase = 2; private const string projectilePrefabPath = "Prefabs/Projectiles/ShurikenProjectile"; private const float totalReloadTime = 10f; private const float damageCoefficientBase = 3f; private const float damageCoefficientPerStack = 1f; private const float force = 0f; private SkillLocator skillLocator; private float reloadTimer; private GameObject projectilePrefab; private InputBankTest inputBank; private void Awake() { base.enabled = false; } private void Start() { projectilePrefab = LegacyResourcesAPI.Load("Prefabs/Projectiles/ShurikenProjectile"); } private void OnEnable() { if ((bool)body) { body.onSkillActivatedServer += OnSkillActivated; skillLocator = body.GetComponent(); inputBank = body.GetComponent(); } } private void OnDisable() { if ((bool)body) { body.onSkillActivatedServer -= OnSkillActivated; while (body.HasBuff(DLC1Content.Buffs.PrimarySkillShurikenBuff)) { body.RemoveBuff(DLC1Content.Buffs.PrimarySkillShurikenBuff); } } inputBank = null; skillLocator = null; } private void OnSkillActivated(GenericSkill skill) { if ((object)skillLocator?.primary == skill && body.GetBuffCount(DLC1Content.Buffs.PrimarySkillShurikenBuff) > 0) { body.RemoveBuff(DLC1Content.Buffs.PrimarySkillShurikenBuff); FireShuriken(); } } private void FixedUpdate() { int num = stack + 2; if (body.GetBuffCount(DLC1Content.Buffs.PrimarySkillShurikenBuff) < num) { float num2 = 10f / (float)num; reloadTimer += Time.fixedDeltaTime; while (reloadTimer > num2 && body.GetBuffCount(DLC1Content.Buffs.PrimarySkillShurikenBuff) < num) { body.AddBuff(DLC1Content.Buffs.PrimarySkillShurikenBuff); reloadTimer -= num2; } } } private void FireShuriken() { Ray aimRay = GetAimRay(); ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction) * GetRandomRollPitch(), base.gameObject, body.damage * (3f + 1f * (float)stack), 0f, Util.CheckRoll(body.crit, body.master), DamageColorIndex.Item); } private Ray GetAimRay() { if ((bool)inputBank) { return new Ray(inputBank.aimOrigin, inputBank.aimDirection); } return new Ray(base.transform.position, base.transform.forward); } protected UnityEngine.Quaternion GetRandomRollPitch() { UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.forward); UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(0f + UnityEngine.Random.Range(0f, 1f), UnityEngine.Vector3.left); return quaternion * quaternion2; } } public class VoidMegaCrabItemBehavior : CharacterBody.ItemBehavior { private const float baseSecondsPerSpawn = 60f; private const int baseMaxAllies = 1; private const int maxAlliesPerStack = 1; private const float minSpawnDist = 3f; private const float maxSpawnDist = 40f; private float spawnTimer; private Xoroshiro128Plus rng; private WeightedSelection spawnSelection; private DirectorPlacementRule placementRule; public static int GetMaxProjectiles(Inventory inventory) { return 1 + (inventory.GetItemCount(DLC1Content.Items.VoidMegaCrabItem) - 1); } private void Awake() { base.enabled = false; ulong seed = Run.instance.seed ^ (ulong)Run.instance.stageClearCount; rng = new Xoroshiro128Plus(seed); spawnSelection = new WeightedSelection(); spawnSelection.AddChoice(Addressables.LoadAssetAsync("RoR2/DLC1/VoidJailer/cscVoidJailerAlly.asset").WaitForCompletion(), 15f); spawnSelection.AddChoice(Addressables.LoadAssetAsync("RoR2/Base/Nullifier/cscNullifierAlly.asset").WaitForCompletion(), 15f); spawnSelection.AddChoice(Addressables.LoadAssetAsync("RoR2/DLC1/VoidMegaCrab/cscVoidMegaCrabAlly.asset").WaitForCompletion(), 1f); placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, minDistance = 3f, maxDistance = 40f, spawnOnTarget = base.transform }; } private void FixedUpdate() { spawnTimer += Time.fixedDeltaTime; if (!body.master.IsDeployableLimited(DeployableSlot.VoidMegaCrabItem) && spawnTimer > 60f / (float)stack) { spawnTimer = 0f; DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnSelection.Evaluate(rng.nextNormalizedFloat), placementRule, rng); directorSpawnRequest.summonerBodyObject = base.gameObject; directorSpawnRequest.onSpawnedServer = OnMasterSpawned; directorSpawnRequest.summonerBodyObject = base.gameObject; DirectorCore.instance.TrySpawnObject(directorSpawnRequest); } } private void OnMasterSpawned(SpawnCard.SpawnResult spawnResult) { GameObject spawnedInstance = spawnResult.spawnedInstance; if (!spawnedInstance) { return; } CharacterMaster component = spawnedInstance.GetComponent(); if ((bool)component) { Deployable component2 = component.GetComponent(); if ((bool)component2) { body.master.AddDeployable(component2, DeployableSlot.VoidMegaCrabItem); } } } } public class ItemDisplay : MonoBehaviour { public CharacterModel.RendererInfo[] rendererInfos; public GameObject[] hideOnDeathObjects; private VisibilityLevel visibilityLevel = VisibilityLevel.Visible; private bool isDead; public VisibilityLevel GetVisibilityLevel() { return visibilityLevel; } public void SetVisibilityLevel(VisibilityLevel newVisibilityLevel) { if (visibilityLevel == newVisibilityLevel) { return; } visibilityLevel = newVisibilityLevel; switch (visibilityLevel) { case VisibilityLevel.Invisible: { for (int l = 0; l < rendererInfos.Length; l++) { CharacterModel.RendererInfo rendererInfo4 = rendererInfos[l]; rendererInfo4.renderer.enabled = false; rendererInfo4.renderer.shadowCastingMode = ShadowCastingMode.Off; } break; } case VisibilityLevel.Cloaked: { for (int j = 0; j < rendererInfos.Length; j++) { CharacterModel.RendererInfo rendererInfo2 = rendererInfos[j]; rendererInfo2.renderer.enabled = !rendererInfo2.ignoreOverlays && (!isDead || !rendererInfo2.hideOnDeath); rendererInfo2.renderer.shadowCastingMode = ShadowCastingMode.Off; rendererInfo2.renderer.material = CharacterModel.cloakedMaterial; } break; } case VisibilityLevel.Revealed: { for (int k = 0; k < rendererInfos.Length; k++) { CharacterModel.RendererInfo rendererInfo3 = rendererInfos[k]; rendererInfo3.renderer.enabled = !rendererInfo3.ignoreOverlays && (!isDead || !rendererInfo3.hideOnDeath); rendererInfo3.renderer.shadowCastingMode = ShadowCastingMode.Off; rendererInfo3.renderer.material = CharacterModel.revealedMaterial; } break; } case VisibilityLevel.Visible: { for (int i = 0; i < rendererInfos.Length; i++) { CharacterModel.RendererInfo rendererInfo = rendererInfos[i]; bool flag = !isDead || !rendererInfo.hideOnDeath; rendererInfo.renderer.enabled = flag; rendererInfo.renderer.shadowCastingMode = ((!flag) ? ShadowCastingMode.On : ShadowCastingMode.Off); rendererInfo.renderer.material = rendererInfo.defaultMaterial; } break; } } } public void OnDeath() { isDead = true; for (int i = 0; i < rendererInfos.Length; i++) { CharacterModel.RendererInfo rendererInfo = rendererInfos[i]; if (rendererInfo.hideOnDeath) { rendererInfo.renderer.enabled = false; rendererInfo.renderer.shadowCastingMode = ShadowCastingMode.Off; } } GameObject[] array = hideOnDeathObjects; for (int j = 0; j < array.Length; j++) { array[j].SetActive(value: false); } } } [SelectionBase] [ExecuteInEditMode] [DisallowMultipleComponent] public class ItemDisplayRuleComponent : MonoBehaviour { public UnityEngine.Object keyAsset; public LimbFlags limbMask; [SerializeField] [HideInInspector] private ItemDisplayRuleType _ruleType; public string nameInLocator; [HideInInspector] [SerializeField] private GameObject _prefab; private GameObject prefabInstance; private ItemDisplayRule itemDisplayRule; public ItemDisplayRuleType ruleType { get { return _ruleType; } set { _ruleType = value; if (_ruleType != 0) { prefab = null; } } } public GameObject prefab { get { return _prefab; } set { if (!prefabInstance || _prefab != value) { _prefab = value; BuildPreview(); } } } private void Start() { BuildPreview(); } public bool SetItemDisplayRule(ItemDisplayRule newItemDisplayRule, ChildLocator childLocator, UnityEngine.Object newKeyAsset) { itemDisplayRule = newItemDisplayRule; string childName = itemDisplayRule.childName; Transform transform = childLocator.FindChild(childName); if (!transform) { UnityEngine.Debug.LogWarningFormat(childLocator.gameObject, "Could not fully load item display rules for {0} because child {1} could not be found in the child locator.", childLocator.gameObject.name, childName); return false; } base.transform.parent = transform; keyAsset = newKeyAsset; nameInLocator = itemDisplayRule.childName; ruleType = itemDisplayRule.ruleType; switch (ruleType) { case ItemDisplayRuleType.ParentedPrefab: base.transform.localPosition = itemDisplayRule.localPos; base.transform.localEulerAngles = itemDisplayRule.localAngles; base.transform.localScale = itemDisplayRule.localScale; prefab = itemDisplayRule.followerPrefab; limbMask = LimbFlags.None; break; case ItemDisplayRuleType.LimbMask: prefab = null; limbMask = itemDisplayRule.limbMask; break; } return true; } private void DestroyPreview() { if ((bool)prefabInstance) { UnityEngine.Object.DestroyImmediate(prefabInstance); } prefabInstance = null; } private void BuildPreview() { DestroyPreview(); if ((bool)prefab) { prefabInstance = UnityEngine.Object.Instantiate(prefab); prefabInstance.name = "Preview"; prefabInstance.transform.parent = base.transform; prefabInstance.transform.localPosition = UnityEngine.Vector3.zero; prefabInstance.transform.localRotation = UnityEngine.Quaternion.identity; prefabInstance.transform.localScale = UnityEngine.Vector3.one; SetPreviewFlags(prefabInstance.transform); } } private static void SetPreviewFlags(Transform transform) { transform.gameObject.hideFlags = HideFlags.DontSave | HideFlags.NotEditable; foreach (Transform item in transform) { SetPreviewFlags(item); } } private void OnDestroy() { DestroyPreview(); } } [RequireComponent(typeof(ItemDisplay))] public class ItemFollower : MonoBehaviour { public GameObject followerPrefab; public GameObject targetObject; public BezierCurveLine followerCurve; public LineRenderer followerLineRenderer; public float distanceDampTime; public float distanceMaxSpeed; private ItemDisplay itemDisplay; private UnityEngine.Vector3 velocityDistance; private UnityEngine.Vector3 v0; private UnityEngine.Vector3 v1; [HideInInspector] public GameObject followerInstance; private void Start() { itemDisplay = GetComponent(); followerLineRenderer = GetComponent(); Rebuild(); } private void Rebuild() { if (itemDisplay.GetVisibilityLevel() == VisibilityLevel.Invisible) { if ((bool)followerInstance) { UnityEngine.Object.Destroy(followerInstance); } if ((bool)followerLineRenderer) { followerLineRenderer.enabled = false; } return; } if (!followerInstance) { followerInstance = UnityEngine.Object.Instantiate(followerPrefab, targetObject.transform.position, UnityEngine.Quaternion.identity); followerInstance.transform.localScale = base.transform.localScale; if ((bool)followerCurve) { v0 = followerCurve.v0; v1 = followerCurve.v1; } } if ((bool)followerLineRenderer) { followerLineRenderer.enabled = true; } } private void Update() { Rebuild(); if ((bool)followerInstance) { Transform transform = followerInstance.transform; Transform transform2 = targetObject.transform; transform.position = UnityEngine.Vector3.SmoothDamp(transform.position, transform2.position, ref velocityDistance, distanceDampTime); transform.rotation = transform2.rotation; if ((bool)followerCurve) { followerCurve.v0 = base.transform.TransformVector(v0); followerCurve.v1 = transform.TransformVector(v1); followerCurve.p1 = transform.position; } } } private void OnDestroy() { if ((bool)followerInstance) { UnityEngine.Object.Destroy(followerInstance); } } } public class ItemStealController : NetworkBehaviour { [Serializable] private class StolenInventoryInfo : IDisposable { [SerializeField] private ItemStealController owner; public Inventory victimInventory; public bool allowLending = true; public bool showStealOrbs = true; private int[] stolenItemStacks; private int[] lentItemStacks; private int[] itemAcqusitionSet; private ItemIndex[] itemAcquisitionOrder; [SerializeField] private int itemAcquisitionOrderCount; [SerializeField] private List inFlightOrbs; public int stolenItemCount => itemAcquisitionOrderCount; [SerializeField] private Inventory lendeeInventory => owner.lendeeInventory; public bool hasOrbsInFlight => inFlightOrbs.Count > 0; public bool hasItemsToReclaim { get; private set; } public StolenInventoryInfo(ItemStealController owner, Inventory victimInventory) { this.owner = owner; this.victimInventory = victimInventory; stolenItemStacks = ItemCatalog.RequestItemStackArray(); lentItemStacks = ItemCatalog.RequestItemStackArray(); itemAcqusitionSet = ItemCatalog.RequestItemStackArray(); itemAcquisitionOrder = ItemCatalog.RequestItemOrderBuffer(); itemAcquisitionOrderCount = 0; inFlightOrbs = new List(); } public void Dispose() { victimInventory = null; if (stolenItemStacks != null) { ItemCatalog.ReturnItemStackArray(stolenItemStacks); stolenItemStacks = null; } if (lentItemStacks != null) { ItemCatalog.ReturnItemStackArray(lentItemStacks); lentItemStacks = null; } if (itemAcqusitionSet != null) { ItemCatalog.ReturnItemStackArray(itemAcqusitionSet); itemAcqusitionSet = null; } if (itemAcquisitionOrder != null) { ItemCatalog.ReturnItemOrderBuffer(itemAcquisitionOrder); itemAcquisitionOrder = null; } inFlightOrbs = null; } public bool StealNewestItem(int maxStackToSteal = int.MaxValue, bool? useOrbOverride = null) { if (!victimInventory) { return false; } List list = victimInventory.itemAcquisitionOrder; for (int num = list.Count - 1; num >= 0; num--) { ItemIndex itemIndex = list[num]; if (StealItem(itemIndex, maxStackToSteal, useOrbOverride) > 0) { return true; } } return false; } private int StealItem(ItemIndex itemIndex, int maxStackToSteal, bool? useOrbOverride = null) { if (!owner.itemStealFilter(itemIndex)) { return 0; } int itemCount = victimInventory.GetItemCount(itemIndex); int itemsToSteal = Math.Min(itemCount, maxStackToSteal); if (itemsToSteal > 0) { victimInventory.RemoveItem(itemIndex, itemsToSteal); UnityEngine.Vector3? vector = ((useOrbOverride ?? showStealOrbs) ? FindInventoryOrbOrigin(victimInventory) : null); if (vector.HasValue) { ItemTransferOrb item = ItemTransferOrb.DispatchItemTransferOrb(vector.Value, null, itemIndex, itemsToSteal, delegate(ItemTransferOrb orb) { GiveItemToSelf(itemIndex, itemsToSteal); inFlightOrbs.Remove(orb); }, owner.networkIdentity); inFlightOrbs.Add(item); } else { GiveItemToSelf(itemIndex, itemsToSteal); } } return itemsToSteal; } private void RegisterItemAsAcquired(ItemIndex itemIndex) { ref int reference = ref itemAcqusitionSet[(int)itemIndex]; if (reference == 0) { reference = 1; itemAcquisitionOrder[itemAcquisitionOrderCount++] = itemIndex; } } public bool LendNewestStolenItem(bool useOrb, int maxStackToGive = int.MaxValue) { for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--) { ItemIndex itemIndex = itemAcquisitionOrder[num]; if (LendStolenItem(itemIndex, useOrb, maxStackToGive) > 0) { return true; } } return false; } public void LendAllItems(bool useOrb, int maxStackToGive = int.MaxValue) { for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--) { ItemIndex itemIndex = itemAcquisitionOrder[num]; LendStolenItem(itemIndex, useOrb, maxStackToGive); } } private int LendStolenItem(ItemIndex itemIndex, bool useOrb, int maxStackToGive = int.MaxValue) { if (!lendeeInventory) { return 0; } int num = TakeItemFromSelf(itemIndex, maxStackToGive); if (num > 0) { if (useOrb) { ItemTransferOrb item = ItemTransferOrb.DispatchItemTransferOrb(owner.orbTargetTransform.position, lendeeInventory, itemIndex, num, delegate(ItemTransferOrb orb) { GiveItemToLendee(orb.itemIndex, orb.stack); inFlightOrbs.Remove(orb); }); inFlightOrbs.Add(item); } else { GiveItemToLendee(itemIndex, num); } } hasItemsToReclaim = true; return num; } private int ReclaimLentItem(ItemIndex itemToReclaim, int maxStackToReclaim = int.MaxValue, bool? useOrbOverride = null) { int num = TakeItemFromLendee(itemToReclaim, maxStackToReclaim); if (num > 0) { UnityEngine.Vector3? orbOrigin = ((useOrbOverride ?? showStealOrbs) ? FindInventoryOrbOrigin(lendeeInventory) : null); DispatchOrbOrGiveItem(victimInventory, itemToReclaim, num, orbOrigin, useOrbOverride); } return num; } private int ReclaimStolenItem(ItemIndex itemToReclaim, int maxStacksToReclaim = int.MaxValue, bool? useOrbOverride = null) { int num = TakeItemFromSelf(itemToReclaim, maxStacksToReclaim); if (num > 0) { DispatchOrbOrGiveItem(victimInventory, itemToReclaim, num, owner.orbTargetTransform.position, useOrbOverride); } return num; } private void DispatchOrbOrGiveItem(Inventory inventoryToGrantTo, ItemIndex itemToReclaim, int stacks, UnityEngine.Vector3? orbOrigin, bool? useOrbOverride = null) { if (!inventoryToGrantTo) { return; } if (orbOrigin.HasValue && (useOrbOverride ?? showStealOrbs)) { ItemTransferOrb item = ItemTransferOrb.DispatchItemTransferOrb(orbOrigin.Value, victimInventory, itemToReclaim, stacks, delegate(ItemTransferOrb orb) { ItemTransferOrb.DefaultOnArrivalBehavior(orb); inFlightOrbs.Remove(orb); }); inFlightOrbs.Add(item); } else if ((bool)inventoryToGrantTo) { inventoryToGrantTo.GiveItem(itemToReclaim, stacks); } } public bool ReclaimNewestLentItem(int maxStackToReclaim = int.MaxValue) { for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--) { ItemIndex itemToReclaim = itemAcquisitionOrder[num]; if (ReclaimLentItem(itemToReclaim, maxStackToReclaim) > 0) { return true; } } hasItemsToReclaim = false; return false; } public bool ReclaimOldestLentItem(int maxStackToReclaim = int.MaxValue) { for (int i = 0; i < itemAcquisitionOrderCount; i++) { ItemIndex itemToReclaim = itemAcquisitionOrder[i]; if (ReclaimLentItem(itemToReclaim, maxStackToReclaim) > 0) { return true; } } hasItemsToReclaim = false; return false; } private void ForceAllOrbsToFinish() { while (inFlightOrbs.Count > 0) { OrbManager.instance.ForceImmediateArrival(inFlightOrbs[0]); } } private void GiveItemToSelf(ItemIndex itemIndex, int stack) { stolenItemStacks[(int)itemIndex] += stack; RegisterItemAsAcquired(itemIndex); } private int TakeItemFromSelf(ItemIndex itemIndex, int maxStackToTake) { ref int reference = ref stolenItemStacks[(int)itemIndex]; int num = Math.Min(reference, maxStackToTake); reference -= num; return num; } private void GiveItemToLendee(ItemIndex itemIndex, int stack) { lentItemStacks[(int)itemIndex] += stack; if ((bool)lendeeInventory && allowLending && owner.itemLendFilter(itemIndex)) { lendeeInventory.GiveItem(itemIndex, stack); } } private int TakeItemFromLendee(ItemIndex itemIndex, int maxStackToTake) { ref int reference = ref lentItemStacks[(int)itemIndex]; int num = Math.Min(reference, maxStackToTake); if ((bool)lendeeInventory && owner.itemLendFilter(itemIndex)) { lendeeInventory.RemoveItem(itemIndex, num); } reference -= num; return num; } public void ForceReclaimAllItemsImmediately() { ForceAllOrbsToFinish(); for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--) { ItemIndex itemIndex = itemAcquisitionOrder[num]; int num2 = 0; num2 += TakeItemFromSelf(itemIndex, int.MaxValue); num2 += TakeItemFromLendee(itemIndex, int.MaxValue); if ((bool)victimInventory) { victimInventory.GiveItem(itemIndex, num2); } } } public void ReclaimAllItems(bool? useOrbOverride) { for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--) { ItemIndex itemToReclaim = itemAcquisitionOrder[num]; ReclaimLentItem(itemToReclaim, int.MaxValue, useOrbOverride); ReclaimStolenItem(itemToReclaim, int.MaxValue, useOrbOverride); } hasItemsToReclaim = false; } public void TakeBackItemsFromLendee() { UnityEngine.Vector3? vector = FindInventoryOrbOrigin(lendeeInventory); for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--) { ItemIndex itemIndex = itemAcquisitionOrder[num]; int itemStackToTake = TakeItemFromLendee(itemIndex, int.MaxValue); if (vector.HasValue) { ItemTransferOrb item = ItemTransferOrb.DispatchItemTransferOrb(vector.Value, null, itemIndex, itemStackToTake, delegate(ItemTransferOrb orb) { GiveItemToSelf(itemIndex, itemStackToTake); inFlightOrbs.Remove(orb); }, owner.orbTarget); inFlightOrbs.Add(item); } else { GiveItemToSelf(itemIndex, itemStackToTake); } } } private static UnityEngine.Vector3? FindInventoryOrbOrigin(Inventory inventory) { if ((bool)inventory) { CharacterMaster component = inventory.GetComponent(); if ((bool)component) { CharacterBody body = component.GetBody(); if ((bool)body) { return body.corePosition; } } } return null; } } public UnityEvent onStealBeginServer; public UnityEvent onStealFinishServer; public UnityEvent onLendingBeginServer; public UnityEvent onLendingFinishServer; public float stealInterval = 0.2f; public HurtBox orbDestinationHurtBoxOverride; private NetworkIdentity networkIdentity; public Func itemStealFilter = DefaultItemFilter; public Func itemLendFilter = AIItemFilter; private StolenInventoryInfo[] stolenInventoryInfos = Array.Empty(); private bool _inItemSteal; private bool _inLending; private float stealTimer; private float lendTimer; private Func stealMasterFilter; private static int kRpcRpcOnStealBeginClient; private static int kRpcRpcOnStealFinishClient; private static int kRpcRpcOnLendingBeginClient; private static int kRpcRpcOnLendingFinishClient; public Inventory lendeeInventory { get; private set; } public bool inItemSteal { get { return _inItemSteal; } private set { if (_inItemSteal != value) { if (_inItemSteal) { hasStolen = true; } _inItemSteal = value; (_inItemSteal ? onStealBeginServer : onStealFinishServer)?.Invoke(); if (_inItemSteal) { CallRpcOnStealBeginClient(); } else { CallRpcOnStealFinishClient(); } } } } public bool hasStolen { get; private set; } public bool inLending { get { return _inLending; } private set { if (_inLending != value) { _inLending = value; (_inLending ? onLendingBeginServer : onLendingFinishServer)?.Invoke(); if (_inItemSteal) { CallRpcOnLendingBeginClient(); } else { CallRpcOnLendingFinishClient(); } } } } private Either orbTarget { get { if ((bool)orbDestinationHurtBoxOverride) { return orbDestinationHurtBoxOverride; } return networkIdentity; } } private Transform orbTargetTransform { get { if ((bool)orbDestinationHurtBoxOverride) { return orbDestinationHurtBoxOverride.transform; } return networkIdentity.transform; } } public event Action onStealBeginClient; public event Action onStealFinishClient; public event Action onLendingBeginClient; public event Action onLendingFinishClient; private void Awake() { networkIdentity = GetComponent(); } private void OnEnable() { if (!NetworkServer.active) { base.enabled = false; } } private void OnDisable() { inItemSteal = false; ForceReclaimAllItemsImmediately(); } private void OnDestroy() { StolenInventoryInfo[] array = stolenInventoryInfos; for (int i = 0; i < array.Length; i++) { array[i].Dispose(); } stolenInventoryInfos = Array.Empty(); } private void FixedUpdate() { if (inItemSteal) { stealTimer -= Time.fixedDeltaTime; if (stealTimer <= 0f) { stealTimer = stealInterval; StepSteal(); } } if (inLending) { lendTimer -= Time.fixedDeltaTime; if (lendTimer <= 0f) { lendTimer = stealInterval; StepLend(); } } } public static bool DefaultItemFilter(ItemIndex itemIndex) { ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); if (itemDef.canRemove) { return itemDef.DoesNotContainTag(ItemTag.CannotSteal); } return false; } public static bool AIItemFilter(ItemIndex itemIndex) { ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); if (itemDef.canRemove) { return itemDef.DoesNotContainTag(ItemTag.AIBlacklist); } return false; } public static bool BrotherItemFilter(ItemIndex itemIndex) { ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex); if (itemDef.canRemove && itemDef.DoesNotContainTag(ItemTag.AIBlacklist)) { return itemDef.DoesNotContainTag(ItemTag.BrotherBlacklist); } return false; } public void StartLending(Inventory newLendeeInventory) { if (lendeeInventory != newLendeeInventory) { StolenInventoryInfo[] array = stolenInventoryInfos; for (int i = 0; i < array.Length; i++) { array[i].TakeBackItemsFromLendee(); } } lendeeInventory = newLendeeInventory; inLending = true; } public void LendImmediately(Inventory newLendeeInventory) { UnityEngine.Debug.LogFormat("LendImmediately({0})", newLendeeInventory); StartLending(newLendeeInventory); StolenInventoryInfo[] array = stolenInventoryInfos; for (int i = 0; i < array.Length; i++) { array[i].LendAllItems(useOrb: false); } inLending = false; } public void StartStealingFromInventory(Inventory victimInventory) { if (GetStolenInventoryInfo(victimInventory) == null) { StolenInventoryInfo value = new StolenInventoryInfo(this, victimInventory); if ((bool)victimInventory.GetComponent().ownerMaster) { value.allowLending = false; value.showStealOrbs = false; } ArrayUtils.ArrayAppend(ref stolenInventoryInfos, in value); inItemSteal = true; } } public void StepSteal() { if (stealMasterFilter != null) { foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList) { if (stealMasterFilter(readOnlyInstances)) { StartStealingFromInventory(readOnlyInstances.inventory); } } } bool flag = false; StolenInventoryInfo[] array = stolenInventoryInfos; foreach (StolenInventoryInfo stolenInventoryInfo in array) { flag |= stolenInventoryInfo.hasOrbsInFlight; flag |= stolenInventoryInfo.StealNewestItem(); } if (!flag) { inItemSteal = false; } } public void StepLend() { bool flag = false; StolenInventoryInfo[] array = stolenInventoryInfos; foreach (StolenInventoryInfo stolenInventoryInfo in array) { flag |= stolenInventoryInfo.hasOrbsInFlight; flag |= stolenInventoryInfo.LendNewestStolenItem(useOrb: true); } if (!flag) { inLending = false; } } public int GetStolenItemCount(Inventory victimInventory) { return GetStolenInventoryInfo(victimInventory)?.stolenItemCount ?? 0; } private StolenInventoryInfo GetStolenInventoryInfo(Inventory victimInventory) { for (int i = 0; i < stolenInventoryInfos.Length; i++) { if (stolenInventoryInfos[i].victimInventory == victimInventory) { return stolenInventoryInfos[i]; } } return null; } private void ForceReclaimAllItemsImmediately() { StolenInventoryInfo[] array = stolenInventoryInfos; for (int i = 0; i < array.Length; i++) { array[i].ForceReclaimAllItemsImmediately(); } } public void ReclaimAllItems() { StolenInventoryInfo[] array = stolenInventoryInfos; for (int i = 0; i < array.Length; i++) { array[i].ReclaimAllItems(null); } } public void StartSteal(Func filter) { if (NetworkServer.active) { stealMasterFilter = filter; inItemSteal = true; } } public bool ReclaimItemForInventory(Inventory inventory, int maxStack = int.MaxValue) { return GetStolenInventoryInfo(inventory)?.ReclaimNewestLentItem(maxStack) ?? false; } public void FindDeadOwnersOfStolenItems(List dest) { List list = CollectionPool>.RentCollection(); List list2 = CollectionPool>.RentCollection(); for (int i = 0; i < stolenInventoryInfos.Length; i++) { ref StolenInventoryInfo reference = ref stolenInventoryInfos[i]; if ((bool)reference.victimInventory) { CharacterMaster component = reference.victimInventory.GetComponent(); if ((bool)component && !component.hasBody && reference.hasItemsToReclaim) { (reference.allowLending ? list : list2).Add(reference.victimInventory); } } } dest.AddRange(list); dest.AddRange(list2); CollectionPool>.ReturnCollection(list2); CollectionPool>.ReturnCollection(list); } public void AddValidStolenInventoriesToList(List list) { if (list == null) { return; } StolenInventoryInfo[] array = stolenInventoryInfos; foreach (StolenInventoryInfo stolenInventoryInfo in array) { if ((bool)stolenInventoryInfo.victimInventory) { list.Add(stolenInventoryInfo.victimInventory); } } } [ClientRpc] private void RpcOnStealBeginClient() { this.onStealBeginClient?.Invoke(); } [ClientRpc] private void RpcOnStealFinishClient() { this.onStealFinishClient?.Invoke(); } [ClientRpc] private void RpcOnLendingBeginClient() { this.onLendingBeginClient?.Invoke(); } [ClientRpc] private void RpcOnLendingFinishClient() { this.onLendingFinishClient?.Invoke(); } private void UNetVersion() { } protected static void InvokeRpcRpcOnStealBeginClient(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcOnStealBeginClient called on server."); } else { ((ItemStealController)obj).RpcOnStealBeginClient(); } } protected static void InvokeRpcRpcOnStealFinishClient(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcOnStealFinishClient called on server."); } else { ((ItemStealController)obj).RpcOnStealFinishClient(); } } protected static void InvokeRpcRpcOnLendingBeginClient(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcOnLendingBeginClient called on server."); } else { ((ItemStealController)obj).RpcOnLendingBeginClient(); } } protected static void InvokeRpcRpcOnLendingFinishClient(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcOnLendingFinishClient called on server."); } else { ((ItemStealController)obj).RpcOnLendingFinishClient(); } } public void CallRpcOnStealBeginClient() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcOnStealBeginClient called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnStealBeginClient); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcOnStealBeginClient"); } public void CallRpcOnStealFinishClient() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcOnStealFinishClient called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnStealFinishClient); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcOnStealFinishClient"); } public void CallRpcOnLendingBeginClient() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcOnLendingBeginClient called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnLendingBeginClient); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcOnLendingBeginClient"); } public void CallRpcOnLendingFinishClient() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcOnLendingFinishClient called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnLendingFinishClient); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcOnLendingFinishClient"); } static ItemStealController() { kRpcRpcOnStealBeginClient = 166425938; NetworkBehaviour.RegisterRpcDelegate(typeof(ItemStealController), kRpcRpcOnStealBeginClient, InvokeRpcRpcOnStealBeginClient); kRpcRpcOnStealFinishClient = -1161796992; NetworkBehaviour.RegisterRpcDelegate(typeof(ItemStealController), kRpcRpcOnStealFinishClient, InvokeRpcRpcOnStealFinishClient); kRpcRpcOnLendingBeginClient = -1214064562; NetworkBehaviour.RegisterRpcDelegate(typeof(ItemStealController), kRpcRpcOnLendingBeginClient, InvokeRpcRpcOnLendingBeginClient); kRpcRpcOnLendingFinishClient = -1007329532; NetworkBehaviour.RegisterRpcDelegate(typeof(ItemStealController), kRpcRpcOnLendingFinishClient, InvokeRpcRpcOnLendingFinishClient); NetworkCRC.RegisterBehaviour("ItemStealController", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public interface IZone { bool IsInBounds(UnityEngine.Vector3 position); } [RequireComponent(typeof(NetworkedBodyAttachment))] public class JetpackController : NetworkBehaviour { private static readonly List instancesList; private NetworkedBodyAttachment networkedBodyAttachment; public float duration; public float acceleration; public float boostSpeedMultiplier = 3f; public float boostCooldown = 0.5f; private float stopwatch; private Transform wingTransform; private Animator wingAnimator; private GameObject[] wingMotions; private GameObject wingMeshObject; private float boostCooldownTimer; private bool hasBegunSoundLoop; private ICharacterGravityParameterProvider targetCharacterGravityParameterProvider; private ICharacterFlightParameterProvider targetCharacterFlightParameterProvider; private bool _providingAntiGravity; private bool _providingFlight; private static int wingsReadyParamHash; private static int flyParamHash; private static int kRpcRpcResetTimer; private CharacterBody targetBody => networkedBodyAttachment.attachedBody; private bool providingAntiGravity { get { return _providingAntiGravity; } set { if (_providingAntiGravity != value) { _providingAntiGravity = value; if (targetCharacterGravityParameterProvider != null) { CharacterGravityParameters gravityParameters = targetCharacterGravityParameterProvider.gravityParameters; gravityParameters.channeledAntiGravityGranterCount += (_providingAntiGravity ? 1 : (-1)); targetCharacterGravityParameterProvider.gravityParameters = gravityParameters; } } } } private bool providingFlight { get { return _providingFlight; } set { if (_providingFlight != value) { _providingFlight = value; if (targetCharacterFlightParameterProvider != null) { CharacterFlightParameters flightParameters = targetCharacterFlightParameterProvider.flightParameters; flightParameters.channeledFlightGranterCount += (_providingFlight ? 1 : (-1)); targetCharacterFlightParameterProvider.flightParameters = flightParameters; } } } } public static JetpackController FindJetpackController(GameObject targetObject) { if (!targetObject) { return null; } for (int i = 0; i < instancesList.Count; i++) { if (instancesList[i].networkedBodyAttachment.attachedBodyObject == targetObject) { return instancesList[i]; } } return null; } private void Awake() { networkedBodyAttachment = GetComponent(); } private void Start() { SetupWings(); if ((bool)targetBody) { targetCharacterGravityParameterProvider = targetBody.GetComponent(); targetCharacterFlightParameterProvider = targetBody.GetComponent(); StartFlight(); } } private void StartFlight() { providingAntiGravity = true; providingFlight = true; if (targetBody.hasEffectiveAuthority && (bool)targetBody.characterMotor && targetBody.characterMotor.isGrounded) { UnityEngine.Vector3 velocity = targetBody.characterMotor.velocity; velocity.y = 15f; targetBody.characterMotor.velocity = velocity; targetBody.characterMotor.Motor.ForceUnground(); } } private void OnDestroy() { ShowMotionLines(showWings: false); if ((bool)targetBody) { providingFlight = false; targetCharacterFlightParameterProvider = null; providingAntiGravity = false; targetCharacterGravityParameterProvider = null; } } private void OnEnable() { instancesList.Add(this); } private void OnDisable() { instancesList.Remove(this); } private void FixedUpdate() { stopwatch += Time.fixedDeltaTime; boostCooldownTimer -= Time.fixedDeltaTime; if ((bool)targetBody) { base.transform.position = targetBody.transform.position; if (targetBody.hasEffectiveAuthority && (bool)targetBody.characterMotor) { if (stopwatch < duration) { if (boostCooldownTimer <= 0f && targetBody.inputBank.jump.justPressed && targetBody.inputBank.moveVector != UnityEngine.Vector3.zero) { boostCooldownTimer = boostCooldown; targetBody.characterMotor.velocity = targetBody.inputBank.moveVector * (targetBody.moveSpeed * boostSpeedMultiplier); targetBody.characterMotor.disableAirControlUntilCollision = false; } } else { UnityEngine.Vector3 velocity = targetBody.characterMotor.velocity; velocity.y = Mathf.Max(velocity.y, -5f); targetBody.characterMotor.velocity = velocity; providingAntiGravity = false; providingFlight = false; } } } if (stopwatch >= duration) { bool flag = !targetBody.characterMotor || !targetBody.characterMotor.isGrounded; if ((bool)wingAnimator && !flag) { wingAnimator.SetBool(wingsReadyParamHash, value: false); } if (NetworkServer.active && !flag) { UnityEngine.Object.Destroy(base.gameObject); } return; } float num = 4f; if ((bool)targetBody.characterMotor) { float magnitude = targetBody.characterMotor.velocity.magnitude; float moveSpeed = targetBody.moveSpeed; if (magnitude != 0f && moveSpeed != 0f) { num += magnitude / moveSpeed * 6f; } } if ((bool)wingAnimator) { wingAnimator.SetBool(wingsReadyParamHash, value: true); wingAnimator.SetFloat(flyParamHash, num, 0.1f, Time.fixedDeltaTime); ShowMotionLines(showWings: true); } } public void ResetTimer() { stopwatch = 0f; StartFlight(); if (NetworkServer.active) { CallRpcResetTimer(); } } [ClientRpc] private void RpcResetTimer() { if (!NetworkServer.active) { ResetTimer(); } } private Transform FindWings() { ModelLocator modelLocator = targetBody.modelLocator; if ((bool)modelLocator) { Transform modelTransform = modelLocator.modelTransform; if ((bool)modelTransform) { CharacterModel component = modelTransform.GetComponent(); if ((bool)component) { List equipmentDisplayObjects = component.GetEquipmentDisplayObjects(RoR2Content.Equipment.Jetpack.equipmentIndex); if (equipmentDisplayObjects.Count > 0) { return equipmentDisplayObjects[0].transform; } } } } return null; } private void ShowMotionLines(bool showWings) { if (wingMotions == null) { return; } for (int i = 0; i < wingMotions.Length; i++) { if ((bool)wingMotions[i]) { wingMotions[i].SetActive(showWings); } } if ((bool)wingMeshObject) { wingMeshObject.SetActive(!showWings); } if (hasBegunSoundLoop != showWings) { if (showWings) { Util.PlaySound("Play_item_use_bugWingFlapLoop", base.gameObject); } else { Util.PlaySound("Stop_item_use_bugWingFlapLoop", base.gameObject); } hasBegunSoundLoop = showWings; } } public void SetupWings() { wingTransform = FindWings(); if ((bool)wingTransform) { wingAnimator = wingTransform.GetComponentInChildren(); ChildLocator component = wingTransform.GetComponent(); if ((bool)wingAnimator) { wingAnimator.SetBool(wingsReadyParamHash, value: true); } if ((bool)component) { wingMotions = new GameObject[4]; wingMotions[0] = component.FindChild("WingMotionLargeL").gameObject; wingMotions[1] = component.FindChild("WingMotionLargeR").gameObject; wingMotions[2] = component.FindChild("WingMotionSmallL").gameObject; wingMotions[3] = component.FindChild("WingMotionSmallR").gameObject; wingMeshObject = component.FindChild("WingMesh").gameObject; } } } static JetpackController() { instancesList = new List(); wingsReadyParamHash = Animator.StringToHash("wingsReady"); flyParamHash = Animator.StringToHash("fly.playbackRate"); kRpcRpcResetTimer = 1278379706; NetworkBehaviour.RegisterRpcDelegate(typeof(JetpackController), kRpcRpcResetTimer, InvokeRpcRpcResetTimer); NetworkCRC.RegisterBehaviour("JetpackController", 0); } private void UNetVersion() { } protected static void InvokeRpcRpcResetTimer(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcResetTimer called on server."); } else { ((JetpackController)obj).RpcResetTimer(); } } public void CallRpcResetTimer() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcResetTimer called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcResetTimer); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcResetTimer"); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class JitterBones : MonoBehaviour { private struct BoneInfo { public Transform transform; public bool isHead; public bool isRoot; } [SerializeField] private SkinnedMeshRenderer _skinnedMeshRenderer; private BoneInfo[] bones = Array.Empty(); public float perlinNoiseFrequency; public float perlinNoiseStrength; public float perlinNoiseMinimumCutoff; public float perlinNoiseMaximumCutoff = 1f; public float headBonusStrength; private float age; public SkinnedMeshRenderer skinnedMeshRenderer { get { return _skinnedMeshRenderer; } set { if ((object)_skinnedMeshRenderer != value) { _skinnedMeshRenderer = value; RebuildBones(); } } } private void RebuildBones() { if (!_skinnedMeshRenderer) { bones = Array.Empty(); return; } Transform[] array = _skinnedMeshRenderer.bones; Array.Resize(ref bones, array.Length); for (int i = 0; i < bones.Length; i++) { Transform transform = array[i]; string text = transform.name.ToLower(); bones[i] = new BoneInfo { transform = transform, isHead = text.Contains("head"), isRoot = text.Contains("root") }; } } private void Start() { RebuildBones(); } private void LateUpdate() { if (!skinnedMeshRenderer) { return; } age += Time.deltaTime; for (int i = 0; i < bones.Length; i++) { BoneInfo boneInfo = bones[i]; if (!boneInfo.isRoot) { float num = age * perlinNoiseFrequency; float num2 = i; UnityEngine.Vector3 value = new UnityEngine.Vector3(Mathf.PerlinNoise(num, num2), Mathf.PerlinNoise(num + 4f, num2 + 3f), Mathf.PerlinNoise(num + 6f, num2 - 7f)); value = HGMath.Remap(value, perlinNoiseMinimumCutoff, perlinNoiseMaximumCutoff, -1f, 1f); value = HGMath.Clamp(value, 0f, 1f); value *= perlinNoiseStrength; if (headBonusStrength >= 0f && boneInfo.isHead) { value *= headBonusStrength; } boneInfo.transform.rotation *= UnityEngine.Quaternion.Euler(value); } } } } public class JumpVolume : MonoBehaviour { public Transform targetElevationTransform; public UnityEngine.Vector3 jumpVelocity; public float time; public string jumpSoundString; public UnityEvent onJump; public void OnTriggerStay(Collider other) { CharacterMotor component = other.GetComponent(); if ((bool)component && component.hasEffectiveAuthority && !component.doNotTriggerJumpVolumes) { onJump.Invoke(); if (!component.disableAirControlUntilCollision) { Util.PlaySound(jumpSoundString, base.gameObject); } component.velocity = jumpVelocity; component.disableAirControlUntilCollision = true; component.Motor.ForceUnground(); } } private void OnDrawGizmos() { int num = 20; float num2 = time / (float)num; UnityEngine.Vector3 vector = base.transform.position; _ = base.transform.position; UnityEngine.Vector3 vector2 = jumpVelocity; Gizmos.color = UnityEngine.Color.yellow; for (int i = 0; i <= num; i++) { UnityEngine.Vector3 vector3 = vector + vector2 * num2; vector2 += Physics.gravity * num2; Gizmos.DrawLine(vector3, vector); vector = vector3; } } } public class KillOnTimer : MonoBehaviour { public float duration; private float age; private HealthComponent health; private void Start() { if (!TryGetComponent(out var component)) { UnityEngine.Debug.LogWarning(base.gameObject.name + " does not have a health component! KillOnTimer will not work!!"); } else { health = component; } } private void Update() { age += Time.deltaTime; if (age > duration) { if ((bool)health && NetworkServer.active) { health.Suicide(); } base.enabled = false; } } } [RequireComponent(typeof(LineRenderer))] public class LaserPointer : MonoBehaviour { public float laserDistance; private LineRenderer line; private void Start() { line = GetComponent(); } private void Update() { if (Physics.Raycast(base.transform.position, base.transform.forward, out var hitInfo, laserDistance, LayerIndex.world.mask)) { line.SetPosition(0, base.transform.position); line.SetPosition(1, hitInfo.point); } } } internal class LaserPointerController : MonoBehaviour { public InputBankTest source; public GameObject dotObject; public LineRenderer beam; public float minDistanceFromStart = 4f; private void LateUpdate() { bool flag = false; bool active = false; if ((bool)source) { Ray ray = new Ray(source.aimOrigin, source.aimDirection); if (Physics.Raycast(ray, out var hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal)) { base.transform.position = hitInfo.point; base.transform.forward = -ray.direction; float num = hitInfo.distance - minDistanceFromStart; if (num >= 0.1f) { beam.SetPosition(1, new UnityEngine.Vector3(0f, 0f, num)); flag = true; } active = true; } } dotObject.SetActive(active); beam.enabled = flag; } } [RequireComponent(typeof(GenericOwnership))] [RequireComponent(typeof(NetworkIdentity))] [RequireComponent(typeof(EntityStateMachine))] [RequireComponent(typeof(NetworkStateMachine))] public class LaserTurbineController : NetworkBehaviour { public float visualSpinRate = 7200f; public Transform chargeIndicator; public Transform spinIndicator; public Transform turbineDisplayRoot; public bool showTurbineDisplay; public string spinRtpc; public float spinRtpcScale; public float visualSpin; public float visualSpinDecayRate = 0.2f; private GenericOwnership genericOwnership; private CharacterBody cachedOwnerBody; public float charge { get; private set; } private void Awake() { genericOwnership = GetComponent(); genericOwnership.onOwnerChanged += OnOwnerChanged; } private void Update() { if (NetworkClient.active) { UpdateClient(); } } private void FixedUpdate() { int killChargeCount = 0; if ((bool)cachedOwnerBody) { killChargeCount = cachedOwnerBody.GetBuffCount(RoR2Content.Buffs.LaserTurbineKillCharge); } charge = CalcCurrentChargeValue(killChargeCount); if ((bool)turbineDisplayRoot) { turbineDisplayRoot.gameObject.SetActive(showTurbineDisplay); } } private void OnEnable() { if (NetworkServer.active) { GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobalServer; } } private void OnDisable() { GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobalServer; } [Client] private void UpdateClient() { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.LaserTurbineController::UpdateClient()' called on server"); return; } if (visualSpin <= charge) { visualSpin = charge; } else { visualSpin -= visualSpinDecayRate * Time.deltaTime; } visualSpin = Mathf.Max(visualSpin, 0f); float num = HGMath.CircleAreaToRadius(visualSpin * HGMath.CircleRadiusToArea(1f)); chargeIndicator.localScale = new UnityEngine.Vector3(num, num, num); UnityEngine.Vector3 localEulerAngles = spinIndicator.localEulerAngles; localEulerAngles.y += visualSpin * Time.deltaTime * visualSpinRate; spinIndicator.localEulerAngles = localEulerAngles; AkSoundEngine.SetRTPCValue(spinRtpc, visualSpin * spinRtpcScale, base.gameObject); } [Server] public void ExpendCharge() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LaserTurbineController::ExpendCharge()' called on client"); } else if ((bool)cachedOwnerBody) { cachedOwnerBody.ClearTimedBuffs(RoR2Content.Buffs.LaserTurbineKillCharge); } } private void OnCharacterDeathGlobalServer(DamageReport damageReport) { if ((object)damageReport.attacker == genericOwnership.ownerObject && (object)damageReport.attacker != null) { OnOwnerKilledOtherServer(); } } private void OnOwnerKilledOtherServer() { if ((bool)cachedOwnerBody) { cachedOwnerBody.AddTimedBuff(RoR2Content.Buffs.LaserTurbineKillCharge, RechargeState.killChargeDuration, RechargeState.killChargesRequired); } } private void OnOwnerChanged(GameObject newOwner) { cachedOwnerBody = (newOwner ? newOwner.GetComponent() : null); } public float CalcCurrentChargeValue(int killChargeCount) { return Mathf.Clamp01((float)killChargeCount / (float)RechargeState.killChargesRequired); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } [RequireComponent(typeof(EntityStateMachine))] public class LightningStormController : NetworkBehaviour { [Serializable] public struct LightningStrikePoint { [Tooltip("Just for identifying points - not used in code")] public string description; [Tooltip("How far from the target's position should this point appear.")] public float distanceFromTargetPosition; [FormerlySerializedAs("speedMultiplier")] [Tooltip("How much the projected position should take into account the player's current velocity. 1.8 tends to work if you want it to go off right as they pass by it.")] [FormerlySerializedAs("distanceProjectionMultiplier")] public float velocityMultiplier; [Tooltip("Degrees to offset the prstrike position (0 = forward, 180 = behind, 90 = right, 270 / -90 = left, etc)")] public float directionOffset; [Tooltip("A randomized number of degrees (+/-) to adjust direction offset by.")] public float randomDegreeOffset; } public static LightningStrikePattern lightningPattern; [SyncVar(hook = "Client_HandleStormActiveChanged")] public bool stormActive; [SyncVar(hook = "Client_SetStormStrikePattern")] private int strikePatternID = -1; [SerializeField] private List strikePatterns = new List(); [SerializeField] [Space(20f)] private EntityStateMachine stormStateMachine; [SerializeField] public GameObject startPostProcessingObject; [SerializeField] public PostProcessDuration startPostProcessDuration; [SerializeField] public GameObject endPostProcessingObject; [SerializeField] public PostProcessDuration endPostProcessDuration; [SerializeField] [FormerlySerializedAs("serializedlightningPattern")] public LightningStrikePattern fallbackLightningPattern; private static int kCmdCmdSetStormActive; private static int kCmdCmdSetStrikePattern; public static LightningStormController instance { get; private set; } public bool NetworkstormActive { get { return stormActive; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; Client_HandleStormActiveChanged(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref stormActive, 1u); } } public int NetworkstrikePatternID { get { return strikePatternID; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; Client_SetStormStrikePattern(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref strikePatternID, 2u); } } public static void SetStormActive(bool b) { if (!(instance == null) && b != instance.stormActive) { if (!NetworkServer.active) { instance.CallCmdSetStormActive(b); } else { instance.ServerSetStormActive(b); } } } public static void SetStormStrikePattern(LightningStrikePattern _pattern) { if (!(instance == null) && !(_pattern == null) && !(_pattern == lightningPattern) && _pattern != null) { if (NetworkServer.active) { instance.ServerSetStrikePattern(_pattern.ID); } else { instance.CallCmdSetStrikePattern(_pattern.ID); } } } public static LightningStrikeInstance FireLightningBolt(UnityEngine.Vector3 position, GameObject lightningPrefab, BlastAttack _blastInfo = null) { if (instance != null && !instance.stormActive) { return null; } GameObject gameObject = UnityEngine.Object.Instantiate(lightningPrefab); LightningStrikeInstance component = gameObject.GetComponent(); if (!component) { UnityEngine.Object.Destroy(gameObject); return null; } component.Initialize(position, _blastInfo); return component; } public static bool ShouldFireLighting() { if (instance == null) { return false; } return instance.stormActive; } public static UnityEngine.Vector3 PredictPosition(UnityEngine.Vector3 position, UnityEngine.Vector3 forwardDirection, float maxSpeed, LightningStrikePoint strikePointData) { forwardDirection = UnityEngine.Quaternion.AngleAxis(strikePointData.directionOffset, UnityEngine.Vector3.up) * forwardDirection; if (strikePointData.randomDegreeOffset != 0f) { forwardDirection = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f - strikePointData.randomDegreeOffset, strikePointData.randomDegreeOffset), UnityEngine.Vector3.up) * forwardDirection; } position += forwardDirection * maxSpeed * strikePointData.velocityMultiplier; position += forwardDirection * strikePointData.distanceFromTargetPosition; return position; } public static float GetMaxDistance(UnityEngine.Vector3 forwardDirection, float maxSpeed, LightningStrikePoint strikePointData) { return (forwardDirection * maxSpeed * strikePointData.velocityMultiplier).magnitude + strikePointData.distanceFromTargetPosition; } [ContextMenu("Load Current Lightning Pattern Scrob into Memory")] public void LoadCurrentLightningPatternScrob() { SetStormStrikePattern(fallbackLightningPattern); } [Command] private void CmdSetStormActive(bool b) { ServerSetStormActive(b); } [Server] private void ServerSetStormActive(bool b) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LightningStormController::ServerSetStormActive(System.Boolean)' called on client"); return; } if (b != stormActive) { if (b) { HandleStormBegins(); } else { HandleStormEnds(); } } NetworkstormActive = b; } private void Client_HandleStormActiveChanged(bool newValue) { if (NetworkServer.active) { return; } if (newValue != stormActive) { if (newValue) { HandleStormBegins(); } else { HandleStormEnds(); } } NetworkstormActive = newValue; } [Server] private void ServerSetStrikePattern(int patternID) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LightningStormController::ServerSetStrikePattern(System.Int32)' called on client"); return; } if (patternID >= strikePatterns.Count || patternID < 0) { patternID = 0; } if (patternID != strikePatternID) { NetworkstrikePatternID = patternID; lightningPattern = strikePatterns[patternID]; } } [Command] private void CmdSetStrikePattern(int patternID) { ServerSetStrikePattern(patternID); } private void Client_SetStormStrikePattern(int newPatternIndex) { if (NetworkServer.active) { return; } if (newPatternIndex >= strikePatterns.Count || newPatternIndex < 0) { newPatternIndex = 0; if (strikePatterns.Count < 1) { return; } } lightningPattern = strikePatterns[newPatternIndex]; NetworkstrikePatternID = newPatternIndex; } private void Awake() { if (strikePatterns.Count >= 1) { for (int i = 0; i < strikePatterns.Count; i++) { strikePatterns[i].ID = i; } int num = ((fallbackLightningPattern != null) ? fallbackLightningPattern.ID : 0); if (NetworkServer.active) { ServerSetStrikePattern(num); } else { lightningPattern = strikePatterns[num]; } } } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); if (stormActive) { HandleStormBegins(); } } private void OnDisable() { instance = SingletonHelper.Unassign(instance, this); HandleStormEnds(); } private void HandleStormBegins() { if (!(lightningPattern == null)) { SetStormStrikePattern(fallbackLightningPattern); stormStateMachine.SetNextState(new LightningStormState()); } } private void HandleStormEnds() { stormStateMachine.SetNextState(new EntityStates.Idle()); } private void UNetVersion() { } protected static void InvokeCmdCmdSetStormActive(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetStormActive called on client."); } else { ((LightningStormController)obj).CmdSetStormActive(reader.ReadBoolean()); } } protected static void InvokeCmdCmdSetStrikePattern(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetStrikePattern called on client."); } else { ((LightningStormController)obj).CmdSetStrikePattern((int)reader.ReadPackedUInt32()); } } public void CallCmdSetStormActive(bool b) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetStormActive called on server."); return; } if (base.isServer) { CmdSetStormActive(b); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetStormActive); networkWriter.Write(GetComponent().netId); networkWriter.Write(b); SendCommandInternal(networkWriter, 0, "CmdSetStormActive"); } public void CallCmdSetStrikePattern(int patternID) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetStrikePattern called on server."); return; } if (base.isServer) { CmdSetStrikePattern(patternID); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetStrikePattern); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32((uint)patternID); SendCommandInternal(networkWriter, 0, "CmdSetStrikePattern"); } static LightningStormController() { kCmdCmdSetStormActive = 753869832; NetworkBehaviour.RegisterCommandDelegate(typeof(LightningStormController), kCmdCmdSetStormActive, InvokeCmdCmdSetStormActive); kCmdCmdSetStrikePattern = 1007190007; NetworkBehaviour.RegisterCommandDelegate(typeof(LightningStormController), kCmdCmdSetStrikePattern, InvokeCmdCmdSetStrikePattern); NetworkCRC.RegisterBehaviour("LightningStormController", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(stormActive); writer.WritePackedUInt32((uint)strikePatternID); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(stormActive); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)strikePatternID); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { stormActive = reader.ReadBoolean(); strikePatternID = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { Client_HandleStormActiveChanged(reader.ReadBoolean()); } if (((uint)num & 2u) != 0) { Client_SetStormStrikePattern((int)reader.ReadPackedUInt32()); } } public override void PreStartClient() { } } public class LightningStrikeInstance : MonoBehaviour { public GameObject warningEffectPrefab; public GameObject impactEffectPrefab; public TeamComponent teamComponent; public float impactDelay; public float blastDamage; public float blastRadius; public float blastForce; public DamageTypeCombo blastDamageType; private Action ExecuteNextStep; private float stepTimer; private UnityEngine.Vector3 impactPosition; private BlastAttack blastAttack; public bool Initialize(UnityEngine.Vector3 _impactPosition, BlastAttack _blastInfo) { impactPosition = _impactPosition; if (!ConfirmGroundBelowImpactPoint()) { return false; } base.transform.position = impactPosition; stepTimer = 0.0001f; if (impactDelay <= 0f) { ExecuteNextStep = HandleStrike; } else { ExecuteNextStep = HandleWarning; } if (_blastInfo != null) { blastAttack = _blastInfo; } else { blastAttack = new BlastAttack { attacker = null, baseDamage = blastDamage, baseForce = blastForce, radius = blastRadius, damageType = blastDamageType, teamIndex = teamComponent.teamIndex }; } SetupDefaultBlastInfo(ref blastAttack); return true; } private bool ConfirmGroundBelowImpactPoint() { if (Physics.Raycast(new Ray(impactPosition + UnityEngine.Vector3.up * 2f, UnityEngine.Vector3.down), out var hitInfo, 200f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault, QueryTriggerInteraction.Ignore)) { impactPosition = hitInfo.point; return true; } return false; } private void SetupDefaultBlastInfo(ref BlastAttack _blastInfo) { _blastInfo.position = impactPosition; if (_blastInfo.attacker == null) { _blastInfo.attacker = base.gameObject; } _blastInfo.inflictor = base.gameObject; _blastInfo.attackerFiltering = AttackerFiltering.Default; _blastInfo.falloffModel = BlastAttack.FalloffModel.Linear; _blastInfo.bonusForce = UnityEngine.Vector3.zero; _blastInfo.damageColorIndex = DamageColorIndex.Item; _blastInfo.procChainMask = default(ProcChainMask); _blastInfo.procCoefficient = 1f; if (_blastInfo.teamIndex == TeamIndex.Neutral) { _blastInfo.teamIndex = teamComponent.teamIndex; } } private void Update() { if (stepTimer > 0f) { stepTimer -= Time.deltaTime; if (stepTimer <= 0f) { ExecuteNextStep?.Invoke(); } } } private void HandleWarning() { if (!LightningStormController.ShouldFireLighting()) { ExecuteNextStep = HandleCleanup; stepTimer = 0.2f; return; } EffectManager.SpawnEffect(warningEffectPrefab, new EffectData { origin = impactPosition, scale = blastRadius }, transmit: true); stepTimer = impactDelay; ExecuteNextStep = HandleStrike; } private void HandleStrike() { if (!LightningStormController.ShouldFireLighting()) { ExecuteNextStep = HandleCleanup; stepTimer = 0.2f; return; } if ((bool)impactEffectPrefab) { EffectData effectData = new EffectData { origin = impactPosition }; EffectManager.SpawnEffect(impactEffectPrefab, effectData, transmit: true); } StrikeAboveImpactPosition(); blastAttack.Fire(); stepTimer = 1f; ExecuteNextStep = HandleCleanup; } private void StrikeAboveImpactPosition() { ReadOnlyCollection readOnlyInstancesList = CharacterMaster.readOnlyInstancesList; float num = 100f; float radius = this.blastAttack.radius; float num2 = this.blastAttack.radius * 1.3f; num2 *= num2; UnityEngine.Vector3 vector = impactPosition; foreach (CharacterMaster item in readOnlyInstancesList) { if (item == null || item.GetBody() == null) { continue; } UnityEngine.Vector3 corePosition = item.GetBody().corePosition; float num3 = Mathf.Abs(corePosition.y - impactPosition.y); if (num3 > num || num3 < radius) { continue; } vector.y = corePosition.y; if (!((corePosition - vector).sqrMagnitude > num2)) { BlastAttack blastAttack = CopyBlastAttack(ref this.blastAttack); blastAttack.position = vector; if ((bool)impactEffectPrefab) { EffectData effectData = new EffectData { origin = blastAttack.position }; EffectManager.SpawnEffect(impactEffectPrefab, effectData, transmit: true); } blastAttack.Fire(); } } } private BlastAttack CopyBlastAttack(ref BlastAttack _source) { BlastAttack _blastInfo = new BlastAttack(); _blastInfo.attacker = _source.attacker; _blastInfo.baseDamage = _source.baseDamage; _blastInfo.baseForce = _source.baseForce; _blastInfo.radius = _source.radius; _blastInfo.damageType = _source.damageType; SetupDefaultBlastInfo(ref _blastInfo); return _blastInfo; } private void HandleCleanup() { UnityEngine.Object.Destroy(base.gameObject); } } [CreateAssetMenu(fileName = "New Lightning Pattern Data", menuName = "RoR2/Lightning Pattern")] public class LightningStrikePattern : ScriptableObject { [NonSerialized] [HideInInspector] public int ID; [Tooltip("How far can a discovered node be from the predicted position and still qualify as a strike point.")] public float maxAcceptableDistanceFromPredictedPoint = 2f; [Tooltip("How many lightning strikes should we reduce the total by, per additional player. (Single player will not reduce any)")] public float forEachAdditionalPlayerReduceStrikeTotalBy = 1f; public float frequencyOfLightningStrikes = 4f; public float timeBetweenIndividualStrikes = 0.2f; public List lightningStrikePoints; } public class LightScaleFromParent : MonoBehaviour { private void Start() { Light component = GetComponent(); if ((bool)component) { float range = component.range; UnityEngine.Vector3 lossyScale = base.transform.lossyScale; component.range = range * Mathf.Max(lossyScale.x, lossyScale.y, lossyScale.z); } } } public class LimbMatcher : MonoBehaviour { [Serializable] public struct LimbPair { public Transform originalTransform; public string targetChildLimb; public float originalLimbLength; [NonSerialized] public Transform targetTransform; } public bool scaleLimbs = true; private bool valid; public LimbPair[] limbPairs; public void SetChildLocator(ChildLocator childLocator) { valid = true; for (int i = 0; i < limbPairs.Length; i++) { LimbPair limbPair = limbPairs[i]; Transform transform = childLocator.FindChild(limbPair.targetChildLimb); if (!transform) { valid = false; break; } limbPairs[i].targetTransform = transform; } } private void LateUpdate() { UpdateLimbs(); } private void UpdateLimbs() { if (!valid) { return; } for (int i = 0; i < limbPairs.Length; i++) { LimbPair limbPair = limbPairs[i]; Transform targetTransform = limbPair.targetTransform; if (!targetTransform || !limbPair.originalTransform) { continue; } limbPair.originalTransform.position = targetTransform.position; limbPair.originalTransform.rotation = targetTransform.rotation; if (i < limbPairs.Length - 1) { float num = UnityEngine.Vector3.Magnitude(limbPairs[i + 1].targetTransform.position - targetTransform.position); float originalLimbLength = limbPair.originalLimbLength; if (scaleLimbs) { UnityEngine.Vector3 localScale = limbPair.originalTransform.localScale; localScale.y = num / originalLimbLength; limbPair.originalTransform.localScale = localScale; } } } } } [RequireComponent(typeof(CharacterBody))] public class LoaderStaticChargeComponent : NetworkBehaviour, IOnDamageDealtServerReceiver, IOnTakeDamageServerReceiver { private enum State { Idle, Drain } public float maxCharge = 100f; public float consumptionRate = 10f; [SyncVar] private float _charge; private CharacterBody characterBody; private State state; private static int kCmdCmdConsumeCharge; public float charge => _charge; public float chargeFraction => charge / maxCharge; public float Network_charge { get { return _charge; } [param: In] set { SetSyncVar(value, ref _charge, 1u); } } private void Awake() { characterBody = GetComponent(); } public void OnDamageDealtServer(DamageReport damageReport) { AddChargeServer(damageReport.damageDealt); } public void OnTakeDamageServer(DamageReport damageReport) { AddChargeServer(damageReport.damageDealt); } [Server] private void AddChargeServer(float additionalCharge) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LoaderStaticChargeComponent::AddChargeServer(System.Single)' called on client"); return; } float num = _charge + additionalCharge; if (num > maxCharge) { num = maxCharge; } Network_charge = num; } [Server] private void ConsumeChargeInternal() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LoaderStaticChargeComponent::ConsumeChargeInternal()' called on client"); } else { SetState(State.Drain); } } public void ConsumeChargeAuthority() { if (NetworkServer.active) { ConsumeChargeInternal(); } else { CallCmdConsumeCharge(); } } private void SetState(State newState) { if (state != newState) { if (state == State.Drain && NetworkServer.active) { characterBody.RemoveBuff(JunkContent.Buffs.LoaderOvercharged); } state = newState; if (state == State.Drain && NetworkServer.active) { characterBody.AddBuff(JunkContent.Buffs.LoaderOvercharged); } } } private void FixedUpdate() { if (NetworkServer.active && state == State.Drain) { Network_charge = _charge - Time.fixedDeltaTime * consumptionRate; if (_charge <= 0f) { Network_charge = 0f; SetState(State.Idle); } } } [Command] private void CmdConsumeCharge() { ConsumeChargeInternal(); } private void UNetVersion() { } protected static void InvokeCmdCmdConsumeCharge(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdConsumeCharge called on client."); } else { ((LoaderStaticChargeComponent)obj).CmdConsumeCharge(); } } public void CallCmdConsumeCharge() { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdConsumeCharge called on server."); return; } if (base.isServer) { CmdConsumeCharge(); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdConsumeCharge); networkWriter.Write(GetComponent().netId); SendCommandInternal(networkWriter, 0, "CmdConsumeCharge"); } static LoaderStaticChargeComponent() { kCmdCmdConsumeCharge = -261598328; NetworkBehaviour.RegisterCommandDelegate(typeof(LoaderStaticChargeComponent), kCmdCmdConsumeCharge, InvokeCmdCmdConsumeCharge); NetworkCRC.RegisterBehaviour("LoaderStaticChargeComponent", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(_charge); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_charge); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { _charge = reader.ReadSingle(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { _charge = reader.ReadSingle(); } } public override void PreStartClient() { } } public class LocalCameraEffect : MonoBehaviour { public GameObject targetCharacter; public GameObject effectRoot; private static List instancesList; static LocalCameraEffect() { instancesList = new List(); RoR2Application.onUpdate += CullNonLocalCameraEffects; } private static void CullNonLocalCameraEffects() { foreach (LocalCameraEffect instances in instancesList) { instances.effectRoot.SetActive(instances.TryFindLocalUserCameraRigController() != null); } } private CameraRigController TryFindLocalUserCameraRigController() { foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList) { CameraRigController cameraRigController = readOnlyLocalUsers.cameraRigController; if ((bool)cameraRigController && cameraRigController.target == targetCharacter && cameraRigController.cameraMode == CameraModePlayerBasic.playerBasic) { return cameraRigController; } } return null; } private void Start() { instancesList.Add(this); PostProcessVolume componentInChildren = effectRoot.GetComponentInChildren(); if (componentInChildren != null) { CameraRigController cameraRigController = TryFindLocalUserCameraRigController(); if (cameraRigController != null) { cameraRigController.SetPostProcessVolumeExclusive(componentInChildren); } } } private void OnDestroy() { instancesList.Remove(this); } } [ExecuteAlways] public class LookAtTransform : MonoBehaviour { public enum Axis { Right, Left, Up, Down, Forward, Backward } public Transform target; public Axis axis = Axis.Forward; private void LateUpdate() { if (!target) { return; } UnityEngine.Vector3 vector = target.position - base.transform.position; if (!(vector == UnityEngine.Vector3.zero)) { switch (axis) { case Axis.Right: base.transform.right = vector; break; case Axis.Left: base.transform.right = -vector; break; case Axis.Up: base.transform.up = vector; break; case Axis.Down: base.transform.right = -vector; break; case Axis.Forward: base.transform.forward = vector; break; case Axis.Backward: base.transform.forward = -vector; break; default: throw new ArgumentOutOfRangeException(); } } } } public class LoopSound : MonoBehaviour { public string akSoundString; public float repeatInterval; public Transform soundOwner; private float stopwatch; private void Update() { stopwatch += Time.deltaTime; if (stopwatch > repeatInterval) { stopwatch -= repeatInterval; if ((bool)soundOwner) { Util.PlaySound(akSoundString, soundOwner.gameObject); } } } } public class LoopSoundPlayer : MonoBehaviour { [SerializeField] private LoopSoundDef loopDef; private LoopSoundManager.SoundLoopPtr loopPtr; private void OnEnable() { if ((bool)loopDef) { loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopDef); } } private void OnDisable() { if (loopPtr.isValid) { LoopSoundManager.StopSoundLoopLocal(loopPtr); } } } [RequireComponent(typeof(CharacterMotor))] [RequireComponent(typeof(CharacterBody))] public class LoopSoundWhileCharacterMoving : MonoBehaviour { [SerializeField] private string startSoundName; [SerializeField] private string stopSoundName; [SerializeField] private float minSpeed; [SerializeField] private bool requireGrounded; [SerializeField] private bool disableWhileSprinting; [SerializeField] private bool applyScale; private CharacterBody body; private CharacterMotor motor; private bool isLooping; private uint soundId; private void Start() { isLooping = false; body = GetComponent(); motor = GetComponent(); } private void OnDestroy() { if (isLooping) { StopLoop(); } } private void FixedUpdate() { if (!body || !motor) { return; } if (isLooping) { float magnitude = motor.velocity.magnitude; if (applyScale) { float num = body.moveSpeed; float num2 = num; if (!body.isSprinting) { num *= body.sprintingSpeedMultiplier; } else { num2 /= body.sprintingSpeedMultiplier; } float in_value = Mathf.Lerp(0f, 50f, magnitude / num2) + Mathf.Lerp(0f, 50f, (magnitude - num2) / (num - num2)); AkSoundEngine.SetRTPCValueByPlayingID("charMultSpeed", in_value, soundId); } if ((body.isSprinting && disableWhileSprinting) || (requireGrounded && !motor.isGrounded) || magnitude < minSpeed) { StopLoop(); } } else if ((!body.isSprinting || !disableWhileSprinting) && (!requireGrounded || motor.isGrounded) && motor.velocity.sqrMagnitude >= minSpeed) { StartLoop(); } } private void StartLoop() { soundId = Util.PlaySound(startSoundName, base.gameObject); isLooping = true; } private void StopLoop() { Util.PlaySound(stopSoundName, base.gameObject); isLooping = false; } } [RequireComponent(typeof(NetworkedBodyAttachment))] public class LunarDetonatorPassiveAttachment : NetworkBehaviour, INetworkedBodyAttachmentListener { private class DamageListener : MonoBehaviour, IOnDamageDealtServerReceiver { public LunarDetonatorPassiveAttachment passiveController; public void OnDamageDealtServer(DamageReport damageReport) { if (passiveController.skillAvailable && damageReport.victim.alive && Util.CheckRoll(damageReport.damageInfo.procCoefficient * 100f, damageReport.attackerMaster)) { damageReport.victimBody.AddTimedBuff(RoR2Content.Buffs.LunarDetonationCharge, 10f); } } } private GenericSkill _monitoredSkill; [SyncVar(hook = "SetSkillSlotIndexPlusOne")] private uint skillSlotIndexPlusOne; private bool skillAvailable; private NetworkedBodyAttachment networkedBodyAttachment; private DamageListener damageListener; private static int kCmdCmdSetSkillAvailable; public GenericSkill monitoredSkill { get { return _monitoredSkill; } set { if ((object)_monitoredSkill == value) { return; } _monitoredSkill = value; int num = -1; if ((bool)_monitoredSkill) { SkillLocator component = _monitoredSkill.GetComponent(); if ((bool)component) { num = component.GetSkillSlotIndex(_monitoredSkill); } } SetSkillSlotIndexPlusOne((uint)(num + 1)); } } public uint NetworkskillSlotIndexPlusOne { get { return skillSlotIndexPlusOne; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SetSkillSlotIndexPlusOne(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref skillSlotIndexPlusOne, 1u); } } private void Awake() { networkedBodyAttachment = GetComponent(); } private void FixedUpdate() { if (networkedBodyAttachment.hasEffectiveAuthority) { FixedUpdateAuthority(); } } private void OnDestroy() { if ((bool)damageListener) { UnityEngine.Object.Destroy(damageListener); } damageListener = null; } public override void OnStartClient() { SetSkillSlotIndexPlusOne(skillSlotIndexPlusOne); } private void SetSkillSlotIndexPlusOne(uint newSkillSlotIndexPlusOne) { NetworkskillSlotIndexPlusOne = newSkillSlotIndexPlusOne; if (!NetworkServer.active) { ResolveMonitoredSkill(); } } private void ResolveMonitoredSkill() { if ((bool)networkedBodyAttachment.attachedBody) { SkillLocator component = networkedBodyAttachment.attachedBody.GetComponent(); if ((bool)component) { monitoredSkill = component.GetSkillAtIndex((int)(skillSlotIndexPlusOne - 1)); } } } private void FixedUpdateAuthority() { bool flag = false; if ((bool)monitoredSkill) { flag = monitoredSkill.stock > 0; } if (skillAvailable != flag) { skillAvailable = flag; if (!NetworkServer.active) { CallCmdSetSkillAvailable(skillAvailable); } } } [Command] private void CmdSetSkillAvailable(bool newSkillAvailable) { skillAvailable = newSkillAvailable; } public void OnAttachedBodyDiscovered(NetworkedBodyAttachment networkedBodyAttachment, CharacterBody attachedBody) { if (NetworkServer.active) { damageListener = attachedBody.gameObject.AddComponent(); damageListener.passiveController = this; } } private void UNetVersion() { } protected static void InvokeCmdCmdSetSkillAvailable(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetSkillAvailable called on client."); } else { ((LunarDetonatorPassiveAttachment)obj).CmdSetSkillAvailable(reader.ReadBoolean()); } } public void CallCmdSetSkillAvailable(bool newSkillAvailable) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetSkillAvailable called on server."); return; } if (base.isServer) { CmdSetSkillAvailable(newSkillAvailable); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetSkillAvailable); networkWriter.Write(GetComponent().netId); networkWriter.Write(newSkillAvailable); SendCommandInternal(networkWriter, 0, "CmdSetSkillAvailable"); } static LunarDetonatorPassiveAttachment() { kCmdCmdSetSkillAvailable = -1453655134; NetworkBehaviour.RegisterCommandDelegate(typeof(LunarDetonatorPassiveAttachment), kCmdCmdSetSkillAvailable, InvokeCmdCmdSetSkillAvailable); NetworkCRC.RegisterBehaviour("LunarDetonatorPassiveAttachment", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt32(skillSlotIndexPlusOne); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32(skillSlotIndexPlusOne); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { skillSlotIndexPlusOne = reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { SetSkillSlotIndexPlusOne(reader.ReadPackedUInt32()); } } public override void PreStartClient() { } } [RequireComponent(typeof(CharacterBody))] public class MageCalibrationController : MonoBehaviour { [Serializable] public struct CalibrationInfo { public bool enableCalibrationOverlay; public Material calibrationOverlayMaterial; } public CalibrationInfo[] calibrationInfos; public SkinnedMeshRenderer calibrationOverlayRenderer; [Tooltip("The state machine upon which to perform the calibration state.")] public EntityStateMachine stateMachine; [Tooltip("The priority with which the calibration state will try to interrupt the current state.")] public InterruptPriority calibrationStateInterruptPriority; private CharacterBody characterBody; private bool hasEffectiveAuthority; private MageElement _currentElement; private static readonly int[] elementCounter = new int[4]; private MageElement currentElement { get { return _currentElement; } set { if (value != _currentElement) { _currentElement = value; RefreshCalibrationElement(_currentElement); } } } private void Awake() { characterBody = GetComponent(); characterBody.onInventoryChanged += OnInventoryChanged; hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject); } private void Start() { currentElement = GetAwardedElementFromInventory(); RefreshCalibrationElement(currentElement); } private void OnDestroy() { characterBody.onInventoryChanged -= OnInventoryChanged; } private void OnInventoryChanged() { base.enabled = true; } private void FixedUpdate() { base.enabled = false; currentElement = GetAwardedElementFromInventory(); if (hasEffectiveAuthority && currentElement == MageElement.None) { MageElement mageElement = CalcElementToAward(); if (mageElement != 0 && !(stateMachine.state is MageCalibrate)) { MageCalibrate mageCalibrate = new MageCalibrate(); mageCalibrate.element = mageElement; stateMachine.SetInterruptState(mageCalibrate, calibrationStateInterruptPriority); } } } private MageElement GetAwardedElementFromInventory() { Inventory inventory = characterBody.inventory; if ((bool)inventory) { MageElement mageElement = (MageElement)inventory.GetItemCount(JunkContent.Items.MageAttunement); if ((int)mageElement >= 0 && (int)mageElement < 4) { return mageElement; } } return MageElement.None; } private MageElement CalcElementToAward() { for (int i = 0; i < elementCounter.Length; i++) { elementCounter[i] = 0; } Inventory inventory = characterBody.inventory; if (!inventory) { return MageElement.None; } List itemAcquisitionOrder = inventory.itemAcquisitionOrder; for (int j = 0; j < itemAcquisitionOrder.Count; j++) { ItemCatalog.GetItemDef(itemAcquisitionOrder[j]); } EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(inventory.currentEquipmentIndex); if ((bool)equipmentDef) { MageElement mageElement = equipmentDef.mageElement; if (mageElement != 0) { elementCounter[(uint)mageElement] += 2; } } MageElement result = MageElement.None; int num = 0; MageElement mageElement2 = MageElement.Fire; while ((int)mageElement2 < 4) { int num2 = elementCounter[(uint)mageElement2]; if (num2 > num) { result = mageElement2; num = num2; } mageElement2++; } if (num >= 5) { return result; } return MageElement.None; } public MageElement GetActiveCalibrationElement() { return currentElement; } public void SetElement(MageElement newElement) { if (!NetworkServer.active) { return; } Inventory inventory = characterBody.inventory; if ((bool)inventory) { MageElement mageElement = (MageElement)inventory.GetItemCount(JunkContent.Items.MageAttunement); if (mageElement != newElement) { int count = newElement - mageElement; inventory.GiveItem(JunkContent.Items.MageAttunement, count); } } } public void RefreshCalibrationElement(MageElement targetElement) { CalibrationInfo calibrationInfo = calibrationInfos[(uint)targetElement]; calibrationOverlayRenderer.enabled = calibrationInfo.enableCalibrationOverlay; calibrationOverlayRenderer.material = calibrationInfo.calibrationOverlayMaterial; } } public class MapZone : MonoBehaviour { public enum TriggerType { TriggerExit, TriggerEnter } public enum ZoneType { OutOfBounds, KickOutPlayers } private struct CollisionInfo : IEquatable { public readonly MapZone mapZone; public readonly Collider otherCollider; public CollisionInfo(MapZone mapZone, Collider otherCollider) { this.mapZone = mapZone; this.otherCollider = otherCollider; } public bool Equals(CollisionInfo other) { if ((object)mapZone == other.mapZone) { return (object)otherCollider == other.otherCollider; } return false; } public override bool Equals(object obj) { if (obj is CollisionInfo) { return Equals((CollisionInfo)obj); } return false; } public override int GetHashCode() { return otherCollider.GetHashCode(); } } public TriggerType triggerType; public ZoneType zoneType; public Transform explicitDestination; public GameObject explicitSpawnEffectPrefab; public float destinationIdealRadius; private Collider collider; private readonly List queuedCollisions = new List(); private static readonly Queue collidersToCheckInFixedUpdate; public event Action onBodyTeleport; static MapZone() { collidersToCheckInFixedUpdate = new Queue(); VehicleSeat.onPassengerExitGlobal += CheckCharacterOnVehicleExit; RoR2Application.onFixedUpdate += StaticFixedUpdate; } private static bool TestColliders(Collider characterCollider, Collider triggerCollider) { UnityEngine.Vector3 direction; float distance; return Physics.ComputePenetration(characterCollider, characterCollider.transform.position, characterCollider.transform.rotation, triggerCollider, triggerCollider.transform.position, triggerCollider.transform.rotation, out direction, out distance); } private void Awake() { collider = GetComponent(); } public void OnTriggerEnter(Collider other) { if (triggerType == TriggerType.TriggerEnter) { TryZoneStart(other); } else { TryZoneEnd(other); } } public void OnTriggerExit(Collider other) { if (triggerType == TriggerType.TriggerExit) { TryZoneStart(other); } else { TryZoneEnd(other); } } public bool IsPointInsideMapZone(UnityEngine.Vector3 point) { if (collider == null) { return true; } return collider.bounds.Contains(point); } private void TryZoneStart(Collider other) { CharacterBody component = other.GetComponent(); if (!component) { return; } if ((bool)component.currentVehicle) { if (component.currentVehicle.GetComponent() == null) { queuedCollisions.Add(new CollisionInfo(this, other)); return; } component.currentVehicle.EjectPassenger(); } TeamComponent teamComponent = component.teamComponent; switch (zoneType) { case ZoneType.OutOfBounds: { bool flag = false; if ((bool)component.inventory) { flag = component.inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0 || component.inventory.GetItemCount(RoR2Content.Items.TeleportWhenOob) > 0; } if (teamComponent.teamIndex != TeamIndex.Player && !flag) { if (!NetworkServer.active || Physics.GetIgnoreLayerCollision(base.gameObject.layer, other.gameObject.layer)) { break; } UnityEngine.Debug.LogFormat("Killing {0} for being out of bounds.", component.gameObject); HealthComponent healthComponent = component.healthComponent; if ((bool)healthComponent) { if ((bool)component.master) { component.master.TrueKill(healthComponent.lastHitAttacker, base.gameObject, DamageType.OutOfBounds); } else { healthComponent.Suicide(healthComponent.lastHitAttacker, base.gameObject, DamageType.OutOfBounds); } } else if ((bool)component.master) { component.master.TrueKill(null, null, DamageType.OutOfBounds); } } else { TeleportBody(component); } break; } case ZoneType.KickOutPlayers: if (teamComponent.teamIndex == TeamIndex.Player) { TeleportBody(component); } break; } } private void TryZoneEnd(Collider other) { if (queuedCollisions.Count != 0 && queuedCollisions.Contains(new CollisionInfo(this, other))) { queuedCollisions.Remove(new CollisionInfo(this, other)); } } private void ProcessQueuedCollisionsForCollider(Collider collider) { for (int num = queuedCollisions.Count - 1; num >= 0; num--) { if ((object)queuedCollisions[num].otherCollider == collider) { queuedCollisions.RemoveAt(num); TryZoneStart(collider); } } } private static void StaticFixedUpdate() { int i = 0; for (int count = collidersToCheckInFixedUpdate.Count; i < count; i++) { Collider collider = collidersToCheckInFixedUpdate.Dequeue(); if (!collider) { continue; } foreach (MapZone instances in InstanceTracker.GetInstancesList()) { instances.ProcessQueuedCollisionsForCollider(collider); } } } private static void CheckCharacterOnVehicleExit(VehicleSeat vehicleSeat, GameObject passengerObject) { Collider component = passengerObject.GetComponent(); collidersToCheckInFixedUpdate.Enqueue(component); } private void OnEnable() { InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); } private void TeleportBody(CharacterBody characterBody) { if (Util.HasEffectiveAuthority(characterBody.gameObject) && !Physics.GetIgnoreLayerCollision(base.gameObject.layer, characterBody.gameObject.layer)) { UnityEngine.Vector3 vector = Run.instance.FindSafeTeleportPosition(characterBody, explicitDestination, 0f, destinationIdealRadius); TeleportHelper.TeleportBody(characterBody, vector); GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(characterBody.gameObject); if ((bool)explicitSpawnEffectPrefab) { teleportEffectPrefab = explicitSpawnEffectPrefab; } if ((bool)teleportEffectPrefab) { EffectManager.SimpleEffect(teleportEffectPrefab, vector, UnityEngine.Quaternion.identity, transmit: true); } this.onBodyTeleport?.Invoke(characterBody); } } } [RequireComponent(typeof(CharacterMaster))] public class MasterDropDroplet : MonoBehaviour { private CharacterMaster characterMaster; public PickupDropTable[] dropTables; public ulong salt; [Header("Deprecated")] public SerializablePickupIndex[] pickupsToDrop; private Xoroshiro128Plus rng; private void Start() { characterMaster = GetComponent(); rng = new Xoroshiro128Plus(Run.instance.seed ^ salt); } public void DropItems() { CharacterBody body = characterMaster.GetBody(); if (!body) { return; } PickupDropTable[] array = dropTables; foreach (PickupDropTable pickupDropTable in array) { if ((bool)pickupDropTable) { PickupDropletController.CreatePickupDroplet(pickupDropTable.GenerateDrop(rng), body.coreTransform.position, new UnityEngine.Vector3(UnityEngine.Random.Range(-4f, 4f), 20f, UnityEngine.Random.Range(-4f, 4f))); } } SerializablePickupIndex[] array2 = pickupsToDrop; for (int i = 0; i < array2.Length; i++) { PickupDropletController.CreatePickupDroplet(PickupCatalog.FindPickupIndex(array2[i].pickupName), body.coreTransform.position, new UnityEngine.Vector3(UnityEngine.Random.Range(-4f, 4f), 20f, UnityEngine.Random.Range(-4f, 4f))); } } } public class MasterSpawnSlotController : NetworkBehaviour { public interface ISlot { bool IsOpen(); void Spawn(GameObject summonerBodyObject, Xoroshiro128Plus rng, Action callback = null); void Kill(); } public List slots = new List(); [SyncVar] private int _openSlotCount; public int openSlotCount { get { if (NetworkServer.active) { return CalcOpenSlotCount(); } return _openSlotCount; } } public int Network_openSlotCount { get { return _openSlotCount; } [param: In] set { SetSyncVar(value, ref _openSlotCount, 1u); } } private int CalcOpenSlotCount() { int num = 0; foreach (ISlot slot in slots) { if (slot.IsOpen()) { num++; } } return num; } private void OnEnable() { GetComponents(slots); } [Server] public void SpawnAllOpen(GameObject summonerBodyObject, Xoroshiro128Plus rng, Action callback = null) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MasterSpawnSlotController::SpawnAllOpen(UnityEngine.GameObject,Xoroshiro128Plus,System.Action`2)' called on client"); return; } foreach (ISlot slot in slots) { if (slot.IsOpen()) { slot.Spawn(summonerBodyObject, rng, callback); } } } [Server] public void SpawnRandomOpen(int spawnCount, Xoroshiro128Plus rng, GameObject summonerBodyObject, Action callback = null) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MasterSpawnSlotController::SpawnRandomOpen(System.Int32,Xoroshiro128Plus,UnityEngine.GameObject,System.Action`2)' called on client"); return; } List list = new List(); foreach (ISlot slot in slots) { if (slot.IsOpen()) { list.Add(slot); } } Util.ShuffleList(list, rng); for (int i = 0; i < spawnCount && i < list.Count; i++) { list[i].Spawn(summonerBodyObject, rng, callback); } } [Server] public void KillAll() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MasterSpawnSlotController::KillAll()' called on client"); return; } foreach (ISlot slot in slots) { slot.Kill(); } } private void Update() { if (NetworkServer.active) { Network_openSlotCount = CalcOpenSlotCount(); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt32((uint)_openSlotCount); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)_openSlotCount); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { _openSlotCount = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { _openSlotCount = (int)reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public class MasterSuicideOnTimer : MonoBehaviour { public float lifeTimer; [Tooltip("Reset the timer if we're within this radius of the owner")] public float timerResetDistanceToOwner; public MinionOwnership minionOwnership; private CharacterBody body; private CharacterBody ownerBody; private float timer; private bool hasDied; private CharacterMaster characterMaster; private void Start() { characterMaster = GetComponent(); if ((bool)minionOwnership && (bool)minionOwnership.ownerMaster) { ownerBody = minionOwnership.ownerMaster.GetBody(); } } private void FixedUpdate() { if (!NetworkServer.active) { return; } if ((bool)ownerBody) { if (!body) { body = characterMaster.GetBody(); } if ((bool)body && (ownerBody.transform.position - body.transform.position).sqrMagnitude < timerResetDistanceToOwner * timerResetDistanceToOwner) { timer = 0f; } } timer += Time.fixedDeltaTime; if (!(timer >= lifeTimer) || hasDied) { return; } GameObject bodyObject = characterMaster.GetBodyObject(); if ((bool)bodyObject) { HealthComponent component = bodyObject.GetComponent(); if ((bool)component) { component.Suicide(); hasDied = true; } } } } [ExecuteInEditMode] [RequireComponent(typeof(Camera))] public class MatchCamera : MonoBehaviour { private Camera destCamera; public Camera srcCamera; public bool matchFOV = true; public bool matchRect = true; public bool matchPosition; private void Awake() { destCamera = GetComponent(); } private void LateUpdate() { if ((bool)srcCamera) { if (matchRect) { destCamera.rect = srcCamera.rect; } if (matchFOV) { destCamera.fieldOfView = srcCamera.fieldOfView; } if (matchPosition) { destCamera.transform.position = srcCamera.transform.position; destCamera.transform.rotation = srcCamera.transform.rotation; } } } } [ExecuteAlways] public class MatchTransform : MonoBehaviour { public Transform targetTransform; public void LateUpdate() { UpdateNow(); } [ContextMenu("Update Now")] public void UpdateNow() { if ((bool)targetTransform) { base.transform.SetPositionAndRotation(targetTransform.position, targetTransform.rotation); } } } public class MeridianEventLightningTrigger : NetworkBehaviour { public GameObject lightningStorm; public CombatDirector enemySpawnerScript; public bool lightningToggle; public bool enemySpawnToggle; private float monsterCredit; [SerializeField] private float levelstartMonsterCredit; [SerializeField] private float expRewardCoefficient; [SerializeField] private float eliteBias; [SerializeField] private float spawnDistanceMultiplier; private void Start() { if (NetworkServer.active) { monsterCredit = (int)(levelstartMonsterCredit * Run.instance.difficultyCoefficient); } } public void OnTriggerExit(Collider other) { if (other.TryGetComponent(out var component) && component.isPlayerControlled) { LightningStormController.SetStormActive(lightningToggle); enemySpawnerScript.enabled = enemySpawnToggle; PopulateSceneWithMonsters(); UnityEngine.Object.Destroy(base.gameObject); } } private void PopulateSceneWithMonsters() { float num = enemySpawnerScript.expRewardCoefficient; float num2 = enemySpawnerScript.eliteBias; float num3 = enemySpawnerScript.spawnDistanceMultiplier; enemySpawnerScript.monsterCredit += monsterCredit; enemySpawnerScript.expRewardCoefficient = expRewardCoefficient; enemySpawnerScript.eliteBias = eliteBias; enemySpawnerScript.spawnDistanceMultiplier = spawnDistanceMultiplier; monsterCredit = 0f; enemySpawnerScript.SpendAllCreditsOnMapSpawns(TeleporterInteraction.instance ? TeleporterInteraction.instance.transform : null); enemySpawnerScript.expRewardCoefficient = num; enemySpawnerScript.eliteBias = num2; enemySpawnerScript.spawnDistanceMultiplier = num3; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } [Serializable] public struct GameObjectsToModify { public GameObject[] objects; public Material idleMaterial; public Material eventMaterial; } [RequireComponent(typeof(EntityStateMachine))] public class MeridianEventTriggerInteraction : NetworkBehaviour, IDisplayNameProvider { public enum RingFallingState { None, OuterRingFalling, MiddleRingFalling } public class MeridianEventBaseState : EntityState { protected MeridianEventTriggerInteraction meridianEventTriggerInteraction => instance; } public class MeridianEventStart : MeridianEventBaseState { public static event Action OnMeridianEventStart; public override void OnEnter() { base.OnEnter(); MeridianEventStart.OnMeridianEventStart?.Invoke(); base.meridianEventTriggerInteraction.EventPPVolume.SetActive(value: true); base.meridianEventTriggerInteraction.HandleNodeGateActivation(0); if (NetworkServer.active) { base.meridianEventTriggerInteraction.CallRpcSetEventMaterials(); } base.meridianEventTriggerInteraction.SetEventObjects(); base.meridianEventTriggerInteraction.isHeadRotating = true; outer.SetNextState(new Phase1()); } } public class FSBFEncounterBaseState : EntityState { protected ChildLocator childLocator; protected MeridianEventTriggerInteraction meridianEventTriggerInteraction => instance; public override void OnEnter() { base.OnEnter(); childLocator = GetComponent(); } public override void OnExit() { base.OnExit(); } public void KillAllMonsters() { if (!NetworkServer.active) { return; } foreach (TeamComponent item in new List(TeamComponent.GetTeamMembers(TeamIndex.Monster))) { if ((bool)item) { HealthComponent component = item.GetComponent(); if ((bool)component) { component.Suicide(); } } } } } public abstract class FSBFPhaseBaseState : FSBFEncounterBaseState { [NonSerialized] public static bool readyToSpawnNextBossBody; [SerializeField] public float durationBeforeEnablingCombatEncounter; [SerializeField] public float durationBeforeRingsSpawn; [SerializeField] public GameObject speechControllerPrefab; [SerializeField] public GameObject spawnVFX; protected ScriptedCombatEncounter phaseScriptedCombatEncounter; protected GameObject phaseControllerObject; protected GameObject phaseControllerSubObjectContainer; protected BossGroup phaseBossGroup; private bool hasSpawned; private bool spawnedNextState; private const float minimumDurationPerPhase = 2f; private Run.FixedTimeStamp healthBarShowTime = Run.FixedTimeStamp.positiveInfinity; protected abstract EntityState nextState { get; } protected abstract string phaseControllerChildString { get; } protected virtual float healthBarShowDelay => 0f; public override void OnEnter() { base.OnEnter(); if (!base.meridianEventTriggerInteraction.isFirstPhase) { speechControllerPrefab = base.meridianEventTriggerInteraction.falseSonBoss1PhaseSpeechController; base.meridianEventTriggerInteraction.isFirstPhase = true; } else if (!base.meridianEventTriggerInteraction.isFinalPhase) { speechControllerPrefab = base.meridianEventTriggerInteraction.falseSonBossEarlySpeechController; } else { speechControllerPrefab = base.meridianEventTriggerInteraction.falseSonBossLateSpeechController; } if ((bool)childLocator) { phaseControllerObject = childLocator.FindChild(phaseControllerChildString).gameObject; if ((bool)phaseControllerObject) { phaseScriptedCombatEncounter = phaseControllerObject.GetComponent(); phaseBossGroup = phaseControllerObject.GetComponent(); } } healthBarShowTime = Run.FixedTimeStamp.now + healthBarShowDelay; if ((bool)DirectorCore.instance) { CombatDirector[] components = DirectorCore.instance.GetComponents(); for (int i = 0; i < components.Length; i++) { components[i].enabled = false; } } if (NetworkServer.active && (object)phaseScriptedCombatEncounter != null) { phaseScriptedCombatEncounter.combatSquad.onMemberAddedServer += OnMemberAddedServer; } } public override void OnExit() { if (NetworkServer.active) { if ((object)phaseScriptedCombatEncounter != null) { phaseScriptedCombatEncounter.combatSquad.onMemberAddedServer -= OnMemberAddedServer; } if ((bool)phaseControllerSubObjectContainer) { phaseControllerSubObjectContainer.SetActive(value: false); } } if ((bool)phaseBossGroup) { phaseBossGroup.shouldDisplayHealthBarOnHud = false; } base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); phaseBossGroup.shouldDisplayHealthBarOnHud = healthBarShowTime.hasPassed; if (!hasSpawned && readyToSpawnNextBossBody && base.fixedAge > durationBeforeEnablingCombatEncounter) { BeginEncounter(); } else if (hasSpawned && readyToSpawnNextBossBody && !spawnedNextState && base.fixedAge > 2f + durationBeforeEnablingCombatEncounter && (bool)phaseScriptedCombatEncounter && phaseScriptedCombatEncounter.combatSquad.memberCount == 0) { spawnedNextState = true; outer.SetNextState(nextState); } } protected void BeginEncounter() { readyToSpawnNextBossBody = false; hasSpawned = true; PreEncounterBegin(); if (NetworkServer.active) { phaseScriptedCombatEncounter.BeginEncounter(); } } protected virtual void PreEncounterBegin() { } protected virtual void OnMemberAddedServer(CharacterMaster master) { if ((bool)speechControllerPrefab) { UnityEngine.Object.Instantiate(speechControllerPrefab, master.transform).GetComponent().characterMaster = master; } } } public class Phase1 : FSBFPhaseBaseState { private bool spawnedEntryFX; private bool lightningStarted; protected override string phaseControllerChildString => "Phase1"; protected override EntityState nextState => new Phase2(); public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > 15f && !lightningStarted) { lightningStarted = true; base.meridianEventTriggerInteraction.arenaGeode3.SetActive(value: true); base.meridianEventTriggerInteraction.arenaGeode4.SetActive(value: true); } if (!spawnedEntryFX && base.fixedAge > base.meridianEventTriggerInteraction.additionalEntryVFXDelay + durationBeforeEnablingCombatEncounter) { spawnedEntryFX = true; SetPlayersInvulnerable(b: false); EffectManager.SpawnEffect(base.meridianEventTriggerInteraction.falseSonEntryFX, new EffectData { origin = base.meridianEventTriggerInteraction.falseSonEntryFXPosition.position }, transmit: false); base.meridianEventTriggerInteraction.musicPhaseNone.SetActive(value: false); base.meridianEventTriggerInteraction.musicPhaseOne.SetActive(value: true); } if (spawnedEntryFX && base.meridianEventTriggerInteraction.meridianColumnsGameObject.activeInHierarchy && !base.meridianEventTriggerInteraction.meridianPlayableColumns.activeInHierarchy && base.fixedAge > base.meridianEventTriggerInteraction.additionalEntryVFXDelay + durationBeforeEnablingCombatEncounter + 3f) { base.meridianEventTriggerInteraction.meridianColumnsGameObject.SetActive(value: false); base.meridianEventTriggerInteraction.meridianPlayableColumns.SetActive(value: true); } } public override void OnEnter() { base.meridianEventTriggerInteraction.onFalseSonAppearance.SetActive(value: true); base.meridianEventTriggerInteraction.HandleNodeGateActivation(0); durationBeforeEnablingCombatEncounter = 7f; KillAllMonsters(); base.OnEnter(); FSBFPhaseBaseState.readyToSpawnNextBossBody = true; Util.PlaySound("Play_boss_falseson_VO_spawn", base.gameObject); base.meridianEventTriggerInteraction.Boundary1.SetActive(value: true); if (NetworkServer.active) { SetPlayersInvulnerable(b: true); } } protected override void OnMemberAddedServer(CharacterMaster master) { base.OnMemberAddedServer(master); } } public class Phase2 : FSBFPhaseBaseState { private bool startRingsFalling; protected override string phaseControllerChildString => "Phase2"; protected override EntityState nextState => new Phase3(); public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > durationBeforeRingsSpawn && !startRingsFalling) { base.meridianEventTriggerInteraction.Boundary1.SetActive(value: false); base.meridianEventTriggerInteraction.Boundary2.SetActive(value: true); base.meridianEventTriggerInteraction.StartOuterRingFalling(); base.meridianEventTriggerInteraction.arenaGeode3.SetActive(value: false); startRingsFalling = true; } } public override void OnEnter() { base.meridianEventTriggerInteraction.onEnteringPhase2.SetActive(value: true); base.meridianEventTriggerInteraction.HandleNodeGateActivation(1); base.meridianEventTriggerInteraction.phase2CombatDirector.SetActive(value: true); durationBeforeEnablingCombatEncounter = 1f; durationBeforeRingsSpawn = 1.75f; childLocator = GetComponent(); phaseControllerObject = childLocator.FindChild(phaseControllerChildString).gameObject; Util.PlaySound("Play_boss_falseson_VO_spawn", base.gameObject); Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject); base.OnEnter(); SetPlayersInvulnerable(b: false); } public override void OnExit() { base.meridianEventTriggerInteraction.isFinalPhase = true; base.meridianEventTriggerInteraction.phase2CombatDirector.SetActive(value: false); KillAllMonsters(); base.OnExit(); } protected override void OnMemberAddedServer(CharacterMaster master) { base.OnMemberAddedServer(master); } } public class Phase3 : FSBFPhaseBaseState { private bool startRingsFalling; protected override string phaseControllerChildString => "Phase3"; protected override EntityState nextState => new MeridianEventCleared(); public override void FixedUpdate() { base.FixedUpdate(); if (base.fixedAge > durationBeforeRingsSpawn && !startRingsFalling) { base.meridianEventTriggerInteraction.Boundary2.SetActive(value: false); base.meridianEventTriggerInteraction.Boundary3.SetActive(value: true); base.meridianEventTriggerInteraction.StartMiddleRingFalling(); base.meridianEventTriggerInteraction.arenaGeode4.SetActive(value: false); startRingsFalling = true; } } public override void OnEnter() { speechControllerPrefab = base.meridianEventTriggerInteraction.falseSonBossLateSpeechController; if (NetworkServer.active) { LightningStormController.SetStormStrikePattern(base.meridianEventTriggerInteraction.bossLightningStrikePattern); LightningStormController.SetStormActive(b: true); } base.meridianEventTriggerInteraction.onEnteringPhase3.SetActive(value: true); base.meridianEventTriggerInteraction.HandleNodeGateActivation(2); durationBeforeEnablingCombatEncounter = 1f; durationBeforeRingsSpawn = 1.75f; childLocator = GetComponent(); phaseControllerObject = childLocator.FindChild(phaseControllerChildString).gameObject; GoldTitanManager.onGoldTitanSpawned += IsAurelionitePresent; Util.PlaySound("Play_boss_falseson_VO_spawn", base.gameObject); base.OnEnter(); } public override void OnExit() { base.OnExit(); GoldTitanManager.onGoldTitanSpawned -= IsAurelionitePresent; } protected override void OnMemberAddedServer(CharacterMaster master) { base.OnMemberAddedServer(master); } private void IsAurelionitePresent() { instance.isGoldTitanSpawned = true; } } public class MeridianEventCleared : MeridianEventBaseState { public override void OnEnter() { base.OnEnter(); base.meridianEventTriggerInteraction.EventCompletePPVolume.SetActive(value: true); base.meridianEventTriggerInteraction.EventPPVolume.SetActive(value: false); base.meridianEventTriggerInteraction.shrineModel.SetActive(value: true); base.meridianEventTriggerInteraction.shrine.GetComponent().stateMachine.SetNextStateToMain(); base.meridianEventTriggerInteraction.finalPillars.SetActive(value: true); base.meridianEventTriggerInteraction.meridianRain.SetActive(value: false); base.meridianEventTriggerInteraction.meridianStormCloud.SetActive(value: false); base.meridianEventTriggerInteraction.eventClearedVFX.SetActive(value: true); base.meridianEventTriggerInteraction.arenaGeode1.SetActive(value: false); base.meridianEventTriggerInteraction.arenaGeode2.SetActive(value: false); base.meridianEventTriggerInteraction.bossFightAMB.Stop(base.gameObject); base.meridianEventTriggerInteraction.bossDefeatAMB.Post(base.gameObject); Util.PlaySound("Play_env_meridian_level_cleared", base.gameObject); if (!NetworkServer.active) { return; } GameObject[] destinationPortals = base.meridianEventTriggerInteraction.destinationPortals; for (int i = 0; i < destinationPortals.Length; i++) { destinationPortals[i].SetActive(value: true); } foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (!(instance == null)) { CharacterBody body = instance.master.GetBody(); if (!(body == null)) { Util.CleanseBody(body, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: false, removeDots: false, removeStun: false, removeNearbyProjectiles: false); } } } } } [HideInInspector] public static Transform bossTransform; public string contextToken = "MERIDIAN_EVENTTRIGGER_CONTEXT"; public string displayNameToken = "MERIDIAN_EVENTTRIGGER_NAME"; public int minimumNumberToSpawnPerMonsterType; public int maximumNumberToSpawnBeforeSkipping; public GameObject eventGateStateObject; public GameObject eventGateStatePhase2Object; public GameObject eventGateStatePhase3Object; public CombatDirector combatDirectorWave1; public CombatDirector combatDirectorWave2; public SceneExitController sceneExitController; [Header("Post Process Volumes")] public GameObject EventPPVolume; public GameObject EventCompletePPVolume; public GameObject AfterEventCompletePPVolume; [Header("Destination Portals")] public GameObject[] destinationPortals; [Header("Colossus Head")] public GameObject colossusHead; public Transform colossusHeadFinalPosition; public float colossusHeadDuration = 420f; private bool isHeadRotating; [Header("False Son Core")] public GameObject falseSonCore; [Header("Game Objects to Modify")] public GameObjectsToModify[] gameObjectsToModify; [Header("Event Objects to Toggle")] public GameObject[] eventGameObjectsToToggle; [Header("Cleaered Objects to Toggle")] public GameObject[] clearedGameObjectsToToggle; [Header("False Son Boss Encounter")] public ScriptedCombatEncounter falseSonBossEncounter; public BossGroup falseSonBossGroup; public CombatDirector combatDirector; [Header("Teleport Locs")] public GameObject playerTPLoc1; public GameObject playerTPLoc2; public GameObject playerTPLoc3; public GameObject playerTPLoc4; private GameObject[] playerTPLocs = new GameObject[4]; [Header("Cutscene")] public GameObject cutsceneCamera; public AK.Wwise.Event startSceneAMB; public AK.Wwise.Event bossFightAMB; public AK.Wwise.Event bossDefeatAMB; [Header("Boss Music Phases")] public GameObject musicPhaseNone; public GameObject musicPhaseOne; public GameObject musicPhaseTwo; public GameObject musicPhaseThree; public GameObject musicPhaseBossDead; [Header("Arena Setup")] public GameObject lightningStorm; public GameObject fog; public GameObject sceneBoundsOld; public GameObject sceneBoundsNew; public GameObject meridianColumnsGameObject; public GameObject meridianPlayableColumns; public LightningStrikePattern bossLightningStrikePattern; [Header("Phase 1 Spawn FX Data")] [SerializeField] [HideInInspector] public GameObject falseSonEntryFX; [SerializeField] public Transform falseSonEntryFXPosition; [SerializeField] public float additionalEntryVFXDelay; [Header("In-Scene Phase Transition VFX - should automatically disable itself")] public GameObject onFalseSonAppearance; public GameObject onEnteringPhase2; public GameObject onEnteringPhase3; [Space(20f)] public float ringFallOffTime = 50f; [HideInInspector] public int ringFallingState; private int localRingFallingState; [Header("Rings Locs")] public GameObject ringPiece1; public GameObject ringPiece2; public GameObject ringPiece3; public GameObject ringPiece4; public GameObject ringPiece5; public GameObject ringPiece6; public GameObject ringPiece7; public GameObject ringPiece8; public GameObject ringPiece9; public GameObject ringPiece10; public GameObject ringPiece1FinalPosition; public GameObject ringPiece2FinalPosition; public GameObject ringPiece3FinalPosition; public GameObject ringPiece4FinalPosition; public GameObject ringPiece5FinalPosition; public GameObject ringPiece6FinalPosition; public GameObject ringPiece7FinalPosition; public GameObject ringPiece8FinalPosition; public GameObject ringPiece9FinalPosition; public GameObject ringPiece10FinalPosition; [Header("Arena Finale")] public GameObject shrine; public GameObject shrineModel; public GameObject finalPillars; public GameObject eventClearedVFX; public GameObject meridianRain; public GameObject meridianStormCloud; [Header("Geode System")] public GameObject arenaGeode1; public GameObject arenaGeode2; public GameObject arenaGeode3; public GameObject arenaGeode4; [Header("Boss Bounds System")] public GameObject Boundary1; public GameObject Boundary2; public GameObject Boundary3; [Header("Boss Dialogue Prefabs")] public GameObject falseSonBossEarlySpeechController; public GameObject falseSonBossLateSpeechController; public GameObject falseSonBoss1PhaseSpeechController; [HideInInspector] public bool isFirstPhase; [HideInInspector] public bool isFinalPhase; [HideInInspector] public bool isGoldTitanSpawned; [Header("Monster Waves Combat Director Prefabs")] public GameObject phase2CombatDirector; private EntityStateMachine mainStateMachine; private bool triggerEventClear; [SyncVar(hook = "Client_HandleStartMeridianEvent")] public bool isTriggered; private static int kRpcRpcTeleportWithLocalAuthority; private static int kRpcRpcOnFalseSonDefeated; private static int kRpcRpcSetEventMaterials; public static MeridianEventTriggerInteraction instance { get; private set; } protected MeridianEventTriggerInteraction eventTriggerInteraction { get; private set; } public bool NetworkisTriggered { get { return isTriggered; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; Client_HandleStartMeridianEvent(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref isTriggered, 1u); } } public static event Action onDefeatedServerGlobal; public static event Action onActivated; public static event Action onInstanceChangedGlobal; public string GetContextString(Interactor activator) { return Language.GetString(contextToken); } public override int GetNetworkChannel() { return QosChannelIndex.defaultReliable.intVal; } public Interactability GetInteractability(Interactor activator) { if (isTriggered) { return Interactability.Disabled; } return Interactability.Available; } public string GetDisplayName() { return Language.GetString(displayNameToken); } public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator) { return false; } public bool ShouldShowOnScanner() { return !isTriggered; } private void Start() { eventTriggerInteraction = GetComponent(); } public void OnEnable() { instance = SingletonHelper.Assign(instance, this); MeridianEventTriggerInteraction.onInstanceChangedGlobal?.Invoke(); if (falseSonEntryFX == null) { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("FalseSonBoss/FalseSonBossAppearVFX"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle result) { falseSonEntryFX = result.Result; }; } } public void OnDisable() { instance = SingletonHelper.Unassign(instance, this); MeridianEventTriggerInteraction.onInstanceChangedGlobal?.Invoke(); } [Server] public override void OnStartServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MeridianEventTriggerInteraction::OnStartServer()' called on client"); return; } base.OnStartServer(); startSceneAMB.Post(base.gameObject); } public void OnTriggerEnter(Collider other) { if (NetworkServer.active && !isTriggered && other.TryGetComponent(out var component) && component.isPlayerControlled) { HandleInitializeMeridianEvent(); } } public static void SetPlayersInvulnerable(bool b) { if (!NetworkServer.active) { return; } foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (instance == null) { continue; } CharacterBody body = instance.master.GetBody(); if (!(body == null)) { if (b) { body.AddTimedBuff(DLC2Content.Buffs.HiddenRejectAllDamage, 1.5f); } else if (body.HasBuff(DLC2Content.Buffs.HiddenRejectAllDamage)) { body.RemoveBuff(DLC2Content.Buffs.HiddenRejectAllDamage); } } } } [Server] private void HandleInitializeMeridianEvent() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MeridianEventTriggerInteraction::HandleInitializeMeridianEvent()' called on client"); return; } LightningStormController.SetStormActive(b: false); combatDirector.enabled = false; playerTPLocs[0] = playerTPLoc1; playerTPLocs[1] = playerTPLoc2; playerTPLocs[2] = playerTPLoc3; playerTPLocs[3] = playerTPLoc4; int num = 0; int num2 = 0; int count = PlayerCharacterMasterController.instances.Count; bool flag = count > 4; foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (instance == null) { continue; } UnityEngine.Vector3 vector; UnityEngine.Quaternion rotation; if (flag) { int num3 = playerTPLocs.Length - 1; float num4 = (float)num2 / (float)(count - 1) * (float)num3; int num5 = Mathf.Clamp(Mathf.FloorToInt(num4), 0, num3 - 1); float t = num4 - (float)num5; Transform obj = playerTPLocs[num5].transform; Transform transform = playerTPLocs[num5 + 1].transform; vector = UnityEngine.Vector3.Lerp(obj.position, transform.position, t); rotation = UnityEngine.Quaternion.Lerp(obj.rotation, transform.rotation, t); } else { int num6 = num2; if (playerTPLocs[num6] == null) { num6 = num; } Transform obj2 = playerTPLocs[num6].transform; vector = obj2.position; rotation = obj2.rotation; } CharacterBody body = instance.master.GetBody(); if (!(body == null)) { body.currentVehicle?.EjectPassenger(); if (Util.HasEffectiveAuthority(body.gameObject)) { TeleportHelper.TeleportBody(body, vector); } else { CallRpcTeleportWithLocalAuthority(body.gameObject, vector, rotation); } num2++; } } NetworkisTriggered = true; } [ClientRpc] private void RpcTeleportWithLocalAuthority(GameObject playerObject, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation) { if (Util.HasEffectiveAuthority(playerObject)) { CharacterBody component = playerObject.GetComponent(); if (component == null) { UnityEngine.Debug.LogWarning("Received RPCTeleport request but the game object doesn't have a CharacterBody! " + playerObject.name, playerObject); } else { TeleportHelper.TeleportBody(component, position); } } } [Client] private void Client_HandleStartMeridianEvent(bool newValue) { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.MeridianEventTriggerInteraction::Client_HandleStartMeridianEvent(System.Boolean)' called on server"); return; } NetworkisTriggered = newValue; HandleStartMeridianEvent(); } private void HandleStartMeridianEvent() { fog.SetActive(value: true); sceneBoundsOld.SetActive(value: false); sceneBoundsNew.SetActive(value: true); startSceneAMB.Stop(base.gameObject); bossFightAMB.Post(base.gameObject); musicPhaseNone.SetActive(value: true); cutsceneCamera.SetActive(value: true); Util.PlaySound("Play_env_meridian_activate_boss_cutscene", base.gameObject); LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); if (firstLocalUser != null && firstLocalUser.cachedBody != null) { string bodyName = BodyCatalog.GetBodyName(firstLocalUser.cachedBody.bodyIndex); firstLocalUser.userProfile.HasAchievement(bodyName.Substring(0, bodyName.Length - 4) + "ClearMeridianEvent"); } mainStateMachine.SetNextState(new MeridianEventStart()); } private IEnumerator RotateHead() { float timeElapsed = 0f; while (timeElapsed < colossusHeadDuration) { colossusHead.transform.rotation = UnityEngine.Quaternion.Lerp(colossusHead.transform.rotation, colossusHeadFinalPosition.rotation, timeElapsed / colossusHeadDuration); ringPiece1.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece1.transform.rotation, ringPiece1FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 20f)); ringPiece2.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece2.transform.rotation, ringPiece2FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 22f)); ringPiece3.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece3.transform.rotation, ringPiece3FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 25f)); ringPiece4.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece4.transform.rotation, ringPiece4FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 26f)); ringPiece5.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece5.transform.rotation, ringPiece5FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 19f)); ringPiece1.transform.position = UnityEngine.Vector3.Lerp(ringPiece1.transform.position, ringPiece1FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 20f)); ringPiece2.transform.position = UnityEngine.Vector3.Lerp(ringPiece2.transform.position, ringPiece2FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 22f)); ringPiece3.transform.position = UnityEngine.Vector3.Lerp(ringPiece3.transform.position, ringPiece3FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 25f)); ringPiece4.transform.position = UnityEngine.Vector3.Lerp(ringPiece4.transform.position, ringPiece4FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 26f)); ringPiece5.transform.position = UnityEngine.Vector3.Lerp(ringPiece5.transform.position, ringPiece5FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 19f)); ringPiece6.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece6.transform.rotation, ringPiece6FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration); ringPiece7.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece7.transform.rotation, ringPiece7FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration); ringPiece8.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece8.transform.rotation, ringPiece8FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration); ringPiece9.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece9.transform.rotation, ringPiece9FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration); ringPiece10.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece10.transform.rotation, ringPiece10FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration); ringPiece6.transform.position = UnityEngine.Vector3.Lerp(ringPiece6.transform.position, ringPiece6FinalPosition.transform.position, timeElapsed / colossusHeadDuration); ringPiece7.transform.position = UnityEngine.Vector3.Lerp(ringPiece7.transform.position, ringPiece7FinalPosition.transform.position, timeElapsed / colossusHeadDuration); ringPiece8.transform.position = UnityEngine.Vector3.Lerp(ringPiece8.transform.position, ringPiece8FinalPosition.transform.position, timeElapsed / colossusHeadDuration); ringPiece9.transform.position = UnityEngine.Vector3.Lerp(ringPiece9.transform.position, ringPiece9FinalPosition.transform.position, timeElapsed / colossusHeadDuration); ringPiece10.transform.position = UnityEngine.Vector3.Lerp(ringPiece10.transform.position, ringPiece10FinalPosition.transform.position, timeElapsed / colossusHeadDuration); timeElapsed += Time.deltaTime; yield return null; } } private void StartOuterRingFalling() { ringFallingState = Mathf.Max(1, ringFallingState); Util.PlaySound("Play_env_meridian_level_ring_fall", base.gameObject); } private void StartMiddleRingFalling() { ringFallingState = Mathf.Max(2, ringFallingState); Util.PlaySound("Play_env_meridian_level_ring_fall", base.gameObject); } private IEnumerator OuterRingFalling() { float timeElapsed = 0f; while (timeElapsed < ringFallOffTime) { ringPiece6.transform.position = UnityEngine.Vector3.Lerp(ringPiece6.transform.position, ringPiece6.transform.position - new UnityEngine.Vector3(0f, 100f, 0f), timeElapsed / ringFallOffTime); ringPiece7.transform.position = UnityEngine.Vector3.Lerp(ringPiece7.transform.position, ringPiece7.transform.position - new UnityEngine.Vector3(0f, 230f, 0f), timeElapsed / ringFallOffTime); ringPiece8.transform.position = UnityEngine.Vector3.Lerp(ringPiece8.transform.position, ringPiece8.transform.position - new UnityEngine.Vector3(0f, 120f, 0f), timeElapsed / ringFallOffTime); ringPiece9.transform.position = UnityEngine.Vector3.Lerp(ringPiece9.transform.position, ringPiece9.transform.position - new UnityEngine.Vector3(0f, 350f, 0f), timeElapsed / ringFallOffTime); ringPiece10.transform.position = UnityEngine.Vector3.Lerp(ringPiece10.transform.position, ringPiece10.transform.position - new UnityEngine.Vector3(0f, 130f, 0f), timeElapsed / ringFallOffTime); timeElapsed += Time.deltaTime; yield return null; } ringPiece6.SetActive(value: false); ringPiece7.SetActive(value: false); ringPiece8.SetActive(value: false); ringPiece9.SetActive(value: false); ringPiece10.SetActive(value: false); } private IEnumerator MiddleRingFalling() { float timeElapsed = 0f; while (timeElapsed < ringFallOffTime) { ringPiece1.transform.position = UnityEngine.Vector3.Lerp(ringPiece1.transform.position, ringPiece1.transform.position - new UnityEngine.Vector3(0f, 120f, 0f), timeElapsed / ringFallOffTime); ringPiece2.transform.position = UnityEngine.Vector3.Lerp(ringPiece2.transform.position, ringPiece2.transform.position - new UnityEngine.Vector3(0f, 110f, 0f), timeElapsed / ringFallOffTime); ringPiece3.transform.position = UnityEngine.Vector3.Lerp(ringPiece3.transform.position, ringPiece3.transform.position - new UnityEngine.Vector3(0f, 350f, 0f), timeElapsed / ringFallOffTime); ringPiece4.transform.position = UnityEngine.Vector3.Lerp(ringPiece4.transform.position, ringPiece4.transform.position - new UnityEngine.Vector3(0f, 130f, 0f), timeElapsed / ringFallOffTime); ringPiece5.transform.position = UnityEngine.Vector3.Lerp(ringPiece5.transform.position, ringPiece5.transform.position - new UnityEngine.Vector3(0f, 470f, 0f), timeElapsed / ringFallOffTime); timeElapsed += Time.deltaTime; yield return null; } ringPiece1.SetActive(value: false); ringPiece2.SetActive(value: false); ringPiece3.SetActive(value: false); ringPiece4.SetActive(value: false); ringPiece5.SetActive(value: false); } public void TriggerEventClear() { triggerEventClear = true; } public void Update() { if (isHeadRotating) { StartCoroutine(RotateHead()); cutsceneCamera.SetActive(value: true); isHeadRotating = false; } if (ringFallingState > localRingFallingState) { if (ringFallingState == 1) { StartCoroutine(OuterRingFalling()); } else if (ringFallingState == 2) { StartCoroutine(MiddleRingFalling()); } localRingFallingState = ringFallingState; } if (triggerEventClear && NetworkServer.active) { CallRpcOnFalseSonDefeated(); triggerEventClear = false; } } private void Awake() { mainStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Main"); if (NetworkServer.active) { SkyJumpDeathState.falseSonDeathEvent += TriggerEventClear; } GameObject[] array = destinationPortals; for (int i = 0; i < array.Length; i++) { array[i].SetActive(value: false); } } [ClientRpc] private void RpcOnFalseSonDefeated() { EventCompletePPVolume.SetActive(value: true); EventPPVolume.SetActive(value: false); if (AfterEventCompletePPVolume != null) { AfterEventCompletePPVolume.SetActive(value: true); } SetIdleMaterials(); SetClearedObjects(); } private void Wave1OnDefeatedServer() { combatDirectorWave2.enabled = true; combatDirectorWave2.currentSpawnTarget = base.gameObject; combatDirectorWave2.monsterCredit += (int)(600f * Mathf.Pow(Run.instance.compensatedDifficultyCoefficient, 0.5f)); } private void Wave2OnDefeatedServer() { mainStateMachine.SetNextState(new MeridianEventCleared()); } private void SetEventObjects() { for (int i = 0; i < eventGameObjectsToToggle.Length; i++) { if (!(eventGameObjectsToToggle[i] == null)) { bool activeInHierarchy = eventGameObjectsToToggle[i].activeInHierarchy; eventGameObjectsToToggle[i].SetActive(!activeInHierarchy); } } } private void HandleNodeGateActivation(int currentState) { eventGateStateObject.SetActive(currentState <= 0); eventGateStatePhase2Object.SetActive(currentState <= 1); eventGateStatePhase3Object.SetActive(currentState <= 2); } private void SetClearedObjects() { for (int i = 0; i < clearedGameObjectsToToggle.Length; i++) { if (!(clearedGameObjectsToToggle[i] == null)) { bool activeInHierarchy = clearedGameObjectsToToggle[i].activeInHierarchy; clearedGameObjectsToToggle[i].SetActive(!activeInHierarchy); } } } [ClientRpc] private void RpcSetEventMaterials() { for (int i = 0; i < gameObjectsToModify.Length; i++) { GameObject[] objects = gameObjectsToModify[i].objects; foreach (GameObject gameObject in objects) { if (!(gameObject == null) && gameObject.TryGetComponent(out var component)) { component.material = gameObjectsToModify[i].eventMaterial; } } } } private void SetIdleMaterials() { for (int i = 0; i < gameObjectsToModify.Length; i++) { GameObject[] objects = gameObjectsToModify[i].objects; foreach (GameObject gameObject in objects) { if (!(gameObject == null)) { gameObject.GetComponent().material = gameObjectsToModify[i].idleMaterial; } } } } private void UNetVersion() { } protected static void InvokeRpcRpcTeleportWithLocalAuthority(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcTeleportWithLocalAuthority called on server."); } else { ((MeridianEventTriggerInteraction)obj).RpcTeleportWithLocalAuthority(reader.ReadGameObject(), reader.ReadVector3(), reader.ReadQuaternion()); } } protected static void InvokeRpcRpcOnFalseSonDefeated(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcOnFalseSonDefeated called on server."); } else { ((MeridianEventTriggerInteraction)obj).RpcOnFalseSonDefeated(); } } protected static void InvokeRpcRpcSetEventMaterials(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcSetEventMaterials called on server."); } else { ((MeridianEventTriggerInteraction)obj).RpcSetEventMaterials(); } } public void CallRpcTeleportWithLocalAuthority(GameObject playerObject, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcTeleportWithLocalAuthority called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcTeleportWithLocalAuthority); networkWriter.Write(GetComponent().netId); networkWriter.Write(playerObject); networkWriter.Write(position); networkWriter.Write(rotation); SendRPCInternal(networkWriter, 0, "RpcTeleportWithLocalAuthority"); } public void CallRpcOnFalseSonDefeated() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcOnFalseSonDefeated called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnFalseSonDefeated); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcOnFalseSonDefeated"); } public void CallRpcSetEventMaterials() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcSetEventMaterials called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcSetEventMaterials); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcSetEventMaterials"); } static MeridianEventTriggerInteraction() { kRpcRpcTeleportWithLocalAuthority = -40849326; NetworkBehaviour.RegisterRpcDelegate(typeof(MeridianEventTriggerInteraction), kRpcRpcTeleportWithLocalAuthority, InvokeRpcRpcTeleportWithLocalAuthority); kRpcRpcOnFalseSonDefeated = 1048548329; NetworkBehaviour.RegisterRpcDelegate(typeof(MeridianEventTriggerInteraction), kRpcRpcOnFalseSonDefeated, InvokeRpcRpcOnFalseSonDefeated); kRpcRpcSetEventMaterials = 1585739; NetworkBehaviour.RegisterRpcDelegate(typeof(MeridianEventTriggerInteraction), kRpcRpcSetEventMaterials, InvokeRpcRpcSetEventMaterials); NetworkCRC.RegisterBehaviour("MeridianEventTriggerInteraction", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(isTriggered); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(isTriggered); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { isTriggered = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { Client_HandleStartMeridianEvent(reader.ReadBoolean()); } } public override void PreStartClient() { } } public class MeridianSpawnPointGenerator : MonoBehaviour { [SerializeField] private Transform playerSpawnPoint; private void OnEnable() { SceneDirector.onPreGeneratePlayerSpawnPointsServer += OnPreGeneratePlayerSpawnPointsServer; } private void OnDisable() { SceneDirector.onPreGeneratePlayerSpawnPointsServer -= OnPreGeneratePlayerSpawnPointsServer; } private void OnPreGeneratePlayerSpawnPointsServer(SceneDirector sceneDirector, ref Action generationMethod) { generationMethod = GeneratePlayerSpawnPointsServer; } private void GeneratePlayerSpawnPointsServer() { if (SpawnPoint.readOnlyInstancesList.Count > 3 || playerSpawnPoint == null) { return; } UnityEngine.Vector3 position = playerSpawnPoint.position; NodeGraph groundNodes = SceneInfo.instance.groundNodes; if (!groundNodes) { UnityEngine.Debug.LogError("MeridianSpawnPointGenerator.GeneratePlayerSpawnPointsServer: No ground nodegraph found to place spawn points.", this); return; } NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(groundNodes, HullMask.Human); nodeGraphSpider.AddNodeForNextStep(groundNodes.FindClosestNode(position, HullClassification.Human)); for (int i = 0; i < 4; i++) { nodeGraphSpider.PerformStep(); if (nodeGraphSpider.collectedSteps.Count > 16) { break; } } for (int j = 0; j < nodeGraphSpider.collectedSteps.Count; j++) { NodeGraphSpider.StepInfo stepInfo = nodeGraphSpider.collectedSteps[j]; groundNodes.GetNodePosition(stepInfo.node, out var position2); UnityEngine.Quaternion rotation = playerSpawnPoint.rotation; SpawnPoint.AddSpawnPoint(position2, rotation); } } } public class MeteorController : NetworkBehaviour { public GameObject meteorTest1; public GameObject meteorTest2; public GameObject meteorTest3; private ParticleSystem meteorTest1ps; private ParticleSystem meteorTest2ps; private ParticleSystem meteorTest3ps; public ShakeEmitter shakeEmitter; private bool meteorTimerOn; private float meteorTimer; private float meteorDuration = 30f; private void Awake() { meteorTest1ps = meteorTest1.GetComponent(); meteorTest2ps = meteorTest2.GetComponent(); meteorTest3ps = meteorTest3.GetComponent(); meteorTest1.SetActive(value: false); meteorTest2.SetActive(value: false); meteorTest3.SetActive(value: false); } private void Start() { } private void ActivateMeteors(bool value) { meteorTest1.SetActive(value); meteorTest2.SetActive(value); meteorTest3.SetActive(value); } private void Update() { if ((double)Run.instance.GetRunStopwatch() - Math.Floor(Run.instance.GetRunStopwatch() * (1f / 60f)) * 60.0 <= 0.1 && !meteorTimerOn) { meteorTimerOn = true; ActivateMeteors(value: true); } if (meteorTimerOn) { meteorTimer += Time.fixedDeltaTime; } if (meteorTimer >= meteorDuration) { meteorTimerOn = false; meteorTimer = 0f; ActivateMeteors(value: false); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class MeteorStormController : MonoBehaviour { private class Meteor { public UnityEngine.Vector3 impactPosition; public float startTime; public bool didTravelEffect; public bool valid = true; } private class MeteorWave { private readonly CharacterBody[] targets; private int currentStep; private float hitChance = 0.4f; private readonly UnityEngine.Vector3 center; public float timer; private NodeGraphSpider nodeGraphSpider; public MeteorWave(CharacterBody[] targets, UnityEngine.Vector3 center) { this.targets = new CharacterBody[targets.Length]; targets.CopyTo(this.targets, 0); Util.ShuffleArray(targets); this.center = center; nodeGraphSpider = new NodeGraphSpider(SceneInfo.instance.groundNodes, HullMask.Human); nodeGraphSpider.AddNodeForNextStep(SceneInfo.instance.groundNodes.FindClosestNode(center, HullClassification.Human)); int i = 0; for (int num = 20; i < num; i++) { if (!nodeGraphSpider.PerformStep()) { break; } } } public Meteor GetNextMeteor() { if (currentStep >= targets.Length) { return null; } CharacterBody characterBody = targets[currentStep]; Meteor meteor = new Meteor(); if ((bool)characterBody && UnityEngine.Random.value < hitChance) { meteor.impactPosition = characterBody.corePosition; UnityEngine.Vector3 origin = meteor.impactPosition + UnityEngine.Vector3.up * 6f; UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere; onUnitSphere.y = -1f; if (Physics.Raycast(origin, onUnitSphere, out var hitInfo, 12f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { meteor.impactPosition = hitInfo.point; } else if (Physics.Raycast(meteor.impactPosition, UnityEngine.Vector3.down, out hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore)) { meteor.impactPosition = hitInfo.point; } } else if (nodeGraphSpider.collectedSteps.Count != 0) { int index = UnityEngine.Random.Range(0, nodeGraphSpider.collectedSteps.Count); SceneInfo.instance.groundNodes.GetNodePosition(nodeGraphSpider.collectedSteps[index].node, out meteor.impactPosition); } else { meteor.valid = false; } meteor.startTime = Run.instance.time; currentStep++; return meteor; } } public int waveCount; public float waveMinInterval; public float waveMaxInterval; public GameObject warningEffectPrefab; public GameObject travelEffectPrefab; public float travelEffectDuration; public GameObject impactEffectPrefab; public float impactDelay; public float blastDamageCoefficient; public float blastRadius; public float blastForce; public DamageTypeCombo blastDamageType; [NonSerialized] public GameObject owner; [NonSerialized] public float ownerDamage; [NonSerialized] public bool isCrit; public UnityEvent onDestroyEvents; private List meteorList; private List waveList; private int wavesPerformed; private float waveTimer; private void Start() { if (NetworkServer.active) { meteorList = new List(); waveList = new List(); } } private void FixedUpdate() { if (!NetworkServer.active) { return; } waveTimer -= Time.fixedDeltaTime; if (waveTimer <= 0f && wavesPerformed < waveCount) { wavesPerformed++; waveTimer = UnityEngine.Random.Range(waveMinInterval, waveMaxInterval); MeteorWave item = new MeteorWave(CharacterBody.readOnlyInstancesList.ToArray(), base.transform.position); waveList.Add(item); } for (int num = waveList.Count - 1; num >= 0; num--) { MeteorWave meteorWave = waveList[num]; meteorWave.timer -= Time.fixedDeltaTime; if (meteorWave.timer <= 0f) { meteorWave.timer = UnityEngine.Random.Range(0.05f, 1f); Meteor nextMeteor = meteorWave.GetNextMeteor(); if (nextMeteor == null) { waveList.RemoveAt(num); } else if (nextMeteor.valid) { meteorList.Add(nextMeteor); EffectManager.SpawnEffect(warningEffectPrefab, new EffectData { origin = nextMeteor.impactPosition, scale = blastRadius }, transmit: true); } } } float num2 = Run.instance.time - impactDelay; float num3 = num2 - travelEffectDuration; for (int num4 = meteorList.Count - 1; num4 >= 0; num4--) { Meteor meteor = meteorList[num4]; if (meteor.startTime < num3 && !meteor.didTravelEffect) { DoMeteorEffect(meteor); } if (meteor.startTime < num2) { meteorList.RemoveAt(num4); DetonateMeteor(meteor); } } if (wavesPerformed == waveCount && meteorList.Count == 0) { UnityEngine.Object.Destroy(base.gameObject); } } private void OnDestroy() { onDestroyEvents.Invoke(); } private void DoMeteorEffect(Meteor meteor) { meteor.didTravelEffect = true; if ((bool)travelEffectPrefab) { EffectManager.SpawnEffect(travelEffectPrefab, new EffectData { origin = meteor.impactPosition }, transmit: true); } } private void DetonateMeteor(Meteor meteor) { EffectData effectData = new EffectData { origin = meteor.impactPosition }; EffectManager.SpawnEffect(impactEffectPrefab, effectData, transmit: true); BlastAttack blastAttack = new BlastAttack(); blastAttack.inflictor = base.gameObject; blastAttack.baseDamage = blastDamageCoefficient * ownerDamage; blastAttack.baseForce = blastForce; blastAttack.attackerFiltering = AttackerFiltering.AlwaysHit; blastAttack.crit = isCrit; blastAttack.falloffModel = BlastAttack.FalloffModel.Linear; blastAttack.attacker = owner; blastAttack.bonusForce = UnityEngine.Vector3.zero; blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.position = meteor.impactPosition; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = 1f; blastAttack.teamIndex = TeamIndex.None; blastAttack.radius = blastRadius; blastAttack.damageType = blastDamageType; blastAttack.Fire(); } } [ExecuteAlways] public class MidpointBetweenTwoTransforms : MonoBehaviour { public Transform transform1; public Transform transform2; public void Update() { base.transform.position = UnityEngine.Vector3.Lerp(transform1.position, transform2.position, 0.5f); } } [DisallowMultipleComponent] public class MinionOwnership : NetworkBehaviour { public class MinionGroup : IDisposable { private class MinionGroupDestroyer : MonoBehaviour { public MinionGroup group; private void OnDestroy() { group.Dispose(); group.refCount--; } } private static readonly List instancesList = new List(); public readonly NetworkInstanceId ownerId; private MinionOwnership[] _members; private int _memberCount; private int refCount; private bool resolved; private GameObject resolvedOwnerGameObject; private CharacterMaster resolvedOwnerMaster; public MinionOwnership[] members => _members; public int memberCount => _memberCount; public bool isMinion => ownerId != NetworkInstanceId.Invalid; public static MinionGroup FindGroup(NetworkInstanceId ownerId) { foreach (MinionGroup instances in instancesList) { if (instances.ownerId == ownerId) { return instances; } } return null; } public static void SetMinionOwner(MinionOwnership minion, NetworkInstanceId ownerId) { if (minion.group != null) { if (minion.group.ownerId == ownerId) { return; } RemoveMinion(minion.group.ownerId, minion); } if (ownerId != NetworkInstanceId.Invalid) { AddMinion(ownerId, minion); } } private static void AddMinion(NetworkInstanceId ownerId, MinionOwnership minion) { MinionGroup minionGroup = null; for (int i = 0; i < instancesList.Count; i++) { MinionGroup minionGroup2 = instancesList[i]; if (instancesList[i].ownerId == ownerId) { minionGroup = minionGroup2; break; } } if (minionGroup == null) { minionGroup = new MinionGroup(ownerId); } minionGroup.AddMember(minion); minionGroup.AttemptToResolveOwner(); CharacterMaster component = minion.GetComponent(); if ((bool)component) { component.inventory.GiveItem(RoR2Content.Items.MinionLeash); } } private static void RemoveMinion(NetworkInstanceId ownerId, MinionOwnership minion) { CharacterMaster component = minion.GetComponent(); if ((bool)component) { component.inventory.RemoveItem(RoR2Content.Items.MinionLeash); } MinionGroup minionGroup = null; for (int i = 0; i < instancesList.Count; i++) { MinionGroup minionGroup2 = instancesList[i]; if (instancesList[i].ownerId == ownerId) { minionGroup = minionGroup2; break; } } if (minionGroup == null) { throw new InvalidOperationException(string.Format("{0}.{1} Could not find group to which {2} belongs", "MinionGroup", "RemoveMinion", minion)); } minionGroup.RemoveMember(minion); if (minionGroup.refCount == 0 && !minionGroup.resolvedOwnerGameObject) { minionGroup.Dispose(); } } private MinionGroup(NetworkInstanceId ownerId) { this.ownerId = ownerId; _members = new MinionOwnership[4]; _memberCount = 0; instancesList.Add(this); } public void Dispose() { for (int num = _memberCount - 1; num >= 0; num--) { RemoveMemberAt(num); } instancesList.Remove(this); } private void AttemptToResolveOwner() { if (resolved) { return; } resolvedOwnerGameObject = Util.FindNetworkObject(ownerId); if ((bool)resolvedOwnerGameObject) { resolved = true; resolvedOwnerMaster = resolvedOwnerGameObject.GetComponent(); resolvedOwnerGameObject.AddComponent().group = this; refCount++; for (int i = 0; i < _memberCount; i++) { _members[i].HandleOwnerDiscovery(resolvedOwnerMaster); } } } public void AddMember(MinionOwnership minion) { ArrayUtils.ArrayAppend(ref _members, ref _memberCount, in minion); refCount++; minion.HandleGroupDiscovery(this); if ((bool)resolvedOwnerMaster) { minion.HandleOwnerDiscovery(resolvedOwnerMaster); } } public void RemoveMember(MinionOwnership minion) { RemoveMemberAt(Array.IndexOf(_members, minion)); refCount--; } private void RemoveMemberAt(int i) { MinionOwnership obj = _members[i]; ArrayUtils.ArrayRemoveAt(_members, ref _memberCount, i); obj.HandleOwnerDiscovery(null); obj.HandleGroupDiscovery(null); } [ConCommand(commandName = "minion_dump", flags = ConVarFlags.None, helpText = "Prints debug information about all active minion groups.")] private static void CCMinionPrint(ConCommandArgs args) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < instancesList.Count; i++) { MinionGroup minionGroup = instancesList[i]; stringBuilder.Append("group [").Append(i).Append("] size=") .Append(minionGroup._memberCount) .Append(" id=") .Append(minionGroup.ownerId) .Append(" resolvedOwnerGameObject=") .Append(minionGroup.resolvedOwnerGameObject) .AppendLine(); for (int j = 0; j < minionGroup._memberCount; j++) { stringBuilder.Append(" ").Append("[").Append(j) .Append("] member.name=") .Append(minionGroup._members[j].name) .AppendLine(); } } } } [SyncVar(hook = "OnSyncOwnerMasterId")] private NetworkInstanceId ownerMasterId = NetworkInstanceId.Invalid; public CharacterMaster ownerMaster { get; private set; } public MinionGroup group { get; private set; } public NetworkInstanceId NetworkownerMasterId { get { return ownerMasterId; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; OnSyncOwnerMasterId(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref ownerMasterId, 1u); } } public event Action onOwnerDiscovered; public event Action onOwnerLost; public static event Action onMinionGroupChangedGlobal; public static event Action onMinionOwnerChangedGlobal; [Server] public void SetOwner(CharacterMaster newOwnerMaster) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MinionOwnership::SetOwner(RoR2.CharacterMaster)' called on client"); return; } NetworkownerMasterId = (newOwnerMaster ? newOwnerMaster.netId : NetworkInstanceId.Invalid); MinionGroup.SetMinionOwner(this, ownerMasterId); } private void OnSyncOwnerMasterId(NetworkInstanceId newOwnerMasterId) { MinionGroup.SetMinionOwner(this, ownerMasterId); } public override void OnStartClient() { base.OnStartClient(); if (!NetworkServer.active) { MinionGroup.SetMinionOwner(this, ownerMasterId); } } private void HandleGroupDiscovery(MinionGroup newGroup) { group = newGroup; MinionOwnership.onMinionGroupChangedGlobal?.Invoke(this); } private void HandleOwnerDiscovery(CharacterMaster newOwner) { if ((object)ownerMaster != null) { this.onOwnerLost?.Invoke(ownerMaster); } ownerMaster = newOwner; if ((object)ownerMaster != null) { this.onOwnerDiscovered?.Invoke(ownerMaster); } MinionOwnership.onMinionOwnerChangedGlobal?.Invoke(this); } private void OnDestroy() { MinionGroup.SetMinionOwner(this, NetworkInstanceId.Invalid); } [AssetCheck(typeof(CharacterMaster))] private static void AddMinionOwnershipComponent(AssetCheckArgs args) { CharacterMaster characterMaster = args.asset as CharacterMaster; if (!characterMaster.GetComponent()) { characterMaster.gameObject.AddComponent(); args.UpdatePrefab(); } } private void OnValidate() { if (GetComponents().Length > 1) { UnityEngine.Debug.LogError("Only one MinionOwnership is allowed per object!", this); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(ownerMasterId); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(ownerMasterId); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { ownerMasterId = reader.ReadNetworkId(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { OnSyncOwnerMasterId(reader.ReadNetworkId()); } } public override void PreStartClient() { } } [RequireComponent(typeof(Camera))] public class ModelCamera : MonoBehaviour { private struct ObjectRestoreInfo { public GameObject obj; public int layer; } [NonSerialized] public RenderSettingsState renderSettings; public UnityEngine.Color ambientLight; private readonly List lights = new List(); public static ModelCamera instance { get; private set; } public Camera attachedCamera { get; private set; } private void OnEnable() { if ((bool)instance && instance != this) { UnityEngine.Debug.LogErrorFormat("Only one {0} instance can be active at a time.", GetType().Name); } else { instance = this; } } private void OnDisable() { if (instance == this) { instance = null; } } private void Awake() { attachedCamera = GetComponent(); attachedCamera.enabled = false; attachedCamera.cullingMask = LayerIndex.manualRender.mask; UnityEngine.Object.Destroy(GetComponent()); } private static void PrepareObjectForRendering(Transform objTransform, List objectRestorationList) { GameObject gameObject = objTransform.gameObject; objectRestorationList.Add(new ObjectRestoreInfo { obj = gameObject, layer = gameObject.layer }); gameObject.layer = LayerIndex.manualRender.intVal; int childCount = objTransform.childCount; for (int i = 0; i < childCount; i++) { PrepareObjectForRendering(objTransform.GetChild(i), objectRestorationList); } } public void RenderItem(GameObject obj, RenderTexture targetTexture) { for (int i = 0; i < lights.Count; i++) { lights[i].cullingMask = LayerIndex.manualRender.mask; } RenderSettingsState renderSettingsState = RenderSettingsState.FromCurrent(); renderSettings.Apply(); List list = new List(); if ((bool)obj) { PrepareObjectForRendering(obj.transform, list); } attachedCamera.targetTexture = targetTexture; attachedCamera.Render(); for (int j = 0; j < list.Count; j++) { list[j].obj.layer = list[j].layer; } for (int k = 0; k < lights.Count; k++) { lights[k].cullingMask = 0; } renderSettingsState.Apply(); } public void AddLight(Light light) { lights.Add(light); } public void RemoveLight(Light light) { lights.Remove(light); } } [DisallowMultipleComponent] public class ModelLocator : MonoBehaviour, ILifeBehavior { private class DestructionNotifier : MonoBehaviour { public ModelLocator subscriber { private get; set; } private void OnDestroy() { if ((object)subscriber != null) { subscriber.modelTransform = null; } } } [SerializeField] [FormerlySerializedAs("modelTransform")] [Tooltip("The transform of the child gameobject which acts as the model for this entity.")] [Header("Cached Model Values")] private Transform _modelTransform; public RendererVisiblity modelVisibility; private DestructionNotifier modelDestructionNotifier; [Tooltip("The transform of the child gameobject which acts as the base for this entity's model. If provided, this will be detached from the hierarchy and positioned to match this object's position.")] public Transform modelBaseTransform; [Tooltip("Compensates for the irregular scaling from baseline human scale for attached VFX.")] public float modelScaleCompensation = 1f; [Tooltip("Whether or not to update the model transforms automatically.")] [Header("Update Properties")] public bool autoUpdateModelTransform = true; [Tooltip("Forces the model to remain in hierarchy, rather that detaching on start. You usually don't want this for anything that moves.")] public bool dontDetatchFromParent; private Transform modelParentTransform; [Tooltip("Only matters if preserveModel=true. Prevents the addition of a Corpse component to the model when this object is destroyed.")] [Header("Corpse Properties")] public bool noCorpse; [Tooltip("If true, ownership of the model will not be relinquished by death.")] public bool dontReleaseModelOnDeath; [Tooltip("Prevents the model from being destroyed when this object is destroyed. This is rarely used, as character death states are usually responsible for snatching the model away and leaving this ModelLocator with nothing to destroy.")] public bool preserveModel; public bool forceCulled; [Header("Normal Properties")] [Tooltip("Allows the model to align to the floor.")] public bool normalizeToFloor; public float normalSmoothdampTime = 0.1f; [Range(0f, 90f)] public float normalMaxAngleDelta = 90f; private UnityEngine.Vector3 normalSmoothdampVelocity; private UnityEngine.Vector3 targetNormal = UnityEngine.Vector3.up; private UnityEngine.Vector3 currentNormal = UnityEngine.Vector3.up; private CharacterMotor characterMotor; public Transform modelTransform { get { return _modelTransform; } set { if ((object)_modelTransform != value) { if ((object)modelDestructionNotifier != null) { modelDestructionNotifier.subscriber = null; UnityEngine.Object.Destroy(modelDestructionNotifier); modelDestructionNotifier = null; } _modelTransform = value; if ((bool)_modelTransform) { modelDestructionNotifier = _modelTransform.gameObject.AddComponent(); modelDestructionNotifier.subscriber = this; } this.onModelChanged?.Invoke(_modelTransform); } } } public event Action onModelChanged; private void Awake() { characterMotor = GetComponent(); } public void Start() { if ((bool)modelTransform) { modelParentTransform = modelTransform.parent; if (!dontDetatchFromParent) { modelTransform.parent = null; } } } private void UpdateModelTransform(float deltaTime) { if ((bool)modelTransform && (bool)modelParentTransform) { UnityEngine.Vector3 position = modelParentTransform.position; UnityEngine.Quaternion rotation = modelParentTransform.rotation; UpdateTargetNormal(); SmoothNormals(deltaTime); rotation = UnityEngine.Quaternion.FromToRotation(UnityEngine.Vector3.up, currentNormal) * rotation; modelTransform.SetPositionAndRotation(position, rotation); } } private void SmoothNormals(float deltaTime) { currentNormal = UnityEngine.Vector3.SmoothDamp(currentNormal, targetNormal, ref normalSmoothdampVelocity, normalSmoothdampTime, float.PositiveInfinity, deltaTime); } private void UpdateTargetNormal() { if (normalizeToFloor && (bool)characterMotor) { targetNormal = (characterMotor.isGrounded ? characterMotor.estimatedGroundNormal : UnityEngine.Vector3.up); targetNormal = UnityEngine.Vector3.RotateTowards(UnityEngine.Vector3.up, targetNormal, normalMaxAngleDelta * (MathF.PI / 180f), float.PositiveInfinity); } else { targetNormal = UnityEngine.Vector3.up; } } public void LateUpdate() { if (autoUpdateModelTransform) { UpdateModelTransform(Time.deltaTime); } } private void OnDestroy() { if (!modelTransform) { return; } if (preserveModel) { if (!noCorpse) { modelTransform.gameObject.AddComponent(); } modelTransform = null; } else { UnityEngine.Object.Destroy(modelTransform.gameObject); } } public void OnDeathStart() { if (!dontReleaseModelOnDeath) { preserveModel = true; } } } public class ModelPanelParameters : MonoBehaviour { public Transform focusPointTransform; public Transform cameraPositionTransform; public UnityEngine.Quaternion modelRotation = UnityEngine.Quaternion.identity; public float minDistance = 1f; public float maxDistance = 10f; public UnityEngine.Vector3 cameraDirection => focusPointTransform.position - cameraPositionTransform.position; public void OnDrawGizmos() { if ((bool)focusPointTransform) { Gizmos.color = UnityEngine.Color.yellow; Gizmos.DrawWireSphere(focusPointTransform.position, 0.1f); Gizmos.color = UnityEngine.Color.gray; Gizmos.DrawWireSphere(focusPointTransform.position, minDistance); Gizmos.DrawWireSphere(focusPointTransform.position, maxDistance); } if ((bool)cameraPositionTransform) { Gizmos.color = UnityEngine.Color.yellow; Gizmos.DrawWireSphere(cameraPositionTransform.position, 0.2f); } if ((bool)focusPointTransform && (bool)cameraPositionTransform) { Gizmos.DrawLine(focusPointTransform.position, cameraPositionTransform.position); } } } [RequireComponent(typeof(CharacterModel))] [DisallowMultipleComponent] public class ModelSkinController : MonoBehaviour { public SkinDef[] skins; private CharacterModel characterModel; public int currentSkinIndex { get; private set; } = -1; private void Awake() { characterModel = GetComponent(); } private void Start() { if ((bool)characterModel.body) { ApplySkin((int)characterModel.body.skinIndex); } } public void ApplySkin(int skinIndex) { if (skinIndex != currentSkinIndex && (uint)skinIndex < skins.Length) { skins[skinIndex].Apply(base.gameObject); characterModel.forceUpdate = true; currentSkinIndex = skinIndex; } } } public class MoneyPickup : MonoBehaviour { [Tooltip("The base object to destroy when this pickup is consumed.")] public GameObject baseObject; [Tooltip("The team filter object which determines who can pick up this pack.")] public TeamFilter teamFilter; public GameObject pickupEffectPrefab; public int baseGoldReward; public bool shouldScale; private bool alive = true; private int goldReward; private void Start() { if (NetworkServer.active) { goldReward = (shouldScale ? Run.instance.GetDifficultyScaledCost(baseGoldReward) : baseGoldReward); } } private void OnTriggerStay(Collider other) { if (!NetworkServer.active || !alive) { return; } TeamIndex objectTeam = TeamComponent.GetObjectTeam(other.gameObject); if (objectTeam == teamFilter.teamIndex) { alive = false; UnityEngine.Vector3 position = base.transform.position; TeamManager.instance.GiveTeamMoney(objectTeam, (uint)goldReward); if ((bool)pickupEffectPrefab) { EffectManager.SimpleEffect(pickupEffectPrefab, position, UnityEngine.Quaternion.identity, transmit: true); } UnityEngine.Object.Destroy(baseObject); } } } public class MonsterCounter : MonoBehaviour { private int enemyList; private int CountEnemies() { return TeamComponent.GetTeamMembers(TeamIndex.Monster).Count; } private void Update() { enemyList = CountEnemies(); } private void OnGUI() { GUI.Label(new UnityEngine.Rect(12f, 160f, 200f, 25f), "Living Monsters: " + enemyList); } } [RequireComponent(typeof(EntityStateMachine))] public class MoonBatteryMissionController : NetworkBehaviour { [SerializeField] private GameObject[] moonBatteries; [SerializeField] private GameObject[] elevators; [SerializeField] private int _numRequiredBatteries; [SerializeField] private string _objectiveToken; private HoldoutZoneController[] batteryHoldoutZones; private EntityStateMachine[] batteryStateMachines; private EntityStateMachine[] elevatorStateMachines; [SyncVar] private int _numChargedBatteries; public static MoonBatteryMissionController instance { get; private set; } public int numChargedBatteries => _numChargedBatteries; public int numRequiredBatteries => _numRequiredBatteries; public string objectiveToken => _objectiveToken; public int Network_numChargedBatteries { get { return _numChargedBatteries; } [param: In] set { SetSyncVar(value, ref _numChargedBatteries, 1u); } } public static event Action onInstanceChangedGlobal; private void Awake() { List list = new List(); List list2 = new List(); for (int i = 0; i < moonBatteries.Length; i++) { if (moonBatteries[i] != null) { list.Add(moonBatteries[i].GetComponent()); list2.Add(moonBatteries[i].GetComponent()); } } batteryHoldoutZones = list.ToArray(); batteryStateMachines = list2.ToArray(); List list3 = new List(); for (int j = 0; j < elevators.Length; j++) { if (elevators[j] != null) { list3.Add(elevators[j].GetComponent()); } } elevatorStateMachines = list3.ToArray(); } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); MoonBatteryMissionController.onInstanceChangedGlobal?.Invoke(); ObjectivePanelController.collectObjectiveSources += OnCollectObjectiveSources; for (int i = 0; i < batteryHoldoutZones.Length; i++) { batteryHoldoutZones[i].onCharged.AddListener(OnBatteryCharged); } } private void OnDisable() { instance = SingletonHelper.Unassign(instance, this); MoonBatteryMissionController.onInstanceChangedGlobal?.Invoke(); ObjectivePanelController.collectObjectiveSources -= OnCollectObjectiveSources; for (int i = 0; i < batteryHoldoutZones.Length; i++) { batteryHoldoutZones[i].onCharged.RemoveListener(OnBatteryCharged); } } private void OnCollectObjectiveSources(CharacterMaster master, List objectiveSourcesList) { if (_numChargedBatteries > 0 && _numChargedBatteries < _numRequiredBatteries) { objectiveSourcesList.Add(new ObjectivePanelController.ObjectiveSourceDescriptor { master = master, objectiveType = typeof(MoonBatteryMissionObjectiveTracker), source = this }); } } private void OnBatteryCharged(HoldoutZoneController holdoutZone) { Network_numChargedBatteries = _numChargedBatteries + 1; if (_numChargedBatteries < _numRequiredBatteries || !NetworkServer.active) { return; } for (int i = 0; i < batteryHoldoutZones.Length; i++) { if (batteryHoldoutZones[i].enabled) { batteryHoldoutZones[i].FullyChargeHoldoutZone(); batteryHoldoutZones[i].onCharged.RemoveListener(OnBatteryCharged); } } batteryHoldoutZones = new HoldoutZoneController[0]; for (int j = 0; j < batteryStateMachines.Length; j++) { if (!(batteryStateMachines[j].state is MoonBatteryComplete)) { batteryStateMachines[j].SetNextState(new MoonBatteryDisabled()); } } for (int k = 0; k < elevatorStateMachines.Length; k++) { elevatorStateMachines[k].SetNextState(new InactiveToReady()); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt32((uint)_numChargedBatteries); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)_numChargedBatteries); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { _numChargedBatteries = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { _numChargedBatteries = (int)reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public class MoonMissionController : NetworkBehaviour { private Xoroshiro128Plus rng; public static MoonMissionController instance { get; private set; } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); SceneDirector.onPreGeneratePlayerSpawnPointsServer += OnPreGeneratePlayerSpawnPointsServer; } private void OnDisable() { SceneDirector.onPreGeneratePlayerSpawnPointsServer -= OnPreGeneratePlayerSpawnPointsServer; instance = SingletonHelper.Unassign(instance, this); } [Server] public override void OnStartServer() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MoonMissionController::OnStartServer()' called on client"); return; } base.OnStartServer(); rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint); } private void OnPreGeneratePlayerSpawnPointsServer(SceneDirector sceneDirector, ref Action generationMethod) { generationMethod = GeneratePlayerSpawnPointsServer; } private void GeneratePlayerSpawnPointsServer() { if (!SceneInfo.instance) { return; } ChildLocator component = SceneInfo.instance.GetComponent(); if (!component) { return; } Transform transform = component.FindChild("PlayerSpawnOrigin"); UnityEngine.Vector3 position = transform.position; NodeGraph groundNodes = SceneInfo.instance.groundNodes; if (!groundNodes) { UnityEngine.Debug.LogError("MoonMissionController.GeneratePlayerSpawnPointsServer: No ground nodegraph found to place spawn points.", this); return; } NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(groundNodes, HullMask.Human); nodeGraphSpider.AddNodeForNextStep(groundNodes.FindClosestNode(position, HullClassification.Human)); for (int i = 0; i < 4; i++) { nodeGraphSpider.PerformStep(); if (nodeGraphSpider.collectedSteps.Count > 16) { break; } } for (int j = 0; j < nodeGraphSpider.collectedSteps.Count; j++) { NodeGraphSpider.StepInfo stepInfo = nodeGraphSpider.collectedSteps[j]; groundNodes.GetNodePosition(stepInfo.node, out var position2); UnityEngine.Quaternion rotation = transform.rotation; SpawnPoint.AddSpawnPoint(position2, rotation); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class MorsecodeFlasher : MonoBehaviour { private string[] alphabet = new string[36] { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----." }; public string morsecodeMessage; public float spaceDelay; public float delayBetweenCharacters; public float dotDuration; public float dashDuration; public float messageRepeatDelay; public GameObject flashRootObject; private float age; private void FixedUpdate() { age -= Time.fixedDeltaTime; if (age <= 0f) { age = messageRepeatDelay; PlayMorseCodeMessage(morsecodeMessage); } } public void PlayMorseCodeMessage(string message) { StartCoroutine("_PlayMorseCodeMessage", message); } private IEnumerator _PlayMorseCodeMessage(string message) { Regex regex = new Regex("[^A-z0-9 ]"); message = regex.Replace(message.ToUpper(), ""); string text = message; foreach (char c in text) { if (c == ' ') { yield return new WaitForSeconds(spaceDelay); continue; } int num = c - 65; if (num < 0) { num = c - 48 + 26; } string text2 = alphabet[num]; string text3 = text2; foreach (char num2 in text3) { float num3 = dotDuration; if (num2 == '-') { num3 = dashDuration; } StartCoroutine("_FlashMorseCodeObject", num3); yield return new WaitForSeconds(num3 + delayBetweenCharacters); } } } private IEnumerator _FlashMorseCodeObject(float duration) { flashRootObject.SetActive(value: true); yield return new WaitForSeconds(duration); flashRootObject.SetActive(value: false); } } public class MultiBodyTrigger : MonoBehaviour { [Header("Parameters")] public bool playerControlledOnly = true; [Header("Events")] public CharacterBody.CharacterBodyUnityEvent onFirstQualifyingBodyEnter; public CharacterBody.CharacterBodyUnityEvent onLastQualifyingBodyExit; public CharacterBody.CharacterBodyUnityEvent onAnyQualifyingBodyEnter; public CharacterBody.CharacterBodyUnityEvent onAnyQualifyingBodyExit; public UnityEvent onAllQualifyingBodiesEnter; public UnityEvent onAllQualifyingBodiesExit; private readonly Queue collisionsQueue = new Queue(); private readonly List encounteredBodies = new List(); private bool allCandidatesPreviouslyTriggering; private bool cachedEnabled; private void OnEnable() { cachedEnabled = true; } private void OnDisable() { cachedEnabled = false; collisionsQueue.Clear(); List list = CollectionPool>.RentCollection(); SetEncounteredBodies(list, 0); list = CollectionPool>.ReturnCollection(list); } private void OnTriggerStay(Collider collider) { if (cachedEnabled) { collisionsQueue.Enqueue(collider); } } private void FixedUpdate() { if (collisionsQueue.Count == 0 && encounteredBodies.Count == 0) { return; } List list = CollectionPool>.RentCollection(); while (collisionsQueue.Count > 0) { Collider collider = collisionsQueue.Dequeue(); if ((bool)collider) { CharacterBody value = collider.GetComponent(); if ((bool)value && (!playerControlledOnly || value.isPlayerControlled) && ListUtils.FirstOccurrenceByReference(list, in value) == -1) { list.Add(value); } } } SetEncounteredBodies(list, playerControlledOnly ? (Run.instance?.livingPlayerCount ?? 0) : 0); list = CollectionPool>.ReturnCollection(list); } private void SetEncounteredBodies(List newEncounteredBodies, int candidateCount) { List list = CollectionPool>.RentCollection(); List list2 = CollectionPool>.RentCollection(); ListUtils.FindExclusiveEntriesByReference(encounteredBodies, newEncounteredBodies, list2, list); bool flag = encounteredBodies.Count == 0; bool flag2 = newEncounteredBodies.Count == 0; ListUtils.CloneTo(newEncounteredBodies, encounteredBodies); foreach (CharacterBody item in list2) { try { onAnyQualifyingBodyExit?.Invoke(item); } catch (Exception message) { UnityEngine.Debug.LogError(message); } } if (flag != flag2) { if (flag2) { try { onLastQualifyingBodyExit?.Invoke(list2[list2.Count - 1]); } catch (Exception message2) { UnityEngine.Debug.LogError(message2); } } else { try { onFirstQualifyingBodyEnter?.Invoke(list[0]); } catch (Exception message3) { UnityEngine.Debug.LogError(message3); } } } foreach (CharacterBody item2 in list) { try { onAnyQualifyingBodyEnter?.Invoke(item2); } catch (Exception message4) { UnityEngine.Debug.LogError(message4); } } list2 = CollectionPool>.ReturnCollection(list2); list = CollectionPool>.ReturnCollection(list); bool flag3 = encounteredBodies.Count >= candidateCount && candidateCount > 0; if (allCandidatesPreviouslyTriggering == flag3) { return; } try { if (flag3) { onAllQualifyingBodiesEnter?.Invoke(); } else { onAllQualifyingBodiesExit?.Invoke(); } } catch (Exception message5) { UnityEngine.Debug.LogError(message5); } allCandidatesPreviouslyTriggering = flag3; } public void KillAllOutsideWithVoidDeath() { List list = CollectionPool>.RentCollection(); ListUtils.AddRange(list, CharacterBody.readOnlyInstancesList); foreach (CharacterBody item in list) { if (encounteredBodies.Contains(item)) { continue; } CharacterMaster master = item.master; if ((bool)master) { try { master.TrueKill(BodyCatalog.FindBodyPrefab("BrotherBody"), null, DamageType.VoidDeath); } catch (Exception message) { UnityEngine.Debug.LogError(message); } } } list = CollectionPool>.ReturnCollection(list); } } [ExecuteAlways] [RequireComponent(typeof(LineRenderer))] public class MultiPointBezierCurveLine : MonoBehaviour { [Serializable] public struct Vertex { public Transform vertexTransform; public UnityEngine.Vector3 position; public UnityEngine.Vector3 localVelocity; } public Vertex[] vertexList; public UnityEngine.Vector3[] linePositionList; [HideInInspector] public LineRenderer lineRenderer; private void Start() { lineRenderer = GetComponent(); } private void LateUpdate() { for (int i = 0; i < linePositionList.Length; i++) { float globalT = (float)i / (float)(linePositionList.Length - 1); linePositionList[i] = EvaluateBezier(globalT); } lineRenderer.SetPositions(linePositionList); } private UnityEngine.Vector3 EvaluateBezier(float globalT) { int num = vertexList.Length - 1; int num2; int num3 = Mathf.Min((num2 = Mathf.FloorToInt((float)num * globalT)) + 1, num); Vertex vertex = vertexList[num2]; Vertex vertex2 = vertexList[num3]; UnityEngine.Vector3 vector = (vertex.vertexTransform ? vertex.vertexTransform.position : vertex.position); UnityEngine.Vector3 vector2 = (vertex2.vertexTransform ? vertex2.vertexTransform.position : vertex2.position); UnityEngine.Vector3 vector3 = (vertex.vertexTransform ? vertex.vertexTransform.TransformVector(vertex.localVelocity) : vertex.localVelocity); UnityEngine.Vector3 vector4 = (vertex2.vertexTransform ? vertex2.vertexTransform.TransformVector(vertex2.localVelocity) : vertex2.localVelocity); if (num2 == num3) { return vector; } float inMin = (float)num2 / (float)num; float inMax = (float)num3 / (float)num; float num4 = Util.Remap(globalT, inMin, inMax, 0f, 1f); UnityEngine.Vector3 a = UnityEngine.Vector3.Lerp(vector, vector + vector3, num4); UnityEngine.Vector3 b = UnityEngine.Vector3.Lerp(vector2, vector2 + vector4, 1f - num4); return UnityEngine.Vector3.Lerp(a, b, num4); } } public class MultiShopController : NetworkBehaviour, IHologramContentProvider { [Tooltip("The shop terminal prefab to instantiate.")] public GameObject terminalPrefab; [Tooltip("The positions at which to instantiate shop terminals.")] public Transform[] terminalPositions; [Tooltip("The number of terminals guaranteed to have their item revealed")] public int revealCount = 1; [Tooltip("The percentage chance that terminals after the reveal count will be hidden")] public float hiddenChance = 0.2f; [Header("Deprecated")] [Tooltip("The tier of items to drop")] public ItemTier itemTier; public bool doEquipmentInstead; [Tooltip("Whether or not there's a chance the item contents are replaced with a '?'")] private bool hideDisplayContent = true; private bool[] doCloseOnTerminalPurchase; private GameObject[] _terminalGameObjects; public ReadOnlyArray terminalGameObjects; [SyncVar] private bool available = true; public int baseCost; public CostTypeIndex costType; [SyncVar] private int cost; private Xoroshiro128Plus rng; private static int kRpcRpcSetTerminalPingable; public bool Networkavailable { get { return available; } [param: In] set { SetSyncVar(value, ref available, 1u); } } public int Networkcost { get { return cost; } [param: In] set { SetSyncVar(value, ref cost, 2u); } } private void Start() { if (!Run.instance || !NetworkServer.active) { return; } rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); CreateTerminals(); Networkcost = Run.instance.GetDifficultyScaledCost(baseCost); if (_terminalGameObjects != null) { GameObject[] array = _terminalGameObjects; for (int i = 0; i < array.Length; i++) { PurchaseInteraction component = array[i].GetComponent(); component.Networkcost = cost; component.costType = costType; } } } private void OnDestroy() { if (_terminalGameObjects != null) { for (int num = _terminalGameObjects.Length - 1; num >= 0; num--) { UnityEngine.Object.Destroy(_terminalGameObjects[num]); } _terminalGameObjects = null; } } private void CreateTerminals() { doCloseOnTerminalPurchase = new bool[terminalPositions.Length]; _terminalGameObjects = new GameObject[terminalPositions.Length]; terminalGameObjects = new ReadOnlyArray(_terminalGameObjects); for (int i = 0; i < terminalPositions.Length; i++) { doCloseOnTerminalPurchase[i] = true; GameObject gameObject = UnityEngine.Object.Instantiate(terminalPrefab, terminalPositions[i].position, terminalPositions[i].rotation); _terminalGameObjects[i] = gameObject; ShopTerminalBehavior component = gameObject.GetComponent(); component.serverMultiShopController = this; if (!component.selfGeneratePickup) { PickupIndex newPickupIndex = PickupIndex.none; if (doEquipmentInstead) { newPickupIndex = rng.NextElementUniform(Run.instance.availableEquipmentDropList); } else { switch (itemTier) { case ItemTier.Tier1: newPickupIndex = rng.NextElementUniform(Run.instance.availableTier1DropList); break; case ItemTier.Tier2: newPickupIndex = rng.NextElementUniform(Run.instance.availableTier2DropList); break; case ItemTier.Tier3: newPickupIndex = rng.NextElementUniform(Run.instance.availableTier3DropList); break; case ItemTier.Lunar: newPickupIndex = rng.NextElementUniform(Run.instance.availableLunarCombinedDropList); break; case ItemTier.VoidTier1: newPickupIndex = rng.NextElementUniform(Run.instance.availableVoidTier1DropList); break; case ItemTier.VoidTier2: newPickupIndex = rng.NextElementUniform(Run.instance.availableVoidTier2DropList); break; case ItemTier.VoidTier3: newPickupIndex = rng.NextElementUniform(Run.instance.availableVoidTier3DropList); break; case ItemTier.VoidBoss: newPickupIndex = rng.NextElementUniform(Run.instance.availableVoidBossDropList); break; } } bool newHidden = hideDisplayContent && i >= revealCount && rng.nextNormalizedFloat < hiddenChance; component.SetPickupIndex(newPickupIndex, newHidden); } else { component.SetHidden(i >= revealCount && rng.nextNormalizedFloat < hiddenChance); } NetworkServer.Spawn(gameObject); } GameObject[] array = _terminalGameObjects; foreach (GameObject gameObject2 in array) { PurchaseInteraction purchaseInteraction = gameObject2.GetComponent(); purchaseInteraction.onPurchase.AddListener(delegate(Interactor interactor) { OnPurchase(interactor, purchaseInteraction); }); } } private void OnPurchase(Interactor interactor, PurchaseInteraction purchaseInteraction) { bool flag = false; Networkavailable = false; for (int i = 0; i < _terminalGameObjects.Length; i++) { GameObject gameObject = _terminalGameObjects[i]; PurchaseInteraction component = gameObject.GetComponent(); if ((object)purchaseInteraction == component) { component.Networkavailable = false; gameObject.GetComponent().SetNoPickup(); CallRpcSetTerminalPingable(gameObject, value: false); flag = doCloseOnTerminalPurchase[i]; } Networkavailable = available || component.available; } if (flag) { Networkavailable = false; GameObject[] array = _terminalGameObjects; foreach (GameObject gameObject2 in array) { gameObject2.GetComponent().Networkavailable = false; gameObject2.GetComponent().SetNoPickup(); CallRpcSetTerminalPingable(gameObject2, value: false); } } } [ClientRpc] private void RpcSetTerminalPingable(GameObject terminalGO, bool value) { NetworkIdentity component = terminalGO.GetComponent(); if ((bool)component) { component.isPingable = value; } } public bool ShouldDisplayHologram(GameObject viewer) { if (available) { if (cost != 0) { return costType != CostTypeIndex.None; } return false; } return false; } public GameObject GetHologramContentPrefab() { return LegacyResourcesAPI.Load("Prefabs/CostHologramContent"); } public void UpdateHologramContent(GameObject hologramContentObject, Transform viewer) { CostHologramContent component = hologramContentObject.GetComponent(); if (!component) { return; } if ((bool)viewer && costType.Equals(CostTypeIndex.Money)) { if (TeamManager.LongstandingSolitudesInParty() > 0) { component.displayValue = cost * (TeamManager.LongstandingSolitudesInParty() + 1); } else { component.displayValue = cost; } } component.costType = costType; } public void SetCloseOnTerminalPurchase(PurchaseInteraction terminalPurchaseInteraction, bool doCloseMultiShop) { for (int i = 0; i < _terminalGameObjects.Length; i++) { if ((object)_terminalGameObjects[i].GetComponent() == terminalPurchaseInteraction) { doCloseOnTerminalPurchase[i] = doCloseMultiShop; } } } private void UNetVersion() { } protected static void InvokeRpcRpcSetTerminalPingable(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcSetTerminalPingable called on server."); } else { ((MultiShopController)obj).RpcSetTerminalPingable(reader.ReadGameObject(), reader.ReadBoolean()); } } public void CallRpcSetTerminalPingable(GameObject terminalGO, bool value) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcSetTerminalPingable called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcSetTerminalPingable); networkWriter.Write(GetComponent().netId); networkWriter.Write(terminalGO); networkWriter.Write(value); SendRPCInternal(networkWriter, 0, "RpcSetTerminalPingable"); } static MultiShopController() { kRpcRpcSetTerminalPingable = -474614679; NetworkBehaviour.RegisterRpcDelegate(typeof(MultiShopController), kRpcRpcSetTerminalPingable, InvokeRpcRpcSetTerminalPingable); NetworkCRC.RegisterBehaviour("MultiShopController", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(available); writer.WritePackedUInt32((uint)cost); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(available); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)cost); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { available = reader.ReadBoolean(); cost = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { available = reader.ReadBoolean(); } if (((uint)num & 2u) != 0) { cost = (int)reader.ReadPackedUInt32(); } } public override void PreStartClient() { } } public class MusicController : MonoBehaviour { public delegate void PickTrackDelegate(MusicController musicController, ref MusicTrackDef newTrack); private struct EnemyInfo { public Ray aimRay; public float lookScore; public float proximityScore; public float threatScore; } private struct CalculateIntensityJob : IJobParallelFor { [ReadOnly] public UnityEngine.Vector3 targetPosition; [ReadOnly] public int elementCount; public NativeArray enemyInfoBuffer; [ReadOnly] public float nearDistance; [ReadOnly] public float farDistance; public void Execute(int i) { EnemyInfo value = enemyInfoBuffer[i]; UnityEngine.Vector3 vector = targetPosition - value.aimRay.origin; float magnitude = vector.magnitude; float num = Mathf.Clamp01(UnityEngine.Vector3.Dot(vector / magnitude, value.aimRay.direction)); float num2 = Mathf.Clamp01(Mathf.InverseLerp(farDistance, nearDistance, magnitude)); value.lookScore = num * value.threatScore; value.proximityScore = num2 * value.threatScore; enemyInfoBuffer[i] = value; } public void CalculateSum(out float proximityScore, out float lookScore) { proximityScore = 0f; lookScore = 0f; for (int i = 0; i < elementCount; i++) { proximityScore += enemyInfoBuffer[i].proximityScore; lookScore += enemyInfoBuffer[i].lookScore; } } } public GameObject target; public bool enableMusicSystem; public MusicTrackDef introCutsceneMusic; private CameraRigController targetCamera; private MusicTrackDef _currentTrack; private RtpcSetter rtpcPlayerHealthValue; private RtpcSetter rtpcEnemyValue; private RtpcSetter rtpcTeleporterProximityValue; private RtpcSetter rtpcTeleporterDirectionValue; private RtpcSetter rtpcTeleporterPlayerStatus; private StateSetter stBossStatus; public static int timesStartRan; private float updateTimer; private const float MUSIC_UPDATE_INTERVAL = 0.25f; private bool wasPaused; private NativeArray enemyInfoBuffer; private CalculateIntensityJob calculateIntensityJob; private JobHandle calculateIntensityJobHandle; public static MusicController Instance { get; private set; } private MusicTrackDef currentTrack { get { return _currentTrack; } set { if ((object)_currentTrack != value) { if ((object)_currentTrack != null) { _currentTrack.Stop(); } _currentTrack = value; if ((object)_currentTrack != null) { _currentTrack.Play(); } } } } public static event PickTrackDelegate pickTrackHook; private void InitializeEngineDependentValues() { rtpcPlayerHealthValue = new RtpcSetter("playerHealth"); rtpcEnemyValue = new RtpcSetter("enemyValue"); rtpcTeleporterProximityValue = new RtpcSetter("teleporterProximity"); rtpcTeleporterDirectionValue = new RtpcSetter("teleporterDirection"); rtpcTeleporterPlayerStatus = new RtpcSetter("teleporterPlayerStatus"); stBossStatus = new StateSetter("bossStatus"); } private void Update() { if (updateTimer <= 0f) { updateTimer = 0.25f; UpdateState(); targetCamera = ((CameraRigController.readOnlyInstancesList.Count > 0) ? CameraRigController.readOnlyInstancesList[0] : null); target = (targetCamera ? targetCamera.target : null); ScheduleIntensityCalculation(target); } else { updateTimer -= Time.deltaTime; } } private void RecalculateHealth(GameObject playerObject) { rtpcPlayerHealthValue.value = 100f; if (!target) { return; } CharacterBody component = target.GetComponent(); if (!component) { return; } if (component.HasBuff(JunkContent.Buffs.Deafened)) { rtpcPlayerHealthValue.value = -100f; return; } HealthComponent healthComponent = component.healthComponent; if ((bool)healthComponent) { rtpcPlayerHealthValue.value = healthComponent.combinedHealthFraction * 100f; } } private void UpdateTeleporterParameters(TeleporterInteraction teleporter, Transform cameraTransform, CharacterBody targetBody) { float value = float.PositiveInfinity; float value2 = 0f; bool flag = true; stBossStatus.valueId = CommonWwiseIds.alive; if ((bool)teleporter) { if ((bool)cameraTransform) { UnityEngine.Vector3 position = cameraTransform.position; UnityEngine.Vector3 forward = cameraTransform.forward; UnityEngine.Vector3 vector = teleporter.transform.position - position; float num = UnityEngine.Vector2.SignedAngle(new UnityEngine.Vector2(vector.x, vector.z), new UnityEngine.Vector2(forward.x, forward.z)); if (num < 0f) { num += 360f; } value = vector.magnitude; value2 = num; } if (TeleporterInteraction.instance.isIdleToCharging || TeleporterInteraction.instance.isCharging) { stBossStatus.valueId = CommonWwiseIds.alive; } else if (TeleporterInteraction.instance.isCharged) { stBossStatus.valueId = CommonWwiseIds.dead; } if (teleporter.isCharging && (bool)targetBody) { flag = teleporter.holdoutZoneController.IsBodyInChargingRadius(targetBody); } } value = Mathf.Clamp(value, 20f, 250f); rtpcTeleporterProximityValue.value = Util.Remap(value, 20f, 250f, 0f, 10000f); rtpcTeleporterDirectionValue.value = value2; rtpcTeleporterPlayerStatus.value = (flag ? 1f : 0f); } private void LateUpdate() { bool flag = Time.timeScale == 0f; if (wasPaused != flag) { AkSoundEngine.PostEvent(flag ? "Pause_Music" : "Unpause_Music", base.gameObject); wasPaused = flag; } RecalculateHealth(target); UpdateTeleporterParameters(TeleporterInteraction.instance, targetCamera ? targetCamera.transform : null, target ? target.GetComponent() : null); calculateIntensityJobHandle.Complete(); calculateIntensityJob.CalculateSum(out var proximityScore, out var lookScore); float num = 0.025f; Mathf.Clamp(1f - rtpcPlayerHealthValue.value * 0.01f, 0.25f, 0.75f); float value = (proximityScore * 0.75f + lookScore * 0.25f) * num; rtpcEnemyValue.value = value; FlushValuesToEngine(); } private void FlushValuesToEngine() { stBossStatus.FlushIfChanged(); rtpcPlayerHealthValue.FlushIfChanged(); rtpcTeleporterProximityValue.FlushIfChanged(); rtpcTeleporterDirectionValue.FlushIfChanged(); rtpcTeleporterPlayerStatus.FlushIfChanged(); rtpcEnemyValue.FlushIfChanged(); } private void PickCurrentTrack(ref MusicTrackDef newTrack) { SceneDef mostRecentSceneDef = SceneCatalog.mostRecentSceneDef; bool flag = false; if ((bool)TeleporterInteraction.instance && !TeleporterInteraction.instance.isIdle) { flag = true; } if (enableMusicSystem && (bool)mostRecentSceneDef) { if (flag && (bool)mostRecentSceneDef.bossTrack) { newTrack = mostRecentSceneDef.bossTrack; } else if ((bool)mostRecentSceneDef.mainTrack) { newTrack = mostRecentSceneDef.mainTrack; } } MusicController.pickTrackHook?.Invoke(this, ref newTrack); } private void UpdateState() { MusicTrackDef newTrack = currentTrack; PickCurrentTrack(ref newTrack); currentTrack = newTrack; } private void EnsureEnemyBufferSize(int requiredSize) { if (enemyInfoBuffer.Length < requiredSize) { if (enemyInfoBuffer.Length != 0) { enemyInfoBuffer.Dispose(); } enemyInfoBuffer = new NativeArray(requiredSize, Allocator.Persistent); } } private void OnDestroy() { enemyInfoBuffer.Dispose(); } private void ScheduleIntensityCalculation(GameObject targetBodyObject) { if (!targetBodyObject) { return; } ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Monster); int count = teamMembers.Count; EnsureEnemyBufferSize(count); int num = 0; int i = 0; for (int num2 = count; i < num2; i++) { TeamComponent teamComponent = teamMembers[i]; InputBankTest component = teamComponent.GetComponent(); CharacterBody component2 = teamComponent.GetComponent(); if ((bool)component) { enemyInfoBuffer[num++] = new EnemyInfo { aimRay = new Ray(component.aimOrigin, component.aimDirection), threatScore = (component2.master ? component2.GetNormalizedThreatValue() : 0f) }; } } calculateIntensityJob = new CalculateIntensityJob { enemyInfoBuffer = enemyInfoBuffer, elementCount = num, targetPosition = targetBodyObject.transform.position, nearDistance = 20f, farDistance = 75f }; calculateIntensityJobHandle = calculateIntensityJob.Schedule(num, 32); } public static void Init() { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/MusicController"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle result) { GameObject gameObject = UnityEngine.Object.Instantiate(result.Result, RoR2Application.instance.transform); if (gameObject != null) { gameObject.GetComponent().PreloadForCutsceneStart(); } }; } public void PreloadForCutsceneStart() { Instance = this; enemyInfoBuffer = new NativeArray(64, Allocator.Persistent); InitializeEngineDependentValues(); SceneManager.sceneLoaded += SceneManager_OnLoadNextScene; } private void SceneManager_OnLoadNextScene(Scene arg0, LoadSceneMode arg1) { if (arg0.name == "intro") { currentTrack = introCutsceneMusic; } else { SceneManager.sceneLoaded -= SceneManager_OnLoadNextScene; } } public void StartIntroMusic() { AkSoundEngine.PostEvent("Play_Music_System", base.gameObject); currentTrack = introCutsceneMusic; enableMusicSystem = true; } } public class MusicTrackOverride : MonoBehaviour { public MusicTrackDef track; public int priority; private void OnEnable() { InstanceTracker.Add(this); if (InstanceTracker.GetInstancesList().Count == 1) { MusicController.pickTrackHook += PickMusicTrack; } } private void OnDisable() { if (InstanceTracker.GetInstancesList().Count == 1) { MusicController.pickTrackHook -= PickMusicTrack; } InstanceTracker.Remove(this); } private static void PickMusicTrack(MusicController musicController, ref MusicTrackDef newTrack) { List instancesList = InstanceTracker.GetInstancesList(); int num = int.MinValue; int i = 0; for (int count = instancesList.Count; i < count; i++) { MusicTrackOverride musicTrackOverride = instancesList[i]; int num2 = musicTrackOverride.priority; if (num < num2) { num = num2; newTrack = musicTrackOverride.track; } } } } public sealed class NetworkedBodyAttachment : NetworkBehaviour { [SyncVar(hook = "OnSyncAttachedBodyObject")] private GameObject _attachedBodyObject; [SyncVar(hook = "OnSyncAttachedBodyChildName")] private string attachedBodyChildName; public bool shouldParentToAttachedBody = true; public bool forceHostAuthority; private NetworkIdentity networkIdentity; private CharacterBody attachmentBody; private bool attached; private NetworkInstanceId ____attachedBodyObjectNetId; public GameObject attachedBodyObject => _attachedBodyObject; public CharacterBody attachedBody { get; private set; } public bool hasEffectiveAuthority { get; private set; } public GameObject Network_attachedBodyObject { get { return _attachedBodyObject; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; OnSyncAttachedBodyObject(value); base.syncVarHookGuard = false; } SetSyncVarGameObject(value, ref _attachedBodyObject, 1u, ref ____attachedBodyObjectNetId); } } public string NetworkattachedBodyChildName { get { return attachedBodyChildName; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; OnSyncAttachedBodyChildName(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref attachedBodyChildName, 2u); } } private void OnSyncAttachedBodyObject(GameObject value) { if (!NetworkServer.active) { Network_attachedBodyObject = value; OnAttachedBodyObjectAssigned(); } } private void OnSyncAttachedBodyChildName(string newName) { NetworkattachedBodyChildName = newName; if (shouldParentToAttachedBody) { ParentToBody(); } } private void Awake() { networkIdentity = GetComponent(); attachmentBody = GetComponent(); } [Server] public void AttachToGameObjectAndSpawn([NotNull] GameObject newAttachedBodyObject, string attachedBodyChildName = null) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkedBodyAttachment::AttachToGameObjectAndSpawn(UnityEngine.GameObject,System.String)' called on client"); } else if (attached) { UnityEngine.Debug.LogErrorFormat("Can't attach object '{0}' to object '{1}', it's already been assigned to object '{2}'.", base.gameObject, newAttachedBodyObject, attachedBodyObject); } else if ((bool)newAttachedBodyObject) { NetworkIdentity component = newAttachedBodyObject.GetComponent(); if (component.netId.Value == 0) { UnityEngine.Debug.LogWarningFormat("Network Identity for object {0} has a zero netID. Attachment will fail over the network.", newAttachedBodyObject); } NetworkattachedBodyChildName = attachedBodyChildName; Network_attachedBodyObject = newAttachedBodyObject; OnAttachedBodyObjectAssigned(); NetworkConnection networkConnection = null; networkConnection = component.clientAuthorityOwner; if (networkConnection == null || forceHostAuthority) { NetworkServer.Spawn(base.gameObject); } else { NetworkServer.SpawnWithClientAuthority(base.gameObject, networkConnection); } } } private void OnAttachedBodyObjectAssigned() { if (attached) { return; } attached = true; if ((bool)_attachedBodyObject) { attachedBody = _attachedBodyObject.GetComponent(); if (shouldParentToAttachedBody) { ParentToBody(); } } if (!attachedBody) { return; } List list = CollectionPool>.RentCollection(); GetComponents(list); foreach (INetworkedBodyAttachmentListener item in list) { item.OnAttachedBodyDiscovered(this, attachedBody); } list = CollectionPool>.ReturnCollection(list); } private void ParentToBody() { if (!_attachedBodyObject) { return; } Transform parent = _attachedBodyObject.transform; if (!string.IsNullOrEmpty(attachedBodyChildName)) { ModelLocator component = _attachedBodyObject.GetComponent(); if ((bool)component && (bool)component.modelTransform) { ChildLocator component2 = component.modelTransform.GetComponent(); if ((bool)component2) { Transform transform = component2.FindChild(attachedBodyChildName); if ((bool)transform) { parent = transform; } else { transform = component2.FindChild("Root"); if ((bool)transform) { parent = transform; } } } } } base.transform.SetParent(parent, worldPositionStays: false); base.transform.localPosition = UnityEngine.Vector3.zero; } public override void OnStartClient() { base.OnStartClient(); OnSyncAttachedBodyObject(attachedBodyObject); } private void FixedUpdate() { if (!attachedBodyObject && NetworkServer.active) { if ((bool)attachmentBody && (bool)attachmentBody.healthComponent) { attachmentBody.healthComponent.Suicide(); } else { UnityEngine.Object.Destroy(base.gameObject); } } } private void OnValidate() { if (!GetComponent().localPlayerAuthority && !forceHostAuthority) { UnityEngine.Debug.LogWarningFormat("NetworkedBodyAttachment: Object {0} NetworkIdentity needs localPlayerAuthority=true", base.gameObject.name); } } private void OnEnable() { InstanceTracker.Add(this); } private void OnDisable() { InstanceTracker.Remove(this); } public static void FindBodyAttachments(CharacterBody body, List output) { foreach (NetworkedBodyAttachment instances in InstanceTracker.GetInstancesList()) { if ((object)instances.attachedBody == body) { output.Add(instances); } } } public override void OnStartAuthority() { base.OnStartAuthority(); hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity); } public override void OnStopAuthority() { base.OnStopAuthority(); hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(_attachedBodyObject); writer.Write(attachedBodyChildName); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_attachedBodyObject); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(attachedBodyChildName); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { ____attachedBodyObjectNetId = reader.ReadNetworkId(); attachedBodyChildName = reader.ReadString(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { OnSyncAttachedBodyObject(reader.ReadGameObject()); } if (((uint)num & 2u) != 0) { OnSyncAttachedBodyChildName(reader.ReadString()); } } public override void PreStartClient() { if (!____attachedBodyObjectNetId.IsEmpty()) { Network_attachedBodyObject = ClientScene.FindLocalObject(____attachedBodyObjectNetId); } } } public interface INetworkedBodyAttachmentListener { void OnAttachedBodyDiscovered(NetworkedBodyAttachment networkedBodyAttachment, CharacterBody attachedBody); } public class NetworkedBodySpawnSlot : MonoBehaviour, MasterSpawnSlotController.ISlot { [SerializeField] private SpawnCard spawnCard; [SerializeField] private CharacterBody ownerBody; [SerializeField] private ChildLocator ownerChildLocator; [SerializeField] private string ownerAttachChildName; [SerializeField] private GameObject spawnEffectPrefab; [SerializeField] private GameObject killEffectPrefab; private CharacterMaster spawnedMaster; private bool isSpawnPending; public bool IsOpen() { if (!isSpawnPending) { return !spawnedMaster; } return false; } public void Spawn(GameObject summonerBodyObject, Xoroshiro128Plus rng, Action callback = null) { if (!NetworkServer.active || !ownerBody) { return; } Transform spawnOnTarget = ownerBody.transform; if (!string.IsNullOrEmpty(ownerAttachChildName) && (bool)ownerChildLocator) { Transform transform = ownerChildLocator.FindChild(ownerAttachChildName); if ((bool)transform) { spawnOnTarget = transform.transform; } } DirectorPlacementRule placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Direct, spawnOnTarget = spawnOnTarget }; DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, placementRule, rng); directorSpawnRequest.summonerBodyObject = summonerBodyObject; directorSpawnRequest.onSpawnedServer = (Action)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action)delegate(SpawnCard.SpawnResult spawnResult) { OnSpawnedServer(ownerBody.gameObject, spawnResult, callback); }); isSpawnPending = true; DirectorCore.instance?.TrySpawnObject(directorSpawnRequest); } public void Kill() { if (NetworkServer.active && (bool)spawnedMaster) { GameObject bodyObject = spawnedMaster.GetBodyObject(); if ((bool)killEffectPrefab && (bool)bodyObject) { EffectData effectData = new EffectData { origin = bodyObject.transform.position, rotation = bodyObject.transform.rotation }; EffectManager.SpawnEffect(killEffectPrefab, effectData, transmit: true); } spawnedMaster.TrueKill(); spawnedMaster = null; } } private void OnSpawnedServer(GameObject ownerBodyObject, SpawnCard.SpawnResult spawnResult, Action callback) { isSpawnPending = false; if (spawnResult.success) { spawnedMaster = spawnResult.spawnedInstance.GetComponent(); spawnedMaster.onBodyDestroyed += OnBodyDestroyed; GameObject bodyObject = spawnedMaster.GetBodyObject(); if ((bool)bodyObject) { if ((bool)spawnEffectPrefab) { EffectData effectData = new EffectData { origin = bodyObject.transform.position, rotation = bodyObject.transform.rotation }; EffectManager.SpawnEffect(spawnEffectPrefab, effectData, transmit: true); } NetworkedBodyAttachment component = bodyObject.GetComponent(); if ((bool)component) { component.AttachToGameObjectAndSpawn(ownerBodyObject, ownerAttachChildName); } } } callback?.Invoke(this, spawnResult); } private void OnBodyDestroyed(CharacterBody body) { if (body.master.IsDeadAndOutOfLivesServer() && (bool)spawnedMaster) { spawnedMaster.onBodyDestroyed -= OnBodyDestroyed; spawnedMaster = null; } } } public class NetworkParent : NetworkBehaviour { [Serializable] private struct ParentIdentifier : IEquatable { public byte indexInParentChildLocatorPlusOne; public NetworkInstanceId parentNetworkInstanceId; public int indexInParentChildLocator { get { return indexInParentChildLocatorPlusOne - 1; } set { indexInParentChildLocatorPlusOne = (byte)(value + 1); } } private static ChildLocator LookUpChildLocator(Transform rootObject) { ModelLocator component = rootObject.GetComponent(); if (!component) { return null; } Transform modelTransform = component.modelTransform; if (!modelTransform) { return null; } return modelTransform.GetComponent(); } public ParentIdentifier(Transform parent) { parentNetworkInstanceId = NetworkInstanceId.Invalid; indexInParentChildLocatorPlusOne = 0; if (!parent) { return; } NetworkIdentity componentInParent = parent.GetComponentInParent(); if (!componentInParent) { UnityEngine.Debug.LogWarningFormat("NetworkParent cannot accept a non-null parent without a NetworkIdentity! parent={0}", parent); return; } parentNetworkInstanceId = componentInParent.netId; if ((object)componentInParent.gameObject == parent.gameObject) { return; } ChildLocator childLocator = LookUpChildLocator(componentInParent.transform); if (!childLocator) { UnityEngine.Debug.LogWarningFormat("NetworkParent can only be parented directly to another object with a NetworkIdentity or an object registered in the ChildLocator of a a model of an object with a NetworkIdentity. parent={0}", parent); return; } indexInParentChildLocator = childLocator.FindChildIndex(parent); if (indexInParentChildLocatorPlusOne == 0) { UnityEngine.Debug.LogWarningFormat("NetworkParent parent={0} is not registered in a ChildLocator.", parent); } } public bool Equals(ParentIdentifier other) { if (indexInParentChildLocatorPlusOne == other.indexInParentChildLocatorPlusOne) { return parentNetworkInstanceId.Equals(other.parentNetworkInstanceId); } return false; } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is ParentIdentifier other) { return Equals(other); } return false; } public override int GetHashCode() { return (indexInParentChildLocatorPlusOne.GetHashCode() * 397) ^ parentNetworkInstanceId.GetHashCode(); } public Transform Resolve() { GameObject gameObject = Util.FindNetworkObject(parentNetworkInstanceId); NetworkIdentity networkIdentity = (gameObject ? gameObject.GetComponent() : null); if (!networkIdentity) { return null; } if (indexInParentChildLocatorPlusOne == 0) { return networkIdentity.transform; } ChildLocator childLocator = LookUpChildLocator(networkIdentity.transform); if ((bool)childLocator) { return childLocator.FindChild(indexInParentChildLocator); } return null; } } private Transform cachedServerParentTransform; private new Transform transform; [SyncVar(hook = "SetParentIdentifier")] private ParentIdentifier parentIdentifier; public ParentIdentifier NetworkparentIdentifier { get { return parentIdentifier; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SetParentIdentifier(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref parentIdentifier, 1u); } } private void Awake() { transform = base.transform; } public override void OnStartServer() { ServerUpdateParent(); } private void OnTransformParentChanged() { if (NetworkServer.active) { ServerUpdateParent(); } if ((bool)transform.parent) { transform.localPosition = UnityEngine.Vector3.zero; transform.localRotation = UnityEngine.Quaternion.identity; transform.localScale = UnityEngine.Vector3.one; } } [Server] private void ServerUpdateParent() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkParent::ServerUpdateParent()' called on client"); return; } Transform transform = this.transform.parent; if ((object)transform != cachedServerParentTransform) { if (!transform) { transform = null; } cachedServerParentTransform = transform; SetParentIdentifier(new ParentIdentifier(transform)); } } public override void OnStartClient() { base.OnStartClient(); SetParentIdentifier(parentIdentifier); } private void SetParentIdentifier(ParentIdentifier newParentIdentifier) { NetworkparentIdentifier = newParentIdentifier; if (!NetworkServer.active) { transform.parent = parentIdentifier.Resolve(); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { GeneratedNetworkCode._WriteParentIdentifier_NetworkParent(writer, parentIdentifier); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WriteParentIdentifier_NetworkParent(writer, parentIdentifier); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { parentIdentifier = GeneratedNetworkCode._ReadParentIdentifier_NetworkParent(reader); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { SetParentIdentifier(GeneratedNetworkCode._ReadParentIdentifier_NetworkParent(reader)); } } public override void PreStartClient() { } } [DefaultExecutionOrder(-1)] public class NetworkRuleBook : NetworkBehaviour { private const uint ruleBookDirtyBit = 1u; public RuleBook ruleBook { get; private set; } public event Action onRuleBookUpdated; private void Awake() { ruleBook = new RuleBook(); } [Server] public void SetRuleBook([NotNull] RuleBook newRuleBook) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkRuleBook::SetRuleBook(RoR2.RuleBook)' called on client"); } else if (!ruleBook.Equals(newRuleBook)) { SetDirtyBit(1u); ruleBook.Copy(newRuleBook); this.onRuleBookUpdated?.Invoke(this); } } public override bool OnSerialize(NetworkWriter writer, bool initialState) { uint num = base.syncVarDirtyBits; if (initialState) { num = 1u; } bool num2 = (num & 1) != 0; writer.Write((byte)num); if (num2) { writer.Write(ruleBook); } if (!initialState) { return num != 0; } return false; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (((uint)reader.ReadByte() & (true ? 1u : 0u)) != 0) { reader.ReadRuleBook(ruleBook); try { this.onRuleBookUpdated?.Invoke(this); } catch (Exception message) { UnityEngine.Debug.LogError(message); } } } private void UNetVersion() { } public override void PreStartClient() { } } [DefaultExecutionOrder(-1)] public class NetworkRuleChoiceMask : NetworkBehaviour { private const uint maskDirtyBit = 1u; public RuleChoiceMask ruleChoiceMask { get; private set; } private void Awake() { ruleChoiceMask = new RuleChoiceMask(); } [Server] public void SetRuleChoiceMask([NotNull] RuleChoiceMask newRuleChoiceMask) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkRuleChoiceMask::SetRuleChoiceMask(RoR2.RuleChoiceMask)' called on client"); } else if (!ruleChoiceMask.Equals(newRuleChoiceMask)) { SetDirtyBit(1u); ruleChoiceMask.Copy(newRuleChoiceMask); } } public override bool OnSerialize(NetworkWriter writer, bool initialState) { uint num = base.syncVarDirtyBits; if (initialState) { num = 1u; } bool num2 = (num & 1) != 0; writer.Write((byte)num); if (num2) { writer.Write(ruleChoiceMask); } if (!initialState) { return num != 0; } return false; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (((uint)reader.ReadByte() & (true ? 1u : 0u)) != 0) { reader.ReadRuleChoiceMask(ruleChoiceMask); } } private void UNetVersion() { } public override void PreStartClient() { } } public class NetworkSession : NetworkBehaviour { [Flags] public enum Flags { None = 0, HasPassword = 1, IsDedicatedServer = 2 } [SyncVar(hook = "OnSyncSteamId")] private ulong serverSteamId; [SyncVar] public ulong lobbySteamId; [SyncVar] private uint _flags; [SyncVar] public string tagsString; [SyncVar] public uint maxPlayers; [SyncVar] public string serverName; private TagManager serverManager; private static readonly BoolConVar cvSteamLobbyAllowPersistence = new BoolConVar("steam_lobby_allow_persistence", ConVarFlags.None, "1", "Whether or not the application should attempt to reestablish an active game session's Steamworks lobby if it's been lost."); public static NetworkSession instance { get; private set; } public Flags flags { get { return (Flags)_flags; } set { Network_flags = (uint)value; } } public ulong NetworkserverSteamId { get { return serverSteamId; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; OnSyncSteamId(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref serverSteamId, 1u); } } public ulong NetworklobbySteamId { get { return lobbySteamId; } [param: In] set { SetSyncVar(value, ref lobbySteamId, 2u); } } public uint Network_flags { get { return _flags; } [param: In] set { SetSyncVar(value, ref _flags, 4u); } } public string NetworktagsString { get { return tagsString; } [param: In] set { SetSyncVar(value, ref tagsString, 8u); } } public uint NetworkmaxPlayers { get { return maxPlayers; } [param: In] set { SetSyncVar(value, ref maxPlayers, 16u); } } public string NetworkserverName { get { return serverName; } [param: In] set { SetSyncVar(value, ref serverName, 32u); } } private void SetFlag(Flags flag, bool flagEnabled) { if (flagEnabled) { flags |= flag; } else { flags &= ~flag; } } public bool HasFlag(Flags flag) { return (flags & flag) == flag; } public override void OnStartServer() { base.OnStartServer(); SetFlag(Flags.IsDedicatedServer, flagEnabled: false); NetworkManagerSystem.SvPasswordConVar.instance.onValueChanged += UpdatePasswordFlag; UpdatePasswordFlag(NetworkManagerSystem.SvPasswordConVar.instance.value); RegisterTags(); NetworkmaxPlayers = (uint)NetworkManagerSystem.SvMaxPlayersConVar.instance.intValue; NetworkManagerSystem.SvHostNameConVar.instance.onValueChanged += UpdateServerName; UpdateServerName(NetworkManagerSystem.SvHostNameConVar.instance.GetString()); } private void RegisterTags() { if (PlatformSystems.ShouldUseEpicOnlineSystems) { serverManager = ServerManagerBase.instance; } else { serverManager = ServerManagerBase.instance; NetworkserverSteamId = NetworkManagerSystem.singleton.serverP2PId.ID; } if (serverManager != null) { TagManager tagManager = serverManager; tagManager.onTagsStringUpdated = (Action)Delegate.Combine(tagManager.onTagsStringUpdated, new Action(UpdateTagsString)); UpdateTagsString(serverManager.tagsString ?? string.Empty); } } private void OnDestroy() { NetworkManagerSystem.SvHostNameConVar.instance.onValueChanged -= UpdateServerName; NetworkManagerSystem.SvPasswordConVar.instance.onValueChanged -= UpdatePasswordFlag; UnregisterTags(); } private void UnregisterTags() { if (serverManager != null) { TagManager tagManager = serverManager; tagManager.onTagsStringUpdated = (Action)Delegate.Remove(tagManager.onTagsStringUpdated, new Action(UpdateTagsString)); } } private void UpdateTagsString(string tagsString) { NetworktagsString = tagsString; } public override void OnStartClient() { base.OnStartClient(); SteamworksAdvertiseGame(); } private void UpdatePasswordFlag(string password) { SetFlag(Flags.HasPassword, !string.IsNullOrEmpty(password)); } private void OnSyncSteamId(ulong newValue) { NetworkserverSteamId = newValue; SteamworksAdvertiseGame(); } private void SteamworksAdvertiseGame() { if (RoR2Application.instance.steamworksClient != null) { ulong num = serverSteamId; uint num2 = 0u; ushort num3 = 0; CallMethod(GetField(GetField(Client.Instance, "native"), "user"), "AdvertiseGame", new object[3] { num, num2, num3 }); } static void CallMethod(object obj, string methodName, object[] args) { obj.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic).Invoke(obj, args); } static object GetField(object obj, string fieldName) { return obj.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj); } } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); } private void OnDisable() { instance = SingletonHelper.Unassign(instance, this); } private void Start() { UnityEngine.Object.DontDestroyOnLoad(base.gameObject); if (NetworkServer.active) { NetworkServer.Spawn(base.gameObject); } StartCoroutine(SteamworksLobbyPersistenceCoroutine()); } private void UpdateServerName(string newHostName) { NetworkserverName = newHostName; } [Server] public Run BeginRun(Run runPrefabComponent, RuleBook ruleBook, ulong seed) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'RoR2.Run RoR2.NetworkSession::BeginRun(RoR2.Run,RoR2.RuleBook,System.UInt64)' called on client"); return null; } if (!Run.instance) { GameObject gameObject = UnityEngine.Object.Instantiate(runPrefabComponent.gameObject); Run component = gameObject.GetComponent(); component.SetRuleBook(ruleBook); component.seed = seed; NetworkServer.Spawn(gameObject); { foreach (ExpansionDef expansionDef in ExpansionCatalog.expansionDefs) { if (component.IsExpansionEnabled(expansionDef) && (bool)expansionDef.runBehaviorPrefab) { NetworkServer.Spawn(UnityEngine.Object.Instantiate(expansionDef.runBehaviorPrefab, gameObject.transform)); } } return component; } } return null; } [Server] public void EndRun() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkSession::EndRun()' called on client"); } else if ((bool)Run.instance) { UnityEngine.Object.Destroy(Run.instance.gameObject); } } private IEnumerator SteamworksLobbyPersistenceCoroutine() { while (true) { UpdateSteamworksLobbyPersistence(); yield return new WaitForSecondsRealtime(4f); } } private void UpdateSteamworksLobbyPersistence() { if (Client.Instance == null || !cvSteamLobbyAllowPersistence.value || NetworkServer.dontListen || PlatformSystems.lobbyManager.awaitingJoin || PlatformSystems.lobbyManager.awaitingCreate) { return; } ulong currentLobby = Client.Instance.Lobby.CurrentLobby; if (NetworkServer.active) { if (PlatformSystems.lobbyManager.isInLobby) { NetworklobbySteamId = currentLobby; } else { PlatformSystems.lobbyManager.CreateLobby(); } } else if (lobbySteamId != 0L && lobbySteamId != currentLobby) { PlatformSystems.lobbyManager.JoinLobby(new PlatformID(lobbySteamId)); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.WritePackedUInt64(serverSteamId); writer.WritePackedUInt64(lobbySteamId); writer.WritePackedUInt32(_flags); writer.Write(tagsString); writer.WritePackedUInt32(maxPlayers); writer.Write(serverName); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt64(serverSteamId); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt64(lobbySteamId); } if ((base.syncVarDirtyBits & 4u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32(_flags); } if ((base.syncVarDirtyBits & 8u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(tagsString); } if ((base.syncVarDirtyBits & 0x10u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32(maxPlayers); } if ((base.syncVarDirtyBits & 0x20u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(serverName); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { serverSteamId = reader.ReadPackedUInt64(); lobbySteamId = reader.ReadPackedUInt64(); _flags = reader.ReadPackedUInt32(); tagsString = reader.ReadString(); maxPlayers = reader.ReadPackedUInt32(); serverName = reader.ReadString(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { OnSyncSteamId(reader.ReadPackedUInt64()); } if (((uint)num & 2u) != 0) { lobbySteamId = reader.ReadPackedUInt64(); } if (((uint)num & 4u) != 0) { _flags = reader.ReadPackedUInt32(); } if (((uint)num & 8u) != 0) { tagsString = reader.ReadString(); } if (((uint)num & 0x10u) != 0) { maxPlayers = reader.ReadPackedUInt32(); } if (((uint)num & 0x20u) != 0) { serverName = reader.ReadString(); } } public override void PreStartClient() { } } public class NetworkSpawnOnStart : MonoBehaviour { private void Start() { if (NetworkServer.active) { NetworkServer.Spawn(base.gameObject); } } } [DisallowMultipleComponent] public class NetworkStateMachine : NetworkBehaviour { [SerializeField] [Tooltip("The sibling state machine components to network.")] private EntityStateMachine[] stateMachines = Array.Empty(); private NetworkIdentity networkIdentity; private void Awake() { networkIdentity = GetComponent(); for (int i = 0; i < stateMachines.Length; i++) { EntityStateMachine obj = stateMachines[i]; obj.networkIndex = i; obj.networker = this; obj.networkIdentity = networkIdentity; } } public override bool OnSerialize(NetworkWriter writer, bool initialState) { if (initialState) { for (int i = 0; i < stateMachines.Length; i++) { EntityStateMachine entityStateMachine = stateMachines[i]; writer.Write(EntityStateCatalog.GetStateIndex(entityStateMachine.state.GetType())); entityStateMachine.state.OnSerialize(writer); } return true; } return false; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (!initialState) { return; } for (int i = 0; i < stateMachines.Length; i++) { EntityStateMachine entityStateMachine = stateMachines[i]; EntityStateIndex entityStateIndex = reader.ReadEntityStateIndex(); if (base.hasAuthority) { continue; } EntityState entityState = EntityStateCatalog.InstantiateState(entityStateIndex); if (entityState != null) { entityState.outer = entityStateMachine; entityState.OnDeserialize(reader); if (!stateMachines[i]) { UnityEngine.Debug.LogErrorFormat("State machine [{0}] on object {1} is not set! incoming state = {2}", i, base.gameObject, entityState.GetType()); } entityStateMachine.SetNextState(entityState); } } } [NetworkMessageHandler(msgType = 48, client = true, server = true)] public static void HandleSetEntityState(NetworkMessage netMsg) { NetworkIdentity networkIdentity = netMsg.reader.ReadNetworkIdentity(); byte b = netMsg.reader.ReadByte(); EntityStateIndex entityStateIndex = netMsg.reader.ReadEntityStateIndex(); if (networkIdentity == null) { return; } NetworkStateMachine component = networkIdentity.gameObject.GetComponent(); if (component == null || b >= component.stateMachines.Length) { return; } EntityStateMachine entityStateMachine = component.stateMachines[b]; if (entityStateMachine == null) { return; } if (networkIdentity.isServer) { HashSet clientOwnedObjects = netMsg.conn.clientOwnedObjects; if (clientOwnedObjects == null || !clientOwnedObjects.Contains(networkIdentity.netId)) { return; } } else if (networkIdentity.hasAuthority) { return; } EntityState entityState = EntityStateCatalog.InstantiateState(entityStateIndex); if (entityState != null) { entityState.outer = entityStateMachine; entityState.OnDeserialize(netMsg.reader); entityStateMachine.SetState(entityState); } } public void SendSetEntityState(int stateMachineIndex) { if (NetworkServer.active || base.hasAuthority) { NetworkWriter networkWriter = new NetworkWriter(); EntityStateMachine entityStateMachine = stateMachines[stateMachineIndex]; networkWriter.StartMessage(48); networkWriter.Write(networkIdentity); networkWriter.Write((byte)stateMachineIndex); networkWriter.Write(EntityStateCatalog.GetStateIndex(entityStateMachine.state.GetType())); entityStateMachine.state.OnSerialize(networkWriter); networkWriter.FinishMessage(); if (NetworkServer.active) { NetworkServer.SendWriterToReady(base.gameObject, networkWriter, GetNetworkChannel()); } else if (ClientScene.readyConnection != null) { ClientScene.readyConnection.SendWriter(networkWriter, GetNetworkChannel()); } } } private void OnValidate() { for (int i = 0; i < stateMachines.Length; i++) { if (!stateMachines[i]) { UnityEngine.Debug.LogErrorFormat("{0} has a blank entry for NetworkStateMachine!", base.gameObject); } } } private void UNetVersion() { } public override void PreStartClient() { } } public class NetworkUIPromptController : NetworkBehaviour { private struct LocalUserInfo { public LocalUser localUser; public NetworkUIPromptController currentController; } private float lastCurrentLocalParticipantUpdateTime = float.NegativeInfinity; private LocalUser _currentLocalParticipant; private CharacterMaster _currentParticipantMaster; private bool _inControl; [SyncVar(hook = "SetParticipantMasterId")] private NetworkInstanceId masterObjectInstanceId; private CameraRigController _currentCamera; private static LocalUserInfo[] allLocalUserInfo = Array.Empty(); private static int allLocalUserInfoCount = 0; public Action messageFromClientHandler; private LocalUser currentLocalParticipant { get { return _currentLocalParticipant; } set { if (_currentLocalParticipant != value) { if (_currentLocalParticipant != null) { OnLocalParticipantLost(_currentLocalParticipant); } _currentLocalParticipant = value; if (_currentLocalParticipant != null) { OnLocalParticipantDiscovered(_currentLocalParticipant); } } } } public CharacterMaster currentParticipantMaster { get { return _currentParticipantMaster; } private set { if ((object)_currentParticipantMaster != value) { if ((object)_currentParticipantMaster != null) { OnParticipantLost(_currentParticipantMaster); } _currentParticipantMaster = value; if ((object)_currentParticipantMaster != null) { OnParticipantDiscovered(_currentParticipantMaster); } } } } private bool inControl { get { return _inControl; } set { if (_inControl != value) { _inControl = value; if (_inControl) { OnControlBegin(); } else { OnControlEnd(); } } } } private CameraRigController currentCamera { get { return _currentCamera; } set { if ((object)_currentCamera != value) { if ((object)_currentCamera != null) { this.onDisplayEnd?.Invoke(this, currentLocalParticipant, _currentCamera); } _currentCamera = value; if ((object)_currentCamera != null) { this.onDisplayBegin?.Invoke(this, currentLocalParticipant, _currentCamera); } } } } public bool inUse => currentParticipantMaster; public bool isDisplaying => currentCamera; public NetworkInstanceId NetworkmasterObjectInstanceId { get { return masterObjectInstanceId; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SetParticipantMasterId(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref masterObjectInstanceId, 1u); } } public event Action onDisplayBegin; public event Action onDisplayEnd; private void OnParticipantDiscovered([NotNull] CharacterMaster master) { LocalUser localUser = null; if ((bool)master.playerCharacterMasterController && (bool)master.playerCharacterMasterController.networkUser) { localUser = master.playerCharacterMasterController.networkUser.localUser; } currentLocalParticipant = localUser; } private void OnParticipantLost([NotNull] CharacterMaster master) { currentLocalParticipant = null; } private void OnLocalParticipantDiscovered([NotNull] LocalUser localUser) { lastCurrentLocalParticipantUpdateTime = Time.unscaledTime; UpdateBestControllerForLocalUser(localUser); } private void OnLocalParticipantLost([NotNull] LocalUser localUser) { ref LocalUserInfo localUserInfo = ref GetLocalUserInfo(localUser); if (localUserInfo.currentController == this) { localUserInfo.currentController.inControl = false; localUserInfo.currentController = null; } } private void HandleCameraDiscovered(CameraRigController cameraRigController) { currentCamera = cameraRigController; } private void HandleCameraLost(CameraRigController cameraRigController) { currentCamera = null; } private void OnControlBegin() { currentCamera = currentLocalParticipant.cameraRigController; currentLocalParticipant.onCameraDiscovered += HandleCameraDiscovered; currentLocalParticipant.onCameraLost += HandleCameraLost; } private void OnControlEnd() { currentLocalParticipant.onCameraLost -= HandleCameraLost; currentLocalParticipant.onCameraDiscovered -= HandleCameraDiscovered; currentCamera = null; } [CanBeNull] private static NetworkUIPromptController FindBestControllerForLocalUser([NotNull] LocalUser localUser) { NetworkUIPromptController result = null; float num = float.PositiveInfinity; List instancesList = InstanceTracker.GetInstancesList(); for (int i = 0; i < instancesList.Count; i++) { NetworkUIPromptController networkUIPromptController = instancesList[i]; if (networkUIPromptController.currentLocalParticipant == localUser && networkUIPromptController.lastCurrentLocalParticipantUpdateTime < num) { num = networkUIPromptController.lastCurrentLocalParticipantUpdateTime; result = networkUIPromptController; } } return result; } private static void UpdateBestControllerForLocalUser([NotNull] LocalUser localUser) { ref LocalUserInfo localUserInfo = ref GetLocalUserInfo(localUser); NetworkUIPromptController currentController = localUserInfo.currentController; NetworkUIPromptController networkUIPromptController = FindBestControllerForLocalUser(localUser); if ((object)currentController != networkUIPromptController) { if ((object)currentController != null) { currentController.inControl = false; } if ((object)networkUIPromptController != null) { networkUIPromptController.inControl = true; } localUserInfo.currentController = networkUIPromptController; } } private void OnEnable() { InstanceTracker.Add(this); } private void OnDisable() { SetParticipantMasterId(NetworkInstanceId.Invalid); InstanceTracker.Remove(this); } public override void OnStartClient() { base.OnStartClient(); if (!NetworkServer.active) { SetParticipantMasterId(masterObjectInstanceId); } } private void SetParticipantMasterId(NetworkInstanceId newMasterObjectInstanceId) { NetworkmasterObjectInstanceId = newMasterObjectInstanceId; GameObject gameObject = Util.FindNetworkObject(masterObjectInstanceId); CharacterMaster characterMaster = null; if ((bool)gameObject) { characterMaster = gameObject.GetComponent(); } currentParticipantMaster = characterMaster; } [Server] public void ClearParticipant() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUIPromptController::ClearParticipant()' called on client"); } else { SetParticipantMaster(null); } } [Server] public void SetParticipantMaster([CanBeNull] CharacterMaster newParticipantMaster) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUIPromptController::SetParticipantMaster(RoR2.CharacterMaster)' called on client"); return; } NetworkIdentity networkIdentity = (newParticipantMaster ? newParticipantMaster.networkIdentity : null); SetParticipantMasterId(networkIdentity ? networkIdentity.netId : NetworkInstanceId.Invalid); } [Server] public void SetParticipantMasterFromInteractor([CanBeNull] Interactor newParticipantInteractor) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUIPromptController::SetParticipantMasterFromInteractor(RoR2.Interactor)' called on client"); return; } CharacterMaster participantMaster = ((!newParticipantInteractor) ? null : newParticipantInteractor.GetComponent()?.master); SetParticipantMaster(participantMaster); } [Server] public void SetParticipantMasterFromInteractorObject([CanBeNull] UnityEngine.Object newParticipantInteractor) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUIPromptController::SetParticipantMasterFromInteractorObject(UnityEngine.Object)' called on client"); } else { SetParticipantMasterFromInteractor(newParticipantInteractor as Interactor); } } [SystemInitializer(new Type[] { })] private static void Init() { LocalUserManager.onUserSignIn += OnUserSignIn; LocalUserManager.onUserSignOut += OnUserSignOut; } private static void OnUserSignIn(LocalUser localUser) { LocalUserInfo localUserInfo = default(LocalUserInfo); localUserInfo.localUser = localUser; localUserInfo.currentController = null; LocalUserInfo value = localUserInfo; ArrayUtils.ArrayAppend(ref allLocalUserInfo, ref allLocalUserInfoCount, in value); } private static void OnUserSignOut(LocalUser localUser) { for (int i = 0; i < allLocalUserInfoCount; i++) { if (allLocalUserInfo[i].localUser == localUser) { ArrayUtils.ArrayRemoveAt(allLocalUserInfo, ref allLocalUserInfoCount, i); break; } } } private static ref LocalUserInfo GetLocalUserInfo(LocalUser localUser) { for (int i = 0; i < allLocalUserInfoCount; i++) { if (allLocalUserInfo[i].localUser == localUser) { return ref allLocalUserInfo[i]; } } throw new ArgumentException("localUser must be signed in"); } [Client] public NetworkWriter BeginMessageToServer() { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'UnityEngine.Networking.NetworkWriter RoR2.NetworkUIPromptController::BeginMessageToServer()' called on server"); return null; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.StartMessage(76); networkWriter.Write(base.gameObject); return networkWriter; } [Client] public void FinishMessageToServer(NetworkWriter writer) { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUIPromptController::FinishMessageToServer(UnityEngine.Networking.NetworkWriter)' called on server"); return; } writer.FinishMessage(); NetworkUser networkUser = FindParticipantNetworkUser(this); if ((bool)networkUser) { networkUser.connectionToServer.SendWriter(writer, GetNetworkChannel()); } } private static NetworkUser FindParticipantNetworkUser(NetworkUIPromptController instance) { if ((bool)instance) { CharacterMaster characterMaster = instance.currentParticipantMaster; if ((bool)characterMaster) { PlayerCharacterMasterController playerCharacterMasterController = characterMaster.playerCharacterMasterController; if ((bool)playerCharacterMasterController) { return playerCharacterMasterController.networkUser; } } } return null; } [NetworkMessageHandler(client = false, server = true, msgType = 76)] private static void HandleNetworkUIPromptMessage(NetworkMessage netMsg) { GameObject gameObject = netMsg.reader.ReadGameObject(); if (!gameObject) { return; } NetworkUIPromptController component = gameObject.GetComponent(); if ((bool)component) { NetworkUser networkUser = FindParticipantNetworkUser(component); NetworkConnection networkConnection = (networkUser ? networkUser.connectionToClient : null); if (netMsg.conn == networkConnection) { component.messageFromClientHandler?.Invoke(netMsg.reader); } } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(masterObjectInstanceId); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(masterObjectInstanceId); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { masterObjectInstanceId = reader.ReadNetworkId(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { SetParticipantMasterId(reader.ReadNetworkId()); } } public override void PreStartClient() { } } [RequireComponent(typeof(NetworkLoadout))] public class NetworkUser : NetworkBehaviour { public delegate void NetworkUserGenericDelegate(NetworkUser networkUser); private static readonly List instancesList; public static readonly ReadOnlyCollection readOnlyInstancesList; private static readonly List localPlayers; public static readonly ReadOnlyCollection readOnlyLocalPlayersList; [SyncVar(hook = "OnSyncId")] private NetworkUserId _id; [SyncVar] public byte rewiredPlayerId; [SyncVar(hook = "OnSyncMasterObjectId")] private NetworkInstanceId _masterObjectId; [CanBeNull] public LocalUser localUser; public CameraRigController cameraRigController; public string userName = ""; [SyncVar] public Color32 userColor = UnityEngine.Color.red; [SyncVar] private uint netLunarCoins; [SyncVar] public ItemIndex rebirthItem = ItemIndex.None; private MemoizedGetComponent cachedMaster; private MemoizedGetComponent cachedPlayerCharacterMasterController; private MemoizedGetComponent cachedPlayerStatsComponent; private GameObject _masterObject; [NonSerialized] [SyncVar(hook = "SetBodyPreference")] public BodyIndex bodyIndexPreference = BodyIndex.None; private float secondAccumulator; [NonSerialized] public List unlockables = new List(); public List debugUnlockablesList = new List(); private static NetworkInstanceId serverCurrentStage; private NetworkInstanceId _serverLastStageAcknowledgedByClient; private static int kRpcRpcDeductLunarCoins; private static int kCmdCmdAwardLunarCoins; private static int kCmdCmdStoreRebirthItems; private static int kRpcRpcStoreRebirthItems; private static int kCmdCmdSetRebirthItems; private static int kRpcRpcAwardLunarCoins; private static int kCmdCmdSetNetLunarCoins; private static int kCmdCmdSetBodyPreference; private static int kCmdCmdSendConsoleCommand; private static int kCmdCmdSendNewUnlockables; private static int kRpcRpcRequestUnlockables; private static int kCmdCmdReportAchievement; private static int kCmdCmdReportUnlock; private static int kCmdCmdAcknowledgeStage; private static int kCmdCmdSubmitVote; public NetworkLoadout networkLoadout { get; private set; } public NetworkUserId id { get { return _id; } set { if (!_id.Equals(value)) { Network_id = value; UpdateUserName(); } } } public bool authed => id.HasValidValue(); public Player inputPlayer => localUser?.inputPlayer; public uint lunarCoins { get { if (localUser != null) { return localUser.userProfile.coins; } return netLunarCoins; } } public CharacterMaster master => cachedMaster.Get(masterObject); public PlayerCharacterMasterController masterController => cachedPlayerCharacterMasterController.Get(masterObject); public PlayerStatsComponent masterPlayerStatsComponent => cachedPlayerStatsComponent.Get(masterObject); public GameObject masterObject { get { if (!_masterObject) { _masterObject = Util.FindNetworkObject(_masterObjectId); } return _masterObject; } set { if ((bool)value) { Network_masterObjectId = value.GetComponent().netId; _masterObject = value; } else { Network_masterObjectId = NetworkInstanceId.Invalid; _masterObject = null; } } } public bool isParticipating => masterObject; public bool isSplitScreenExtraPlayer => id.subId != 0; public bool serverIsClientLoaded { get; private set; } private NetworkInstanceId serverLastStageAcknowledgedByClient { get { return _serverLastStageAcknowledgedByClient; } set { if (!(_serverLastStageAcknowledgedByClient == value)) { _serverLastStageAcknowledgedByClient = value; if (serverCurrentStage == _serverLastStageAcknowledgedByClient) { serverIsClientLoaded = true; NetworkUser.onNetworkUserLoadedSceneServer?.Invoke(this); } } } } public NetworkUserId Network_id { get { return _id; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; OnSyncId(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref _id, 1u); } } public byte NetworkrewiredPlayerId { get { return rewiredPlayerId; } [param: In] set { SetSyncVar(value, ref rewiredPlayerId, 2u); } } public NetworkInstanceId Network_masterObjectId { get { return _masterObjectId; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; OnSyncMasterObjectId(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref _masterObjectId, 4u); } } public Color32 NetworkuserColor { get { return userColor; } [param: In] set { SetSyncVar(value, ref userColor, 8u); } } public uint NetworknetLunarCoins { get { return netLunarCoins; } [param: In] set { SetSyncVar(value, ref netLunarCoins, 16u); } } public ItemIndex NetworkrebirthItem { get { return rebirthItem; } [param: In] set { ulong newValueAsUlong = (ulong)value; ulong fieldValueAsUlong = (ulong)rebirthItem; SetSyncVarEnum(value, newValueAsUlong, ref rebirthItem, fieldValueAsUlong, 32u); } } public BodyIndex NetworkbodyIndexPreference { get { return bodyIndexPreference; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SetBodyPreference(value); base.syncVarHookGuard = false; } ulong newValueAsUlong = (ulong)value; ulong fieldValueAsUlong = (ulong)bodyIndexPreference; SetSyncVarEnum(value, newValueAsUlong, ref bodyIndexPreference, fieldValueAsUlong, 64u); } } public static event Action onNetworkUserLoadedSceneServer; public static event Action onLoadoutChangedGlobal; [Obsolete("Use onPostNetworkUserStart instead", false)] public static event NetworkUserGenericDelegate OnPostNetworkUserStart { add { onPostNetworkUserStart += value; } remove { onPostNetworkUserStart -= value; } } public static event NetworkUserGenericDelegate onPostNetworkUserStart; [Obsolete("Use onNetworkUserUnlockablesUpdated instead", false)] public static event NetworkUserGenericDelegate OnNetworkUserUnlockablesUpdated { add { onNetworkUserUnlockablesUpdated += value; } remove { onNetworkUserUnlockablesUpdated -= value; } } public static event NetworkUserGenericDelegate onNetworkUserUnlockablesUpdated; public static event NetworkUserGenericDelegate onNetworkUserDiscovered; public static event NetworkUserGenericDelegate onNetworkUserLost; public static event NetworkUserGenericDelegate onNetworkUserBodyPreferenceChanged; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void Init() { UserProfile.onUnlockableGranted += delegate(UserProfile userProfile, UnlockableDef unlockableDef) { if (NetworkClient.active) { NetworkUser networkUser3 = FindNetworkUserByUserProfile(userProfile); if ((bool)networkUser3) { networkUser3.SendServerUnlockables(); } } }; UserProfile.onLoadoutChangedGlobal += delegate(UserProfile userProfile) { if (NetworkClient.active) { NetworkUser networkUser2 = FindNetworkUserByUserProfile(userProfile); if ((bool)networkUser2) { networkUser2.PullLoadoutFromUserProfile(); } } }; UserProfile.onSurvivorPreferenceChangedGlobal += delegate(UserProfile userProfile) { if (NetworkClient.active) { NetworkUser networkUser = FindNetworkUserByUserProfile(userProfile); if ((bool)networkUser) { networkUser.SetSurvivorPreferenceClient(userProfile.GetSurvivorPreference()); } } }; Stage.onStageStartGlobal += delegate(Stage stage) { if (NetworkServer.active) { serverCurrentStage = stage.netId; } foreach (NetworkUser localPlayer in localPlayers) { localPlayer.CallCmdAcknowledgeStage(stage.netId); } }; } private void OnEnable() { instancesList.Add(this); NetworkUser.onNetworkUserDiscovered?.Invoke(this); } private void OnDisable() { NetworkUser.onNetworkUserLost?.Invoke(this); instancesList.Remove(this); } private void Awake() { UnityEngine.Object.DontDestroyOnLoad(base.gameObject); networkLoadout = GetComponent(); networkLoadout.onLoadoutUpdated += OnLoadoutUpdated; } private void OnLoadoutUpdated() { NetworkUser.onLoadoutChangedGlobal?.Invoke(this); } private void PullLoadoutFromUserProfile() { UserProfile userProfile = localUser?.userProfile; if (userProfile != null) { Loadout loadout = Loadout.RequestInstance(); userProfile.CopyLoadout(loadout); networkLoadout.SetLoadout(loadout); Loadout.ReturnInstance(loadout); } } private void Start() { if (base.isLocalPlayer) { LocalUserManager.FindLocalUser(base.playerControllerId)?.LinkNetworkUser(this); PullLoadoutFromUserProfile(); if (!Run.instance || bodyIndexPreference == BodyIndex.None) { SetSurvivorPreferenceClient(localUser.userProfile.GetSurvivorPreference()); } } if ((bool)Run.instance) { Run.instance.OnUserAdded(this); } if (NetworkClient.active) { SyncLunarCoinsToServer(); SyncRebirthItemsToServer(); SendServerUnlockables(); } OnLoadoutUpdated(); NetworkUser.onPostNetworkUserStart?.Invoke(this); if (base.isLocalPlayer && (bool)Stage.instance) { CallCmdAcknowledgeStage(Stage.instance.netId); } } private void OnDestroy() { localPlayers.Remove(this); Run.instance?.OnUserRemoved(this); RunCameraManager.instance?.OnUserRemoved(this); localUser?.UnlinkNetworkUser(); } public void BumpDLCChecker() { NetworkUser.onPostNetworkUserStart(this); } public override void OnStartLocalPlayer() { base.OnStartLocalPlayer(); if (!localPlayers.Contains(this)) { localPlayers.Add(this); } else { UnityEngine.Debug.LogError("OnStartLocalPlayer Already has THIS local player!"); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"OnStartLocalPlayer LOCAL_PLAYERS COUNT {localPlayers.Count}:"); foreach (NetworkUser localPlayer in localPlayers) { stringBuilder.AppendLine("\t" + localPlayer.id.strValue); } } public override void OnStartClient() { UpdateUserName(); } private void OnSyncId(NetworkUserId newId) { id = newId; } private void OnSyncMasterObjectId(NetworkInstanceId newValue) { _masterObject = null; Network_masterObjectId = newValue; } public NetworkPlayerName GetNetworkPlayerName() { NetworkPlayerName result = default(NetworkPlayerName); result.nameOverride = ((id.strValue != null) ? id.strValue : null); result.playerId = ((!string.IsNullOrEmpty(id.strValue)) ? default(PlatformID) : new PlatformID(id.value)); return result; } [Server] public void DeductLunarCoins(uint count) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::DeductLunarCoins(System.UInt32)' called on client"); return; } NetworknetLunarCoins = HGMath.UintSafeSubtract(netLunarCoins, count); CallRpcDeductLunarCoins(count); } [ClientRpc] private void RpcDeductLunarCoins(uint count) { if (localUser != null) { localUser.userProfile.coins = HGMath.UintSafeSubtract(localUser.userProfile.coins, count); SyncLunarCoinsToServer(); } } [Server] public void AwardLunarCoins(uint count) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::AwardLunarCoins(System.UInt32)' called on client"); return; } NetworknetLunarCoins = HGMath.UintSafeAdd(netLunarCoins, count); CallRpcAwardLunarCoins(count); } [Command] public void CmdAwardLunarCoins(uint count) { AwardLunarCoins(count); } [Command] public void CmdStoreRebirthItems(ItemIndex item) { StoreRebirthItems(item); } [Server] private void StoreRebirthItems(ItemIndex item) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::StoreRebirthItems(RoR2.ItemIndex)' called on client"); return; } NetworkrebirthItem = item; CallRpcStoreRebirthItems(item); } [ClientRpc] private void RpcStoreRebirthItems(ItemIndex item) { if (localUser != null) { localUser.userProfile.RebirthItem = PickupCatalog.GetPickupDef(PickupCatalog.FindPickupIndex(item))?.internalName; SyncRebirthItemsToServer(); } } [Client] private void SyncRebirthItemsToServer() { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUser::SyncRebirthItemsToServer()' called on server"); } else if (localUser != null) { UserProfile userProfile = localUser.userProfile; if (!string.IsNullOrEmpty(userProfile.RebirthItem)) { CallCmdSetRebirthItems((userProfile.RebirthItem != null) ? PickupCatalog.GetPickupDef(PickupCatalog.FindPickupIndex(userProfile.RebirthItem)).itemIndex : ItemIndex.None); } } } [Command] private void CmdSetRebirthItems(ItemIndex item) { NetworkrebirthItem = item; } [ClientRpc] private void RpcAwardLunarCoins(uint count) { if (localUser != null) { _ = localUser.userProfile.name; localUser.userProfile.coins = HGMath.UintSafeAdd(localUser.userProfile.coins, count); localUser.userProfile.totalCollectedCoins = HGMath.UintSafeAdd(localUser.userProfile.totalCollectedCoins, count); SyncLunarCoinsToServer(); } } [Client] private void SyncLunarCoinsToServer() { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUser::SyncLunarCoinsToServer()' called on server"); } else if (localUser != null) { CallCmdSetNetLunarCoins(localUser.userProfile.coins); } } [Command] private void CmdSetNetLunarCoins(uint newNetLunarCoins) { NetworknetLunarCoins = newNetLunarCoins; } public CharacterBody GetCurrentBody() { CharacterMaster characterMaster = master; if ((bool)characterMaster) { return characterMaster.GetBody(); } return null; } [Server] public void CopyLoadoutFromMaster() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::CopyLoadoutFromMaster()' called on client"); } else { networkLoadout.SetLoadout(master.loadout); } } [Server] public void CopyLoadoutToMaster() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::CopyLoadoutToMaster()' called on client"); return; } Loadout loadout = Loadout.RequestInstance(); networkLoadout.CopyLoadout(loadout); master.SetLoadoutServer(loadout); Loadout.ReturnInstance(loadout); } private void SetBodyPreference(BodyIndex newBodyIndexPreference) { NetworkbodyIndexPreference = newBodyIndexPreference; NetworkUser.onNetworkUserBodyPreferenceChanged?.Invoke(this); } [Command] public void CmdSetBodyPreference(BodyIndex newBodyIndexPreference) { SetBodyPreference(newBodyIndexPreference); } [Client] public void SetSurvivorPreferenceClient(SurvivorDef survivorDef) { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUser::SetSurvivorPreferenceClient(RoR2.SurvivorDef)' called on server"); return; } if (!survivorDef) { throw new ArgumentException("Provided object is null or invalid", "survivorDef"); } BodyIndex bodyIndexFromSurvivorIndex = SurvivorCatalog.GetBodyIndexFromSurvivorIndex(survivorDef ? survivorDef.survivorIndex : SurvivorIndex.None); CallCmdSetBodyPreference(bodyIndexFromSurvivorIndex); } public SurvivorDef GetSurvivorPreference() { return SurvivorCatalog.GetSurvivorDef(SurvivorCatalog.GetSurvivorIndexFromBodyIndex(bodyIndexPreference)); } private void Update() { if (localUser == null) { return; } if (Time.timeScale != 0f) { secondAccumulator += Time.unscaledDeltaTime; } if (!(secondAccumulator >= 1f)) { return; } secondAccumulator -= 1f; if (!Run.instance) { return; } localUser.userProfile.totalRunSeconds++; if ((bool)masterObject) { CharacterMaster component = masterObject.GetComponent(); if ((bool)component && component.hasBody) { localUser.userProfile.totalAliveSeconds++; } } } public void UpdateUserName() { userName = GetNetworkPlayerName().GetResolvedName(); } [Command] public void CmdSendConsoleCommand(string commandName, string[] args) { Console.instance.RunClientCmd(this, commandName, args); } [Client] public void SendServerUnlockables() { if (!NetworkClient.active) { UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUser::SendServerUnlockables()' called on server"); } else if (localUser != null) { int unlockableCount = localUser.userProfile.statSheet.GetUnlockableCount(); UnlockableIndex[] array = new UnlockableIndex[unlockableCount]; for (int i = 0; i < unlockableCount; i++) { array[i] = localUser.userProfile.statSheet.GetUnlockableIndex(i); } CallCmdSendNewUnlockables(array); } } [Command] private void CmdSendNewUnlockables(UnlockableIndex[] newUnlockableIndices) { unlockables.Clear(); debugUnlockablesList.Clear(); int i = 0; for (int num = newUnlockableIndices.Length; i < num; i++) { UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(newUnlockableIndices[i]); if (unlockableDef != null) { unlockables.Add(unlockableDef); debugUnlockablesList.Add(unlockableDef.cachedName); } } NetworkUser.onNetworkUserUnlockablesUpdated?.Invoke(this); } [Server] public void ServerRequestUnlockables() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::ServerRequestUnlockables()' called on client"); } else { CallRpcRequestUnlockables(); } } [ClientRpc] private void RpcRequestUnlockables() { if (Util.HasEffectiveAuthority(base.gameObject)) { SendServerUnlockables(); } } [Command] public void CmdReportAchievement(string achievementNameToken) { Chat.SubjectFormatChatMessage subjectFormatChatMessage = new Chat.SubjectFormatChatMessage(); subjectFormatChatMessage.baseToken = "ACHIEVEMENT_UNLOCKED_MESSAGE"; subjectFormatChatMessage.subjectAsNetworkUser = this; subjectFormatChatMessage.paramTokens = new string[1] { achievementNameToken }; Chat.SendBroadcastChat(subjectFormatChatMessage); } [Command] public void CmdReportUnlock(UnlockableIndex unlockIndex) { UnityEngine.Debug.LogFormat("NetworkUser.CmdReportUnlock({0})", unlockIndex); UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(unlockIndex); if (unlockableDef != null) { ServerHandleUnlock(unlockableDef); } } [Server] public void ServerHandleUnlock([NotNull] UnlockableDef unlockableDef) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::ServerHandleUnlock(RoR2.UnlockableDef)' called on client"); return; } UnityEngine.Debug.LogFormat("NetworkUser.ServerHandleUnlock({0})", unlockableDef.cachedName); if ((bool)masterObject) { PlayerStatsComponent component = masterObject.GetComponent(); if ((bool)component) { component.currentStats.AddUnlockable(unlockableDef); component.ForceNextTransmit(); } } } [Server] public void ServerRemoveUnlock(UnlockableIndex index) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::ServerRemoveUnlock(RoR2.UnlockableIndex)' called on client"); return; } UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(index); UnityEngine.Debug.LogFormat("NetworkUser.ServerRemoveUnlock({0})", unlockableDef.cachedName); if ((bool)masterObject) { PlayerStatsComponent component = masterObject.GetComponent(); if ((bool)component) { component.currentStats.RemoveUnlockable(index); component.ForceNextTransmit(); } } (localUser?.userProfile)?.RevokeUnlockable(unlockableDef); } [Command] public void CmdAcknowledgeStage(NetworkInstanceId stageNetworkId) { serverLastStageAcknowledgedByClient = stageNetworkId; } [Command] public void CmdSubmitVote(GameObject voteControllerGameObject, int choiceIndex) { if ((bool)voteControllerGameObject) { VoteController component = voteControllerGameObject.GetComponent(); if ((bool)component) { component.ReceiveUserVote(this, choiceIndex); } } } public static bool AllParticipatingNetworkUsersReady() { ReadOnlyCollection readOnlyCollection = readOnlyInstancesList; for (int i = 0; i < readOnlyCollection.Count; i++) { NetworkUser networkUser = readOnlyCollection[i]; if (networkUser.isParticipating && !networkUser.connectionToClient.isReady) { return false; } } return true; } [CanBeNull] private static NetworkUser FindNetworkUserByUserProfile([NotNull] UserProfile userProfile) { if (userProfile == null) { throw new ArgumentNullException("userProfile"); } ReadOnlyCollection readOnlyLocalUsersList = LocalUserManager.readOnlyLocalUsersList; for (int i = 0; i < readOnlyLocalUsersList.Count; i++) { LocalUser localUser = readOnlyLocalUsersList[i]; if (localUser.userProfile == userProfile) { return localUser.currentNetworkUser; } } return null; } static NetworkUser() { instancesList = new List(); readOnlyInstancesList = new ReadOnlyCollection(instancesList); localPlayers = new List(); readOnlyLocalPlayersList = new ReadOnlyCollection(localPlayers); kCmdCmdAwardLunarCoins = 654823536; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdAwardLunarCoins, InvokeCmdCmdAwardLunarCoins); kCmdCmdStoreRebirthItems = -2063320580; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdStoreRebirthItems, InvokeCmdCmdStoreRebirthItems); kCmdCmdSetRebirthItems = 1883408829; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSetRebirthItems, InvokeCmdCmdSetRebirthItems); kCmdCmdSetNetLunarCoins = -934763456; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSetNetLunarCoins, InvokeCmdCmdSetNetLunarCoins); kCmdCmdSetBodyPreference = 234442470; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSetBodyPreference, InvokeCmdCmdSetBodyPreference); kCmdCmdSendConsoleCommand = -1997680971; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSendConsoleCommand, InvokeCmdCmdSendConsoleCommand); kCmdCmdSendNewUnlockables = 1855027350; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSendNewUnlockables, InvokeCmdCmdSendNewUnlockables); kCmdCmdReportAchievement = -1674656990; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdReportAchievement, InvokeCmdCmdReportAchievement); kCmdCmdReportUnlock = -1831223439; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdReportUnlock, InvokeCmdCmdReportUnlock); kCmdCmdAcknowledgeStage = -2118585573; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdAcknowledgeStage, InvokeCmdCmdAcknowledgeStage); kCmdCmdSubmitVote = 329593659; NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSubmitVote, InvokeCmdCmdSubmitVote); kRpcRpcDeductLunarCoins = -1554352898; NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkUser), kRpcRpcDeductLunarCoins, InvokeRpcRpcDeductLunarCoins); kRpcRpcStoreRebirthItems = -669811482; NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkUser), kRpcRpcStoreRebirthItems, InvokeRpcRpcStoreRebirthItems); kRpcRpcAwardLunarCoins = -604060198; NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkUser), kRpcRpcAwardLunarCoins, InvokeRpcRpcAwardLunarCoins); kRpcRpcRequestUnlockables = -1809653515; NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkUser), kRpcRpcRequestUnlockables, InvokeRpcRpcRequestUnlockables); NetworkCRC.RegisterBehaviour("NetworkUser", 0); } private void UNetVersion() { } protected static void InvokeCmdCmdAwardLunarCoins(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdAwardLunarCoins called on client."); } else { ((NetworkUser)obj).CmdAwardLunarCoins(reader.ReadPackedUInt32()); } } protected static void InvokeCmdCmdStoreRebirthItems(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdStoreRebirthItems called on client."); } else { ((NetworkUser)obj).CmdStoreRebirthItems((ItemIndex)reader.ReadInt32()); } } protected static void InvokeCmdCmdSetRebirthItems(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetRebirthItems called on client."); } else { ((NetworkUser)obj).CmdSetRebirthItems((ItemIndex)reader.ReadInt32()); } } protected static void InvokeCmdCmdSetNetLunarCoins(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetNetLunarCoins called on client."); } else { ((NetworkUser)obj).CmdSetNetLunarCoins(reader.ReadPackedUInt32()); } } protected static void InvokeCmdCmdSetBodyPreference(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSetBodyPreference called on client."); } else { ((NetworkUser)obj).CmdSetBodyPreference((BodyIndex)reader.ReadInt32()); } } protected static void InvokeCmdCmdSendConsoleCommand(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSendConsoleCommand called on client."); } else { ((NetworkUser)obj).CmdSendConsoleCommand(reader.ReadString(), GeneratedNetworkCode._ReadArrayString_None(reader)); } } protected static void InvokeCmdCmdSendNewUnlockables(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSendNewUnlockables called on client."); } else { ((NetworkUser)obj).CmdSendNewUnlockables(GeneratedNetworkCode._ReadArrayUnlockableIndex_None(reader)); } } protected static void InvokeCmdCmdReportAchievement(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdReportAchievement called on client."); } else { ((NetworkUser)obj).CmdReportAchievement(reader.ReadString()); } } protected static void InvokeCmdCmdReportUnlock(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdReportUnlock called on client."); } else { ((NetworkUser)obj).CmdReportUnlock((UnlockableIndex)reader.ReadInt32()); } } protected static void InvokeCmdCmdAcknowledgeStage(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdAcknowledgeStage called on client."); } else { ((NetworkUser)obj).CmdAcknowledgeStage(reader.ReadNetworkId()); } } protected static void InvokeCmdCmdSubmitVote(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("Command CmdSubmitVote called on client."); } else { ((NetworkUser)obj).CmdSubmitVote(reader.ReadGameObject(), (int)reader.ReadPackedUInt32()); } } public void CallCmdAwardLunarCoins(uint count) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdAwardLunarCoins called on server."); return; } if (base.isServer) { CmdAwardLunarCoins(count); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdAwardLunarCoins); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32(count); SendCommandInternal(networkWriter, 0, "CmdAwardLunarCoins"); } public void CallCmdStoreRebirthItems(ItemIndex item) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdStoreRebirthItems called on server."); return; } if (base.isServer) { CmdStoreRebirthItems(item); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdStoreRebirthItems); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)item); SendCommandInternal(networkWriter, 0, "CmdStoreRebirthItems"); } public void CallCmdSetRebirthItems(ItemIndex item) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetRebirthItems called on server."); return; } if (base.isServer) { CmdSetRebirthItems(item); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetRebirthItems); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)item); SendCommandInternal(networkWriter, 0, "CmdSetRebirthItems"); } public void CallCmdSetNetLunarCoins(uint newNetLunarCoins) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetNetLunarCoins called on server."); return; } if (base.isServer) { CmdSetNetLunarCoins(newNetLunarCoins); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetNetLunarCoins); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32(newNetLunarCoins); SendCommandInternal(networkWriter, 0, "CmdSetNetLunarCoins"); } public void CallCmdSetBodyPreference(BodyIndex newBodyIndexPreference) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSetBodyPreference called on server."); return; } if (base.isServer) { CmdSetBodyPreference(newBodyIndexPreference); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetBodyPreference); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)newBodyIndexPreference); SendCommandInternal(networkWriter, 0, "CmdSetBodyPreference"); } public void CallCmdSendConsoleCommand(string commandName, string[] args) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSendConsoleCommand called on server."); return; } if (base.isServer) { CmdSendConsoleCommand(commandName, args); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSendConsoleCommand); networkWriter.Write(GetComponent().netId); networkWriter.Write(commandName); GeneratedNetworkCode._WriteArrayString_None(networkWriter, args); SendCommandInternal(networkWriter, 0, "CmdSendConsoleCommand"); } public void CallCmdSendNewUnlockables(UnlockableIndex[] newUnlockableIndices) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSendNewUnlockables called on server."); return; } if (base.isServer) { CmdSendNewUnlockables(newUnlockableIndices); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSendNewUnlockables); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WriteArrayUnlockableIndex_None(networkWriter, newUnlockableIndices); SendCommandInternal(networkWriter, 0, "CmdSendNewUnlockables"); } public void CallCmdReportAchievement(string achievementNameToken) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdReportAchievement called on server."); return; } if (base.isServer) { CmdReportAchievement(achievementNameToken); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdReportAchievement); networkWriter.Write(GetComponent().netId); networkWriter.Write(achievementNameToken); SendCommandInternal(networkWriter, 0, "CmdReportAchievement"); } public void CallCmdReportUnlock(UnlockableIndex unlockIndex) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdReportUnlock called on server."); return; } if (base.isServer) { CmdReportUnlock(unlockIndex); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdReportUnlock); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)unlockIndex); SendCommandInternal(networkWriter, 0, "CmdReportUnlock"); } public void CallCmdAcknowledgeStage(NetworkInstanceId stageNetworkId) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdAcknowledgeStage called on server."); return; } if (base.isServer) { CmdAcknowledgeStage(stageNetworkId); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdAcknowledgeStage); networkWriter.Write(GetComponent().netId); networkWriter.Write(stageNetworkId); SendCommandInternal(networkWriter, 0, "CmdAcknowledgeStage"); } public void CallCmdSubmitVote(GameObject voteControllerGameObject, int choiceIndex) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("Command function CmdSubmitVote called on server."); return; } if (base.isServer) { CmdSubmitVote(voteControllerGameObject, choiceIndex); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSubmitVote); networkWriter.Write(GetComponent().netId); networkWriter.Write(voteControllerGameObject); networkWriter.WritePackedUInt32((uint)choiceIndex); SendCommandInternal(networkWriter, 0, "CmdSubmitVote"); } protected static void InvokeRpcRpcDeductLunarCoins(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcDeductLunarCoins called on server."); } else { ((NetworkUser)obj).RpcDeductLunarCoins(reader.ReadPackedUInt32()); } } protected static void InvokeRpcRpcStoreRebirthItems(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcStoreRebirthItems called on server."); } else { ((NetworkUser)obj).RpcStoreRebirthItems((ItemIndex)reader.ReadInt32()); } } protected static void InvokeRpcRpcAwardLunarCoins(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcAwardLunarCoins called on server."); } else { ((NetworkUser)obj).RpcAwardLunarCoins(reader.ReadPackedUInt32()); } } protected static void InvokeRpcRpcRequestUnlockables(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { UnityEngine.Debug.LogError("RPC RpcRequestUnlockables called on server."); } else { ((NetworkUser)obj).RpcRequestUnlockables(); } } public void CallRpcDeductLunarCoins(uint count) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcDeductLunarCoins called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcDeductLunarCoins); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32(count); SendRPCInternal(networkWriter, 0, "RpcDeductLunarCoins"); } public void CallRpcStoreRebirthItems(ItemIndex item) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcStoreRebirthItems called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcStoreRebirthItems); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)item); SendRPCInternal(networkWriter, 0, "RpcStoreRebirthItems"); } public void CallRpcAwardLunarCoins(uint count) { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcAwardLunarCoins called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcAwardLunarCoins); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32(count); SendRPCInternal(networkWriter, 0, "RpcAwardLunarCoins"); } public void CallRpcRequestUnlockables() { if (!NetworkServer.active) { UnityEngine.Debug.LogError("RPC Function RpcRequestUnlockables called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcRequestUnlockables); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcRequestUnlockables"); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { GeneratedNetworkCode._WriteNetworkUserId_None(writer, _id); writer.WritePackedUInt32(rewiredPlayerId); writer.Write(_masterObjectId); writer.Write(userColor); writer.WritePackedUInt32(netLunarCoins); writer.Write((int)rebirthItem); writer.Write((int)bodyIndexPreference); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WriteNetworkUserId_None(writer, _id); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32(rewiredPlayerId); } if ((base.syncVarDirtyBits & 4u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(_masterObjectId); } if ((base.syncVarDirtyBits & 8u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(userColor); } if ((base.syncVarDirtyBits & 0x10u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32(netLunarCoins); } if ((base.syncVarDirtyBits & 0x20u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write((int)rebirthItem); } if ((base.syncVarDirtyBits & 0x40u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write((int)bodyIndexPreference); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { _id = GeneratedNetworkCode._ReadNetworkUserId_None(reader); rewiredPlayerId = (byte)reader.ReadPackedUInt32(); _masterObjectId = reader.ReadNetworkId(); userColor = reader.ReadColor32(); netLunarCoins = reader.ReadPackedUInt32(); rebirthItem = (ItemIndex)reader.ReadInt32(); bodyIndexPreference = (BodyIndex)reader.ReadInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { OnSyncId(GeneratedNetworkCode._ReadNetworkUserId_None(reader)); } if (((uint)num & 2u) != 0) { rewiredPlayerId = (byte)reader.ReadPackedUInt32(); } if (((uint)num & 4u) != 0) { OnSyncMasterObjectId(reader.ReadNetworkId()); } if (((uint)num & 8u) != 0) { userColor = reader.ReadColor32(); } if (((uint)num & 0x10u) != 0) { netLunarCoins = reader.ReadPackedUInt32(); } if (((uint)num & 0x20u) != 0) { rebirthItem = (ItemIndex)reader.ReadInt32(); } if (((uint)num & 0x40u) != 0) { SetBodyPreference((BodyIndex)reader.ReadInt32()); } } public override void PreStartClient() { } } [DisallowMultipleComponent] public class NonSolidToCamera : MonoBehaviour { } [ExecuteAlways] [RequireComponent(typeof(ParticleSystem))] public class NormalizeParticleScale : MonoBehaviour { public bool normalizeWithSkinnedMeshRendererInstead; [Tooltip("if the mesh scale is below this value, don't use the renderer to normalize our scale")] public float skinnedMeshRendererMinScale; private ParticleSystem particleSystem; public void OnEnable() { UpdateParticleSystem(); } public void UpdateParticleSystem() { if (!particleSystem) { particleSystem = GetComponent(); } ParticleSystem.MainModule main = particleSystem.main; ParticleSystem.MinMaxCurve startSize = main.startSize; UnityEngine.Vector3 lossyScale = base.transform.lossyScale; float num = 1f; if (normalizeWithSkinnedMeshRendererInstead) { SkinnedMeshRenderer skinnedMeshRenderer = particleSystem.shape.skinnedMeshRenderer; if ((bool)skinnedMeshRenderer) { _ = skinnedMeshRenderer.transform.lossyScale; float num2 = Mathf.Max(lossyScale.x, lossyScale.y, lossyScale.z); if (num2 < skinnedMeshRendererMinScale) { num = num2; } } } else { num = Mathf.Max(lossyScale.x, lossyScale.y, lossyScale.z); } startSize.constantMin /= num; startSize.constantMax /= num; main.startSize = startSize; } } public class ObjectScaleCurve : MonoBehaviour { public bool useOverallCurveOnly; public bool resetOnAwake = true; public bool useUnscaledTime; public AnimationCurve curveX; public AnimationCurve curveY; public AnimationCurve curveZ; public AnimationCurve overallCurve; public float timeMax = 5f; public float time { get; set; } public UnityEngine.Vector3 baseScale { get; set; } private void Awake() { baseScale = base.transform.localScale; if (resetOnAwake) { Reset(); } } private void OnEnable() { Reset(); } public void Reset() { time = 0f; UpdateScale(0f); } private void Update() { time += (useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime); UpdateScale(time); } private void UpdateScale(float time) { float num = ((timeMax > 0f) ? Mathf.Clamp01(time / timeMax) : 0f); float num2 = 1f; if (overallCurve != null) { num2 = overallCurve.Evaluate(num); } UnityEngine.Vector3 vector; if (useOverallCurveOnly) { vector = baseScale * num2; } else { if (curveX == null || curveY == null || curveZ == null) { return; } vector = new UnityEngine.Vector3(curveX.Evaluate(num) * baseScale.x, curveY.Evaluate(num) * baseScale.y, curveZ.Evaluate(num) * baseScale.z); } base.transform.localScale = vector * num2; } } public class ObjectTransformCurve : MonoBehaviour { public bool useRotationCurves; public bool useTranslationCurves; public bool loop; public bool randomizeInitialTime; public AnimationCurve rotationCurveX; public AnimationCurve rotationCurveY; public AnimationCurve rotationCurveZ; public AnimationCurve translationCurveX; public AnimationCurve translationCurveY; public AnimationCurve translationCurveZ; public float timeMax = 5f; public float time { get; set; } public UnityEngine.Vector3 basePosition { get; private set; } public UnityEngine.Quaternion baseRotation { get; private set; } private void Awake() { basePosition = base.transform.localPosition; baseRotation = base.transform.localRotation; Reset(); } private void OnEnable() { Reset(); } public void Reset() { time = 0f; if (randomizeInitialTime) { time = UnityEngine.Random.Range(0f, timeMax); } UpdateTransform(time); } private void Update() { time += Time.deltaTime; if (loop && time > timeMax) { time %= timeMax; } UpdateTransform(time); } private void UpdateTransform(float time) { UnityEngine.Vector3 vector = basePosition; UnityEngine.Quaternion quaternion = baseRotation; float num = ((timeMax > 0f) ? Mathf.Clamp01(time / timeMax) : 0f); if (useRotationCurves) { if (rotationCurveX == null || rotationCurveY == null || rotationCurveZ == null) { return; } quaternion = UnityEngine.Quaternion.Euler(rotationCurveX.Evaluate(num), rotationCurveY.Evaluate(num), rotationCurveZ.Evaluate(num)); base.transform.localRotation = quaternion; } if (useTranslationCurves && translationCurveX != null && translationCurveY != null && translationCurveZ != null) { vector = new UnityEngine.Vector3(translationCurveX.Evaluate(num), translationCurveY.Evaluate(num), translationCurveZ.Evaluate(num)); base.transform.localPosition = vector; } } } public class OccupyNearbyNodes : MonoBehaviour { public float radius = 5f; private static readonly List instancesList = new List(); private void OnDrawGizmos() { Gizmos.color = new UnityEngine.Color(1f, 1f, 0f, 0.3f); Gizmos.DrawWireSphere(base.transform.position, radius); } private void OnEnable() { instancesList.Add(this); } private void OnDisable() { instancesList.Remove(this); } [RuntimeInitializeOnLoadMethod] private static void Init() { SceneDirector.onPrePopulateSceneServer += OnSceneDirectorPrePopulateSceneServer; } private static void OnSceneDirectorPrePopulateSceneServer(SceneDirector sceneDirector) { DirectorCore instance = DirectorCore.instance; NodeGraph groundNodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground); NodeGraph.NodeIndex[] array = instancesList.SelectMany((OccupyNearbyNodes v) => groundNodeGraph.FindNodesInRange(v.transform.position, 0f, v.radius, HullMask.None)).Distinct().ToArray(); foreach (NodeGraph.NodeIndex nodeIndex in array) { instance.AddOccupiedNode(groundNodeGraph, nodeIndex); } } } public class OmniEffect : MonoBehaviour { [Serializable] public class OmniEffectElement { public string name; public ParticleSystem particleSystem; public bool particleSystemEmitParticles; public Material particleSystemOverrideMaterial; public float maximumValidRadius = float.PositiveInfinity; public float bonusEmissionPerBonusRadius; public void ProcessEffectElement(float radius, float minimumValidRadius) { if (!particleSystem) { return; } if ((bool)particleSystemOverrideMaterial) { ParticleSystemRenderer component = particleSystem.GetComponent(); if ((bool)particleSystemOverrideMaterial) { component.material = particleSystemOverrideMaterial; } } ParticleSystem.EmissionModule emission = particleSystem.emission; if (emission.burstCount > 0) { int num = Mathf.Min(emission.GetBurst(0).maxCount + (int)((radius - minimumValidRadius) * bonusEmissionPerBonusRadius), particleSystem.main.maxParticles); emission.SetBurst(0, new ParticleSystem.Burst(0f, num)); } if (particleSystemEmitParticles) { particleSystem.gameObject.SetActive(value: true); } else { particleSystem.gameObject.SetActive(value: false); } } } [Serializable] public class OmniEffectGroup { public string name; public OmniEffectElement[] omniEffectElements; } public OmniEffectGroup[] omniEffectGroups; private float radius; private void Start() { radius = base.transform.localScale.x; OmniEffectGroup[] array = omniEffectGroups; foreach (OmniEffectGroup omniEffectGroup in array) { float minimumValidRadius = 0f; for (int j = 0; j < omniEffectGroup.omniEffectElements.Length; j++) { OmniEffectElement omniEffectElement = omniEffectGroup.omniEffectElements[j]; if (omniEffectElement.maximumValidRadius >= radius) { omniEffectElement.ProcessEffectElement(radius, minimumValidRadius); break; } minimumValidRadius = omniEffectElement.maximumValidRadius; } } } } public class OnCollisionEventController : NetworkBehaviour { [Serializable] public class OnCollisionEvent : UnityEvent { } [SerializeField] private float monsterCredits; [SerializeField] private CombatDirector director; [SerializeField] private bool shouldAccountForMultiplePlayers; public OnCollisionEvent onPlayerCollision; [SyncVar] public bool available = true; public bool Networkavailable { get { return available; } [param: In] set { SetSyncVar(value, ref available, 1u); } } public override int GetNetworkChannel() { return QosChannelIndex.defaultReliable.intVal; } public void OnTriggerStay(Collider other) { if (NetworkServer.active && available && other.TryGetComponent(out var component) && component.isPlayerControlled) { int participatingPlayerCount = Run.instance.participatingPlayerCount; if (shouldAccountForMultiplePlayers) { monsterCredits *= participatingPlayerCount; } if ((bool)director) { director.SetMonsterCredit(monsterCredits); } onPlayerCollision.Invoke(); } } [Server] public void SetAvailable(bool setActive) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.OnCollisionEventController::SetAvailable(System.Boolean)' called on client"); } else { Networkavailable = setActive; } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(available); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(available); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { available = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { available = reader.ReadBoolean(); } } public override void PreStartClient() { } } public class OnDestroyCallback : MonoBehaviour { private Action callback; public void OnDestroy() { if (callback != null) { callback(this); } } public static OnDestroyCallback AddCallback(GameObject gameObject, Action callback) { OnDestroyCallback onDestroyCallback = gameObject.AddComponent(); onDestroyCallback.callback = callback; return onDestroyCallback; } public static void RemoveCallback(OnDestroyCallback callbackComponent) { callbackComponent.callback = null; UnityEngine.Object.Destroy(callbackComponent); } } public class OnDisableEvent : MonoBehaviour { public UnityEvent action; private void OnDisable() { action?.Invoke(); } } public class OnEnableEvent : MonoBehaviour { public UnityEvent action; private void OnEnable() { action?.Invoke(); } } public class OnPlayerEnterEvent : MonoBehaviour { public bool serverOnly; public UnityEvent action; private bool calledAction; private void OnTriggerEnter(Collider other) { if ((!serverOnly || NetworkServer.active) && !calledAction) { CharacterBody component = other.GetComponent(); if ((bool)component && component.isPlayerControlled) { UnityEngine.Debug.LogFormat("OnPlayerEnterEvent called on {0}", base.gameObject.name); calledAction = true; action?.Invoke(); } } } } public class OptionChestBehavior : NetworkBehaviour, IChestBehavior { [SerializeField] private PickupDropTable dropTable; [SerializeField] private Transform dropTransform; [SerializeField] private float dropUpVelocityStrength = 20f; [SerializeField] private float dropForwardVelocityStrength = 2f; [SerializeField] private SerializableEntityStateType openState = new SerializableEntityStateType(typeof(EntityStates.Barrel.Opening)); [SerializeField] private GameObject pickupPrefab; [SerializeField] private int numOptions; [SerializeField] private ItemTier displayTier; private PickupIndex[] generatedDrops; private Xoroshiro128Plus rng; public override int GetNetworkChannel() { return QosChannelIndex.defaultReliable.intVal; } [Server] public void Roll() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.OptionChestBehavior::Roll()' called on client"); } else { generatedDrops = dropTable.GenerateUniqueDrops(numOptions, rng); } } private void Awake() { if (dropTransform == null) { dropTransform = base.transform; } } private void Start() { if (NetworkServer.active) { rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); Roll(); } } [Server] public void Open() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.OptionChestBehavior::Open()' called on client"); return; } EntityStateMachine component = GetComponent(); if ((bool)component) { component.SetNextState(EntityStateCatalog.InstantiateState(ref openState)); } } [Server] public void ItemDrop() { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.OptionChestBehavior::ItemDrop()' called on client"); } else if (generatedDrops != null && generatedDrops.Length != 0) { GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo); createPickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromArray(generatedDrops); createPickupInfo.prefabOverride = pickupPrefab; createPickupInfo.position = dropTransform.position; createPickupInfo.rotation = UnityEngine.Quaternion.identity; createPickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(displayTier); GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo; PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, UnityEngine.Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength); generatedDrops = null; } } public bool HasRolledPickup(PickupIndex pickupIndex) { if (generatedDrops != null) { PickupIndex[] array = generatedDrops; for (int i = 0; i < array.Length; i++) { if (array[i] == pickupIndex) { return true; } } } return false; } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { bool result = default(bool); return result; } public override void OnDeserialize(NetworkReader reader, bool initialState) { } public override void PreStartClient() { } } public class OrbFireZone : MonoBehaviour { public float baseDamage; public float procCoefficient; public float orbRemoveFromBottomOfListFrequency; public float orbResetListFrequency; private List previousColliderList = new List(); private float resetStopwatch; private float removeFromBottomOfListStopwatch; private void Awake() { } private void FixedUpdate() { if (previousColliderList.Count > 0) { resetStopwatch += Time.fixedDeltaTime; removeFromBottomOfListStopwatch += Time.fixedDeltaTime; if (removeFromBottomOfListStopwatch > 1f / orbRemoveFromBottomOfListFrequency) { removeFromBottomOfListStopwatch -= 1f / orbRemoveFromBottomOfListFrequency; previousColliderList.RemoveAt(previousColliderList.Count - 1); } if (resetStopwatch > 1f / orbResetListFrequency) { resetStopwatch -= 1f / orbResetListFrequency; previousColliderList.Clear(); } } } private void OnTriggerStay(Collider other) { if (!NetworkServer.active || previousColliderList.Contains(other)) { return; } previousColliderList.Add(other); CharacterBody component = other.GetComponent(); if ((bool)component && (bool)component.mainHurtBox) { DamageOrb damageOrb = new DamageOrb(); damageOrb.attacker = null; damageOrb.damageOrbType = DamageOrb.DamageOrbType.ClayGooOrb; damageOrb.procCoefficient = procCoefficient; damageOrb.damageValue = baseDamage * Run.instance.teamlessDamageCoefficient; damageOrb.target = component.mainHurtBox; damageOrb.teamIndex = TeamIndex.None; if (Physics.Raycast(damageOrb.target.transform.position + UnityEngine.Random.insideUnitSphere * 3f, UnityEngine.Vector3.down, out var hitInfo, 1000f, LayerIndex.world.mask)) { damageOrb.origin = hitInfo.point; OrbManager.instance.AddOrb(damageOrb); } } } } public class OrbitalLaserController : MonoBehaviour { private abstract class OrbitalLaserBaseState : BaseState { protected OrbitalLaserController controller; public override void OnEnter() { base.OnEnter(); controller = GetComponent(); } } private class OrbitalLaserChargeState : OrbitalLaserBaseState { public override void OnEnter() { base.OnEnter(); controller.chargeEffect.SetActive(value: true); controller.maxSpeed = controller.chargeMaxVelocity; } public override void OnExit() { controller.chargeEffect.SetActive(value: false); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= controller.chargeDuration) { outer.SetNextState(new OrbitalLaserFireState()); } } } private class OrbitalLaserFireState : OrbitalLaserBaseState { private float bulletAttackTimer; public override void OnEnter() { base.OnEnter(); controller.fireEffect.SetActive(value: true); controller.maxSpeed = controller.fireMaxVelocity; } public override void OnExit() { controller.fireEffect.SetActive(value: false); base.OnExit(); } public override void FixedUpdate() { base.FixedUpdate(); if (!NetworkServer.active) { return; } if (base.fixedAge >= controller.fireDuration || !controller.ownerBody) { outer.SetNextState(new OrbitalLaserDecayState()); return; } bulletAttackTimer -= GetDeltaTime(); if ((bool)controller.ownerBody && bulletAttackTimer < 0f) { bulletAttackTimer += 1f / controller.fireFrequency; BulletAttack bulletAttack = new BulletAttack(); bulletAttack.owner = controller.ownerBody.gameObject; bulletAttack.weapon = base.gameObject; bulletAttack.origin = base.transform.position + UnityEngine.Vector3.up * 600f; bulletAttack.maxDistance = 1200f; bulletAttack.aimVector = UnityEngine.Vector3.down; bulletAttack.minSpread = 0f; bulletAttack.maxSpread = 0f; bulletAttack.damage = Mathf.Lerp(controller.damageCoefficientInitial, controller.damageCoefficientFinal, base.fixedAge / controller.fireDuration) * controller.ownerBody.damage / controller.fireFrequency; bulletAttack.force = controller.force; bulletAttack.tracerEffectPrefab = controller.tracerEffectPrefab; bulletAttack.muzzleName = ""; bulletAttack.hitEffectPrefab = controller.hitEffectPrefab; bulletAttack.isCrit = Util.CheckRoll(controller.ownerBody.crit, controller.ownerBody.master); bulletAttack.stopperMask = LayerIndex.world.mask; bulletAttack.damageColorIndex = DamageColorIndex.Item; bulletAttack.procCoefficient = controller.procCoefficient / controller.fireFrequency; bulletAttack.radius = 2f; bulletAttack.Fire(); } } } private class OrbitalLaserDecayState : OrbitalLaserBaseState { public override void OnEnter() { base.OnEnter(); controller.maxSpeed = 0f; } public override void FixedUpdate() { base.FixedUpdate(); if (NetworkServer.active && base.fixedAge >= controller.decayDuration) { EntityState.Destroy(base.gameObject); } } } [NonSerialized] public CharacterBody ownerBody; private InputBankTest ownerInputBank; [Header("Movement Parameters")] public float smoothDampTime = 0.3f; private UnityEngine.Vector3 velocity; private float maxSpeed; [Header("Attack Parameters")] public float fireFrequency = 5f; public float damageCoefficientInitial = 6f; public float damageCoefficientFinal = 6f; public float procCoefficient = 0.5f; public float force; [Header("Charge")] public GameObject chargeEffect; public float chargeDuration = 3f; public float chargeMaxVelocity = 20f; private Transform chargeEffectTransform; [Header("Fire")] public GameObject fireEffect; public float fireDuration = 6f; public float fireMaxVelocity = 1f; public GameObject tracerEffectPrefab; public GameObject hitEffectPrefab; [Header("Decay")] public float decayDuration = 1.5f; [Header("Laser Pointer")] [Tooltip("The transform of the child laser pointer effect.")] public Transform laserPointerEffectTransform; [Tooltip("The transform of the muzzle effect.")] public Transform muzzleEffectTransform; private UnityEngine.Vector3 mostRecentPointerPosition; private UnityEngine.Vector3 mostRecentPointerNormal; private UnityEngine.Vector3 mostRecentMuzzlePosition; private void Start() { chargeEffect.SetActive(value: true); chargeEffect.GetComponent().timeMax = chargeDuration; mostRecentPointerPosition = base.transform.position; mostRecentPointerNormal = UnityEngine.Vector3.up; } private void UpdateLaserPointer() { if ((bool)ownerBody) { ownerInputBank = ownerBody.GetComponent(); Ray ray = default(Ray); ray.origin = ownerInputBank.aimOrigin; ray.direction = ownerInputBank.aimDirection; Ray ray2 = ray; mostRecentMuzzlePosition = ray2.origin; float num = 900f; if (Physics.Raycast(ray2, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) { mostRecentPointerPosition = hitInfo.point; } else { mostRecentPointerPosition = ray2.GetPoint(num); } mostRecentPointerNormal = -ray2.direction; } } private void Update() { UpdateLaserPointer(); laserPointerEffectTransform.SetPositionAndRotation(mostRecentPointerPosition, UnityEngine.Quaternion.LookRotation(mostRecentPointerNormal)); muzzleEffectTransform.SetPositionAndRotation(mostRecentMuzzlePosition, UnityEngine.Quaternion.identity); } private void FixedUpdate() { UpdateLaserPointer(); if (NetworkServer.active) { base.transform.position = UnityEngine.Vector3.SmoothDamp(base.transform.position, mostRecentPointerPosition, ref velocity, smoothDampTime, maxSpeed, Time.fixedDeltaTime); } } } public class OutroCutsceneController : MonoBehaviour { public PlayableDirector playableDirector; private int finishCount; public static OutroCutsceneController instance { get; private set; } public bool cutsceneIsFinished { get; private set; } public void Finish() { finishCount++; if (finishCount >= 1) { cutsceneIsFinished = true; } } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); } private void OnDisable() { instance = SingletonHelper.Unassign(instance, this); } } public class OutsideInteractableLocker : MonoBehaviour { private struct Candidate { public PurchaseInteraction purchaseInteraction; public float distanceSqr; } private class LockInfo { public GameObject lockObj; public float distSqr; public bool IsLocked() { return lockObj != null; } } [StructLayout(LayoutKind.Sequential, Size = 1)] private struct CandidateDistanceCompararer : IComparer { public int Compare(Candidate a, Candidate b) { return a.distanceSqr.CompareTo(b.distanceSqr); } } [Tooltip("The networked object which will be instantiated to lock purchasables.")] public GameObject lockPrefab; [Tooltip("How long to wait between steps.")] public float updateInterval = 0.1f; [Tooltip("Whether or not to invert the requirements.")] public bool lockInside; private Dictionary lockObjectMap; private Dictionary eggLockInfoMap; private float updateTimer; private IEnumerator currentCoroutine; public float radius { get; set; } private void Awake() { if (NetworkServer.active) { lockObjectMap = new Dictionary(); if (DevotionInventoryController.isDevotionEnable) { eggLockInfoMap = new Dictionary(); } } else { base.enabled = false; } } private void OnEnable() { if (NetworkServer.active) { currentCoroutine = ChestLockCoroutine(); updateTimer = updateInterval; } } private void OnDisable() { if (NetworkServer.active) { currentCoroutine = null; UnlockAll(); } } private void FixedUpdate() { updateTimer -= Time.fixedDeltaTime; if (updateTimer <= 0f) { updateTimer = updateInterval; currentCoroutine?.MoveNext(); } } private void LockPurchasable(PurchaseInteraction purchaseInteraction) { if (!purchaseInteraction.lockGameObject) { GameObject gameObject = UnityEngine.Object.Instantiate(lockPrefab, purchaseInteraction.transform.position, UnityEngine.Quaternion.identity); NetworkServer.Spawn(gameObject); purchaseInteraction.NetworklockGameObject = gameObject; lockObjectMap.Add(purchaseInteraction, gameObject); } } private void UnlockPurchasable(PurchaseInteraction purchaseInteraction) { if (lockObjectMap.TryGetValue(purchaseInteraction, out var value) && !(value != purchaseInteraction.lockGameObject)) { UnityEngine.Object.Destroy(value); lockObjectMap.Remove(purchaseInteraction); } } private void UnlockAll() { foreach (GameObject value in lockObjectMap.Values) { UnityEngine.Object.Destroy(value); } lockObjectMap.Clear(); if (eggLockInfoMap == null) { return; } foreach (KeyValuePair item in eggLockInfoMap) { UnlockLemurianEgg(item.Key); } eggLockInfoMap.Clear(); } private void LockLemurianEgg(LemurianEggController egg) { GameObject gameObject = UnityEngine.Object.Instantiate(lockPrefab, egg.transform.position, UnityEngine.Quaternion.identity); NetworkServer.Spawn(gameObject); eggLockInfoMap[egg].lockObj = gameObject; egg.SetInteractability(interactable: false); } private void UnlockLemurianEgg(LemurianEggController egg) { LockInfo lockInfo = eggLockInfoMap[egg]; if ((bool)lockInfo.lockObj) { NetworkServer.Destroy(lockInfo.lockObj); lockInfo.lockObj = null; } egg.SetInteractability(interactable: true); } private IEnumerator ChestLockCoroutine() { Candidate[] candidates = new Candidate[64]; int candidatesCount = 0; if (DevotionInventoryController.isDevotionEnable) { foreach (LemurianEggController instances in InstanceTracker.GetInstancesList()) { LockInfo lockInfo = new LockInfo(); lockInfo.lockObj = null; lockInfo.distSqr = (instances.transform.position - base.transform.position).sqrMagnitude; eggLockInfoMap[instances] = lockInfo; } } while (true) { UnityEngine.Vector3 position = base.transform.position; if (DevotionInventoryController.isDevotionEnable) { foreach (KeyValuePair item in eggLockInfoMap) { float num = radius * radius; LockInfo value = item.Value; bool flag = value.distSqr <= num; value.IsLocked(); if (flag != lockInside) { UnlockLemurianEgg(item.Key); } else { LockLemurianEgg(item.Key); } } } List instancesList = InstanceTracker.GetInstancesList(); int num2 = candidatesCount; candidatesCount = instancesList.Count; ArrayUtils.EnsureCapacity(ref candidates, candidatesCount); for (int j = num2; j < candidatesCount; j++) { candidates[j] = default(Candidate); } for (int k = 0; k < candidatesCount; k++) { PurchaseInteraction purchaseInteraction = instancesList[k]; candidates[k] = new Candidate { purchaseInteraction = purchaseInteraction, distanceSqr = (purchaseInteraction.transform.position - position).sqrMagnitude }; } yield return null; Array.Sort(candidates, 0, candidatesCount, default(CandidateDistanceCompararer)); yield return null; int i = 0; while (i < candidatesCount) { PurchaseInteraction purchaseInteraction2 = candidates[i].purchaseInteraction; if ((bool)purchaseInteraction2) { float num3 = radius * radius; if (candidates[i].distanceSqr <= num3 != lockInside || !purchaseInteraction2.available) { UnlockPurchasable(purchaseInteraction2); } else { LockPurchasable(purchaseInteraction2); } yield return null; } int num4 = i + 1; i = num4; } yield return null; } } } public class PaintDetailsBelow : MonoBehaviour { [Tooltip("Influence radius in world coordinates")] public float influenceOuter = 2f; public float influenceInner = 1f; [Tooltip("Which detail layer")] public int layer; [Tooltip("Density, from 0-1")] public float density = 0.5f; public float densityPower = 1f; private static List painterList; static PaintDetailsBelow() { painterList = new List(); } public void OnEnable() { painterList.Add(this); } public void OnDisable() { painterList.Remove(this); } public static List GetPainters() { return painterList; } } public class PaintTerrain : MonoBehaviour { public float splatHeightReference = 60f; public float splatRaycastLength = 200f; public float splatSlopePower = 1f; public float heightPower = 1f; public UnityEngine.Vector3 snowfallDirection = UnityEngine.Vector3.up; public Texture2D grassNoiseMap; private Terrain terrain; private TerrainData data; private float[,,] alphamaps; private int[,] detailmapGrass; private void Start() { snowfallDirection = snowfallDirection.normalized; terrain = GetComponent(); data = terrain.terrainData; alphamaps = data.GetAlphamaps(0, 0, data.alphamapWidth, data.alphamapHeight); detailmapGrass = data.GetDetailLayer(0, 0, data.detailWidth, data.detailHeight, 0); UpdateAlphaMaps(); UpdateDetailMaps(); } private void UpdateAlphaMaps() { for (int i = 0; i < data.alphamapHeight; i++) { for (int j = 0; j < data.alphamapWidth; j++) { float z = (float)j / (float)data.alphamapWidth * data.size.x; float x = (float)i / (float)data.alphamapHeight * data.size.z; float num = 0f; float num2 = 0f; float num3 = 0f; float num4 = 0f; float num5 = Mathf.Pow(UnityEngine.Vector3.Dot(UnityEngine.Vector3.up, data.GetInterpolatedNormal((float)i / (float)data.alphamapHeight, (float)j / (float)data.alphamapWidth)), splatSlopePower); num = num5; num3 = 1f - num5; float interpolatedHeight = data.GetInterpolatedHeight((float)i / (float)data.alphamapHeight, (float)j / (float)data.alphamapWidth); if (Physics.Raycast(new UnityEngine.Vector3(x, interpolatedHeight, z), snowfallDirection, out var hitInfo, splatRaycastLength, LayerIndex.world.mask)) { float num6 = num; float num7 = Mathf.Clamp01(Mathf.Pow(hitInfo.distance / splatHeightReference, heightPower)); num = num7 * num6; num2 = (1f - num7) * num6; } alphamaps[j, i, 0] = num; alphamaps[j, i, 1] = num2; alphamaps[j, i, 2] = num3; alphamaps[j, i, 3] = num4; } } data.SetAlphamaps(0, 0, alphamaps); } private void UpdateDetailMaps() { for (int i = 0; i < data.detailHeight; i++) { for (int j = 0; j < data.detailWidth; j++) { int num = 0; detailmapGrass[j, i] = num; } } data.SetDetailLayer(0, 0, 0, detailmapGrass); } } public class PaladinBarrierController : MonoBehaviour, IBarrier { public float blockLaserDamageCoefficient; public float blockLaserProcCoefficient; public float blockLaserDistance; private float totalDamageBlocked; private CharacterBody characterBody; private InputBankTest inputBank; private TeamComponent teamComponent; private bool barrierIsOn; public Transform barrierPivotTransform; public void BlockedDamage(DamageInfo damageInfo, float actualDamageBlocked) { totalDamageBlocked += actualDamageBlocked; LightningOrb lightningOrb = new LightningOrb(); lightningOrb.teamIndex = teamComponent.teamIndex; lightningOrb.origin = damageInfo.position; lightningOrb.damageValue = actualDamageBlocked * blockLaserDamageCoefficient; lightningOrb.bouncesRemaining = 0; lightningOrb.attacker = damageInfo.attacker; lightningOrb.procCoefficient = blockLaserProcCoefficient; lightningOrb.lightningType = LightningOrb.LightningType.TreePoisonDart; HurtBox hurtBox = lightningOrb.PickNextTarget(lightningOrb.origin); if ((bool)hurtBox) { lightningOrb.target = hurtBox; lightningOrb.isCrit = Util.CheckRoll(characterBody.crit, characterBody.master); OrbManager.instance.AddOrb(lightningOrb); } } public void EnableBarrier() { barrierPivotTransform.gameObject.SetActive(value: true); barrierIsOn = true; } public void DisableBarrier() { barrierPivotTransform.gameObject.SetActive(value: false); barrierIsOn = false; } private void Start() { inputBank = GetComponent(); characterBody = GetComponent(); teamComponent = GetComponent(); DisableBarrier(); } private void Update() { if (barrierIsOn) { barrierPivotTransform.rotation = Util.QuaternionSafeLookRotation(inputBank.aimDirection); } } } public class ParticleBirthEvent : MonoBehaviour { public ParticleSystem particleSystemToTrack; public bool OnServerOnly; [Tooltip("Displays a message whenever a new particle is born")] public bool debugMessages; [Space(20f)] public UnityEvent onParticleBirth; private ParticleSystem.Particle[] particleArray; private void Awake() { if (particleSystemToTrack == null) { particleSystemToTrack = GetComponent(); } if (particleSystemToTrack != null) { particleArray = new ParticleSystem.Particle[particleSystemToTrack.main.maxParticles]; } } private void LateUpdate() { if (particleSystemToTrack == null || (OnServerOnly && !NetworkServer.active)) { base.enabled = false; } else { if (!particleSystemToTrack.isEmitting) { return; } int particles = particleSystemToTrack.GetParticles(particleArray); for (int i = 0; i < particles; i++) { ParticleSystem.Particle particle = particleArray[i]; if (Mathf.Approximately(particle.startLifetime, particle.remainingLifetime)) { FireEvent(); break; } } } } private void FireEvent() { _ = debugMessages; onParticleBirth?.Invoke(); } } public class ParticleDeathEvent : MonoBehaviour { public ParticleSystem particleSystemToTrack; public bool OnServerOnly; [Tooltip("Displays a message whenever a new particle is born")] public bool debugMessages; [Space(20f)] [Tooltip("The trigger will not fire if it's fired within this many seconds ago. Leave at -1 for 'fire every frame if need be.'")] public float triggerCooldown = -1f; [Space(20f)] public UnityEvent onParticleTrigger; private ParticleSystem.Particle[] particleArray; private float lastTriggerTimestamp; private float nextEventFireTimestamp = -1f; private void Awake() { if (particleSystemToTrack == null) { particleSystemToTrack = GetComponent(); } if (particleSystemToTrack != null) { particleArray = new ParticleSystem.Particle[particleSystemToTrack.main.maxParticles]; } } private void LateUpdate() { if (particleSystemToTrack == null || (OnServerOnly && !NetworkServer.active)) { base.enabled = false; return; } float time = Time.time; if (nextEventFireTimestamp > 0f && time > nextEventFireTimestamp) { HandleFireEvent(time); } if (particleSystemToTrack.isEmitting) { HandleEstimateNextParticleDeath(time); } } private void HandleEstimateNextParticleDeath(float currentTime) { int particles = particleSystemToTrack.GetParticles(particleArray); float num = ((nextEventFireTimestamp != -1f) ? (nextEventFireTimestamp - currentTime) : float.MaxValue); for (int i = 0; i < particles; i++) { float remainingLifetime = particleArray[i].remainingLifetime; if (remainingLifetime < num) { num = remainingLifetime; } } if (num != float.MaxValue) { nextEventFireTimestamp = currentTime + num; } } private void HandleFireEvent(float currentTime) { nextEventFireTimestamp = -1f; if (!(currentTime - lastTriggerTimestamp < triggerCooldown)) { _ = debugMessages; lastTriggerTimestamp = currentTime; onParticleTrigger?.Invoke(); } } } public class ParticleLifetimeSoundPlayer : MonoBehaviour { private class ParticleLifetimeTracker { private static int idCounter; public bool isActive; private bool firedStart; private bool firedEnd; private float lifetimeTimeStamp; private float startTimeTimeStamp; private float endTimeTimeStamp; private int localId; private AK.Wwise.Event startEvent; private AK.Wwise.Event endEvent; private GameObject soundObject; public ParticleLifetimeTracker(GameObject go) { soundObject = go; } public void Initialize(float currentTime, float lifeTime, float startTimeOffset, float endTimeOffset, ref AK.Wwise.Event _startEvent, ref AK.Wwise.Event _endEvent, bool debug) { localId = idCounter++; lifetimeTimeStamp = currentTime + lifeTime; startTimeTimeStamp = currentTime + startTimeOffset; endTimeTimeStamp = lifetimeTimeStamp + endTimeOffset; firedStart = false; firedEnd = false; isActive = true; startEvent = _startEvent; endEvent = _endEvent; } public void Update(float currentTime, bool debug) { if (isActive) { if (!firedStart && currentTime > startTimeTimeStamp) { firedStart = true; startEvent?.Post(soundObject); } if (!firedEnd && currentTime > endTimeTimeStamp) { firedEnd = true; endEvent?.Post(soundObject); } isActive = currentTime < lifetimeTimeStamp; _ = !isActive && debug; } } } public ParticleSystem particleSystemToTrack; [Tooltip("How long after a particle is born should the StartEvent be posted.")] public float startTimeOffset; [Tooltip("How long before/after a particle dies should the EndEvent be posted.")] public float endTimeOffset; [Tooltip("Displays a message whenever a new particle is born")] public bool debugMessages; public AK.Wwise.Event startEvent; public AK.Wwise.Event endEvent; [Tooltip("How long between particles should we wait before firing the next sound. -1 = no delay")] public float soundCooldown = -1f; private float lastParticleTrackedTimeStamp; private ParticleSystem.Particle[] particleArray; [Space(20f)] [SerializeField] public List soundObjects = new List(); private List particleTrackers = new List(); private void Awake() { if (particleSystemToTrack == null) { particleSystemToTrack = GetComponent(); } int count = soundObjects.Count; for (int i = 0; i < count; i++) { particleTrackers.Add(new ParticleLifetimeTracker(soundObjects[i])); } if (particleSystemToTrack != null) { particleArray = new ParticleSystem.Particle[particleSystemToTrack.main.maxParticles]; } } private void LateUpdate() { if (particleSystemToTrack == null) { base.enabled = false; return; } float time = Time.time; UpdateExistingParticlePlayers(time); if (particleSystemToTrack.isEmitting && !(time - lastParticleTrackedTimeStamp < soundCooldown)) { DiscoverAndTrackNewParticles(time); } } private void UpdateExistingParticlePlayers(float currentTime) { for (int i = 0; i < particleTrackers.Count; i++) { particleTrackers[i]?.Update(currentTime, debugMessages); } } private ParticleLifetimeTracker FindAvailableParticleTracker() { int count = particleTrackers.Count; for (int i = 0; i < count; i++) { if (!particleTrackers[i].isActive) { return particleTrackers[i]; } } return null; } private void DiscoverAndTrackNewParticles(float currentTime) { ParticleLifetimeTracker particleLifetimeTracker = FindAvailableParticleTracker(); if (particleLifetimeTracker == null) { return; } int particles = particleSystemToTrack.GetParticles(particleArray); for (int i = 0; i < particles; i++) { ParticleSystem.Particle particle = particleArray[i]; if (Mathf.Approximately(particle.startLifetime, particle.remainingLifetime)) { lastParticleTrackedTimeStamp = currentTime; particleLifetimeTracker.Initialize(currentTime, particle.remainingLifetime, startTimeOffset, endTimeOffset, ref startEvent, ref endEvent, debugMessages); break; } } } } [RequireComponent(typeof(EffectComponent))] public class ParticleSystemColorFromEffectData : MonoBehaviour { public ParticleSystem[] particleSystems; public EffectComponent effectComponent; private void Start() { UnityEngine.Color color = effectComponent.effectData.color; for (int i = 0; i < particleSystems.Length; i++) { ParticleSystem.MainModule main = particleSystems[i].main; main.startColor = color; particleSystems[i].Clear(); particleSystems[i].Play(); } } } public class ParticleSystemRandomColor : MonoBehaviour { public UnityEngine.Color[] colors; public ParticleSystem[] particleSystems; private void Awake() { if (colors.Length != 0) { UnityEngine.Color color = colors[UnityEngine.Random.Range(0, colors.Length)]; for (int i = 0; i < particleSystems.Length; i++) { ParticleSystem.MainModule main = particleSystems[i].main; main.startColor = color; } } } [AssetCheck(typeof(ParticleSystemRandomColor))] private static void CheckParticleSystemRandomColor(AssetCheckArgs args) { ParticleSystemRandomColor particleSystemRandomColor = (ParticleSystemRandomColor)args.asset; for (int i = 0; i < particleSystemRandomColor.particleSystems.Length; i++) { if (!particleSystemRandomColor.particleSystems[i]) { args.LogErrorFormat(args.asset, "Null particle system in slot {0}", i); } } } } public class ParticleTriggerEvent : MonoBehaviour { public ParticleSystem particleSystemToTrack; public bool OnServerOnly; public bool killParticleOnEventTrigger; [Tooltip("Displays a message whenever a new particle is born")] public bool debugMessages; [Space(20f)] public ParticleSystemTriggerEventType triggerType; [Tooltip("The trigger will not fire if it's fired within this many seconds ago. Leave at -1 for 'fire every frame if need be.'")] [Space(20f)] public float triggerCooldown = -1f; [Space(20f)] public UnityEvent onParticleTrigger; private List particleList; private float lastTriggerTimestamp; private void Awake() { if (particleSystemToTrack == null) { particleSystemToTrack = GetComponent(); } if (particleSystemToTrack != null) { particleList = new List(particleSystemToTrack.main.maxParticles); } if (particleSystemToTrack == null || (OnServerOnly && !NetworkServer.active)) { base.enabled = false; } } private void OnParticleTrigger() { float time = Time.time; if (particleSystemToTrack.GetTriggerParticles(triggerType, particleList) > 0) { FireEvent(time); if (killParticleOnEventTrigger) { KillParticles(triggerType); } } } private void KillParticles(ParticleSystemTriggerEventType trigType) { int count = particleList.Count; for (int i = 0; i < count; i++) { ParticleSystem.Particle value = particleList[i]; value.remainingLifetime = -1f; particleList[i] = value; } _ = debugMessages; particleSystemToTrack.SetTriggerParticles(trigType, particleList); } private void FireEvent(float currentTime) { if (triggerCooldown == -1f || !(currentTime - lastTriggerTimestamp < triggerCooldown)) { _ = debugMessages; lastTriggerTimestamp = currentTime; onParticleTrigger?.Invoke(); } } } public class PhaseCounter : MonoBehaviour { private static PhaseCounter _instance; public static PhaseCounter instance => _instance; public int phase { get; private set; } private void OnEnable() { if (!_instance) { _instance = this; } } private void OnDisable() { if (_instance == this) { _instance = null; } } public void GoToNextPhase() { phase++; UnityEngine.Debug.LogFormat("Entering phase {0}", phase); } } public class PhasedInventorySetter : MonoBehaviour { [Serializable] public struct PhaseItems { public ItemCountPair[] itemCounts; } [SerializeField] private CharacterBody body; [SerializeField] private PhaseItems[] phases; private bool isPhaseDirty = true; private int phaseIndex; public bool AdvancePhase() { if (phaseIndex < phases.Length - 1) { phaseIndex++; isPhaseDirty = true; TryUpdateInventory(); return true; } return false; } private void FixedUpdate() { TryUpdateInventory(); } private void TryUpdateInventory() { if (NetworkServer.active && isPhaseDirty && phaseIndex < phases.Length && (bool)body && (bool)body.inventory) { ItemCountPair[] itemCounts = phases[phaseIndex].itemCounts; for (int i = 0; i < itemCounts.Length; i++) { ItemCountPair itemCountPair = itemCounts[i]; int itemCount = body.inventory.GetItemCount(itemCountPair.itemDef); body.inventory.GiveItem(itemCountPair.itemDef, itemCountPair.count - itemCount); } isPhaseDirty = false; } } public int GetNumPhases() { return phases.Length; } public int GetItemCountForPhase(int phaseIndex, ItemDef itemDef) { if (phases.Length > phaseIndex) { ItemCountPair[] itemCounts = phases[phaseIndex].itemCounts; for (int i = 0; i < itemCounts.Length; i++) { ItemCountPair itemCountPair = itemCounts[i]; if ((object)itemDef == itemCountPair.itemDef) { return itemCountPair.count; } } } return 0; } } public class PickRandomObjectOnAwake : MonoBehaviour { public GameObject[] ObjectsToSelect; private void Awake() { int num = UnityEngine.Random.Range(0, ObjectsToSelect.Length); for (int i = 0; i < ObjectsToSelect.Length; i++) { ObjectsToSelect[i].SetActive(i == num); } } } public class PickupDisplay : MonoBehaviour { [Tooltip("The vertical motion of the display model.")] public Wave verticalWave; public bool dontInstantiatePickupModel; [Tooltip("The speed in degrees/second at which the display model rotates about the y axis.")] public float spinSpeed = 75f; public GameObject tier1ParticleEffect; public GameObject tier2ParticleEffect; public GameObject tier3ParticleEffect; public GameObject equipmentParticleEffect; public GameObject lunarParticleEffect; public GameObject bossParticleEffect; public GameObject voidParticleEffect; [Tooltip("The particle system to tint.")] public ParticleSystem[] coloredParticleSystems; private PickupIndex pickupIndex = PickupIndex.none; private bool hidden; public Highlight highlight; private static readonly UnityEngine.Vector3 idealModelBox = UnityEngine.Vector3.one; private static readonly float idealVolume = idealModelBox.x * idealModelBox.y * idealModelBox.z; private GameObject modelObject; private GameObject modelPrefab; private float modelScale; private float localTime; private bool shouldUpdate = true; public Renderer modelRenderer { get; private set; } private UnityEngine.Vector3 localModelPivotPosition => UnityEngine.Vector3.up * verticalWave.Evaluate(localTime); public void SetPickupIndex(PickupIndex newPickupIndex, bool newHidden = false) { if (!(pickupIndex == newPickupIndex) || hidden != newHidden) { pickupIndex = newPickupIndex; hidden = newHidden; RebuildModel(); } } private void DestroyModel() { if ((bool)modelObject) { UnityEngine.Object.Destroy(modelObject); modelObject = null; modelRenderer = null; } } public void RebuildModel(GameObject modelObjectOverride = null) { PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (modelObjectOverride != null) { modelObject = modelObjectOverride; } else { GameObject gameObject = null; if (pickupDef != null) { gameObject = (hidden ? PickupCatalog.GetHiddenPickupDisplayPrefab() : pickupDef.displayPrefab); } if (modelPrefab != gameObject) { DestroyModel(); modelPrefab = gameObject; modelScale = base.transform.lossyScale.x; if (!dontInstantiatePickupModel && modelPrefab != null) { modelObject = UnityEngine.Object.Instantiate(modelPrefab); modelRenderer = modelObject.GetComponentInChildren(); if ((bool)modelRenderer) { modelObject.transform.rotation = UnityEngine.Quaternion.identity; UnityEngine.Vector3 size = modelRenderer.bounds.size; float num = size.x * size.y * size.z; if (num <= float.Epsilon) { UnityEngine.Debug.LogError("PickupDisplay bounds are zero! This is not allowed!"); num = 1f; } modelScale *= Mathf.Pow(idealVolume, 1f / 3f) / Mathf.Pow(num, 1f / 3f); if ((bool)highlight) { highlight.targetRenderer = modelRenderer; highlight.isOn = true; highlight.pickupIndex = pickupIndex; highlight.ResetHighlight(); } } modelObject.transform.parent = base.transform; modelObject.transform.localPosition = localModelPivotPosition; modelObject.transform.localRotation = UnityEngine.Quaternion.identity; modelObject.transform.localScale = new UnityEngine.Vector3(modelScale, modelScale, modelScale); } } } if ((bool)tier1ParticleEffect) { tier1ParticleEffect.SetActive(value: false); } if ((bool)tier2ParticleEffect) { tier2ParticleEffect.SetActive(value: false); } if ((bool)tier3ParticleEffect) { tier3ParticleEffect.SetActive(value: false); } if ((bool)equipmentParticleEffect) { equipmentParticleEffect.SetActive(value: false); } if ((bool)lunarParticleEffect) { lunarParticleEffect.SetActive(value: false); } if ((bool)voidParticleEffect) { voidParticleEffect.SetActive(value: false); } ItemIndex itemIndex = pickupDef?.itemIndex ?? ItemIndex.None; EquipmentIndex equipmentIndex = pickupDef?.equipmentIndex ?? EquipmentIndex.None; if (itemIndex != ItemIndex.None) { switch (ItemCatalog.GetItemDef(itemIndex).tier) { case ItemTier.Tier1: if ((bool)tier1ParticleEffect) { tier1ParticleEffect.SetActive(value: true); } break; case ItemTier.Tier2: if ((bool)tier2ParticleEffect) { tier2ParticleEffect.SetActive(value: true); } break; case ItemTier.Tier3: if ((bool)tier3ParticleEffect) { tier3ParticleEffect.SetActive(value: true); } break; case ItemTier.VoidTier1: case ItemTier.VoidTier2: case ItemTier.VoidTier3: case ItemTier.VoidBoss: if ((bool)voidParticleEffect) { voidParticleEffect.SetActive(value: true); } break; } } else if (equipmentIndex != EquipmentIndex.None && (bool)equipmentParticleEffect) { equipmentParticleEffect.SetActive(value: true); } if ((bool)bossParticleEffect) { bossParticleEffect.SetActive(pickupDef?.isBoss ?? false); } if ((bool)lunarParticleEffect) { lunarParticleEffect.SetActive(pickupDef?.isLunar ?? false); } if ((bool)highlight) { highlight.isOn = true; highlight.pickupIndex = pickupIndex; } ParticleSystem[] array = coloredParticleSystems; foreach (ParticleSystem obj in array) { obj.gameObject.SetActive(modelPrefab != null); ParticleSystem.MainModule main = obj.main; main.startColor = pickupDef?.baseColor ?? PickupCatalog.invalidPickupColor; } } private void Start() { localTime = 0f; } private void OnBecameVisible() { shouldUpdate = true; } private void OnBecameInvisible() { shouldUpdate = false; } private void Update() { if (shouldUpdate) { localTime += Time.deltaTime; if ((bool)modelObject) { Transform obj = modelObject.transform; UnityEngine.Vector3 localEulerAngles = obj.localEulerAngles; localEulerAngles.y = spinSpeed * localTime; obj.localEulerAngles = localEulerAngles; obj.localPosition = localModelPivotPosition; } } } private void OnDrawGizmos() { Gizmos.color = UnityEngine.Color.yellow; UnityEngine.Matrix4x4 matrix = Gizmos.matrix; Gizmos.matrix = UnityEngine.Matrix4x4.TRS(base.transform.position, base.transform.rotation, base.transform.lossyScale); Gizmos.DrawWireCube(UnityEngine.Vector3.zero, idealModelBox); Gizmos.matrix = matrix; } } public class PickupDropletController : NetworkBehaviour { [NonSerialized] [SyncVar] public PickupIndex pickupIndex = PickupIndex.none; private bool alive = true; private GenericPickupController.CreatePickupInfo createPickupInfo; private static GameObject commandCubePrefab; private static bool isCommandChest; private static GameObject pickupDropletPrefab; public PickupIndex NetworkpickupIndex { get { return pickupIndex; } [param: In] set { SetSyncVar(value, ref pickupIndex, 1u); } } public static void CreatePickupDroplet(PickupIndex pickupIndex, UnityEngine.Vector3 position, UnityEngine.Vector3 velocity) { GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo); pickupInfo.rotation = UnityEngine.Quaternion.identity; pickupInfo.pickupIndex = pickupIndex; pickupInfo.position = position; CreatePickupDroplet(pickupInfo, position, velocity); } public static void CreatePickupDroplet(GenericPickupController.CreatePickupInfo pickupInfo, UnityEngine.Vector3 position, UnityEngine.Vector3 velocity) { if (CommandArtifactManager.IsCommandArtifactEnabled) { pickupInfo.artifactFlag |= GenericPickupController.PickupArtifactFlag.COMMAND; } GameObject obj = UnityEngine.Object.Instantiate(pickupDropletPrefab, position, UnityEngine.Quaternion.identity); PickupDropletController component = obj.GetComponent(); if ((bool)component) { component.createPickupInfo = pickupInfo; component.NetworkpickupIndex = pickupInfo.pickupIndex; } Rigidbody component2 = obj.GetComponent(); component2.velocity = velocity; component2.AddTorque(UnityEngine.Random.Range(150f, 120f) * UnityEngine.Random.onUnitSphere); NetworkServer.Spawn(obj); } [InitDuringStartup] private static void Init() { LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/PickupDroplet", delegate(GameObject operationResult) { pickupDropletPrefab = operationResult; }); } public static void IfCommandChestSpawned(bool value, PickupIndex pickupIndex, UnityEngine.Vector3 position, UnityEngine.Vector3 velocity) { isCommandChest = value; commandCubePrefab = LegacyResourcesAPI.Load("Prefabs/NetworkedObjects/CommandCube"); CreatePickupDroplet(pickupIndex, position, velocity); } public void OnCollisionEnter(Collision collision) { if (NetworkServer.active && alive) { alive = false; createPickupInfo.position = base.transform.position; CreatePickup(); UnityEngine.Object.Destroy(base.gameObject); } } private void Start() { GameObject gameObject = PickupCatalog.GetPickupDef(pickupIndex)?.dropletDisplayPrefab; if ((bool)gameObject) { UnityEngine.Object.Instantiate(gameObject, base.transform); } } private void CreatePickup() { if (createPickupInfo.artifactFlag.HasFlag(GenericPickupController.PickupArtifactFlag.COMMAND) && !createPickupInfo.artifactFlag.HasFlag(GenericPickupController.PickupArtifactFlag.DELUSION)) { PickupDef pickupDef = PickupCatalog.GetPickupDef(createPickupInfo.pickupIndex); if (pickupDef != null && (pickupDef.itemIndex != ItemIndex.None || pickupDef.equipmentIndex != EquipmentIndex.None || pickupDef.itemTier != ItemTier.NoTier)) { CreateCommandCube(); return; } } GenericPickupController.CreatePickup(in createPickupInfo); } private void CreateCommandCube() { GameObject obj = UnityEngine.Object.Instantiate(CommandArtifactManager.commandCubePrefab, createPickupInfo.position, createPickupInfo.rotation); obj.GetComponent().NetworkpickupIndex = createPickupInfo.pickupIndex; PickupPickerController component = obj.GetComponent(); component.SetOptionsFromPickupForCommandArtifact(createPickupInfo.pickupIndex); component.chestGeneratedFrom = createPickupInfo.chest; NetworkServer.Spawn(obj); } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader); } } public override void PreStartClient() { } } public class PickupIndexNetworker : NetworkBehaviour { [SyncVar(hook = "SyncPickupIndex")] public PickupIndex pickupIndex; public PickupDisplay pickupDisplay; public PickupIndex NetworkpickupIndex { get { return pickupIndex; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; SyncPickupIndex(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref pickupIndex, 1u); } } private void SyncPickupIndex(PickupIndex newPickupIndex) { NetworkpickupIndex = newPickupIndex; UpdatePickupDisplay(); } private void UpdatePickupDisplay() { if ((bool)pickupDisplay) { pickupDisplay.SetPickupIndex(pickupIndex); } } private void UNetVersion() { } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { SyncPickupIndex(GeneratedNetworkCode._ReadPickupIndex_None(reader)); } } public override void PreStartClient() { } } [RequireComponent(typeof(NetworkUIPromptController))] public class PickupPickerController : NetworkBehaviour, IInteractable, IInspectable { public struct Option { public PickupIndex pickupIndex; public bool available; } [Serializable] public class PickupIndexUnityEvent : UnityEvent { } public GameObject panelPrefab; public PickupIndexUnityEvent onPickupSelected; public GenericInteraction.InteractorUnityEvent onServerInteractionBegin; public float cutoffDistance; private bool available = true; public string contextString = ""; public bool shouldProximityHighlight = true; public bool synchronizeItemSelectionAcrossNetwork; public bool isDelusionChoice; public bool isRebirthChoice; private Inventory delusionInventory; private bool delusionOptionsSet; private int delusionChoicePickupIndex; private NetworkUIPromptController networkUIPromptController; private const byte msgSubmit = 0; private const byte msgCancel = 1; private GameObject panelInstance; private PickupPickerPanel panelInstanceController; public ChestBehavior chestGeneratedFrom; private Option[] options = Array.Empty