Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of RodamortaSkillCycler v1.0.0
RodamortaSkillCycler.dll
Decompiled 9 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using HG; using HarmonyLib; using Microsoft.CodeAnalysis; using Rewired; using RoR2; using RoR2.ExpansionManagement; using RoR2.Skills; using RoR2.UI; using TMPro; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("RodamortaSkillCycler")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RodamortaSkillCycler")] [assembly: AssemblyTitle("RodamortaSkillCycler")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace RainCycler { internal static class FirstRun { private const string Section = "Rodamorta - Modules"; private static bool shown; public static void Check() { if (!shown && !RainCyclerPlugin.FirstRunDone.Value && Object.op_Implicit((Object)(object)RainCyclerPlugin.Instance)) { shown = true; ((MonoBehaviour)RainCyclerPlugin.Instance).StartCoroutine(Ask()); } } private static IEnumerator Ask() { yield return (object)new WaitForSecondsRealtime(2.5f); Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "title") { shown = false; yield break; } try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("This mod is made of two parts:"); stringBuilder.AppendLine(); stringBuilder.AppendLine("<b>SkillCycler</b>: swap skills, passives and skins (already on)."); stringBuilder.AppendLine(); stringBuilder.AppendLine("<b>Rodamorta</b>: miscellaneous features that change how the game plays. They are off until you enable them:"); stringBuilder.AppendLine(); ConfigFile config = ((BaseUnityPlugin)RainCyclerPlugin.Instance).Config; foreach (ConfigDefinition key in config.Keys) { if (!(key.Section != "Rodamorta - Modules")) { stringBuilder.AppendLine("<b>" + key.Key + "</b>"); stringBuilder.AppendLine(config[key].Description.Description); stringBuilder.AppendLine(); } } stringBuilder.Append("You can change any of them later in Risk of Options or in the config file. This question is only asked once."); try { Util.PlaySound("Play_UI_menuClick", ((Component)RoR2Application.instance).gameObject); } catch (Exception) { } Show("Rodamorta SkillCycler", stringBuilder.ToString(), new string[3] { "Enable All", "Keep Them Off", "Enable only Rodamorta" }, new Action[3] { delegate { Answer(rodamorta: true, skillCycler: true); }, delegate { Answer(rodamorta: false, skillCycler: true); }, delegate { Answer(rodamorta: true, skillCycler: false); } }); } catch (Exception ex2) { shown = false; RainCyclerPlugin.Log.LogWarning((object)("First start window failed: " + ex2.Message)); } } private static void Show(string header, string body, string[] buttons, Action[] actions) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown SimpleDialogBox val = SimpleDialogBox.Create((MPEventSystem)null); Dim(val); val.headerToken = new TokenParamsPair { token = header }; val.descriptionToken = new TokenParamsPair { token = body }; for (int i = 0; i < buttons.Length; i++) { Action action = actions[i]; val.AddActionButton((UnityAction)delegate { action(); }, buttons[i], true, Array.Empty<object>()); } } private static void Dim(SimpleDialogBox box) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject("RainCyclerDim", new Type[2] { typeof(RectTransform), typeof(Image) }) { layer = ((Component)box).gameObject.layer }; RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent(((Component)box).transform, false); Vector2 anchorMin = (val2.anchorMax = new Vector2(0.5f, 0.5f)); val2.anchorMin = anchorMin; val2.sizeDelta = new Vector2(8000f, 8000f); ((Transform)val2).SetAsFirstSibling(); Image component = val.GetComponent<Image>(); ((Graphic)component).color = new Color(0f, 0f, 0f, 0.6f); ((Graphic)component).raycastTarget = true; } catch (Exception) { } } private static void Answer(bool rodamorta, bool skillCycler) { bool flag = rodamorta; ConfigFile config = ((BaseUnityPlugin)RainCyclerPlugin.Instance).Config; if (flag) { foreach (ConfigDefinition key in config.Keys) { if (!(key.Section != "Rodamorta - Modules") && config[key] is ConfigEntry<bool> val) { val.Value = true; } } } if (!skillCycler) { RainCyclerPlugin.ModSkillCycler.Value = false; } RainCyclerPlugin.FirstRunDone.Value = true; config.Save(); if (flag) { try { Show("Rodamorta Features", "The features are enabled. Restarting the game is recommended so everything starts cleanly.", new string[1] { "OK" }, new Action[1] { delegate { } }); } catch (Exception) { } } } } internal static class Floppy { private sealed class Bone { public DynamicBone Db; public float Born; public float In; public float OutAt = -1f; public float OutFrom = 1f; public float Last = -1f; public float Max = 1f; public float Fade = 1f; } private sealed class Hold { public SkillSlot Slot; public GenericSkill Skill; public float Until; public float Last; } private static readonly string[] buffs = new string[12] { "TearGasBerserk", "Fracture", "Blight", "TeleportOnLowHealthActive", "KnockbackFinGuaranteedCritDebuff", "KnockUpHitEnemiesJuggleCount", "KnockUpHitEnemies", "Entangle", "LunarSecondaryRoot", "NanoBug", "NullifyStack", "TransferDebuffOnHit" }; private static readonly Dictionary<CharacterBody, float> voidUntil = new Dictionary<CharacterBody, float>(); private static readonly Dictionary<CharacterBody, bool> hadVoid = new Dictionary<CharacterBody, bool>(); private static readonly Dictionary<CharacterBody, float> firstSeen = new Dictionary<CharacterBody, float>(); private static float next; private static readonly Dictionary<Object, Bone> bones = new Dictionary<Object, Bone>(); private static MethodInfo setWeight; private static bool setWeightSearched; private static float nextLobby; private static Type slotType; private static bool slotSearched; private static readonly Dictionary<CharacterBody, Hold> holds = new Dictionary<CharacterBody, Hold>(); private static readonly Dictionary<CharacterBody, float> lastHealth = new Dictionary<CharacterBody, float>(); private static readonly Dictionary<CharacterBody, float> hitUntil = new Dictionary<CharacterBody, float>(); public static void Tick() { if (!RainCyclerPlugin.FloppyEnabled.Value && !RainCyclerPlugin.ModHeresyAnims.Value) { if (bones.Count > 0) { ReleaseAll(); } } else { if (Time.unscaledTime < next) { return; } next = Time.unscaledTime + 0.1f; try { Forget(); foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { if (!Object.op_Implicit((Object)(object)readOnlyInstances) || !Object.op_Implicit((Object)(object)readOnlyInstances.modelLocator)) { continue; } int num; int num2; if (Object.op_Implicit((Object)(object)readOnlyInstances.healthComponent) && readOnlyInstances.healthComponent.alive) { num = ((!Ragdoll.IsFallen(readOnlyInstances)) ? 1 : 0); if (num != 0 && RainCyclerPlugin.FloppyEnabled.Value) { num2 = (Wanted(readOnlyInstances) ? 1 : 0); goto IL_00c0; } } else { num = 0; } num2 = 0; goto IL_00c0; IL_00c0: bool flag = (byte)num2 != 0; bool quick = false; float num3 = ((num != 0) ? HeresyStrength(readOnlyInstances, out quick) : 0f); bool flag2 = num3 > 0f && !flag && quick; bool flag3 = flag || num3 > 0f; bool flag4 = bones.ContainsKey((Object)(object)readOnlyInstances); if (flag3 && flag4) { Bone bone = bones[(Object)(object)readOnlyInstances]; bone.Max = (flag ? 1f : num3); bone.Fade = (flag2 ? 0.15f : 1f); StopFading((Object)(object)readOnlyInstances); } else if (flag3) { AddBones((Object)(object)readOnlyInstances, Object.op_Implicit((Object)(object)readOnlyInstances.modelLocator.modelTransform) ? ((Component)readOnlyInstances.modelLocator.modelTransform).gameObject : null, flag2 ? 0.1f : 0.5f); if (bones.TryGetValue((Object)(object)readOnlyInstances, out var value)) { value.Max = (flag ? 1f : num3); value.Fade = (flag2 ? 0.15f : 1f); } } else if (flag4) { RemoveBones((Object)(object)readOnlyInstances); } } } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Floppy failed: " + ex.Message)); } try { LobbyTick(); } catch (Exception) { } } } private static void AddBones(Object key, GameObject model, float fadeIn) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown Transform val = (Object.op_Implicit((Object)(object)model) ? TryFindRoot(model) : null); if (!Object.op_Implicit((Object)(object)val)) { bones[key] = new Bone(); return; } DynamicBone val2 = ((Component)val).gameObject.AddComponent<DynamicBone>(); val2.m_Root = val; val2.m_UpdateRate = 60f; val2.m_UpdateMode = (UpdateMode)0; val2.m_Damping = 0.344f; val2.m_DampingDistrib = new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 1f), new Keyframe(1f, 1f) }); val2.m_Elasticity = 0.1f; val2.m_ElasticityDistrib = new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 1f), new Keyframe(1f, 0f) }); Bone bone = new Bone { Db = val2, Born = Time.time, In = fadeIn }; bones[key] = bone; Apply(bone, (fadeIn > 0f) ? 0f : 1f); } private static float WeightOf(Bone b) { if (b.OutAt >= 0f) { return Mathf.Clamp01(b.OutFrom * (1f - (Time.time - b.OutAt) / b.Fade)) * b.Max; } return ((b.In > 0f) ? Mathf.Clamp01((Time.time - b.Born) / b.In) : 1f) * b.Max; } private static void Apply(Bone b, float w) { if (!Object.op_Implicit((Object)(object)b.Db) || Mathf.Abs(w - b.Last) < 0.004f) { return; } b.Last = w; try { if (!setWeightSearched) { setWeightSearched = true; setWeight = typeof(DynamicBone).GetMethod("SetWeight", new Type[1] { typeof(float) }); } if (setWeight != null) { setWeight.Invoke(b.Db, new object[1] { w }); } else { b.Db.m_Elasticity = Mathf.Lerp(1f, 0.1f, w); } } catch (Exception) { b.Db.m_Elasticity = Mathf.Lerp(1f, 0.1f, w); } } private static void RemoveBones(Object key) { if (bones.TryGetValue(key, out var value)) { if (!Object.op_Implicit((Object)(object)value.Db)) { bones.Remove(key); } else if (!(value.OutAt >= 0f)) { value.OutFrom = ((value.Max > 0f) ? (WeightOf(value) / value.Max) : 0f); value.OutAt = Time.time; } } } private static void StopFading(Object key) { if (bones.TryGetValue(key, out var value) && !(value.OutAt < 0f)) { float num = ((value.Max > 0f) ? (WeightOf(value) / value.Max) : 0f); value.OutAt = -1f; value.In = ((value.Fade < 0.5f) ? 0.1f : 0.5f); value.Born = Time.time - num * value.In; } } public static void Frame() { if (bones.Count == 0) { return; } List<Object> list = null; foreach (KeyValuePair<Object, Bone> bone in bones) { Bone value = bone.Value; if (!Object.op_Implicit(bone.Key) || !Object.op_Implicit((Object)(object)value.Db)) { (list ?? (list = new List<Object>())).Add(bone.Key); continue; } float num = WeightOf(value); if (value.OutAt >= 0f && num <= 0.001f) { Object.Destroy((Object)(object)value.Db); (list ?? (list = new List<Object>())).Add(bone.Key); } else { Apply(value, num); } } if (list == null) { return; } foreach (Object item in list) { bones.Remove(item); } } private static void LobbyTick() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Invalid comparison between Unknown and I4 //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown Scene activeScene = SceneManager.GetActiveScene(); bool flag = ((Scene)(ref activeScene)).name == "lobby"; HashSet<Transform> hashSet = new HashSet<Transform>(); if (flag && Time.unscaledTime >= nextLobby) { nextLobby = Time.unscaledTime + 0.5f; bool flag2 = false; try { flag2 = Object.op_Implicit((Object)(object)PreGameController.instance) && (int)PreGameController.instance.readOnlyRuleBook.FindDifficulty() == 0; } catch (Exception) { } if (flag2) { Object[] array = FindSlots(); for (int i = 0; i < array.Length; i++) { Transform val = MannequinOf(array[i]); if (Object.op_Implicit((Object)(object)val)) { hashSet.Add(val); } } } } else if (flag) { return; } foreach (Transform item in hashSet) { if (!bones.ContainsKey((Object)(object)item)) { AddBones((Object)(object)item, ((Component)item).gameObject, 2f); } else { StopFading((Object)(object)item); } } foreach (Object item2 in new List<Object>(bones.Keys)) { if (item2 is Transform && !hashSet.Contains((Transform)item2)) { RemoveBones(item2); } } } private static Object[] FindSlots() { if (!slotSearched) { slotSearched = true; Type[] types = typeof(CharacterBody).Assembly.GetTypes(); foreach (Type type in types) { if (type.Name == "SurvivorMannequinSlotController") { slotType = type; break; } } if (slotType == null) { RainCyclerPlugin.Log.LogInfo((object)"Lobby display slots not found; lobby floppy is off."); } } if (!(slotType != null)) { return (Object[])(object)new Object[0]; } return Object.FindObjectsOfType(slotType); } private static Transform MannequinOf(Object slot) { Type type = ((object)slot).GetType(); FieldInfo field = type.GetField("mannequinInstanceTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object? value = field.GetValue(slot); return (Transform)((value is Transform) ? value : null); } PropertyInfo property = type.GetProperty("mannequinInstanceTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(property != null)) { return null; } object? value2 = property.GetValue(slot, null); return (Transform)((value2 is Transform) ? value2 : null); } private static Transform TryFindRoot(GameObject prefab) { ChildLocator componentInChildren = prefab.GetComponentInChildren<ChildLocator>(); if (Object.op_Implicit((Object)(object)componentInChildren)) { Transform val = componentInChildren.FindChild("Base"); if (Object.op_Implicit((Object)(object)val)) { return val; } val = componentInChildren.FindChild("Root"); if (Object.op_Implicit((Object)(object)val)) { return val; } val = componentInChildren.FindChild("ROOT"); if (Object.op_Implicit((Object)(object)val)) { return val; } } SkinnedMeshRenderer componentInChildren2 = prefab.GetComponentInChildren<SkinnedMeshRenderer>(); if (!Object.op_Implicit((Object)(object)componentInChildren2)) { return null; } return componentInChildren2.rootBone; } private static void ReleaseAll() { foreach (Object item in new List<Object>(bones.Keys)) { RemoveBones(item); } } private static void Forget() { List<CharacterBody> list = null; foreach (CharacterBody key in lastHealth.Keys) { if (!Object.op_Implicit((Object)(object)key)) { (list ?? (list = new List<CharacterBody>())).Add(key); } } foreach (CharacterBody key2 in hitUntil.Keys) { if (!Object.op_Implicit((Object)(object)key2)) { (list ?? (list = new List<CharacterBody>())).Add(key2); } } if (list != null) { foreach (CharacterBody item in list) { lastHealth.Remove(item); hitUntil.Remove(item); } } List<CharacterBody> list2 = null; foreach (CharacterBody key3 in voidUntil.Keys) { if (!Object.op_Implicit((Object)(object)key3)) { (list2 ?? (list2 = new List<CharacterBody>())).Add(key3); } } foreach (CharacterBody key4 in hadVoid.Keys) { if (!Object.op_Implicit((Object)(object)key4)) { (list2 ?? (list2 = new List<CharacterBody>())).Add(key4); } } foreach (CharacterBody key5 in firstSeen.Keys) { if (!Object.op_Implicit((Object)(object)key5)) { (list2 ?? (list2 = new List<CharacterBody>())).Add(key5); } } if (list2 == null) { return; } foreach (CharacterBody item2 in list2) { voidUntil.Remove(item2); hadVoid.Remove(item2); firstSeen.Remove(item2); } } public static void HeresyUsed(CharacterBody body, SkillSlot slot, GenericSkill skill) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 if (Object.op_Implicit((Object)(object)body) && RainCyclerPlugin.ModHeresyAnims.Value) { float time = Time.time; Hold hold = new Hold { Slot = slot, Skill = skill, Last = time }; hold.Until = (((int)slot == 3) ? (time + 1.5f) : (((int)slot == 2) ? (time + 0.35f) : (time + 0.2f))); holds[body] = hold; } } private static float HeresyStrength(CharacterBody body, out bool quick) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Invalid comparison between Unknown and I4 //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Invalid comparison between Unknown and I4 //IL_00e2: Unknown result type (might be due to invalid IL or missing references) quick = true; if (!holds.TryGetValue(body, out var value)) { return 0f; } float time = Time.time; bool flag = false; SkillSlot slot = value.Slot; if ((int)slot != 0) { if ((int)slot == 1) { flag = Object.op_Implicit((Object)(object)body.inputBank) && body.inputBank.skill2.down && time < value.Last + 8f; if (!flag) { flag = time < value.Until; } } else { flag = time < value.Until; } } else { flag = Object.op_Implicit((Object)(object)value.Skill) && value.Skill.stock > 0 && time < value.Last + 0.5f; } if (!flag) { holds.Remove(body); return 0f; } if ((int)value.Slot == 3) { quick = false; return 0.3f; } if ((int)value.Slot == 1) { return 0.2f; } if ((int)value.Slot == 0 && Object.op_Implicit((Object)(object)value.Skill)) { int num = Mathf.Max(2, value.Skill.maxStock); float num2 = Mathf.Clamp01((float)(num - value.Skill.stock) / (float)(num - 1)); return 0.24f * Mathf.Max(1f, (float)num / 12f) * num2; } return 0.12f; } private static bool Wanted(CharacterBody body) { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); bool flag = firstLocalUser != null && (Object)(object)firstLocalUser.cachedBody == (Object)(object)body; string[] array = buffs; foreach (string text in array) { if ((!(text == "NanoBug" && flag) || !(Time.time < Swapper.FlashUntil)) && Swapper.HasBuff(body, Swapper.BuffIndexOf(text))) { return true; } } if (Object.op_Implicit((Object)(object)body.inventory)) { if (Swapper.CountItem(body, "SlipperyGround") > 0) { return true; } if (HasGoobo(body) && Time.time < HitUntil(body)) { return true; } } if (IsGooboClone(body) && Object.op_Implicit((Object)(object)body.healthComponent) && body.healthComponent.combinedHealthFraction < 0.5f) { return true; } object index = Swapper.BuffIndexOf("EliteVoid"); bool flag2 = Swapper.HasBuff(body, index); hadVoid.TryGetValue(body, out var value); hadVoid[body] = flag2; if (!firstSeen.ContainsKey(body)) { firstSeen[body] = Time.time; } if (flag2 && !value && Time.time - firstSeen[body] > 1.5f) { voidUntil[body] = Time.time + 1.5f; } if (voidUntil.TryGetValue(body, out var value2) && Time.time < value2) { return true; } return false; } private static float HitUntil(CharacterBody body) { HealthComponent healthComponent = body.healthComponent; if (!Object.op_Implicit((Object)(object)healthComponent)) { return 0f; } float num = healthComponent.health + healthComponent.shield; bool isPlayerControlled = body.isPlayerControlled; if (lastHealth.TryGetValue(body, out var value) && num < value - 0.01f) { hitUntil[body] = (isPlayerControlled ? float.MaxValue : (Time.time + 0.5f)); } if (isPlayerControlled && hitUntil.TryGetValue(body, out var value2) && value2 > Time.time && Object.op_Implicit((Object)(object)body.inputBank) && body.inputBank.jump.down) { hitUntil[body] = 0f; } lastHealth[body] = num; if (!hitUntil.TryGetValue(body, out var value3)) { return 0f; } return value3; } private static bool HasGoobo(CharacterBody body) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) EquipmentSlot equipmentSlot = body.equipmentSlot; if (!Object.op_Implicit((Object)(object)equipmentSlot)) { return false; } EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentSlot.equipmentIndex); if (Object.op_Implicit((Object)(object)equipmentDef)) { return ((Object)equipmentDef).name == "GummyClone"; } return false; } private static bool IsGooboClone(CharacterBody body) { CharacterMaster master = body.master; if (Object.op_Implicit((Object)(object)master)) { return ((Object)master).name.ToLowerInvariant().Contains("gummyclone"); } return false; } } internal static class Fx { private static HashSet<string> events; private static string infoText; private static readonly HashSet<string> banksTried = new HashSet<string>(); private static readonly Dictionary<string, string> working = new Dictionary<string, string>(); private static bool critLogged; private static Material particleMaterial; private static bool particlesBroken; private static void LoadEvents() { if (events != null) { return; } events = new HashSet<string>(); try { string path = Path.Combine(Application.streamingAssetsPath, Path.Combine("Audio", Path.Combine("GeneratedSoundBanks", "Windows"))); string[] array = new string[2] { "SoundbanksInfo.xml", "SoundbanksInfo.json" }; foreach (string path2 in array) { string path3 = Path.Combine(path, path2); if (!File.Exists(path3)) { continue; } infoText = File.ReadAllText(path3); foreach (Match item in Regex.Matches(infoText, "Play_[A-Za-z0-9_]+")) { events.Add(item.Value); } break; } if (events.Count <= 0) { return; } List<string> list = new List<string>(); foreach (string @event in events) { if (Has(@event, "laserturbine") || Has(@event, "engi", "m1") || Has(@event, "infestor") || Has(@event, "ui", "menu")) { list.Add(@event); } } list.Sort(); } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Reading sound events failed: " + ex.Message)); } } private static bool Has(string name, params string[] tokens) { string text = name.ToLowerInvariant(); foreach (string value in tokens) { if (!text.Contains(value)) { return false; } } return true; } private static void Play(string key, GameObject go, string[] tokens, string[] prefer, string[] avoid, string[] guesses) { if (!Object.op_Implicit((Object)(object)go)) { return; } try { if (working.TryGetValue(key, out var value)) { if (value.Length > 0) { Util.PlaySound(value, go); } return; } LoadEvents(); List<string> list = new List<string>(); List<string> list2 = new List<string>(); foreach (string @event in events) { if (!Has(@event, tokens)) { continue; } bool flag = false; string[] array = avoid; foreach (string text in array) { if (Has(@event, text)) { flag = true; } } if (flag) { continue; } bool flag2 = prefer.Length == 0; array = prefer; foreach (string text2 in array) { if (Has(@event, text2)) { flag2 = true; } } (flag2 ? list2 : list).Add(@event); } list2.Sort(); list.Sort(); List<string> list3 = new List<string>(list2); list3.AddRange(list); list3.AddRange(guesses); foreach (string item in list3) { if (Util.PlaySound(item, go) != 0) { working[key] = item; return; } } working[key] = ""; } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Sound '" + key + "' failed: " + ex.Message)); } } public static void Disc(GameObject go) { Play("disc", go, new string[1] { "laserturbine" }, new string[4] { "throw", "return", "launch", "fire" }, new string[2] { "loop", "stop" }, new string[8] { "Play_item_use_laserTurbine_throw", "Play_item_use_laserturbine_throw", "Play_item_use_laserTurbine_return", "Play_item_use_laserturbine_return", "Play_item_use_laserTurbine_launch", "Play_item_use_laserturbine_launch", "Play_item_use_laserTurbine", "Play_item_use_laserturbine" }); } public static void Engi(GameObject go) { if (RainCyclerPlugin.ModSwapSounds.Value) { string text = RainCyclerPlugin.SwapSound.Value.Trim(); Util.PlaySound((text.Length > 0) ? text : "Play_UI_menuClick", go); } } public static void Crit(GameObject go) { if (RainCyclerPlugin.ModSwapSounds.Value) { Play("crit", go, new string[1] { "crit" }, new string[5] { "hit", "impact", "enemy", "damage", "player" }, new string[11] { "loop", "stop", "glasses", "lens", "attackspeed", "chance", "heal", "explo", "void", "chain", "buff" }, new string[5] { "Play_player_crit", "Play_hitenemy_crit", "Play_UI_crit", "Play_item_proc_crit", "Play_UI_menuClick" }); if (!critLogged && working.TryGetValue("crit", out var value)) { critLogged = true; RainCyclerPlugin.Log.LogInfo((object)("Passive change sound: " + ((value.Length > 0) ? value : "none found"))); } } } public static void Hover(GameObject go) { if (RainCyclerPlugin.ModSwapSounds.Value && Object.op_Implicit((Object)(object)go)) { Play("hover", go, new string[3] { "ui", "menu", "hover" }, new string[0], new string[1] { "stop" }, new string[2] { "Play_UI_menuHover", "Play_UI_menuClick" }); } } public static void Laugh(GameObject go) { Play("laugh", go, new string[1] { "laugh" }, new string[5] { "haunt", "ghost", "spectral", "circlet", "equip" }, new string[2] { "loop", "stop" }, new string[3] { "Play_item_use_haunted_laugh", "Play_item_proc_haunted_laugh", "Play_ghost_laugh" }); } public static void Infestor(GameObject go) { Play("infestor", go, new string[2] { "infestor", "spawn" }, new string[0], new string[1] { "stop" }, new string[5] { "Play_voidinfestor_spawn", "Play_voidInfestor_spawn", "Play_void_infestor_spawn", "Play_infestor_spawn", "Play_UI_menuCancel" }); } public static void MenuOpen(GameObject go) { Play("menuopen", go, new string[3] { "ui", "menu", "hover" }, new string[0], new string[1] { "stop" }, new string[2] { "Play_UI_menuHover", "Play_UI_menuClick" }); } public static void MenuClose(GameObject go) { Play("menuclose", go, new string[3] { "ui", "menu", "cancel" }, new string[0], new string[1] { "stop" }, new string[3] { "Play_UI_menuCancel", "Play_UI_menuBack", "Play_UI_menuClick" }); } public static void Burst(CharacterBody body) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Expected O, but got Unknown try { if (!Object.op_Implicit((Object)(object)body) || particlesBroken) { return; } GameObject val = new GameObject("RainCyclerBurst"); Object.Destroy((Object)(object)val, 2f); val.transform.position = body.corePosition; ParticleSystem val2 = val.AddComponent<ParticleSystem>(); val2.Stop(true, (ParticleSystemStopBehavior)0); MainModule main = val2.main; ((MainModule)(ref main)).duration = 0.5f; ((MainModule)(ref main)).loop = false; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.8f); ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(2.2f); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.16f); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.8f, 0.7f, 1f, 1f)); ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(-0.15f); EmissionModule emission = val2.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); ((EmissionModule)(ref emission)).SetBursts((Burst[])(object)new Burst[1] { new Burst(0f, (short)26) }); ShapeModule shape = val2.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape)).radius = Mathf.Max(0.4f, body.radius * 0.8f); Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[2] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(0f, 1f) }); ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val3); ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>(); if (!Object.op_Implicit((Object)(object)particleMaterial)) { Shader val4 = Shader.Find("Sprites/Default"); if (Object.op_Implicit((Object)(object)val4)) { particleMaterial = new Material(val4) { mainTexture = (Texture)(object)RoundSprites.Disc.texture }; } } if (Object.op_Implicit((Object)(object)particleMaterial)) { ((Renderer)component).material = particleMaterial; } val2.Play(); } catch (Exception) { particlesBroken = true; } } public static void JumpAnimation(CharacterBody body) { try { Transform val = ((Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.modelLocator)) ? body.modelLocator.modelTransform : null); Animator val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponentInChildren<Animator>() : null); if (Object.op_Implicit((Object)(object)val2)) { ((MonoBehaviour)RainCyclerPlugin.Instance).StartCoroutine(JumpRoutine(val2)); } } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Jump animation failed: " + ex.Message)); } } private static IEnumerator JumpRoutine(Animator animator) { bool value = RainCyclerPlugin.ReverseJump.Value; int layer = animator.GetLayerIndex("Body"); if (layer < 0) { layer = 0; } float oldSpeed = animator.speed; try { animator.speed = (value ? (-1f) : 1f); animator.Play("Jump", layer, value ? 0.9f : 0f); } catch (Exception) { } yield return (object)new WaitForSeconds(0.35f); if (Object.op_Implicit((Object)(object)animator)) { animator.speed = oldSpeed; animator.CrossFadeInFixedTime("Idle", 0.1f, layer); } } } internal static class HeresyAnim { private sealed class Found { public string Layer; public string State; } private static readonly Dictionary<string, Found> learnt = new Dictionary<string, Found>(); private static readonly Dictionary<string, Found> cache = new Dictionary<string, Found>(); private static readonly Dictionary<Type, List<string>> stringCache = new Dictionary<Type, List<string>>(); private static readonly HashSet<long> running = new HashSet<long>(); private static int logs; private static readonly Dictionary<CharacterBody, KeyValuePair<SkillDef, float>> lastUsed = new Dictionary<CharacterBody, KeyValuePair<SkillDef, float>>(); private static int noteLogs; public static void Install() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown try { Harmony val = new Harmony("local.rodamortaraincycler.anim"); MethodInfo methodInfo = AccessTools.Method(typeof(GenericSkill), "ExecuteIfReady", (Type[])null, (Type[])null); if (methodInfo != null) { val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(HeresyAnim).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } HarmonyMethod val2 = new HarmonyMethod(typeof(HeresyAnim).GetMethod("Heard", BindingFlags.Static | BindingFlags.Public)); MethodInfo[] methods = typeof(EntityState).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2.Name != "PlayAnimation") || !(methodInfo2.Name != "PlayCrossfade")) { ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length >= 2 && !(parameters[0].ParameterType != typeof(string)) && !(parameters[1].ParameterType != typeof(string))) { val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Heresy animation patch failed: " + ex.Message)); } } private static string KeyOf(CharacterBody body, SkillDef def) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected I4, but got Unknown return (int)body.bodyIndex + "/" + def.skillNameToken; } private static bool Usable(string name) { if (!string.IsNullOrEmpty(name)) { return name.IndexOf("empty", StringComparison.OrdinalIgnoreCase) < 0; } return false; } public static void Heard(EntityState __instance, object[] __args) { try { if (__args == null || __args.Length < 2) { return; } string text = __args[0] as string; string text2 = __args[1] as string; if (!Usable(text) || !Usable(text2)) { return; } EntityStateMachine outer = __instance.outer; if (!Object.op_Implicit((Object)(object)outer)) { return; } CharacterBody component = ((Component)outer).GetComponent<CharacterBody>(); LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); if (!Object.op_Implicit((Object)(object)component) || firstLocalUser == null || (Object)(object)firstLocalUser.cachedBody != (Object)(object)component) { return; } Type type = ((object)__instance).GetType(); GenericSkill[] components = ((Component)component).GetComponents<GenericSkill>(); for (int i = 0; i < components.Length; i++) { SkillDef skillDef = components[i].skillDef; if (Object.op_Implicit((Object)(object)skillDef) && !(((SerializableEntityStateType)(ref skillDef.activationState)).stateType != type)) { string key = KeyOf(component, skillDef); if (!learnt.ContainsKey(key)) { learnt[key] = new Found { Layer = text, State = text2 }; Note("learnt (state) ", component, skillDef, text, text2); } return; } } if ((text.Contains("Gesture") || text.Contains("FullBody") || text.Contains("Override")) && lastUsed.TryGetValue(component, out var value) && Time.time - value.Value < 0.6f && Object.op_Implicit((Object)(object)value.Key)) { string key2 = KeyOf(component, value.Key); if (!learnt.ContainsKey(key2)) { learnt[key2] = new Found { Layer = text, State = text2 }; Note("learnt (after use) ", component, value.Key, text, text2); } } } catch (Exception) { } } private static void Note(string what, CharacterBody body, SkillDef def, string layer, string state) { if (noteLogs++ < 40) { RainCyclerPlugin.Log.LogInfo((object)("Heresy animation " + what + ((Object)body).name + " (" + def.skillNameToken + "): " + layer + " / " + state)); } } public static void Postfix(GenericSkill __instance, bool __result) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (!__result) { return; } try { Swapper.NoteUse(__instance); if (!Object.op_Implicit((Object)(object)Swapper.HeresyAnimationSource(__instance, out var body, out var slotOut)) || !Object.op_Implicit((Object)(object)body)) { CharacterBody val = (Object.op_Implicit((Object)(object)__instance) ? ((Component)__instance).GetComponent<CharacterBody>() : null); LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); if (Object.op_Implicit((Object)(object)val) && firstLocalUser != null && (Object)(object)firstLocalUser.cachedBody == (Object)(object)val && Object.op_Implicit((Object)(object)__instance.skillDef)) { lastUsed[val] = new KeyValuePair<SkillDef, float>(__instance.skillDef, Time.time); } } else { Floppy.HeresyUsed(body, slotOut, __instance); } } catch (Exception) { } } private static IEnumerator Run(Animator animator, int layer, Found found, float forwardSpeed, float backSpeed) { long id = ((long)((Object)animator).GetInstanceID() << 8) | (uint)layer; if (!running.Add(id)) { yield break; } try { animator.PlayInFixedTime(found.State, layer, 0f); animator.Update(0f); AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(layer); float num = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length; if (float.IsInfinity(num) || num < 0.05f) { num = 0.5f; } float duration = Mathf.Min(num, 0.7f); float portion = Mathf.Clamp01(duration / num); float t = 0f; while (t < duration) { if (!Object.op_Implicit((Object)(object)animator)) { yield break; } t += Time.deltaTime * forwardSpeed; animator.Play(found.State, layer, Mathf.Clamp01(t / duration) * portion); animator.Update(0f); yield return null; } while (backSpeed > 0f && t > 0f) { if (!Object.op_Implicit((Object)(object)animator)) { yield break; } t -= Time.deltaTime * backSpeed; animator.Play(found.State, layer, Mathf.Clamp01(t / duration) * portion); animator.Update(0f); yield return null; } if (Object.op_Implicit((Object)(object)animator)) { Release(animator, layer, found.Layer); } } finally { running.Remove(id); } } private static void Release(Animator animator, int layer, string layerName) { string[] array = new string[2] { "BufferEmpty", "Empty" }; foreach (string text in array) { if (animator.HasState(layer, Animator.StringToHash(text))) { animator.CrossFadeInFixedTime(text, 0.12f, layer); return; } } if (animator.HasState(layer, Animator.StringToHash("Idle"))) { animator.CrossFadeInFixedTime("Idle", 0.12f, layer); } } private static Found Search(SkillDef source, Animator animator) { Type stateType = ((SerializableEntityStateType)(ref source.activationState)).stateType; if (stateType == null) { return null; } List<string> list = StringsOf(stateType); for (int i = 0; i < list.Count; i++) { int layerIndex = animator.GetLayerIndex(list[i]); if (layerIndex < 0) { continue; } for (int j = i + 1; j < list.Count && j <= i + 3; j++) { if (Usable(list[j]) && animator.HasState(layerIndex, Animator.StringToHash(list[j]))) { return new Found { Layer = list[i], State = list[j] }; } } } Found found = null; foreach (string item in list) { if (!Usable(item)) { continue; } for (int k = 0; k < animator.layerCount; k++) { if (animator.HasState(k, Animator.StringToHash(item))) { string layerName = animator.GetLayerName(k); bool flag = layerName.Contains("Gesture") || layerName.Contains("Override"); if (found == null || (flag && !found.Layer.Contains("Gesture") && !found.Layer.Contains("Override"))) { found = new Found { Layer = layerName, State = item }; } } } } return found; } private static List<string> StringsOf(Type type) { if (stringCache.TryGetValue(type, out var value)) { return value; } List<string> list = new List<string>(); try { Type type2 = type; while (type2 != null && type2 != typeof(object) && type2.Name != "EntityState" && type2.Name != "BaseState" && type2.Name != "BaseSkillState") { List<MethodInfo> list2 = new List<MethodInfo>(); MethodInfo method = type2.GetMethod("OnEnter", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { list2.Add(method); } MethodInfo[] methods = type2.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo != method && methodInfo.Name != "OnExit" && methodInfo.Name != "FixedUpdate" && methodInfo.Name != "Update") { list2.Add(methodInfo); } } FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType != typeof(string)) { continue; } try { string text = fieldInfo.GetValue(null) as string; if (!string.IsNullOrEmpty(text)) { list.Add(text); } } catch (Exception) { } } foreach (MethodInfo item in list2) { byte[] array = item.GetMethodBody()?.GetILAsByteArray(); if (array == null) { continue; } for (int j = 0; j + 4 < array.Length; j++) { byte num = array[j]; OpCode ldstr = OpCodes.Ldstr; if (num != ldstr.Value) { continue; } int num2 = BitConverter.ToInt32(array, j + 1); if (num2 >> 24 == 112) { try { list.Add(type2.Module.ResolveString(num2)); j += 4; } catch (Exception) { } } } } type2 = type2.BaseType; } } catch (Exception) { } stringCache[type] = list; return list; } } internal static class ItemBuffs { private sealed class Link { public string Item; public string[] Buffs; } private sealed class Line { public float At; public string Tag; public string Text; } private sealed class KeyState { public float Since; public bool Second; } private static readonly Link[] links = new Link[2] { new Link { Item = "MasterBattery", Buffs = new string[1] { "KineticArmor" } }, new Link { Item = "MasterCore", Buffs = new string[2] { "CollectiveShareBuff", "KineticArmor" } } }; private static readonly string[] hexItems = new string[14] { "SlipperyGround", "Blindness", "LowerHealing", "ShareItemsWithEnemies", "HexHaunting", "WeakAssHamstring", "RoamingItemDisable", "Mimicry", "RandomDebuffOnInteract", "BarrierEnemiesOnKill", "HexCurse", "OutOfTPRadius", "IncreasedDifficulty", "HexMountain" }; private static readonly Dictionary<CharacterBody, HashSet<string>> given = new Dictionary<CharacterBody, HashSet<string>>(); private static readonly HashSet<CharacterBody> affixHandled = new HashSet<CharacterBody>(); private static Run hexRun; private static float next; private static readonly List<Line> queue = new List<Line>(); private static readonly HashSet<string> said = new HashSet<string>(); private static Run messageRun; private const string Green = "#7aff9a"; private const string Light = "#b9ffce"; private const string Dark = "#3fb868"; private static float firstAt = -1f; private static readonly Dictionary<CharacterBody, KeyState> keyStates = new Dictionary<CharacterBody, KeyState>(); private static readonly Dictionary<CharacterBody, float> weakUntilHit = new Dictionary<CharacterBody, float>(); private static void Say(string key, string text, string color, float delay = 0f, string tag = null) { if (!said.Contains(key)) { said.Add(key); queue.Add(new Line { At = Time.time + delay, Tag = tag, Text = "<color=" + color + ">" + text + "</color>" }); } } private static void Flush() { queue.Sort((Line x, Line y) => x.At.CompareTo(y.At)); while (queue.Count > 0 && queue[0].At <= Time.time) { Chat.AddMessage(queue[0].Text); queue.RemoveAt(0); } } private static void Messages(CharacterBody body) { if (!Object.op_Implicit((Object)(object)Run.instance)) { return; } if (messageRun != Run.instance) { messageRun = Run.instance; said.Clear(); queue.Clear(); firstAt = -1f; } LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); if (firstLocalUser == null || (Object)(object)firstLocalUser.cachedBody != (Object)(object)body) { return; } int num = 0; string[] array = hexItems; foreach (string itemName in array) { num += Swapper.CountItem(body, itemName); } if (num >= 7) { Say("aware", "You feel Her awareness...", "#7aff9a"); Say("avarice", "Maintain your avarice.", "#3fb868", 1.5f); } object obj = Swapper.BuffIndexOf("PromoteStygianWhenHurt"); object obj2 = Swapper.BuffIndexOf("EliteDeathAffixOnExpire"); bool num2 = obj2 != null && Swapper.HasBuff(body, obj2); if (obj != null && Swapper.HasBuff(body, obj) && !said.Contains("first")) { Say("first", "You have sufficed Her approval...", "#7aff9a"); firstAt = Time.time; } if (num2) { queue.RemoveAll((Line q) => q.Tag == "imp"); if (!said.Contains("impatient")) { said.Add("impatient"); said.Add("weaken"); } Say("hold", "Hold steady for Her grasp.", "#3fb868"); } else if (firstAt >= 0f && Time.time - firstAt >= 5f) { Say("impatient", "Her Impatience is growing,", "#7aff9a", 0f, "imp"); Say("weaken", "Weaken your soul.", "#b9ffce", 0.5f, "imp"); } } public static void Tick() { Flush(); WeakCheck(); if (Time.unscaledTime < next || !NetworkServer.active) { return; } next = Time.unscaledTime + 0.5f; try { ForgetGone(); foreach (CharacterBody item in new List<CharacterBody>(CharacterBody.readOnlyInstancesList)) { if (!Object.op_Implicit((Object)(object)item) || !Object.op_Implicit((Object)(object)item.inventory)) { continue; } if (RainCyclerPlugin.ModBatteryCore.Value) { ItemLinks(item); } if (RainCyclerPlugin.ModArtifactKey.Value) { KeyBuffs(item); } if (item.isPlayerControlled) { if (RainCyclerPlugin.ModHex.Value) { Messages(item); HexCount(item); } if (RainCyclerPlugin.ModHerApproval.Value) { DeathAffix(item); } } } } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Item buffs failed: " + ex.Message)); } } private static void ForgetGone() { List<CharacterBody> list = null; foreach (CharacterBody key in given.Keys) { if (!Object.op_Implicit((Object)(object)key)) { (list ?? (list = new List<CharacterBody>())).Add(key); } } if (list != null) { foreach (CharacterBody item in list) { given.Remove(item); } } affixHandled.RemoveWhere((CharacterBody b) => !Object.op_Implicit((Object)(object)b)); List<CharacterBody> list2 = null; foreach (CharacterBody key2 in keyStates.Keys) { if (!Object.op_Implicit((Object)(object)key2)) { (list2 ?? (list2 = new List<CharacterBody>())).Add(key2); } } if (list2 == null) { return; } foreach (CharacterBody item2 in list2) { keyStates.Remove(item2); } } private static void KeyBuffs(CharacterBody body) { int num = Swapper.CountItem(body, "ArtifactKey"); keyStates.TryGetValue(body, out var value); if (num > 0) { if (value == null) { keyStates[body] = new KeyState { Since = Time.time }; Swapper.GiveBuff(body, Swapper.BuffIndexOf("Weak")); } else if (!value.Second && Time.time - value.Since >= 1.5f) { value.Second = true; Swapper.TakeBuff(body, Swapper.BuffIndexOf("Weak")); Swapper.GiveBuff(body, Swapper.BuffIndexOf("Ethereal")); Swapper.GiveBuff(body, Swapper.BuffIndexOf("Warbanner")); if (body.isPlayerControlled) { Swapper.NanoFlash(body, hop: true); } } } else if (value != null) { keyStates.Remove(body); string[] array = new string[3] { "Weak", "Ethereal", "Warbanner" }; foreach (string name in array) { Swapper.TakeBuff(body, Swapper.BuffIndexOf(name)); } } } private static void ItemLinks(CharacterBody body) { HashSet<string> hashSet = new HashSet<string>(); Link[] array = links; foreach (Link link in array) { if (Swapper.CountItem(body, link.Item) > 0) { string[] buffs = link.Buffs; foreach (string item in buffs) { hashSet.Add(item); } } } if (!given.TryGetValue(body, out var value)) { if (hashSet.Count == 0) { return; } HashSet<string> hashSet2 = (given[body] = new HashSet<string>()); value = hashSet2; } foreach (string item2 in hashSet) { if (!value.Contains(item2)) { object obj = Swapper.BuffIndexOf(item2); if (obj != null) { Swapper.GiveBuff(body, obj); value.Add(item2); } } } List<string> list = null; foreach (string item3 in value) { if (!hashSet.Contains(item3)) { Swapper.TakeBuff(body, Swapper.BuffIndexOf(item3)); (list ?? (list = new List<string>())).Add(item3); } } if (list == null) { return; } foreach (string item4 in list) { value.Remove(item4); } } private static void HexCount(CharacterBody body) { if (!Object.op_Implicit((Object)(object)Run.instance) || hexRun == Run.instance) { return; } int num = 0; string[] array = hexItems; foreach (string itemName in array) { num += Swapper.CountItem(body, itemName); } if (num >= 13) { object obj = Swapper.BuffIndexOf("PromoteStygianWhenHurt"); if (obj != null) { hexRun = Run.instance; Swapper.GiveBuff(body, obj); } } } private static void DeathAffix(CharacterBody body) { object obj = Swapper.BuffIndexOf("EliteDeathAffixOnExpire"); if (obj == null) { return; } if (!Swapper.HasBuff(body, obj)) { affixHandled.Remove(body); } else if (affixHandled.Add(body)) { if (!Swapper.CallOn(body.inventory, "SetEquipmentIndex", (object)(EquipmentIndex)(-1))) { Swapper.CallOn(body.inventory, "SetEquipmentIndex", (object)(EquipmentIndex)(-1), false); } Fx.Laugh(((Component)body).gameObject); SpawnHealingCore(body); Swapper.GiveBuff(body, Swapper.BuffIndexOf("Weak")); weakUntilHit[body] = HealthOf(body); } } private static float HealthOf(CharacterBody body) { if (!Object.op_Implicit((Object)(object)body.healthComponent)) { return 0f; } return body.healthComponent.health + body.healthComponent.shield; } private static void WeakCheck() { if (weakUntilHit.Count == 0) { return; } List<CharacterBody> list = null; foreach (KeyValuePair<CharacterBody, float> item in weakUntilHit) { CharacterBody key = item.Key; if (!Object.op_Implicit((Object)(object)key)) { (list ?? (list = new List<CharacterBody>())).Add(key); } else if (HealthOf(key) < item.Value - 0.01f) { Swapper.TakeBuff(key, Swapper.BuffIndexOf("Weak")); (list ?? (list = new List<CharacterBody>())).Add(key); } } if (list == null) { return; } foreach (CharacterBody item2 in list) { weakUntilHit.Remove(item2); } } private static void SpawnHealingCore(CharacterBody body) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = MasterCatalog.FindMasterPrefab("AffixEarthHealerMaster"); if (!Object.op_Implicit((Object)(object)val)) { foreach (CharacterMaster allMaster in MasterCatalog.allMasters) { if (Object.op_Implicit((Object)(object)allMaster) && ((Object)allMaster).name.ToLowerInvariant().Contains("earthhealer")) { val = ((Component)allMaster).gameObject; break; } } } if (!Object.op_Implicit((Object)(object)val)) { RainCyclerPlugin.Log.LogWarning((object)"Healing Core master not found."); return; } MasterSummon val2 = new MasterSummon(); Swapper.SetOn(val2, "masterPrefab", val); Swapper.SetOn(val2, "position", body.corePosition + Vector3.up * 1.5f); Swapper.SetOn(val2, "rotation", ((Component)body).transform.rotation); Swapper.SetOn(val2, "summonerBodyObject", ((Component)body).gameObject); Swapper.SetOn(val2, "ignoreTeamMemberLimit", true); Swapper.SetOn(val2, "useAmbientLevel", true); if (Object.op_Implicit((Object)(object)body.teamComponent)) { Swapper.SetOn(val2, "teamIndexOverride", body.teamComponent.teamIndex); } CharacterMaster val3 = val2.Perform(); if (Object.op_Implicit((Object)(object)val3)) { ((MonoBehaviour)RainCyclerPlugin.Instance).StartCoroutine(DressCore(val3)); } } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Healing Core failed: " + ex.Message)); } } private static IEnumerator DressCore(CharacterMaster master) { yield return (object)new WaitForSeconds(0.3f); if (!Object.op_Implicit((Object)(object)master)) { yield break; } EquipmentIndex val = EquipmentCatalog.FindEquipmentIndex("EliteHauntedEquipment"); if ((int)val != -1 && Object.op_Implicit((Object)(object)master.inventory) && !Swapper.CallOn(master.inventory, "SetEquipmentIndex", val)) { Swapper.CallOn(master.inventory, "SetEquipmentIndex", val, false); } CharacterBody body = master.GetBody(); if (Object.op_Implicit((Object)(object)body)) { string[] array = new string[3] { "ReaperSiphonTarget", "HealingDisabled", "Fruiting" }; foreach (string name in array) { Swapper.GiveBuff(body, Swapper.BuffIndexOf(name)); } yield return (object)new WaitForSeconds(0.2f); if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.healthComponent)) { Swapper.SetOn(body.healthComponent, "Networkhealth", 1f); } } } } internal static class ItemCountFix { [ThreadStatic] public static bool Bypass; public static Inventory Target; public static readonly HashSet<int> Items = new HashSet<int>(); private static readonly string[] shopWords = new string[13] { "cost", "purchase", "shrine", "cleans", "scrap", "duplicat", "cauldron", "shop", "terminal", "transfer", "steal", "inventoryui", "itemtake" }; public static void Clear() { Target = null; Items.Clear(); } public static void Install() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown try { Harmony val = new Harmony("local.rodamortaraincycler"); HarmonyMethod val2 = new HarmonyMethod(typeof(ItemCountFix).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public)); int num = 0; MethodInfo[] methods = typeof(Inventory).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name.StartsWith("GetItemCount") && !(methodInfo.ReturnType != typeof(int))) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length != 0 && (!(parameters[0].ParameterType != typeof(ItemIndex)) || !(parameters[0].ParameterType != typeof(ItemDef)))) { val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } } } RainCyclerPlugin.Log.LogInfo((object)("Item count patch installed on " + num + " methods")); } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Item count patch failed: " + ex.Message)); } } public static void Postfix(Inventory __instance, object[] __args, ref int __result) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected I4, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected I4, but got Unknown if (Bypass || __result > 0 || Items.Count == 0 || __instance != Target || __args == null || __args.Length == 0) { return; } int num = -1; if (__args[0] is ItemIndex val) { num = (int)val; } else { object obj = __args[0]; ItemDef val2 = (ItemDef)((obj is ItemDef) ? obj : null); if (val2 != null && Object.op_Implicit((Object)(object)val2)) { num = (int)val2.itemIndex; } } if (num >= 0 && Items.Contains(num) && !AskedByAShop()) { __result = 1; } } private static bool AskedByAShop() { try { StackFrame[] frames = new StackTrace(2, fNeedFileInfo: false).GetFrames(); if (frames == null) { return false; } StackFrame[] array = frames; for (int i = 0; i < array.Length; i++) { Type type = array[i].GetMethod()?.DeclaringType; if (type == null) { continue; } string text = (type.FullName ?? type.Name).ToLowerInvariant(); string[] array2 = shopWords; foreach (string value in array2) { if (text.Contains(value)) { return true; } } } } catch (Exception) { } return false; } } internal static class Keys { private static string interactName; private static float interactCheck; public static KeyCode Passive { get { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = RainCyclerPlugin.PassiveKey.Value; return ((KeyboardShortcut)(ref value)).MainKey; } } public static KeyCode Skill(int index) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = RainCyclerPlugin.SkillKeys[Mathf.Clamp(index, 0, 3)].Value; return ((KeyboardShortcut)(ref value)).MainKey; } public unsafe static string Label(KeyCode key) { string text = ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(); if (text.StartsWith("Alpha")) { return text.Substring(5); } if (text.StartsWith("Keypad")) { return "Num" + text.Substring(6); } if (text.StartsWith("Mouse")) { return "M" + text.Substring(5); } return text; } public static bool InteractDown(LocalUser user) { try { if (user != null && user.inputPlayer != null) { return user.inputPlayer.GetButtonDown("Interact"); } } catch (Exception) { } return Input.GetKeyDown((KeyCode)101); } public static string InteractName(LocalUser user) { if (interactName != null && Time.unscaledTime < interactCheck) { return interactName; } interactCheck = Time.unscaledTime + 3f; interactName = "E"; try { Player val = ((user != null) ? user.inputPlayer : null); if (val == null) { return interactName; } object obj = ((object)val).GetType().GetProperty("controllers")?.GetValue(val, null); object obj2 = obj?.GetType().GetProperty("maps")?.GetValue(obj, null); if (obj2 == null) { return interactName; } MethodInfo[] methods = obj2.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name != "GetFirstElementMapWithAction") { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 3 && parameters[0].ParameterType.IsEnum && !(parameters[1].ParameterType != typeof(string))) { object obj3 = Enum.Parse(parameters[0].ParameterType, "Keyboard"); object obj4 = methodInfo.Invoke(obj2, new object[3] { obj3, "Interact", true }); string value = obj4?.GetType().GetProperty("elementIdentifierName")?.GetValue(obj4, null) as string; if (!string.IsNullOrEmpty(value)) { interactName = value; } break; } } } catch (Exception) { } return interactName; } public static bool Typing() { try { GameObject val = (Object.op_Implicit((Object)(object)EventSystem.current) ? EventSystem.current.currentSelectedGameObject : null); if (Object.op_Implicit((Object)(object)val) && (Object.op_Implicit((Object)(object)val.GetComponent<InputField>()) || (Object)(object)val.GetComponent("TMP_InputField") != (Object)null)) { return true; } } catch (Exception) { } return false; } public static bool Paused() { try { return Time.timeScale <= 0.001f; } catch (Exception) { return false; } } public static bool InteractableTargeted(CharacterBody body) { try { InteractionDriver val = (Object.op_Implicit((Object)(object)body) ? ((Component)body).GetComponent<InteractionDriver>() : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } return Object.op_Implicit((Object)(object)val.FindBestInteractableObject()); } catch (Exception) { return false; } } } internal static class OptionsMenu { public static void Register(ConfigFile config) { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "RiskOfOptions"); if (assembly == null) { return; } Type type = assembly.GetType("RiskOfOptions.ModSettingsManager"); MethodInfo methodInfo = type?.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "AddOption" && m.GetParameters().Length == 1); if (methodInfo == null) { RainCyclerPlugin.Log.LogWarning((object)"Risk of Options found, but its API was not recognised."); return; } type.GetMethod("SetModDescription", new Type[1] { typeof(string) })?.Invoke(null, new object[1] { "Rodamorta SkillCycler: swap skills, passives and skins; optional extras." }); int num = 0; foreach (ConfigDefinition item in config.Keys.OrderBy((ConfigDefinition k) => (!(k.Section == "SkillCycler - Modules")) ? ((k.Section == "Rodamorta - Modules") ? 1 : ((!(k.Section == "SkillCycler - Keybinds")) ? 3 : 2)) : 0).ToList()) { if (item.Section == "Setup") { continue; } ConfigEntryBase entry = config[item]; object obj = Make(assembly, entry); if (obj != null) { try { methodInfo.Invoke(null, new object[1] { obj }); num++; } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Option " + item.Key + " not added: " + (ex.InnerException ?? ex).Message)); } } } RainCyclerPlugin.Log.LogInfo((object)("Risk of Options: " + num + " options added.")); } private static object Make(Assembly asm, ConfigEntryBase entry) { Type settingType = entry.SettingType; string text; if (settingType == typeof(bool)) { text = "CheckBoxOption"; } else if (settingType == typeof(string)) { text = "StringInputFieldOption"; } else if (settingType == typeof(float)) { text = "FloatFieldOption"; } else { if (!(settingType == typeof(KeyboardShortcut))) { return null; } text = "KeyBindOption"; } Type type = asm.GetType("RiskOfOptions.Options." + text); if (type == null) { return null; } ConstructorInfo[] constructors = type.GetConstructors(); foreach (ConstructorInfo constructorInfo in constructors) { ParameterInfo[] parameters = constructorInfo.GetParameters(); if (parameters.Length != 0 && parameters[0].ParameterType.IsAssignableFrom(((object)entry).GetType()) && !parameters.Skip(1).Any((ParameterInfo p) => !p.IsOptional)) { object[] array = new object[parameters.Length]; array[0] = entry; for (int num = 1; num < parameters.Length; num++) { array[num] = parameters[num].DefaultValue; } try { return constructorInfo.Invoke(array); } catch (Exception) { } } } return null; } } internal static class Ragdoll { private sealed class Saved { public Rigidbody Body; public bool Kinematic; public bool DetectCollisions; public int Layer; public Collider[] Colliders; public bool[] ColliderOn; public Transform Transform; public Vector3 LocalPosition; public Quaternion LocalRotation; } private sealed class Active { public Animator Animator; public bool AnimatorWasOn; public List<Saved> Parts = new List<Saved>(); public Transform Model; public Rigidbody Pin; public Vector3 PinLocalPosition; public Quaternion PinLocalRotation; } private static readonly Dictionary<CharacterBody, Active> active = new Dictionary<CharacterBody, Active>(); private static readonly HashSet<CharacterBody> fallen = new HashSet<CharacterBody>(); private static GameObject tentabauble; private static bool tentabaubleSearched; public static bool IsActive(CharacterBody body) { if (Object.op_Implicit((Object)(object)body)) { return active.ContainsKey(body); } return false; } public static bool IsFallen(CharacterBody body) { if (Object.op_Implicit((Object)(object)body)) { return fallen.Contains(body); } return false; } public static bool Begin(CharacterBody body, bool puppet) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) try { if (!Object.op_Implicit((Object)(object)body) || Ragdoll.active.ContainsKey(body)) { return false; } Transform val = (Object.op_Implicit((Object)(object)body.modelLocator) ? body.modelLocator.modelTransform : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } Rigidbody[] componentsInChildren = ((Component)val).GetComponentsInChildren<Rigidbody>(true); if (componentsInChildren.Length < 2) { return false; } Active active = new Active { Model = val, Animator = ((Component)val).GetComponentInChildren<Animator>() }; int num = LayerMask.NameToLayer("Ragdoll"); Rigidbody val2 = null; int num2 = int.MaxValue; Rigidbody[] array = componentsInChildren; foreach (Rigidbody val3 in array) { Collider[] components = ((Component)val3).GetComponents<Collider>(); Saved saved = new Saved { Body = val3, Kinematic = val3.isKinematic, DetectCollisions = val3.detectCollisions, Layer = ((Component)val3).gameObject.layer, Colliders = components, ColliderOn = new bool[components.Length], Transform = ((Component)val3).transform, LocalPosition = ((Component)val3).transform.localPosition, LocalRotation = ((Component)val3).transform.localRotation }; for (int j = 0; j < components.Length; j++) { saved.ColliderOn[j] = components[j].enabled; } active.Parts.Add(saved); int num3 = 0; Transform val4 = ((Component)val3).transform; while (Object.op_Implicit((Object)(object)val4) && (Object)(object)val4 != (Object)(object)val) { num3++; val4 = val4.parent; } if (num3 < num2) { num2 = num3; val2 = val3; } } if (Object.op_Implicit((Object)(object)active.Animator)) { active.AnimatorWasOn = ((Behaviour)active.Animator).enabled; ((Behaviour)active.Animator).enabled = false; } Vector3 velocity = Vector3.zero; Component component = ((Component)body).GetComponent("CharacterMotor"); if ((Object)(object)component != (Object)null && !puppet) { velocity = Swapper.ReadVelocity(component); } foreach (Saved part in active.Parts) { part.Body.isKinematic = false; part.Body.detectCollisions = true; if (!puppet) { part.Body.velocity = velocity; } if (num >= 0) { ((Component)part.Body).gameObject.layer = num; } Collider[] colliders = part.Colliders; foreach (Collider val5 in colliders) { if (Object.op_Implicit((Object)(object)val5)) { val5.enabled = true; } } } if (puppet && Object.op_Implicit((Object)(object)val2)) { active.Pin = val2; active.PinLocalPosition = val.InverseTransformPoint(val2.position); active.PinLocalRotation = Quaternion.Inverse(val.rotation) * val2.rotation; val2.isKinematic = true; } Ragdoll.active[body] = active; return true; } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Ragdoll failed: " + ex.Message)); return false; } } public static void End(CharacterBody body) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)body) || !active.TryGetValue(body, out var value)) { return; } active.Remove(body); try { foreach (Saved part in value.Parts) { if (!Object.op_Implicit((Object)(object)part.Body)) { continue; } part.Body.isKinematic = true; part.Body.detectCollisions = part.DetectCollisions; ((Component)part.Body).gameObject.layer = part.Layer; for (int i = 0; i < part.Colliders.Length; i++) { if (Object.op_Implicit((Object)(object)part.Colliders[i])) { part.Colliders[i].enabled = part.ColliderOn[i]; } } part.Body.isKinematic = part.Kinematic; if (Object.op_Implicit((Object)(object)part.Transform)) { part.Transform.localPosition = part.LocalPosition; part.Transform.localRotation = part.LocalRotation; } } if (Object.op_Implicit((Object)(object)value.Animator) && value.AnimatorWasOn) { ((Behaviour)value.Animator).enabled = true; } } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Ending ragdoll failed: " + ex.Message)); } } public static void Pin() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if (active.Count == 0) { return; } List<CharacterBody> list = null; foreach (KeyValuePair<CharacterBody, Active> item in active) { if (!Object.op_Implicit((Object)(object)item.Key)) { (list ?? (list = new List<CharacterBody>())).Add(item.Key); continue; } Active value = item.Value; if (Object.op_Implicit((Object)(object)value.Pin) && Object.op_Implicit((Object)(object)value.Model)) { value.Pin.position = value.Model.TransformPoint(value.PinLocalPosition); value.Pin.rotation = value.Model.rotation * value.PinLocalRotation; } } if (list == null) { return; } foreach (CharacterBody item2 in list) { active.Remove(item2); } } public static void FakeDeath(CharacterBody body, float seconds = 1.5f) { if (Object.op_Implicit((Object)(object)body) && !fallen.Contains(body) && !active.ContainsKey(body)) { ((MonoBehaviour)RainCyclerPlugin.Instance).StartCoroutine(FakeDeathRoutine(body, seconds)); } } private static IEnumerator FakeDeathRoutine(CharacterBody body, float seconds) { fallen.Add(body); try { Lock(body, locked: true); Begin(body, puppet: false); Tentabauble(body); float end = Time.time + seconds; while (Time.time < end && Object.op_Implicit((Object)(object)body)) { yield return null; } } finally { End(body); if (Object.op_Implicit((Object)(object)body)) { Lock(body, locked: false); Swapper.PlayEffect(body); Swapper.NanoFlash(body, hop: true, buff: false); } fallen.Remove(body); } } private static void Tentabauble(CharacterBody body) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown try { if (!tentabaubleSearched) { tentabaubleSearched = true; GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); foreach (GameObject val in array) { if (Object.op_Implicit((Object)(object)val) && ((Object)val).name.ToLowerInvariant().Contains("tentabauble") && Object.op_Implicit((Object)(object)val.GetComponent<EffectComponent>())) { tentabauble = val; break; } } if (!Object.op_Implicit((Object)(object)tentabauble)) { RainCyclerPlugin.Log.LogInfo((object)"No Tentabauble effect prefab found."); } } if (Object.op_Implicit((Object)(object)tentabauble) && Object.op_Implicit((Object)(object)body)) { EffectManager.SpawnEffect(tentabauble, new EffectData { origin = body.corePosition, scale = body.radius }, NetworkServer.active); } } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Tentabauble failed: " + ex.Message)); } } private static void Lock(CharacterBody body, bool locked) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown try { EntityStateMachine[] components = ((Component)body).GetComponents<EntityStateMachine>(); foreach (EntityStateMachine val in components) { if (!Object.op_Implicit((Object)(object)val)) { continue; } if (val.customName == "Body") { if (locked) { val.SetNextState((EntityState)new Idle()); } else { val.SetNextStateToMain(); } } else if (locked) { val.SetNextStateToMain(); } } } catch (Exception ex) { RainCyclerPlugin.Log.LogWarning((object)("Locking the body failed: " + ex.Message)); } } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("local.rodamortaskillcycler", "Rodamorta SkillCycler", "0.9.5")] public class RainCyclerPlugin : BaseUnityPlugin { internal sealed class Fixed<T> { public readonly T Value; public Fixed(T value) { Value = value; } } internal static ManualLogSource Log; internal static RainCyclerPlugin Instance; internal static ConfigEntry<bool> ShowPassives; internal static ConfigEntry<bool> UseWheel; internal static ConfigEntry<bool> ChatMessage; internal static ConfigEntry<string> PeacefulStages; internal static ConfigEntry<string> ProudStages; internal static ConfigEntry<float> ProudPassiveSeconds; internal static ConfigEntry<float> SkinCooldown; internal static ConfigEntry<bool> UseKeys; internal static ConfigEntry<bool> ShowKeyHints; internal static ConfigEntry<bool> FloppyEnabled; internal static ConfigEntry<bool> ModSkillCycler; internal static ConfigEntry<bool> ModPassiveSwap; internal static ConfigEntry<bool> ModSkinSwap; internal static ConfigEntry<bool> ModPassivesSafe; internal static ConfigEntry<bool> ModPassivesProud; internal static ConfigEntry<bool> ModHeresyAnims; internal static ConfigEntry<bool> ModStageNames; internal static ConfigEntry<bool> ModBatteryCore; internal static ConfigEntry<bool> ModArtifactKey; internal static ConfigEntry<bool> ModHex; internal static ConfigEntry<bool> FirstRunDone; internal static readonly Fixed<bool> ModFakeDeath = new Fixed<bool>(value: true); internal static readonly Fixed<bool> ModSwapSounds = new Fixed<bool>(value: true); internal static readonly Fixed<bool> ReverseJump = new Fixed<bool>(value: true); internal static readonly Fixed<string> SwapSound = new Fixed<string>(""); internal static ConfigEntry<KeyboardShortcut>[] SkillKeys; internal static ConfigEntry<KeyboardShortcut> PassiveKey; internal static int SettingsVersion; private float nextTick; private static Run highlightedRun; internal static ConfigEntry<bool> ModSeerQuotes => ModStageNames; internal static ConfigEntry<bool> ModHerApproval => ModHex; private void Awake() { //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Instance = this; ShowPassives = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - UI", "Show Passive Row", true, "Show the survivor's passive above the skill bar."); ShowPassives.SettingChanged += delegate { SettingsVersion++; }; UseWheel = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Input", "Mouse Wheel Scrolls Menus", true, "Scroll the mouse wheel to browse the options of the hovered skill, passive or skin."); ChatMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - UI", "Chat Messages", true, "Print what happened (skill, passive or skin changed) in chat."); PeacefulStages = ((BaseUnityPlugin)this).Config.Bind<string>("SkillCycler - Rules", "Semi-arid Stages (Safe)", "bazaar,computationalexchange,ss2_voidshop,mysteryspace", "Comma separated words. A stage whose internal name contains one of them is a Semi-arid (safe) stage: free switching, passives and skins can be changed."); ProudStages = ((BaseUnityPlugin)this).Config.Bind<string>("SkillCycler - Rules", "Cataclysmic Environment (Proud)", "moon2,moon,voidraid,solutionalhaunt,solusweb,soulbound threshold,soulboundthreshold,ultima,limbo,artifactworld,goldshores,meridian,bulwarkshaunt_ghostwave,enemiesreturns_outoftime", "Final boss stages (same kind of list). Passives can be changed here, but only once every 'Passive Cooldown' seconds."); ProudPassiveSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("SkillCycler - Rules", "Passive Cooldown in Cataclysmic Stages (seconds)", 120f, "Seconds between passive changes in the Cataclysmic Environment (Proud) stages."); SkinCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("SkillCycler - Rules", "Skin Change Cooldown (seconds)", 1.5f, "Seconds before the skin can be changed again (a lock shows on the skin button meanwhile)."); ModSkillCycler = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Enable SkillCycler (skill, passive and skin swapping)", true, "The whole swapping feature (skill, passive and skin menus). Needs a new stage to fully apply."); ModPassiveSwap = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Passive Swapping", true, "Passive swapping (where the stage options below allow it)."); ModSkinSwap = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Skin Swapping", true, "Skin swapping (in Semi-arid stages)."); ModPassivesSafe = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Passive and Skin Swapping in Semi-arid Stages (Safe)", true, "Passives and skins can be changed in Semi-arid (safe) stages."); ModPassivesProud = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Passive Swapping in Cataclysmic Environment (Proud)", true, "Passives can be changed in Cataclysmic Environment (Proud, final boss) stages, with a cooldown."); ModHeresyAnims = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Heresy Skills Slightly Floppy", true, "Using Heresy skills makes your bones very slightly floppy (Ruin: as floppy as usual). Not for the Heretic. Needs a game restart."); ModStageNames = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Modules", "Stage Names and Seer Quotes", true, "The Semi-arid / Cataclysmic text, the stage name with its icon on top of the timer, and the Lunar Seer's line under the skills (both extra lines show with the scoreboard open)."); ModBatteryCore = ((BaseUnityPlugin)this).Config.Bind<bool>("Rodamorta - Modules", "Core and Battery Items Give Buffs", false, "Charged Battery and Core items give their buff (Kinetic Armor, Collective Share) while held."); ModArtifactKey = ((BaseUnityPlugin)this).Config.Bind<bool>("Rodamorta - Modules", "Artifact Key Gives Buffs", false, "The Artifact Key weakens you, then after 1.5 s Ethereal and Warbanner They go away with the item."); ModHex = ((BaseUnityPlugin)this).Config.Bind<bool>("Rodamorta - Modules", "Her Approval", false, "\"Collect my hexes\""); FloppyEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Rodamorta - Modules", "Floppy Bones", false, "Loose, floppy bones (like the Floppy Survivors mod) on certain occasions: debuffs like Blight, Collapse or Fracture, Slippery Ground, Goobo Jr., and after becoming Void elite."); UseKeys = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Keybinds", "Enable Number Key Menus", true, "Open the swap menus with the keys below while playing (Interact picks)."); ShowKeyHints = ((BaseUnityPlugin)this).Config.Bind<bool>("SkillCycler - Keybinds", "Show Key Hints Over Skills", true, "Show the keys over the skills for a few seconds (after the first Interact press, and on first entering a safe stage)."); SkillKeys = new ConfigEntry<KeyboardShortcut>[4] { ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Primary Skill Menu Key", new KeyboardShortcut((KeyCode)49, Array.Empty<KeyCode>()), "Opens the primary skill menu."), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Secondary Skill Menu Key", new KeyboardShortcut((KeyCode)50, Array.Empty<KeyCode>()), "Opens the secondary skill menu."), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Utility Skill Menu Key", new KeyboardShortcut((KeyCode)51, Array.Empty<KeyCode>()), "Opens the utility skill menu."), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Special Skill Menu Key", new KeyboardShortcut((KeyCode)52, Array.Empty<KeyCode>()), "Opens the special skill menu.") }; PassiveKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SkillCycler - Keybinds", "Passive Menu Key", new KeyboardShortcut((KeyCode)53, Array.Empty<KeyCode>()), "Opens the passive menu (Semi-arid stages, and Cataclysmic ones when allowed)."); FirstRunDone = ((BaseUnityPlugin)this).Config.Bind<bool>("Setup", "FirstRunQuestionAnswered", false, "Internal: the first-start question about the Rodamorta features was answered."); HUD.onHudTargetChangedGlobal += OnHud; CharacterBody.onBodyStartGlobal += OnBodyStart; SceneManager.activeSceneChanged += OnScene; Run.onRunStartGlobal += OnRunStart; ItemCountFix.Install(); if (ModHeresyAnims.Value) { HeresyAnim.Install(); } } private void Start() { try { OptionsMenu.Register(((BaseUnityPlugin)this).Config); } catch (Exception ex) { Log.LogWarning((object)("Risk of Options setup failed: " + ex.Message)); } if (Chainloader.PluginInfos.TryGetValue("ntshtng.PassiveSkillHud", out var value) && (Object)(object)value.Instance != (Object)null) { ConfigFile config = value.Instance.Config; ConfigEntry<bool> val = default(ConfigEntry<bool>); if (config.TryGetEntry<bool>("General", "Show passives", ref val)) { bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; val.Value = false; config.SaveOnConfigSet = saveOnConfigSet; Log.LogWarning((object)"PassiveSkillHud is installed: its passive display was switched off, Rain Cycler shows passives itself. You can uninstall PassiveSkillHud."); } } } private void OnDestroy() { HUD.onHudTargetChangedGlobal -= OnHud; CharacterBody.onBodyStartGlobal -= OnBodyStart; SceneManager.activeSceneChanged -= OnScene; Run.onRunStartGlobal -= OnRunStart; } private static void OnHud(HUD hud) { if (ModSkillCycler.Value && !Object.op_Implicit((Object)(object)((Component)hud).GetComponent<SkillBarUi>())) { ((Component)hud).gameObject.AddComponent<SkillBarUi>(); } } private static void OnRunStart(Run run) { Swapper.ResetRun(); } private static void OnScene(Scene from, Scene to) { if (((Scene)(ref to)).name == "title") { FirstRun.Check(); } if (Object.op_Implicit((Object)(object)Run.instance)) { StageInfo.OnSceneEntered(); } if (Swapper.IsPeaceful() && Object.op_Implicit((Object)(object)Run.instance) && highlightedRun != Run.instance) { highlightedRun = Run.instance; SkillBarUi.HighlightPending = true; } if (Swapper.IsProud()) { SkillBarUi.ProudPending = true; } } private void OnBodyStart(CharacterBody body) { if (Object.op_Implicit((Object)(object)body) && body.isPlayerControlled && body.hasEffectiveAuthority) { ((MonoBehaviour)this).StartCoroutine(ApplyLater(body)); } } private IEnumerator ApplyLater(CharacterBody body) { yield return null; yield return null; if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.skillLocator)) { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); if (firstLocalUser != null) { Swapper.ApplySaved(firstLocalUser, body); } } } private void LateUpdate() { Ragdoll.Pin(); } private void Update() { Floppy.Tick(); Floppy.Frame(); ItemBuffs.Tick(); if (!ModSkillCycler.Value) { return; } LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); CharacterBody val = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null); if (Object.op_Implicit((Object)(object)val)) { Swapper.Frame(val); if (!(Time.unscaledTime < nextTick)) { nextTick = Time.unscaledTime + 0.25f; Swapper.Tick(val); } } } } internal static class RoundSprites { private const int Size = 128; private const float RingInnerRadius = 0.93f; private static Sprite disc; private static Sprite ring; private static Sprite frame; private static Sprite glow; private static Sprite pulse; private static Sprite outline; private static Sprite skinSpiral; private static Sprite lockClosed; private static Sprite lockOpen; public static Sprite Disc { get { if (!Object.op_Implicit((Object)(object)disc)) { return disc = Create("RainCyclerDisc", 0f); } return disc; } } public static Sprite Ring { get { if (!Object.op_Implicit((Object)(object)ring)) { return ring = Create("RainCyclerRing", 0.93f); } return ring; } } public static Sprite Frame { get { if (!Object.op_Implicit((Object)(object)frame)) { return frame = CreateFrame(); } return frame; } } public static Sprite Glow { get { if (!Object.op_Implicit((Object)(object)glow)) { return glow = CreateSpiral(3, 3.2f, "RainCyclerSpiral"); } return glow; } } public static Sprite Outline { get { if (!Object.op_Implicit((Object)(object)outline)) { return outline = CreateOutline(); } return outline; } } public static Sprite SkinSpiral { get { if (!Object.op_Implicit((Object)(object)skinSpiral)) { return skinSpiral = CreateSpiral(2, 2.4f, "RainCyclerSkinSpiral"); } return skinSpiral; } } public static Sprite LockClosed { get { if (!Object.op_Implicit((Object)(object)lockClosed)) { return lockClosed = CreateLock(open: false); } return lockClosed; } } public static Sprite LockOpen { get { if (!Object.op_Implicit((Object)(object)lockOpen)) { return lockOpen = CreateLock(open: true); } return lockOpen; } } public static Sprite Pulse { get { if (!Object.op_Implicit((Object)(object)pulse)) { return pulse = CreatePulse(); } return pulse; } } private static bool InLock(float u, float v, bool open) { float num = Mathf.Max(Mathf.Abs(u - 0.5f) - 0.22f, 0f); float num2 = Mathf.Max(Mathf.Abs(v - 0.31f) - 0.14f, 0f); if (Mathf.Sqrt(num * num + num2 * num2) < 0.05f) { float num3 = u - 0.5f; float num4 = v - 0.35f; if (num3 * num3 + num4 * num4 < 0.002025f) { return false; } if (Mathf.Abs(num3) < 0.018f && v > 0.22f && v < 0.35f) { return false; } return true; } float num5 = (open ? 0.64f : 0.52f); float num6 = u - 0.5f; float num7 = v - num5; float num8 = Mathf.Sqrt(num6 * num6 + num7 * num7); if