using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Mutators.Announcements; using Mutators.Assets; using Mutators.Assets.Loaders; using Mutators.Enums; using Mutators.Extensions; using Mutators.Logging.Loggers; using Mutators.Managers; using Mutators.Mutators; using Mutators.Mutators.Behaviours; using Mutators.Mutators.Behaviours.HurtColliders; using Mutators.Mutators.Behaviours.Markers; using Mutators.Mutators.Behaviours.UI; using Mutators.Mutators.MultiMutators; using Mutators.Mutators.Patches; using Mutators.Network; using Mutators.Patches; using Mutators.Providers.Random; using Mutators.Providers.Semiwork; using Mutators.Rules.Loaders; using Mutators.Rules.Loaders.Json; using Mutators.Rules.Loaders.Strategies; using Mutators.Rules.Registries; using Mutators.Services.Selection; using Mutators.Services.Selection.Strategies; using Mutators.Settings; using Mutators.Settings.Specific; using Mutators.Utility; using Mutators.Utility.Config; using Newtonsoft.Json; using Photon.Pun; using Photon.Realtime; using REPOLib.Modules; using ScalerCore; using TMPro; using Unity.VisualScripting; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Xepos")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3+da0a5261df0daa082b4c5feafc5e4a019daf68b4")] [assembly: AssemblyProduct("Mutators")] [assembly: AssemblyTitle("Mutators")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Justin-dr/REPO-Mutators.git")] [assembly: InternalsVisibleTo("Mutators.Tests")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [CompilerGenerated] internal sealed class <>z__ReadOnlyArray : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection.Count => _items.Length; T IReadOnlyList.this[int index] => _items[index]; int ICollection.Count => _items.Length; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return ((ICollection)_items).Contains(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { ((ICollection)_items).CopyTo(array, arrayIndex); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { return ((IList)_items).IndexOf(item); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } } [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator { object IEnumerator.Current => _item; T IEnumerator.Current => _item; public Enumerator(T item) { _item = item; } bool IEnumerator.MoveNext() { if (!_moveNextCalled) { return _moveNextCalled = true; } return false; } void IEnumerator.Reset() { _moveNextCalled = false; } void IDisposable.Dispose() { } } int ICollection.Count => 1; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection.Count => 1; T IReadOnlyList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection.Count => 1; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } public <>z__ReadOnlySingleElementList(T item) { _item = item; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.CopyTo(Array array, int index) { array.SetValue(_item, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return EqualityComparer.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { if (!EqualityComparer.Default.Equals(_item, (T)value)) { return -1; } return 0; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return EqualityComparer.Default.Equals(_item, item); } void ICollection.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { if (!EqualityComparer.Default.Equals(_item, item)) { return -1; } return 0; } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 Mutators { [BepInDependency("Vippy.ScalerCore", "1.0.2")] [BepInDependency("REPOLib", "4.2.0")] [BepInPlugin("Xepos.REPO-Mutators", "Mutators", "1.0.3")] public class RepoMutators : BaseUnityPlugin { internal const string MainScenePath = "Assets/Scenes/Main/Main.unity"; internal const string NETWORKMANAGER_NAME = "MutatorsNetworkManager"; internal const string MUTATOR_OVERRIDES = "mutatorOverrides"; public static string ConfigPath => Path.Combine(Paths.ConfigPath, "Mutators"); internal static RepoMutators Instance { get; private set; } = null; internal static ModSettings Settings { get; private set; } = null; internal static IMutatorsLogger Logger { get; private set; } = new NullMutatorsLogger(); internal Harmony? Harmony { get; set; } public static event Action, string, bool>>>? OnLoadMultiMutatorRules; public static event Action>>? OnLoadSingleMutatorRules; private RepoMutators() { } private void Awake() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown Instance = this; Logger = new MutatorsLogger(((BaseUnityPlugin)this).Logger); ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Settings = new ModSettings(((BaseUnityPlugin)this).Config); MutatorSettings.Initialize(((BaseUnityPlugin)this).Config); InitializeDependencyContainer(new NopMutator(MutatorSettings.NopMutator)); GameObject val = new GameObject("RepoMutatorsPrefab") { hideFlags = (HideFlags)61 }; val.SetActive(false); val.AddComponent(); val.AddComponent(); string myPrefabId = "Xepos.REPO-Mutators/MutatorsNetworkManager"; NetworkPrefabs.RegisterNetworkPrefab(myPrefabId, val); ScheduleAssetLoad(); SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode _) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if (!(((Scene)(ref scene)).path != "Assets/Scenes/Main/Main.unity") && SemiFunc.IsMasterClientOrSingleplayer()) { if ((Object)(object)RunManager.instance.levelCurrent == (Object)(object)RunManager.instance.levelMainMenu) { if ((Object)(object)MutatorsNetworkManager.Instance != (Object)null && (Object)(object)((Component)MutatorsNetworkManager.Instance).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)MutatorsNetworkManager.Instance).gameObject); } } else if (!((Object)(object)MutatorsNetworkManager.Instance != (Object)null) && SemiFunc.RunIsLobbyMenu()) { Logger.LogDebug("Reviving network manager"); PrefabRef val2 = default(PrefabRef); if (!NetworkPrefabs.TryGetNetworkPrefabRef(myPrefabId, ref val2)) { throw new Exception("Unable to establish Mutators NetworkManager: Could not find PrefabRef with id: " + myPrefabId); } NetworkPrefabs.SpawnNetworkPrefab(val2, Vector3.zero, Quaternion.identity, (byte)0, (object[])null); MutatorManager instance = MutatorManager.Instance; Logger.LogInfo(string.Join(", ", instance.RegisteredMutators.Select, string>((KeyValuePair x) => $"{x.Key}: {x.Value.Settings.Weight}")) ?? ""); IMutator weightedMutator = instance.GetWeightedMutator(); Logger.LogDebug("Picked weighted mutator: " + weightedMutator.Name); instance.CurrentMutator = weightedMutator; if (weightedMutator is IMultiMutator multiMutator) { (IList, IDictionary) tuple = multiMutator.Format(); MutatorsNetworkManager.Instance.SendActiveMutators(multiMutator, tuple.Item2); } else { MutatorsNetworkManager.Instance.SendActiveMutator(weightedMutator.NamespacedName, weightedMutator.Settings.AsMetadata()); } Logger.LogDebug("Mutator set: " + weightedMutator.Name); } } }; MutatorManager.Instance.GameStateChanged += delegate(MutatorsGameState gameState) { Logger.LogDebug($"Changed Mutators gamestate to {gameState}"); }; Patch(); Logger.LogInfo($"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!"); Logger.LogDebug("Initializing default mutators."); MutatorManager.Instance.InitializeDefaultMutators(); OnLoadSingleMutatorRules += delegate(IRuleLoader> ruleLoader) { ruleLoader.AddRuleStrategy(new ExclusionRuleLoadingStrategy()); ruleLoader.AddDefaultRule(new JsonMutatorRule("exclude-null-signal", "Exclusion", new string[1] { MutatorSettings.NullSignal.NamespacedName })); }; OnLoadMultiMutatorRules += delegate(IRuleLoader, string, bool>> ruleLoader) { ruleLoader.AddRuleStrategy(new MultiExclusionRuleLoadingStrategy()); ruleLoader.AddRuleStrategy(new MutualExclusionRuleLoadingStrategy()); ruleLoader.AddRuleStrategy(new RequiresAmountOfOtherMutatorsRuleLoadingStrategy()); IDictionary arguments = new Dictionary { { "other-mutators-required-amount", 2 } }; ruleLoader.AddDefaultRules(new JsonMutatorRule("handle-with-care-less-is-more", "Mutual Exclusion", new string[2] { MutatorSettings.HandleWithCare.NamespacedName, MutatorSettings.LessIsMore.NamespacedName }), new JsonMutatorRule("protect-the-weak-protect-the-president", "Mutual Exclusion", new string[2] { MutatorSettings.ProtectTheWeak.NamespacedName, MutatorSettings.ProtectThePresident.NamespacedName }), new JsonMutatorRule("the-floor-is-lava-one-shot-one-kill", "Mutual Exclusion", new string[2] { MutatorSettings.TheFloorIsLava.NamespacedName, MutatorSettings.OneShotOneKill.NamespacedName }), new JsonMutatorRule("the-floor-is-lava-rusty-servos", "Mutual Exclusion", new string[2] { MutatorSettings.TheFloorIsLava.NamespacedName, MutatorSettings.RustyServos.NamespacedName }), new JsonMutatorRule("size-matters-rusty-servos", "Mutual Exclusion", new string[2] { MutatorSettings.SizeMatters.NamespacedName, MutatorSettings.RustyServos.NamespacedName }), new JsonMutatorRule("null-signal-required-amount-of-other-mutators", "Requires Amount Of Other Mutators", new string[1] { MutatorSettings.NullSignal.NamespacedName }, null, arguments)); }; } private void InitializeDependencyContainer(NopMutator nopMutator) { DI.Container.AddSingleton(Logger).AddSingleton().AddSingleton() .AddSingleton(new GeneratedMultiMutatorSelectionRulesRegistry()) .AddSingleton() .AddSingleton() .AddSingleton(Settings.MoonMutatorSettings) .AddSingleton(Settings.RandomMutatorSettings) .AddSingleton(nopMutator) .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton(); } private static void ScheduleAssetLoad() { UnityAction sceneLoaded = null; sceneLoaded = delegate(Scene scene, LoadSceneMode _) { if (!(((Scene)(ref scene)).path != "Assets/Scenes/Main/Main.unity")) { List list = new List(2) { new LaserAssetLoader(), new ExplosionAssetLoader() }; list.ForEach(delegate(BaseGameAssetLoader loader) { loader.Load(); }); SceneManager.sceneLoaded -= sceneLoaded; } }; SceneManager.sceneLoaded += sceneLoaded; } private void LoadRules() { SingleMutatorRuleLoader singleMutatorRuleLoader = new SingleMutatorRuleLoader(); MultiMutatorRuleLoader multiMutatorRuleLoader = new MultiMutatorRuleLoader(); RepoMutators.OnLoadSingleMutatorRules?.Invoke(singleMutatorRuleLoader); RepoMutators.OnLoadMultiMutatorRules?.Invoke(multiMutatorRuleLoader); IDictionary> source = singleMutatorRuleLoader.Load(); IDictionary, string, bool>> source2 = multiMutatorRuleLoader.Load(); SingleMutatorSelectionRulesRegistry singleRegistry = DI.Container.Resolve(); GeneratedMultiMutatorSelectionRulesRegistry multiRegistry = DI.Container.Resolve(); source.ForEach(delegate(KeyValuePair> rule) { singleRegistry.Register(rule.Key, rule.Value); }); source2.ForEach(delegate(KeyValuePair, string, bool>> rule) { multiRegistry.Register(rule.Key, rule.Value); }); RepoMutators.OnLoadSingleMutatorRules = null; RepoMutators.OnLoadMultiMutatorRules = null; } private void Start() { MutatorManager.Instance.InitializeMultiMutators(); LoadRules(); } private void Patch() { //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_004f: Expected O, but got Unknown //IL_0054: Expected O, but got Unknown bool flag = Chainloader.PluginInfos.Values.Any((PluginInfo x) => x.Metadata.GUID == "soundedsquash.spawnmanager"); if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(typeof(RunManagerPatch)); Harmony.PatchAll(typeof(LoadingUIPatch)); Harmony.PatchAll(typeof(MapToolControllerPatch)); Harmony.PatchAll(typeof(SemiFuncPatch)); Harmony.PatchAll(typeof(MenuPagePatch)); Harmony.PatchAll(typeof(SpectateCameraPatch)); Harmony.PatchAll(typeof(LevelGeneratorPatch)); Harmony.PatchAll(typeof(MenuManagerPatch)); Harmony.PatchAll(typeof(HealthUIPatch)); Harmony.PatchAll(typeof(MapBacktrackPatch)); if (!flag) { Harmony.PatchAll(typeof(EnemyDirectorPatch)); } } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } foreach (IMutator value in MutatorManager.Instance.RegisteredMutators.Values) { value.Unpatch(); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Xepos.REPO-Mutators"; public const string PLUGIN_NAME = "Mutators"; public const string PLUGIN_VERSION = "1.0.3"; } internal class DI { private IDictionary _registry = new Dictionary(); private IDictionary _singletons = new Dictionary(); public static DI Container { get; } = new DI(); public IReadOnlyCollection RegisteredTypes => new ReadOnlyCollection(_registry.Keys.ToList()); public DI AddSingleton() where I : T { Type typeFromHandle = typeof(T); Type typeFromHandle2 = typeof(I); if (_registry.ContainsKey(typeFromHandle)) { throw new InvalidOperationException($"A type of {typeFromHandle} has already been registered."); } if (IsStatic(typeFromHandle2)) { throw new ArgumentException("Concrete type " + typeFromHandle2.FullName + " may not be static."); } if (typeFromHandle2.IsInterface || typeFromHandle2.IsAbstract) { throw new ArgumentException(typeFromHandle2.FullName + " must be a concrete type."); } GetConstructor(typeFromHandle2); _registry[typeFromHandle] = typeFromHandle2; return this; } public DI AddSingleton() where T : class { return AddSingleton(); } public DI AddSingleton(T instance) where T : class { if (instance == null) { throw new ArgumentNullException("instance"); } Type typeFromHandle = typeof(T); if (_registry.ContainsKey(typeFromHandle)) { throw new InvalidOperationException($"A type of {typeFromHandle} has already been registered."); } _registry[typeFromHandle] = instance.GetType(); _singletons[typeFromHandle] = instance; return this; } public T Resolve() { return (T)Resolve(typeof(T), new List()); } private object Resolve(Type serviceType, IList resolutionPath) { if (_singletons.TryGetValue(serviceType, out var value)) { return value; } int num = resolutionPath.IndexOf(serviceType); if (num >= 0) { string text = string.Join(" -> ", from type in resolutionPath.Skip(num).Append(serviceType) select type.Name); throw new InvalidOperationException("Circular dependency detected: " + text); } if (!_registry.TryGetValue(serviceType, out var value2)) { throw new ArgumentException("Could not find registered implementation for " + serviceType.FullName + "."); } ConstructorInfo constructor = GetConstructor(value2); resolutionPath.Add(serviceType); try { object[] parameters = (from parameter in constructor.GetParameters() select Resolve(parameter.ParameterType, resolutionPath)).ToArray(); object obj = constructor.Invoke(parameters); _singletons[serviceType] = obj; return obj; } finally { resolutionPath.RemoveAt(resolutionPath.Count - 1); } } private static ConstructorInfo GetConstructor(Type concreteType) { ConstructorInfo[] constructors = concreteType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); ConstructorInfo[] array = constructors.Where((ConstructorInfo c) => c.IsDefined(typeof(InjectAttribute))).ToArray(); if (array.Length > 1) { throw new ArgumentException("Type " + concreteType.FullName + " has multiple constructors marked with [Inject]."); } if (array.Length == 1) { return array[0]; } return constructors.OrderByDescending((ConstructorInfo c) => c.GetParameters().Length).FirstOrDefault(); } private static bool IsStatic(Type type) { if ((object)type != null && type.IsClass && type.IsSealed) { return type.IsAbstract; } return false; } } [AttributeUsage(AttributeTargets.Constructor)] internal class InjectAttribute : Attribute { } } namespace Mutators.Utility { internal static class LevelRemovalUtils { internal static void RemoveLevels(bool lobbyMenu = false) { IMutator currentMutator = MutatorManager.Instance.CurrentMutator; if (currentMutator is IMultiMutator multiMutator) { { foreach (KeyValuePair> subMutator in multiMutator.SubMutators) { subMutator.Key.Settings.ClearRuntimeOverrides(); subMutator.Key.Settings.ApplyRuntimeOverrides(subMutator.Value); if (subMutator.Key.Settings is ILevelRemovingMutatorSettings settings) { settings.RemoveLevels(lobbyMenu); } } return; } } if (currentMutator.Settings is ILevelRemovingMutatorSettings settings2) { settings2.RemoveLevels(lobbyMenu); } } } public static class TemporaryItemUtils { public static void RemoveMarkedItems(string marker) { StatsManager instance = StatsManager.instance; foreach (string item in (from x in instance.item where x.Key.Contains("(" + marker + ")") select x.Key).ToList()) { instance.item.Remove(item); instance.itemStatBattery.Remove(item); } } public static void DropAndRemoveMarkedItems(string marker) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) Inventory instance = Inventory.instance; foreach (InventorySpot inventorySpot in instance.inventorySpots) { ItemEquippable currentItem = inventorySpot.CurrentItem; if (Object.op_Implicit((Object)(object)currentItem) && Object.op_Implicit((Object)(object)((Component)currentItem).gameObject.GetComponent())) { ((Component)currentItem).GetComponent().ForceUnequip(instance.playerAvatar.PlayerVisionTarget.VisionTransform.position, SemiFunc.IsMultiplayer() ? instance.physGrabber.photonView.ViewID : (-1)); } } RemoveMarkedItems(marker); } } } namespace Mutators.Utility.Config { public class ConfigRange where T : struct, IComparable, IComparable, IConvertible, IEquatable, IFormattable { private readonly ConfigEntry _min; private readonly ConfigEntry _max; public T MinimumValue => _min.Value; public T MaximumValue => _max.Value; internal ConfigRange(ConfigEntry min, ConfigEntry max) { _min = min; _max = max; } } internal class PositiveIntValue : AcceptableValueBase { private const int MinValue = 0; public PositiveIntValue() : base(typeof(int)) { } public override object Clamp(object value) { if (!(value is int num)) { return 0; } return (num >= 0) ? num : 0; } public override bool IsValid(object value) { if (value is int) { return (int)value >= 0; } return false; } public override string ToDescriptionString() { return "# Acceptable values are integers of 0 or higher"; } } } namespace Mutators.Settings { public abstract class AbstractMutatorSettings { protected const string WeightConfigKey = "Weight"; protected const string MinimumLevelConfigKey = "Minimum level"; protected const string MaximumLevelConfigKey = "Maximum level"; private readonly IDictionary _runtimeOverrides = new Dictionary(); public string NamespacedName { get; } public string MutatorName { get; } public string MutatorDescription { get; } public abstract int Weight { get; } public abstract int MinimumLevel { get; } public abstract int MaximumLevel { get; } public AbstractMutatorSettings(string @namespace, string name, string description) { NamespacedName = name.ToSlug(@namespace); MutatorName = name; MutatorDescription = description; } public virtual void ApplyRuntimeOverrides(IDictionary? overrides) { if (overrides == null || overrides.Count == 0) { return; } foreach (KeyValuePair @override in overrides) { _runtimeOverrides[@override.Key] = @override.Value; } } public virtual void ClearRuntimeOverrides() { _runtimeOverrides.Clear(); } protected T GetRuntimeOverride(string key, T fallback) { if (!_runtimeOverrides.TryGetValue(key, out object value)) { return fallback; } if (value.TryCoerce(typeof(T), out object coerced) && coerced is T) { return (T)coerced; } return fallback; } protected IList GetRuntimeOverrideList(string key, IList fallback) { if (!_runtimeOverrides.TryGetValue(key, out object value)) { return fallback; } if (value is IList result) { return result; } if (value is IEnumerable source) { return source.ToList(); } if (value is string text && typeof(T) == typeof(string)) { return (from text2 in text.Split(",") select text2.Trim() into text2 where text2.Length > 0 select text2).Cast().ToList(); } if (value is IEnumerable enumerable) { IList list = new List(); { foreach (object item3 in enumerable) { if (item3.TryCoerce(typeof(T), out object coerced) && coerced is T item) { list.Add(item); continue; } return fallback; } return list; } } if (!value.TryCoerce(typeof(T), out object coerced2) || !(coerced2 is T item2)) { return fallback; } return new List(1) { item2 }; } public virtual bool IsEligibleForSelection() { int levelsCompleted = RunManager.instance.levelsCompleted; if (MaximumLevel > 0 && MinimumLevel > MaximumLevel) { RepoMutators.Logger.LogWarning(MutatorName + " was configured with a minimum level larger than the maximum level!"); RepoMutators.Logger.LogWarning("This configuration is consider invalid, the level bounds will be ignored."); return true; } if (MaximumLevel == 0) { return levelsCompleted >= MinimumLevel; } if (levelsCompleted >= MinimumLevel) { return levelsCompleted <= MaximumLevel; } return false; } public IDictionary? AsMetadata() { return CreateMetadata()?.WithMutator(NamespacedName); } protected virtual IDictionary? CreateMetadata() { return null; } } public class EnemyDisablingMutatorSettings : GenericMutatorSettings { public const string ExcludedEnemiesKey = "excluded-enemies"; private readonly ConfigEntry _excludedEnemies; private IList _excludedEnemiesList = new List(); public IList ExcludedEnemies => GetRuntimeOverrideList("excluded-enemies", _excludedEnemiesList); public EnemyDisablingMutatorSettings(string @namespace, string name, string description, int weight, ConfigFile config, params string[] defaultDisabledEnemies) : base(@namespace, name, description, weight, config) { _excludedEnemies = config.Bind(GenericMutatorSettings.GetSection(name), "Excluded enemies", string.Join(", ", defaultDisabledEnemies), "Enemies that cannot be spawned by the " + name + " Mutator. (Comma separated e.g. Apex Predator,Huntsman)"); _excludedEnemies.SettingChanged += delegate { CacheEnemies(); }; CacheEnemies(); } public EnemyDisablingMutatorSettings(string @namespace, string name, string description, ConfigFile config, params string[] defaultDisabledEnemies) : this(@namespace, name, description, 100, config, defaultDisabledEnemies) { } internal void CacheEnemies() { _excludedEnemiesList = (from value in _excludedEnemies.Value.Split(",") select value.Trim()).ToList(); } } public class GenericMutatorSettings : AbstractMutatorSettings { private readonly ConfigEntry _weight; private readonly ConfigEntry _minimumLevel; private readonly ConfigEntry _maximumLevel; public override int Weight => _weight.Value; public override int MinimumLevel => _minimumLevel.Value; public override int MaximumLevel => _maximumLevel.Value; public GenericMutatorSettings(string @namespace, string name, string description, int weight, ConfigFile config) : base(@namespace, name, description) { _weight = config.BindPositive(GetSection(name), "Weight", weight, "Weighted chance for the " + name + " Mutator to be active."); _minimumLevel = config.BindPositive(GetSection(name), "Minimum level", 0, "The minimum level on which the " + name + " Mutator can show up"); _maximumLevel = config.BindPositive(GetSection(name), "Maximum level", 1000, "The maximum level on which the " + name + " mutator can show up (0 = no upper bound)"); } public GenericMutatorSettings(string @namespace, string name, string description, ConfigFile config) : this(@namespace, name, description, 100, config) { } protected T GetClampedRuntimeOverride(string key, ConfigEntry entry) { T runtimeOverride = GetRuntimeOverride(key, entry.Value); if (((ConfigEntryBase)entry).Description.AcceptableValues == null) { return runtimeOverride; } return (T)((ConfigEntryBase)entry).Description.AcceptableValues.Clamp((object)runtimeOverride); } protected static string GetSection(string name) { return name + " Mutator"; } } internal interface ILevelRemovingMutatorSettings { bool AllowCustomLevels { get; } IList ExcludedLevels { get; } } internal class ModSettings { internal enum MutatorNameToggleType { Keybind, WithDescription } internal enum MultiMutatorScalingType { None, Random, Moon } internal sealed class MoonSetting(ConfigRange multiMutatorMoonRange, ConfigEntry generatedChance) { private ConfigRange MultiMutatorMoonRange => multiMutatorMoonRange; internal int GeneratedChance => generatedChance.Value; internal int MaximumMutators => MultiMutatorMoonRange.MaximumValue; internal int MinimumMutators => MultiMutatorMoonRange.MinimumValue; } internal sealed class MoonSettings { private readonly IDictionary _multiMutatorMoonRanges = new Dictionary(); private int _moonCount; internal void LateBindMoonConfig(ConfigFile config, int moonCount) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown _moonCount = moonCount; for (int i = 0; i <= _moonCount; i++) { ConfigEntry generatedChance = config.Bind(GetMoonSection(i), "Generated Multi-Mutator Chance (%)", 50, new ConfigDescription($"The chance that a Generated Multi-Mutator will occur when the moon level is {i}", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ConfigRange multiMutatorMoonRange = new ConfigRange(CreateMoonRange(config, i, min: true), CreateMoonRange(config, i, min: false)); _multiMutatorMoonRanges[i] = new MoonSetting(multiMutatorMoonRange, generatedChance); } RepoMutators.Logger.LogDebug($"Late-bound moon config with {moonCount} moons."); } internal MoonSetting GetMultiMutatorMoonRange(int moon) { int key = Math.Clamp(moon, 0, _moonCount); return _multiMutatorMoonRanges[key]; } } internal sealed class RandomSettings { private const string ConfigSection = "Multi-Mutators - Random"; private readonly ConfigEntry _minimumAmount; private readonly ConfigEntry _maximumAmount; private readonly IDictionary> _weight = new Dictionary>(MaximumGeneratedActiveSubMutators); private readonly IDictionary> _generatedChance = new Dictionary>(MaximumGeneratedActiveSubMutators); internal int MinimumAmount => _minimumAmount.Value; internal int MaximumAmount => _maximumAmount.Value; internal RandomSettings(ConfigFile config) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown _minimumAmount = config.Bind("Multi-Mutators - Random", "Minimum amount of Mutators", 1, new ConfigDescription("The minimum amount of Mutators that can be selected when using random scaling.", (AcceptableValueBase)(object)new AcceptableValueRange(1, (int)MaximumGeneratedActiveSubMutators), Array.Empty())); _maximumAmount = config.Bind("Multi-Mutators - Random", "Maximum amount of Mutators", 4, new ConfigDescription("The maximum amount of Mutators that can be selected when using random scaling.", (AcceptableValueBase)(object)new AcceptableValueRange(1, (int)MaximumGeneratedActiveSubMutators), Array.Empty())); for (byte b = 1; b <= MaximumGeneratedActiveSubMutators; b++) { _weight[b] = config.Bind("Multi-Mutators - Random", $"{b} Mutators - Weight", 50, new ConfigDescription(string.Format("The weighted chance for {0} {1} to be selected when using random scaling.", b, (b == 1) ? "Mutator" : "Mutators"), (AcceptableValueBase)(object)new AcceptableValueRange(0, 1000), Array.Empty())); if (b > 1) { _generatedChance[b] = config.Bind("Multi-Mutators - Random", $"{b} Mutators - Generated Multi-Mutator Chance (%)", 50, new ConfigDescription($"The chance that a Generated Multi-Mutator will occur when picking {b} Mutators.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); } } } internal int GetWeight(int amountOfMutators) { if (amountOfMutators < 0 || amountOfMutators > MaximumGeneratedActiveSubMutators) { throw new ArgumentException($"Amount of Mutators should be between 0 and {MaximumGeneratedActiveSubMutators}", "amountOfMutators"); } return _weight[(byte)amountOfMutators].Value; } internal int GetGeneratedChance(int amountOfMutators) { if (amountOfMutators < 2) { return 0; } if (amountOfMutators <= MaximumGeneratedActiveSubMutators) { return _generatedChance[(byte)amountOfMutators].Value; } throw new ArgumentException($"Amount of Mutators should not be greater than {MaximumGeneratedActiveSubMutators}", "amountOfMutators"); } } internal static readonly byte MaximumGeneratedActiveSubMutators = 10; private readonly ConfigEntry _extendedLogging; private readonly ConfigEntry _mutatorDisplayY; private readonly ConfigEntry _mutatorDisplaySize; private readonly ConfigEntry _mutatorDisplayToggleKey; private readonly ConfigEntry _mutatorDisplayToggleType; private readonly ConfigEntry _mutatorDescriptionDisplayY; private readonly ConfigEntry _mutatorDescriptionDisplaySize; private readonly ConfigEntry _mutatorDescriptionInitialDisplayTime; private readonly ConfigEntry _mutatorDescriptionPinned; private readonly ConfigEntry _mutatorDescriptionInMapTool; private readonly ConfigEntry _targetDisplaySize; private readonly ConfigEntry _specialActionY; private readonly ConfigEntry _specialActionKey; private readonly ConfigEntry _multiMutatorSelectionMode; public RandomSettings RandomMutatorSettings { get; } public MoonSettings MoonMutatorSettings { get; } public bool ExtendedLogging => _extendedLogging.Value; public float MutatorDisplayY => _mutatorDisplayY.Value; public float MutatorDisplaySize => _mutatorDisplaySize.Value; public KeyCode MutatorDisplayToggleKey { get; private set; } public MutatorNameToggleType MutatorDisplayToggleType { get; private set; } public float MutatorDescriptionDisplayY => _mutatorDescriptionDisplayY.Value; public float MutatorDescriptionDisplaySize => _mutatorDescriptionDisplaySize.Value; public float MutatorDescriptionInitialDisplayTime => _mutatorDescriptionInitialDisplayTime.Value; public bool MutatorDescriptionPinned => _mutatorDescriptionPinned.Value; public bool MutatorDescriptionInMapTool => _mutatorDescriptionInMapTool.Value; public float TargetDisplaySize => _targetDisplaySize.Value; public float SpecialActionY => _specialActionY.Value; public KeyCode SpecialActionKey { get; private set; } public MultiMutatorScalingType MutatorScalingType { get; private set; } internal ModSettings(ConfigFile config) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Expected O, but got Unknown _extendedLogging = config.Bind("Logging", "Extended Logging", false, "Enable extended logging."); _mutatorDisplayY = config.Bind("Mutator Interface", "Y position", -75f, "The Y position of the active Mutator overlay"); _mutatorDisplaySize = config.Bind("Mutator Interface", "Size", 30f, "The size of the active Mutator overlay"); _mutatorDisplayToggleType = config.Bind("Mutator Interface", "Mutator display toggle type", "Keybind", new ConfigDescription("The method used to toggle the active Mutator overlay", (AcceptableValueBase)(object)new AcceptableValueList(new string[2] { "Keybind", "With Description" }), Array.Empty())); _mutatorDisplayToggleKey = config.Bind("Mutator Interface", "Mutator display toggle key", "H", "The key use to toggle the active Mutator overlay"); _mutatorDescriptionDisplayY = config.Bind("Mutator Interface", "Description Y position", -110f, "The Y position of the active Mutator's description overlay"); _mutatorDescriptionDisplaySize = config.Bind("Mutator Interface", "Description size", 20f, "The size of the active Mutator's description overlay"); _mutatorDescriptionInitialDisplayTime = config.Bind("Mutator Interface", "Description initial display time", 8f, "The time for which the mutator's description is on screen when starting the level"); _mutatorDescriptionPinned = config.Bind("Mutator Interface", "Description always active", false, "If true, \"Description initial display time\" will be ignored and the description will always stay on screen"); _mutatorDescriptionInMapTool = config.Bind("Mutator Interface", "Description active in map tool", true, "If true, the mutator's description will be displayed when opening the map tool"); _targetDisplaySize = config.Bind("Mutator Interface", "Target Size", 40f, "The size of the target (e.g. president health) overlay"); _specialActionY = config.Bind("Special Action", "Special Action Y position", -50f, "The Y position of the Special Action overlay"); _specialActionKey = config.Bind("Special Action", "Special Action Key", "R", "Keybind that activates the Special Action"); _multiMutatorSelectionMode = config.Bind("Multi-Mutators", "Scaling Mode", "Moon", new ConfigDescription("The method used to scale the amount of mutators. None = No scaling, Random = Random scaling, Moon = Scaling based on moon", (AcceptableValueBase)(object)new AcceptableValueList(new string[3] { "None", "Random", "Moon" }), Array.Empty())); RandomMutatorSettings = new RandomSettings(config); MoonMutatorSettings = new MoonSettings(); CacheKeys(); config.SettingChanged += delegate { CacheKeys(); }; } internal void LateBindMoonConfig(ConfigFile config, int moonCount) { MoonMutatorSettings.LateBindMoonConfig(config, moonCount); } internal void CacheKeys() { //IL_0023: 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) MutatorDisplayToggleKey = (KeyCode)(Enum.TryParse(typeof(KeyCode), _mutatorDisplayToggleKey.Value, out object result) ? ((int)(KeyCode)result) : 0); MutatorDisplayToggleType = (Enum.TryParse(typeof(MutatorNameToggleType), _mutatorDisplayToggleType.Value.Replace(" ", ""), out object result2) ? ((MutatorNameToggleType)result2) : MutatorNameToggleType.Keybind); SpecialActionKey = (KeyCode)(Enum.TryParse(typeof(KeyCode), _specialActionKey.Value, out object result3) ? ((int)(KeyCode)result3) : 0); MutatorScalingType = (Enum.TryParse(typeof(MultiMutatorScalingType), _multiMutatorSelectionMode.Value, out object result4) ? ((MultiMutatorScalingType)result4) : MultiMutatorScalingType.None); } private static ConfigEntry CreateMoonRange(ConfigFile config, int moon, bool min) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown return config.Bind(GetMoonSection(moon), min ? "Minimum Mutators" : "Maximum Mutators", GetMoonDefaultValue(moon, min), new ConfigDescription(string.Format("The {0} amount of mutators that can be selected for moon {1}", min ? "minimum" : "maximum", moon), (AcceptableValueBase)(object)new AcceptableValueRange(0, (int)MaximumGeneratedActiveSubMutators), Array.Empty())); } private static int GetMoonDefaultValue(int moon, bool min) { if (!min) { return Math.Min(4, moon + 1); } return Math.Max(moon, 1); } private static string GetMoonSection(int moon) { return "Multi-Mutators - " + ((moon == 0) ? "No Moon" : $"Moon {moon}"); } } internal class MultiMutatorSettings : AbstractMutatorSettings { public override int Weight { get; } public override int MinimumLevel { get; } public override int MaximumLevel { get; } public MultiMutatorSettings(string @namespace, string name, string description, int weight = 0, int minimumLevel = 0, int maximumLevel = 1000) : base(@namespace, name, description) { Weight = weight; MinimumLevel = minimumLevel; MaximumLevel = maximumLevel; } } public static class MutatorSettings { public static NopMutatorSettings NopMutator { get; private set; } public static ApolloElevenMutatorSettings ApolloEleven { get; private set; } public static OutWithABangMutatorSettings OutWithABang { get; private set; } public static DuckThisMutatorSettings DuckThis { get; private set; } public static UltraViolenceMutatorSettings UltraViolence { get; private set; } public static ProtectThePresidentMutatorSettings ProtectThePresident { get; private set; } public static OneShotOneKillMutatorSettings OneShotOneKill { get; private set; } public static GenericMutatorSettings RustyServos { get; private set; } public static HandleWithCareMutatorSettings HandleWithCare { get; private set; } public static EnemyDisablingMutatorSettings HuntingSeason { get; private set; } public static ThereCanOnlyBeOneMutatorSettings ThereCanOnlyBeOne { get; private set; } public static GenericMutatorSettings VolatileCargo { get; private set; } public static SealedAwayMutatorSettings SealedAway { get; private set; } public static GenericMutatorSettings ProtectTheWeak { get; private set; } public static FiringMyLaserMutatorSettings FiringMyLaser { get; private set; } public static VoiceoverMutatorSettings Voiceover { get; private set; } public static TheFloorIsLavaMutatorSettings TheFloorIsLava { get; private set; } public static LessIsMoreMutatorSettings LessIsMore { get; private set; } public static AmalgamMutatorSettings Amalgam { get; private set; } public static GenericMutatorSettings NullSignal { get; private set; } public static SizeMattersMutatorSettings SizeMatters { get; private set; } internal static void Initialize(ConfigFile config) { NopMutator = new NopMutatorSettings(config); ApolloEleven = new ApolloElevenMutatorSettings("Apollo 11", "Level-wide Zero-Gravity", config); OutWithABang = new OutWithABangMutatorSettings("Out With a Bang!", "Monsters explode on death", config); DuckThis = new DuckThisMutatorSettings("Duck This", "Ducks aggro on sight instead of on interaction\nAlways spawn at least 1 duck", config); UltraViolence = new UltraViolenceMutatorSettings("Ultra-Violence", "Immediately activates the final extraction phase", config); ProtectThePresident = new ProtectThePresidentMutatorSettings("Protect the President", "A random player becomes the \"President\"\nIf they die, everyone else self-destructs", config); OneShotOneKill = new OneShotOneKillMutatorSettings("One Shot, One Kill", "Any damage taken by a player is lethal", config); RustyServos = new GenericMutatorSettings("Xepos.REPO-Mutators", "Rusty Servos", "Players cannot jump\n+3 Grab Range", config); HandleWithCare = new HandleWithCareMutatorSettings("Handle With Care", "Valuables are worth more but break on any impact", config); HuntingSeason = new EnemyDisablingMutatorSettings("Xepos.REPO-Mutators", "Hunting Season", "No valuables spawn, weapons spawn instead\nEnemy respawn time reduced to 10 seconds", config, "Voodoo", "Weeping Angel"); ThereCanOnlyBeOne = new ThereCanOnlyBeOneMutatorSettings("There Can Only Be One", "All monster spawns are of the same type", config); VolatileCargo = new GenericMutatorSettings("Xepos.REPO-Mutators", "Volatile Cargo", "Valuables explode on destruction\nExplosion radius and strength based on value", config); SealedAway = new SealedAwayMutatorSettings("Sealed Away", "Breaking valuables has a chance to spawn monsters", config); ProtectTheWeak = new ProtectTheWeakMutatorSettings("Protect the Weak", "Protect your weaker friends!", config); FiringMyLaser = new FiringMyLaserMutatorSettings("Firing My Laser", "Fire your laser by pressing {specialActionKey}\nUncontrollably fire your laser when taking damage", config); Voiceover = new VoiceoverMutatorSettings("Voiceover", "Player voices are shuffled", config); TheFloorIsLava = new TheFloorIsLavaMutatorSettings("The Floor Is Lava", "You take damage while standing on the floor", config); LessIsMore = new LessIsMoreMutatorSettings("Less Is More", "Valuables are worth less but gain value when hit\nNormal breaking mechanics apply", config); Amalgam = new AmalgamMutatorSettings("Amalgam", "You’ve been here before — just not all at once", config); NullSignal = new GenericMutatorSettings("Xepos.REPO-Mutators", "Null Signal", "Active Mutator information is hidden", config); SizeMatters = new SizeMattersMutatorSettings("Size Matters", "All players are shrunk", config); } } } namespace Mutators.Settings.Specific { public class AmalgamMutatorSettings : GenericMutatorSettings, ILevelRemovingMutatorSettings { public const string ExcludedLevelsKey = "excluded-levels"; private readonly ConfigEntry _excludedLevels; private IList _excludedLevelsList; public bool AllowCustomLevels => true; public IList ExcludedLevels => GetExcludedLevelsWithDefault(GetRuntimeOverrideList("excluded-levels", _excludedLevelsList)); internal AmalgamMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { _excludedLevels = config.Bind(GenericMutatorSettings.GetSection(name), "Excluded levels", "", "Levels that should be excluded from the " + name + " Mutator. These can neither be picked as a base, nor will their rooms be used in the level generation"); _excludedLevelsList = ExcludedLevelsAsList(); _excludedLevels.SettingChanged += SettingChanged; } private void SettingChanged(object sender, EventArgs e) { _excludedLevelsList = ExcludedLevelsAsList(); } private IList ExcludedLevelsAsList() { return (from value in _excludedLevels.Value.Split(",") select value.Trim()).ToList(); } private static IList GetExcludedLevelsWithDefault(IList excluded) { IList list = excluded.ToList(); if (!list.Contains("Backrooms")) { list.Add("Backrooms"); } if (!list.Contains("PeachCastle")) { list.Add("PeachCastle"); } return list; } } public class ApolloElevenMutatorSettings : GenericMutatorSettings { public const string ApplyToEnemiesKey = "apply-to-enemies"; public const string ApplyInCartKey = "apply-in-cart"; private readonly ConfigEntry _applyToEnemies; private readonly ConfigEntry _applyInCart; private readonly ConfigEntry _downwardsKey; public bool ApplyToEnemies => GetRuntimeOverride("apply-to-enemies", _applyToEnemies.Value); public bool ApplyInCart => GetRuntimeOverride("apply-in-cart", _applyInCart.Value); public KeyCode DownwardsKey { get; private set; } internal ApolloElevenMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { _applyToEnemies = config.Bind(GenericMutatorSettings.GetSection(name), "Apply to monsters", false, "If true, Zero-Gravity will also be applied to monsters while the " + name + " Mutator is active."); _applyInCart = config.Bind(GenericMutatorSettings.GetSection(name), "Apply in cart/extraction", true, "If true, Zero-Gravity will also apply to valuables in the cart and extraction points."); _downwardsKey = config.Bind(GenericMutatorSettings.GetSection(name), "Downwards momentum keybind", "LeftControl", "(Client sided) If bound, this key can be used to control yourself downwards while the " + name + " Mutator is active"); CacheKey(); } internal void CacheKey() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (Enum.TryParse(typeof(KeyCode), _downwardsKey.Value, out object result)) { DownwardsKey = (KeyCode)result; } else { DownwardsKey = (KeyCode)0; } } } public class DuckThisMutatorSettings : GenericMutatorSettings { public const string AggroCooldownKey = "aggro-cooldown"; private readonly ConfigEntry _duckAggroCooldown; public float AggroCooldown => GetClampedRuntimeOverride("aggro-cooldown", _duckAggroCooldown); internal DuckThisMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown _duckAggroCooldown = config.Bind(GenericMutatorSettings.GetSection(name), "Duck aggro cooldown", 50f, new ConfigDescription("The cooldown between duck aggro while the Duck This Mutator is active.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 300f), Array.Empty())); } } public class FiringMyLaserMutatorSettings : GenericMutatorSettings { public const string LaserActionCooldownKey = "laser-action-cooldown"; public const string LaserActionEnemyDamageKey = "laser-enemy-damage"; public const string LaserActionEnabledKey = "laser-action-enabled"; public const string LaserOnHurtEnabledKey = "laser-on-hurt-enabled"; private readonly ConfigEntry _laserActionCooldown; private readonly ConfigEntry _laserActionEnemyDamage; private readonly ConfigEntry _laserActionEnabled; private readonly ConfigEntry _laserOnHurtEnabled; public int LaserActionCooldown => GetClampedRuntimeOverride("laser-action-cooldown", _laserActionCooldown); public int LaserActionEnemyDamage => GetClampedRuntimeOverride("laser-enemy-damage", _laserActionEnemyDamage); public bool LaserActionEnabled => GetRuntimeOverride("laser-action-enabled", _laserActionEnabled.Value); public bool LaserOnHurtEnabled => GetRuntimeOverride("laser-on-hurt-enabled", _laserOnHurtEnabled.Value); internal FiringMyLaserMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown _laserActionEnabled = config.Bind(GenericMutatorSettings.GetSection(name), "Allow manual laser action", true, "If true, players can manually use their laser action while the cooldown is over. Otherwise, only use the laser when getting hit"); _laserOnHurtEnabled = config.Bind(GenericMutatorSettings.GetSection(name), "Fire laser on hurt", true, "If true, players will automatically fire their laser when getting hurt."); _laserActionCooldown = config.Bind(GenericMutatorSettings.GetSection(name), "Laser action cooldown", 60, new ConfigDescription("The amount of seconds before the laser special action can be used again.", (AcceptableValueBase)(object)new AcceptableValueRange(5, 10000), Array.Empty())); _laserActionEnemyDamage = config.Bind(GenericMutatorSettings.GetSection(name), "Laser action enemy damage", 30, new ConfigDescription("The amount of damage the laser special action deals to enemies per tick.", (AcceptableValueBase)(object)new AcceptableValueRange(10, 200), Array.Empty())); } protected override IDictionary CreateMetadata() { return new Dictionary { { "laser-action-enabled", LaserActionEnabled }, { "laser-on-hurt-enabled", LaserOnHurtEnabled } }; } } public class HandleWithCareMutatorSettings : GenericMutatorSettings { public const string ValueMultiplierKey = "value-multiplier"; public const string InstantlyDestroySurplusKey = "instantly-destroy-surplus"; public const string MultiplySurplusValueKey = "multiply-surplus-value"; private readonly ConfigEntry _valueMultiplier; private readonly ConfigEntry _instaDestroySurplus; private readonly ConfigEntry _multiplySurplus; public float ValueMultiplier => GetClampedRuntimeOverride("value-multiplier", _valueMultiplier); public bool InstantlyDestroySurplus => GetClampedRuntimeOverride("instantly-destroy-surplus", _instaDestroySurplus); public bool MultiplySurplusValue => GetClampedRuntimeOverride("multiply-surplus-value", _multiplySurplus); internal HandleWithCareMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown _valueMultiplier = config.Bind(GenericMutatorSettings.GetSection(name), "Value Multiplier", 2f, new ConfigDescription("The amount by which the value of valuables should be multiplier when " + name + " is active.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); _instaDestroySurplus = config.Bind(GenericMutatorSettings.GetSection(name), "Instantly Destroy Surplus on Damage", false, "If true, while the " + name + " Mutator is active, the surplus will instantly be destroyed when taking any damage, just like other valuables."); _multiplySurplus = config.Bind(GenericMutatorSettings.GetSection(name), "Multiply Surplus Value", false, "If true, while the " + name + " Mutator is active, the surplus value will be multiplied, just like other valuables."); } } public class LessIsMoreMutatorSettings : GenericMutatorSettings { public const string StrongDivisionFactorKey = "strong-division-factor"; public const string WeakDivisionFactorKey = "weak-division-factor"; private readonly ConfigEntry _strongDivisionFactor; private readonly ConfigEntry _weakDivisionFactor; private readonly ConfigEntry _valueGainMultiplier; public float StrongDivisionFactor => GetClampedRuntimeOverride("strong-division-factor", _strongDivisionFactor); public float WeakDivisionFactor => GetClampedRuntimeOverride("weak-division-factor", _weakDivisionFactor); public float ValueGainMultiplier => _valueGainMultiplier.Value; internal LessIsMoreMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown _weakDivisionFactor = config.Bind(GenericMutatorSettings.GetSection(name), "Weak Durability Division Factor", 1f, new ConfigDescription("The amount by which the value of weak durability valuables should be divided when the " + name + " Mutator is active. Acts as an lower bound.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 5f), Array.Empty())); _strongDivisionFactor = config.Bind(GenericMutatorSettings.GetSection(name), "Strong Durability Division Factor", 2f, new ConfigDescription("The amount by which the value of strong durability valuables should be divided when the " + name + " Mutator is active. Acts as a upper bound.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 5f), Array.Empty())); _valueGainMultiplier = config.Bind(GenericMutatorSettings.GetSection(name), "Value Gain Multiplier", 2f, new ConfigDescription("The amount by which the normal value gain should be multiplied when the " + name + " Mutator is active.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); } protected override IDictionary? CreateMetadata() { return new Dictionary { { "value-gain-multiplier", ValueGainMultiplier } }; } } public sealed class NopMutatorSettings : AbstractMutatorSettings { private readonly ConfigEntry _weight; private readonly ConfigEntry _minimumLevel; private readonly ConfigEntry _maximumLevel; public override int Weight => _weight.Value; public override int MinimumLevel => _minimumLevel.Value; public override int MaximumLevel => _maximumLevel.Value; internal NopMutatorSettings(ConfigFile config) : base("Xepos.REPO-Mutators", "None", "A normal run, no special effects") { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown _weight = config.Bind("No Mutator", "Chance (%)", 50, new ConfigDescription("Percentage chance for no mutator to be active. Unlike other mutators, this one is not weighted", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); _minimumLevel = config.BindPositive("No Mutator", "Minimum level", 0, "The minimum level on which no mutator can show up"); _maximumLevel = config.BindPositive("No Mutator", "Maximum level", 1000, "The maximum level on which no mutator can show up (0 = no upper bound)"); } } public class OneShotOneKillMutatorSettings : EnemyDisablingMutatorSettings { public const string InstaReviveInTruckOrExtractionKey = "revive-in-truck-or-extraction"; public const string InstaReviveHealthKey = "revive-health"; private readonly ConfigEntry _instaReviveInTruckOrExtraction; private readonly ConfigEntry _instaReviveHealth; public bool InstaReviveInTruckOrExtraction => GetRuntimeOverride("revive-in-truck-or-extraction", _instaReviveInTruckOrExtraction.Value); public int InstaReviveHealth => GetClampedRuntimeOverride("revive-health", _instaReviveHealth); internal OneShotOneKillMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config, "Peeper") { _instaReviveInTruckOrExtraction = config.Bind(GenericMutatorSettings.GetSection(name), "Instant revive in truck or extraction", false, "If true, while the " + name + " Mutator is active, players are instantly revived with full head if their head is brought to the truck or an active extraction point."); _instaReviveHealth = config.BindPositive(GenericMutatorSettings.GetSection(name), "Instant revive health", 0, "The amount of health the player should be revived with when Instant revive is enabled. (0 = Revive with max health)"); } } public class OutWithABangMutatorSettings : GenericMutatorSettings { public const string Tier1Radius = "tier-1-enemy-explosion-radius"; public const string Tier1Damage = "tier-1-enemy-explosion-damage"; public const string Tier2Radius = "tier-2-enemy-explosion-radius"; public const string Tier2Damage = "tier-2-enemy-explosion-damage"; public const string Tier3Radius = "tier-3-enemy-explosion-radius"; public const string Tier3Damage = "tier-3-enemy-explosion-damage"; private readonly ConfigEntry _tier1ExplosionRadius; private readonly ConfigEntry _tier1ExplosionDamage; private readonly ConfigEntry _tier2ExplosionRadius; private readonly ConfigEntry _tier2ExplosionDamage; private readonly ConfigEntry _tier3ExplosionRadius; private readonly ConfigEntry _tier3ExplosionDamage; public float Tier1ExplosionRadius => _tier1ExplosionRadius.Value; public int Tier1ExplosionDamage => _tier1ExplosionDamage.Value; public float Tier2ExplosionRadius => _tier2ExplosionRadius.Value; public int Tier2ExplosionDamage => _tier2ExplosionDamage.Value; public float Tier3ExplosionRadius => _tier3ExplosionRadius.Value; public int Tier3ExplosionDamage => _tier3ExplosionDamage.Value; internal OutWithABangMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { _tier1ExplosionRadius = config.Bind(GenericMutatorSettings.GetSection(name), "Tier 1 Enemy Explosion Radius", 1f, "The on-death explosion radius of Tier 1 enemies during the " + name + " Mutator."); _tier1ExplosionDamage = config.BindPositive(GenericMutatorSettings.GetSection(name), "Tier 1 Enemy Explosion Damage", 50, "The on-death explosion damage of Tier 1 enemies during the " + name + " Mutator."); _tier2ExplosionRadius = config.Bind(GenericMutatorSettings.GetSection(name), "Tier 2 Enemy Explosion Radius", 2f, "The on-death explosion radius of Tier 2 enemies during the " + name + " Mutator."); _tier2ExplosionDamage = config.BindPositive(GenericMutatorSettings.GetSection(name), "Tier 2 Enemy Explosion Damage", 100, "The on-death explosion damage of Tier 2 enemies during the " + name + " Mutator."); _tier3ExplosionRadius = config.Bind(GenericMutatorSettings.GetSection(name), "Tier 3 Enemy Explosion Radius", 3f, "The on-death explosion radius of Tier 3 enemies during the " + name + " Mutator."); _tier3ExplosionDamage = config.BindPositive(GenericMutatorSettings.GetSection(name), "Tier 3 Enemy Explosion Damage", 200, "The on-death explosion damage of Tier 3 enemies during the " + name + " Mutator."); } protected override IDictionary? CreateMetadata() { return new Dictionary { { "tier-1-enemy-explosion-radius", Tier1ExplosionRadius }, { "tier-1-enemy-explosion-damage", Tier1ExplosionDamage }, { "tier-2-enemy-explosion-radius", Tier2ExplosionRadius }, { "tier-2-enemy-explosion-damage", Tier2ExplosionDamage }, { "tier-3-enemy-explosion-radius", Tier3ExplosionRadius }, { "tier-3-enemy-explosion-damage", Tier3ExplosionDamage } }; } } public class ProtectThePresidentMutatorSettings : GenericMutatorSettings { private readonly ConfigEntry _minimumPlayerCount; public byte MinimumPlayerCount => (byte)_minimumPlayerCount.Value; internal ProtectThePresidentMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown _minimumPlayerCount = config.Bind(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", 3, new ConfigDescription("The minimum amount of players required for the " + name + " Mutator to be available for selection.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20), Array.Empty())); } public override bool IsEligibleForSelection() { if (base.IsEligibleForSelection()) { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { return currentRoom.PlayerCount >= MinimumPlayerCount; } return false; } return false; } } public class ProtectTheWeakMutatorSettings : GenericMutatorSettings { private readonly ConfigEntry _minimumPlayerCount; public byte MinimumPlayerCount => (byte)_minimumPlayerCount.Value; internal ProtectTheWeakMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown _minimumPlayerCount = config.Bind(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", 3, new ConfigDescription("The minimum amount of players required for the " + name + " Mutator to be available for selection.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20), Array.Empty())); } public override bool IsEligibleForSelection() { if (base.IsEligibleForSelection()) { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { return currentRoom.PlayerCount >= MinimumPlayerCount; } return false; } return false; } } public class SealedAwayMutatorSettings : EnemyDisablingMutatorSettings { public const string MaximumMonsterSpawnsKey = "maximum-monster-spawns"; public const string MonsterSpawnChanceKey = "monster-spawn-chance"; private readonly ConfigEntry _maximumMonsterSpawns; private readonly ConfigEntry _monsterSpawnChance; public int MaximumMonsterSpawns => GetClampedRuntimeOverride("maximum-monster-spawns", _maximumMonsterSpawns); public float MonsterSpawnChance => GetClampedRuntimeOverride("monster-spawn-chance", _monsterSpawnChance); internal SealedAwayMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config, "Voodoo", "Shadow Child") { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown _maximumMonsterSpawns = config.Bind(GenericMutatorSettings.GetSection(name), "Maximum monster spawns", 5, new ConfigDescription("Maximum amount of extra monsters that can be spawned by the " + name + " Mutator per level.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 15), Array.Empty())); _monsterSpawnChance = config.Bind(GenericMutatorSettings.GetSection(name), "Monster spawn chance", 65f, new ConfigDescription("The chance that a monster is spawned when breaking a valuable when the " + name + " Mutator is active.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); } } public class SizeMattersMutatorSettings : GenericMutatorSettings { public const string ScaleValuablesKey = "scale-valuables"; public const string ScaleEnemiesKey = "scale-enemies"; public const string ScaleCartsKey = "scale-carts"; private readonly ConfigEntry _scaleValuables; private readonly ConfigEntry _scaleEnemies; private readonly ConfigEntry _scaleCart; public bool ScaleValuables => GetRuntimeOverride("scale-valuables", _scaleValuables.Value); public bool ScaleEnemies => GetRuntimeOverride("scale-enemies", _scaleEnemies.Value); public bool ScaleCarts => GetRuntimeOverride("scale-carts", _scaleCart.Value); internal SizeMattersMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { _scaleValuables = config.Bind(GenericMutatorSettings.GetSection(name), "Scale valuables", false, "If true, valuables will also be scaled."); _scaleEnemies = config.Bind(GenericMutatorSettings.GetSection(name), "Scale enemies", false, "If true, enemies will also be scaled."); _scaleCart = config.Bind(GenericMutatorSettings.GetSection(name), "Scale carts", false, "If true, carts will also be scaled."); } protected override IDictionary CreateMetadata() { return new Dictionary { { "scale-valuables", ScaleValuables }, { "scale-enemies", ScaleEnemies }, { "scale-carts", ScaleCarts } }; } } public class TheFloorIsLavaMutatorSettings : GenericMutatorSettings, ILevelRemovingMutatorSettings { public const string ImmunePlayerCountKey = "immune-player-amount"; public const string AllowCustomLevelsKey = "allow-custom-levels"; public const string DisableEnemiesKey = "disable-enemies"; private readonly ConfigEntry _immunePlayerCount; private readonly ConfigEntry _usePercentageDamage; private readonly ConfigEntry _allowCustomLevels; private readonly ConfigEntry _disableEnemies; private readonly ConfigEntry _reviveImmunityDuration; public int DamagePerTick { get; private set; } public int ImmunePlayerCount => GetClampedRuntimeOverride("immune-player-amount", _immunePlayerCount); public bool UsePercentageDamage => _usePercentageDamage.Value; public bool AllowCustomLevels => GetRuntimeOverride("allow-custom-levels", _allowCustomLevels.Value); public bool DisableEnemies => GetRuntimeOverride("disable-enemies", _disableEnemies.Value); public float ReviveImmunityDuration => _reviveImmunityDuration.Value; public IList ExcludedLevels => new List(); internal TheFloorIsLavaMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, 0, config) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown ConfigEntry val = config.BindPositive(GenericMutatorSettings.GetSection(name), "Damage", 1, "The amount of damage that players receive per second when standing on floor tiles."); _usePercentageDamage = config.Bind(GenericMutatorSettings.GetSection(name), "Use percentage damage", false, "If true, players will receive percentage max health damage instead of a flat amount."); _immunePlayerCount = config.Bind(GenericMutatorSettings.GetSection(name), "Immune player count", 0, new ConfigDescription("The amount of players that are immune to " + name + " damage.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20), Array.Empty())); _allowCustomLevels = config.Bind(GenericMutatorSettings.GetSection(name), "Allow custom levels", true, "If false, custom levels cannot be picked while the " + name + " Mutator is active."); _disableEnemies = config.Bind(GenericMutatorSettings.GetSection(name), "Disable enemies", false, "If true, no enemies will spawn while the " + name + " Mutator is active."); _reviveImmunityDuration = config.Bind(GenericMutatorSettings.GetSection(name), "Revive immunity duration", 20f, "The time in seconds for which players are immune to lava damage after reviving while the " + name + " Mutator is active."); DamagePerTick = Math.Clamp(val.Value, 1, int.MaxValue); } protected override IDictionary? CreateMetadata() { return new Dictionary { { "damage", DamagePerTick }, { "is-percentage-damage", UsePercentageDamage }, { "revive-immunity-duration", ReviveImmunityDuration } }; } } public class ThereCanOnlyBeOneMutatorSettings : EnemyDisablingMutatorSettings { public const string GroupSpawnsThresholdKey = "group-spawns-threshold"; private readonly ConfigEntry _groupSpawnsThreshold; public int GroupSpawnsThreshold => GetClampedRuntimeOverride("group-spawns-threshold", _groupSpawnsThreshold); internal ThereCanOnlyBeOneMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { _groupSpawnsThreshold = config.BindPositive(GenericMutatorSettings.GetSection(name), "Group spawn minimum level", 8, "The minimum level from which enemy groups (e.g. 3 mentalists or 10 gnomes) can be spawned by the " + name + " Mutator."); } } public class UltraViolenceMutatorSettings : EnemyDisablingMutatorSettings { private readonly ConfigEntry _keepOnLight; private readonly ConfigEntry _minimumPlayerCount; public bool KeepOnLight => _keepOnLight.Value; public byte MinimumPlayerCount => (byte)_minimumPlayerCount.Value; internal UltraViolenceMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, 0, config) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown _keepOnLight = config.Bind(GenericMutatorSettings.GetSection(name), "Keep on lights", false, "Keep on the level lighting while the " + name + " Mutator is active."); _minimumPlayerCount = config.Bind(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", 0, new ConfigDescription("The minimum amount of players required for the " + name + " Mutator to be available for selection.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20), Array.Empty())); } public override bool IsEligibleForSelection() { if (base.IsEligibleForSelection()) { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { return currentRoom.PlayerCount >= MinimumPlayerCount; } return false; } return false; } protected override IDictionary? CreateMetadata() { return new Dictionary { { "keep-lights-on", KeepOnLight } }; } } public class VoiceoverMutatorSettings : GenericMutatorSettings { private readonly ConfigEntry _minimumPlayerCount; public byte MinimumPlayerCount => (byte)_minimumPlayerCount.Value; internal VoiceoverMutatorSettings(string name, string description, ConfigFile config) : base("Xepos.REPO-Mutators", name, description, config) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown _minimumPlayerCount = config.Bind(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", 3, new ConfigDescription("The minimum amount of players required for the " + name + " Mutator to be available for selection.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20), Array.Empty())); } public override bool IsEligibleForSelection() { if (base.IsEligibleForSelection()) { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { return currentRoom.PlayerCount >= MinimumPlayerCount; } return false; } return false; } } } namespace Mutators.Services.Selection { public interface IMutatorSelectionService { IMutator GetWeightedMutator(ICollection mutators); } internal interface IRepeatSelectionTracker { IMutator? PreviousMutator { get; } bool ShouldBlockRepeat(IMutator mutator, float probability); IMutator TrackSelectedMutator(IMutator mutator); } public class MutatorSelectionContext(uint amountToPick) { public uint AmountToPick { get; } = amountToPick; } public class MutatorSelectionService : IMutatorSelectionService { private readonly IDictionary _selectionStrategies; private readonly NopMutator _nopMutator; private readonly IRepeatSelectionTracker _repeatSelectionTracker; private readonly IRandomProvider _randomProvider; internal MutatorSelectionService(NoneScalingSelectionStrategy noneScalingSelectionStrategy, MoonScalingSelectionStrategy moonScalingSelectionStrategy, RandomScalingSelectionStrategy randomScalingSelectionStrategy, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator nopMutator) { _selectionStrategies = new Dictionary { { ModSettings.MultiMutatorScalingType.None, noneScalingSelectionStrategy }, { ModSettings.MultiMutatorScalingType.Moon, moonScalingSelectionStrategy }, { ModSettings.MultiMutatorScalingType.Random, randomScalingSelectionStrategy } }; _repeatSelectionTracker = repeatSelectionTracker; _randomProvider = randomProvider; _nopMutator = nopMutator; } public IMutator GetWeightedMutator(ICollection mutators) { ModSettings.MultiMutatorScalingType mutatorScalingType = RepoMutators.Settings.MutatorScalingType; if (ShouldUseNopMutator(_nopMutator)) { return _repeatSelectionTracker.TrackSelectedMutator(_nopMutator); } IList mutators2 = mutators.Where((IMutator mutator) => !(mutator is NopMutator) && mutator.Settings.Weight > 0).ToList(); return _selectionStrategies[mutatorScalingType].Execute(mutators2); } private bool ShouldUseNopMutator(NopMutator nopMutator) { int weight = nopMutator.Settings.Weight; if (weight <= 0) { return false; } float probability = (float)weight / 100f; if (_repeatSelectionTracker.ShouldBlockRepeat(nopMutator, probability)) { RepoMutators.Logger.LogDebug("Cannot pick " + nopMutator.Name + ", threshold reached"); return false; } if (weight < 100) { return _randomProvider.Range(0f, 100f) <= (float)weight; } return true; } } internal class RepeatSelectionTracker : IRepeatSelectionTracker { private int _repeatCount; public IMutator? PreviousMutator { get; private set; } public bool ShouldBlockRepeat(IMutator mutator, float probability) { if (mutator == PreviousMutator) { return MathF.Pow(probability, _repeatCount + 1) < 0.1f; } return false; } public IMutator TrackSelectedMutator(IMutator mutator) { if (mutator == PreviousMutator) { _repeatCount++; } else { PreviousMutator = mutator; _repeatCount = 1; } return mutator; } } } namespace Mutators.Services.Selection.Strategies { internal class MoonScalingSelectionStrategy : MutatorSelectionStrategy { private readonly ModSettings.MoonSettings _moonSettings; private readonly ISemiFuncProvider _semiFuncProvider; public MoonScalingSelectionStrategy(GeneratedMultiMutatorSelectionRulesRegistry multiRegistry, SingleMutatorSelectionRulesRegistry singleRegistry, ModSettings.MoonSettings moonSettings, ISemiFuncProvider semiFuncProvider, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator fallbackMutator) : base(multiRegistry, singleRegistry, repeatSelectionTracker, randomProvider, fallbackMutator) { _moonSettings = moonSettings; _semiFuncProvider = semiFuncProvider; } public sealed override IMutator Execute(IList mutators) { int moonMutatorsAmount = GetMoonMutatorsAmount(); if (moonMutatorsAmount == 1) { return GetSingleMutator(mutators); } if (!ShouldGenerateMulti(GetMoonGeneratedChance())) { return TryPickUserDefinedMultiMutatorOrElseGenerate(mutators, moonMutatorsAmount); } return PickGeneratedMultiMutator(mutators, moonMutatorsAmount); } private int GetMoonMutatorsAmount() { ModSettings.MoonSetting multiMutatorMoonRange = _moonSettings.GetMultiMutatorMoonRange(_semiFuncProvider.MoonLevel()); return randomProvider.RandomRangeInt(multiMutatorMoonRange.MinimumMutators, multiMutatorMoonRange.MaximumMutators + 1); } private int GetMoonGeneratedChance() { return _moonSettings.GetMultiMutatorMoonRange(_semiFuncProvider.MoonLevel()).GeneratedChance; } } internal abstract class MutatorSelectionStrategy { private readonly IMutator _fallbackMutator; private readonly GeneratedMultiMutatorSelectionRulesRegistry _multiRegistry; private readonly SingleMutatorSelectionRulesRegistry _singleRegistry; protected readonly IRandomProvider randomProvider; private readonly IRepeatSelectionTracker _repeatSelectionTracker; internal MutatorSelectionStrategy(GeneratedMultiMutatorSelectionRulesRegistry multiRegistry, SingleMutatorSelectionRulesRegistry singleRegistry, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator nopMutator) { _multiRegistry = multiRegistry; _singleRegistry = singleRegistry; _repeatSelectionTracker = repeatSelectionTracker; this.randomProvider = randomProvider; _fallbackMutator = nopMutator; } public abstract IMutator Execute(IList mutators); protected IMutator PickSingleMutator(IList mutators, MutatorSelectionContext context) { if (context.AmountToPick == 1) { mutators = mutators.Where((IMutator m) => _singleRegistry.RunRules(m)).ToList(); } IMutator previousMutator = _repeatSelectionTracker.PreviousMutator; float num = mutators.Sum((IMutator item) => item.Settings.Weight); if (previousMutator != null && mutators.Contains(previousMutator) && num > 0f) { float num2 = previousMutator.Settings.Weight; if (num2 > 0f && _repeatSelectionTracker.ShouldBlockRepeat(previousMutator, num2 / num)) { RepoMutators.Logger.LogDebug("Cannot pick " + (previousMutator?.Name ?? "None") + ", threshold reached"); mutators = mutators.Where((IMutator m) => m != previousMutator).ToList(); num = mutators.Sum((IMutator m) => m.Settings.Weight); } } if (num <= 0f) { RepoMutators.Logger.LogWarning($"Fell back to None mutator, invalid total weight: {num}"); return _fallbackMutator; } float num3 = randomProvider.Range(0f, num); float num4 = 0f; foreach (IMutator mutator in mutators) { num4 += (float)mutator.Settings.Weight; if (num3 <= num4) { return _repeatSelectionTracker.TrackSelectedMutator(mutator); } } RepoMutators.Logger.LogWarning("Fell back to None mutator, mutator selection failed"); return _fallbackMutator; } protected IMutator PickGeneratedMultiMutator(IList mutators, int amountToPick) { IList excludeList = new List(1) { _fallbackMutator }; IList pickedMutators = new List(); MutatorSelectionContext context = new MutatorSelectionContext((uint)amountToPick); IList selection = mutators.GetSelection((IMutator mutator2) => !(mutator2 is IMultiMutator) && !excludeList.Contains(mutator2)); for (int num = 0; num < amountToPick; num++) { IList selection2 = selection.GetSelection((IMutator mutator2) => ApplyGenerationRules(pickedMutators, mutator2)); IMutator mutator = PickSingleMutator(selection2, context); if (mutator != _fallbackMutator) { pickedMutators.Add(mutator); } } if (pickedMutators.Count == 0) { return _fallbackMutator; } if (pickedMutators.Count == 1) { return pickedMutators.First(); } return new MultiMutator(new MultiMutatorSettings("Xepos.REPO-Mutators", string.Empty, string.Empty), ((IEnumerable)pickedMutators).ToDictionary((Func)((IMutator m) => m), (Func>)((IMutator _) => new Dictionary()))); } private bool ApplyGenerationRules(IList pickedMutators, IMutator mutator) { if (pickedMutators.Contains(mutator)) { return false; } return _multiRegistry.RunRules(new ReadOnlyCollection(pickedMutators), mutator); } protected bool ShouldGenerateMulti(int generatedChance) { if (generatedChance <= 0) { if (generatedChance < 0) { LogMisconfiguredMultiMutatorChance(generatedChance); RepoMutators.Logger.LogWarning("The minimum allowed value is 0."); } return false; } if (generatedChance > 100) { LogMisconfiguredMultiMutatorChance(generatedChance); RepoMutators.Logger.LogWarning("The maximum allowed value is 100."); return true; } if (generatedChance != 100) { return randomProvider.RandomRangeInt(1, 101) <= generatedChance; } return true; } protected IMutator GetSingleMutator(IList mutators) { return PickSingleMutator(mutators.GetSelection(delegate(IMutator mutator) { if (mutator is IMultiMutator multiMutator) { IReadOnlyDictionary> subMutators = multiMutator.SubMutators; if (subMutators != null) { int count = subMutators.Count; if (count == 1) { goto IL_001f; } } return false; } goto IL_001f; IL_001f: return true; }).ToList(), new MutatorSelectionContext(1u)); } protected IMutator TryPickUserDefinedMultiMutatorOrElseGenerate(IList mutators, int amountOfSubMutators) { IList list = mutators.GetSelection((IMutator mutator) => mutator is IMultiMutator multiMutator && multiMutator.SubMutators.Count == amountOfSubMutators).ToList(); if (list.Select((IMutator m) => m.Settings.Weight).Sum() > 0) { return PickSingleMutator(list, new MutatorSelectionContext(1u)); } RepoMutators.Logger.LogDebug($"No user defined multi-mutator found for {amountOfSubMutators} sub-mutators."); return PickGeneratedMultiMutator(mutators, amountOfSubMutators); } private static void LogMisconfiguredMultiMutatorChance(int generatedChance) { RepoMutators.Logger.LogWarning($"Generated multi-mutator chance is misconfigured: {generatedChance}."); } } internal class NoneScalingSelectionStrategy : MutatorSelectionStrategy { public NoneScalingSelectionStrategy(GeneratedMultiMutatorSelectionRulesRegistry multiRegistry, SingleMutatorSelectionRulesRegistry singleRegistry, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator fallbackMutator) : base(multiRegistry, singleRegistry, repeatSelectionTracker, randomProvider, fallbackMutator) { } public sealed override IMutator Execute(IList mutators) { return PickSingleMutator(mutators.GetSelection(delegate(IMutator mutator) { if (mutator is IMultiMutator multiMutator) { IReadOnlyDictionary> subMutators = multiMutator.SubMutators; if (subMutators != null) { int count = subMutators.Count; if (count == 1) { goto IL_001f; } } return false; } goto IL_001f; IL_001f: return true; }), new MutatorSelectionContext(1u)); } } internal class RandomScalingSelectionStrategy : MutatorSelectionStrategy { private readonly ModSettings.RandomSettings _randomSettings; public RandomScalingSelectionStrategy(GeneratedMultiMutatorSelectionRulesRegistry multiRegistry, SingleMutatorSelectionRulesRegistry singleRegistry, ModSettings.RandomSettings randomSettings, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator fallbackMutator) : base(multiRegistry, singleRegistry, repeatSelectionTracker, randomProvider, fallbackMutator) { _randomSettings = randomSettings; } public sealed override IMutator Execute(IList mutators) { int randomAmountOfMutatorsBetweenByWeight = GetRandomAmountOfMutatorsBetweenByWeight(); if (randomAmountOfMutatorsBetweenByWeight == 1) { return GetSingleMutator(mutators); } if (!ShouldGenerateMulti(GetRandomGeneratedChance(randomAmountOfMutatorsBetweenByWeight))) { return TryPickUserDefinedMultiMutatorOrElseGenerate(mutators, randomAmountOfMutatorsBetweenByWeight); } return PickGeneratedMultiMutator(mutators, randomAmountOfMutatorsBetweenByWeight); } private int GetRandomGeneratedChance(int amountOfMutators) { return _randomSettings.GetGeneratedChance(amountOfMutators); } private int GetRandomAmountOfMutatorsBetweenByWeight() { int minimumAmount = _randomSettings.MinimumAmount; int maximumAmount = _randomSettings.MaximumAmount; if (minimumAmount < 1 || minimumAmount > ModSettings.MaximumGeneratedActiveSubMutators) { throw new ArgumentException($"Minimum amount of Mutators should be between 1 and {ModSettings.MaximumGeneratedActiveSubMutators}", "minimumAmount"); } if (maximumAmount < 1 || maximumAmount > ModSettings.MaximumGeneratedActiveSubMutators) { throw new ArgumentException($"Maximum amount of Mutators should be between 1 and {ModSettings.MaximumGeneratedActiveSubMutators}", "maximumAmount"); } if (minimumAmount > maximumAmount) { throw new ArgumentException("Minimum amount of Mutators should not be greater than maximum amount of Mutators.", "minimumAmount"); } int num = 0; for (int i = minimumAmount; i <= maximumAmount; i++) { num += _randomSettings.GetWeight(i); } if (num <= 0) { return randomProvider.RandomRangeInt(minimumAmount, maximumAmount + 1); } int num2 = randomProvider.RandomRangeInt(0, num); int num3 = 0; for (int j = minimumAmount; j <= maximumAmount; j++) { num3 += _randomSettings.GetWeight(j); if (num2 < num3) { return j; } } return maximumAmount; } } } namespace Mutators.Rules { public static class MultiMutatorRules { public static Func, string, bool> RequiresAmountOfOtherMutatorsRule(string namespacedName, int amount) { return (IReadOnlyCollection pickedList, string candidate) => namespacedName != candidate || pickedList.Count >= amount; } public static Func, string, bool> MutualExclusionRule(string firstNamespacedName, string secondNamespacedName) { return (IReadOnlyCollection pickedList, string candidate) => (!pickedList.Contains(firstNamespacedName) || !string.Equals(candidate, secondNamespacedName, StringComparison.OrdinalIgnoreCase)) && (!pickedList.Contains(secondNamespacedName) || !string.Equals(candidate, firstNamespacedName, StringComparison.OrdinalIgnoreCase)); } } public static class MultiMutatorRuleType { public const string Exclusion = "Exclusion"; public const string MutualExclusion = "Mutual Exclusion"; public const string RequiresAmountOfOtherMutators = "Requires Amount Of Other Mutators"; } public static class SingleMutatorRules { public static Predicate ExclusionRule(string namespacedName) { return (IMutator mutator) => mutator.NamespacedName != namespacedName; } } public static class SingleMutatorRuleType { public const string Exclusion = "Exclusion"; } } namespace Mutators.Rules.Registries { public class GeneratedMultiMutatorSelectionRulesRegistry : MutatorSelectionRulesRegistry, string, bool>, Func, IMutator, bool>> { internal GeneratedMultiMutatorSelectionRulesRegistry() { } internal bool RunRules(ICollection pickedMutators, IMutator mutator) { ReadOnlyCollection pickedMutatorNamesReadOnly = pickedMutators.Select((IMutator m) => m.NamespacedName).Distinct(StringComparer.OrdinalIgnoreCase).ToList() .AsReadOnly(); IReadOnlyCollection pickedMutatorsReadonly = new ReadOnlyCollection(pickedMutators.ToList()); if (mutatorSelectionRulesExtended.Values.All((Func, IMutator, bool> rule) => rule(pickedMutatorsReadonly, mutator))) { return mutatorSelectionRules.Values.All((Func, string, bool> rule) => rule(pickedMutatorNamesReadOnly, mutator.NamespacedName)); } return false; } } public abstract class MutatorSelectionRulesRegistry { protected readonly IDictionary mutatorSelectionRules = new Dictionary(); protected readonly IDictionary mutatorSelectionRulesExtended = new Dictionary(); public void Register(string key, T rule) { ValidateAndThen(key, delegate { mutatorSelectionRules.Add(key, rule); }); } public void Register(string key, TE rule) { ValidateAndThen(key, delegate { mutatorSelectionRulesExtended.Add(key, rule); }); } public bool Unregister(string key) { if (!mutatorSelectionRules.Remove(key)) { return mutatorSelectionRulesExtended.Remove(key); } return true; } public bool IsRuleRegistered(string key) { if (!mutatorSelectionRules.ContainsKey(key)) { return mutatorSelectionRulesExtended.ContainsKey(key); } return true; } private void ValidateAndThen(string key, Action action) { if (IsRuleRegistered(key)) { throw new InvalidOperationException("Rule with key " + key + " already exists"); } action(); } } public class SingleMutatorSelectionRulesRegistry : MutatorSelectionRulesRegistry, Predicate> { internal bool RunRules(IMutator mutator) { if (mutatorSelectionRulesExtended.Values.All((Predicate rule) => rule(mutator))) { return mutatorSelectionRules.Values.All((Predicate rule) => rule(mutator.NamespacedName)); } return false; } } } namespace Mutators.Rules.Loaders { public interface IRuleLoader { void AddDefaultRule(JsonMutatorRule jsonRule); void AddDefaultRules(params JsonMutatorRule[] jsonRules); void AddRuleStrategy(IRuleLoadingStrategy strategy); } internal sealed class MultiMutatorRuleLoader : RuleLoader, string, bool>> { private static readonly string MultiMutatorRulesPath = Path.Combine(RepoMutators.ConfigPath, "multi-mutator-rules.json"); protected override JsonMutatorRule[] CreateDefaultRules() { return Array.Empty(); } protected override string GetRulesPath() { return MultiMutatorRulesPath; } } public abstract class RuleLoader : IRuleLoader { protected readonly IDictionary defaultRules = new Dictionary(); protected readonly IDictionary> strategies = new Dictionary>(); public IDictionary Load() { IDictionary executableRules = new Dictionary(); CreateDefaultFilesAndThen(RepoMutators.ConfigPath, delegate { JsonMutatorRule[] array = ReadRules(GetRulesPath()); JsonMutatorRule[] array2 = array; foreach (JsonMutatorRule jsonMutatorRule in array2) { defaultRules[jsonMutatorRule.Key] = jsonMutatorRule; if (!strategies.TryGetValue(jsonMutatorRule.Type, out IRuleLoadingStrategy value)) { RepoMutators.Logger.LogError("Skipping invalid rule " + jsonMutatorRule.Key + ": unknown rule type " + jsonMutatorRule.Type); } else if (!jsonMutatorRule.Enabled) { RepoMutators.Logger.LogDebug("Skipping disabled rule " + jsonMutatorRule.Key); } else if (!value.Validate(jsonMutatorRule)) { RepoMutators.Logger.LogWarning("Rule " + jsonMutatorRule.Key + " has an invalid configuration, skipping..."); } else { executableRules.Add(jsonMutatorRule.Key, value.Load(jsonMutatorRule.Mutators, jsonMutatorRule.Arguments)); RepoMutators.Logger.LogDebug("Successfully loaded rule " + jsonMutatorRule.Key + " with strategy " + value.Key + "!"); } } }); WriteRules(GetRulesPath(), GetSortedDefaultRules()); return executableRules; } protected void CreateDefaultFilesAndThen(string configPath, Action then) { if (!Directory.Exists(configPath)) { Directory.CreateDirectory(configPath); } if (!File.Exists(GetRulesPath())) { WriteRules(GetRulesPath(), GetSortedDefaultRules()); } then(); } private JsonMutatorRule[] GetSortedDefaultRules() { return (from kv in defaultRules select kv.Value into rule orderby rule.Enabled, rule.Key select rule).ToArray(); } public void AddDefaultRule(JsonMutatorRule jsonRule) { defaultRules.Add(jsonRule.Key, jsonRule); } public void AddDefaultRules(params JsonMutatorRule[] jsonRules) { foreach (JsonMutatorRule jsonRule in jsonRules) { AddDefaultRule(jsonRule); } } public void AddRuleStrategy(IRuleLoadingStrategy strategy) { strategies.Add(strategy.Key, strategy); } protected JsonMutatorRule[] ReadRules(string path) { string text = File.ReadAllText(path); return JsonConvert.DeserializeObject(text) ?? CreateDefaultRules(); } protected void WriteRules(string path, JsonMutatorRule[] rules) { RepoMutators.Logger.LogDebug("Writing rules to " + path); File.WriteAllText(path, JsonConvert.SerializeObject((object)rules, (Formatting)1)); } protected abstract JsonMutatorRule[] CreateDefaultRules(); protected abstract string GetRulesPath(); } internal sealed class SingleMutatorRuleLoader : RuleLoader> { private static readonly string SingleMutatorRulesPath = Path.Combine(RepoMutators.ConfigPath, "single-mutator-rules.json"); protected override JsonMutatorRule[] CreateDefaultRules() { return Array.Empty(); } protected override string GetRulesPath() { return SingleMutatorRulesPath; } private void ValidateAndRegisterExclusionRule(SingleMutatorSelectionRulesRegistry registry, JsonMutatorRule rule) { if (string.IsNullOrWhiteSpace(rule.Key)) { RepoMutators.Logger.LogError("Skipping invalid rule: exclusion rules must have a non-empty key"); } else if (rule.Mutators.Any(string.IsNullOrWhiteSpace)) { RepoMutators.Logger.LogError("Skipping invalid rule " + rule.Key + ": exclusion rules must have non-empty mutators"); } else if (rule.Mutators.Count != 1) { RepoMutators.Logger.LogError("Skipping invalid rule " + rule.Key + ": exclusion rules must have exactly 1 mutators"); } else { registry.Register(rule.Key, SingleMutatorRules.ExclusionRule(rule.Mutators[0])); } } } } namespace Mutators.Rules.Loaders.Strategies { public class ExclusionRuleLoadingStrategy : ISingleMutatorRuleLoadingStrategy, IRuleLoadingStrategy> { public string Key => "Exclusion"; public bool Validate(JsonMutatorRule rule) { if (rule.Mutators.Count == 1) { return !string.IsNullOrEmpty(rule.Mutators[0]); } return false; } public Predicate Load(IReadOnlyList mutators, IReadOnlyDictionary? arguments = null) { return (string mutator) => mutator != mutators[0]; } } public class MultiExclusionRuleLoadingStrategy : IMultiMutatorRuleLoadingStrategy, IRuleLoadingStrategy, string, bool>> { private readonly ExclusionRuleLoadingStrategy _exclusionRuleLoadingStrategy = new ExclusionRuleLoadingStrategy(); public string Key => _exclusionRuleLoadingStrategy.Key; public bool Validate(JsonMutatorRule rule) { return _exclusionRuleLoadingStrategy.Validate(rule); } public Func, string, bool> Load(IReadOnlyList mutators, IReadOnlyDictionary? arguments = null) { Predicate exclusionRule = _exclusionRuleLoadingStrategy.Load(mutators, arguments); return (IReadOnlyCollection _, string mutator) => exclusionRule(mutator); } } public interface IMultiMutatorRuleLoadingStrategy : IRuleLoadingStrategy, string, bool>> { } public interface IRuleLoadingStrategy { string Key { get; } bool Validate(JsonMutatorRule rule); T Load(IReadOnlyList mutators, IReadOnlyDictionary? arguments = null); } public interface ISingleMutatorRuleLoadingStrategy : IRuleLoadingStrategy> { } public class MutualExclusionRuleLoadingStrategy : IMultiMutatorRuleLoadingStrategy, IRuleLoadingStrategy, string, bool>> { public string Key => "Mutual Exclusion"; public bool Validate(JsonMutatorRule rule) { if (rule.Mutators.Count != 2) { RepoMutators.Logger.LogError("Skipping invalid rule " + rule.Key + ": mutual exclusion rules must have exactly 2 mutators"); return false; } return true; } public Func, string, bool> Load(IReadOnlyList mutators, IReadOnlyDictionary? arguments) { return MultiMutatorRules.MutualExclusionRule(mutators[0], mutators[1]); } } public class RequiresAmountOfOtherMutatorsRuleLoadingStrategy : IMultiMutatorRuleLoadingStrategy, IRuleLoadingStrategy, string, bool>> { public string Key => "Requires Amount Of Other Mutators"; public bool Validate(JsonMutatorRule rule) { if (rule.Mutators.Count != 1) { return false; } if (rule.Arguments == null || !rule.Arguments.TryGetValue("other-mutators-required-amount", out object value)) { return false; } if (!(value is long)) { return false; } return true; } public Func, string, bool> Load(IReadOnlyList mutators, IReadOnlyDictionary? arguments = null) { long? num = arguments["other-mutators-required-amount"] as long?; return MultiMutatorRules.RequiresAmountOfOtherMutatorsRule(mutators[0], (int)Math.Clamp(num.Value, 0L, 10L)); } } } namespace Mutators.Rules.Loaders.Json { public class JsonMutatorRule { public string Key { get; } public string Type { get; } public IReadOnlyList Mutators { get; } [JsonProperty(/*Could not decode attribute arguments.*/)] public IReadOnlyDictionary? Arguments { get; } public bool Enabled { get; } [JsonConstructor] public JsonMutatorRule(string key, string type, string[]? mutators = null, string? mutator = null, IDictionary? arguments = null, bool enabled = true) { Key = key; Type = type; Mutators = (IReadOnlyList)(mutators ?? ((mutator == null) ? ((object)Array.Empty()) : ((object)new string[1] { mutator }))); Arguments = ((arguments != null) ? new Dictionary(arguments) : null); Enabled = enabled; } } } namespace Mutators.Providers.Semiwork { internal interface ISemiFuncProvider { int MoonLevel(); bool IsMultiplayer(); } internal class SemiFuncProvider : ISemiFuncProvider { public int MoonLevel() { return SemiFunc.MoonLevel(); } public bool IsMultiplayer() { return SemiFunc.IsMultiplayer(); } } } namespace Mutators.Providers.Random { internal interface IRandomProvider { float Range(float minInclusive, float maxInclusive); int RandomRangeInt(int minInclusive, int maxExclusive); } internal class RandomProvider : IRandomProvider { public float Range(float minInclusive, float maxInclusive) { return Random.Range(minInclusive, maxInclusive); } public int RandomRangeInt(int minInclusive, int maxExclusive) { return Random.RandomRangeInt(minInclusive, maxExclusive); } } } namespace Mutators.Patches { [HarmonyPatch(typeof(EnemyDirector))] internal class EnemyDirectorPatch { private static List _startingEnemyList = new List(); private static bool _isListSet; [HarmonyPrefix] [HarmonyPriority(600)] [HarmonyPatch("GetEnemy")] private static void EnemyDirectorGetEnemyPrefix(ref List ___enemyList, int ___enemyListIndex) { if (!SemiFunc.IsMultiplayer() || !SemiFunc.IsNotMasterClient()) { ___enemyList.RemoveAll((EnemySetup x) => (Object)(object)x == (Object)null); if (!_isListSet) { _startingEnemyList = new List(___enemyList); _isListSet = true; } if (___enemyList.Count == 0) { EnemySetup val = ScriptableObject.CreateInstance(); val.spawnObjects = new List(); ___enemyList.Add(val); } while (___enemyList.Count < ___enemyListIndex + 1) { int index = Random.Range(0, _startingEnemyList.Count); ___enemyList.Add(___enemyList[index]); } } } } [HarmonyPatch(typeof(HealthUI))] internal class HealthUIPatch { [HarmonyPostfix] [HarmonyPriority(600)] [HarmonyPatch("Start")] private static void HealthUIStartPostfix() { if (SemiFunc.IsMasterClientOrSingleplayer()) { LevelRemovalUtils.RemoveLevels(); } } } [HarmonyPatch(typeof(LevelGenerator))] internal class LevelGeneratorPatch { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePrefix() { if (SemiFunc.RunIsLevel()) { MutatorManager.Instance.GameState = MutatorsGameState.LevelReady; } } [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePostfix() { if (SemiFunc.RunIsLevel()) { MutatorManager.Instance.GameState = MutatorsGameState.LevelGenerated; } } } [HarmonyPatch(typeof(LoadingUI))] internal class LoadingUIPatch { [HarmonyPostfix] [HarmonyPriority(800)] [HarmonyPatch("StopLoading")] private static void LoadingUIStopLoadingPostfix() { if (SemiFunc.RunIsLevel()) { GameObject hud = GameObject.Find("Game Hud"); GameObject health = GameObject.Find("Health"); CreateMutatorText(hud, health); CreateMutatorDescriptionText(hud, health); CreateTargetPlayerText(hud, health); CreateAnnouncementController(hud); IMutator currentMutator = MutatorManager.Instance.CurrentMutator; if (currentMutator != null && currentMutator.HasSpecialAction) { GameObject energy = GameObject.Find("Energy"); CreateSpecialActionText(hud, health, energy); } } } private static void CreateAnnouncementController(GameObject hud) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown GameObject val = new GameObject("Mutator Announcement Controller"); val.transform.SetParent(hud.transform, false); val.AddComponent(); } private static void CreateMutatorText(GameObject hud, GameObject health) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Mutator"); val.transform.SetParent(hud.transform, false); TextMeshProUGUI val2 = val.AddComponent(); TextMeshProUGUI component = health.GetComponent(); ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontMaterial = ((TMP_Text)component).fontMaterial; RectTransform component2 = val.GetComponent(); component2.sizeDelta = new Vector2(250f, 50f); component2.anchorMin = new Vector2(1f, 1f); component2.anchorMax = new Vector2(1f, 1f); component2.pivot = new Vector2(1f, 1f); component2.anchoredPosition = new Vector2(0f, RepoMutators.Settings.MutatorDisplayY); ((TMP_Text)val2).alignment = (TextAlignmentOptions)516; val.AddComponent(); ((TMP_Text)val2).text = MutatorManager.Instance.CurrentMutator.Name; ((TMP_Text)val2).fontSize = RepoMutators.Settings.MutatorDisplaySize; ((Behaviour)val2).enabled = true; } private static void CreateMutatorDescriptionText(GameObject hud, GameObject health) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Mutator Description"); val.transform.SetParent(hud.transform, false); TextMeshProUGUI val2 = val.AddComponent(); TextMeshProUGUI component = health.GetComponent(); ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontMaterial = ((TMP_Text)component).fontMaterial; RectTransform component2 = val.GetComponent(); component2.sizeDelta = new Vector2(300f, 100f); component2.anchorMin = new Vector2(1f, 1f); component2.anchorMax = new Vector2(1f, 1f); component2.pivot = new Vector2(1f, 1f); component2.anchoredPosition = new Vector2(0f, RepoMutators.Settings.MutatorDescriptionDisplayY); ((TMP_Text)val2).alignment = (TextAlignmentOptions)516; ((TMP_Text)val2).verticalAlignment = (VerticalAlignmentOptions)256; val.AddComponent(); ((TMP_Text)val2).text = string.Empty; ((TMP_Text)val2).lineSpacing = -50f; ((TMP_Text)val2).fontSize = RepoMutators.Settings.MutatorDescriptionDisplaySize; ((Behaviour)val2).enabled = true; } private static void CreateTargetPlayerText(GameObject hud, GameObject health) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ChosenPlayerTarget"); val.transform.SetParent(hud.transform, false); TextMeshProUGUI val2 = val.AddComponent(); TextMeshProUGUI component = health.GetComponent(); ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontMaterial = ((TMP_Text)component).fontMaterial; ((Graphic)val2).color = ((Graphic)component).color; RectTransform component2 = val.GetComponent(); component2.sizeDelta = new Vector2(300f, 50f); component2.anchorMin = new Vector2(0.5f, 1f); component2.anchorMax = new Vector2(0.5f, 1f); component2.pivot = new Vector2(0.5f, 1f); component2.anchoredPosition = new Vector2(0f, 10f); ((TMP_Text)val2).alignment = (TextAlignmentOptions)4098; val.AddComponent(); ((TMP_Text)val2).text = string.Empty; ((TMP_Text)val2).fontSize = RepoMutators.Settings.TargetDisplaySize; ((Behaviour)val2).enabled = true; } private static void CreateSpecialActionText(GameObject hud, GameObject health, GameObject energy) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SpecialAction"); val.transform.SetParent(hud.transform, false); TextMeshProUGUI val2 = val.AddComponent(); Zap(val, energy); GameObject val3 = new GameObject("SpecialActionMax"); val3.transform.SetParent(val.transform, false); TextMeshProUGUI val4 = val3.AddComponent(); TextMeshProUGUI component = health.GetComponent(); ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontWeight = ((TMP_Text)component).fontWeight; ((TMP_Text)val2).fontMaterial = ((TMP_Text)component).fontMaterial; ((Graphic)val2).color = Color.red; RectTransform component2 = val.GetComponent(); component2.sizeDelta = new Vector2(120f, 50f); component2.anchorMin = new Vector2(0f, 1f); component2.anchorMax = new Vector2(0f, 1f); component2.pivot = new Vector2(0f, 1f); component2.anchoredPosition = new Vector2(29f, RepoMutators.Settings.SpecialActionY); ((TMP_Text)val2).alignment = (TextAlignmentOptions)513; ((TMP_Text)val2).text = string.Empty; ((TMP_Text)val2).fontStyle = (FontStyles)1; ((TMP_Text)val2).fontSize = 40f; ((Behaviour)val2).enabled = true; ((TMP_Text)val4).font = ((TMP_Text)component).font; ((TMP_Text)val4).fontMaterial = ((TMP_Text)component).fontMaterial; ((Graphic)val4).color = Color.red; RectTransform component3 = val3.GetComponent(); component3.sizeDelta = new Vector2(120f, 50f); component3.anchorMin = new Vector2(0f, 1f); component3.anchorMax = new Vector2(0f, 1f); component3.pivot = new Vector2(0f, 1f); component3.anchoredPosition = new Vector2(45f, 5f); ((TMP_Text)val4).alignment = (TextAlignmentOptions)513; val.AddComponent(); ((TMP_Text)val4).text = string.Empty; ((TMP_Text)val4).fontSize = 20f; ((Behaviour)val4).enabled = true; } private static void Zap(GameObject specialActionObject, GameObject energy) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) GameObject val = new GameObject("SpecialActionZap"); val.transform.SetParent(specialActionObject.transform, false); Image component = ((Component)energy.transform.Find("Zap")).GetComponent(); Image val2 = val.AddComponent(); val2.sprite = component.sprite; ((Graphic)val2).color = Color.red; RectTransform component2 = val.GetComponent(); component2.sizeDelta = new Vector2(25f, 25f); component2.anchoredPosition = new Vector2(-75f, 0f); } } internal class MapBacktrackPatch { [HarmonyTranspiler] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static IEnumerable MapBacktrackBacktrackTranspiler(IEnumerable instructions) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown List list = new List(instructions); FieldInfo fieldInfo = AccessTools.Field(typeof(MapBacktrack), "truckDestination") ?? throw new Exception("MapBacktrack.truckDestination field not found"); MethodInfo methodInfo = AccessTools.Method(typeof(MapBacktrackPatch), "GetTargetPosition", (Type[])null, (Type[])null) ?? throw new Exception("GetTargetPosition method not found"); for (int i = 0; i < list.Count - 1; i++) { CodeInstruction val = list[i]; CodeInstruction val2 = list[i + 1]; if (CodeInstructionExtensions.LoadsField(val, fieldInfo, false) && IsStoreLocal(val2)) { list.InsertRange(i + 2, new <>z__ReadOnlyArray((CodeInstruction[])(object)new CodeInstruction[3] { LoadStoredLocal(val2), new CodeInstruction(OpCodes.Call, (object)methodInfo), new CodeInstruction(val2.opcode, val2.operand) })); return list; } } throw new Exception("Could not find MapBacktrack truck target assignment"); } private static Vector3 GetTargetPosition(Vector3 targetPosition) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_003f: Unknown result type (might be due to invalid IL or missing references) if (!MutatorManager.Instance.HasCurrentMutator(MutatorSettings.UltraViolence.NamespacedName)) { return targetPosition; } if (!UltraViolencePatch.ShouldHideFakeFinalState()) { return targetPosition; } RoundDirector instance = RoundDirector.instance; if (Object.op_Implicit((Object)(object)instance.extractionPointCurrent)) { return ((Component)instance.extractionPointCurrent).transform.position; } return PlayerController.instance.playerAvatarScript.LastNavmeshPosition; } private static bool IsStoreLocal(CodeInstruction instruction) { if (!(instruction.opcode == OpCodes.Stloc) && !(instruction.opcode == OpCodes.Stloc_S) && !(instruction.opcode == OpCodes.Stloc_0) && !(instruction.opcode == OpCodes.Stloc_1) && !(instruction.opcode == OpCodes.Stloc_2)) { return instruction.opcode == OpCodes.Stloc_3; } return true; } private static CodeInstruction LoadStoredLocal(CodeInstruction storeInstruction) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown if (!(storeInstruction.opcode == OpCodes.Stloc_0)) { if (!(storeInstruction.opcode == OpCodes.Stloc_1)) { if (!(storeInstruction.opcode == OpCodes.Stloc_2)) { if (!(storeInstruction.opcode == OpCodes.Stloc_3)) { if (!(storeInstruction.opcode == OpCodes.Stloc_S)) { return new CodeInstruction(OpCodes.Ldloc, storeInstruction.operand); } return new CodeInstruction(OpCodes.Ldloc_S, storeInstruction.operand); } return new CodeInstruction(OpCodes.Ldloc_3, (object)null); } return new CodeInstruction(OpCodes.Ldloc_2, (object)null); } return new CodeInstruction(OpCodes.Ldloc_1, (object)null); } return new CodeInstruction(OpCodes.Ldloc_0, (object)null); } } [HarmonyPatch(typeof(MapToolController))] internal class MapToolControllerPatch { [HarmonyPostfix] [HarmonyPatch("Update")] private static void Postfix(MapToolController __instance) { MutatorDescriptionAnnouncingBehaviour instance = MutatorDescriptionAnnouncingBehaviour.Instance; if (Object.op_Implicit((Object)(object)instance) && __instance.Active && RepoMutators.Settings.MutatorDescriptionInMapTool && (Object)(object)__instance.PlayerAvatar == (Object)(object)PlayerAvatar.instance) { ((SemiUI)instance).Show(); } if (RepoMutators.Settings.MutatorDisplayToggleType == ModSettings.MutatorNameToggleType.WithDescription) { MutatorAnnouncingBehaviour instance2 = MutatorAnnouncingBehaviour.instance; if (Object.op_Implicit((Object)(object)instance2) && __instance.Active && RepoMutators.Settings.MutatorDescriptionInMapTool && (Object)(object)__instance.PlayerAvatar == (Object)(object)PlayerAvatar.instance) { ((SemiUI)instance2).Show(); } } } } [HarmonyPatch(typeof(MenuManager))] internal class MenuManagerPatch { [HarmonyPostfix] [HarmonyPriority(600)] [HarmonyPatch("PageOpen")] private static void PageOpenPostfix(MenuPageIndex menuPageIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if ((int)menuPageIndex == 0) { LevelManager.Instance.RestoreLevels(); } } } [HarmonyPatch(typeof(MenuPage))] internal class MenuPagePatch { [HarmonyPostfix] [HarmonyPatch("LockAndHide")] private static void MenuPageLockAndHidePostfix() { MutatorAnnouncingBehaviour instance = MutatorAnnouncingBehaviour.instance; MutatorDescriptionAnnouncingBehaviour instance2 = MutatorDescriptionAnnouncingBehaviour.Instance; TargetPlayerAnnouncingBehaviour instance3 = TargetPlayerAnnouncingBehaviour.Instance; SpecialActionAnnouncingBehaviour instance4 = SpecialActionAnnouncingBehaviour.Instance; if (Object.op_Implicit((Object)(object)instance)) { ((SemiUI)instance).Hide(); } if (Object.op_Implicit((Object)(object)instance2)) { ((SemiUI)instance2).Hide(); } if (Object.op_Implicit((Object)(object)instance3)) { ((SemiUI)instance3).Hide(); } if (Object.op_Implicit((Object)(object)instance4)) { ((SemiUI)instance4).Hide(); } } } [HarmonyPatch(typeof(RunManager))] internal class RunManagerPatch { private static bool _isMoonConfigApplied; [HarmonyPostfix] [HarmonyPatch("Awake")] private static void RunManagerAwakePostfix(RunManager __instance) { if (!_isMoonConfigApplied) { RepoMutators.Settings.LateBindMoonConfig(((BaseUnityPlugin)RepoMutators.Instance).Config, __instance.moons.Count); _isMoonConfigApplied = true; } } [HarmonyPostfix] [HarmonyPatch("ChangeLevel")] private static void RunManagerChangeLevelPostfix() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMultiplayer() && SemiFunc.IsNotMasterClient()) { return; } RepoMutators.Logger.LogDebug("RunManagerPatch Host only"); if (!SemiFunc.IsMultiplayer() && !SemiFunc.RunIsLobbyMenu() && (Object)(object)MutatorsNetworkManager.Instance == (Object)null) { RepoMutators.Logger.LogDebug("Spawning singleplayer NetworkManager"); string text = "Xepos.REPO-Mutators/MutatorsNetworkManager"; PrefabRef val = default(PrefabRef); if (!NetworkPrefabs.TryGetNetworkPrefabRef(text, ref val)) { throw new Exception("Unable to establish Mutators NetworkManager: Could not find PrefabRef with id: " + text); } GameObject val2 = NetworkPrefabs.SpawnNetworkPrefab(val, Vector3.zero, Quaternion.identity, (byte)0, (object[])null); if (val2 != null) { val2.SetActive(true); } GetAndSendMutator(); } ApplyPatch(); } [HarmonyPostfix] [HarmonyPatch("UpdateLevel")] private static void RunManagerUpdateLevelPostfix() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { RepoMutators.Logger.LogDebug("RunManagerPatch Client only"); ApplyPatch(); } } [HarmonyPostfix] [HarmonyPatch("Awake")] private static void RunManagerAwakePrefix(RunManager __instance) { IMutatorsLogger logger = RepoMutators.Logger; object arg = ((Object)__instance).GetInstanceID(); RunManager instance = RunManager.instance; logger.LogDebug($"Awake RunManager instance={arg} static={((instance != null) ? new int?(((Object)instance).GetInstanceID()) : ((int?)null))}"); } [HarmonyPrefix] [HarmonyPatch("SetRunLevel")] private static void RunManagerSetRunLevelPrefix() { RunManager instance = RunManager.instance; bool flag = (Object)(object)instance.levelCurrent == (Object)(object)instance.levelLobbyMenu; if (flag || (Object)(object)instance.levelCurrent == (Object)(object)instance.levelLobby) { LevelRemovalUtils.RemoveLevels(flag); } instance.levels.ForEach(delegate(Level level) { RepoMutators.Logger.LogDebug("Level " + ((Object)level).name + " is active"); }); } private static void ApplyPatch() { MutatorManager instance = MutatorManager.Instance; if (IsInShop()) { instance.GameState = MutatorsGameState.Shop; if (SemiFunc.IsMasterClientOrSingleplayer()) { MutatorsNetworkManager.Instance.ClearBufferedRPCs(); GetAndSendMutator(); } } else if (SemiFunc.RunIsLevel()) { RepoMutators.Logger.LogDebug("Applying patch now for mutator: " + instance.CurrentMutator.Name); instance.CurrentMutator.Patch(); } else { instance.GameState = MutatorsGameState.None; if (SemiFunc.RunIsArena()) { instance.SetActiveMutator(MutatorSettings.NopMutator.NamespacedName); } } } private static void GetAndSendMutator() { IMutator weightedMutator = MutatorManager.Instance.GetWeightedMutator(); if (weightedMutator is IMultiMutator multiMutator) { var (list, metadata) = multiMutator.Format(); MutatorsNetworkManager.Instance.SendActiveMutators(multiMutator, metadata); } else { MutatorsNetworkManager.Instance.SendActiveMutator(weightedMutator.NamespacedName, weightedMutator.Settings.AsMetadata()); } } private static bool IsInShop() { RunManager runManager = RunManager.instance; return runManager.levelShop.Any((Level level) => ((Object)level).name == ((Object)runManager.levelCurrent).name); } } [HarmonyPatch(typeof(SemiFunc))] internal class SemiFuncPatch { [HarmonyPostfix] [HarmonyPriority(800)] [HarmonyPatch("OnSceneSwitch")] private static void SemiFuncOnSceneSwitchPostfix(bool _gameOver, bool _leaveGame) { if (_leaveGame) { MutatorManager instance = MutatorManager.Instance; instance.GameState = MutatorsGameState.None; instance.SetActiveMutator(MutatorSettings.NopMutator.NamespacedName); } } } [HarmonyPatch(typeof(SpectateCamera))] internal class SpectateCameraPatch { [HarmonyPostfix] [HarmonyPatch("LateUpdate")] private static void SpectateCameraLateUpdatePostfix() { SpecialActionAnnouncingBehaviour instance = SpecialActionAnnouncingBehaviour.Instance; if (Object.op_Implicit((Object)(object)instance)) { ((SemiUI)instance).Hide(); } } } } namespace Mutators.Network { public class MutatorsNetworkManager : MonoBehaviourPunCallbacks { private PhotonView _photonView; public static MutatorsNetworkManager Instance { get; private set; } private void Awake() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) Instance = this; ((Component)this).transform.parent = ((Component)StatsManager.instance).transform; ((Object)((Component)this).gameObject).name = "MutatorsNetworkManager"; GameObject gameObject = ((Component)this).gameObject; ((Object)gameObject).hideFlags = (HideFlags)(((Object)gameObject).hideFlags & -62); _photonView = ((Component)this).GetComponent(); } internal void ClearBufferedRPCs() { if (_photonView.IsMine) { PhotonNetwork.RemoveBufferedRPCs(_photonView.ViewID, (string)null, (int[])null); } } public void SendMetadata(string mutatorNamespacedName, IDictionary metadata) { IDictionary dict = metadata.WithMutator(mutatorNamespacedName); Hashtable hashtable = dict.ToPhotonHashtable(); Send("SetMetadata", (RpcTarget)4, delegate { SetMetadataHostLocal(hashtable); }, hashtable); } internal void SendActiveMutator(string namespacedName, IDictionary? metadata = null) { if (SemiFunc.IsMasterClientOrSingleplayer()) { Hashtable hashtable = metadata?.ToPhotonHashtable(); Send("SetActiveMutator", (RpcTarget)4, delegate { SetActiveMutatorHostLocal(namespacedName, hashtable); }, namespacedName, hashtable); } } internal void SendActiveMutators(IMultiMutator multiMutator, IDictionary? metadata = null) { Send("SetActiveMutators", (RpcTarget)4, delegate { SetActiveMutatorsHost(multiMutator, metadata); }, multiMutator.SubMutators.Keys.Select((IMutator mutator) => mutator.NamespacedName).ToArray(), metadata?.ToPhotonHashtable()); } internal void SendComponentForViews(int[] views, Type componentType) { string fullName = componentType.FullName; Send("AddComponentToViewGameObject", (RpcTarget)4, delegate { AddComponentToViewGameObjectHostLocal(views, fullName); }, views, fullName); } public void SendMetaToHost(string namespacedName, IDictionary meta) { Hashtable val = meta.ToPhotonHashtable(); if (SemiFunc.IsMultiplayer() && !SemiFunc.IsMasterClient()) { _photonView.RPC("SetClientMetadata", (RpcTarget)2, new object[2] { namespacedName, val }); } } [PunRPC] private void AddComponentToViewGameObject(int[] views, string componentType, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.MasterOnlyRPC(info)) { AddComponentToViewGameObjectHostLocal(views, componentType); } } private static void AddComponentToViewGameObjectHostLocal(int[] views, string componentType) { Type type = Type.GetType(componentType); if (type == null) { RepoMutators.Logger.LogError("Failed to resolve type: " + componentType); return; } foreach (int num in views) { PhotonView val = PhotonView.Find(num); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)((Component)val).gameObject)) { ((Component)val).gameObject.AddComponent(type); } } } [PunRPC] private void SetActiveMutator(string namespacedName, Hashtable? hashtable, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.MasterOnlyRPC(info)) { SetActiveMutatorHostLocal(namespacedName, hashtable); } } private static void SetActiveMutatorHostLocal(string namespacedName, Hashtable? hashtable) { MutatorManager instance = MutatorManager.Instance; bool flag = SemiFunc.RunIsLevel(); RepoMutators.Logger.LogDebug("Set mutator to " + namespacedName + ", applying patch " + (flag ? "now" : "later")); instance.SetActiveMutator(namespacedName, flag); IDictionary dictionary; if (hashtable != null) { dictionary = hashtable.FromPhotonHashtable(); } else { IDictionary dictionary2 = new Dictionary(); dictionary = dictionary2; } IDictionary metadata = dictionary; instance.CurrentMutator.ConsumeMetadata(metadata); } [PunRPC] private void SetActiveMutators(IList names, Hashtable? hashtable, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.MasterOnlyRPC(info)) { return; } if (SemiFunc.IsMasterClientOrSingleplayer()) { RepoMutators.Logger.LogError("Received SetActiveMutators RPC as the host, but this is a client-only handler!"); return; } MutatorManager instance = MutatorManager.Instance; bool applyPatchNow = SemiFunc.RunIsLevel(); if (names.Count == 0) { RepoMutators.Logger.LogError("Received empty list of active mutators"); } else { if (names.Count <= 0) { return; } if (hashtable == null) { RepoMutators.Logger.LogError("Critical failure during multi-mutator activation: no metadata hashtable found!"); return; } IDictionary dictionary = hashtable.FromPhotonHashtable(); if (!SemiFunc.IsMasterClientOrSingleplayer()) { IList source = (from x in instance.RegisteredMutators where names.Contains(x.Key) select x.Value).ToList(); IDictionary dictionary2 = dictionary.Get>("mutatorOverrides"); MultiMutatorSettings settings = new MultiMutatorSettings("Xepos.REPO-Mutators", dictionary2.Get("name") ?? "Name", dictionary2.Get("description") ?? "Description"); Dictionary> mutators = ((IEnumerable)source).ToDictionary((Func)((IMutator k) => k), (Func>)((IMutator _) => new Dictionary())); MutatorSource source2 = GetSource(dictionary2); IMutator mutator = new MultiMutator(settings, mutators, null, null, source2); instance.SetActiveMutator(mutator, applyPatchNow); mutator.ConsumeMetadata(dictionary); } } } private static MutatorSource GetSource(IDictionary overrides) { string value = overrides.Get("source"); if (!Enum.TryParse(value, ignoreCase: true, out var result)) { return MutatorSource.Mod; } return result; } private void SetActiveMutatorsHost(IMultiMutator mutator, IDictionary? metadata) { if (metadata == null) { RepoMutators.Logger.LogError("Critical failure during multi-mutator activation: no metadata hashtable found!"); return; } MutatorManager.Instance.SetActiveMutator(mutator, SemiFunc.RunIsLevel()); mutator.ConsumeMetadata(metadata); } [PunRPC] private void SetMetadata(Hashtable hashtable, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.MasterOnlyRPC(info)) { SetMetadataHostLocal(hashtable); } } private static void SetMetadataHostLocal(Hashtable hashtable) { MutatorManager instance = MutatorManager.Instance; IDictionary metadata = hashtable.FromPhotonHashtable(); instance.CurrentMutator.ConsumeMetadata(metadata); } [PunRPC] private void SetClientMetadata(string namespacedName, Hashtable hashtable, PhotonMessageInfo info = default(PhotonMessageInfo)) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) string text = SemiFunc.PlayerAvatarGetFromPhotonPlayer(info.Sender)?.steamID; if (text == null) { RepoMutators.Logger.LogError("Received SetClientMetadata RPC with no steamID!"); return; } MutatorManager instance = MutatorManager.Instance; IDictionary value = hashtable.FromPhotonHashtable(); IDictionary value2 = new Dictionary { { text, value } }; IDictionary dictionary = new Dictionary { { "clients", value2 } }; instance.CurrentMutator.ConsumeMetadata(dictionary.WithMutator(namespacedName)); } [PunRPC] private void SendModVersion() { ((MonoBehaviour)this).StartCoroutine(ComparedModVersionCoroutine()); } [PunRPC] private void CompareModVersion(string version, Hashtable mutators, PhotonMessageInfo info) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (version == "1.0.3") { RepoMutators.Logger.LogInfo(info.Sender.NickName + " is on the same version!"); } else { HandleVersionMismatch(version, info.Sender.NickName); } HashSet hashSet = MutatorManager.Instance.RegisteredMutators.Keys.ToHashSet(); foreach (string item in hashSet) { } } public override void OnPlayerEnteredRoom(Player newPlayer) { if (_photonView.IsMine) { _photonView.RPC("SendModVersion", newPlayer, Array.Empty()); } } private void HandleVersionMismatch(string version, string playerName) { string[] array = version.Split('.'); string[] array2 = "1.0.3".Split('.'); if (array[0] != array2[0] || array[1] != array2[1]) { RepoMutators.Logger.LogError(playerName + " is on version " + version + ", which doesn't match the host version!"); } else if (array[2] != array2[2]) { RepoMutators.Logger.LogWarning(playerName + " is on version " + version + ", which doesn't match the host version!"); } } private void Send(string rpcMethod, RpcTarget rpcTarget, Action applyLocally, params object[] rpcArguments) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer()) { if (SemiFunc.IsMultiplayer()) { _photonView.RPC(rpcMethod, rpcTarget, rpcArguments); } applyLocally(); } } private IEnumerator ComparedModVersionCoroutine() { while ((Object)(object)_photonView == (Object)null) { yield return (object)new WaitForSeconds(0.5f); } IDictionary dictionary = new Dictionary(); foreach (string key2 in MutatorManager.Instance.RegisteredMutators.Keys) { int num = key2.IndexOf(':'); if (num != -1) { string[] array = key2.Split(':'); string key = array[0]; if (dictionary.TryGetValue(key, out var value) && value is List list) { list.Add(array[1]); continue; } dictionary[key] = new List { array[1] }; } } _photonView.RPC("CompareModVersion", (RpcTarget)2, new object[2] { "1.0.3", dictionary.ToPhotonHashtable() }); } public void Run(IEnumerator coroutine) { ((MonoBehaviour)this).StartCoroutine(coroutine); } } } namespace Mutators.Mutators { public interface IMultiMutator : IMutator { IReadOnlyDictionary> SubMutators { get; } } public interface IMutator { string NamespacedName { get; } string Name { get; } string Description { get; } MutatorDifficulty Difficulty { get; } MutatorSource Source { get; } bool Active { get; } bool HasSpecialAction { get; } AbstractMutatorSettings Settings { get; } IReadOnlyList Patches { get; } IReadOnlyList> Conditions { get; } void Patch(); void Unpatch(); void ConsumeMetadata(IDictionary metadata); bool IsEligibleForSelection() { if (Settings.IsEligibleForSelection()) { return Conditions.All((Func condition) => condition()); } return false; } } public class MultiMutator : IMultiMutator, IMutator { private readonly IList> _conditions; public string NamespacedName => Settings.NamespacedName; public string Name => Settings.MutatorName; public string Description => Settings.MutatorDescription; public MutatorDifficulty Difficulty { get; } public MutatorSource Source { get; } public bool Active { get; private set; } public bool HasSpecialAction { get; } public AbstractMutatorSettings Settings { get; } public IReadOnlyList Patches { get; } public IReadOnlyList> Conditions => new ReadOnlyCollection>(_conditions); public IReadOnlyDictionary> SubMutators { get; } public MultiMutator(AbstractMutatorSettings settings, IDictionary> mutators, MutatorDifficulty? difficulty = null, IList> conditions = null, MutatorSource source = MutatorSource.Mod) { Settings = settings; SubMutators = new ReadOnlyDictionary>(mutators); HasSpecialAction = SubMutators.Any>>((KeyValuePair> mutator) => mutator.Key.HasSpecialAction); _conditions = mutators.SelectMany>, Func>((KeyValuePair> mut) => mut.Key.Conditions).ToList(); if (conditions != null && conditions.Count > 0) { foreach (Func condition in conditions) { _conditions.Add(condition); } } Source = source; Difficulty = difficulty ?? mutators.Select>, MutatorDifficulty>((KeyValuePair> mut) => mut.Key.Difficulty).Max(); Patches = mutators.SelectMany>, Type>((KeyValuePair> mut) => mut.Key.Patches).ToList().AsReadOnly(); } public void Patch() { if (Active) { return; } Active = true; if (SemiFunc.IsMasterClientOrSingleplayer()) { foreach (KeyValuePair> subMutator in SubMutators) { subMutator.Key.Settings.ClearRuntimeOverrides(); subMutator.Key.Settings.ApplyRuntimeOverrides(subMutator.Value); } } foreach (IMutator key in SubMutators.Keys) { key.Patch(); } } public void Unpatch() { if (!Active) { return; } foreach (IMutator key in SubMutators.Keys) { key.Unpatch(); key.Settings.ClearRuntimeOverrides(); } Active = false; } public void ConsumeMetadata(IDictionary metadata) { foreach (IMutator key in SubMutators.Keys) { key.ConsumeMetadata(metadata); } } } public class Mutator : IMutator { private readonly Harmony _harmony; private readonly IList _patches; private readonly IList> _conditions; private readonly IDictionary _pendingDeferredMetadata = new Dictionary(); private IDictionary _metadata; private readonly IList _beforePatchAllHooks = new List(); private readonly IList _afterPatchAllHooks = new List(); private readonly IList>> _onMetadataChangedHooks = new List>>(); private readonly IList _beforeUnpatchAllHooks = new List(); private readonly IList _afterUnpatchAllHooks = new List(); public string NamespacedName => Settings.NamespacedName; public string Name => Settings.MutatorName; public string Description => Settings.MutatorDescription; public MutatorDifficulty Difficulty { get; } public MutatorSource Source => MutatorSource.Mod; public bool Active { get; private set; } public bool HasSpecialAction { get; } public AbstractMutatorSettings Settings { get; } public IReadOnlyList> Conditions => new ReadOnlyCollection>(_conditions); public IReadOnlyList Patches => new ReadOnlyCollection(_patches); public Mutator(AbstractMutatorSettings settings, IList patches, MutatorDifficulty difficulty, IList>? conditions = null, bool specialActionOverlay = false) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown Settings = settings; _harmony = new Harmony(NamespacedName); _patches = patches ?? new List(); Difficulty = difficulty; _conditions = conditions ?? new List>(); _metadata = new Dictionary(); HasSpecialAction = specialActionOverlay; foreach (Type patch in _patches) { TryAddHook(patch, "BeforePatchAll", _beforePatchAllHooks); TryAddHook(patch, "AfterPatchAll", _afterPatchAllHooks); TryAddHook(patch, "BeforeUnpatchAll", _beforeUnpatchAllHooks); TryAddHook(patch, "AfterUnpatchAll", _afterUnpatchAllHooks); TryAddMetadataHook(patch); } } public Mutator(AbstractMutatorSettings settings, Type patch, MutatorDifficulty difficulty, IList> conditions = null, bool specialActionOverlay = false) : this(settings, new List(1) { patch }, difficulty, conditions, specialActionOverlay) { } public void Patch() { RepoMutators.Logger.LogDebug($"{NamespacedName} active: {Active}"); if (Active) { return; } RepoMutators.Logger.LogDebug($"About to apply {_patches.Count} patches for {NamespacedName}"); Active = true; MutatorManager.Instance.GameStateChanged += TryApplyDeferredMetadata; _beforePatchAllHooks.ForEach(delegate(Action action) { action?.Invoke(); }); foreach (Type patch in _patches) { _harmony.PatchAll(patch); RepoMutators.Logger.LogDebug("Applied patch: " + patch.Name); } _afterPatchAllHooks.ForEach(delegate(Action action) { action?.Invoke(); }); } public void Unpatch() { if (Active) { MutatorManager.Instance.GameStateChanged -= TryApplyDeferredMetadata; _metadata.Clear(); _pendingDeferredMetadata.Clear(); _beforeUnpatchAllHooks.ForEach(delegate(Action action) { action?.Invoke(); }); _harmony.UnpatchSelf(); Active = false; _afterUnpatchAllHooks.ForEach(delegate(Action action) { action?.Invoke(); }); Settings.ClearRuntimeOverrides(); RepoMutators.Logger.LogDebug("Unpatched mutator: " + NamespacedName); } } public void ConsumeMetadata(IDictionary metadata) { if (metadata != null && metadata.Count != 0) { ConsumeNamedMetadata(metadata); } } private void ConsumeNamedMetadata(IDictionary metadata) { if (RepoMutators.Settings.ExtendedLogging) { RepoMutators.Logger.LogDebug("[" + Name + "] Consumed Metadata:"); _metadata.LogMetadata(); } IDictionary dictionary2; if (metadata.TryGetValue(NamespacedName, out object value) && value is IDictionary dictionary) { dictionary2 = dictionary; } else { RepoMutators.Logger.LogDebug("[" + Name + "] No metadata found for '" + NamespacedName + "'."); dictionary2 = new Dictionary(); } RepoMutators.Logger.LogDebug("[" + Name + "] Metadata: " + string.Join(",", metadata.Keys)); IDictionary dictionary3 = metadata.Get>("mutatorOverrides")?.Get>(Settings.NamespacedName); RepoMutators.Logger.LogDebug("[" + Name + "] Overrides: " + (dictionary3?.Count.ToString() ?? "null")); if (dictionary3 != null) { foreach (string item in dictionary2.Keys.Where(dictionary3.ContainsKey).ToList()) { object obj = dictionary2[item]; object obj2 = dictionary3[item]; Type type = obj?.GetType(); Type type2 = obj2?.GetType(); if (obj2.TryCoerce(type, out object coerced)) { dictionary2[item] = coerced; RepoMutators.Logger.LogDebug($"[{NamespacedName}] Overrode {item} value {obj} with {coerced}"); } else { RepoMutators.Logger.LogWarning(string.Format("[{0}] Failed to override {1}: original type was {2} but override type was {3}", NamespacedName, item, (type == null) ? ((object)"null") : ((object)type), (type2 == null) ? ((object)"null") : ((object)type2))); } } } IDictionary dictionary4 = new Dictionary(); IDictionary dictionary5 = Settings.AsMetadata() ?? new Dictionary(); if (dictionary5.TryGetValue(NamespacedName, out var value2) && value2 is IDictionary dictionary6) { dictionary5 = dictionary6; } foreach (var (text2, value3) in dictionary2) { if (MutatorManager.Instance.GameState >= MutatorsGameState.LevelReady || dictionary5.ContainsKey(text2)) { dictionary4[text2] = value3; RepoMutators.Logger.LogDebug("Metadata key '" + text2 + "' immediate for mutator '" + NamespacedName + "'."); } else { _pendingDeferredMetadata[text2] = value3; RepoMutators.Logger.LogDebug("Metadata key '" + text2 + "' deferred for mutator '" + NamespacedName + "'."); } } if (dictionary4.Count > 0) { ApplyMetadata(dictionary4); } } private void TryApplyDeferredMetadata(MutatorsGameState gameState) { if (gameState == MutatorsGameState.LevelReady && _pendingDeferredMetadata.Count != 0) { RepoMutators.Logger.LogDebug("Applying deferred metadata for mutator '" + NamespacedName + "'"); ApplyDeferredMetadata(_pendingDeferredMetadata); } } private void ApplyDeferredMetadata(IDictionary pendingDeferredMetadata) { Dictionary metadataToApply = new Dictionary(pendingDeferredMetadata); pendingDeferredMetadata.Clear(); ApplyMetadata(metadataToApply); } private void ApplyMetadata(IDictionary metadataToApply) { _metadata = _metadata.DeepMergedWith(metadataToApply); if (RepoMutators.Settings.ExtendedLogging) { RepoMutators.Logger.LogDebug("DeepMerged: "); _metadata.LogMetadata(); } _onMetadataChangedHooks.ForEach(delegate(Action> hook) { hook?.Invoke(_metadata); }); } private static void TryAddHook(Type type, string methodName, IList hookList) { MethodInfo method = type.GetMethod(methodName, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return; } if (method.GetParameters().Length != 0) { RepoMutators.Logger.LogWarning("Lifecycle hook '" + methodName + "' in type '" + type.FullName + "' must not have parameters."); return; } if (method.ReturnType != typeof(void)) { RepoMutators.Logger.LogWarning("Lifecycle hook '" + methodName + "' in type '" + type.FullName + "' must return void."); return; } try { Action item = (Action)Delegate.CreateDelegate(typeof(Action), method); hookList.Add(item); RepoMutators.Logger.LogDebug("Lifecycle hook '" + methodName + "' in type '" + type.FullName + "' was successfully registered"); } catch (Exception ex) { RepoMutators.Logger.LogError("Failed to bind lifecycle hook '" + methodName + "' in type '" + type.FullName + "': " + ex.Message); } } private void TryAddMetadataHook(Type type) { MethodInfo method = type.GetMethod("OnMetadataChanged", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return; } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 1) { RepoMutators.Logger.LogWarning("Lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "' must have one parameter of type IDictionary."); return; } if (method.ReturnType != typeof(void)) { RepoMutators.Logger.LogWarning("Lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "' must return void."); return; } if (!typeof(IDictionary).IsAssignableFrom(parameters[0].ParameterType)) { RepoMutators.Logger.LogWarning("Lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "' must take a parameter of type IDictionary or a compatible type."); return; } try { Action> item = (Action>)Delegate.CreateDelegate(typeof(Action>), method); _onMetadataChangedHooks.Add(item); RepoMutators.Logger.LogDebug("Lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "' was successfully registered"); } catch (Exception ex) { RepoMutators.Logger.LogError("Failed to bind lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "': " + ex.Message); } } } internal static class Mutators { public const string NopMutatorName = "None"; public const string OutWithABangName = "Out With a Bang!"; public const string ApolloElevenName = "Apollo 11"; public const string UltraViolenceName = "Ultra-Violence"; public const string DuckThisName = "Duck This"; public const string ProtectThePresidentName = "Protect the President"; public const string OneShotOneKillName = "One Shot, One Kill"; public const string RustyServosName = "Rusty Servos"; public const string HandleWithCareName = "Handle With Care"; public const string HuntingSeasonName = "Hunting Season"; public const string ThereCanOnlyBeOneName = "There Can Only Be One"; public const string VolatileCargoName = "Volatile Cargo"; public const string SealedAwayName = "Sealed Away"; public const string ProtectTheWeakName = "Protect the Weak"; public const string FiringMyLaserName = "Firing My Laser"; public const string VoiceoverName = "Voiceover"; public const string TheFloorIsLavaName = "The Floor Is Lava"; public const string LessIsMoreName = "Less Is More"; public const string AmalgamName = "Amalgam"; public const string NullSignalName = "Null Signal"; public const string SizeMattersName = "Size Matters"; public const string InsuranceFraudName = "Insurance Fraud"; public const string NopMutatorDescription = "A normal run, no special effects"; public const string OutWithABangDescription = "Monsters explode on death"; public const string ApolloElevenDescription = "Level-wide Zero-Gravity"; public const string UltraViolenceDescription = "Immediately activates the final extraction phase"; public const string DuckThisDescription = "Ducks aggro on sight instead of on interaction\nAlways spawn at least 1 duck"; public const string ProtectThePresidentDescription = "A random player becomes the \"President\"\nIf they die, everyone else self-destructs"; public const string OneShotOneKillDescription = "Any damage taken by a player is lethal"; public const string RustyServosDescription = "Players cannot jump\n+3 Grab Range"; public const string HandleWithCareDescription = "Valuables are worth more but break on any impact"; public const string HuntingSeasonDescription = "No valuables spawn, weapons spawn instead\nEnemy respawn time reduced to 10 seconds"; public const string ThereCanOnlyBeOneDescription = "All monster spawns are of the same type"; public const string VolatileCargoDescription = "Valuables explode on destruction\nExplosion radius and strength based on value"; public const string SealedAwayDescription = "Breaking valuables has a chance to spawn monsters"; public const string ProtectTheWeakDescription = "Protect your weaker friends!"; public const string FiringMyLaserDescription = "Fire your laser by pressing {specialActionKey}\nUncontrollably fire your laser when taking damage"; public const string VoiceoverDescription = "Player voices are shuffled"; public const string TheFloorIsLavaDescription = "You take damage while standing on the floor"; public const string LessIsMoreDescription = "Valuables are worth less but gain value when hit\nNormal breaking mechanics apply"; public const string AmalgamDescription = "You’ve been here before — just not all at once"; public const string NullSignalDescription = "Active Mutator information is hidden"; public const string SizeMattersDescription = "All players are shrunk"; public const string InsuranceFraudDescription = "Valuables split their value between nearby valuables when broken"; } public sealed class NopMutator : IMutator { private static readonly IReadOnlyList EmptyPatches = Array.Empty(); private static readonly IReadOnlyList> EmptyConditions = Array.Empty>(); public string NamespacedName => Settings.NamespacedName; public string Name => "None"; public string Description => "A normal run, no special effects"; public MutatorDifficulty Difficulty => MutatorDifficulty.Negligible; public MutatorSource Source => MutatorSource.Mod; public bool Active { get; private set; } public AbstractMutatorSettings Settings { get; } public IReadOnlyList Patches => EmptyPatches; public IReadOnlyList> Conditions => EmptyConditions; public bool HasSpecialAction => false; internal NopMutator(AbstractMutatorSettings settings) { Settings = settings; } public void Patch() { Active = true; } public void Unpatch() { Active = false; } public void ConsumeMetadata(IDictionary metadata) { } } } namespace Mutators.Mutators.Patches { internal class AmalgamPatch { private static bool initDone; private static Level actualLevel; private static void BeforePatchAll() { if (SemiFunc.IsMasterClientOrSingleplayer()) { MutatorManager.Instance.GameStateChanged += RemoveBrokenDoors; } } private static void RemoveBrokenDoors(MutatorsGameState gameState) { if (gameState == MutatorsGameState.LevelGenerated) { MutatorsNetworkManager.Instance.Run(ScheduleRemoveBrokenDoors()); } } private static IEnumerator ScheduleRemoveBrokenDoors() { yield return (object)new WaitForSeconds(1f); DirtFinderMapDoor[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (DirtFinderMapDoor val in array) { if (!Object.op_Implicit((Object)(object)val)) { continue; } PhysGrabHinge component = ((Component)val).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.broken) { PhysGrabObjectImpactDetector component2 = ((Component)val).GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { RepoMutators.Logger.LogDebug("[Amalgam] removing broken door " + ((Object)((Component)val).transform).name); component2.DestroyObject(false); } else { RepoMutators.Logger.LogWarning("[Amalgam] unable to find impactDetector on " + ((Object)((Component)val).transform).name); } } } } [HarmonyPrefix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("SpawnModule")] private static void LevelGeneratorSpawnModulePrefix(LevelGenerator __instance) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown if (!SemiFunc.IsMasterClientOrSingleplayer() || initDone) { return; } actualLevel = __instance.Level; __instance.Level = new Level(); __instance.Level.BlockObject = actualLevel.BlockObject; __instance.Level.MusicPreset = actualLevel.MusicPreset; __instance.Level.ConstantMusicPreset = actualLevel.ConstantMusicPreset; RepoMutators.Logger.LogInfo("[Amalgam] Building level from the following available levels:"); foreach (Level allEligibleLevel in GetAllEligibleLevels()) { RepoMutators.Logger.LogInfo("[Amalgam] " + ((Object)allEligibleLevel).name); AddNormalModules(__instance, allEligibleLevel); AddPassageModules(__instance, allEligibleLevel); AddDeadEndModules(__instance, allEligibleLevel); AddExtractionModules(__instance, allEligibleLevel); } initDone = true; } [HarmonyPrefix] [HarmonyPatch(typeof(EnvironmentDirector))] [HarmonyPatch("Setup")] private static void EnvironmentDirectorSetupPrefix() { if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)actualLevel != (Object)null) { LevelGenerator.Instance.Level = actualLevel; } } private static void AddNormalModules(LevelGenerator levelGenerator, Level level) { levelGenerator.ModulesNormalShuffled_1.AddRange(level.ModulesNormal1); levelGenerator.ModulesNormalShuffled_2.AddRange(level.ModulesNormal2); levelGenerator.ModulesNormalShuffled_3.AddRange(level.ModulesNormal3); ListExtension.Shuffle((IList)levelGenerator.ModulesNormalShuffled_1); ListExtension.Shuffle((IList)levelGenerator.ModulesNormalShuffled_2); ListExtension.Shuffle((IList)levelGenerator.ModulesNormalShuffled_3); } private static void AddPassageModules(LevelGenerator levelGenerator, Level level) { levelGenerator.ModulesPassageShuffled_1.AddRange(level.ModulesPassage1); levelGenerator.ModulesPassageShuffled_2.AddRange(level.ModulesPassage2); levelGenerator.ModulesPassageShuffled_3.AddRange(level.ModulesPassage3); ListExtension.Shuffle((IList)levelGenerator.ModulesPassageShuffled_1); ListExtension.Shuffle((IList)levelGenerator.ModulesPassageShuffled_2); ListExtension.Shuffle((IList)levelGenerator.ModulesPassageShuffled_3); } private static void AddDeadEndModules(LevelGenerator levelGenerator, Level level) { levelGenerator.ModulesDeadEndShuffled_1.AddRange(level.ModulesDeadEnd1); levelGenerator.ModulesDeadEndShuffled_2.AddRange(level.ModulesDeadEnd2); levelGenerator.ModulesDeadEndShuffled_3.AddRange(level.ModulesDeadEnd3); ListExtension.Shuffle((IList)levelGenerator.ModulesDeadEndShuffled_1); ListExtension.Shuffle((IList)levelGenerator.ModulesDeadEndShuffled_2); ListExtension.Shuffle((IList)levelGenerator.ModulesDeadEndShuffled_3); } private static void AddExtractionModules(LevelGenerator levelGenerator, Level level) { levelGenerator.ModulesExtractionShuffled_1.AddRange(level.ModulesExtraction1); levelGenerator.ModulesExtractionShuffled_2.AddRange(level.ModulesExtraction2); levelGenerator.ModulesExtractionShuffled_3.AddRange(level.ModulesExtraction3); ListExtension.Shuffle((IList)levelGenerator.ModulesExtractionShuffled_1); ListExtension.Shuffle((IList)levelGenerator.ModulesExtractionShuffled_2); ListExtension.Shuffle((IList)levelGenerator.ModulesExtractionShuffled_3); } private static IList GetAllEligibleLevels() { ISet excludedSet = new HashSet(MutatorSettings.Amalgam.ExcludedLevels.Select((string level) => (!level.StartsWith("level - ", StringComparison.OrdinalIgnoreCase)) ? ("level - " + level).ToLowerInvariant() : level.ToLowerInvariant())); return (from level in Levels.AllLevels where !((Object)level).name.Equals(((Object)actualLevel).name, StringComparison.OrdinalIgnoreCase) where !excludedSet.Contains(((Object)level).name.ToLowerInvariant()) select level).ToList(); } private static void AfterUnpatchAll() { if (SemiFunc.IsMasterClientOrSingleplayer()) { MutatorManager.Instance.GameStateChanged -= RemoveBrokenDoors; } initDone = false; actualLevel = null; } } internal class ApolloElevenPatch { [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePostfix() { if (SemiFunc.RunIsLevel()) { PlayerController.instance.AntiGravity(float.MaxValue); if (SemiFunc.IsMasterClientOrSingleplayer()) { MakeAllPhysGrabObjectsZeroGravity(); } } else { PlayerController.instance.AntiGravity(0f); } } [HarmonyPostfix] [HarmonyPatch(typeof(PhysGrabObjectImpactDetector))] [HarmonyPatch("Update")] private static void PhysGrabObjectImpactDetectorUpdatePostfix(PhysGrabObjectImpactDetector __instance) { if (SemiFunc.IsMasterClientOrSingleplayer() && !MutatorSettings.ApolloEleven.ApplyInCart && !__instance.isNotValuable) { if (__instance.inCart && !__instance.inCartPrevious) { __instance.physGrabObject.OverrideDrag(0.5f, 0.1f); __instance.physGrabObject.OverrideAngularDrag(0.5f, 0.1f); __instance.physGrabObject.OverrideZeroGravity(0.1f); } else if (!__instance.inCart && __instance.inCartPrevious) { MakeObjectZeroGravity(__instance.physGrabObject); } } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerController))] [HarmonyPatch("AntiGravity")] private static bool PlayControllerAntiGravityPrefix(float _timer) { return _timer == float.MaxValue; } [HarmonyPrefix] [HarmonyPatch(typeof(PhysGrabObject))] [HarmonyPatch("OverrideDrag")] private static bool PhysGrabObjectOverrideDragPrefix(PhysGrabObject __instance, float value, float time) { if (__instance.impactDetector.inCart && !MutatorSettings.ApolloEleven.ApplyInCart) { return true; } return time == float.MaxValue; } [HarmonyPrefix] [HarmonyPatch(typeof(PhysGrabObject))] [HarmonyPatch("OverrideAngularDrag")] private static bool PhysGrabObjectOverrideAngularDragPrefix(PhysGrabObject __instance, float value, float time) { if (__instance.impactDetector.inCart && !MutatorSettings.ApolloEleven.ApplyInCart) { return true; } return time == float.MaxValue; } [HarmonyPrefix] [HarmonyPatch(typeof(PhysGrabObject))] [HarmonyPatch("OverrideZeroGravity")] private static bool PhysGrabObjectOverrideZeroGravityPrefix(PhysGrabObject __instance, float time) { if (__instance.impactDetector.inCart && !MutatorSettings.ApolloEleven.ApplyInCart) { return true; } return time == float.MaxValue; } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerController))] [HarmonyPatch("FixedUpdate")] private static void PlayerControllerFixedUpdatePrefix(PlayerController __instance) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!ChatManager.instance.StateIsActive() && Input.GetKey(MutatorSettings.ApolloEleven.DownwardsKey)) { __instance.rb.AddForce(Vector3.down * 50f, (ForceMode)0); } } [HarmonyPostfix] [HarmonyPatch(typeof(RoundDirector))] [HarmonyPatch("PhysGrabObjectAdd")] private static void RoundDirectorPhysGrabObjectAddPostfix(PhysGrabObject _physGrabObject) { MakeObjectZeroGravity(_physGrabObject); } private static void MakeAllPhysGrabObjectsZeroGravity() { foreach (PhysGrabObject physGrabObject in RoundDirector.instance.physGrabObjects) { MakeObjectZeroGravity(physGrabObject); } } private static void MakeObjectZeroGravity(PhysGrabObject physGrabObject) { if (MutatorSettings.ApolloEleven.ApplyToEnemies || !Object.op_Implicit((Object)(object)((Component)physGrabObject).GetComponent())) { physGrabObject.OverrideDrag(0.5f, float.MaxValue); physGrabObject.OverrideAngularDrag(0.5f, float.MaxValue); physGrabObject.OverrideZeroGravity(float.MaxValue); } } } internal class DuckThisPatch { private const string Ducky = "Apex Predator"; [HarmonyPostfix] [HarmonyPriority(99)] [HarmonyPatch(typeof(EnemyDirector))] [HarmonyPatch("AmountSetup")] private static void EnemyDirectorAmountSetupPostfix(EnemyDirector __instance) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } IList enemyList = __instance.enemyList; if (enemyList.Any((EnemySetup setup) => setup.spawnObjects.Select((PrefabRef so) => ((PrefabRef)(object)so).Prefab.GetComponent()).Any((EnemyParent ep) => (Object)(object)ep != (Object)null && ep.enemyName == "Apex Predator"))) { return; } EnemySetup val = ((IEnumerable)Enemies.AllEnemies).FirstOrDefault((Func)((EnemySetup enemySetup) => ((Object)enemySetup).name == "Enemy - Duck")); if (Object.op_Implicit((Object)(object)val)) { IList list = enemyList.Where(delegate(EnemySetup setup) { IEnumerable source = from so in setup.spawnObjects select ((PrefabRef)(object)so).Prefab.GetComponent() into ep where (Object)(object)ep != (Object)null select ep; return source.All((EnemyParent ep) => (int)ep.difficulty == 0) && source.All((EnemyParent ep) => ep.enemyName != "Apex Predator"); }).ToList(); if (list.Count == 0) { RepoMutators.Logger.LogWarning("No suitable enemies found to replace with Apex Predator"); return; } EnemySetup val2 = list[Random.RandomRangeInt(0, list.Count)]; if (!enemyList.Remove(val2)) { return; } RepoMutators.Logger.LogDebug("[" + MutatorSettings.DuckThis.MutatorName + "] " + ((Object)val2).name + " was removed in favor of Apex Predator"); enemyList.Add(val); } RepoMutators.Logger.LogInfo($"Duck cooldown: {MutatorSettings.DuckThis.AggroCooldown}"); } [HarmonyPrefix] [HarmonyPatch(typeof(EnemyDuck))] [HarmonyPatch("Update")] private static void EnemyDuckUpdatePrefix(EnemyDuck __instance) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 if (SemiFunc.IsMasterClientOrSingleplayer()) { DuckThisBehaviour orAddComponent = ComponentHolderProtocol.GetOrAddComponent((Object)(object)__instance); if (((int)__instance.currentState == 5 || (int)__instance.currentState == 6 || (int)__instance.currentState == 7) && orAddComponent.CanNotice()) { __instance.UpdateState((State)11); } if ((int)__instance.currentState == 16) { __instance.playerTarget = null; __instance.UpdateState((State)1); orAddComponent.NoticeCooldown = MutatorSettings.DuckThis.AggroCooldown; } } } } internal class FiringMyLaserPatch { private static bool LaserBlocked = false; private static bool LaserOnHurt = true; private static void OnMetadataChanged(IDictionary metadata) { LaserOnHurt = metadata.Get("laser-on-hurt-enabled"); bool flag = metadata.Get("laser-action-enabled"); FiringMyLaserMutatorSettings firingMyLaser = MutatorSettings.FiringMyLaser; if (!MutatorAnnouncingBag.Instance.TryGetAnnouncement(firingMyLaser.NamespacedName, out MutatorAnnouncement announcement)) { RepoMutators.Logger.LogError("[" + firingMyLaser.MutatorName + "] Unable to find announcement, could not update description."); } else if (!flag && !LaserOnHurt) { announcement.UpdateBaseDescription("Laser module not installed..."); } else if (!flag) { announcement.UpdateBaseDescription("Fire your laser by pressing {specialActionKey}\nUncontrollably fire your laser when taking damage".Split("\n")[1]); } else if (!LaserOnHurt) { announcement.UpdateBaseDescription("Fire your laser by pressing {specialActionKey}\nUncontrollably fire your laser when taking damage".Split("\n")[0]); } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("Start")] private static void PlayerAvatarStartPostfix(PlayerAvatar __instance) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } string text = "Xepos.REPO-Mutators/FiringMyLaser"; PrefabRef val = default(PrefabRef); if (!NetworkPrefabs.TryGetNetworkPrefabRef(text, ref val)) { RepoMutators.Logger.LogError("Unable to instantiate laser: Could not find PrefabRef with id " + text); return; } GameObject val2 = NetworkPrefabs.SpawnNetworkPrefab(val, Vector3.zero, Quaternion.identity, (byte)0, new object[4] { __instance.steamID, MutatorSettings.FiringMyLaser.LaserActionCooldown, MutatorSettings.FiringMyLaser.LaserActionEnemyDamage, MutatorSettings.FiringMyLaser.LaserActionEnabled }); if (!Object.op_Implicit((Object)(object)val2) || (Object)(object)val2 == (Object)null) { RepoMutators.Logger.LogWarning("Failed to create laser for " + __instance.playerName); } else if (!SemiFunc.IsMultiplayer()) { val2.transform.SetParent(((Component)__instance).transform, false); LaserFiringBehaviour componentInChildren = val2.GetComponentInChildren(); if (Object.op_Implicit((Object)(object)componentInChildren)) { val2.SetActive(true); componentInChildren.laserCooldown = MutatorSettings.FiringMyLaser.LaserActionCooldown; componentInChildren.laserCooldownTimer = MutatorSettings.FiringMyLaser.LaserActionCooldown; componentInChildren.manualActionEnabled = MutatorSettings.FiringMyLaser.LaserActionEnabled; ((HurtCollider)val2.GetComponentInChildren(true)).enemyDamage = MutatorSettings.FiringMyLaser.LaserActionEnemyDamage; } } } [HarmonyPrefix] [HarmonyPatch(typeof(HurtCollider))] [HarmonyPatch("PlayerHurt")] private static bool HurtColliderPlayerHurt(HurtCollider __instance, PlayerAvatar _player) { if (__instance is PlayerIgnoringHurtCollider playerIgnoringHurtCollider && playerIgnoringHurtCollider.ignoredPlayers.Contains(_player)) { return false; } return true; } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerHealth))] [HarmonyPatch("HurtOtherRPC")] private static void PlayerHealthHurtOtherRPCPrefix(PlayerHealth __instance, int damage, Vector3 hurtPosition, int enemyIndex) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance.playerAvatar != (Object)(object)PlayerAvatar.instance) && enemyIndex == -1 && !(hurtPosition != Vector3.zero)) { LaserBlocked = true; } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerHealth))] [HarmonyPatch("Hurt")] private static void PlayerHealthHurtPostfix(PlayerHealth __instance, int damage) { if (LaserOnHurt && damage >= 1 && !__instance.playerAvatar.deadSet && !LaserBlocked) { LaserFiringBehaviour componentInChildren = ((Component)__instance.playerAvatar).GetComponentInChildren(); if (Object.op_Implicit((Object)(object)componentInChildren) && !componentInChildren.IsActive() && !componentInChildren.IsReviveLockout()) { componentInChildren.FireLaser(2.5f); } } } [HarmonyPostfix] [HarmonyPriority(1)] [HarmonyPatch(typeof(PlayerHealth))] [HarmonyPatch("Hurt")] private static void PlayerHealthHurtLaserResetPostfix() { LaserBlocked = false; } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("PlayerDeath")] private static void PlayerAvatarDeathPostfix(PlayerAvatar __instance) { LaserFiringBehaviour componentInChildren = ((Component)__instance).GetComponentInChildren(true); if (Object.op_Implicit((Object)(object)componentInChildren)) { componentInChildren.StopLaser(localOnly: true); } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("Revive")] private static void PlayerAvatarReviveRPCPostfix(PlayerAvatar __instance) { LaserFiringBehaviour componentInChildren = ((Component)__instance).GetComponentInChildren(true); if (Object.op_Implicit((Object)(object)componentInChildren)) { componentInChildren.ActivateReviveLockout(); } } private static void BeforeUnpatchAll() { LaserBlocked = false; LaserOnHurt = true; } } internal class HandleWithCarePatch { private const string SurplusValuable = "Surplus Valuable"; private static readonly IList valuableObjects = new List(); private static bool SetupDone = false; [HarmonyPostfix] [HarmonyPatch(typeof(ValuableObject))] [HarmonyPatch("Awake")] private static void ValuableObjectAwake(ValuableObject __instance) { if (SemiFunc.IsMasterClientOrSingleplayer() && (MutatorSettings.HandleWithCare.MultiplySurplusValue || !((Object)((Component)__instance).gameObject).name.StartsWith("Surplus Valuable"))) { valuableObjects.Add(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(ValuableObject))] [HarmonyPatch("DollarValueSetLogic")] private static void ValuableObjectDollarValueSetLogicPostfix(ValuableObject __instance) { if (SemiFunc.IsMasterClientOrSingleplayer() && SetupDone && (MutatorSettings.HandleWithCare.MultiplySurplusValue || !((Object)((Component)__instance).gameObject).name.StartsWith("Surplus Valuable"))) { __instance.dollarValueCurrent *= MutatorSettings.HandleWithCare.ValueMultiplier; __instance.dollarValueOriginal *= MutatorSettings.HandleWithCare.ValueMultiplier; } } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePostfix() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } SetupDone = true; foreach (ValuableObject valuableObject in valuableObjects) { valuableObject.dollarValueCurrent *= MutatorSettings.HandleWithCare.ValueMultiplier; valuableObject.dollarValueOriginal *= MutatorSettings.HandleWithCare.ValueMultiplier; valuableObject.photonView.RPC("DollarValueSetRPC", (RpcTarget)1, new object[1] { valuableObject.dollarValueCurrent }); } valuableObjects.Clear(); } [HarmonyPrefix] [HarmonyPatch(typeof(PhysGrabObjectImpactDetector))] [HarmonyPatch("BreakRPC")] private static void PhysGrabObjectImpactDetectorBreakRPCPrefix(PhysGrabObjectImpactDetector __instance, ref float valueLost, bool _loseValue) { if (SemiFunc.IsMasterClientOrSingleplayer() && (MutatorSettings.HandleWithCare.InstantlyDestroySurplus || !((Object)__instance).name.StartsWith("Surplus Valuable")) && __instance.isValuable && _loseValue) { valueLost = __instance.valuableObject.dollarValueCurrent; } } private static void BeforeUnpatchAll() { SetupDone = false; valuableObjects.Clear(); } } internal class HuntingSeasonPatch { [HarmonyPostfix] [HarmonyPriority(300)] [HarmonyPatch(typeof(EnemyDirector))] [HarmonyPatch("Start")] private static void EnemyDirectorAmountSetupPostfix(EnemyDirector __instance) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } __instance.DisableEnemies(MutatorSettings.HuntingSeason, (EnemySetup setup) => setup.spawnObjects.All(delegate(PrefabRef so) { EnemyParent component = ((PrefabRef)(object)so).Prefab.GetComponent(); if ((Object)(object)component == (Object)null) { return true; } if (!(component.enemyName == "Peeper")) { EnemyHealth componentInChildren = ((PrefabRef)(object)so).Prefab.GetComponentInChildren(); if (componentInChildren == null) { return false; } return !componentInChildren.spawnValuable; } return true; })); } [HarmonyPrefix] [HarmonyPatch(typeof(StatsManager))] [HarmonyPatch("ItemFetchName")] private static void StatsManagerItemFetchNamePrefix(ref string itemName, ItemAttributes itemAttributes) { if (Object.op_Implicit((Object)(object)((Component)itemAttributes).GetComponent())) { itemName += "(Hunting Season)"; } } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePostfix() { //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer() || !SemiFunc.RunIsLevel()) { return; } int num = RoundDirector.instance.physGrabObjects.Count / 2; Item[] possibleItems = GetPossibleItems(); if (possibleItems.Length == 0) { RepoMutators.Logger.LogWarning("No eligable weapons found"); RepoMutators.Logger.LogWarning("Valuables will not removed in order to prevent softlocks"); return; } try { foreach (PhysGrabObject item in RoundDirector.instance.physGrabObjects.ToList()) { if (Object.op_Implicit((Object)(object)item) && item.isValuable) { item.DestroyPhysGrabObject(); } } } catch (Exception arg) { RepoMutators.Logger.LogError(string.Format("[{0}] Error while removing valuables: {1}", "Hunting Season", arg)); } finally { RepoMutators.Logger.LogDebug(string.Format("[{0}] Spawning {1} weapons", "Hunting Season", num)); IList list = SemiFunc.LevelPointsGetAll(); IList list2 = new List(); for (int i = 0; i < num; i++) { LevelPoint val = list[Random.Range(0, list.Count)]; Item val2 = possibleItems[Random.Range(0, possibleItems.Length)]; Vector3 position = ((Component)val).transform.position; position.y += 2f; GameObject val3 = Items.SpawnItem(val2, position, Quaternion.identityQuaternion); if (!((Object)(object)val3 == (Object)null)) { val3.AddComponent(); PhotonView component = val3.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { list2.Add(component); } } } MutatorsNetworkManager.Instance.SendComponentForViews(list2.Select((PhotonView x) => x.ViewID).ToArray(), typeof(TemporaryLevelItemBehaviour)); } } [HarmonyPostfix] [HarmonyPatch(typeof(ItemAttributes))] [HarmonyPatch("Start")] private static void ItemAttributesStartPostfix(ItemAttributes __instance) { TemporaryLevelItemBehaviour component = ((Component)__instance).gameObject.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { __instance.itemName += " (Temporary)"; } } [HarmonyPostfix] [HarmonyPatch(typeof(EnemyParent))] [HarmonyPatch("Despawn")] private static void EnemyParentDespawnPostfix(EnemyParent __instance) { if (__instance.Enemy.HasHealth && __instance.DespawnedTimer > 10f) { __instance.DespawnedTimer = 10f; __instance.Enemy.Health.spawnValuableCurrent = 0; } } [HarmonyPostfix] [HarmonyPatch(typeof(RunManager))] [HarmonyPriority(500)] [HarmonyPatch("ChangeLevel")] private static void RunManagerChangeLevelPostfix() { if (!SemiFunc.IsMultiplayer() || !SemiFunc.IsNotMasterClient()) { TemporaryItemUtils.DropAndRemoveMarkedItems("Hunting Season"); } } [HarmonyPostfix] [HarmonyPatch(typeof(RunManager))] [HarmonyPriority(500)] [HarmonyPatch("UpdateLevel")] private static void RunManagerUpdateLevelPostfix() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { TemporaryItemUtils.DropAndRemoveMarkedItems("Hunting Season"); } } [HarmonyPrefix] [HarmonyPatch(typeof(PunManager))] [HarmonyPatch("SyncAllDictionaries")] private static void PunManagerSyncAllDictionariesPrefix() { if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.RunIsShop()) { TemporaryItemUtils.RemoveMarkedItems("Hunting Season"); } } private static Item[] GetPossibleItems() { return Items.AllItems.Where((Item i) => !Object.op_Implicit((Object)(object)((PrefabRef)(object)i.prefab).Prefab.GetComponent()) && ((int)i.itemType == 7 || (int)i.itemType == 9)).ToArray(); } } internal class LessIsMorePatch { private const string SurplusValuable = "Surplus Valuable"; internal const string ValueGainMultiplier = "value-gain-multiplier"; private static float valueGainMultiplier = MutatorSettings.LessIsMore.ValueGainMultiplier; private static void OnMetadataChanged(IDictionary metadata) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { valueGainMultiplier = metadata.Get("value-gain-multiplier"); } } [HarmonyPostfix] [HarmonyPriority(500)] [HarmonyPatch(typeof(ValuableObject))] [HarmonyPatch("DollarValueSetLogic")] private static void ValuableObjectDollarValueSetLogicPostfix(ValuableObject __instance) { if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)((Component)__instance).gameObject).name.StartsWith("Surplus Valuable") && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { float num = Mathf.InverseLerp(100f, 30f, __instance.durabilityPreset.fragility); float num2 = Mathf.Lerp(MutatorSettings.LessIsMore.StrongDivisionFactor, MutatorSettings.LessIsMore.WeakDivisionFactor, num); __instance.dollarValueCurrent /= num2; __instance.dollarValueOriginal /= num2; ComponentHolderProtocol.AddComponent((Object)(object)__instance); } } [HarmonyPrefix] [HarmonyPatch(typeof(RoundDirector))] [HarmonyPatch("StartRoundLogic")] private static void RoundDirectorStartRoundLogic(ref int value) { if (SemiFunc.IsMasterClientOrSingleplayer()) { value = (int)((double)value * 1.1); } } [HarmonyPrefix] [HarmonyPatch(typeof(PhysGrabObjectImpactDetector))] [HarmonyPatch("BreakRPC")] private static void PhysGrabObjectImpactDetectorBreakRPC(PhysGrabObjectImpactDetector __instance, ref float valueLost, bool _loseValue) { if (_loseValue && __instance.isValuable && !__instance.isNotValuable && !((Object)((Component)__instance).gameObject).name.StartsWith("Surplus Valuable")) { if (SemiFunc.IsMasterClientOrSingleplayer()) { ((Component)__instance).GetComponent()?.SubtractValue(valueLost); } valueLost = (0f - valueLost) * valueGainMultiplier; } } private static void AfterUnpatchAll() { valueGainMultiplier = MutatorSettings.LessIsMore.ValueGainMultiplier; } } internal class NullSignalPatch { private const int Priority = 5; [HarmonyPostfix] [HarmonyPriority(5)] [HarmonyPatch(typeof(MutatorAnnouncement))] [HarmonyPatch("GetName")] private static void MutatorAnnouncementNamePostfix(ref string __result) { __result = "Null Signal"; } [HarmonyPostfix] [HarmonyPriority(5)] [HarmonyPatch(typeof(MutatorAnnouncement))] [HarmonyPatch("GetDescription")] private static void MutatorAnnouncementDescriptionPostfix(ref string __result) { __result = "Active Mutator information is hidden"; } [HarmonyPostfix] [HarmonyPriority(50)] [HarmonyPatch(typeof(LoadingUI))] [HarmonyPatch("StopLoading")] private static void LoadingUIStopLoadingPostfix() { TargetPlayerAnnouncingBehaviour instance = TargetPlayerAnnouncingBehaviour.Instance; SpecialActionAnnouncingBehaviour instance2 = SpecialActionAnnouncingBehaviour.Instance; if (Object.op_Implicit((Object)(object)instance)) { ((Component)instance).gameObject.SetActive(false); } if (Object.op_Implicit((Object)(object)instance2)) { ((Component)instance2).gameObject.SetActive(false); } } } internal class OneShotOneKillPatch { [HarmonyPostfix] [HarmonyPatch(typeof(PlayerHealthGrab))] [HarmonyPatch("Start")] private static void PlayerHealthGrabStart(PlayerHealthGrab __instance) { ((Behaviour)__instance).enabled = false; } [HarmonyPostfix] [HarmonyPriority(300)] [HarmonyPatch(typeof(EnemyDirector))] [HarmonyPatch("Start")] private static void EnemyDirectorAmountSetupPostfix(EnemyDirector __instance) { if (SemiFunc.IsMasterClientOrSingleplayer()) { __instance.DisableEnemies(MutatorSettings.OneShotOneKill); } } [HarmonyPostfix] [HarmonyPriority(450)] [HarmonyPatch(typeof(PlayerDeathHead))] [HarmonyPatch("Update")] private static void PlayerDeathHeadUpdatePostfix(PlayerDeathHead __instance) { if (__instance.triggered && MutatorSettings.OneShotOneKill.InstaReviveInTruckOrExtraction && !SemiFunc.IsNotMasterClient()) { if (__instance.roomVolumeCheck.inTruck) { DoRevive(__instance, inTruck: true); } else if (__instance.roomVolumeCheck.inExtractionPoint) { DoRevive(__instance, inTruck: false); } } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerHealth))] [HarmonyPatch("Hurt")] private static void PlayerHealthHurtPrefix(PlayerHealth __instance, ref int damage, ref bool savingGrace) { if (!__instance.godMode && damage >= 1) { damage = __instance.maxHealth; savingGrace = false; } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerHealth))] [HarmonyPatch("HurtOther")] private static void PlayerHealthHurtOtherPrefix(PlayerHealth __instance, ref int damage, ref bool savingGrace) { if (!__instance.godMode && damage >= 1) { damage = __instance.maxHealth; savingGrace = false; } } private static void DoRevive(PlayerDeathHead playerDeathHead, bool inTruck) { int num = ((MutatorSettings.OneShotOneKill.InstaReviveHealth == 0) ? (playerDeathHead.playerAvatar.playerHealth.maxHealth - 1) : (MutatorSettings.OneShotOneKill.InstaReviveHealth - 1)); playerDeathHead.playerAvatar.Revive(inTruck); if (num > 0) { playerDeathHead.playerAvatar.playerHealth.HealOther(num, true); } } } [HarmonyPatch(typeof(EnemyHealth))] internal class OutWithABangPatch { private static ExplosionPreset explosionPreset = null; private static readonly float ExplosionSizeFallback = 3f; private static readonly int ExplosionDamageFallback = 200; private static readonly IDictionary SizeDamage = new Dictionary(); private static void OnMetadataChanged(IDictionary metadata) { float item = metadata.Get("tier-1-enemy-explosion-radius"); int item2 = metadata.Get("tier-1-enemy-explosion-damage"); SizeDamage[(Difficulty)0] = (item, item2); float item3 = metadata.Get("tier-2-enemy-explosion-radius"); int item4 = metadata.Get("tier-2-enemy-explosion-damage"); SizeDamage[(Difficulty)1] = (item3, item4); float item5 = metadata.Get("tier-3-enemy-explosion-radius"); int item6 = metadata.Get("tier-3-enemy-explosion-damage"); SizeDamage[(Difficulty)2] = (item5, item6); } [HarmonyPostfix] [HarmonyPatch("Awake")] private static void EnemeyHealthAwakePostfix(EnemyHealth __instance) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown if ((Object)(object)explosionPreset == (Object)null) { explosionPreset = Object.Instantiate(AssetStore.Preset); } EnemyParent enemyParent = __instance.enemy.EnemyParent; if (enemyParent.enemyName != "Banger") { ParticleScriptExplosion particleScriptExplosion = ComponentHolderProtocol.AddComponent((Object)(object)__instance); particleScriptExplosion.explosionPreset = explosionPreset; float explosionSize = ExplosionSizeFallback; int explosionDamage = ExplosionDamageFallback; if (SizeDamage.TryGetValue(enemyParent.difficulty, out (float, int) value)) { (explosionSize, explosionDamage) = value; } __instance.onDeath.AddListener((UnityAction)delegate { Explode(__instance.enemy, particleScriptExplosion, explosionSize, explosionDamage); }); } } private static void Explode(Enemy enemy, ParticleScriptExplosion particleScriptExplosion, float size, int damage) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) particleScriptExplosion.Spawn(enemy.CenterTransform.position, size, damage, damage, 1f, false, false, 1f); } private static void BeforeUnpatchAll() { SizeDamage.Clear(); } } internal class ProtectThePresidentPatch { private const string PresidentId = "presidentId"; private static bool _presidentAlive = true; private static bool _failureMessageSent = false; private static string? _presidentId; private static void OnMetadataChanged(IDictionary metadata) { string text = metadata.Get("presidentId"); if (_presidentId != text) { _presidentId = text; UpdatePresidentHealth(_presidentId); } } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePostfix() { _presidentAlive = true; _failureMessageSent = false; if (SemiFunc.IsMultiplayer() && SemiFunc.IsMasterClient()) { PlayerAvatar val = PickPresidentPlayer(); RepoMutators.Logger.LogDebug("Picked " + val.playerName + " as the president!"); SendPresidentMeta(val); } } [HarmonyPrefix] [HarmonyPatch(typeof(NetworkManager))] [HarmonyPatch("OnPlayerLeftRoom")] private static void NetworkManagerOnPlayerLeftRoomPrefix(Player otherPlayer) { PlayerAvatar val = SemiFunc.PlayerGetFromName(otherPlayer.NickName); if (val.steamID == _presidentId && SemiFunc.IsMultiplayer() && SemiFunc.IsMasterClient()) { PlayerAvatar president = PickPresidentPlayer(); SendPresidentMeta(president); } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("PlayerDeathRPC")] private static void PlayerAvatarPlayerDeathRPCPostfix(PlayerAvatar __instance, int enemyIndex) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (__instance.steamID == _presidentId && __instance.steamID != PlayerAvatar.instance.steamID) { _presidentAlive = false; PlayerAvatar val = SemiFunc.PlayerGetFromSteamID(_presidentId); SemiFunc.UIFocusText("President " + ((val != null && val.playerName != null) ? (val.playerName + " ") : "") + " has died.", Color.white, AssetManager.instance.colorYellow, 3f); ChatManager.instance.PossessSelfDestruction(); } } [HarmonyPrefix] [HarmonyPatch(typeof(ChatManager))] [HarmonyPatch("PossessChat")] private static void ChatManagerPossessChatPrefix(PossessChatID _possessChatID, ref string message) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 if (!_presidentAlive && !_failureMessageSent && (int)_possessChatID == 3) { message = "We have failed " + (SemiFunc.PlayerGetFromSteamID(_presidentId)?.playerName ?? " the president"); _failureMessageSent = true; } } [HarmonyPostfix] [HarmonyPriority(100)] [HarmonyPatch(typeof(PlayerHealth))] [HarmonyPatch("UpdateHealthRPC")] private static void PlayerHealthUpdateHealthRPCPostfix(PlayerHealth __instance) { if (!(__instance.playerAvatar.steamID != _presidentId) && !(_presidentId == PlayerAvatar.instance.steamID)) { UpdatePresidentHealth(_presidentId); } } [HarmonyPrefix] [HarmonyPatch(typeof(LoadingUI))] [HarmonyPatch("StopLoading")] private static void InitializePresidentHealth() { if (!SemiFunc.RunIsLevel()) { TargetPlayerAnnouncingBehaviour instance = TargetPlayerAnnouncingBehaviour.Instance; if (Object.op_Implicit((Object)(object)instance)) { ((TMP_Text)instance.Text).text = string.Empty; } } else if (_presidentId != null && _presidentId != PlayerAvatar.instance.steamID) { MutatorsNetworkManager.Instance.Run(InitializePresidentHealthEnumerator(_presidentId)); } } private static void UpdatePresidentHealth(string presidentId) { TargetPlayerAnnouncingBehaviour instance = TargetPlayerAnnouncingBehaviour.Instance; if (Object.op_Implicit((Object)(object)instance)) { RepoMutators.Logger.LogDebug("Updating President Health"); if (presidentId == PlayerAvatar.instance.steamID) { ((TMP_Text)instance.Text).text = string.Empty; } else { ((TMP_Text)instance.Text).text = BuildPresidentText(presidentId); } } } internal static string BuildPresidentText(string presidentId) { PlayerAvatar val = SemiFunc.PlayerAvatarGetFromSteamID(presidentId); return string.Format("{0}: {1}/{2}", val.playerName ?? "President", val.playerHealth.health, val.playerHealth.maxHealth); } private static IEnumerator InitializePresidentHealthEnumerator(string presidentId) { while ((Object)(object)TargetPlayerAnnouncingBehaviour.Instance == (Object)null) { yield return (object)new WaitForSeconds(0.5f); } UpdatePresidentHealth(presidentId); } private static PlayerAvatar PickPresidentPlayer() { List list = SemiFunc.PlayerGetAll(); return list[Random.RandomRangeInt(0, list.Count)]; } private static void SendPresidentMeta(PlayerAvatar president) { MutatorsNetworkManager.Instance.SendMetadata(MutatorSettings.ProtectThePresident.NamespacedName, new Dictionary { { "presidentId", president.steamID } }); } private static void AfterUnpatchAll() { _presidentId = null; } } internal class ProtectTheWeakPatch { private static bool initDone = false; private static int initialHealth = 100; internal const string BodyGuardId = "BodyguardId"; internal const string TranqViewId = "tranqViewId"; private static string? _bodyGuardId = null; private static IDictionary _clients = new Dictionary(); private static void OnMetadataChanged(IDictionary metadata) { string text = metadata.Get("BodyguardId"); _clients = metadata.Get>("clients") ?? new Dictionary(); if (text != _bodyGuardId) { _bodyGuardId = text; PlayerAvatar instance = PlayerAvatar.instance; BodyguardPlayerHealthBehaviour bodyguardPlayerHealthBehaviour = ((instance != null) ? ((Component)instance).GetComponent() : null); if ((Object)(object)bodyguardPlayerHealthBehaviour != (Object)null && Object.op_Implicit((Object)(object)bodyguardPlayerHealthBehaviour)) { bodyguardPlayerHealthBehaviour.BodyguardId = _bodyGuardId; } AssignBodyguard(metadata); } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("Awake")] private static void PlayerAvatarAwakePrefix(PlayerAvatar __instance) { MutatorsNetworkManager.Instance.Run(Check(__instance)); } private static IEnumerator Check(PlayerAvatar playerAvatar) { while (playerAvatar.steamID == null) { yield return (object)new WaitForSeconds(0.1f); } if (playerAvatar.steamID == PlayerAvatar.instance.steamID) { ComponentHolderProtocol.AddComponent((Object)(object)playerAvatar); } } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePostfix() { StartupLogic(); } [HarmonyPrefix] [HarmonyPatch(typeof(StatsManager))] [HarmonyPatch("ItemFetchName")] private static void StatsManagerItemFetchNamePrefix(ref string itemName, ItemAttributes itemAttributes) { if (Object.op_Implicit((Object)(object)((Component)itemAttributes).GetComponent())) { itemName += "(Protect the Weak)"; } } [HarmonyPostfix] [HarmonyPatch(typeof(ItemAttributes))] [HarmonyPatch("Start")] private static void ItemAttributesStartPostfix(ItemAttributes __instance) { TemporaryLevelItemBehaviour component = ((Component)__instance).gameObject.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { __instance.itemName += " (Bodyguard Only)"; } } [HarmonyPrefix] [HarmonyPatch(typeof(ItemGun))] [HarmonyPatch("Shoot")] private static bool ItemGunShootPrefix(ItemGun __instance) { if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent())) { bool flag = false; foreach (PhysGrabber item in __instance.physGrabObject.playerGrabbing) { flag = item.playerAvatar.steamID == _bodyGuardId; if (flag) { break; } } return flag; } return true; } [HarmonyPrefix] [HarmonyPatch(typeof(NetworkManager))] [HarmonyPatch("OnPlayerLeftRoom")] private static void NetworkManagerOnPlayerLeftRoomPrefix(Player otherPlayer) { PlayerAvatar val = SemiFunc.PlayerGetFromName(otherPlayer.NickName); if (val.steamID == _bodyGuardId) { StartupLogic(val.steamID); } } [HarmonyPrefix] [HarmonyPatch(typeof(ItemBattery))] [HarmonyPatch("RemoveFullBar")] private static bool ItemBatteryRemoveFullBarPrefix(ItemBattery __instance) { return !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent()); } [HarmonyPostfix] [HarmonyPatch(typeof(RunManager))] [HarmonyPriority(500)] [HarmonyPatch("ChangeLevel")] private static void RunManagerChangeLevelPostfix() { if (!SemiFunc.IsMultiplayer() || !SemiFunc.IsNotMasterClient()) { TemporaryItemUtils.DropAndRemoveMarkedItems("Protect the Weak"); } } [HarmonyPostfix] [HarmonyPatch(typeof(RunManager))] [HarmonyPriority(500)] [HarmonyPatch("UpdateLevel")] private static void RunManagerUpdateLevelPostfix() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { TemporaryItemUtils.DropAndRemoveMarkedItems("Protect the Weak"); } } [HarmonyPrefix] [HarmonyPatch(typeof(PunManager))] [HarmonyPatch("SyncAllDictionaries")] private static void PunManagerSyncAllDictionariesPrefix() { if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.RunIsShop()) { TemporaryItemUtils.RemoveMarkedItems("Protect the Weak"); } } [HarmonyPrefix] [HarmonyPatch(typeof(TruckScreenText))] [HarmonyPatch("GotoNextLevel")] private static void TruckScreenTextEngineStartRPCPrefix() { if (!SemiFunc.IsMultiplayer() || !SemiFunc.IsMasterClient()) { return; } foreach (PlayerAvatar item in from player in SemiFunc.PlayerGetAll() where player.steamID != PlayerAvatar.instance.steamID select player) { int? num = _clients.Get>(item.steamID).Get("originalHealth"); if (!num.HasValue) { RepoMutators.Logger.LogWarning("Failed to restore original health for " + item.playerName); continue; } RepoMutators.Logger.LogDebug($"Setting health to {num.Value} for {item.playerName}"); StatsManager.instance.SetPlayerHealth(item.steamID, num.Value, false); } ((Component)PlayerAvatar.instance).GetComponent()?.RestoreOriginalHealth(); } [HarmonyPostfix] [HarmonyPriority(300)] [HarmonyPatch(typeof(PunManager))] [HarmonyPatch("UpdateHealthRightAway")] private static void PunManagerUpgradeHealthRightAwayPostfix(string _steamID) { PlayerAvatar val = SemiFunc.PlayerAvatarGetFromSteamID(_steamID); BodyguardPlayerHealthBehaviour component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { component.originalHealth += 20; component.originalMaxHealth += 20; component.UpdateHealth(); component.SendHealth(); } } [HarmonyPostfix] [HarmonyPriority(100)] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("PlayerDeathRPC")] private static void PlayerDeathRPCPostfix() { PlayerAvatar localPlayer = PlayerAvatar.instance; if (_bodyGuardId == PlayerAvatar.instance.steamID && !localPlayer.deadSet) { IList list = SemiFunc.PlayerGetAll(); if (list.Count > 1 && list.Where((PlayerAvatar player) => player.steamID != localPlayer.steamID).All((PlayerAvatar player) => player.deadSet)) { ChatManager.instance.PossessSelfDestruction(); } } } private static PlayerAvatar PickBodyguardPlayer(string? excludedId = null) { List list = (from x in SemiFunc.PlayerGetAll() where x.steamID != excludedId select x).ToList(); return list[Random.RandomRangeInt(0, list.Count)]; } private static void StartupLogic(string? excludedId = null) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClient()) { return; } PlayerAvatar val = PickBodyguardPlayer(excludedId); RepoMutators.Logger.LogDebug("Picked " + val.playerName + " as the bodyguard!"); Item val2 = ((IEnumerable)Items.AllItems).FirstOrDefault((Func)((Item x) => "Tranq Gun".Equals(x.itemName))); if (Object.op_Implicit((Object)(object)val2)) { GameObject val3 = Items.SpawnItem(val2, ((Component)val).transform.position, Quaternion.identity); if ((Object)(object)val3 != (Object)null) { PhotonView component = val3.GetComponent(); int? num = ((component != null) ? new int?(component.ViewID) : ((int?)null)); if (num.HasValue) { MutatorsNetworkManager.Instance.SendMetadata(MutatorSettings.ProtectTheWeak.NamespacedName, BuildMeta(val, num.Value)); MutatorsNetworkManager.Instance.SendComponentForViews(new int[1] { num.Value }, typeof(TemporaryLevelItemBehaviour)); return; } } } RepoMutators.Logger.LogWarning("Failed to spawn Tranq gun"); MutatorsNetworkManager.Instance.SendMetadata(MutatorSettings.ProtectTheWeak.NamespacedName, BuildMeta(val)); } private static void AssignBodyguard(IDictionary metadata) { if (string.IsNullOrEmpty(_bodyGuardId)) { return; } PlayerAvatar instance = PlayerAvatar.instance; MutatorAnnouncingBag instance2 = MutatorAnnouncingBag.Instance; MutatorDescriptionAnnouncingBehaviour instance3 = MutatorDescriptionAnnouncingBehaviour.Instance; MutatorAnnouncement announcement; bool flag = instance2.TryGetAnnouncement(MutatorSettings.ProtectTheWeak.NamespacedName, out announcement); if (initDone) { if (_bodyGuardId == instance.steamID) { if (flag) { string text = metadata.Get("descriptionBodyguard"); announcement.AddOrUpdateSegment(new MutatorAnnouncementDescriptionSegment("role", 10, (text == null) ? string.Empty : ("\n" + text))); } ((Component)instance).GetComponent()?.UpdateHealth(); MutatorsNetworkManager.Instance.Run(EquipDelayed(metadata, 1f)); } else if (flag) { string text2 = metadata.Get("description"); announcement.AddOrUpdateSegment(new MutatorAnnouncementDescriptionSegment("role", 10, (text2 == null) ? string.Empty : ("\n" + text2))); } } else { initDone = true; if (_bodyGuardId == instance.steamID) { if (flag) { string text3 = metadata.Get("descriptionBodyguard"); announcement.AddOrUpdateSegment(new MutatorAnnouncementDescriptionSegment("role", 10, (text3 == null) ? string.Empty : ("\n" + text3))); } MutatorsNetworkManager.Instance.Run(EquipDelayed(metadata)); } else if (flag) { string text4 = metadata.Get("description"); announcement.AddOrUpdateSegment(new MutatorAnnouncementDescriptionSegment("role", 10, (text4 == null) ? string.Empty : ("\n" + text4))); } } if (flag && instance2.MoveTo(announcement) && Object.op_Implicit((Object)(object)instance3)) { instance3.ShowDescription(); } } private static IEnumerator EquipDelayed(IDictionary metadata, float delay = 3f) { yield return (object)new WaitForSeconds(delay); RepoMutators.Logger.LogDebug("I am the bodyguard"); HandleWeapon(metadata.Get("tranqViewId")); } private static void HandleWeapon(int tranqViewId) { //IL_005b: 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_0065: Unknown result type (might be due to invalid IL or missing references) PhotonView val = PhotonView.Find(tranqViewId); ItemEquippable val2 = ((val != null) ? ((Component)val).GetComponent() : null); if ((Object)(object)val2 != (Object)null) { RepoMutators.Logger.LogDebug("Attempting to equip tranq gun"); PlayerAvatar instance = PlayerAvatar.instance; Inventory instance2 = Inventory.instance; int num = instance2.GetFirstFreeInventorySpotIndex(); if (num == -1) { InventorySpot spotByIndex = instance2.GetSpotByIndex(0); spotByIndex.CurrentItem.ForceUnequip(((Component)instance).transform.position + Vector3.forward, instance.photonView.ViewID); num = 0; } val2.RequestEquip(num, instance.photonView.ViewID); } else { RepoMutators.Logger.LogWarning($"Failed to equip bodyguard weapon - viewId: {tranqViewId} - equippable: {(Object)(object)val2 != (Object)null}"); } } private static IDictionary BuildMeta(PlayerAvatar bodyguard, int tranqGunId = 0) { Dictionary dictionary = new Dictionary(); dictionary.Add("BodyguardId", bodyguard.steamID); dictionary.Add("description", "You are fragile but " + bodyguard.playerName + " will protect you!\n" + bodyguard.playerName + " dies if they are the last one standing"); dictionary.Add("descriptionBodyguard", "You are the bodyguard, you have increased health\nYour tranq gun has infinite ammo\nYou die if you are the last one standing\nProtect your friends!"); IDictionary dictionary2 = dictionary; if (tranqGunId > 0) { dictionary2.Add("tranqViewId", tranqGunId); } return dictionary2.WithMutator(MutatorSettings.ProtectTheWeak.NamespacedName); } private static void BeforeUnpatchAll() { initialHealth = 100; initDone = false; _bodyGuardId = null; _clients.Clear(); } } internal class RustyServosPatch { [HarmonyPostfix] [HarmonyPatch(typeof(PhysGrabber))] [HarmonyPatch("Start")] private static void PhysGrabberStartPostfix(PhysGrabber __instance) { if (!((Object)(object)__instance != (Object)(object)PhysGrabber.instance)) { __instance.grabRange += 3f; } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerController))] [HarmonyPatch("Start")] private static void PlayerControllerStartPostfix(PlayerController __instance) { __instance.JumpCooldown = float.MaxValue; } } internal class SealedAwayPatch { private static uint _currentSpawns; private static ScaleOptions scaleOptions = ScaleOptions.Default; private static void BeforePatchAll() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) scaleOptions.IgnoreBonkExpand = true; scaleOptions.RejectExternalApply = true; scaleOptions.Duration = 0f; scaleOptions.AllowedTargets = (ScaleTargets)2; } [HarmonyPostfix] [HarmonyPatch(typeof(ValuableObject))] [HarmonyPatch("DollarValueSetLogic")] private static void ValuableObjectDollarValueSetLogicPostfix(ValuableObject __instance) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } PhysGrabObjectImpactDetector component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { SealedAwayMarkerBehaviour component2 = ((Component)component).GetComponent(); if (!((Object)(object)component2 != (Object)null)) { component.onDestroy.AddListener((UnityAction)delegate { Spawn(__instance); }); ComponentHolderProtocol.AddComponent((Object)(object)component); } } else { RepoMutators.Logger.LogWarning("[Sealed Away] unable to find impactDetector on " + ((Object)((Component)__instance).transform).name); } } private static void Spawn(ValuableObject valuableObject) { //IL_0096: 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_0141: Unknown result type (might be due to invalid IL or missing references) if (_currentSpawns >= MutatorSettings.SealedAway.MaximumMonsterSpawns || !(Random.Range(0f, 100f) <= MutatorSettings.SealedAway.MonsterSpawnChance)) { return; } EnemyDirector instance = EnemyDirector.instance; EnemySetup[] array = (from setup in instance.enemiesDifficulty1.Concat(instance.enemiesDifficulty2).Concat(instance.enemiesDifficulty3) where setup.spawnObjects.Count == 1 && !setup.spawnObjects.Any(delegate(PrefabRef so) { EnemyParent enemyParent = ((PrefabRef)(object)so).Prefab.GetComponent(); if (!((Object)(object)enemyParent == (Object)null)) { EnemyHealth componentInChildren = ((PrefabRef)(object)so).Prefab.GetComponentInChildren(); if (componentInChildren != null && componentInChildren.spawnValuable) { return MutatorSettings.SealedAway.ExcludedEnemies.Any((string excluded) => excluded.Equals(enemyParent?.enemyName, StringComparison.OrdinalIgnoreCase)); } } return true; }) select setup).ToArray(); if (array.Length == 0) { return; } EnemySetup val = array[Random.RandomRangeInt(0, array.Length)]; List list = Enemies.SpawnEnemy(val, ((Component)valuableObject).transform.position, Quaternion.identity, false); if (list == null) { return; } PlayerAvatar lastPlayerGrabbing = valuableObject.physGrabObject.lastPlayerGrabbing; foreach (EnemyParent item in list) { RepoMutators.Logger.LogDebug("Valuable broken - Spawned " + item.enemyName); EnemyVision component = ((Component)item.Enemy).GetComponent(); EnemyHealth component2 = ((Component)item.Enemy).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.health /= 2; component2.healthCurrent = component2.health; component2.spawnValuableMax = int.MaxValue; } ScaleManager.Apply(((Component)item).gameObject, scaleOptions); if (!((Object)(object)component == (Object)null)) { ((Behaviour)component).enabled = false; MutatorsNetworkManager.Instance.Run(ActivateVisionLater(component, lastPlayerGrabbing)); } } _currentSpawns++; } private static IEnumerator ActivateVisionLater(EnemyVision enemyVision, PlayerAvatar? playerAvatar) { yield return (object)new WaitForSeconds(0.5f); ((Behaviour)enemyVision).enabled = true; if (Object.op_Implicit((Object)(object)playerAvatar) && (Object)(object)playerAvatar != (Object)null) { enemyVision.Enemy.SetChaseTarget(playerAvatar); } } private static void BeforeUnpatchAll() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) scaleOptions = ScaleOptions.Default; _currentSpawns = 0u; RepoMutators.Logger.LogDebug($"[Sealed Away] Set tracked monster spawns to {_currentSpawns}"); } } internal class SizeMattersPatch { private static ScaleOptions scaleOptions = ScaleOptions.Default; private static bool _late; private static void OnMetadataChanged(IDictionary metadata) { IList list = new List { "Players" }; if (metadata.Get("scale-valuables")) { list.Add("valuables"); } if (metadata.Get("scale-enemies")) { list.Add("enemies"); } if (metadata.Get("scale-carts")) { list.Add("carts"); } if (MutatorAnnouncingBag.Instance.TryGetAnnouncement(MutatorSettings.SizeMatters.NamespacedName, out MutatorAnnouncement announcement)) { announcement.UpdateBaseDescription(FormatScaleTargets(list) + " are shrunk"); } else { RepoMutators.Logger.LogWarning("[" + MutatorSettings.SizeMatters.MutatorName + "] Unable to find announcement, could not update description."); } } private static string FormatScaleTargets(IList targets) { return targets.Count switch { 1 => targets[0], 2 => string.Join(" and ", targets), _ => string.Join(", ", targets.Take(targets.Count - 1)) + ", and " + targets.Last(), }; } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePostfix() { if (SemiFunc.IsMasterClientOrSingleplayer()) { SetupScaleOptions(); if (!MutatorManager.Instance.HasCurrentMutator(MutatorSettings.NullSignal.NamespacedName)) { SemiFunc.PlayerGetAll().ForEach(ScalePlayer); _late = true; } } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("Start")] private static void PlayerAvatarStartPrefix(PlayerAvatar __instance) { if (_late && SemiFunc.IsMasterClientOrSingleplayer()) { ScalePlayer(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(ExtractionPoint))] [HarmonyPatch("ActivateTheFirstExtractionPointAutomaticallyWhenAPlayerLeaveTruck")] private static void ExtractionPointActivateTheFirstExtractionPointAutomaticallyWhenAPlayerLeaveTruckPostfix() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } if (MutatorManager.Instance.HasCurrentMutator(MutatorSettings.NullSignal.NamespacedName)) { SemiFunc.PlayerGetAll().ForEach(ScalePlayer); _late = true; } foreach (PhysGrabObject item in RoundDirector.instance.physGrabObjects.ToList()) { if (Object.op_Implicit((Object)(object)item) && ShouldScale(item)) { ScaleManager.Apply(((Component)item).gameObject, scaleOptions); } } } [HarmonyPostfix] [HarmonyPriority(300)] [HarmonyPatch(typeof(PhysGrabObject))] [HarmonyPatch("Start")] private static void PhysGrabObjectStartPostfix(PhysGrabObject __instance) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (_late && SemiFunc.IsMasterClientOrSingleplayer() && ShouldScale(__instance)) { ScaleManager.Apply(((Component)__instance).gameObject, scaleOptions); } } [HarmonyPostfix] [HarmonyPatch(typeof(EnemyParent))] [HarmonyPatch("SpawnRPC")] private static void EnemyParentSpawnRPCPostfix(EnemyParent __instance) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer() && MutatorSettings.SizeMatters.ScaleEnemies) { RepoMutators.Logger.LogInfo("Applying scale to " + __instance.enemyName); ScaleManager.Apply(((Component)__instance.Enemy.Rigidbody).gameObject, scaleOptions); } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("ReviveRPC")] private static void PlayerAvatarReviveRPCPostfix(PlayerAvatar __instance) { if (SemiFunc.IsMasterClientOrSingleplayer()) { ScalePlayer(__instance); } } private static void ScalePlayer(PlayerAvatar playerAvatar) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ScaleManager.Apply(((Component)playerAvatar).gameObject, scaleOptions); } private static void SetupScaleOptions() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) scaleOptions.IgnoreBonkExpand = true; scaleOptions.RejectExternalApply = true; scaleOptions.Duration = 0f; scaleOptions.AllowedTargets = (ScaleTargets)15; } private static bool ShouldScale(PhysGrabObject physGrabObject) { if (!IsScalableEnemy(physGrabObject) && !IsScalableCart(physGrabObject)) { return IsScalableItem(physGrabObject); } return true; } private static bool IsScalableEnemy(PhysGrabObject physGrabObject) { if (MutatorSettings.SizeMatters.ScaleEnemies) { return physGrabObject.isEnemy; } return false; } private static bool IsScalableCart(PhysGrabObject physGrabObject) { if (MutatorSettings.SizeMatters.ScaleCarts) { return IsCart(physGrabObject); } return false; } private static bool IsScalableItem(PhysGrabObject physGrabObject) { if (MutatorSettings.SizeMatters.ScaleValuables && !IsCart(physGrabObject)) { if (!physGrabObject.isValuable && !Object.op_Implicit((Object)(object)((Component)physGrabObject).GetComponent())) { return Object.op_Implicit((Object)(object)((Component)physGrabObject).GetComponent()); } return true; } return false; } private static bool IsCart(PhysGrabObject physGrabObject) { if (!physGrabObject.isCart) { return Object.op_Implicit((Object)(object)((Component)physGrabObject).GetComponent()); } return true; } private static void AfterUnpatchAll() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer()) { scaleOptions = ScaleOptions.Default; } _late = false; } } internal class TheFloorIsLavaPatch { private const string ExtraDescriptionAnnouncementKey = "floor-is-lava:extra-description"; private const string ExtraDescription = "extraDescription"; private const string ImmunePlayers = "immunePlayers"; internal const string Damage = "damage"; internal const string UsePercentageDamage = "is-percentage-damage"; internal const string RevivalImmunityDuration = "revive-immunity-duration"; private static readonly ISet immunePlayers = new HashSet(); private static float reviveImmunityDuration = MutatorSettings.TheFloorIsLava.ReviveImmunityDuration; private static int damage = MutatorSettings.TheFloorIsLava.DamagePerTick; private static bool usePercentageDamage = MutatorSettings.TheFloorIsLava.UsePercentageDamage; private static bool initDone; private static void OnMetadataChanged(IDictionary metadata) { reviveImmunityDuration = metadata.Get("revive-immunity-duration"); damage = metadata.Get("damage"); usePercentageDamage = metadata.Get("is-percentage-damage"); RepoMutators.Logger.LogInfo($"[The Floor Is Lava] Damage: {damage} - State {MutatorManager.Instance.GameState}"); MutatorsGameState gameState = MutatorManager.Instance.GameState; if ((uint)(gameState - 29) <= 1u) { RepoMutators.Logger.LogInfo($"[The Floor Is Lava] Damage: {damage}"); HandleImmuneLogic(metadata.GetAsList("immunePlayers") ?? new List(), metadata.Get("extraDescription"), damage, usePercentageDamage); } } [HarmonyPrefix] [HarmonyPriority(601)] [HarmonyPatch(typeof(EnemyDirector))] [HarmonyPatch("GetEnemy")] private static void EnemyDirectorGetEnemyPrefix(ref List ___enemyList, int ___enemyListIndex) { if (SemiFunc.IsMasterClientOrSingleplayer() && MutatorSettings.TheFloorIsLava.DisableEnemies) { ___enemyList.Clear(); EnemySetup val = ScriptableObject.CreateInstance(); val.spawnObjects = new List(); ___enemyList.Add(val); while (___enemyList.Count < ___enemyListIndex + 1) { ___enemyList.Add(val); } } } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePostfix() { if (!SemiFunc.IsMultiplayer() || !SemiFunc.IsMasterClient()) { return; } IList list = SemiFunc.PlayerGetAll().ToList(); if (MutatorSettings.TheFloorIsLava.ImmunePlayerCount > 0 && list.Count > 1) { int num = Mathf.Min(MutatorSettings.TheFloorIsLava.ImmunePlayerCount, list.Count); for (int i = 0; i < num; i++) { PlayerAvatar item = list[Random.RandomRangeInt(0, list.Count)]; list.Remove(item); immunePlayers.Add(item); } } SendMetadata(); } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("Start")] private static void PlayerAvatarAwakePostfix(PlayerAvatar __instance) { if ((Object)(object)__instance == (Object)(object)PlayerAvatar.instance) { TheFloorIsLavaBehaviour theFloorIsLavaBehaviour = ComponentHolderProtocol.AddComponent((Object)(object)__instance); theFloorIsLavaBehaviour.damagePerTick = damage; theFloorIsLavaBehaviour.usePercentageDamage = usePercentageDamage; } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("ReviveRPC")] private static void PlayerAvatarReviveRPCPostfix(PlayerAvatar __instance) { if ((Object)(object)__instance == (Object)(object)PlayerAvatar.instance && reviveImmunityDuration > 0f) { TheFloorIsLavaBehaviour component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { component.immunityTimer = reviveImmunityDuration; } else { RepoMutators.Logger.LogWarning("No TheFloorIsLavaBehaviour found on local player!"); } } } private static void HandleImmuneLogic(IList immunePlayerList, string? extraDescription, int damagePerTick, bool usePercentageDamage) { immunePlayers.Clear(); LinqUtility.AddRange((ICollection)immunePlayers, (IEnumerable)immunePlayerList.Select((string ip) => SemiFunc.PlayerAvatarGetFromSteamID(ip)).ToList()); ApplyImmunity(damagePerTick, usePercentageDamage); HandleDescription(extraDescription); } private static void ApplyImmunity(int damagePerTick, bool usePercentageDamage) { TheFloorIsLavaBehaviour component = ((Component)PlayerAvatar.instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.Immune = immunePlayers.Contains(PlayerAvatar.instance); component.damagePerTick = damagePerTick; component.usePercentageDamage = usePercentageDamage; } else { RepoMutators.Logger.LogWarning("No TheFloorIsLavaBehaviour found on local player!"); } } private static void HandleDescription(string? extraDescription) { AbstractMutatorSettings theFloorIsLava = MutatorSettings.TheFloorIsLava; if (MutatorAnnouncingBag.Instance.TryGetAnnouncement(theFloorIsLava.NamespacedName, out MutatorAnnouncement announcement)) { if (extraDescription == null) { announcement.RemoveSegment("floor-is-lava:extra-description"); } else { announcement.AddOrUpdateSegment(new MutatorAnnouncementDescriptionSegment("floor-is-lava:extra-description", 10, "\n" + extraDescription)); } } else { RepoMutators.Logger.LogWarning("[The Floor Is Lava] Tried to update announcement, but it was not found!"); } } private static void SendMetadata() { IDictionary dictionary = new Dictionary(); if (immunePlayers.Count > 0) { dictionary.Add("immunePlayers", immunePlayers.Select((PlayerAvatar player) => player.steamID).ToList()); RepoMutators.Logger.LogInfo("Immune players: " + string.Join(", ", immunePlayers.Select((PlayerAvatar p) => p.playerName + " (" + p.steamID + ")"))); string value = JoinWithAnd(immunePlayers.Select((PlayerAvatar p) => p.playerName).ToList()) + " " + ((immunePlayers.Count == 1) ? "is" : "are") + " immune to lava damage!"; dictionary.Add("extraDescription", value); MutatorsNetworkManager.Instance.SendMetadata(MutatorSettings.TheFloorIsLava.NamespacedName, dictionary.WithMutator(MutatorSettings.TheFloorIsLava.NamespacedName)); } } private static void AfterUnpatchAll() { immunePlayers.Clear(); initDone = false; damage = MutatorSettings.TheFloorIsLava.DamagePerTick; usePercentageDamage = MutatorSettings.TheFloorIsLava.UsePercentageDamage; reviveImmunityDuration = MutatorSettings.TheFloorIsLava.ReviveImmunityDuration; } private static string JoinWithAnd(IList items) { if (items == null || items.Count == 0) { return ""; } if (items.Count == 1) { return items[0]; } if (items.Count == 2) { return items[0] + " and " + items[1]; } return string.Join(", ", items.Take(items.Count - 1)) + " and " + items.Last(); } } internal class ThereCanOnlyBeOnePatch { private const string Ducky = "Apex Predator"; private const string EnemyGroupPrefix = "Enemy Group - "; [HarmonyPostfix] [HarmonyPriority(100)] [HarmonyPatch(typeof(EnemyDirector))] [HarmonyPatch("AmountSetup")] private static void EnemyDirectorAmountSetupPostfix(EnemyDirector __instance) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } IList excludedEnemies = MutatorSettings.ThereCanOnlyBeOne.ExcludedEnemies; bool groupsAllowed = RunManager.instance.levelsCompleted >= MutatorSettings.ThereCanOnlyBeOne.GroupSpawnsThreshold; IEnumerable enumerable = from setup in __instance.enemiesDifficulty1.Concat(__instance.enemiesDifficulty2).Concat(__instance.enemiesDifficulty3) where groupsAllowed || !((Object)setup).name.StartsWith("Enemy Group - ") select setup; if (!excludedEnemies.Contains("Apex Predator") && MutatorManager.Instance.HasCurrentMutator(MutatorSettings.DuckThis.NamespacedName) && EnemiesContainDucky(enumerable)) { RepoMutators.Logger.LogDebug("[There Can Only Be One] Applying special logic for Duck This"); List list = enumerable.Where((EnemySetup setup) => setup.spawnObjects.All((PrefabRef so) => ((PrefabRef)(object)so).Prefab.GetComponent()?.enemyName == "Apex Predator")).ToList(); ApplyChosenEnemy(__instance, list[Random.RandomRangeInt(0, list.Count)]); return; } IList list2 = enumerable.Where((EnemySetup setup) => setup.spawnObjects.All((PrefabRef so) => !excludedEnemies.Any((string excluded) => excluded.Equals(((PrefabRef)(object)so).Prefab.GetComponent()?.enemyName, StringComparison.OrdinalIgnoreCase)))).ToList(); if (list2.Count == 0) { RepoMutators.Logger.LogWarning("[There Can Only Be One] Based on your config, there were no enemies that could be spawned for the There Can Only Be One Mutator!"); return; } EnemySetup enemySetup = list2[Random.RandomRangeInt(0, list2.Count)]; ApplyChosenEnemy(__instance, enemySetup); } private static void ApplyChosenEnemy(EnemyDirector enemyDirector, EnemySetup enemySetup) { enemyDirector.enemyList.Clear(); enemyDirector.enemyList.Add(enemySetup); for (int i = 0; i < enemyDirector.totalAmount; i++) { enemyDirector.enemyList.Add(enemySetup); } } private static bool EnemiesContainDucky(IEnumerable enemies) { return enemies.Any((EnemySetup setup) => setup.spawnObjects.All((PrefabRef so) => ((PrefabRef)(object)so).Prefab.GetComponent()?.enemyName == "Apex Predator")); } } internal class UltraViolencePatch { private static bool _keepLightsOn = MutatorSettings.UltraViolence.KeepOnLight; internal const string KeepLightsOn = "keep-lights-on"; private static void OnMetadataChanged(IDictionary metadata) { _keepLightsOn = metadata.Get("keep-lights-on"); } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePostfix() { if (SemiFunc.IsMasterClientOrSingleplayer()) { MutatorsNetworkManager.Instance.SendMetadata(MutatorSettings.UltraViolence.NamespacedName, new Dictionary { { "keep-lights-on", MutatorSettings.UltraViolence.KeepOnLight } }); } } [HarmonyPostfix] [HarmonyPriority(300)] [HarmonyPatch(typeof(EnemyDirector))] [HarmonyPatch("Start")] private static void EnemyDirectorAmountSetupPostfix(EnemyDirector __instance) { if (SemiFunc.IsMasterClientOrSingleplayer()) { __instance.DisableEnemies(MutatorSettings.UltraViolence); } } [HarmonyPostfix] [HarmonyPatch(typeof(ExtractionPoint))] [HarmonyPatch("ActivateTheFirstExtractionPointAutomaticallyWhenAPlayerLeaveTruck")] private static void ExtractionPointActivateTheFirstExtractionPointAutomaticallyWhenAPlayerLeaveTruckPostfix() { RoundDirector instance = RoundDirector.instance; int extractionPoints = instance.extractionPoints; instance.extractionPointsCompleted = extractionPoints; instance.ExtractionCompletedAllCheck(); instance.extractionPointsCompleted = 0; } [HarmonyPrefix] [HarmonyPatch(typeof(LightManager))] [HarmonyPatch("Update")] private static void LightManagerUpdatePrefix(out bool __state) { __state = ShouldHideFakeFinalStateFromLightManager(); if (__state) { RoundDirector.instance.allExtractionPointsCompleted = false; } } [HarmonyPostfix] [HarmonyPatch(typeof(LightManager))] [HarmonyPatch("Update")] private static void LightManagerUpdatePostfix(bool __state) { if (__state) { RoundDirector.instance.allExtractionPointsCompleted = true; } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerAvatar))] [HarmonyPatch("FinalHeal")] private static bool PlayerAvatarFinalHealPrefix() { RoundDirector instance = RoundDirector.instance; return instance.extractionPointsCompleted >= instance.extractionPoints; } [HarmonyPrefix] [HarmonyPatch(typeof(TruckHealer))] [HarmonyPatch("StateUpdate")] private static bool TruckHealerStateUpdatePrefixPrefix() { RoundDirector instance = RoundDirector.instance; return instance.extractionPointsCompleted >= instance.extractionPoints; } private static bool ShouldHideFakeFinalStateFromLightManager() { if (_keepLightsOn) { return ShouldHideFakeFinalState(); } return false; } internal static bool ShouldHideFakeFinalState() { //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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Invalid comparison between Unknown and I4 RoundDirector instance = RoundDirector.instance; if (!Object.op_Implicit((Object)(object)instance) || !instance.allExtractionPointsCompleted) { return false; } int extractionPoints = instance.extractionPoints; int extractionPointsCompleted = instance.extractionPointsCompleted; if (!Object.op_Implicit((Object)(object)instance.extractionPointCurrent)) { return extractionPointsCompleted < extractionPoints; } bool flag = extractionPointsCompleted >= extractionPoints - 1; State currentState = instance.extractionPointCurrent.currentState; if (flag) { if ((int)currentState != 6) { return (int)currentState != 7; } return false; } return true; } private static void BeforeUnpatchAll() { _keepLightsOn = MutatorSettings.UltraViolence.KeepOnLight; } } internal class VoiceoverPatch { private static IDictionary originalVoiceChats = new Dictionary(); private static IDictionary voiceOwnership = new Dictionary(); private static void OnMetadataChanged(IDictionary metadata) { IDictionary dictionary = metadata.Get>("originalVoices"); IDictionary dictionary2 = metadata.Get>("voiceOwnership"); if (originalVoiceChats.Count != 0 || dictionary == null || dictionary.Count <= 0 || dictionary2.Count <= 0) { return; } originalVoiceChats = dictionary; voiceOwnership = dictionary2; IDictionary dictionary3 = metadata.Get>("voices"); foreach (KeyValuePair item in dictionary3) { ChangeVoices(item.Key, item.Value); } } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDone() { if (SemiFunc.IsMasterClient()) { IList playerAvatars = SemiFunc.PlayerGetAll(); MutatorsNetworkManager.Instance.Run(WaitForVoiceChats(playerAvatars)); } } [HarmonyPrefix] [HarmonyPatch(typeof(NetworkManager))] [HarmonyPatch("OnPlayerLeftRoom")] private static void NetworkManagerOnPlayerLeftRoomPrefix(Player otherPlayer) { string leavingPlayerId = SemiFunc.PlayerGetFromName(otherPlayer.NickName)?.steamID; if (leavingPlayerId != null && originalVoiceChats.ContainsKey(leavingPlayerId)) { string text = voiceOwnership[leavingPlayerId]; string key = voiceOwnership.First>((KeyValuePair kvp) => kvp.Value == leavingPlayerId).Key; ChangeVoices(leavingPlayerId, originalVoiceChats[leavingPlayerId]); ChangeVoices(key, originalVoiceChats[text]); voiceOwnership[key] = text; originalVoiceChats.Remove(leavingPlayerId); voiceOwnership.Remove(leavingPlayerId); } } private static IEnumerator WaitForVoiceChats(IList playerAvatars) { while (playerAvatars.Any((PlayerAvatar avatar) => !avatar.voiceChatFetched)) { yield return (object)new WaitForSeconds(0.1f); } originalVoiceChats = playerAvatars.ToDictionary((PlayerAvatar a) => a.steamID, (PlayerAvatar a) => a.voiceChat.photonView.ViewID); voiceOwnership = DerangeVoices(originalVoiceChats, out Dictionary newAssignments); IDictionary metadata = new Dictionary { { "voices", newAssignments }, { "voiceOwnership", voiceOwnership }, { "originalVoices", originalVoiceChats } }; MutatorsNetworkManager.Instance.SendMetadata(MutatorSettings.Voiceover.NamespacedName, metadata); voiceOwnership.ForEach>(delegate(KeyValuePair kvp) { RepoMutators.Logger.LogDebug("Gave voice of " + SemiFunc.PlayerAvatarGetFromSteamID(kvp.Value)?.playerName + " to " + SemiFunc.PlayerAvatarGetFromSteamID(kvp.Key)?.playerName); }); foreach (KeyValuePair item in newAssignments) { ChangeVoices(item.Key, item.Value); } } public static Dictionary DerangeVoices(IDictionary originalMap, out Dictionary newAssignments) { List list = new List(originalMap.Keys); List list2 = new List(originalMap.Values); int count = list.Count; List list3 = new List(list2); for (int i = 0; i < count - 1; i++) { int num = Random.Range(i + 1, count); List list4 = list3; int index = i; int index2 = num; int value = list3[num]; int value2 = list3[i]; list4[index] = value; list3[index2] = value2; } if (list3[count - 1] == list2[count - 1]) { int num2 = Random.Range(0, count - 1); List list4 = list3; int index2 = count - 1; int index = num2; int value2 = list3[num2]; int value = list3[count - 1]; list4[index2] = value2; list3[index] = value; } newAssignments = new Dictionary(); Dictionary dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); for (int j = 0; j < count; j++) { dictionary2[list2[j]] = list[j]; } for (int k = 0; k < count; k++) { string key = list[k]; int num3 = list3[k]; newAssignments[key] = num3; string value3 = dictionary2[num3]; dictionary[key] = value3; } return dictionary; } private static void ChangeVoices(string steamId, int photonViewID) { PlayerAvatar val = SemiFunc.PlayerAvatarGetFromSteamID(steamId); val.voiceChat = ((Component)PhotonView.Find(photonViewID)).GetComponent(); val.voiceChat.playerAvatar = val; if (val.voiceChat.TTSinstantiated) { val.voiceChat.ttsVoice.playerAvatar = val; } if (!SemiFunc.MenuLevel()) { val.voiceChat.ToggleMixer(false, false); } } private static IEnumerator Debug() { PlayerVoiceChat playerVoiceChat = PlayerAvatar.instance.voiceChat; while (true) { RepoMutators.Logger.LogInfo($"ToggleMute: {playerVoiceChat.toggleMute} - Director: {DataDirector.instance.toggleMute}"); RepoMutators.Logger.LogInfo($"Lobby: {(Object)(object)playerVoiceChat.audioSource.outputAudioMixerGroup == (Object)(object)playerVoiceChat.mixerMicrophoneSpectate} - Game: {(Object)(object)playerVoiceChat.audioSource.outputAudioMixerGroup == (Object)(object)playerVoiceChat.mixerMicrophoneSound}"); RepoMutators.Logger.LogInfo($"Active and Enabled: {((Behaviour)playerVoiceChat).isActiveAndEnabled}"); yield return (object)new WaitForSeconds(1f); } } private static void BeforeUnpatchAll() { originalVoiceChats.Clear(); voiceOwnership.Clear(); } } internal class VolatileCargoPatch { private static ExplosionPreset explosionPreset; [HarmonyPostfix] [HarmonyPatch(typeof(ValuableObject))] [HarmonyPatch("DollarValueSetLogic")] private static void ValuableObjectDollarValueSetLogicPostfix(ValuableObject __instance) { if (!((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { AddExplosion(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(ValuableObject))] [HarmonyPatch("DollarValueSetRPC")] private static void ValuableObjectDollarValueSetRPCPostfix(ValuableObject __instance, float value) { if (!((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { AddExplosion(__instance); } } private static void Explode(ValuableObject valuableObject, ParticleScriptExplosion particleScriptExplosion) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) float num = Math.Max(valuableObject.dollarValueCurrent, valuableObject.dollarValueOriginal); int num2 = (int)Math.Ceiling(Math.Max(25f, num / 250f)); float num3 = Math.Clamp(num / 12000f, 0.5f, 3f); particleScriptExplosion.Spawn(((Component)valuableObject).transform.position, num3, num2, num2, 1f, false, false, 1f); } private static void AddExplosion(ValuableObject __instance) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown if ((Object)(object)explosionPreset == (Object)null) { explosionPreset = Object.Instantiate(AssetStore.Preset); } ParticleScriptExplosion particleScriptExplosion = ComponentHolderProtocol.GetOrAddComponent((Object)(object)__instance); if ((Object)(object)particleScriptExplosion.explosionPreset == (Object)null) { particleScriptExplosion.explosionPreset = explosionPreset; } PhysGrabObjectImpactDetector component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { component.onDestroy.AddListener((UnityAction)delegate { Explode(__instance, particleScriptExplosion); }); ComponentHolderProtocol.AddComponent((Object)(object)__instance); } else { RepoMutators.Logger.LogWarning("[Volatile Cargo] unable to find impactDetector on " + ((Object)((Component)__instance).transform).name); } } } } namespace Mutators.Mutators.MultiMutators { internal class JsonMultiMutator { public string Name { get; set; } public string? Description { get; set; } public int Weight { get; set; } public int MinimumLevel { get; set; } public int MaximumLevel { get; set; } = 1000; public IDictionary> Mutators { get; set; } = new Dictionary>(); internal JsonMultiMutator() { } } internal static class MultiMutatorLoader { public static IList LoadAll() { string path = Path.Combine(RepoMutators.ConfigPath, "MultiMutators"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string[] files = Directory.GetFiles(path); return (from multiMutator in files.Where((string file) => Path.GetExtension(file).Equals(".json", StringComparison.OrdinalIgnoreCase)).Select(File.ReadAllText).Select((Func)JsonConvert.DeserializeObject) .Select(JsonToMultiMutator) where multiMutator != null select multiMutator).ToList(); } private static IMultiMutator? JsonToMultiMutator(JsonMultiMutator? jsonMultiMutator) { if (jsonMultiMutator == null) { return null; } IDictionary> dictionary = new Dictionary>(); foreach (KeyValuePair> mutator in jsonMultiMutator.Mutators) { if (MutatorManager.Instance.RegisteredMutators.TryGetValue(mutator.Key, out IMutator value)) { if (value is IMultiMutator) { RepoMutators.Logger.LogError("MultiMutator " + jsonMultiMutator.Name + " contains a MultiMutator with name " + mutator.Key + "!"); RepoMutators.Logger.LogError("MultiMutators with MultiMutators are not supported!"); LogAbortCreation(jsonMultiMutator); return null; } dictionary.Add(value, mutator.Value); continue; } RepoMutators.Logger.LogError("Unable to find Mutator with name " + mutator.Key + "!"); LogAbortCreation(jsonMultiMutator); return null; } if (!ValidateAndIsValid(jsonMultiMutator)) { LogAbortCreation(jsonMultiMutator); return null; } return new MultiMutator(new MultiMutatorSettings("Xepos.REPO-Mutators", jsonMultiMutator.Name, string.IsNullOrWhiteSpace(jsonMultiMutator.Description) ? string.Empty : jsonMultiMutator.Description, Math.Clamp(jsonMultiMutator.Weight, 0, int.MaxValue), Math.Clamp(jsonMultiMutator.MinimumLevel, 0, int.MaxValue), Math.Clamp(jsonMultiMutator.MaximumLevel, 0, int.MaxValue)), dictionary, null, null, MutatorSource.User); } private static bool ValidateAndIsValid(JsonMultiMutator jsonMultiMutator) { List list = new List(); if (string.IsNullOrWhiteSpace(jsonMultiMutator.Name)) { list.Add("Name"); } if (jsonMultiMutator.Mutators.Count <= 0) { list.Add("Mutators"); } if (jsonMultiMutator.Weight == 0) { RepoMutators.Logger.LogInfo("MultiMutator " + jsonMultiMutator.Name + " configured with weight: 0"); } if (list.Count <= 0) { return true; } RepoMutators.Logger.LogError("Invalid MultiMutator properties: " + string.Join(", ", list)); return false; } private static void LogAbortCreation(JsonMultiMutator jsonMultiMutator) { RepoMutators.Logger.LogError("Aborting creation of MultiMutator with name " + (jsonMultiMutator.Name ?? "") + "!"); } } } namespace Mutators.Mutators.Behaviours { internal class BodyguardPlayerHealthBehaviour : MonoBehaviour { private PlayerAvatar _playerAvatar; private PlayerHealth _playerHealth; internal int originalHealth = 100; internal int originalMaxHealth = 100; private bool _initDone; internal string? BodyguardId { get; set; } private void Awake() { _playerAvatar = PlayerAvatar.instance; _playerHealth = _playerAvatar.playerHealth; ((MonoBehaviour)this).StartCoroutine(GetAndSetHealthLate()); } private IEnumerator GetAndSetHealthLate() { while (!_playerHealth.healthSet) { yield return (object)new WaitForSeconds(0.1f); } originalHealth = _playerHealth.health; originalMaxHealth = _playerHealth.maxHealth; SendHealth(); while (BodyguardId == null) { yield return (object)new WaitForSeconds(0.1f); } UpdateHealth(); } internal void UpdateHealth() { if (BodyguardId == _playerAvatar.steamID) { if (!_initDone) { float num = CalculateBodyguardHealthMultiplier(_playerHealth.maxHealth); _playerHealth.health = (int)((float)_playerHealth.health * num); _playerHealth.maxHealth = (int)((float)_playerHealth.maxHealth * num); } else { float num2 = CalculateBodyguardHealthMultiplier(originalMaxHealth); _playerHealth.health = (int)((float)originalMaxHealth * num2); _playerHealth.maxHealth = (int)((float)originalMaxHealth * num2); } } else { _playerHealth.health = 60; _playerHealth.maxHealth = 60; } SetHealth(_playerHealth.health, _playerHealth.maxHealth); _initDone = true; } internal void RestoreOriginalHealth() { SetHealth(originalHealth, originalMaxHealth); } private void SetHealth(int health, int maxHealth, bool setInShop = false) { StatsManager.instance.SetPlayerHealth(_playerAvatar.steamID, health, setInShop); if (SemiFunc.IsMultiplayer()) { _playerHealth.photonView.RPC("UpdateHealthRPC", (RpcTarget)1, new object[4] { health, maxHealth, true, false }); } } internal void SendHealth() { Dictionary meta = new Dictionary { { "originalHealth", originalHealth } }; MutatorsNetworkManager.Instance.SendMetaToHost(MutatorSettings.ProtectTheWeak.NamespacedName, meta); } private static float CalculateBodyguardHealthMultiplier(int health) { int num = Math.Max(health, 100); float num2 = 125f / ((float)(num - 100) + 125f); return 1.1f + 0.9f * num2; } } internal class DuckThisBehaviour : MonoBehaviour { public float NoticeCooldown { get; internal set; } private void Update() { if (NoticeCooldown > 0f && SemiFunc.IsMasterClientOrSingleplayer()) { NoticeCooldown -= Time.deltaTime; } } internal bool CanNotice() { return NoticeCooldown <= 0f; } } internal class LaserFiringBehaviour : MonoBehaviour, IPunInstantiateMagicCallback { private PhotonView photonView; private PlayerAvatar playerAvatar; private SemiLaser semiLaser; private Transform visionTransform; private float laserTimer; internal float laserReviveLockout = 5f; internal float laserReviveLockoutTimer = 5f; internal float laserCooldown = 100f; internal float laserCooldownTimer = 100f; internal bool canFire = true; internal bool manualActionEnabled = true; private void Awake() { photonView = ((Component)this).GetComponent(); } private void Start() { playerAvatar = ((Component)((Component)this).transform.parent).GetComponent(); visionTransform = ((Component)playerAvatar).transform.Find("Vision Target"); semiLaser = ((Component)((Component)this).transform.Find("SemiLaser(Clone)")).GetComponent(); ((Component)((Component)this).transform).GetComponentInChildren(true).ignoredPlayers.Add(playerAvatar); } private void Update() { //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0168: 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_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)playerAvatar == (Object)(object)PlayerAvatar.instance) { if (laserCooldownTimer < laserCooldown) { laserCooldownTimer += Time.deltaTime; } if (laserReviveLockoutTimer > 0f) { laserReviveLockoutTimer -= Time.deltaTime; } if (manualActionEnabled && laserCooldownTimer >= laserCooldown && !ChatManager.instance.StateIsActive() && Input.GetKeyDown(RepoMutators.Settings.SpecialActionKey)) { FireLaser(2.5f); laserCooldownTimer = 0f; } SpecialActionAnnouncingBehaviour instance = SpecialActionAnnouncingBehaviour.Instance; if ((Object)(object)instance?.Text != (Object)null && (Object)(object)instance?.TextMax != (Object)null) { if (manualActionEnabled) { ((TMP_Text)instance.Text).text = $"{(int)laserCooldownTimer}"; ((TMP_Text)instance.TextMax).text = $"/{(int)laserCooldown}"; } else { ((SemiUI)instance).Hide(); } } } if (IsActive()) { laserTimer -= Time.deltaTime; bool flag = false; Vector3 val = visionTransform.position + visionTransform.forward * 15f; RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(visionTransform.position, visionTransform.forward, ref val2, 15f, LayerMask.op_Implicit(SemiFunc.LayerMaskGetVisionObstruct()))) { val = ((RaycastHit)(ref val2)).point; flag = true; } semiLaser.LaserActive(visionTransform.position, val, flag); } } [PunRPC] public void StaffLaserRPC(float _time) { laserTimer = _time; } public void FireLaser(float _time) { if (SemiFunc.IsMultiplayer()) { photonView.RPC("StaffLaserRPC", (RpcTarget)0, new object[1] { _time }); } else { StaffLaserRPC(_time); } } public void StopLaser(bool localOnly = false) { if (localOnly) { laserTimer = 0f; } else { FireLaser(0f); } } public bool IsActive() { return laserTimer > 0f; } public bool IsReviveLockout() { return laserReviveLockoutTimer > 0f; } public void ActivateReviveLockout() { laserReviveLockoutTimer = laserReviveLockout; } public void OnPhotonInstantiate(PhotonMessageInfo info) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) object[] instantiationData = info.photonView.InstantiationData; if (instantiationData.Length < 4) { RepoMutators.Logger.LogWarning("Received invalid data for LaserFiringBehaviour"); return; } if (instantiationData[0] is string text) { PlayerAvatar val = SemiFunc.PlayerAvatarGetFromSteamID(text); ((Component)this).transform.SetParent(((Component)val).transform, false); } if (instantiationData[1] is int num) { laserCooldown = num; laserCooldownTimer = num; } if (instantiationData[2] is int damage) { ((MonoBehaviour)this).StartCoroutine(ApplyDamageDelayed(damage)); } if (instantiationData[3] is bool flag) { manualActionEnabled = flag; } } private IEnumerator ApplyDamageDelayed(int damage) { while ((Object)(object)semiLaser == (Object)null) { yield return (object)new WaitForSeconds(0.1f); } ((HurtCollider)((Component)semiLaser).GetComponentInChildren(true)).enemyDamage = damage; } } internal class LessIsMoreBehaviour : MonoBehaviour { private ValuableObject valuableObject; private PhysGrabObjectImpactDetector physGrabObjectImpactDetector; private float realValue; private void Awake() { valuableObject = ((Component)this).GetComponent(); physGrabObjectImpactDetector = ((Component)this).GetComponent(); realValue = valuableObject.dollarValueCurrent; } private void Update() { if ((double)realValue < (double)valuableObject.dollarValueOriginal * 0.15) { physGrabObjectImpactDetector.DestroyObject(true); } } internal void SubtractValue(float value) { realValue -= value; } } internal class TemporaryLevelItemBehaviour : MonoBehaviour { internal PhysGrabObject _physGrabObject; internal string levelName; private void Awake() { _physGrabObject = ((Component)this).GetComponent(); ItemAttributes component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null) { component.itemName += " (Temporary)"; } } } internal class TheFloorIsLavaBehaviour : MonoBehaviour { private PlayerAvatar playerAvatar; private Transform physObjectStander; private LayerMask layerMask = LayerMask.op_Implicit(~LayerMask.GetMask(new string[2] { "Player", "CollisionCheck" })); internal float immunityTimer; private float groundedTimer; private float damageCooldownTimer; private readonly float damageCooldown = 1f; private readonly float damageInterval = 1f; private readonly float raycastDistance = 0.5f; internal int damagePerTick = MutatorSettings.TheFloorIsLava.DamagePerTick; internal bool usePercentageDamage = MutatorSettings.TheFloorIsLava.UsePercentageDamage; private int playerOnlyCollisionLayer; internal bool Immune { get; set; } private void Start() { playerAvatar = ((Component)this).GetComponent(); physObjectStander = ((Component)playerAvatar).transform.Find("Phys Object Stander"); playerOnlyCollisionLayer = LayerMask.NameToLayer("PlayerOnlyCollision"); } private void Update() { //IL_0087: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Invalid comparison between Unknown and I4 if (!LevelGenerator.Instance.Generated || playerAvatar.RoomVolumeCheck.inTruck || playerAvatar.RoomVolumeCheck.inExtractionPoint) { return; } if (immunityTimer > 0f) { immunityTimer -= Time.deltaTime; } else { if (Immune) { return; } damageCooldownTimer += Time.deltaTime; groundedTimer += Time.deltaTime; bool flag = false; RaycastHit val = default(RaycastHit); if (Physics.Raycast(physObjectStander.position, Vector3.down, ref val, raycastDistance, LayerMask.op_Implicit(layerMask))) { Collider collider = ((RaycastHit)(ref val)).collider; if (((Component)collider).CompareTag("Floor") || ((Component)collider).CompareTag("Wall")) { flag = true; } else if (((Component)collider).CompareTag("Untagged") && ((int)playerAvatar.MaterialTrigger.LastMaterialType == 5 || ((Component)((RaycastHit)(ref val)).collider).gameObject.layer == playerOnlyCollisionLayer)) { flag = true; } } if (flag && groundedTimer >= damageInterval && damageCooldownTimer >= damageCooldown) { int num = damagePerTick; if (usePercentageDamage) { num = (int)MathF.Ceiling((float)playerAvatar.playerHealth.maxHealth * ((float)num / 100f)); } playerAvatar.playerHealth.Hurt(num, false, -1, false); groundedTimer = 0f; damageCooldownTimer = 0f; } } } } } namespace Mutators.Mutators.Behaviours.UI { internal class MutatorAnnouncementControllerBehaviour : MonoBehaviour { private const float CycleTime = 5f; private float _cycleTimer = 5f; private MutatorAnnouncingBag _announcingBag; private void Awake() { _announcingBag = MutatorAnnouncingBag.Instance; } private void Start() { ApplyAnnouncement(_announcingBag.Current); } private void OnEnable() { _announcingBag.CurrentChanged += HandleCurrentChanged; } private void OnDisable() { _announcingBag.CurrentChanged -= HandleCurrentChanged; } private void HandleCurrentChanged(MutatorAnnouncement announcement) { _cycleTimer = 5f; ApplyAnnouncement(announcement); } private void Update() { if (_announcingBag.Count > 1) { _cycleTimer -= Time.deltaTime; if (!(_cycleTimer > 0f)) { _announcingBag.MoveNext(); } } } private static void ApplyAnnouncement(MutatorAnnouncement announcement) { MutatorAnnouncingBehaviour.instance?.SetText(announcement.GetName()); MutatorDescriptionAnnouncingBehaviour.Instance?.SetText(announcement.GetDescription()); } } internal class MutatorAnnouncingBehaviour : SemiUI { private TextMeshProUGUI Text; internal static MutatorAnnouncingBehaviour instance; private bool _isVisible = true; private float _showTimer = (IsToggleWithDescription() ? RepoMutators.Settings.MutatorDescriptionInitialDisplayTime : 0f); public override void Start() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) base.animateTheEntireObject = true; base.hidePosition = new Vector2(300f, 0f); ((SemiUI)this).Start(); Text = ((Component)this).GetComponent(); instance = this; ((TMP_Text)Text).text = string.Empty; } public override void Update() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) ((SemiUI)this).Update(); if (RepoMutators.Settings.MutatorDisplayToggleType == ModSettings.MutatorNameToggleType.WithDescription) { ((SemiUI)this).Hide(); if (_showTimer > 0f) { if (!RepoMutators.Settings.MutatorDescriptionPinned) { _showTimer -= Time.deltaTime; } if ((Object)(object)MenuPageEsc.instance?.menuPage == (Object)null) { ((SemiUI)this).Show(); } } } else { if (!ChatManager.instance.StateIsActive() && RepoMutators.Settings.MutatorDisplayToggleType == ModSettings.MutatorNameToggleType.Keybind && Input.GetKeyDown(RepoMutators.Settings.MutatorDisplayToggleKey)) { _isVisible = !_isVisible; } if (!_isVisible) { ((SemiUI)this).Hide(); } } } private static bool IsToggleWithDescription() { return RepoMutators.Settings.MutatorDisplayToggleType == ModSettings.MutatorNameToggleType.WithDescription; } internal void SetText(string text) { ((TMP_Text)Text).text = text; } } internal class MutatorDescriptionAnnouncingBehaviour : SemiUI { private float _showTimer = RepoMutators.Settings.MutatorDescriptionInitialDisplayTime; public TextMeshProUGUI Text { get; private set; } public static MutatorDescriptionAnnouncingBehaviour Instance { get; private set; } public override void Start() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) base.animateTheEntireObject = true; base.hidePosition = new Vector2(400f, 0f); ((SemiUI)this).Start(); Text = ((Component)this).GetComponent(); Instance = this; ((TMP_Text)Text).text = string.Empty; } public override void Update() { ((SemiUI)this).Update(); ((SemiUI)this).Hide(); if (_showTimer > 0f) { if (!RepoMutators.Settings.MutatorDescriptionPinned) { _showTimer -= Time.deltaTime; } if ((Object)(object)MenuPageEsc.instance?.menuPage == (Object)null) { ((SemiUI)this).Show(); } } } public void ShowDescription(float showTimerOverride = 0f) { ((SemiUI)this).SemiUISpringShakeY(20f, 10f, 0.3f); ((SemiUI)this).SemiUISpringScale(0.4f, 5f, 0.2f); float mutatorDescriptionInitialDisplayTime = RepoMutators.Settings.MutatorDescriptionInitialDisplayTime; _showTimer = ((showTimerOverride > mutatorDescriptionInitialDisplayTime) ? showTimerOverride : mutatorDescriptionInitialDisplayTime); } private string GetDescription(string description) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (description.Contains("{specialActionKey}")) { return description.Replace("{specialActionKey}", ((object)RepoMutators.Settings.SpecialActionKey/*cast due to .constrained prefix*/).ToString()); } return description; } internal void SetText(string text) { ((TMP_Text)Text).text = GetDescription(text); } } public class SpecialActionAnnouncingBehaviour : SemiUI { public TextMeshProUGUI Text { get; private set; } public TextMeshProUGUI TextMax { get; private set; } public static SpecialActionAnnouncingBehaviour Instance { get; private set; } private void Awake() { Instance = this; Text = ((Component)this).GetComponent(); TextMax = ((Component)((Component)this).transform.Find("SpecialActionMax")).GetComponent(); } public override void Start() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) base.animateTheEntireObject = true; base.hidePosition = new Vector2(-140f, 0f); base.doNotDisable = new List(); ((SemiUI)this).Start(); ((TMP_Text)Text).text = string.Empty; } } public class TargetPlayerAnnouncingBehaviour : SemiUI { public TextMeshProUGUI Text { get; private set; } public static TargetPlayerAnnouncingBehaviour Instance { get; private set; } private void Awake() { Instance = this; ((SemiUI)Instance).doNotDisable = new List(); Text = ((Component)this).GetComponent(); } public override void Start() { ((SemiUI)this).Start(); } public override void Update() { ((SemiUI)this).Update(); if (((TMP_Text)Text).text == string.Empty) { ((SemiUI)this).Hide(); } } } } namespace Mutators.Mutators.Behaviours.Markers { internal class SealedAwayMarkerBehaviour : MonoBehaviour { } internal class VolatileCargoMarkerBehaviour : MonoBehaviour { } } namespace Mutators.Mutators.Behaviours.HurtColliders { internal class PlayerIgnoringHurtCollider : HurtCollider { internal readonly ISet ignoredPlayers = new HashSet(); } } namespace Mutators.Managers { internal class LevelManager { private static readonly IDictionary RemovedLevels = new Dictionary(StringComparer.OrdinalIgnoreCase); public static LevelManager Instance { get; private set; } = new LevelManager(); public void RemoveLevels(ICollection levelsToRemove) { if (levelsToRemove.Count == 0) { return; } List levels = RunManager.instance.levels; ISet removeSet = new HashSet(levelsToRemove, StringComparer.OrdinalIgnoreCase); List list = levels.FindAll((Level level) => removeSet.Contains(((Object)level).name)); foreach (Level item in list) { RemovedLevels[((Object)item).name] = item; RepoMutators.Logger.LogDebug("Removed level " + ((Object)item).name); } levels.RemoveAll((Level level) => removeSet.Contains(((Object)level).name)); } public void RestoreLevels() { if (RemovedLevels.Count == 0) { return; } List levels = RunManager.instance.levels; ISet existingNames = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (Level item in levels) { existingNames.Add(((Object)item).name); } levels.AddRange(RemovedLevels.Values.Where((Level level) => existingNames.Add(((Object)level).name))); foreach (Level value in RemovedLevels.Values) { RepoMutators.Logger.LogInfo("Restoring level " + ((Object)value).name); } foreach (Level level in RunManager.instance.levels) { RepoMutators.Logger.LogInfo("Level " + ((Object)level).name + " is now active"); } RemovedLevels.Clear(); } } public class MutatorManager { private readonly IDictionary _mutators = new Dictionary(); private readonly IMutatorSelectionService _mutatorSelectionService; private MutatorsGameState _gameState; private bool _initialized; private ISemiFuncProvider SemiFunc { get; } public static MutatorManager Instance { get; private set; } = DI.Container.Resolve(); public GeneratedMultiMutatorSelectionRulesRegistry GeneratedMultiMutatorSelectionRulesRegistry { get; } public SingleMutatorSelectionRulesRegistry SingleMutatorSelectionRulesRegistry { get; } public IReadOnlyDictionary RegisteredMutators => new ReadOnlyDictionary(_mutators); public IMutator CurrentMutator { get; internal set; } public MutatorsGameState GameState { get { return _gameState; } internal set { if (_gameState != value) { _gameState = value; this.GameStateChanged(value); } } } public event Action GameStateChanged; internal MutatorManager(IMutatorSelectionService mutatorSelectionService, ISemiFuncProvider semiFunc, GeneratedMultiMutatorSelectionRulesRegistry generatedMultiMutatorSelectionRulesRegistry, SingleMutatorSelectionRulesRegistry singleMutatorSelectionRulesRegistry, NopMutator currentMutator) { _mutatorSelectionService = mutatorSelectionService; SemiFunc = semiFunc; GeneratedMultiMutatorSelectionRulesRegistry = generatedMultiMutatorSelectionRulesRegistry; SingleMutatorSelectionRulesRegistry = singleMutatorSelectionRulesRegistry; CurrentMutator = currentMutator; } internal void InitializeDefaultMutators() { if (_initialized) { RepoMutators.Logger.LogWarning("Tried to initialize default mutators, but these were already initialized!"); return; } List list = new List(21); list.Add(DI.Container.Resolve()); list.Add(new Mutator(MutatorSettings.OutWithABang, typeof(OutWithABangPatch), MutatorDifficulty.Normal, new List>(1) { () => Object.op_Implicit((Object)(object)AssetStore.Preset) })); list.Add(new Mutator(MutatorSettings.ApolloEleven, typeof(ApolloElevenPatch), MutatorDifficulty.Normal)); list.Add(new Mutator(MutatorSettings.UltraViolence, typeof(UltraViolencePatch), MutatorDifficulty.Hard)); list.Add(new Mutator(MutatorSettings.DuckThis, typeof(DuckThisPatch), MutatorDifficulty.Normal)); list.Add(new Mutator(MutatorSettings.OneShotOneKill, typeof(OneShotOneKillPatch), MutatorDifficulty.Hard)); list.Add(new Mutator(MutatorSettings.ProtectThePresident, typeof(ProtectThePresidentPatch), MutatorDifficulty.Normal, new List>(1) { SemiFunc.IsMultiplayer })); list.Add(new Mutator(MutatorSettings.RustyServos, typeof(RustyServosPatch), MutatorDifficulty.Normal)); list.Add(new Mutator(MutatorSettings.HandleWithCare, typeof(HandleWithCarePatch), MutatorDifficulty.Normal)); list.Add(new Mutator(MutatorSettings.HuntingSeason, typeof(HuntingSeasonPatch), MutatorDifficulty.Hard)); list.Add(new Mutator(MutatorSettings.ThereCanOnlyBeOne, typeof(ThereCanOnlyBeOnePatch), MutatorDifficulty.Normal)); list.Add(new Mutator(MutatorSettings.VolatileCargo, typeof(VolatileCargoPatch), MutatorDifficulty.Normal, new List>(1) { () => Object.op_Implicit((Object)(object)AssetStore.Preset) })); list.Add(new Mutator(MutatorSettings.SealedAway, typeof(SealedAwayPatch), MutatorDifficulty.Normal)); list.Add(new Mutator(MutatorSettings.ProtectTheWeak, typeof(ProtectTheWeakPatch), MutatorDifficulty.Normal, new List>(1) { SemiFunc.IsMultiplayer })); list.Add(new Mutator(MutatorSettings.FiringMyLaser, typeof(FiringMyLaserPatch), MutatorDifficulty.Normal, new List>(1) { () => AssetStore.IsLaserLoaded }, specialActionOverlay: true)); list.Add(new Mutator(MutatorSettings.Voiceover, typeof(VoiceoverPatch), MutatorDifficulty.Normal, new List>(1) { SemiFunc.IsMultiplayer })); list.Add(new Mutator(MutatorSettings.TheFloorIsLava, typeof(TheFloorIsLavaPatch), MutatorDifficulty.Hard)); list.Add(new Mutator(MutatorSettings.LessIsMore, typeof(LessIsMorePatch), MutatorDifficulty.Normal)); list.Add(new Mutator(MutatorSettings.Amalgam, typeof(AmalgamPatch), MutatorDifficulty.Normal)); list.Add(new Mutator(MutatorSettings.NullSignal, typeof(NullSignalPatch), MutatorDifficulty.Normal)); list.Add(new Mutator(MutatorSettings.SizeMatters, typeof(SizeMattersPatch), MutatorDifficulty.Normal)); IList source = list; source.ForEach(RegisterMutator); GameStateChanged += delegate(MutatorsGameState gameState) { if (gameState == MutatorsGameState.LevelReady) { LevelManager.Instance.RestoreLevels(); } }; _initialized = true; } internal void InitializeMultiMutators() { IList list = MultiMutatorLoader.LoadAll(); list.ForEach(RegisterMutator); RepoMutators.Logger.LogInfo(string.Format("Loaded {0} MultiMutator{1}!", list.Count, (list.Count == 1) ? "" : "s")); } public void RegisterMutator(IMutator mutator) { RepoMutators.Logger.LogDebug("Registering mutator " + mutator.NamespacedName); if (_mutators.TryAdd(mutator.NamespacedName, mutator)) { RepoMutators.Logger.LogInfo("Successfully registered mutator " + mutator.NamespacedName + "!"); } } public void UnregisterMutator(IMutator mutator) { if (_mutators.Remove(mutator.NamespacedName)) { if (mutator.Active) { mutator.Unpatch(); } RepoMutators.Logger.LogInfo("Successfully unregistered mutator " + mutator.NamespacedName); } } public void UnregisterMutator(string namespacedName) { if (_mutators.TryGetValue(namespacedName, out IMutator value)) { UnregisterMutator(value); } } public bool HasCurrentMutator(IMutator mutator) { return HasCurrentMutator(mutator.NamespacedName); } public bool HasCurrentMutator(string namespacedName) { if (CurrentMutator.NamespacedName == namespacedName) { return true; } if (!(CurrentMutator is IMultiMutator multiMutator)) { return false; } foreach (IMutator key in multiMutator.SubMutators.Keys) { if (key.NamespacedName == namespacedName) { return true; } } return false; } internal void SetActiveMutator(string namespacedName, bool applyPatchNow = true) { if (!_mutators.TryGetValue(namespacedName, out IMutator value)) { RepoMutators.Logger.LogWarning("Tried to activate unknown mutator: " + namespacedName + "."); RepoMutators.Logger.LogWarning("You might be out of sync if you are not the host!"); } else { SetActiveMutator(value, applyPatchNow); } } internal void SetActiveMutator(IMutator mutator, bool applyPatchNow = true) { CurrentMutator.Unpatch(); RegisteredMutators.Values.Where((IMutator registeredMutator) => registeredMutator.Active).ForEach(delegate(IMutator activeMutator) { activeMutator.Unpatch(); }); CurrentMutator = mutator; RepoMutators.Logger.LogDebug("Mutator " + mutator.NamespacedName + " set as active"); if (applyPatchNow) { CurrentMutator.Patch(); } MutatorAnnouncingBag.Instance.Prime(CurrentMutator); } internal IMutator GetWeightedMutator() { return _mutatorSelectionService.GetWeightedMutator(_mutators.Values); } } } namespace Mutators.Logging.Loggers { internal interface IMutatorsLogger { void LogFatal(object data); void LogError(object data); void LogWarning(object data); void LogMessage(object data); void LogInfo(object data); void LogDebug(object data); } internal sealed class MutatorsLogger(ManualLogSource logSource) : IMutatorsLogger { public void LogFatal(object data) { logSource.LogFatal(data); } public void LogError(object data) { logSource.LogError(data); } public void LogWarning(object data) { logSource.LogWarning(data); } public void LogMessage(object data) { logSource.LogMessage(data); } public void LogInfo(object data) { logSource.LogInfo(data); } public void LogDebug(object data) { logSource.LogDebug(data); } } internal sealed class NullMutatorsLogger : IMutatorsLogger { internal NullMutatorsLogger() { } public void LogFatal(object data) { } public void LogError(object data) { } public void LogWarning(object data) { } public void LogMessage(object data) { } public void LogInfo(object data) { } public void LogDebug(object data) { } } } namespace Mutators.Extensions { internal static class BepInExConfigFileExtensions { public static ConfigEntry BindPositive(this ConfigFile configFile, string section, string key, int defaultValue, string description) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown return configFile.Bind(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new PositiveIntValue(), Array.Empty())); } } internal static class CollectionExtensions { public static void ForEach(this IEnumerable source, Action action) { foreach (T item in source) { action(item); } } } public static class DictionaryExtensions { public static T? Get(this IDictionary dictionary, string key) { if (dictionary.TryGetValue(key, out object value)) { return (T)value; } return default(T); } public static T? Get(this IReadOnlyDictionary dictionary, string key) { if (dictionary.TryGetValue(key, out object value)) { return (T)value; } return default(T); } public static List GetAsList(this IDictionary metadata, string key) { return ((IReadOnlyDictionary)metadata).GetAsList(key); } public static List GetAsList(this IReadOnlyDictionary metadata, string key) { if (!metadata.TryGetValue(key, out object value)) { return new List(); } if (!(value is List result)) { if (!(value is IEnumerable source)) { if (value is T item) { return new List(1) { item }; } return new List(); } return source.Select((object o) => (o is T) ? ((T)o) : ((T)Convert.ChangeType(o, typeof(T)))).ToList(); } return result; } public static IDictionary DeepMergedWith(this IDictionary dict1, IDictionary dict2) { Dictionary dictionary = new Dictionary(dict1); foreach (KeyValuePair item in dict2) { object value; if (item.Value == null) { dictionary.Remove(item.Key); } else if (dictionary.TryGetValue(item.Key, out value) && value is IDictionary dict3 && item.Value is IDictionary dict4) { dictionary[item.Key] = dict3.DeepMergedWith(dict4); } else { dictionary[item.Key] = item.Value; } } return dictionary; } public static IDictionary WithMutator(this IDictionary dictionary, string mutatorNamespacedName) { if (dictionary.ContainsKey(mutatorNamespacedName)) { return dictionary; } return new Dictionary { { mutatorNamespacedName, dictionary } }; } public static IDictionary WithMutator(this IDictionary dictionary, IMutator mutator) { return dictionary.WithMutator(mutator.NamespacedName); } internal static void LogMetadata(this IDictionary metadata, int level = 0) { string text = new string(' ', level); foreach (KeyValuePair metadatum in metadata) { object value = metadatum.Value; if (!(value is string text2)) { if (!(value is IDictionary metadata2)) { if (value is IEnumerable enumerable) { RepoMutators.Logger.LogDebug(text + metadatum.Key + ": [" + GeneralExtensions.Join(enumerable, (Func)null, ", ") + "]"); } else { RepoMutators.Logger.LogDebug($"{text}{metadatum.Key}: {metadatum.Value}"); } } else { RepoMutators.Logger.LogDebug(text + metadatum.Key + ":"); metadata2.LogMetadata(level + 1); } } else { RepoMutators.Logger.LogDebug(text + metadatum.Key + ": " + text2); } } } } internal static class EnemyDirectorExtensions { public static void DisableEnemies(this EnemyDirector enemyDirector, EnemyDisablingMutatorSettings mutatorSettings, Predicate? condition = null) { Predicate predicate = delegate(EnemySetup setup) { Predicate? predicate2 = condition; return (predicate2 != null && predicate2(setup)) || setup.spawnObjects.Any((PrefabRef so) => mutatorSettings.ExcludedEnemies.Any((string excluded) => excluded.Equals(((PrefabRef)(object)so).Prefab.GetComponent()?.enemyName, StringComparison.OrdinalIgnoreCase))); }; IList list = (from setup in enemyDirector.enemiesDifficulty1.Concat(enemyDirector.enemiesDifficulty2).Concat(enemyDirector.enemiesDifficulty3) where predicate(setup) select setup).ToList(); foreach (EnemySetup item in list) { enemyDirector.enemiesDifficulty1.Remove(item); enemyDirector.enemiesDifficulty2.Remove(item); enemyDirector.enemiesDifficulty3.Remove(item); } } } internal static class LevelRemovingMutatorSettingsExtensions { private const string TRUCK_LEVEL_NAME = "Level - Lobby"; private static readonly ISet vanillaLevelNames = new HashSet { "Level - Arctic", "Level - Manor", "Level - Wizard", "Level - Museum" }; internal static void RemoveLevels(this ILevelRemovingMutatorSettings settings, bool lobbyMenu = false) { RunManager instance = RunManager.instance; if (!lobbyMenu && ((Object)instance.levelCurrent).name != "Level - Lobby") { return; } if (!settings.AllowCustomLevels) { LevelManager.Instance.RemoveLevels(vanillaLevelNames); } if (settings.ExcludedLevels.Count > 0) { ISet levelsToRemove = new HashSet(settings.ExcludedLevels.Select((string level) => (!level.StartsWith("level - ", StringComparison.OrdinalIgnoreCase)) ? ("level - " + level).ToLowerInvariant() : level.ToLowerInvariant())); LevelManager.Instance.RemoveLevels(levelsToRemove); } if (instance.levels.Count == 1) { instance.previousRunLevel = null; } else if (instance.levels.Count == 0) { instance.previousRunLevel = null; RepoMutators.Logger.LogError("Attempted to start a run with 0 available levels, please revisit your mod settings!"); RepoMutators.Logger.LogError("There must be at least one level available to choose from!"); } } } internal static class MultiMutatorExtensions { internal static (IList mutators, IDictionary meta) Format(this IMultiMutator multiMutator) { IEnumerable keys = multiMutator.SubMutators.Keys; IDictionary dictionary = keys.Select((IMutator mutator) => mutator.Settings.AsMetadata()).SelectMany((IDictionary dict) => dict ?? new Dictionary()).ToDictionary((KeyValuePair pair) => pair.Key, (KeyValuePair pair) => pair.Value); dictionary.Add("mutatorOverrides", CreateOverrides(multiMutator)); return (mutators: keys.Select((IMutator mutator) => mutator.NamespacedName).ToList(), meta: dictionary); } private static IDictionary CreateOverrides(IMultiMutator multiMutator) { IDictionary mutatorOverrides = new Dictionary { { "namespacedName", multiMutator.NamespacedName }, { "name", multiMutator.Name }, { "description", multiMutator.Description }, { "source", multiMutator.Source.ToString() } }; multiMutator.SubMutators.ForEach>>(delegate(KeyValuePair> mutator) { mutatorOverrides.Add(mutator.Key.NamespacedName, mutator.Value); }); return mutatorOverrides; } internal static bool TryCoerce(this object? value, Type targetType, out object? coerced) { coerced = null; Type underlyingType = Nullable.GetUnderlyingType(targetType); bool flag = underlyingType != null; Type type = underlyingType ?? targetType; if (value == null) { if (flag) { coerced = null; return true; } return false; } Type type2 = value.GetType(); if (type.IsAssignableFrom(type2)) { coerced = value; return true; } if (type.IsEnum) { try { if (value is string value2) { coerced = Enum.Parse(type, value2, ignoreCase: true); return true; } object value3 = Convert.ChangeType(value, Enum.GetUnderlyingType(type), CultureInfo.InvariantCulture); coerced = Enum.ToObject(type, value3); return true; } catch { return false; } } try { coerced = Convert.ChangeType(value, type, CultureInfo.InvariantCulture); return true; } catch { return false; } } } internal static class MutatorSelectionExtensions { internal static IList GetSelection(this ICollection mutators, Predicate predicate) { return mutators.Where((IMutator mutator) => mutator.IsEligibleForSelection() && predicate(mutator)).ToList(); } } internal static class PhotonHashtableExtensions { internal static Hashtable ToPhotonHashtable(this IDictionary dict) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown Hashtable val = new Hashtable(); foreach (KeyValuePair item in dict) { if (item.Value is IDictionary dict2) { val[(object)item.Key] = dict2.ToPhotonHashtable(); } else if (item.Value is IList list) { val[(object)item.Key] = list.ToPhotonArray(); } else { val[(object)item.Key] = item.Value; } } return val; } private static object[] ToPhotonArray(this IList list) { object[] array = new object[list.Count]; for (int i = 0; i < list.Count; i++) { if (list[i] is IDictionary dict) { array[i] = dict.ToPhotonHashtable(); } else { array[i] = list[i]; } } return array; } internal unsafe static IDictionary FromPhotonHashtable(this Hashtable hashtable) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); DictionaryEntryEnumerator enumerator = hashtable.GetEnumerator(); try { while (((DictionaryEntryEnumerator)(ref enumerator)).MoveNext()) { DictionaryEntry current = ((DictionaryEntryEnumerator)(ref enumerator)).Current; if (current.Key is string key) { object value = current.Value; Hashtable val = (Hashtable)((value is Hashtable) ? value : null); if (val != null) { dictionary[key] = val.FromPhotonHashtable(); } else if (value is object[] array) { dictionary[key] = array.FromPhotonArray(); } else { dictionary[key] = value; } } } return dictionary; } finally { ((IDisposable)(*(DictionaryEntryEnumerator*)(&enumerator))/*cast due to .constrained prefix*/).Dispose(); } } private static IList FromPhotonArray(this object[] array) { IList list = new List(); foreach (object obj in array) { Hashtable val = (Hashtable)((obj is Hashtable) ? obj : null); if (val != null) { list.Add(val.FromPhotonHashtable()); } else { list.Add(obj); } } return list; } } public static class StringExtensions { public static string ToSlug(this string input, string @namespace) { if (string.IsNullOrEmpty(input)) { return @namespace; } string slug; return @namespace.ToLowerInvariant() + ":" + (TryCreateReadableSlug(input, out slug) ? slug : CreateEncodedSlug(input)); } private static bool TryCreateReadableSlug(string input, out string slug) { string text = input.Normalize(NormalizationForm.FormD); StringBuilder stringBuilder = new StringBuilder(input.Length); string text2 = text; foreach (char c in text2) { UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); if (unicodeCategory == UnicodeCategory.NonSpacingMark) { continue; } if (IsAsciiLetter(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); continue; } if (IsAsciiDigit(c)) { stringBuilder.Append(c); continue; } if (char.IsLetterOrDigit(c)) { slug = string.Empty; return false; } if (stringBuilder.Length > 0) { if (stringBuilder[stringBuilder.Length - 1] != '-') { stringBuilder.Append('-'); } } } if (stringBuilder.Length > 0) { if (stringBuilder[stringBuilder.Length - 1] == '-') { stringBuilder.Length--; } } slug = stringBuilder.ToString(); return slug.Length > 0; } private static string CreateEncodedSlug(string input) { byte[] bytes = Encoding.UTF8.GetBytes(input); StringBuilder stringBuilder = new StringBuilder(bytes.Length * 2 + 2); stringBuilder.Append("hex-"); byte[] array = bytes; foreach (byte b in array) { stringBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture)); } return stringBuilder.ToString(); } private static bool IsAsciiLetter(char character) { switch (character) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': return true; default: return false; } } private static bool IsAsciiDigit(char character) { if (character >= '0') { return character <= '9'; } return false; } } } namespace Mutators.Enums { public enum MutatorDifficulty { Negligible, VeryEasy, Easy, Normal, Hard, VeryHard, Insanity } public enum MutatorsGameState { None = 0, Shop = 5, LevelReady = 29, LevelGenerated = 30 } public enum MutatorSource { User, Mod } } namespace Mutators.Assets { internal class AssetStore { internal const string FIRING_MY_LASER_PREFAB_ID = "Xepos.REPO-Mutators/FiringMyLaser"; internal static bool IsLaserLoaded { get; set; } internal static ExplosionPreset Preset { get; set; } } } namespace Mutators.Assets.Loaders { internal abstract class BaseGameAssetLoader { internal abstract void Load(); } internal class ExplosionAssetLoader : BaseGameAssetLoader { private const string Source = "Enemy - Bang"; internal override void Load() { if (!TryLoadExplosionPreset()) { RepoMutators.Logger.LogWarning("Mutators Handle With Care and Out With a Bang! will be excluded from selection."); } else { RepoMutators.Logger.LogDebug("Registered ExplosionPreset ScriptableObject from source Enemy - Bang."); } } private static bool TryLoadExplosionPreset() { EnemySetup val = ((IEnumerable)Enemies.AllEnemies).FirstOrDefault((Func)((EnemySetup setup) => ((Object)setup).name == "Enemy - Bang")); if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val)) { RepoMutators.Logger.LogWarning("Unable to register ExplosionPreset: could not find source Enemy - Bang."); return false; } GameObject val2 = ((PrefabRef)(object)((IEnumerable)val.spawnObjects).FirstOrDefault((Func)((PrefabRef so) => ((PrefabRef)(object)so).PrefabName == "Enemy - Bang")))?.Prefab; if ((Object)(object)val2 == (Object)null || !Object.op_Implicit((Object)(object)val2)) { RepoMutators.Logger.LogWarning("Unable to register ExplosionPreset: could not find source spawn object Enemy - Bang."); return false; } ExplosionPreset val3 = val2.GetComponentInChildren(true)?.explosionPreset; if ((Object)(object)val3 == (Object)null || !Object.op_Implicit((Object)(object)val3)) { RepoMutators.Logger.LogWarning("Unable to register ExplosionPreset: could not find ExplosionPreset on Enemy - Bang."); return false; } AssetStore.Preset = val3; return true; } } internal class LaserAssetLoader : BaseGameAssetLoader { private const string Source = "Valuable Wizard Dumgolfs Staff"; internal override void Load() { bool flag = TryRegisterFiringMyLaserPrefab(); if (!flag) { RepoMutators.Logger.LogWarning("Mutator Firing My Laser will be excluded from selection."); } AssetStore.IsLaserLoaded = flag; } private static bool TryRegisterFiringMyLaserPrefab() { if (NetworkPrefabs.HasNetworkPrefab("Xepos.REPO-Mutators/FiringMyLaser")) { return true; } GameObject val = CreateFiringMyLaserPrefab(); if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val)) { RepoMutators.Logger.LogWarning("Unable to register FiringMyLaser: could not find source Valuable Wizard Dumgolfs Staff."); return false; } NetworkPrefabs.RegisterNetworkPrefab("Xepos.REPO-Mutators/FiringMyLaser", val); RepoMutators.Logger.LogDebug("Registered FiringMyLaser network prefab from source Valuable Wizard Dumgolfs Staff."); return true; } private static GameObject? CreateFiringMyLaserPrefab() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown SemiLaser val = FindLaserOnValuable(); if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val)) { return null; } GameObject val2 = new GameObject("FiringMyLaser") { hideFlags = (HideFlags)61 }; val2.SetActive(false); GameObject val3 = Object.Instantiate(((Component)val).gameObject, val2.transform, false); val3.SetActive(true); ReplaceHurtColliders(val2); val2.AddComponent(); val2.AddComponent(); return val2; } private static SemiLaser? FindLaserOnValuable() { GameObject val = ((PrefabRef)(object)((IEnumerable)Valuables.AllValuables).FirstOrDefault((Func)((PrefabRef v) => string.Equals(((PrefabRef)(object)v).PrefabName, "Valuable Wizard Dumgolfs Staff", StringComparison.InvariantCultureIgnoreCase))))?.Prefab; if (val == null) { return null; } return val.GetComponentInChildren(true); } private static void ReplaceHurtColliders(GameObject prefab) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) HurtCollider[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (HurtCollider val in componentsInChildren) { if (!(val is PlayerIgnoringHurtCollider)) { PlayerIgnoringHurtCollider playerIgnoringHurtCollider = ((Component)val).gameObject.AddComponent(); ((HurtCollider)playerIgnoringHurtCollider).playerKill = true; ((HurtCollider)playerIgnoringHurtCollider).enemyDamage = 30; ((HurtCollider)playerIgnoringHurtCollider).enemyKill = false; ((HurtCollider)playerIgnoringHurtCollider).enemyStun = val.enemyStun; ((HurtCollider)playerIgnoringHurtCollider).enemyStunTime = val.enemyStunTime; ((HurtCollider)playerIgnoringHurtCollider).enemyHitForce = val.enemyHitForce; ((HurtCollider)playerIgnoringHurtCollider).enemyHitTorque = val.enemyHitTorque; ((HurtCollider)playerIgnoringHurtCollider).playerDamageCooldown = val.playerDamageCooldown; ((HurtCollider)playerIgnoringHurtCollider).physDamageCooldown = val.physDamageCooldown; ((HurtCollider)playerIgnoringHurtCollider).physImpact = val.physImpact; ((HurtCollider)playerIgnoringHurtCollider).physHitForce = val.physHitForce; ((HurtCollider)playerIgnoringHurtCollider).physHitTorque = val.physHitTorque; ((HurtCollider)playerIgnoringHurtCollider).hitSpread = val.hitSpread; Object.DestroyImmediate((Object)(object)val); } } } } } namespace Mutators.Announcements { public sealed class MutatorAnnouncement { private bool _isDirty; private string _name; private string _description = string.Empty; private readonly List _descriptionSegments; public MutatorAnnouncementDescriptionSegment DescriptionBase { get; } public bool IsUpdatingBaseDescriptionAllowed { get; } internal event Action? Changed; internal MutatorAnnouncement(string name, string description, bool allowEditBaseDescription) { _name = name; DescriptionBase = new MutatorAnnouncementDescriptionSegment("description".ToSlug(name), 0, description); IsUpdatingBaseDescriptionAllowed = allowEditBaseDescription; _descriptionSegments = new List(); BuildDescription(); } public string GetName() { return _name; } public string GetDescription() { if (!_isDirty) { return _description; } BuildDescription(); _isDirty = false; return _description; } public void UpdateBaseDescription(string description) { if (IsUpdatingBaseDescriptionAllowed && !(DescriptionBase.Value == description)) { DescriptionBase.Value = description; NotifyChanged(); } } public void UpdateSegment(string key, string value, ushort? priority = null) { MutatorAnnouncementDescriptionSegment descriptionSegment = GetDescriptionSegment(key); if (descriptionSegment == null) { return; } bool flag = descriptionSegment.Value != value; ushort valueOrDefault = priority.GetValueOrDefault(); bool flag2 = priority.HasValue && descriptionSegment.Priority != valueOrDefault; if (flag || flag2) { if (flag2) { descriptionSegment.Priority = valueOrDefault; SortSegments(); } if (flag) { descriptionSegment.Value = value; } NotifyChanged(); } } public bool RemoveSegment(string key) { MutatorAnnouncementDescriptionSegment descriptionSegment = GetDescriptionSegment(key); if (descriptionSegment == null) { return false; } if (!_descriptionSegments.Remove(descriptionSegment)) { return false; } NotifyChanged(); return true; } public bool AddSegment(MutatorAnnouncementDescriptionSegment segment) { if (!IsKeyUnique(segment.Key)) { return false; } _descriptionSegments.Add(segment); SortSegments(); NotifyChanged(); return true; } public bool AddOrUpdateSegment(MutatorAnnouncementDescriptionSegment segment) { MutatorAnnouncementDescriptionSegment descriptionSegment = GetDescriptionSegment(segment.Key); bool result = true; if (descriptionSegment != null) { bool flag = descriptionSegment.Priority != segment.Priority; if (descriptionSegment.Value == segment.Value && !flag) { return false; } descriptionSegment.Priority = segment.Priority; descriptionSegment.Value = segment.Value; if (flag) { SortSegments(); } NotifyChanged(); } else { result = AddSegment(segment); } return result; } public MutatorAnnouncementDescriptionSegment? GetDescriptionSegment(string key) { foreach (MutatorAnnouncementDescriptionSegment descriptionSegment in _descriptionSegments) { if (descriptionSegment.Key == key) { return descriptionSegment; } } return null; } private bool IsKeyUnique(string key) { return _descriptionSegments.All((MutatorAnnouncementDescriptionSegment segment) => segment.Key != key); } private void SortSegments() { _descriptionSegments.Sort((MutatorAnnouncementDescriptionSegment a, MutatorAnnouncementDescriptionSegment b) => b.Priority.CompareTo(a.Priority)); } private void BuildDescription() { _description = DescriptionBase.Value + string.Join("", _descriptionSegments.Select((MutatorAnnouncementDescriptionSegment segment) => segment.Value)); } private void NotifyChanged() { _isDirty = true; this.Changed?.Invoke(this); } } public class MutatorAnnouncementDescriptionSegment(string key, ushort priority, string value) { public string Key { get; } = key; public ushort Priority { get; internal set; } = priority; public string Value { get; internal set; } = value; } public class MutatorAnnouncingBag { private int _index; private MutatorAnnouncement[] _announcements; private readonly IDictionary _announcementsByNamespacedName = new Dictionary(); public static MutatorAnnouncingBag Instance { get; } = new MutatorAnnouncingBag(); internal MutatorAnnouncement Current => _announcements[_index]; public bool IsEmpty => _announcements.Length == 0; public int Count => _announcements.Length; internal event Action? CurrentChanged; internal void Prime(IMutator mutator) { _index = 0; _announcementsByNamespacedName.Clear(); IList list = GetMutators(mutator).ToList(); if (list.Count == 0) { _announcements = Array.Empty(); return; } _announcements = new MutatorAnnouncement[list.Count]; IMutator currentMutator = MutatorManager.Instance.CurrentMutator; bool flag = currentMutator is IMultiMutator; for (int i = 0; i < list.Count; i++) { IMutator mutator2 = list[i]; string name = ((flag && !string.IsNullOrEmpty(currentMutator.Name)) ? currentMutator.Name : (mutator2.Name + ((list.Count > 1) ? $" + {list.Count - 1}" : string.Empty))); string description = ((flag && !string.IsNullOrEmpty(currentMutator.Description)) ? currentMutator.Description : mutator2.Description); MutatorAnnouncement mutatorAnnouncement = new MutatorAnnouncement(name, description, !flag || string.IsNullOrWhiteSpace(currentMutator.Description)); mutatorAnnouncement.Changed += HandleAnnouncementChanged; _announcements[i] = mutatorAnnouncement; _announcementsByNamespacedName[mutator2.NamespacedName] = mutatorAnnouncement; } this.CurrentChanged?.Invoke(Current); } private static IEnumerable GetMutators(IMutator mutator) { if (mutator is IMultiMutator multiMutator) { return multiMutator.SubMutators.Keys; } return new <>z__ReadOnlySingleElementList(mutator); } internal bool MoveNext() { if (_announcements.Length <= 1) { return false; } _index = (_index + 1) % _announcements.Length; this.CurrentChanged?.Invoke(Current); return true; } internal bool MoveTo(MutatorAnnouncement announcement) { for (int i = 0; i < _announcements.Length; i++) { if (announcement == _announcements[i]) { _index = i; this.CurrentChanged?.Invoke(Current); return true; } } return false; } private void HandleAnnouncementChanged(MutatorAnnouncement announcement) { if (announcement == Current) { this.CurrentChanged?.Invoke(announcement); } } public bool TryGetAnnouncement(string namespacedName, [NotNullWhen(true)] out MutatorAnnouncement? announcement) { if (_announcementsByNamespacedName.TryGetValue(namespacedName, out MutatorAnnouncement value)) { announcement = value; return true; } announcement = null; return false; } } }