Decompiled source of Runes Redone v1.0.0
plugins/RunesRedone.dll
Decompiled 2 days 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.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using SideLoader; using SideLoader.Model; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("RunesRedone")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RunesRedone")] [assembly: AssemblyTitle("RunesRedone")] [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 RunicBow { public static class RunicBowManager { [HarmonyPatch(typeof(WeaponLoadoutItem), "ShootItemFromLoadout")] public class WeaponLoadoutItem_ShootItemFromLoadout { [HarmonyPrefix] public static void Prefix(ProjectileItem _projItem) { if (!((Object)(object)_projItem == (Object)null) && !((Component)_projItem).gameObject.activeSelf) { ((Component)_projItem).gameObject.SetActive(true); } } } [HarmonyPatch] public class AttackAttempt_Begin { public static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Character), "StartAttack", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Weapon), "OnStartCharging", (Type[])null, (Type[])null); } [HarmonyPrefix] public static void Prefix() { InAttackAttempt = true; } [HarmonyFinalizer] public static Exception Finalizer() { InAttackAttempt = false; return null; } } [HarmonyPatch(typeof(Character), "AttackReleased")] public class Character_AttackReleased { [HarmonyPostfix] public static void Postfix() { ManaNotified = false; } } [HarmonyPatch(typeof(CharacterUI), "ShowInfoNotificationLoc", new Type[] { typeof(string) })] public class CharacterUI_ShowInfoNotificationLoc { [HarmonyPrefix] public static bool Prefix(string _localizationKey) { if (_localizationKey != "Notification_ProjectileWeapon_NoAmmunition") { return true; } if (Time.time - ManaRefusedAt <= 0.5f) { return false; } if (Time.time - ArrowRestoreAt <= 0.75f) { return false; } return true; } } [HarmonyPatch(typeof(ProjectileItem), "AssignVisual")] public class ProjectileItem_AssignVisual { [HarmonyPrefix] public static void Prefix(ref Projectile ___m_projectile, ProjectileItem __instance) { ___m_projectile = ((Component)__instance).GetComponent<Projectile>(); } } [HarmonyPatch(typeof(PlayerCharacterStats), "OnUpdateStats")] public class PlayerStats_Update { [HarmonyFinalizer] public static Exception Finalizer(PlayerCharacterStats __instance) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Invalid comparison between Unknown and I4 //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown Character component = ((Component)__instance).GetComponent<Character>(); if (!Object.op_Implicit((Object)(object)component)) { return null; } if (!CharChargingAttack.Invoke(component) || !CharBowDrawn.Invoke(component)) { return null; } if (Object.op_Implicit((Object)(object)component.CurrentWeapon) && (int)component.CurrentWeapon.Type == 200) { WeaponCharger val = (WeaponCharger)((Item)component.CurrentWeapon).GetExtension("WeaponCharger"); if (!val.ChargeStarted && val.StartChargeTime < 0.0) { CharChargingAttack.Invoke(component) = false; CharBowDrawn.Invoke(component) = false; } } return null; } } [HarmonyPatch(typeof(EffectSynchronizer), "RegisterEffectReference")] public class EffectSynchronizer_RegisterEffectReference { [HarmonyPrefix] public static void Prefix(EffectSynchronizer __instance, ref List<string>[] ___m_categoryEffects) { if (___m_categoryEffects == null) { ___m_categoryEffects = new List<string>[EffectSynchronizer.EffectCategoriesCount]; for (int i = 0; i < ___m_categoryEffects.Length; i++) { ___m_categoryEffects[i] = new List<string>(); } } } } [HarmonyPatch(typeof(ProjectileWeapon), "UpdateProcessing")] public class ProjectileWeapon_UpdateProcessing { [HarmonyPostfix] public static void Postfix(ProjectileWeapon __instance, ref bool ___m_fullyBent) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (IsRunicBow((Item)(object)__instance) & ___m_fullyBent) { Character ownerCharacter = ((EffectSynchronizer)__instance).OwnerCharacter; if (!Object.op_Implicit((Object)(object)ownerCharacter.Inventory.Equipment.GetEquippedItem((EquipmentSlotIDs)8))) { ___m_fullyBent = false; CharChargingAttack.Invoke(ownerCharacter) = false; ownerCharacter.BowRelease(); ((WeaponCharger)((Item)__instance).GetExtension("WeaponCharger")).ResetCharging(); } } } } [HarmonyPatch(typeof(ProjectileItem), "ForceReturn")] public class ProjectileItem_ForceReturn { [HarmonyFinalizer] public static Exception Finalizer() { return null; } } [HarmonyPatch(typeof(WeaponLoadout), "CanBeLoaded")] public class WeaponLoadout_CanBeLoaded { [HarmonyPrefix] public static bool Prefix(WeaponLoadout __instance, ref bool __result) { Item item = ((ItemExtension)__instance).Item; if (IsRunicBow(item)) { Character ownerCharacter = ((EffectSynchronizer)item).OwnerCharacter; if (Object.op_Implicit((Object)(object)ownerCharacter) && !ownerCharacter.IsLocalPlayer) { return true; } __result = CanBeLoaded(item); return false; } return true; } public static bool CanBeLoaded(Item item) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown Character ownerCharacter = ((EffectSynchronizer)item).OwnerCharacter; if (!Object.op_Implicit((Object)(object)ownerCharacter)) { Debug.Log((object)"Runic bow has no owner!"); return false; } float currentMana = ownerCharacter.Stats.CurrentMana; float finalManaConsumption = ownerCharacter.Stats.GetFinalManaConsumption((Tag[])null, 5f); if (currentMana - finalManaConsumption < 0f) { ManaRefusedAt = Time.time; if ((InAttackAttempt || Time.time - SkillAttemptAt <= 3f) && !ManaNotified) { ManaNotified = true; ownerCharacter.CharacterUI.ShowInfoNotificationLoc("Notification_Skill_NotEnoughtMana"); } return false; } Ammunition equippedAmmunition = ownerCharacter.Inventory.GetEquippedAmmunition(); if ((Object)(object)equippedAmmunition == (Object)null) { List<Item> ownedItems = ownerCharacter.Inventory.GetOwnedItems(-88001); Ammunition val = (Ammunition)((ownedItems == null || ownedItems.Count <= 0) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)(Ammunition)ownedItems[0])); ownerCharacter.Inventory.TakeItem((Item)(object)val, true); equippedAmmunition = ownerCharacter.Inventory.GetEquippedAmmunition(); } if ((Object)(object)equippedAmmunition == (Object)null || ((Item)equippedAmmunition).ItemID != -88001) { return false; } return true; } } [HarmonyPatch] public class WeaponLoadout_ReduceShotAmount { [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(WeaponLoadout), "ReduceShotAmount")] public static void ReversePatch(object instance, bool _destroyOnEmpty) { throw new NotImplementedException("WeaponLoadoutRP.ReduceShotAmount"); } [HarmonyPrefix] [HarmonyPatch(typeof(WeaponLoadout), "ReduceShotAmount")] [HarmonyPatch(typeof(WeaponLoadoutItem), "ReduceShotAmount")] [HarmonyBefore(new string[] { "com.SpicerXD.RaidMode" })] public static bool Prefix(WeaponLoadout __instance, bool _destroyOnEmpty) { //IL_0124: Unknown result type (might be due to invalid IL or missing references) Item item = ((ItemExtension)__instance).Item; if (IsRunicBow(item)) { Character ownerCharacter = ((EffectSynchronizer)item).OwnerCharacter; if (Object.op_Implicit((Object)(object)ownerCharacter) && ownerCharacter.IsLocalPlayer) { ownerCharacter.Stats.UseMana((Tag[])null, 5f); } RemainingShots.Invoke(__instance)--; if (RemainingShots.Invoke(__instance) < 0) { RemainingShots.Invoke(__instance) = 0; } if (RemainingShots.Invoke(__instance) == 0) { __instance.Unload(); } SetHasChanged((ItemExtension)(object)__instance); return false; } WeaponLoadoutItem val = (WeaponLoadoutItem)(object)((__instance is WeaponLoadoutItem) ? __instance : null); if (val != null) { if (!val.ReduceAmmunitionOnLoad) { Ammunition val2 = LoadedAmmunition.Invoke(val); if ((Object)(object)val2 != (Object)null && ((EffectSynchronizer)((ItemExtension)__instance).Item).OwnerCharacter.IsLocalPlayer) { Global.RPCManager.SendSkillUseItem(((Item)val2).UID, 1); if (PhotonNetwork.isNonMasterClientInRoom && ((Item)val2).RemainingAmount < 1) { int remainingAmount = ((Item)val2).RemainingAmount; ((Item)val2).RemainingAmount = remainingAmount - 1; } } if (_destroyOnEmpty) { LoadedAmmunition.Invoke(val) = null; } else if ((Object)(object)val2 == (Object)null || ((Item)val2).RemainingAmount == 0) { if (Object.op_Implicit((Object)(object)val2)) { ((Item)val2).SaveType = (SaveTypes)2; } List<Item> list = LastLoadedItems.Invoke(val); if (list.Count > 0) { list.RemoveAt(0); } if (list.Count > 0) { ref Ammunition reference = ref LoadedAmmunition.Invoke(val); Item obj = list[0]; reference = (Ammunition)(object)((obj is Ammunition) ? obj : null); } } } ReversePatch(__instance, _destroyOnEmpty); if (val.ReduceAmmunitionOnLoad) { ((ItemExtension)__instance).DataSynced(); } } return true; } } [HarmonyPatch(typeof(AttackSkill), "OwnerHasAllRequiredItems")] public class AttackSkill_OwnerHasAllRequiredItems { [HarmonyPrefix] public static bool Prefix(AttackSkill __instance, bool _TryingToActivate, ref bool __result) { if (!(__instance is RangeAttackSkill)) { return true; } if (Object.op_Implicit((Object)(object)((EffectSynchronizer)__instance).OwnerCharacter)) { Weapon currentWeapon = ((EffectSynchronizer)__instance).OwnerCharacter.CurrentWeapon; ProjectileWeapon val = (ProjectileWeapon)(object)((currentWeapon is ProjectileWeapon) ? currentWeapon : null); if (val != null && IsRunicBow((Item)(object)val)) { __result = WeaponLoadout_CanBeLoaded.CanBeLoaded((Item)(object)val); return false; } } return true; } } [HarmonyPatch(typeof(UseLoadoutAmunition), "TryTriggerConditions")] public class UseLoadoutAmmunition_TryTriggerConditions { [HarmonyPrefix] public static bool Prefix(UseLoadoutAmunition __instance, ref bool __result) { if (__instance.MainHand) { Weapon currentWeapon = ((Effect)__instance).OwnerCharacter.CurrentWeapon; ProjectileWeapon val = (ProjectileWeapon)(object)((currentWeapon is ProjectileWeapon) ? currentWeapon : null); if (val != null && IsRunicBow((Item)(object)val)) { __result = true; return false; } } return true; } } [HarmonyPatch(typeof(UseLoadoutAmunition), "ActivateLocally")] public class UseLoadoutAmmunition_ActivateLocally { [HarmonyPrefix] public static bool Prefix(UseLoadoutAmunition __instance, Character _affectedCharacter, object[] _infos) { if (__instance.MainHand) { Weapon currentWeapon = _affectedCharacter.CurrentWeapon; ProjectileWeapon val = (ProjectileWeapon)(object)((currentWeapon is ProjectileWeapon) ? currentWeapon : null); if (val != null && IsRunicBow((Item)(object)val)) { WeaponLoadout_ReduceShotAmount.Prefix(((Component)val).GetComponent<WeaponLoadout>(), __instance.DestroyOnEmpty); return false; } } return true; } } [HarmonyPatch(typeof(CharacterInventory), "PlayEquipSFX")] public class CharacterInventory_PlayEquipSFX { [HarmonyPrefix] public static bool Prefix(CharacterInventory __instance, Equipment _equipment) { return ((Item)_equipment).ItemID != -88001; } } [HarmonyPatch(typeof(CharacterInventory), "PlayUnequipSFX")] public class CharacterInventory_PlayUnequipSFX { [HarmonyPrefix] public static bool Prefix(CharacterInventory __instance, Equipment _equipment) { return ((Item)_equipment).ItemID != -88001; } } [HarmonyPatch(typeof(Item), "TryQuickSlotUse")] public class Item_TryQuickSlotUse { [HarmonyPrefix] public static void Prefix(Item __instance) { if (__instance is Skill) { SkillAttemptAt = Time.time; ManaNotified = false; } } } [HarmonyPatch(typeof(Equipment), "OnEquip")] public class Equipment_OnEquip { [HarmonyPostfix] public static void Postfix(Equipment __instance, Character _char) { if (Object.op_Implicit((Object)(object)__instance)) { Ammunition val = (Ammunition)(object)((__instance is Ammunition) ? __instance : null); bool num = (Object)(object)val != (Object)null && ((Item)val).ItemID != -88001; bool flag = ((Item)__instance).ItemID == -88000; if ((num || flag) && Object.op_Implicit((Object)(object)_char) && _char.IsLocalPlayer && !((Object)(object)_char.Inventory == (Object)null) && _char.Inventory.OwnsItem(-88000) && Object.op_Implicit((Object)(object)RunicBowPlugin.Instance)) { ArrowRestoreAt = Time.time; ((MonoBehaviour)RunicBowPlugin.Instance).StartCoroutine(RestoreRunicArrowNextFrame(_char)); } } } } [HarmonyPatch(typeof(CharacterEquipment), "UnequipItem", new Type[] { typeof(Equipment), typeof(bool), typeof(ItemContainer) })] public class CharacterEquipment_UnequipItem { [HarmonyPostfix] public static void Postfix(CharacterEquipment __instance, Equipment _itemToUnequip) { if (Object.op_Implicit((Object)(object)_itemToUnequip) && ((Item)_itemToUnequip).ItemID == -88001) { Character ownerCharacter = ((EffectSynchronizer)_itemToUnequip).OwnerCharacter; if (Object.op_Implicit((Object)(object)ownerCharacter) && ownerCharacter.IsLocalPlayer && !((Object)(object)ownerCharacter.Inventory == (Object)null) && ownerCharacter.Inventory.OwnsItem(-88000) && Object.op_Implicit((Object)(object)RunicBowPlugin.Instance)) { ArrowRestoreAt = Time.time; ((MonoBehaviour)RunicBowPlugin.Instance).StartCoroutine(ReEquipArrowNextFrame(ownerCharacter, _itemToUnequip)); } } } } [HarmonyPatch(typeof(SummonedEquipment), "FreeSummon")] public class SummonedEquipment_FreeSummon { private static readonly HashSet<string> Held = new HashSet<string>(); [HarmonyPrefix] public static bool Prefix(SummonedEquipment __instance, bool _expired, out bool __state) { __state = false; if (!_expired || !Object.op_Implicit((Object)(object)__instance)) { return true; } Item item = ((ItemExtension)__instance).Item; if (!Object.op_Implicit((Object)(object)item) || item.ItemID != -88000) { return true; } Character ownerCharacter = ((EffectSynchronizer)item).OwnerCharacter; if (!Object.op_Implicit((Object)(object)ownerCharacter) || (!CharChargingAttack.Invoke(ownerCharacter) && !ownerCharacter.RangeSkillAim)) { if (Held.Remove(item.UID)) { RunicBowPlugin.Log.LogMessage((object)"Runic Bow expired after the draw ended."); } return true; } if (Held.Add(item.UID)) { RunicBowPlugin.Log.LogMessage((object)"Runic Bow expired mid-draw - held until the draw ends."); } SummonUnsummonWanted.Invoke(__instance) = true; __state = true; return false; } [HarmonyPostfix] public static void Postfix(SummonedEquipment __instance, bool _expired, bool __state) { if (__state || !Object.op_Implicit((Object)(object)__instance)) { return; } Item item = ((ItemExtension)__instance).Item; if (!Object.op_Implicit((Object)(object)item) || item.ItemID != -88000) { return; } Character ownerCharacter = ((EffectSynchronizer)item).OwnerCharacter; if (Object.op_Implicit((Object)(object)ownerCharacter) && !((Object)(object)ownerCharacter.StatusEffectMngr == (Object)null)) { StatusEffect statusEffectOfName = ownerCharacter.StatusEffectMngr.GetStatusEffectOfName("RunicBow"); if (Object.op_Implicit((Object)(object)statusEffectOfName)) { ownerCharacter.StatusEffectMngr.CleanseStatusEffect(statusEffectOfName); } } } } [HarmonyPatch(typeof(Item), "ChangeOwner")] public class Item_ChangeOwner { [HarmonyPrefix] public static void Prefix(Item __instance, Character _newOwner, out Character __state) { __state = null; if (IsRunicBow(__instance) && (Object)(object)((EffectSynchronizer)__instance).OwnerCharacter != (Object)(object)_newOwner) { __state = ((EffectSynchronizer)__instance).OwnerCharacter; } } [HarmonyPostfix] public static void Postfix(Character __state) { if ((Object)(object)__state != (Object)null) { CleanupArrowsIfBowGone(__state); } } } [HarmonyPatch(typeof(Item), "AboutToBeDestroyed")] public class Item_AboutToBeDestroyed { [HarmonyPatch(typeof(StatusEffectManager), "AddStatusEffect", new Type[] { typeof(StatusEffect), typeof(Character), typeof(string[]) })] public class StatusEffectManager_AddStatusEffect_BanishedBossGate { private static readonly FieldRef<StatusEffectManager, Character> ManagerCharacter = AccessTools.FieldRefAccess<StatusEffectManager, Character>("m_character"); [HarmonyPrefix] public static bool Prefix(StatusEffectManager __instance, StatusEffect _statusEffect, ref StatusEffect __result) { if ((Object)(object)_statusEffect == (Object)null || _statusEffect.IdentifierName != "Banished") { return true; } Character val = ManagerCharacter.Invoke(__instance); if (!Object.op_Implicit((Object)(object)val) || !val.HasEventOnDeath) { return true; } __result = null; return false; } } [HarmonyPatch(typeof(StatusEffectManager), "AddStatusEffect", new Type[] { typeof(StatusEffect), typeof(Character), typeof(string[]) })] public class StatusEffectManager_AddStatusEffect_BanishedRestore { private static readonly FieldRef<StatusEffectManager, Character> ManagerCharacter = AccessTools.FieldRefAccess<StatusEffectManager, Character>("m_character"); [HarmonyPostfix] public static void Postfix(StatusEffectManager __instance, StatusEffect __result) { if (!((Object)(object)__result == (Object)null) && !(__result.IdentifierName != "Banished") && !((Component)__result).gameObject.activeInHierarchy) { Character val = ManagerCharacter.Invoke(__instance); if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val.StatusEffectMngr == (Object)null) && Object.op_Implicit((Object)(object)RunicBowPlugin.Instance)) { ((MonoBehaviour)RunicBowPlugin.Instance).StartCoroutine(CleanseBanishedNextFrame(val)); } } } } [HarmonyPrefix] public static void Prefix(Item __instance) { if (IsRunicBow(__instance)) { Character ownerCharacter = ((EffectSynchronizer)__instance).OwnerCharacter; if (Object.op_Implicit((Object)(object)ownerCharacter) && Object.op_Implicit((Object)(object)RunicBowPlugin.Instance)) { ((MonoBehaviour)RunicBowPlugin.Instance).StartCoroutine(CleanupNextFrame(ownerCharacter)); } } } private static IEnumerator CleanseBanishedNextFrame(Character affected) { yield return null; if (Object.op_Implicit((Object)(object)affected) && !((Object)(object)affected.StatusEffectMngr == (Object)null)) { StatusEffect statusEffectOfName = affected.StatusEffectMngr.GetStatusEffectOfName("Banished"); if (Object.op_Implicit((Object)(object)statusEffectOfName)) { affected.StatusEffectMngr.CleanseStatusEffect(statusEffectOfName); } } } } private const string RunicBowTagString = "RunicBow"; public const int RunicArrowID = -88001; public const int RunicBowID = -88000; public const float RunicBowCost = 5f; public static Tag RunicBowTag; private static float ManaRefusedAt = -99f; private const float ManaRefusalWindow = 0.5f; private static bool InAttackAttempt; private static float SkillAttemptAt = -99f; private const float SkillAttemptWindow = 3f; private static bool ManaNotified; private const float ArrowUnequipSettleWindow = 0.5f; private static float ArrowRestoreAt = -999f; private const float ArrowRestoreWindow = 0.75f; private const float LoadWaitTimeout = 15f; private const float LoadSettleGrace = 0.25f; private const string RunicBowStatusIdentifier = "RunicBow"; private const string BanishedStatusIdentifier = "Banished"; private static readonly FieldRef<Character, bool> CharChargingAttack = AccessTools.FieldRefAccess<Character, bool>("m_currentlyChargingAttack"); private static readonly FieldRef<Character, bool> CharBowDrawn = AccessTools.FieldRefAccess<Character, bool>("m_bowDrawn"); private static readonly FieldRef<SummonedEquipment, bool> SummonUnsummonWanted = AccessTools.FieldRefAccess<SummonedEquipment, bool>("m_unsummonWanted"); private static readonly FieldRef<CharacterEquipment, Character> EquipmentOwner = AccessTools.FieldRefAccess<CharacterEquipment, Character>("m_character"); private static readonly FieldRef<ProjectileItem, int> ProjectileItemID = AccessTools.FieldRefAccess<ProjectileItem, int>("m_itemID"); private static readonly FieldRef<ProjectileItem, Item> ProjectileItemPrefab = AccessTools.FieldRefAccess<ProjectileItem, Item>("m_item"); private static readonly FieldRef<WeaponLoadout, int> RemainingShots = AccessTools.FieldRefAccess<WeaponLoadout, int>("m_remainingShots"); private static readonly FieldRef<WeaponLoadoutItem, Ammunition> LoadedAmmunition = AccessTools.FieldRefAccess<WeaponLoadoutItem, Ammunition>("m_loadedAmmunition"); private static readonly FieldRef<WeaponLoadoutItem, List<Item>> LastLoadedItems = AccessTools.FieldRefAccess<WeaponLoadoutItem, List<Item>>("m_lastLoadedItems"); private static readonly Action<ItemExtension> SetHasChanged = AccessTools.MethodDelegate<Action<ItemExtension>>(AccessTools.Method(typeof(ItemExtension), "SetHasChanged", (Type[])null, (Type[])null), (object)null, true); public static bool IsRunicBow(Item item) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)item)) { return item.HasTag(RunicBowTag); } return false; } private static void CleanupArrowsIfBowGone(Character owner) { if (!PhotonNetwork.isMasterClient || !Object.op_Implicit((Object)(object)owner) || (Object)(object)owner.Inventory == (Object)null || owner.Inventory.OwnsItem(-88000)) { return; } List<string> list = new List<string>(); Ammunition equippedAmmunition = owner.Inventory.GetEquippedAmmunition(); if (Object.op_Implicit((Object)(object)equippedAmmunition) && ((Item)equippedAmmunition).ItemID == -88001) { list.Add(((Item)equippedAmmunition).UID); } List<Item> ownedItems = owner.Inventory.GetOwnedItems(-88001); if (ownedItems != null) { for (int i = 0; i < ownedItems.Count; i++) { if ((Object)(object)ownedItems[i] != (Object)null && !list.Contains(ownedItems[i].UID)) { list.Add(ownedItems[i].UID); } } } for (int j = 0; j < list.Count; j++) { ItemManager.Instance.DestroyItem(list[j]); } } private static IEnumerator CleanupNextFrame(Character owner) { yield return null; CleanupArrowsIfBowGone(owner); } private static bool AnyRunicBowExists() { ItemManager instance = ItemManager.Instance; if (!Object.op_Implicit((Object)(object)instance) || instance.WorldItems == null) { return true; } for (int i = 0; i < instance.WorldItems.Count; i++) { Item val = instance.WorldItems.Values[i]; if (Object.op_Implicit((Object)(object)val) && val.ItemID == -88000) { return true; } } return false; } private static Character LocalPlayer() { if (!Object.op_Implicit((Object)(object)CharacterManager.Instance)) { return null; } foreach (Character value in CharacterManager.Instance.Characters.Values) { if (Object.op_Implicit((Object)(object)value) && value.IsLocalPlayer) { return value; } } return null; } internal static void OnGameplayResumed() { if (Object.op_Implicit((Object)(object)RunicBowPlugin.Instance)) { ((MonoBehaviour)RunicBowPlugin.Instance).StartCoroutine(ReconcileBowStatusAfterLoad()); } } private static IEnumerator ReconcileBowStatusAfterLoad() { while (Object.op_Implicit((Object)(object)NetworkLevelLoader.Instance) && NetworkLevelLoader.Instance.IsGameplayPaused) { yield return null; } float deadline = Time.time + 15f; while (Object.op_Implicit((Object)(object)ItemManager.Instance) && (!ItemManager.Instance.SceneLoaded || !ItemManager.Instance.FirstSyncCompleted)) { if (Time.time > deadline) { yield break; } yield return null; } yield return (object)new WaitForSeconds(0.25f); Character val = LocalPlayer(); if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val.StatusEffectMngr == (Object)null) && !AnyRunicBowExists()) { StatusEffect statusEffectOfName = val.StatusEffectMngr.GetStatusEffectOfName("RunicBow"); if (Object.op_Implicit((Object)(object)statusEffectOfName)) { val.StatusEffectMngr.CleanseStatusEffect(statusEffectOfName); RunicBowPlugin.Log.LogMessage((object)"Cleared an orphaned Runic Bow status - the bow did not survive the load."); } } } public static void BeforePacksLoaded() { //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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown RunicBowTag = CustomTags.CreateTag("RunicBow"); Type typeByName = At.GetTypeByName("RaidMode.CharacterEquipment_Update"); if (typeByName != null) { MethodInfo method = typeByName.GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public); RunicBowPlugin.harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(RunicBowManager), "FixRaidModePatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } public static bool FixRaidModePatch(CharacterEquipment __0) { return !IsRunicBow((Item)(object)EquipmentOwner.Invoke(__0).CurrentWeapon); } public static void OnPacksLoaded() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) Item itemPrefab = ResourcesPrefabManager.Instance.GetItemPrefab(-88001); Ammunition val = (Ammunition)(object)((itemPrefab is Ammunition) ? itemPrefab : null); if (!Object.op_Implicit((Object)(object)val)) { Debug.LogError((object)("[Runic Bow] Could not find the Runic Arrow prefab (ID " + -88001 + "). Check that SideLoader/Items/-88001_RunicArrow is present and its New_ItemID matches.")); return; } ItemVisualsLink orAddVisualLink = CustomItemVisuals.GetOrAddVisualLink((Item)(object)val); orAddVisualLink.ItemSpecialVisuals = new GameObject("RunicQuiverDummy").transform; Object.DontDestroyOnLoad((Object)(object)((Component)orAddVisualLink.ItemSpecialVisuals).gameObject); GameObject gameObject = ((Component)val.ProjectileFXPrefab).gameObject; gameObject.SetActive(false); val.ProjectileFXPrefab = Object.Instantiate<GameObject>(gameObject).transform; gameObject.SetActive(true); Item itemPrefab2 = ResourcesPrefabManager.Instance.GetItemPrefab(-88000); StatusEffect statusEffectPrefab = ResourcesPrefabManager.Instance.GetStatusEffectPrefab("RunicBow"); if (Object.op_Implicit((Object)(object)itemPrefab2) && Object.op_Implicit((Object)(object)statusEffectPrefab)) { SummonedEquipment component = ((Component)itemPrefab2).GetComponent<SummonedEquipment>(); if (Object.op_Implicit((Object)(object)component)) { component.StatusIcon = statusEffectPrefab.StatusIcon; } else { Debug.LogWarning((object)"[Runic Bow] No SummonedEquipment on the bow prefab - check that SideLoader/Items/-88000_RunicBow has the SL_SummonedEquipment extension."); } } Object.DontDestroyOnLoad((Object)(object)((Component)val.ProjectileFXPrefab).gameObject); ProjectileItem component2 = ((Component)val.ProjectileFXPrefab).GetComponent<ProjectileItem>(); component2.CollisionBehavior = (CollisionBehaviorTypes)2; component2.EphemeralProjectile = true; ProjectileItemID.Invoke(component2) = -88001; ProjectileItemPrefab.Invoke(component2) = ResourcesPrefabManager.Instance.GetItemPrefab(-88001); RaycastProjectile component3 = ((Component)component2).GetComponent<RaycastProjectile>(); ((Projectile)component3).ProjectileVisualsToDisable = ((Component)component2).gameObject; ((Projectile)component3).ImpactSoundMaterial = (EquipmentSoundMaterials)0; ((MonoBehaviour)RunicBowPlugin.Instance).StartCoroutine(LateFix()); } private static IEnumerator LateFix() { yield return (object)new WaitForSeconds(1f); foreach (int item in new List<int> { 8200100, 8200101, 8200102, 8200103, 2502001, 8200310 }) { Item itemPrefab = ResourcesPrefabManager.Instance.GetItemPrefab(item); AttackSkill val = (AttackSkill)(object)((itemPrefab is AttackSkill) ? itemPrefab : null); if (val != null && !val.RequiredWeaponTypes.Contains((WeaponType)200)) { val.RequiredWeaponTypes.Add((WeaponType)200); } } } private static IEnumerator RestoreRunicArrowNextFrame(Character owner) { yield return null; if (!Object.op_Implicit((Object)(object)owner) || (Object)(object)owner.Inventory == (Object)null || !owner.Inventory.OwnsItem(-88000)) { yield break; } Ammunition equippedAmmunition = owner.Inventory.GetEquippedAmmunition(); if (Object.op_Implicit((Object)(object)equippedAmmunition) && ((Item)equippedAmmunition).ItemID == -88001) { yield break; } Equipment arrow = null; float waited = 0f; while (waited < 0.5f) { if (!Object.op_Implicit((Object)(object)owner) || (Object)(object)owner.Inventory == (Object)null || !owner.Inventory.OwnsItem(-88000)) { yield break; } List<Item> ownedItems = owner.Inventory.GetOwnedItems(-88001); arrow = (Equipment)((ownedItems != null && ownedItems.Count > 0) ? /*isinst with value type is only supported in some contexts*/: null); if (Object.op_Implicit((Object)(object)arrow)) { break; } waited += Time.deltaTime; yield return null; } if (Object.op_Implicit((Object)(object)arrow)) { owner.Inventory.Equipment.EquipItem(arrow, false); yield break; } equippedAmmunition = owner.Inventory.GetEquippedAmmunition(); if (Object.op_Implicit((Object)(object)equippedAmmunition)) { owner.Inventory.Equipment.UnequipItem((Equipment)(object)equippedAmmunition, false, owner.Inventory.Pouch); } } private static IEnumerator ReEquipArrowNextFrame(Character owner, Equipment arrow) { yield return null; if (!Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)arrow) || (Object)(object)owner.Inventory == (Object)null || !owner.Inventory.OwnsItem(-88000)) { yield break; } float waited = 0f; while (waited < 0.5f) { if (!Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)arrow) || (Object)(object)owner.Inventory == (Object)null || !owner.Inventory.OwnsItem(-88000)) { yield break; } Ammunition equippedAmmunition = owner.Inventory.GetEquippedAmmunition(); if (!Object.op_Implicit((Object)(object)equippedAmmunition) || ((Item)equippedAmmunition).ItemID != -88001) { break; } waited += Time.deltaTime; yield return null; } Ammunition equippedAmmunition2 = owner.Inventory.GetEquippedAmmunition(); if (!Object.op_Implicit((Object)(object)equippedAmmunition2) || ((Item)equippedAmmunition2).ItemID != -88001) { owner.Inventory.Equipment.EquipItem(arrow, false); } } } [BepInPlugin("com.wrango.runesredone.bow", "Runes Redone - Bow", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency("com.wrango.customeffects", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class RunicBowPlugin : BaseUnityPlugin { public const string GUID = "com.wrango.runesredone.bow"; public const string NAME = "Runes Redone - Bow"; public const string VERSION = "1.0.0"; public static RunicBowPlugin Instance; public static Harmony harmony; internal static ManualLogSource Log; internal void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; harmony = new Harmony("com.wrango.runesredone.bow"); SL.BeforePacksLoaded += RunicBowManager.BeforePacksLoaded; SL.OnPacksLoaded += RunicBowManager.OnPacksLoaded; SL.OnGameplayResumedAfterLoading += RunicBowManager.OnGameplayResumed; try { Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(RunicBowPlugin).Assembly); foreach (Type type in typesFromAssembly) { if (type.Namespace == "RunicBow") { harmony.CreateClassProcessor(type).Patch(); } } } catch (Exception ex) { Log.LogError((object)("Harmony patching failed - the bow will not work correctly: " + ex)); } Log.LogMessage((object)"Runes Redone - Bow 1.0.0 loaded."); } } } namespace RunesRedone { internal static class Info { internal const string VERSION = "1.0.0"; internal const string GUID = "com.wrango.runesredone"; internal const string NAME = "Runes Redone"; } } namespace RunicBarrier { [HarmonyPatch(typeof(Item), "Start")] internal static class Item_Start_NameSync { private static readonly FieldRef<Item, string> ItemRawName = AccessTools.FieldRefAccess<Item, string>("m_name"); private static int _logged; private const int LOG_LIMIT = 5; [HarmonyPriority(0)] private static void Postfix(Item __instance) { try { if (!Object.op_Implicit((Object)(object)__instance) || string.IsNullOrEmpty(__instance.UID)) { return; } string text = ItemRawName.Invoke(__instance); if (string.IsNullOrEmpty(text)) { return; } string text2 = ((__instance.UID.Length > 10) ? __instance.UID.Substring(0, 10) : __instance.UID); string text3 = __instance.ItemID + "_" + text.Replace(" ", string.Empty) + "_" + text2; string text4 = __instance.ToShortString(); if (!(((Object)__instance).name != text3) && !(text3 == text4)) { ((Object)__instance).name = text4; if (_logged < 5) { _logged++; RunicBarrierPlugin.Log.LogMessage((object)("[NameSync] (" + _logged + "/" + 5 + ") renamed '" + text3 + "' -> '" + text4 + "' to match the other clients")); } } } catch (Exception ex) { RunicBarrierPlugin.Log.LogError((object)("[NameSync] rename check threw: " + ex)); } } } internal static class LoadOrder { private const string PACK = "Wrango-Runes_Redone"; private const int MARKER_ITEM = -88003; private static readonly MethodInfo ApplyActual = AccessTools.Method(typeof(ContentTemplate), "ApplyActualTemplate", (Type[])null, (Type[])null); private static readonly FieldInfo FolderPacks = AccessTools.Field(typeof(SL), "folderPacks"); private static bool _installed; internal static void Install() { if (!_installed) { _installed = true; if (SL.PacksLoaded) { Run(); } else { SL.OnPacksLoaded += Run; } } } private static void Run() { try { Dictionary<string, SLPack> dictionary = ((FolderPacks != null) ? (FolderPacks.GetValue(null) as Dictionary<string, SLPack>) : null); if (dictionary == null || ApplyActual == null) { RunicBarrierPlugin.Log.LogWarning((object)"[LoadOrder] SideLoader's packs or apply method not found - RR's overrides are left to SideLoader's order."); return; } SLPack val = FindRR(dictionary); if (val == null) { RunicBarrierPlugin.Log.LogWarning((object)"[LoadOrder] RR's SideLoader pack not found - nothing re-applied."); return; } Dictionary<int, string> dictionary2 = new Dictionary<int, string>(); Dictionary<string, string> dictionary3 = new Dictionary<string, string>(); foreach (KeyValuePair<string, SLPack> item in dictionary) { if (item.Value == val) { continue; } foreach (SL_Item value3 in item.Value.GetContentOfType<SL_Item>().Values) { int key = AppliedID(value3); if (!dictionary2.ContainsKey(key)) { dictionary2[key] = item.Key; } } foreach (SL_StatusEffect value4 in item.Value.GetContentOfType<SL_StatusEffect>().Values) { string text = AppliedIdentifier(value4); if (!string.IsNullOrEmpty(text) && !dictionary3.ContainsKey(text)) { dictionary3[text] = item.Key; } } } int num = 0; string text2 = ""; foreach (SL_Item value5 in val.GetContentOfType<SL_Item>().Values) { int key2 = AppliedID(value5); if (dictionary2.TryGetValue(key2, out var value)) { if (!InPlace(value5)) { text2 = text2 + "\n WARNING item " + key2 + " '" + value5.Name + "' is a new item of RR's, and " + value + " uses the same ID - not re-applied"; } else { ApplyActual.Invoke(value5, null); num++; text2 = text2 + "\n item " + key2 + " '" + value5.Name + "' (also in " + value + ")"; } } } foreach (SL_StatusEffect value6 in val.GetContentOfType<SL_StatusEffect>().Values) { string text3 = AppliedIdentifier(value6); if (!string.IsNullOrEmpty(text3) && dictionary3.TryGetValue(text3, out var value2)) { if (!InPlace(value6)) { text2 = text2 + "\n WARNING status '" + text3 + "' is a new status of RR's, and " + value2 + " uses the same identifier - not re-applied"; } else { ApplyActual.Invoke(value6, null); num++; text2 = text2 + "\n status '" + text3 + "' (also in " + value2 + ")"; } } } if (text2.Length == 0) { RunicBarrierPlugin.Log.LogMessage((object)"[LoadOrder] no other pack overrides RR's items or statuses - nothing to re-apply."); } else { RunicBarrierPlugin.Log.LogMessage((object)("[LoadOrder] RR's overrides re-applied after every pack (" + num + "):" + text2)); } } catch (Exception ex) { RunicBarrierPlugin.Log.LogError((object)("[LoadOrder] threw: " + ex)); } } private static SLPack FindRR(Dictionary<string, SLPack> packs) { if (packs.TryGetValue("Wrango-Runes_Redone", out var value) && value != null) { return value; } foreach (SLPack value2 in packs.Values) { foreach (SL_Item value3 in value2.GetContentOfType<SL_Item>().Values) { if (value3.New_ItemID == -88003) { return value2; } } } return null; } private static int AppliedID(SL_Item t) { if (t.New_ItemID == -1) { return t.Target_ItemID; } return t.New_ItemID; } private static bool InPlace(SL_Item t) { if (t.New_ItemID != -1) { return t.New_ItemID == t.Target_ItemID; } return true; } private static string AppliedIdentifier(SL_StatusEffect s) { if (!string.IsNullOrEmpty(s.StatusIdentifier)) { return s.StatusIdentifier; } return s.TargetStatusIdentifier; } private static bool InPlace(SL_StatusEffect s) { if (!string.IsNullOrEmpty(s.StatusIdentifier)) { return s.StatusIdentifier == s.TargetStatusIdentifier; } return true; } } internal static class OverchargeBlast { private const int DEZ_ITEM_ID = 8100210; private const string BRANCH = "RunicOvercharge"; private static readonly float WAVE_SCALE = 1f; private static readonly float WAVE_SPEED = 0.3f; private static readonly float WAVE_MAX_PARTICLE_SIZE = 100f; private static readonly float FX_MARGIN = 0.1f; private const string CREST_EMITTER = "NewFire"; private static readonly float CREST_TICK = 0.05f; private static readonly float CREST_MARGIN = 0.1f; private const int MAX_ATTEMPTS = 15; private static bool _done; private static int _attempts; private static bool _gaveUp; private static bool _crestReady; private static AnimationCurve _crestCurve; private static float _crestPeak = 1f; private static float _crestDelay; private static float _crestLife = 1f; private static float _crestSim = 1f; internal static float CrestRadius(float radius, float age) { if (!_crestReady) { return radius; } float num = (age * _crestSim - _crestDelay) / _crestLife; if (num >= 1f) { return radius; } if (num < 0f) { num = 0f; } return radius * Mathf.Clamp01(_crestCurve.Evaluate(num) / _crestPeak); } private static float CrestTravel() { if (!_crestReady) { return 0f; } return (_crestDelay + _crestLife) / _crestSim; } private static string ReadCrest(Blast blast) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Invalid comparison between Unknown and I4 //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) ParticleSystem[] componentsInChildren = ((Component)blast).GetComponentsInChildren<ParticleSystem>(true); ParticleSystem val = null; for (int i = 0; i < componentsInChildren.Length; i++) { if (((Object)componentsInChildren[i]).name == "NewFire") { val = componentsInChildren[i]; break; } } if (!Object.op_Implicit((Object)(object)val)) { return "no 'NewFire' emitter - crest OFF, hits land all at once"; } SizeOverLifetimeModule sizeOverLifetime = val.sizeOverLifetime; MinMaxCurve size = ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size; if (!((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled || (int)((MinMaxCurve)(ref size)).mode != 1 || ((MinMaxCurve)(ref size)).curve == null) { return "'NewFire' size-over-lifetime is " + (((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled ? ((object)((MinMaxCurve)(ref size)).mode/*cast due to .constrained prefix*/).ToString() : "off") + ", not a curve - crest OFF, hits land all at once"; } Keyframe[] keys = ((MinMaxCurve)(ref size)).curve.keys; float num = 0f; string text = ""; for (int j = 0; j < keys.Length; j++) { if (((Keyframe)(ref keys[j])).value > num) { num = ((Keyframe)(ref keys[j])).value; } text = text + ((j > 0) ? " " : "") + "(" + ((Keyframe)(ref keys[j])).time.ToString("F2") + "," + ((Keyframe)(ref keys[j])).value.ToString("F2") + ")"; } MainModule main = val.main; if (!(num <= 0f)) { MinMaxCurve val2 = ((MainModule)(ref main)).startLifetime; if (!(((MinMaxCurve)(ref val2)).constantMax <= 0f) && !(((MainModule)(ref main)).simulationSpeed <= 0f)) { _crestCurve = new AnimationCurve(keys); _crestPeak = num; val2 = ((MainModule)(ref main)).startDelay; _crestDelay = ((MinMaxCurve)(ref val2)).constantMax; val2 = ((MainModule)(ref main)).startLifetime; _crestLife = ((MinMaxCurve)(ref val2)).constantMax; _crestSim = ((MainModule)(ref main)).simulationSpeed; _crestReady = true; return "follows 'NewFire' curve " + text + ", delay " + _crestDelay.ToString("F2") + ", life " + _crestLife.ToString("F2") + ", speed x" + _crestSim.ToString("0.##") + " -> reaches the edge " + CrestTravel().ToString("F2") + " s after the cast"; } } return "'NewFire' curve peak, lifetime or speed is zero - crest OFF"; } internal static void TryOnce() { if (!_done && !_gaveUp) { _attempts++; try { _done = Apply(); } catch (Exception ex) { RunicBarrierPlugin.Log.LogError((object)("[RunicBarrier] overcharge wave threw: " + ex)); _gaveUp = true; return; } if (!_done && _attempts >= 15) { _gaveUp = true; RunicBarrierPlugin.Log.LogWarning((object)("[RunicBarrier] overcharge wave gave up after " + _attempts + " attempts - no 'RunicOvercharge' blast found on item " + 8100210 + ". The wave plays at native speed.")); } } } private static bool Apply() { if (ResourcesPrefabManager.Instance == null) { return false; } Item itemPrefab = ResourcesPrefabManager.Instance.GetItemPrefab(8100210); if (!Object.op_Implicit((Object)(object)itemPrefab)) { return false; } Transform val = ((Component)itemPrefab).transform.Find("RunicOvercharge"); if (!Object.op_Implicit((Object)(object)val)) { return false; } ShootBlast[] componentsInChildren = ((Component)val).GetComponentsInChildren<ShootBlast>(true); if (componentsInChildren.Length == 0) { return false; } string text = componentsInChildren.Length.ToString(); float wAVE_SPEED = WAVE_SPEED; string text2 = "[RunicBarrier] overcharge wave, " + text + " blast(s) under 'RunicOvercharge', speed x" + wAVE_SPEED.ToString("0.##"); for (int i = 0; i < componentsInChildren.Length; i++) { Blast baseBlast = componentsInChildren[i].BaseBlast; text2 = text2 + "\n [" + i + "] "; text2 += (Object.op_Implicit((Object)(object)baseBlast) ? Slow(baseBlast) : "no BaseBlast - left alone"); } for (int j = 0; j < componentsInChildren.Length; j++) { if (_crestReady) { break; } if (Object.op_Implicit((Object)(object)componentsInChildren[j].BaseBlast)) { text2 = text2 + "\n crest: " + ReadCrest(componentsInChildren[j].BaseBlast); } } if (_crestReady) { for (int k = 0; k < componentsInChildren.Length; k++) { text2 = text2 + "\n [" + k + "] " + ArmCrest(componentsInChildren[k]); } } RunicBarrierPlugin.Log.LogMessage((object)text2); return true; } private static string ArmCrest(ShootBlast shooter) { Blast baseBlast = shooter.BaseBlast; if (!Object.op_Implicit((Object)(object)baseBlast)) { return "no BaseBlast - crest not armed"; } float blastLifespan = shooter.BlastLifespan; float refreshTime = baseBlast.RefreshTime; bool ignoreStop = shooter.IgnoreStop; shooter.BlastLifespan = CrestTravel() + CREST_MARGIN; baseBlast.RefreshTime = CREST_TICK; shooter.IgnoreStop = true; if (!Object.op_Implicit((Object)(object)((Component)baseBlast).GetComponent<OverchargeCrest>())) { ((Component)baseBlast).gameObject.AddComponent<OverchargeCrest>(); } return "crest armed: lifespan " + blastLifespan.ToString("F2") + " -> " + shooter.BlastLifespan.ToString("F2") + ", tick " + refreshTime.ToString("F2") + " -> " + baseBlast.RefreshTime.ToString("F2") + ", IgnoreStop " + ignoreStop + " -> " + shooter.IgnoreStop + ", radius " + baseBlast.Radius.ToString("F1"); } private static float LastEmission(ParticleSystem ps, out string by) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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) EmissionModule emission = ps.emission; if (!((EmissionModule)(ref emission)).enabled) { by = "emission off"; return 0f; } if (((EmissionModule)(ref emission)).rateOverTimeMultiplier > 0f || ((EmissionModule)(ref emission)).rateOverDistanceMultiplier > 0f) { by = "rate, whole cycle"; MainModule main = ps.main; return ((MainModule)(ref main)).duration; } int burstCount = ((EmissionModule)(ref emission)).burstCount; if (burstCount <= 0) { by = "no rate, no bursts"; return 0f; } Burst[] array = (Burst[])(object)new Burst[burstCount]; ((EmissionModule)(ref emission)).GetBursts(array); float num = 0f; for (int i = 0; i < burstCount; i++) { float num2 = ((Burst)(ref array[i])).time; if (((Burst)(ref array[i])).cycleCount > 1) { num2 += (float)(((Burst)(ref array[i])).cycleCount - 1) * ((Burst)(ref array[i])).repeatInterval; } if (num2 > num) { num = num2; } } by = burstCount + " burst(s)"; return num; } private static string Slow(Blast blast) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) if (WAVE_SPEED <= 0f) { return "WAVE_SPEED must be above zero - left alone"; } string text = "'" + ((Object)blast).name + "'"; float num = 0f; ParticleSystem[] componentsInChildren = ((Component)blast).GetComponentsInChildren<ParticleSystem>(true); for (int i = 0; i < componentsInChildren.Length; i++) { MainModule main = componentsInChildren[i].main; float simulationSpeed = ((MainModule)(ref main)).simulationSpeed; ((MainModule)(ref main)).simulationSpeed = WAVE_SPEED; float num2 = (((MainModule)(ref main)).startSize3D ? ((MainModule)(ref main)).startSizeXMultiplier : ((MainModule)(ref main)).startSizeMultiplier); if (((MainModule)(ref main)).startSize3D) { ((MainModule)(ref main)).startSizeXMultiplier = ((MainModule)(ref main)).startSizeXMultiplier * WAVE_SCALE; ((MainModule)(ref main)).startSizeYMultiplier = ((MainModule)(ref main)).startSizeYMultiplier * WAVE_SCALE; ((MainModule)(ref main)).startSizeZMultiplier = ((MainModule)(ref main)).startSizeZMultiplier * WAVE_SCALE; } else { ((MainModule)(ref main)).startSizeMultiplier = ((MainModule)(ref main)).startSizeMultiplier * WAVE_SCALE; } float num3 = (((MainModule)(ref main)).startSize3D ? ((MainModule)(ref main)).startSizeXMultiplier : ((MainModule)(ref main)).startSizeMultiplier); string text2 = ", no renderer"; ParticleSystemRenderer component = ((Component)componentsInChildren[i]).GetComponent<ParticleSystemRenderer>(); if (Object.op_Implicit((Object)(object)component)) { float maxParticleSize = component.maxParticleSize; component.maxParticleSize = WAVE_MAX_PARTICLE_SIZE; text2 = ", screen cap " + maxParticleSize.ToString("F2") + " -> " + component.maxParticleSize.ToString("F2"); } string by; float num4 = LastEmission(componentsInChildren[i], out by); MinMaxCurve val = ((MainModule)(ref main)).startDelay; float num5 = ((MinMaxCurve)(ref val)).constantMax + num4; val = ((MainModule)(ref main)).startLifetime; float num6 = num5 + ((MinMaxCurve)(ref val)).constantMax; if (num6 > num) { num = num6; } string[] obj = new string[24] { text, "\n ", ((Object)componentsInChildren[i]).name, " speed ", simulationSpeed.ToString("F2"), " -> ", ((MainModule)(ref main)).simulationSpeed.ToString("F2"), ", size ", num2.ToString("F2"), " -> ", num3.ToString("F2"), ((MainModule)(ref main)).startSize3D ? " (3D)" : "", text2, ", life=", null, null, null, null, null, null, null, null, null, null }; val = ((MainModule)(ref main)).startLifetime; obj[14] = ((MinMaxCurve)(ref val)).constantMax.ToString("F2"); obj[15] = ", dur="; obj[16] = ((MainModule)(ref main)).duration.ToString("F2"); obj[17] = ", last emit "; obj[18] = num4.ToString("F2"); obj[19] = " ("; obj[20] = by; obj[21] = "), gone by "; obj[22] = (num6 / WAVE_SPEED).ToString("F2"); obj[23] = " s"; text = string.Concat(obj); } Transform val2 = ((Component)blast).transform.Find("ExplosionFX"); ParticleSystem val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<ParticleSystem>() : null); if (!Object.op_Implicit((Object)(object)val3)) { return text + "\n NO ExplosionFX - the blast switches off right after its lifespan, so the expiry was not touched."; } MainModule main2 = val3.main; float duration = ((MainModule)(ref main2)).duration; float num7 = num / WAVE_SPEED - duration + FX_MARGIN; float addedTimeForFX = blast.AddedTimeForFX; if (num7 > blast.AddedTimeForFX) { blast.AddedTimeForFX = num7; } return text + "\n expiry: ExplosionFX dur " + duration.ToString("F2") + " + AddedTimeForFX " + addedTimeForFX.ToString("F2") + " -> " + blast.AddedTimeForFX.ToString("F2") + " (slowed tail " + (num / WAVE_SPEED).ToString("F2") + " s)"; } } internal class OverchargeCrest : MonoBehaviour { private static readonly FieldRef<Blast, float> ShotTime = AccessTools.FieldRefAccess<Blast, float>("m_shotTime"); private readonly HashSet<int> _hit = new HashSet<int>(); private float _shot = float.MinValue; internal void Filter(Blast blast, List<Hitbox> targets) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) float num = ShotTime.Invoke(blast); if (num != _shot) { _shot = num; _hit.Clear(); } float age = Time.time - _shot; float num2 = OverchargeBlast.CrestRadius(blast.Radius, age); Vector3 position = ((Component)blast).transform.position; for (int num3 = targets.Count - 1; num3 >= 0; num3--) { Hitbox val = targets[num3]; Character val2 = (Object.op_Implicit((Object)(object)val) ? val.OwnerChar : null); if (!Object.op_Implicit((Object)(object)val2)) { targets.RemoveAt(num3); } else { int instanceID = ((Object)val2).GetInstanceID(); if (_hit.Contains(instanceID)) { targets.RemoveAt(num3); } else { Vector3 val3 = ((Component)val2).transform.position - position; val3.y = 0f; float magnitude = ((Vector3)(ref val3)).magnitude; if (magnitude > num2) { targets.RemoveAt(num3); } else { _hit.Add(instanceID); RunicBarrierPlugin.Log.LogMessage((object)("[RunicBarrier] crest hit " + val2.Name + " at " + magnitude.ToString("F1") + " m, " + age.ToString("F2") + " s after the cast (crest " + num2.ToString("F1") + " m)")); } } } } } } [HarmonyPatch(typeof(Blast), "AffectHit")] public class Blast_AffectHit_Crest { [HarmonyPrefix] public static void Prefix(Blast __instance, List<Hitbox> _hitTargets) { try { if (Object.op_Implicit((Object)(object)__instance) && _hitTargets != null && _hitTargets.Count != 0) { OverchargeCrest component = ((Component)__instance).GetComponent<OverchargeCrest>(); if (Object.op_Implicit((Object)(object)component)) { component.Filter(__instance, _hitTargets); } } } catch (Exception ex) { RunicBarrierPlugin.Log.LogError((object)("[RunicBarrier] crest filter threw: " + ex)); } } } [HarmonyPatch(typeof(CharacterInventory), "TakeItemToPouch")] internal static class CharacterInventory_TakeItemToPouch_RunicArrow { private static int _logged; private const int LOG_LIMIT = 3; private static bool Prefix(Character ___m_character, Item _item) { try { if (!Object.op_Implicit((Object)(object)_item) || _item.ItemID != -88001) { return true; } if (!Object.op_Implicit((Object)(object)___m_character) || (Object)(object)___m_character.OwnerPlayerSys != (Object)null) { return true; } if (!PhotonNetwork.isNonMasterClientInRoom) { ItemManager.Instance.DestroyItem(_item.UID); } if (_logged < 3) { _logged++; RunicBarrierPlugin.Log.LogMessage((object)("[RunicArrow] (" + _logged + "/" + 3 + ") kept a Runic Arrow out of " + ___m_character.Name + "'s pouch")); } return false; } catch (Exception ex) { RunicBarrierPlugin.Log.LogError((object)("[RunicArrow] pouch check threw: " + ex)); return true; } } } [BepInPlugin("com.wrango.runesredone.barrier", "Runes Redone - Barrier", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class RunicBarrierPlugin : BaseUnityPlugin { internal enum Tier { None, Normal, Amplified } public const string GUID = "com.wrango.runesredone.barrier"; public const string NAME = "Runes Redone - Barrier"; public const string VERSION = "1.0.0"; internal static ManualLogSource Log; internal static RunicBarrierPlugin Instance; private string _mitigationSig; private static readonly bool DIAG = false; private const bool APPLY_MANA_REDUCTION = true; private const string IMPACT_SOUNDS = "CS_GolemShielded_ShieldImpact_01,CS_GolemShielded_ShieldImpact_02,CS_GolemShielded_ShieldImpact_03,CS_GolemShielded_ShieldImpact_04"; private const float PITCH_MIN = 1f; private const float PITCH_MAX = 1f; private const float VOLUME_MIN = 1f; private const float VOLUME_MAX = 1f; private const ProjectilePrefabs SPARK_PROJECTILE = (ProjectilePrefabs)0; private const float SPARK_LIFESPAN = 0f; private const float SPARK_FORCE = 0f; private const float SPARK_SCALE = 1f; private const string SPARK_HIDE_EMITTERS = "ProjectileFX"; private const BlastPrefabs SPARK_BLAST = (BlastPrefabs)63; private const float SPARK_BLAST_LIFESPAN = 5f; private const float SPARK_BLAST_SCALE = 0.07f; private Sounds[] _sounds = (Sounds[])(object)new Sounds[0]; private int _lastIndex = -1; private readonly Dictionary<Sounds, int> _soundTally = new Dictionary<Sounds, int>(); internal static int AbsorbFrame = -1; internal static int AbsorbVictimId; internal static float AbsorbTook; internal static bool LogHits; private static Harmony _harmony; private static int _cueFrame = -1; private bool _hurtboxLogged; private static int _awaitingPointFrame = -1; private static int _awaitingPointHit; private static string _awaitingPointSrc = ""; private const float CUE_HOLD_SECONDS = 8f; private readonly Dictionary<int, UnityAction<Object, DamageList>> _subs = new Dictionary<int, UnityAction<Object, DamageList>>(); private Character _localPlayer; private float _nextScan; private float _manaSpent; private float _healthLet; private float _negated; private int _hits; private int _observed; private bool _wardWasUp; private static FieldInfo _manaField; private static bool _manaFieldResolved; internal const string STATUS_ID = "RunicBarrier"; internal const string STATUS_ID_AMPLIFIED = "RunicBarrierAmplified"; private const float HEALTH_SHARE = 0.6f; private const float MANA_SHARE = 0.6f; private const float HEALTH_SHARE_AMPLIFIED = 0.5f; private const float MANA_SHARE_AMPLIFIED = 0.5f; private readonly Dictionary<int, Tier> _allyWard = new Dictionary<int, Tier>(); private static bool ResolveManaField(CharacterStats stats) { if (_manaFieldResolved) { return _manaField != null; } _manaFieldResolved = true; BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; float currentMana = stats.CurrentMana; Type type = ((object)stats).GetType(); List<string> list = new List<string>(); FieldInfo[] fields = type.GetFields(bindingAttr); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType != typeof(float)) { continue; } float num; try { num = (float)fieldInfo.GetValue(stats); } catch (Exception) { continue; } float num2 = num - currentMana; if (num2 < 0f) { num2 = 0f - num2; } if (!(num2 > 0.0001f)) { list.Add(fieldInfo.Name); if (fieldInfo.Name == "m_mana") { _manaField = fieldInfo; } } } if (_manaField == null && list.Count == 1) { _manaField = type.GetField(list[0], bindingAttr); } if (_manaField != null) { Log.LogMessage((object)(Stamp() + " [RunicBarrier] mana field = " + _manaField.Name + " (candidates: " + string.Join(", ", list.ToArray()) + ")")); } else { Log.LogError((object)(Stamp() + " [RunicBarrier] COULD NOT RESOLVE the mana backing field. Candidates matching CurrentMana=" + currentMana.ToString("F2") + ": " + string.Join(", ", list.ToArray()) + ". The ward is disabled - it must never take damage it cannot charge for.")); } return _manaField != null; } private static string Stamp() { return DateTime.Now.ToString("HH:mm:ss.fff"); } internal void Awake() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Instance = this; Log.LogMessage((object)(Stamp() + " [RunicBarrier 1.0.0] loaded, WARD model. split=" + 0.6f.ToString("0.##") + "/" + 0.6f.ToString("0.##") + " amplified=" + 0.5f.ToString("0.##") + "/" + 0.5f.ToString("0.##") + " (fixed) ApplyManaReduction=" + true + " Spark=" + ((object)(ProjectilePrefabs)0/*cast due to .constrained prefix*/).ToString())); LogHits = DIAG; InstallHitPointHook(); ParseImpactSounds(); LoadOrder.Install(); SummonIcon.Install(); RunicTrapColour.Install(); } internal void LateUpdate() { RunicTrapColour.LateTick(); } internal void Update() { if (Object.op_Implicit((Object)(object)_localPlayer) && _localPlayer.IsLocalPlayer) { TrackWardSession(_localPlayer); } RunicPortals.Tick(); RunicFlameBlast.Tick(); RunicSpeed.Tick(); RunicTrapStatus.Tick(); CollapseAtZeroMana(); if (Time.time < _nextScan) { return; } _nextScan = Time.time + 2f; VFXTrim.TryOnce(); OverchargeBlast.TryOnce(); RunicFlameBlast.TryOnce(); StealthFX.TryOnce(); TouchFX.TryOnce(); SpeedFX.TryOnce(); if ((Object)(object)CharacterManager.Instance == (Object)null) { return; } List<int> list = new List<int>(); foreach (Character value in CharacterManager.Instance.Characters.Values) { if (!Object.op_Implicit((Object)(object)value) || value.IsAI) { continue; } int instanceID = ((Object)value).GetInstanceID(); list.Add(instanceID); if (value.IsLocalPlayer) { _localPlayer = value; } if (value.IsLocalPlayer) { LogMitigation(value); } else { LogAllyWard(value, instanceID); } if (!_subs.ContainsKey(instanceID)) { Character victim = value; UnityAction<Object, DamageList> val = delegate(Object src, DamageList dmg) { OnHit(victim, src, dmg); }; value.OnHitPreResistance = (UnityAction<Object, DamageList>)(object)Delegate.Combine((Delegate?)(object)value.OnHitPreResistance, (Delegate?)(object)val); _subs.Add(instanceID, val); Log.LogMessage((object)(Stamp() + " [RunicBarrier] watching " + Describe(value))); LogHurtbox(value); } } List<int> list2 = new List<int>(); foreach (int key in _subs.Keys) { if (!list.Contains(key)) { list2.Add(key); } } foreach (int item in list2) { _subs.Remove(item); } } private void ParseImpactSounds() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_0066: Unknown result type (might be due to invalid IL or missing references) try { List<Sounds> list = new List<Sounds>(); List<string> list2 = new List<string>(); string text = "CS_GolemShielded_ShieldImpact_01,CS_GolemShielded_ShieldImpact_02,CS_GolemShielded_ShieldImpact_03,CS_GolemShielded_ShieldImpact_04"; if (!string.IsNullOrEmpty(text)) { string[] array = text.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0) { continue; } try { Sounds val = (Sounds)Enum.Parse(typeof(Sounds), text2, ignoreCase: true); if ((int)val != 0) { list.Add(val); } } catch (Exception) { list2.Add(text2); } } } _sounds = list.ToArray(); if (list2.Count > 0) { Log.LogError((object)(Stamp() + " [RunicBarrier] these ImpactSounds are not valid sound names and were skipped: " + string.Join(", ", list2.ToArray()) + ". Copy them exactly from the ListSoundsMatching output.")); } Log.LogMessage((object)(Stamp() + " [RunicBarrier] impact sounds: " + _sounds.Length + ((_sounds.Length == 0) ? " (silent)" : " in rotation"))); } catch (Exception ex2) { Log.LogError((object)(Stamp() + " [RunicBarrier] could not parse ImpactSounds: " + ex2)); _sounds = (Sounds[])(object)new Sounds[0]; } } private unsafe string PlayImpactSound(Transform at) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) try { if (_sounds.Length == 0 || (Object)(object)Global.AudioManager == (Object)null || !Object.op_Implicit((Object)(object)at)) { return null; } int num; if (_sounds.Length > 1 && _lastIndex >= 0) { num = Random.Range(0, _sounds.Length - 1); if (num >= _lastIndex) { num++; } } else { num = Random.Range(0, _sounds.Length); } Sounds val = _sounds[num]; _lastIndex = num; if ((int)val == 0) { return "(NONE in the list)"; } _soundTally.TryGetValue(val, out var value); _soundTally[val] = value + 1; Global.AudioManager.PlaySoundAndFollow(val, at, 0f, 1f, 1f, 1f, 1f); return ((object)(*(Sounds*)(&val))/*cast due to .constrained prefix*/).ToString(); } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] impact sound failed: " + ex)); return "(threw)"; } } internal static Tier TierOf(Character c) { if (!Object.op_Implicit((Object)(object)c)) { return Tier.None; } StatusEffectManager statusEffectMngr = c.StatusEffectMngr; if ((Object)(object)statusEffectMngr != (Object)null) { if (statusEffectMngr.HasStatusEffect("RunicBarrierAmplified")) { return Tier.Amplified; } if (statusEffectMngr.HasStatusEffect("RunicBarrier")) { return Tier.Normal; } } return Tier.None; } private void SharesFor(Tier tier, out float hShare, out float mShare) { if (tier == Tier.Amplified) { hShare = 0.5f; mShare = 0.5f; } else { hShare = 0.6f; mShare = 0.6f; } } private void TrackWardSession(Character c) { try { if (Object.op_Implicit((Object)(object)c) && c.IsLocalPlayer) { bool flag = TierOf(c) != Tier.None; if (flag && !_wardWasUp) { Log.LogMessage((object)(Stamp() + " [RunicBarrier] ward session started")); } else if (!flag && _wardWasUp) { Log.LogMessage((object)(Stamp() + " [RunicBarrier] ward ended - dismissed, expired or collapsed; this edge does not say which")); } _wardWasUp = flag; } } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] ward session tracking threw: " + ex)); } } private void LogMitigation(Character c) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)c == (Object)null || (Object)(object)c.Stats == (Object)null) { return; } float[] damageProtection = c.Stats.DamageProtection; float[] damageResistance = c.Stats.DamageResistance; if (damageProtection == null || damageResistance == null) { Log.LogMessage((object)(Stamp() + " [RunicBarrier] mitigation: arrays unavailable")); return; } string text = ""; for (int i = 0; i < damageProtection.Length; i++) { string text2 = ((i < 9) ? ((object)(Types)i/*cast due to .constrained prefix*/).ToString() : ("?" + i)); text = text + " " + text2 + "=" + damageProtection[i].ToString("F2") + "/" + (damageResistance[i] * 100f).ToString("F0") + "%"; } float num = c.Stats.GetFinalManaConsumption((Tag[])null, 100f) / 100f; float manaRegen = c.Stats.ManaRegen; string text3 = text + "|" + c.Stats.GetBarrier().ToString("F2") + "|" + num.ToString("F3") + "|" + manaRegen.ToString("F3"); if (!(text3 == _mitigationSig)) { bool flag = _mitigationSig != null; _mitigationSig = text3; Log.LogMessage((object)(Stamp() + " [RunicBarrier] mitigation of " + c.Name + (flag ? " CHANGED" : "") + " | flat/resist by type:" + text + " | Barrier=" + c.Stats.GetBarrier().ToString("F2") + " | manaMod x" + num.ToString("F3") + ((num > 1.001f) ? " (a PENALTY, not a reduction)" : "") + " | manaRegenStat " + manaRegen.ToString("F3") + "/s" + ((manaRegen < -0.001f) ? " (rate negative; food may still carry it positive)" : ((manaRegen < 0.001f) ? " (rate suspended)" : "")))); } } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] mitigation dump threw: " + ex)); } } private float ManaBillBase(Character victim, DamageList dmg, float mShare, out float flatUsed) { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected I4, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected I4, but got Unknown flatUsed = 0f; if ((Object)(object)victim == (Object)null || (Object)(object)victim.Stats == (Object)null) { return dmg.TotalDamage * mShare; } float[] damageProtection = victim.Stats.DamageProtection; float[] damageResistance = victim.Stats.DamageResistance; if (damageProtection == null || damageResistance == null) { return dmg.TotalDamage * mShare; } float barrier = victim.Stats.GetBarrier(); int num = -1; if (barrier > 0f) { float num2 = 0f; float num3 = 0f; for (int i = 0; i < dmg.Count; i++) { DamageType val = dmg[i]; if ((int)val.Type != 0) { int num4 = (int)val.Type; if (num4 >= 0 && num4 < damageResistance.Length && (num < 0 || damageResistance[num4] < num2 || (damageResistance[num4] == num2 && val.Damage > num3))) { num = num4; num2 = damageResistance[num4]; num3 = val.Damage; } } } } float num5 = 0f; for (int j = 0; j < dmg.Count; j++) { DamageType obj = dmg[j]; int num6 = (int)obj.Type; float num7 = ((num6 >= 0 && num6 < damageProtection.Length) ? damageProtection[num6] : 0f); if (num6 == num) { num7 += barrier; } float num8 = obj.Damage * mShare; float num9 = num8 - num7; if (num9 < 0f) { num9 = 0f; } flatUsed += num8 - num9; num5 += num9; } return num5; } private void Collapse(Character victim) { try { if (Object.op_Implicit((Object)(object)victim) && !((Object)(object)victim.StatusEffectMngr == (Object)null)) { bool flag = false; if (victim.StatusEffectMngr.HasStatusEffect("RunicBarrier")) { victim.StatusEffectMngr.CleanseStatusEffect("RunicBarrier"); flag = true; } if (victim.StatusEffectMngr.HasStatusEffect("RunicBarrierAmplified")) { victim.StatusEffectMngr.CleanseStatusEffect("RunicBarrierAmplified"); flag = true; } Log.LogMessage((object)(Stamp() + " [RunicBarrier] WARD COLLAPSED on " + victim.Name + " - out of Mana" + (flag ? ", status removed" : ", no status was present"))); } } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] collapse threw: " + ex)); } } private void CollapseAtZeroMana() { if (Object.op_Implicit((Object)(object)NetworkLevelLoader.Instance) && !NetworkLevelLoader.Instance.IsOverallLoadingDone) { return; } CharacterManager instance = CharacterManager.Instance; if ((Object)(object)instance == (Object)null) { return; } foreach (Character value in instance.Characters.Values) { if (Object.op_Implicit((Object)(object)value) && value.IsLocalPlayer && Object.op_Implicit((Object)(object)value.Stats) && !(value.Stats.CurrentMana > 0f) && TierOf(value) != Tier.None) { Collapse(value); } } } internal static bool WardIsUp(Character c) { return TierOf(c) != Tier.None; } private void LogAllyWard(Character c, int id) { try { if (!((Object)(object)c == (Object)null)) { Tier tier = TierOf(c); if (!_allyWard.TryGetValue(id, out var value) || value != tier) { bool flag = _allyWard.ContainsKey(id); _allyWard[id] = tier; Log.LogMessage((object)(Stamp() + " [RunicBarrier] ally " + c.Name + ": ward " + ((tier == Tier.None) ? "None" : tier.ToString()) + (flag ? " (changed - as THIS client sees it)" : " (first sighting)"))); } } } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] ally ward watch threw: " + ex)); } } private void LogObserved(Character victim, Object src, DamageList dmg) { try { string text = ""; for (int i = 0; i < dmg.Count; i++) { DamageType val = dmg[i]; if (i > 0) { text += "/"; } text = text + ((object)Unsafe.As<Types, Types>(ref val.Type)/*cast due to .constrained prefix*/).ToString() + ":" + val.Damage.ToString("F1"); } float before = (Object.op_Implicit((Object)(object)victim.Stats) ? victim.Stats.CurrentHealth : (-1f)); _observed++; int observed = _observed; string text2 = Stamp() + " [RunicBarrier] OBSERVED #" + observed + " on " + (victim.Name ?? "?") + " (NOT ours - nothing touched) | src=" + (Object.op_Implicit(src) ? ((object)src).GetType().Name : "null") + " | entries=" + dmg.Count + " [" + text + "] raw=" + dmg.TotalDamage.ToString("F2") + " | health before=" + before.ToString("F2"); Log.LogMessage((object)text2); ((MonoBehaviour)this).StartCoroutine(ReportObservedHealth(victim, before, observed)); } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] observer threw: " + ex)); } } private IEnumerator ReportObservedHealth(Character victim, float before, int n) { yield return null; float afterOne = ((Object.op_Implicit((Object)(object)victim) && Object.op_Implicit((Object)(object)victim.Stats)) ? victim.Stats.CurrentHealth : (-1f)); yield return (object)new WaitForSeconds(0.25f); float num = ((Object.op_Implicit((Object)(object)victim) && Object.op_Implicit((Object)(object)victim.Stats)) ? victim.Stats.CurrentHealth : (-1f)); Log.LogMessage((object)(Stamp() + " [RunicBarrier] OBSERVED #" + n + " health " + before.ToString("F2") + " -> " + afterOne.ToString("F2") + " (1 frame) -> " + num.ToString("F2") + " (0.25s) | TOOK " + (before - num).ToString("F2") + " as this client sees it")); } private IEnumerator ReportOwnHealth(Character victim, float before, int hit) { yield return null; yield return (object)new WaitForSeconds(0.25f); float num = ((Object.op_Implicit((Object)(object)victim) && Object.op_Implicit((Object)(object)victim.Stats)) ? victim.Stats.CurrentHealth : (-1f)); Log.LogMessage((object)(Stamp() + " [RunicBarrier] SPLIT #" + hit + " health " + before.ToString("F2") + " -> " + num.ToString("F2") + " (0.25s) | TOOK " + (before - num).ToString("F2") + " as OUR client sees it")); } private void LogSoundTally() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (_soundTally.Count == 0) { return; } int num = 0; foreach (KeyValuePair<Sounds, int> item in _soundTally) { num += item.Value; } Log.LogMessage((object)(Stamp() + " [RunicBarrier] sound tally over " + num + " plays:")); foreach (KeyValuePair<Sounds, int> item2 in _soundTally) { Log.LogMessage((object)(" " + ((object)item2.Key/*cast due to .constrained prefix*/).ToString() + " x" + item2.Value + " (" + (100f * (float)item2.Value / (float)num).ToString("F0") + "%)")); } if (_soundTally.Count < _sounds.Length) { Log.LogMessage((object)(" NOTE: only " + _soundTally.Count + " of " + _sounds.Length + " configured sounds were ever picked.")); } } private void OnHit(Character victim, Object src, DamageList dmg) { //IL_02ea: Unknown result type (might be due to invalid IL or missing references) try { if (!Object.op_Implicit((Object)(object)victim) || dmg == null) { return; } if (!victim.IsLocalPlayer) { if (DIAG) { LogObserved(victim, src, dmg); } return; } string text = (Object.op_Implicit(src) ? ((object)src).GetType().Name : "null"); string text2 = ""; for (int i = 0; i < dmg.Count; i++) { DamageType val = dmg[i]; if (i > 0) { text2 += "/"; } text2 = text2 + ((object)Unsafe.As<Types, Types>(ref val.Type)/*cast due to .constrained prefix*/).ToString() + ":" + val.Damage.ToString("F1"); } string text3 = "entries=" + dmg.Count + " [" + text2 + "] raw=" + dmg.TotalDamage.ToString("F2"); Tier tier = TierOf(victim); if (tier == Tier.None) { if (DIAG) { Log.LogMessage((object)(Stamp() + " [RunicBarrier] ward DOWN, hit passes whole src=" + text + " " + text3)); } return; } float before = (Object.op_Implicit((Object)(object)victim.Stats) ? victim.Stats.CurrentHealth : (-1f)); float totalDamage = dmg.TotalDamage; if (totalDamage <= 0f) { return; } SharesFor(tier, out var hShare, out var mShare); float num = Mathf.Max(0f, 1f - hShare - mShare); if (mShare <= 0f) { if (DIAG) { Log.LogMessage((object)(Stamp() + " [RunicBarrier] Mana share is 0, nothing to charge src=" + text + " " + text3)); } } else { if (!ResolveManaField(victim.Stats)) { return; } LogMitigation(victim); float flatUsed; float num2 = ManaBillBase(victim, dmg, mShare, out flatUsed); float num3 = num2; num3 = victim.Stats.GetFinalManaConsumption((Tag[])null, num2); float currentMana = victim.Stats.CurrentMana; float num4 = 1f; bool flag = false; if (num3 > currentMana) { num4 = ((num3 > 0f) ? Mathf.Clamp01(currentMana / num3) : 0f); flag = true; } float num5 = num3 * num4; float num6 = mShare * num4; float num7 = mShare * (1f - num4); float num8 = hShare + num7; List<DamageType> list = new List<DamageType>(); for (int j = 0; j < dmg.Count; j++) { DamageType val2 = dmg[j]; val2.Damage *= num8; if (val2.Damage <= 0.001f) { list.Add(val2); } } foreach (DamageType item in list) { dmg.Remove(item.Type); } _manaField.SetValue(victim.Stats, currentMana - num5); _hits++; _manaSpent += num5; _healthLet += totalDamage * num8; _negated += totalDamage * num; if (_awaitingPointFrame >= 0) { Log.LogWarning((object)(Stamp() + " [RunicBarrier] split #" + _awaitingPointHit + " (" + _awaitingPointSrc + ") never received a hit point - no impact sound and no spark for it.")); } if (DIAG) { ((MonoBehaviour)this).StartCoroutine(ReportOwnHealth(victim, before, _hits)); } _awaitingPointFrame = Time.frameCount; _awaitingPointHit = _hits; _awaitingPointSrc = text; AbsorbFrame = Time.frameCount; AbsorbVictimId = ((Object)victim).GetInstanceID(); AbsorbTook = totalDamage * num6; if (flag) { Collapse(victim); } Log.LogMessage((object)(Stamp() + " [RunicBarrier] " + (flag ? "SPLIT+COLLAPSE #" : "SPLIT #") + _hits + " src=" + text + " tier=" + tier.ToString() + " (" + hShare.ToString("0.##") + "/" + mShare.ToString("0.##") + " = " + (hShare + mShare).ToString("0.##") + "x raw) | raw=" + totalDamage.ToString("F2") + " -> health=" + (totalDamage * num8).ToString("F2") + " mana=" + (totalDamage * num6).ToString("F2") + " negated=" + (totalDamage * num).ToString("F2") + " | cost=" + num3.ToString("F2") + " (flat -" + flatUsed.ToString("F2") + ((num3 <= 0.001f) ? ", FREE" : "") + ") spent=" + num5.ToString("F2") + ((num3 < num2 - 0.01f) ? (" (reduced from " + num2.ToString("F2") + ")") : "") + " | mana " + currentMana.ToString("F2") + " -> " + victim.Stats.CurrentMana.ToString("F2") + " | " + text3 + " | list now=" + dmg.TotalDamage.ToString("F2") + (flag ? (" | WARD DOWN, " + (totalDamage * num7).ToString("F2") + " fell back to Health") : "") + " | totals mana=" + _manaSpent.ToString("F1") + " healthShare=" + _healthLet.ToString("F1") + " negated=" + _negated.ToString("F1"))); } } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] handler threw: " + ex)); } } private void InstallHitPointHook() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown try { Type[] array = new Type[9] { typeof(Weapon), typeof(float), typeof(DamageList), typeof(Vector3), typeof(Vector3), typeof(float), typeof(float), typeof(Character), typeof(float) }; MethodInfo methodInfo = AccessTools.Method(typeof(Character), "OnReceiveHit", array, (Type[])null); if (methodInfo == null) { Log.LogError((object)(Stamp() + " [RunicBarrier] OnReceiveHit not found with that signature - no hit point, so the spark cannot fire.")); return; } _harmony = new Harmony("com.wrango.runesredone.barrier"); _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(RunicBarrierPlugin).GetMethod("OnReceiveHitPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.PatchAll(typeof(Projectile_Shoot_KeepAlive)); _harmony.PatchAll(typeof(Blast_AffectHit_Crest)); _harmony.PatchAll(typeof(Shooter_GetActivationInfos_RunicFlame)); _harmony.PatchAll(typeof(Blast_Shoot_RunicFlame)); _harmony.PatchAll(typeof(ItemVisual_AddImbueFX_RunicBlade)); _harmony.PatchAll(typeof(DetectabilityEmitter_Detectability_RunicSpeed)); _harmony.PatchAll(typeof(DetectabilityEmitter_VisualDetectability_RunicSpeed)); _harmony.PatchAll(typeof(CharacterStats_GetFinalStaminaConsumption_RunicSpeed)); _harmony.PatchAll(typeof(ShootProjectile_ProcessAffectInfos_Sight)); _harmony.PatchAll(typeof(DeployableTrap_StartInit_RunicTrapColour)); _harmony.PatchAll(typeof(CharacterInventory_TakeItemToPouch_RunicArrow)); _harmony.PatchAll(typeof(RunicBlade_ActivateLocally_PrefixLifespan)); _harmony.PatchAll(typeof(Item_Start_NameSync)); _harmony.PatchAll(typeof(ShootProjectileAmmoVisuals_ActivateLocally_LoadedVisual)); Log.LogMessage((object)(Stamp() + " [RunicBarrier] OnReceiveHit hook installed.")); } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] could not install the hook: " + ex)); } } private static void OnReceiveHitPrefix(Character __instance, Weapon _weapon, float _damage, DamageList _damageList, Vector3 _hitDir, Vector3 _hitPoint, float _angle, float _angleDir, Character _dealerChar, float _knockBack) { //IL_00aa: 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_0229: Unknown result type (might be due to invalid IL or missing references) try { if (!Object.op_Implicit((Object)(object)__instance) || __instance.IsAI) { return; } bool flag = __instance.IsLocalPlayer && Time.frameCount == AbsorbFrame && ((Object)__instance).GetInstanceID() == AbsorbVictimId; bool flag2 = !__instance.IsLocalPlayer && WardIsUp(__instance); if (!flag && !flag2 && !LogHits) { return; } string text = null; string text2 = null; string text3 = null; if ((flag || flag2) && (Object)(object)Instance != (Object)null) { if (flag) { _awaitingPointFrame = -1; } if (Time.frameCount == _cueFrame) { text = "(suppressed, same frame)"; } else { _cueFrame = Time.frameCount; GameObject val = Spark.CreateCue(__instance, _hitPoint, _hitDir, 8f); text2 = Instance.PlayImpactSound(val.transform); text = Spark.Fire(val, __instance, (ProjectilePrefabs)0, 0f, 0f, 1f, "ProjectileFX"); text3 = SparkBlast.Fire(val, __instance, (BlastPrefabs)63, 5f, 0.07f, "ProjectileFX"); } } Log.LogMessage((object)(Stamp() + " [RunicBarrier] OnReceiveHit" + (flag ? (" *** same frame as a split taking " + AbsorbTook.ToString("F2") + " ***") : "") + (flag2 ? (" *** ALLY " + (__instance.Name ?? "?") + ", ward up - cue only, no split on this client ***") : "") + ((text2 == null) ? "" : (" | sound=" + text2)) + ((text == null) ? "" : (" | spark=" + text)) + ((text3 == null) ? "" : (" | blast=" + text3)) + " | _damage=" + _damage.ToString("F2") + " | list=" + ((_damageList == null) ? "null" : (_damageList.Count + " entries total=" + _damageList.TotalDamage.ToString("F2"))) + " | " + Offset(__instance, _hitPoint) + " | _hitPoint=" + ((Vector3)(ref _hitPoint)).ToString("F2") + " | _hitDir=" + ((Vector3)(ref _hitDir)).ToString("F2") + " | _knockBack=" + _knockBack.ToString("F2") + " | dealer=" + (Object.op_Implicit((Object)(object)_dealerChar) ? _dealerChar.Name : "null"))); } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] OnReceiveHit prefix threw: " + ex)); } } private static string Offset(Character victim, Vector3 hitPoint) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)victim)) { return "offset=(no character)"; } Vector3 val = ((Component)victim).transform.InverseTransformPoint(hitPoint); Vector3 val2 = hitPoint - ((Component)victim).transform.position; float magnitude = ((Vector3)(ref val2)).magnitude; return "offset r=" + val.x.ToString("F2") + " u=" + val.y.ToString("F2") + " f=" + val.z.ToString("F2") + " dist=" + magnitude.ToString("F2"); } private void LogHurtbox(Character c) { //IL_0069: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) try { if (_hurtboxLogged || !Object.op_Implicit((Object)(object)c)) { return; } _hurtboxLogged = true; Collider[] componentsInChildren = ((Component)c).GetComponentsInChildren<Collider>(true); string[] obj = new string[7] { Stamp(), " [RunicBarrier] hurtbox of ", c.Name, ": ", componentsInChildren.Length.ToString(), " collider(s), root at ", null }; Vector3 val = ((Component)c).transform.position; obj[6] = ((Vector3)(ref val)).ToString("F2"); string text = string.Concat(obj); foreach (Collider val2 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val2)) { Bounds bounds = val2.bounds; string[] obj2 = new string[12] { text, "\n ", ((object)val2).GetType().Name, " '", ((Object)val2).name, "'", val2.enabled ? "" : " (disabled)", val2.isTrigger ? " (trigger)" : "", " | extents=", null, null, null }; val = ((Bounds)(ref bounds)).extents; obj2[9] = ((Vector3)(ref val)).ToString("F2"); obj2[10] = " | centre offset from root="; val = ((Component)c).transform.InverseTransformPoint(((Bounds)(ref bounds)).center); obj2[11] = ((Vector3)(ref val)).ToString("F2"); text = string.Concat(obj2); } } Log.LogMessage((object)text); } catch (Exception ex) { Log.LogError((object)(Stamp() + " [RunicBarrier] hurtbox dump failed: " + ex)); } } private static string Describe(Character c) { if (!Object.op_Implicit((Object)(object)c)) { return "<null>"; } return c.Name + "(local=" + c.IsLocalPlayer + ",id=" + ((Object)c).GetInstanceID() + ")"; } internal void OnDestroy() { foreach (KeyValuePair<int, UnityAction<Object, DamageList>> sub in _subs) { if ((Object)(object)CharacterManager.Instance == (Object)null) { break; } foreach (Character value in CharacterManager.Instance.Characters.Values) { if (Object.op_Implicit((Object)(object)value) && ((Object)value).GetInstanceID() == sub.Key) { value.OnHitPreResistance = (UnityAction<Object, DamageList>)(object)Delegate.Remove((Delegate?)(object)value.OnHitPreResistance, (Delegate?)(object)sub.Value); } } } _subs.Clear(); if (_harmony != null) { try { _harmony.UnpatchSelf(); } catch (Exception) { } _harmony = null; } if (_awaitingPointFrame >= 0 && Log != null) { Log.LogWarning((object)(Stamp() + " [RunicBarrier] split #" + _awaitingPointHit + " (" + _awaitingPointSrc + ") never received a hit point - no impact sound and no spark for it.")); _awaitingPointFrame = -1; } LogSoundTally(); if (Log != null) { Log.LogMessage((object)(Stamp() + " [RunicBarrier] unloaded. hits=" + _hits + " mana=" + _manaSpent.ToString("F1") + " healthShare=" + _healthLet.ToString("F1") + " negated=" + _negated.ToString("F1"))); } } } internal static class RunicBladeImbueFix { private static readonly int[] Blades = new int[2] { 2000100, 2100999 }; private static int _logged; private const int LOG_LIMIT = 6; private static void FixBow(ItemVisual visual, ImbueStack stack, Weapon weapon) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Invalid comparison between Unknown and I4 if (stack.ParticleSystems == null || stack.ParticleSystems.Length == 0) { return; } SkinnedMeshRenderer componentInChildren = ((Component)visual).GetComponentInChildren<SkinnedMeshRenderer>(true); if (!Object.op_Implicit((Object)(object)componentInChildren)) { return; } string text = ""; for (int i = 0; i < stack.ParticleSystems.Length; i++) { ParticleSystem val = stack.ParticleSystems[i]; if (Object.op_Implicit((Object)(object)val)) { ShapeModule shape = val.shape; if (i == 0) { text = ((object)((ShapeModule)(ref shape)).shapeType/*cast due to .constrained prefix*/).ToString() + (((int)((ShapeModule)(ref shape)).shapeType == 13) ? (" on " + (Object.op_Implicit((Object)(object)((ShapeModule)(ref shape)).meshRenderer) ? ((Object)((ShapeModule)(ref shape)).meshRenderer).name : "nothing")) : ""); } ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)14; ((ShapeModule)(ref shape)).skinnedMeshRenderer = componentInChildren; ((ShapeModule)(ref shape)).meshRenderer = null; val.Play(); } } if (_logged < 6) { _logged++; RunicBarrierPlugin.Log.LogMessage((object)("[RunicBow] imbue (" + _logged + "/" + 6 + ") " + ((Item)weapon).Name + ": " + stack.ParticleSystems.Length + " system(s) " + (Object.op_Implicit((Object)(object)stack.ImbueFX) ? ((Object)stack.ImbueFX).name : "?") + " was " + text + " -> the bow's skinned mesh " + ((Object)componentInChildren).name)); } } internal static void Fix(ItemVisual visual, ImbueStack stack, Weapon weapon) { //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)visual) || stack == null || !Object.op_Implicit((Object)(object)weapon)) { return; } if (((Item)weapon).ItemID == -88000) { FixBow(visual, stack, weapon); } else { if (Array.IndexOf(Blades, ((Item)weapon).ItemID) < 0 || stack.ParticleSystems == null || stack.ParticleSystems.Length == 0 || Object.op_Implicit((Object)(object)((Component)visual).GetComponentInChildren<SkinnedMeshRenderer>(true))) { return; } MeshRenderer val = BladeMesh(visual); if (!Object.op_Implicit((Object)(object)val)) { if (_logged < 6) { _logged++; RunicBarrierPlugin.Log.LogWarning((object)("[RunicBlade] imbue (" + _logged + "/" + 6 + ") " + ((Item)weapon).Name + ": no blade mesh found under " + ((Object)visual).name + " - imbue left as it is")); } return; } string text = ""; for (int i = 0; i < stack.ParticleSystems.Length; i++) { ParticleSystem val2 = stack.ParticleSystems[i]; if (Object.op_Implicit((Object)(object)val2)) { ShapeModule shape = val2.shape; if (i == 0) { text = ((object)((ShapeModule)(ref shape)).shapeType/*cast due to .constrained prefix*/).ToString() + (((int)((ShapeModule)(ref shape)).shapeType == 14) ? (" on " + (Object.op_Implicit((Object)(object)((ShapeModule)(ref shape)).skinnedMeshRenderer) ? ((Object)((ShapeModule)(ref shape)).skinnedMeshRenderer).name : "nothing")) : ""); } ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)13; ((ShapeModule)(ref shape)).meshRenderer = val; ((ShapeModule)(ref shape)).skinnedMeshRenderer = null; val2.Play(); } } if (_logged < 6) { _logged++; RunicBarrierPlugin.Log.LogMessage((object)("[RunicBlade] imbue (" + _logged + "/" + 6 + ") " + ((Item)weapon).Name + ": " + stack.ParticleSystems.Length + " system(s) " + (Object.op_Implicit((Object)(object)stack.ImbueFX) ? ((Object)stack.ImbueFX).name : "?") + " was " + text + " -> the blade's mesh " + ((Object)val).name)); } } } private static MeshRenderer BladeMesh(ItemVisual visual) { MeshRenderer[] componentsInChildren = ((Component)visual).GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val in componentsInChildren) { if (!Object.op_Implicit((Object)(object)((Component)val).GetComponent<WeaponTrail>()) && !((Object)val).name.Contains("LeftHand")) { return val; } } return null; } } [HarmonyPatch(typeof(ItemVisual), "AddImbueFX")] public class ItemVisual_AddImbueFX_RunicBlade { [HarmonyPostfix] public static void Postfix(ItemVisual __instance, ImbueStack __0, Weapon __1) { try { RunicBladeImbueFix.Fix(__instance, __0, __1); } catch (Exception ex) { RunicBarrierPlugin.Log.LogError((object)("[RunicBlade] imbue fix threw: " + ex)); } } } internal static class RunicFlameBlast { private class Swell { public Blast Shot; public ParticleSystem[] Mouth; public Transform Core; public float ShotAt; public bool Releasing; public float Level; public Vector3 Scale; public ParticleSystem[] Systems; public ParticleSystemScalingMode[] Modes; public Transform[] Embers; public Vector3[] EmberScales; public Light[] Lights; public float[] Intensities; } private const int FAL_ITEM_ID = 8100240; private const string BRANCH = "RunicLightning";