using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MonoMod.Utils;
using Newtonsoft.Json;
using Shared;
using TraitControl.Patches;
using UnityEngine;
using UnityEngine.Serialization;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("p1xel8ted")]
[assembly: AssemblyConfiguration("Release-Thunderstore")]
[assembly: AssemblyDescription("TraitControl")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1+985c746328f160bdc22b06eded5c672299f883bb")]
[assembly: AssemblyProduct("TraitControl")]
[assembly: AssemblyTitle("TraitControl")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 TraitControl
{
[BepInPlugin("p1xel8ted.cotl.traitcontrol", "Trait Control", "0.1.1")]
[BepInDependency("com.bepis.bepinex.configurationmanager", "18.4.1")]
[BepInIncompatibility("NothingNegative")]
public class Plugin : BaseUnityPlugin
{
[CompilerGenerated]
private sealed class <RefreshConfigurationManager>d__52 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <RefreshConfigurationManager>d__52(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = null;
<>1__state = 1;
return true;
case 1:
{
<>1__state = -1;
BaseUnityPlugin configurationManager = GetConfigurationManager();
if ((Object)(object)configurationManager == (Object)null)
{
Log.LogWarning((object)"ConfigurationManager plugin not found");
return false;
}
Type type = ((object)configurationManager).GetType();
PropertyInfo property = type.GetProperty("DisplayingWindow");
if (property == null)
{
Log.LogWarning((object)"ConfigurationManager.DisplayingWindow property not found");
return false;
}
if (!(bool)property.GetValue(configurationManager))
{
return false;
}
MethodInfo method = type.GetMethod("BuildSettingList");
if (method == null)
{
Log.LogWarning((object)"ConfigurationManager.BuildSettingList method not found");
return false;
}
method.Invoke(configurationManager, null);
return false;
}
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private const string PluginGuid = "p1xel8ted.cotl.traitcontrol";
internal const string PluginName = "Trait Control";
private const string PluginVer = "0.1.1";
private const string TraitReplacementSection = "01. Trait Replacement";
private const string TraitWeightsSection = "02. Trait Weights";
private static bool? _isNothingNegativePresentCache;
private static Plugin _instance;
internal static ConfigEntry<bool> NoNegativeTraits { get; private set; }
internal static ConfigEntry<bool> UseUnlockedTraitsOnly { get; private set; }
internal static ConfigEntry<bool> IncludeImmortal { get; private set; }
internal static ConfigEntry<bool> IncludeDisciple { get; private set; }
internal static ConfigEntry<bool> ShowNotificationsWhenRemovingTraits { get; private set; }
internal static ConfigEntry<bool> ShowNotificationsWhenAddingTraits { get; private set; }
internal static ConfigEntry<bool> EnableTraitWeights { get; private set; }
internal static Dictionary<TraitType, ConfigEntry<float>> TraitWeights { get; } = new Dictionary<TraitType, ConfigEntry<float>>();
internal static ManualLogSource Log { get; private set; }
private static ConfigFile ConfigInstance { get; set; }
private void Awake()
{
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Expected O, but got Unknown
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Expected O, but got Unknown
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Expected O, but got Unknown
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_0190: Expected O, but got Unknown
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01f8: Expected O, but got Unknown
//IL_022d: Unknown result type (might be due to invalid IL or missing references)
//IL_0237: Expected O, but got Unknown
//IL_0270: Unknown result type (might be due to invalid IL or missing references)
//IL_027a: Expected O, but got Unknown
_instance = this;
Log = ((BaseUnityPlugin)this).Logger;
ConfigInstance = ((BaseUnityPlugin)this).Config;
NoNegativeTraits = ConfigInstance.Bind<bool>("01. Trait Replacement", "Enable Trait Replacement", false, new ConfigDescription("Replace negative traits with positive ones based on the configuration below.", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 10
}
}));
NoNegativeTraits.SettingChanged += delegate
{
UpdateNoNegativeTraits();
};
UseUnlockedTraitsOnly = ConfigInstance.Bind<bool>("01. Trait Replacement", "Use Unlocked Traits Only", true, new ConfigDescription("Only use unlocked traits when replacing negative traits.", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 9
}
}));
UseUnlockedTraitsOnly.SettingChanged += delegate
{
TraitControl.Patches.NoNegativeTraits.GenerateAvailableTraits();
};
IncludeImmortal = ConfigInstance.Bind<bool>("01. Trait Replacement", "Include Immortal", false, new ConfigDescription("Include the Immortal trait when replacing negative traits.", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 8
}
}));
IncludeImmortal.SettingChanged += delegate
{
TraitControl.Patches.NoNegativeTraits.GenerateAvailableTraits();
};
IncludeDisciple = ConfigInstance.Bind<bool>("01. Trait Replacement", "Include Disciple", false, new ConfigDescription("Include the Disciple trait when replacing negative traits.", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 7
}
}));
IncludeDisciple.SettingChanged += delegate
{
TraitControl.Patches.NoNegativeTraits.GenerateAvailableTraits();
};
ShowNotificationsWhenRemovingTraits = ConfigInstance.Bind<bool>("01. Trait Replacement", "Show Notifications When Removing Traits", false, new ConfigDescription("Show notifications when removing negative traits.", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 6
}
}));
ShowNotificationsWhenAddingTraits = ConfigInstance.Bind<bool>("01. Trait Replacement", "Show Notifications When Adding Traits", false, new ConfigDescription("Show notifications when adding positive traits.", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 5
}
}));
EnableTraitWeights = ConfigInstance.Bind<bool>("02. Trait Weights", "Enable Trait Weights", false, new ConfigDescription("Enable weighted random selection for starting traits. When enabled, you can configure how often each trait appears below. Set a weight to 0 to disable that trait entirely.", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 1000
}
}));
EnableTraitWeights.SettingChanged += delegate
{
UpdateTraitWeightVisibility();
};
GenerateTraitWeightConfigs();
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "p1xel8ted.cotl.traitcontrol");
Log.LogInfo((object)"Trait Control loaded.");
}
private static void GenerateTraitWeightConfigs()
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Expected O, but got Unknown
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
HashSet<TraitType> hashSet = new HashSet<TraitType>();
hashSet.UnionWith(FollowerTrait.StartingTraits);
hashSet.UnionWith(FollowerTrait.RareStartingTraits);
int count = hashSet.Count;
foreach (TraitType item in hashSet.OrderBy((TraitType t) => ((object)(TraitType)(ref t)).ToString()))
{
TraitType current = item;
bool flag = !EnableTraitWeights.Value;
string traitDescription = GetTraitDescription(current);
string text = (string.IsNullOrEmpty(traitDescription) ? $"Weight for {current}. Higher = more likely. Set to 0 to disable. Default is 1.0." : (traitDescription + "\n\nWeight: Higher = more likely. Set to 0 to disable. Default is 1.0."));
ConfigEntry<float> value = ConfigInstance.Bind<float>("02. Trait Weights", ((object)(TraitType)(ref current)).ToString(), 1f, new ConfigDescription(text, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), new object[1]
{
new ConfigurationManagerAttributes
{
Order = count--,
Browsable = !flag
}
}));
TraitWeights[current] = value;
}
}
private static string GetTraitDescription(TraitType trait)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
try
{
string localizedDescription = FollowerTrait.GetLocalizedDescription(trait, (FollowerBrain)null);
if (string.IsNullOrWhiteSpace(localizedDescription) || localizedDescription.StartsWith("Traits/"))
{
return null;
}
return StripRichText(localizedDescription);
}
catch
{
return null;
}
}
private static string StripRichText(string input)
{
if (string.IsNullOrEmpty(input))
{
return input;
}
return Regex.Replace(input, "<[^>]+>", string.Empty).Trim();
}
private static void UpdateTraitWeightVisibility()
{
bool value = EnableTraitWeights.Value;
foreach (ConfigEntry<float> value2 in TraitWeights.Values)
{
ConfigDescription description = ((ConfigEntryBase)value2).Description;
if (description != null && description.Tags?.Length > 0 && ((ConfigEntryBase)value2).Description.Tags[0] is ConfigurationManagerAttributes configurationManagerAttributes)
{
configurationManagerAttributes.Browsable = value;
}
}
Plugin instance = _instance;
if (instance != null)
{
((MonoBehaviour)instance).StartCoroutine(RefreshConfigurationManager());
}
}
private static BaseUnityPlugin GetConfigurationManager()
{
return (from pluginInfo in Chainloader.PluginInfos.Values
where pluginInfo.Metadata.GUID == "com.bepis.bepinex.configurationmanager"
select pluginInfo.Instance).FirstOrDefault();
}
[IteratorStateMachine(typeof(<RefreshConfigurationManager>d__52))]
private static IEnumerator RefreshConfigurationManager()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <RefreshConfigurationManager>d__52(0);
}
private static void UpdateNoNegativeTraits()
{
if (IsNothingNegativePresent())
{
NoNegativeTraits.Value = false;
}
else if (NoNegativeTraits.Value)
{
TraitControl.Patches.NoNegativeTraits.UpdateAllFollowerTraits();
}
else
{
TraitControl.Patches.NoNegativeTraits.RestoreOriginalTraits();
}
}
internal static bool IsNothingNegativePresent()
{
bool valueOrDefault = _isNothingNegativePresentCache.GetValueOrDefault();
if (!_isNothingNegativePresentCache.HasValue)
{
valueOrDefault = Chainloader.PluginInfos.Any((KeyValuePair<string, PluginInfo> plugin) => plugin.Value.Instance.Info.Metadata.GUID.Equals("NothingNegative", StringComparison.OrdinalIgnoreCase));
_isNothingNegativePresentCache = valueOrDefault;
}
return _isNothingNegativePresentCache.Value;
}
internal static void L(string message)
{
Log.LogInfo((object)message);
}
}
}
namespace TraitControl.Patches
{
[Harmony]
public static class NoNegativeTraits
{
[Serializable]
public class FollowerTraitBackup
{
[FormerlySerializedAs("ID")]
public int id;
[FormerlySerializedAs("Name")]
public string name;
[FormerlySerializedAs("Traits")]
public List<string> traits;
}
private static HashSet<TraitType> _allTraits;
private static List<FollowerTraitBackup> _followerTraitBackups = new List<FollowerTraitBackup>();
private static string DataPath => Path.Combine(Application.persistentDataPath, "saves", $"slot_{SaveAndLoad.SAVE_SLOT}_follower_trait_backups.json");
private static void LoadBackupFromFile()
{
if (!Plugin.IsNothingNegativePresent() && File.Exists(DataPath))
{
_followerTraitBackups = JsonConvert.DeserializeObject<List<FollowerTraitBackup>>(File.ReadAllText(DataPath));
Plugin.L($"Loaded {_followerTraitBackups.Count} follower trait backups.");
}
}
private static HashSet<TraitType> InitializeAllTraits()
{
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
HashSet<TraitType> hashSet = new HashSet<TraitType>();
hashSet.UnionWith(FollowerTrait.SingleTraits);
hashSet.UnionWith(FollowerTrait.GoodTraits);
hashSet.UnionWith(FollowerTrait.SinTraits);
hashSet.UnionWith(FollowerTrait.RareStartingTraits);
hashSet.UnionWith(FollowerTrait.StartingTraits);
hashSet.UnionWith(FollowerTrait.ExcludedFromMating);
List<TraitType> cultTraits = DataManager.Instance.CultTraits;
if (Plugin.UseUnlockedTraitsOnly.Value && cultTraits != null && cultTraits.Count > 0)
{
Plugin.L("Using unlocked traits only for available traits.");
HashSet<TraitType> hashSet2 = hashSet.Where((TraitType a) => cultTraits.Contains(a) && FollowerTrait.IsPositiveTrait(a)).ToHashSet();
if (hashSet2.Count > 0)
{
hashSet = hashSet2;
}
else
{
Plugin.L("No unlocked positive traits found. Falling back to all positive traits.");
}
}
hashSet.RemoveWhere((TraitType a) => !FollowerTrait.IsPositiveTrait(a));
hashSet.RemoveWhere((TraitType a) => (int)a == 81);
if (!Plugin.IncludeImmortal.Value)
{
Plugin.L("Removing Immortal trait from available traits.");
hashSet.Remove((TraitType)32);
}
if (!Plugin.IncludeDisciple.Value)
{
Plugin.L("Removing Disciple trait from available traits.");
hashSet.Remove((TraitType)35);
}
Plugin.L("All 'positive' traits currently available based on your configuration:");
foreach (TraitType item in hashSet)
{
TraitType current = item;
Plugin.L("\t" + ((object)(TraitType)(ref current)).ToString());
}
return hashSet;
}
internal static void UpdateAllFollowerTraits()
{
if (Plugin.IsNothingNegativePresent())
{
return;
}
foreach (Follower item in FollowerManager.Followers.Values.SelectMany((List<Follower> list) => list))
{
ProcessTraitReplacement(item.Brain);
}
}
internal static void RestoreOriginalTraits()
{
if (Plugin.IsNothingNegativePresent() || _followerTraitBackups == null)
{
return;
}
foreach (FollowerTraitBackup followerTraitBackup in _followerTraitBackups)
{
Follower val = FollowerManager.FindFollowerByID(followerTraitBackup.id);
if ((Object)(object)val == (Object)null || val.Brain == null)
{
Plugin.L($"Could not find follower with ID {followerTraitBackup.id} to restore traits. Is the follower dead?");
}
else if (followerTraitBackup.traits == null)
{
Plugin.L("No traits to restore for " + val.Brain._directInfoAccess.Name);
}
else
{
RestoreFollowerTraits(val, followerTraitBackup.traits);
}
}
}
private static void ClearAllTraits(Follower follower)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: 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 (Plugin.IsNothingNegativePresent())
{
return;
}
foreach (TraitType item in follower.Brain._directInfoAccess.Traits.ToList())
{
follower.Brain.RemoveTrait(item, ShouldShowRemoveNotification(item));
}
}
private static void RestoreFollowerTraits(Follower follower, List<string> backupTraits)
{
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
Plugin.L("Restoring traits for " + follower.Brain._directInfoAccess.Name);
ClearAllTraits(follower);
foreach (string backupTrait in backupTraits)
{
if (Enum.TryParse<TraitType>(backupTrait, out TraitType result))
{
follower.Brain.AddTrait(result, ShouldShowAddNotification(result));
}
else
{
Plugin.L("Could not parse trait " + backupTrait + " for follower " + follower.Brain._directInfoAccess.Name);
}
}
}
private static void SaveBackupToFile(bool log = true)
{
if (Plugin.IsNothingNegativePresent())
{
return;
}
try
{
if (_followerTraitBackups == null || !_followerTraitBackups.Any())
{
if (log)
{
Plugin.L("No follower trait backups to save.");
}
return;
}
string contents = JsonConvert.SerializeObject((object)_followerTraitBackups, (Formatting)1);
File.WriteAllText(DataPath, contents);
if (log)
{
Plugin.L($"Saved {_followerTraitBackups.Count} follower trait backups to {DataPath}");
}
}
catch (Exception ex)
{
if (log)
{
Plugin.L("Error saving follower trait backups: " + ex.Message);
}
}
}
private static void ProcessTraitReplacement(FollowerBrain brain, bool directManipulation = false)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: 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)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_011b: 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_00c7: 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_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
CreateTraitBackup(brain);
List<TraitType> traits = brain._directInfoAccess.Traits;
Plugin.L("Processing traits for " + brain._directInfoAccess.Name);
foreach (TraitType item in traits.ToList())
{
if (FollowerTrait.IsPositiveTrait(item))
{
Plugin.L($"\tSkipping positive trait {item}");
continue;
}
if (!Plugin.UseUnlockedTraitsOnly.Value && IsExclusiveTrait(item) && TryReplaceExclusiveTrait(item, out var replacement))
{
if (directManipulation)
{
traits.Remove(item);
if (!traits.Contains(replacement))
{
traits.Add(replacement);
}
}
else
{
brain.RemoveTrait(item, ShouldShowRemoveNotification(item));
brain.AddTrait(replacement, ShouldShowAddNotification(replacement));
}
Plugin.L($"\tReplacing negative exclusive trait {item} with exclusive {replacement}");
continue;
}
Plugin.L($"\tRemoving negative trait {item}");
if (directManipulation)
{
traits.Remove(item);
}
else
{
brain.RemoveTrait(item, ShouldShowRemoveNotification(item));
}
TraitType val = FindPositiveReplacement(brain);
if ((int)val != 0)
{
if (directManipulation)
{
if (!traits.Contains(val))
{
traits.Add(val);
}
}
else
{
brain.AddTrait(val, ShouldShowAddNotification(val));
}
Plugin.L($"\tAdded replacement positive trait {val}");
}
else
{
Plugin.L($"\tNo replacement trait available for {item}");
}
}
}
private static void CreateTraitBackup(FollowerBrain brain)
{
List<string> traits = brain._directInfoAccess.Traits.Select((TraitType trait) => ((object)(TraitType)(ref trait)).ToString()).ToList();
FollowerTraitBackup traitBackup = new FollowerTraitBackup
{
traits = traits,
id = brain._directInfoAccess.ID,
name = brain._directInfoAccess.Name
};
List<FollowerTraitBackup> followerTraitBackups = _followerTraitBackups;
if (followerTraitBackups == null || !followerTraitBackups.Any((FollowerTraitBackup b) => b.id == traitBackup.id && b.name == traitBackup.name))
{
Plugin.L("Backing up original traits for " + brain._directInfoAccess.Name);
_followerTraitBackups?.Add(traitBackup);
SaveBackupToFile();
}
}
private static bool TryReplaceExclusiveTrait(TraitType trait, out TraitType replacement)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Expected I4, but got Unknown
if (FollowerTrait.ExclusiveTraits.TryGetValue(trait, out replacement))
{
return true;
}
KeyValuePair<TraitType, TraitType> keyValuePair = FollowerTrait.ExclusiveTraits.FirstOrDefault((KeyValuePair<TraitType, TraitType> x) => x.Value == trait);
if ((int)keyValuePair.Key == 0)
{
return false;
}
replacement = (TraitType)(int)keyValuePair.Key;
return true;
}
private static TraitType FindPositiveReplacement(FollowerBrain brain)
{
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
if (_allTraits == null || _allTraits.Count == 0)
{
GenerateAvailableTraits();
}
if (_allTraits == null || _allTraits.Count == 0)
{
Plugin.L("Warning: No positive traits available for replacement.");
return (TraitType)0;
}
List<TraitType> list = _allTraits.Where((TraitType t) => !brain.HasTrait(t)).ToList();
if (list.Count == 0)
{
Plugin.L("Warning: Follower already has all available positive traits.");
return (TraitType)0;
}
return list[Random.Range(0, list.Count)];
}
[HarmonyPostfix]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
private static void FollowerBrain_Constructor(ref FollowerBrain __instance)
{
if (!Plugin.IsNothingNegativePresent() && Plugin.NoNegativeTraits.Value)
{
ProcessTraitReplacement(__instance, directManipulation: true);
}
}
private static bool IsExclusiveTrait(TraitType trait)
{
//IL_0005: 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 (!FollowerTrait.ExclusiveTraits.ContainsKey(trait))
{
return FollowerTrait.ExclusiveTraits.ContainsValue(trait);
}
return true;
}
private static bool HasValidLocalization(TraitType trait)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
string localizedTitle = FollowerTrait.GetLocalizedTitle(trait);
if (!string.IsNullOrWhiteSpace(localizedTitle))
{
return !localizedTitle.StartsWith("Traits/");
}
return false;
}
private static bool ShouldShowAddNotification(TraitType trait)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.ShowNotificationsWhenAddingTraits.Value)
{
return HasValidLocalization(trait);
}
return false;
}
private static bool ShouldShowRemoveNotification(TraitType trait)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.ShowNotificationsWhenRemovingTraits.Value)
{
return HasValidLocalization(trait);
}
return false;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(BiomeBaseManager), "Start")]
private static void BiomeBaseManager_Start()
{
if (!Plugin.IsNothingNegativePresent())
{
_followerTraitBackups?.Clear();
LoadBackupFromFile();
GenerateAvailableTraits();
}
}
internal static void GenerateAvailableTraits()
{
_allTraits = InitializeAllTraits();
}
}
[Harmony]
public static class TraitWeights
{
[HarmonyPrefix]
[HarmonyPatch(typeof(FollowerTrait), "GetStartingTrait")]
public static bool GetStartingTrait_Prefix(ref TraitType __result)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected I4, but got Unknown
if (!Plugin.EnableTraitWeights.Value)
{
return true;
}
__result = (TraitType)(int)GetWeightedTrait(FollowerTrait.StartingTraits);
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(FollowerTrait), "GetRareTrait")]
public static bool GetRareTrait_Prefix(ref TraitType __result)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected I4, but got Unknown
if (!Plugin.EnableTraitWeights.Value)
{
return true;
}
__result = (TraitType)(int)GetWeightedTrait(FollowerTrait.RareStartingTraits);
return false;
}
private static TraitType GetWeightedTrait(List<TraitType> sourceTraits)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: 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)
List<TraitType> list = new List<TraitType>(sourceTraits);
for (int num = list.Count - 1; num >= 0; num--)
{
TraitType val = list[num];
foreach (FollowerBrain allBrain in FollowerBrain.AllBrains)
{
if (allBrain.HasTrait(val) && FollowerTrait.SingleTraits.Contains(val))
{
list.RemoveAt(num);
break;
}
}
}
int num2 = 0;
while (++num2 < 100)
{
TraitType val2 = SelectWeightedTrait(list);
if ((int)val2 == 0)
{
break;
}
if (!FollowerTrait.IsTraitUnavailable(val2) && !DataManager.Instance.CultTraits.Contains(val2))
{
return val2;
}
}
return (TraitType)0;
}
private static TraitType SelectWeightedTrait(List<TraitType> traits)
{
//IL_0028: 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)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: 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)
if (traits.Count == 0)
{
return (TraitType)0;
}
List<float> list = new List<float>();
List<TraitType> list2 = new List<TraitType>();
float num = 0f;
foreach (TraitType trait in traits)
{
float traitWeight = GetTraitWeight(trait);
if (traitWeight > 0f)
{
list.Add(traitWeight);
list2.Add(trait);
num += traitWeight;
}
}
if (list2.Count == 0 || num <= 0f)
{
return (TraitType)0;
}
float num2 = Random.Range(0f, num);
float num3 = 0f;
for (int i = 0; i < list2.Count; i++)
{
num3 += list[i];
if (num2 <= num3)
{
return list2[i];
}
}
return list2[list2.Count - 1];
}
private static float GetTraitWeight(TraitType trait)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.TraitWeights.TryGetValue(trait, out var value))
{
return value.Value;
}
return 1f;
}
}
}
namespace Shared
{
public static class Helpers
{
private static class StorefrontDetector
{
private static readonly string[] PiracyFiles = new string[65]
{
"SmartSteamEmu.ini", "codex.ini", "steam_emu.ini", "goldberg_emulator.dll", "steamclient_loader.dll", "steam_api64_o.dll", "steam_api.cdx", "steam_api64.cdx.dll", "steam_interfaces.txt", "local_save.txt",
"valve.ini", "codex64.dll", "coldclient.dll", "ColdClientLoader.ini", "steamless.dll", "GreenLuma", "CreamAPI.dll", "cream_api.ini", "ScreamAPI.dll", "OnlineFix.dll",
"OnlineFix.url", "online-fix.me", "CODEX", "SKIDROW", "CPY", "PLAZA", "HOODLUM", "EMPRESS", "TENOKE", "PROPHET",
"REVOLT", "DARKSiDERS", "RAZOR1911", "FLT", "FLT.dll", "RUNE", "RUNE.ini", "TiNYiSO", "RELOADED", "RLD!",
"DOGE", "BAT", "P2P", "ElAmigos", "FitGirl", "DODI", "xatab", "KaOs", "IGG", "Masquerade",
"3dmgame.dll", "ALI213.dll", "crack", "crack.exe", "Crack.nfo", "crackfix", "CrackOnly", "fix.exe", "gamefix.dll", "SKIDROW.ini",
"nosTEAM", "NoSteam", "FCKDRM", "Goldberg", "VALVEEMPRESS"
};
public static string DetectStorefront()
{
string dir = Directory.GetCurrentDirectory();
string text = "Unknown";
if (File.Exists(Path.Combine(dir, "steam_api.dll")) || File.Exists(Path.Combine(dir, "steam_api64.dll")) || File.Exists(Path.Combine(dir, "steam_appid.txt")) || Directory.Exists(Path.Combine(dir, "steam_settings")))
{
text = "Steam";
}
else if (Directory.GetFiles(dir, "goggame-*.info").Any() || File.Exists(Path.Combine(dir, "galaxy.dll")))
{
text = "GOG";
}
else if (File.Exists(Path.Combine(dir, "EOSSDK-Win64-Shipping.dll")) || File.Exists(Path.Combine(dir, "EpicOnlineServices.dll")) || Directory.Exists(Path.Combine(dir, ".egstore")))
{
text = "Epic";
}
else if (IsProcessRunning("steam"))
{
text = "Steam (process only)";
}
else if (IsProcessRunning("GalaxyClient"))
{
text = "GOG (process only)";
}
else if (IsProcessRunning("EpicGamesLauncher"))
{
text = "Epic (process only)";
}
if (PiracyFiles.Any((string pirate) => File.Exists(Path.Combine(dir, pirate)) || Directory.Exists(Path.Combine(dir, pirate))))
{
text += " + Possible Pirated/Cracked Files Found!";
}
return text;
}
private static bool IsProcessRunning(string name)
{
return Process.GetProcessesByName(name).Length != 0;
}
}
[CompilerGenerated]
private sealed class <FilterEnumerator>d__5 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public IEnumerator original;
public Type[] typesToRemove;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <FilterEnumerator>d__5(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
break;
case 1:
<>1__state = -1;
break;
}
while (original.MoveNext())
{
object current = original.Current;
if (current != null && !ArrayExtensions.Contains<Type>(typesToRemove, current.GetType()))
{
<>2__current = current;
<>1__state = 1;
return true;
}
}
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
internal static List<Follower> AllFollowers => FollowerManager.Followers.SelectMany((KeyValuePair<FollowerLocation, List<Follower>> followerList) => followerList.Value).ToList();
public static void PrintModLoaded(string plugin, ManualLogSource logger)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
string text = Application.version.Replace("\r", "").Replace("\n", "");
string buildGUID = Application.buildGUID;
Platform current = PlatformHelper.Current;
string text2 = StorefrontDetector.DetectStorefront();
logger.LogInfo((object)"==========================================");
logger.LogInfo((object)(" Plugin Loaded: " + plugin));
logger.LogInfo((object)(" Version : " + text + " (BuildGUID: " + buildGUID + ")"));
logger.LogInfo((object)$" Platform : {current}");
logger.LogInfo((object)(" Storefront: " + text2));
logger.LogInfo((object)"==========================================");
}
public static bool IsMultiplierActive(float value)
{
return !Mathf.Approximately(value, 1f);
}
[IteratorStateMachine(typeof(<FilterEnumerator>d__5))]
public static IEnumerator FilterEnumerator(IEnumerator original, Type[] typesToRemove)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <FilterEnumerator>d__5(0)
{
original = original,
typesToRemove = typesToRemove
};
}
}
internal sealed class ConfigurationManagerAttributes
{
public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);
public bool? ShowRangeAsPercent;
public Action<ConfigEntryBase> CustomDrawer;
public CustomHotkeyDrawerFunc CustomHotkeyDrawer;
public bool? Browsable;
public string Category;
public object DefaultValue;
public bool? HideDefaultButton;
public bool? HideSettingName;
public string Description;
public string DispName;
public int? Order;
public bool? ReadOnly;
public bool? IsAdvanced;
public Func<object, string> ObjToStr;
public Func<string, object> StrToObj;
}
}