using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Lamb.UI;
using MMTools;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Follower Trait Tree")]
[assembly: AssemblyDescription("Controller-friendly follower trait editor prototype for Cult of the Lamb")]
[assembly: AssemblyCompany("Codex")]
[assembly: AssemblyProduct("Follower Trait Tree")]
[assembly: ComVisible(false)]
[assembly: Guid("19bce3de-2b65-4097-8785-fb7c1357c570")]
[assembly: AssemblyFileVersion("0.5.3.0")]
[assembly: AssemblyVersion("0.5.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace FollowerTraitTree
{
[BepInPlugin("com.cotl.followertraittree", "Follower Trait Tree", "0.5.3")]
public sealed class FollowerTraitTreePlugin : BaseUnityPlugin
{
public const string PluginGuid = "com.cotl.followertraittree";
public const string PluginName = "Follower Trait Tree";
public const string PluginVersion = "0.5.3";
internal const string ProfilePromptLabel = "View Follower Profile";
private Harmony _harmony;
private KeyCode _openKey;
private KeyCode _repairKey;
private TraitTreeMenu _menu;
private UIFollowerSummaryMenuController _followerSummaryMenu;
private PlayerFarming _menuPlayer;
private float _nextTreeAttach;
private float _nextTreeUnlock;
private bool _pausedByMenu;
private bool _legacySozoChecked;
private readonly HashSet<TYPES> _treeTypes = new HashSet<TYPES>();
private static readonly HashSet<TraitType> UnsafeTraits = new HashSet<TraitType>
{
(TraitType)35,
(TraitType)53,
(TraitType)54,
(TraitType)55,
(TraitType)56,
(TraitType)57,
(TraitType)61,
(TraitType)62,
(TraitType)63,
(TraitType)64,
(TraitType)65,
(TraitType)66,
(TraitType)67,
(TraitType)70,
(TraitType)71,
(TraitType)72,
(TraitType)73,
(TraitType)74,
(TraitType)75,
(TraitType)76,
(TraitType)77,
(TraitType)78,
(TraitType)80,
(TraitType)81,
(TraitType)90,
(TraitType)92,
(TraitType)112,
(TraitType)113,
(TraitType)116,
(TraitType)121,
(TraitType)122,
(TraitType)123,
(TraitType)124,
(TraitType)125
};
private static readonly HashSet<TraitType> RepairTraits = new HashSet<TraitType>
{
(TraitType)57,
(TraitType)67,
(TraitType)78,
(TraitType)90,
(TraitType)92,
(TraitType)72,
(TraitType)53,
(TraitType)54,
(TraitType)55,
(TraitType)56,
(TraitType)112,
(TraitType)113,
(TraitType)122,
(TraitType)123,
(TraitType)124,
(TraitType)125
};
private static readonly HashSet<TraitType> VisualStateTraits = new HashSet<TraitType>
{
(TraitType)90,
(TraitType)92,
(TraitType)72
};
internal static ManualLogSource Log { get; private set; }
internal static FollowerTraitTreePlugin Instance { get; private set; }
private void Awake()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: 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_0070: Expected O, but got Unknown
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
TraitTreeConfig.Bind(((BaseUnityPlugin)this).Config);
_openKey = ParseKey(TraitTreeConfig.OpenKey.Value, (KeyCode)287);
_repairKey = ParseKey(TraitTreeConfig.RepairKey.Value, (KeyCode)283);
RefreshTreeTypes();
try
{
FollowerTrait.Initialise();
}
catch
{
}
_harmony = new Harmony("com.cotl.followertraittree");
_harmony.PatchAll(typeof(FollowerTraitTreePlugin).Assembly);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Follower Trait Tree 0.5.3 loaded.");
}
private void OnDestroy()
{
_menu?.Close();
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
_harmony = null;
Instance = null;
}
private void Update()
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
if (TraitTreeConfig.Enabled.Value)
{
EnsureCrystalTreeUnlocked();
if (_menu != null && _menu.IsOpen)
{
_menu.HandleInput();
return;
}
if (Input.GetKeyDown(_openKey))
{
OpenMenu(PlayerFarming.Instance);
return;
}
AttachTreeInteractions();
TryRepairLegacySozo();
}
}
internal void OpenMenu(PlayerFarming player)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
if (DataManager.Instance == null || DataManager.Instance.Followers == null || DataManager.Instance.Followers.Count == 0)
{
Log.LogInfo((object)"Trait Tree: no followers available.");
return;
}
if (_menu == null)
{
_menu = new TraitTreeMenu(this, _repairKey);
}
BeginMenuSession(player);
_menu.Open(DataManager.Instance.Followers);
}
internal bool TryOpenFollowerProfile(interaction_FollowerInteraction interaction, StateMachine state)
{
if ((Object)(object)interaction == (Object)null || (Object)(object)((Component)interaction).GetComponent<TraitProfilePromptMarker>() == (Object)null || ((Interaction)interaction).SecondaryLabel != "View Follower Profile" || !CanOpenFollowerProfile(interaction))
{
return false;
}
if ((Object)(object)MonoSingleton<UIManager>.Instance == (Object)null || (Object)(object)MonoSingleton<UIManager>.Instance.FollowerSummaryMenuTemplate == (Object)null)
{
return false;
}
PlayerFarming val = (((Object)(object)state != (Object)null) ? ((Component)state).GetComponent<PlayerFarming>() : PlayerFarming.Instance);
((Interaction)interaction).EndIndicateHighlighted(val);
BeginMenuSession(val);
_followerSummaryMenu = MonoSingleton<UIManager>.Instance.ShowFollowerSummaryMenu(interaction.follower);
UIFollowerSummaryMenuController openedMenu = _followerSummaryMenu;
((UIMenuBase)openedMenu).OnHidden = (Action)Delegate.Combine(((UIMenuBase)openedMenu).OnHidden, (Action)delegate
{
if ((Object)(object)_followerSummaryMenu == (Object)(object)openedMenu)
{
_followerSummaryMenu = null;
}
OnMenuClosed();
});
return true;
}
internal void ConfigureFollowerProfilePrompt(interaction_FollowerInteraction interaction)
{
if ((Object)(object)interaction == (Object)null)
{
return;
}
TraitProfilePromptMarker component = ((Component)interaction).GetComponent<TraitProfilePromptMarker>();
string secondaryLabel = ((Interaction)interaction).SecondaryLabel;
if ((Object)(object)component != (Object)null && !string.IsNullOrEmpty(secondaryLabel) && secondaryLabel != "View Follower Profile")
{
Object.Destroy((Object)(object)component);
return;
}
if (!CanOpenFollowerProfile(interaction))
{
if ((Object)(object)component != (Object)null && (string.IsNullOrEmpty(secondaryLabel) || secondaryLabel == "View Follower Profile"))
{
((Interaction)interaction).HasSecondaryInteraction = false;
((Interaction)interaction).SecondaryInteractable = false;
((Interaction)interaction).SecondaryLabel = "";
}
return;
}
if ((Object)(object)component == (Object)null)
{
if (((Interaction)interaction).HasSecondaryInteraction || !string.IsNullOrEmpty(secondaryLabel))
{
return;
}
component = ((Component)interaction).gameObject.AddComponent<TraitProfilePromptMarker>();
}
((Interaction)interaction).HasSecondaryInteraction = true;
((Interaction)interaction).SecondaryInteractable = true;
((Interaction)interaction).SecondaryLabel = "View Follower Profile";
}
internal void OnMenuClosed()
{
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Invalid comparison between Unknown and I4
if (_pausedByMenu)
{
SimulationManager.UnPause();
_pausedByMenu = false;
}
if ((Object)(object)_menuPlayer != (Object)null && (Object)(object)_menuPlayer.state != (Object)null && (int)_menuPlayer.state.CURRENT_STATE == 13)
{
_menuPlayer.state.CURRENT_STATE = (State)0;
}
_menuPlayer = null;
}
private void BeginMenuSession(PlayerFarming player)
{
_menuPlayer = (((Object)(object)player != (Object)null) ? player : PlayerFarming.Instance);
if (!SimulationManager.IsPaused)
{
SimulationManager.Pause();
_pausedByMenu = true;
}
if ((Object)(object)_menuPlayer != (Object)null && (Object)(object)_menuPlayer.state != (Object)null)
{
_menuPlayer.state.CURRENT_STATE = (State)13;
}
}
private void AttachTreeInteractions()
{
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
if (!TraitTreeConfig.EnableTreeInteraction.Value || Time.unscaledTime < _nextTreeAttach)
{
return;
}
_nextTreeAttach = Time.unscaledTime + 1f;
Structure[] array = Structure.Structures.ToArray();
foreach (Structure val in array)
{
if (!((Object)(object)val == (Object)null) && val.Brain != null && val.Brain.Data != null && _treeTypes.Contains(val.Brain.Data.Type))
{
TraitTreeInteraction traitTreeInteraction = ((Component)val).GetComponent<TraitTreeInteraction>();
if ((Object)(object)traitTreeInteraction == (Object)null)
{
traitTreeInteraction = ((Component)val).gameObject.AddComponent<TraitTreeInteraction>();
}
traitTreeInteraction.Configure(this, val, TraitTreeConfig.InteractionRadius.Value);
}
}
}
private void EnsureCrystalTreeUnlocked()
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
if (TraitTreeConfig.UnlockCrystalTree.Value && !(Time.unscaledTime < _nextTreeUnlock) && DataManager.Instance != null)
{
_nextTreeUnlock = Time.unscaledTime + 2f;
TYPES item = (TYPES)195;
bool flag = false;
if (DataManager.Instance.UnlockedStructures != null && !DataManager.Instance.UnlockedStructures.Contains(item))
{
DataManager.Instance.UnlockedStructures.Add(item);
flag = true;
}
if (DataManager.Instance.RevealedStructures != null && !DataManager.Instance.RevealedStructures.Contains(item))
{
DataManager.Instance.RevealedStructures.Add(item);
flag = true;
}
if (flag)
{
Log.LogInfo((object)"Trait Tree unlocked the Crystal Tree decoration for this save.");
}
}
}
private void RefreshTreeTypes()
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
_treeTypes.Clear();
string[] array = TraitTreeConfig.TreeStructureTypes.Value.Split(new char[3] { ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < array.Length; i++)
{
if (Enum.TryParse<TYPES>(array[i].Trim(), ignoreCase: true, out TYPES result))
{
_treeTypes.Add(result);
}
}
if (_treeTypes.Count == 0)
{
_treeTypes.Add((TYPES)195);
}
}
private void TryRepairLegacySozo()
{
if (_legacySozoChecked || !TraitTreeConfig.RepairLegacySozoOnLoad.Value || DataManager.Instance == null || DataManager.Instance.Followers == null)
{
return;
}
FollowerInfo val = ((IEnumerable<FollowerInfo>)DataManager.Instance.Followers).FirstOrDefault((Func<FollowerInfo, bool>)((FollowerInfo f) => f != null && f.ID == 99996));
if (val != null)
{
_legacySozoChecked = true;
int num = RepairFollower(val, legacySozoRepair: true);
if (num > 0)
{
Log.LogWarning((object)("Trait Tree repaired Dr. Sozo by removing " + num + " incompatible state trait(s) left by v0.1.0."));
}
}
}
internal static bool IsUnsafeTrait(TraitType trait)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
return UnsafeTraits.Contains(trait);
}
internal static bool CanRestoreUnsafeTrait(FollowerInfo follower, TraitType trait)
{
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Invalid comparison between Unknown and I4
if (follower == null || (int)trait != 81)
{
return false;
}
bool num = follower.ID == 99990 || follower.ID == 99991 || follower.ID == 99992 || follower.ID == 99993;
bool flag = !string.IsNullOrEmpty(follower.SkinName) && follower.SkinName.IndexOf("CultLeader", StringComparison.OrdinalIgnoreCase) >= 0;
return num || flag;
}
internal static bool HasRepairableStateTraits(FollowerInfo follower)
{
if (follower != null && follower.Traits != null)
{
return follower.Traits.Any(RepairTraits.Contains);
}
return false;
}
internal unsafe static bool ApplyTrait(FollowerInfo follower, TraitType trait)
{
//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_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: 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_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
if (follower == null || (int)trait == 0)
{
return false;
}
if (follower.Traits == null)
{
follower.Traits = new List<TraitType>();
}
FollowerBrain val = FollowerBrain.FindBrainByID(follower.ID);
bool flag = follower.Traits.Contains(trait);
if (!flag && IsUnsafeTrait(trait) && !CanRestoreUnsafeTrait(follower, trait))
{
Log.LogWarning((object)("Trait Tree blocked unsafe state trait " + ((object)(*(TraitType*)(&trait))/*cast due to .constrained prefix*/).ToString() + " from being added to " + follower.Name + "."));
return false;
}
if (flag)
{
if (val == null)
{
follower.Traits.RemoveAll((TraitType t) => t == trait);
TwitchFollowers.SendFollowers();
}
else
{
val.RemoveTrait(trait, true);
}
}
else if (val == null)
{
RemoveExclusiveTraits(follower, trait);
follower.Traits.Add(trait);
TwitchFollowers.SendFollowers();
}
else
{
val.AddTrait(trait, true);
if (!follower.Traits.Contains(trait))
{
follower.Traits.Add(trait);
}
}
RepairLiveFollower(follower, val, flag && VisualStateTraits.Contains(trait), flag && RepairTraits.Contains(trait));
if (TraitTreeConfig.AutoSaveAfterChange.Value)
{
try
{
SaveAndLoad.Save();
}
catch (Exception ex)
{
Log.LogWarning((object)("Trait Tree autosave failed: " + ex.Message));
}
}
string text = (flag ? "Removed " : "Added ");
Log.LogInfo((object)("Trait Tree: " + text + ((object)(*(TraitType*)(&trait))/*cast due to .constrained prefix*/).ToString() + (flag ? " from " : " to ") + follower.Name + " (" + follower.ID + ")."));
return true;
}
internal static int RepairFollower(FollowerInfo follower, bool legacySozoRepair = false)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: 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_0056: Invalid comparison between Unknown and I4
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Invalid comparison between Unknown and I4
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Invalid comparison between Unknown and I4
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
if (follower == null || follower.Traits == null)
{
return 0;
}
int num = 0;
bool flag = false;
foreach (TraitType trait in RepairTraits)
{
if (follower.Traits.Contains(trait) && (legacySozoRepair || (int)trait == 57 || (int)trait == 67 || (int)trait == 78 || VisualStateTraits.Contains(trait)))
{
num += follower.Traits.RemoveAll((TraitType t) => t == trait);
flag |= VisualStateTraits.Contains(trait);
}
}
FollowerBrain brain = FollowerBrain.FindBrainByID(follower.ID);
RepairLiveFollower(follower, brain, flag, num > 0);
if (num > 0)
{
TwitchFollowers.SendFollowers();
if (TraitTreeConfig.AutoSaveAfterChange.Value)
{
try
{
SaveAndLoad.Save();
}
catch (Exception ex)
{
Log.LogWarning((object)("Trait Tree repair save failed: " + ex.Message));
}
}
Log.LogInfo((object)("Trait Tree repaired " + follower.Name + " (" + follower.ID + "), removed " + num + " incompatible state trait(s)."));
}
return num;
}
private static void RemoveExclusiveTraits(FollowerInfo follower, TraitType trait)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
foreach (KeyValuePair<TraitType, TraitType> pair in FollowerTrait.ExclusiveTraits)
{
if (pair.Key == trait)
{
follower.Traits.RemoveAll((TraitType t) => t == pair.Value);
}
else if (pair.Value == trait)
{
follower.Traits.RemoveAll((TraitType t) => t == pair.Key);
}
}
}
private static void RepairLiveFollower(FollowerInfo follower, FollowerBrain brain, bool rebuildOutfit, bool resetState)
{
Follower val = FollowerManager.FindFollowerByID(follower.ID);
if ((Object)(object)val != (Object)null)
{
if (rebuildOutfit)
{
try
{
val.UpdateOutfit();
}
catch (Exception ex)
{
Log.LogWarning((object)("Trait Tree outfit repair failed for " + follower.Name + ": " + ex.Message));
}
}
try
{
if ((Object)(object)val.Interaction_FollowerInteraction != (Object)null)
{
((Behaviour)val.Interaction_FollowerInteraction).enabled = true;
((Interaction)val.Interaction_FollowerInteraction).Interactable = !follower.Traits.Contains((TraitType)57);
}
}
catch (Exception ex2)
{
Log.LogWarning((object)("Trait Tree interaction repair failed for " + follower.Name + ": " + ex2.Message));
}
}
if (brain != null && resetState)
{
try
{
brain.CompleteCurrentTask();
brain.CheckChangeState();
}
catch (Exception ex3)
{
Log.LogWarning((object)("Trait Tree state repair failed for " + follower.Name + ": " + ex3.Message));
}
}
}
internal unsafe static string TraitTitle(TraitType trait)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
try
{
string localizedTitle = FollowerTrait.GetLocalizedTitle(trait);
return string.IsNullOrEmpty(localizedTitle) ? ((object)(*(TraitType*)(&trait))/*cast due to .constrained prefix*/).ToString() : localizedTitle;
}
catch
{
return ((object)(*(TraitType*)(&trait))/*cast due to .constrained prefix*/).ToString();
}
}
private static KeyCode ParseKey(string raw, KeyCode fallback)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
try
{
return (KeyCode)Enum.Parse(typeof(KeyCode), raw, ignoreCase: true);
}
catch
{
return fallback;
}
}
internal bool CanOpenTree()
{
if (TraitTreeConfig.Enabled.Value && TraitTreeConfig.EnableTreeInteraction.Value && (_menu == null || !_menu.IsOpen))
{
return (Object)(object)_followerSummaryMenu == (Object)null;
}
return false;
}
private bool CanOpenFollowerProfile(interaction_FollowerInteraction interaction)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Invalid comparison between Unknown and I4
if (TraitTreeConfig.Enabled.Value && TraitTreeConfig.EnableFollowerProfiles.Value && (int)PlayerFarming.Location == 1 && (Object)(object)interaction != (Object)null && ((Interaction)interaction).Interactable && !((Interaction)interaction).AutomaticallyInteract && (Object)(object)interaction.follower != (Object)null && interaction.follower.Brain != null && interaction.follower.Brain.Info != null && (_menu == null || !_menu.IsOpen))
{
return (Object)(object)_followerSummaryMenu == (Object)null;
}
return false;
}
}
public sealed class TraitTreeInteraction : Interaction
{
private FollowerTraitTreePlugin _plugin;
private Structure _structure;
internal void Configure(FollowerTraitTreePlugin plugin, Structure structure, float radius)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_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)
_plugin = plugin;
_structure = structure;
base.ActivateDistance = radius;
base.ActivatorOffset = new Vector3(0f, 0.35f, 0f);
base.Offset = new Vector3(0f, 3.5f, 0f);
base.OutlineTarget = (((Object)(object)structure != (Object)null) ? ((Component)structure).gameObject : ((Component)this).gameObject);
base.IgnoreTutorial = true;
base.SwitchMainPlayerOnInteract = true;
base.InputOnlyFromInteractingPlayer = true;
((Interaction)this).HasChanged = true;
}
public override void GetLabel()
{
if ((Object)(object)_plugin == (Object)null)
{
_plugin = FollowerTraitTreePlugin.Instance;
}
base.Interactable = (Object)(object)_plugin != (Object)null && _plugin.CanOpenTree() && (Object)(object)_structure != (Object)null;
((Interaction)this).Label = (base.Interactable ? "Manage Follower Traits" : "");
}
public override void OnInteract(StateMachine state)
{
if (base.Interactable && !((Object)(object)_plugin == (Object)null))
{
((Interaction)this).OnInteract(state);
_plugin.OpenMenu(((Object)(object)state != (Object)null) ? ((Component)state).GetComponent<PlayerFarming>() : PlayerFarming.Instance);
}
}
}
internal sealed class TraitTreeMenu
{
private enum ScreenState
{
Followers,
Traits
}
private readonly FollowerTraitTreePlugin _plugin;
private readonly KeyCode _repairKey;
private readonly List<FollowerInfo> _followers = new List<FollowerInfo>();
private readonly List<TraitType> _traits = new List<TraitType>();
private readonly List<TextMeshProUGUI> _followerRows = new List<TextMeshProUGUI>();
private readonly List<TextMeshProUGUI> _traitRows = new List<TextMeshProUGUI>();
private readonly List<Image> _traitIcons = new List<Image>();
private readonly List<IndoctrinationTraitItem> _nativeTraitItems = new List<IndoctrinationTraitItem>();
private readonly List<TraitType> _nativeTraitTypes = new List<TraitType>();
private readonly string[] _categories = new string[7] { "Current", "Positive", "Negative", "Sin", "Winter", "Special", "All" };
private GameObject _root;
private GameObject _promptBar;
private Transform _previewParent;
private FollowerInformationBox _followerPreview;
private int _previewFollowerId = -1;
private TextMeshProUGUI _title;
private TextMeshProUGUI _subtitle;
private TextMeshProUGUI _modeText;
private TextMeshProUGUI _categoryText;
private TextMeshProUGUI _detailText;
private TextMeshProUGUI _footerText;
private int _selectedFollower;
private int _selectedTrait;
private int _followerTop;
private int _traitTop;
private int _category;
private float _nextMove;
private ScreenState _state;
internal bool IsOpen
{
get
{
if ((Object)(object)_root != (Object)null)
{
return _root.activeSelf;
}
return false;
}
}
internal TraitTreeMenu(FollowerTraitTreePlugin plugin, KeyCode repairKey)
{
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
_plugin = plugin;
_repairKey = repairKey;
}
internal void Open(List<FollowerInfo> followers)
{
_followers.Clear();
foreach (FollowerInfo follower in followers)
{
if (follower != null)
{
_followers.Add(follower);
}
}
_followers.Sort((FollowerInfo a, FollowerInfo b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
_selectedFollower = Mathf.Clamp(_selectedFollower, 0, Mathf.Max(0, _followers.Count - 1));
_selectedTrait = 0;
_followerTop = 0;
_traitTop = 0;
_category = 0;
_state = ScreenState.Followers;
if ((Object)(object)_root == (Object)null)
{
Build();
}
_root.SetActive(true);
RefreshTraits();
Refresh();
}
internal void Close()
{
if ((Object)(object)_root != (Object)null)
{
GameObject root = _root;
_root = null;
ClearViewReferences();
Object.Destroy((Object)(object)root);
}
_plugin.OnMenuClosed();
}
internal void HandleInput()
{
if (RepairPressed())
{
if (_followers.Count > 0)
{
FollowerTraitTreePlugin.RepairFollower(_followers[_selectedFollower]);
RefreshTraits();
}
Refresh();
return;
}
if (CancelPressed())
{
if (_state == ScreenState.Traits)
{
_state = ScreenState.Followers;
Refresh();
}
else
{
Close();
}
return;
}
if (_state == ScreenState.Traits)
{
if (PageLeftPressed())
{
_category = (_category + _categories.Length - 1) % _categories.Length;
_selectedTrait = 0;
_traitTop = 0;
RefreshTraits();
Refresh();
return;
}
if (PageRightPressed())
{
_category = (_category + 1) % _categories.Length;
_selectedTrait = 0;
_traitTop = 0;
RefreshTraits();
Refresh();
return;
}
}
int move = GetMove();
if (move != 0)
{
MoveSelection(move);
}
if (AcceptPressed())
{
Accept();
}
}
private void Accept()
{
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
if (_followers.Count != 0)
{
if (_state == ScreenState.Followers)
{
_state = ScreenState.Traits;
_selectedTrait = 0;
_traitTop = 0;
RefreshTraits();
Refresh();
}
else if (_traits.Count != 0)
{
FollowerTraitTreePlugin.ApplyTrait(_followers[_selectedFollower], _traits[_selectedTrait]);
RefreshTraits();
Refresh();
}
}
}
private void MoveSelection(int delta)
{
if (_state == ScreenState.Followers)
{
_selectedFollower = Mathf.Clamp(_selectedFollower + delta, 0, Mathf.Max(0, _followers.Count - 1));
KeepVisible(ref _selectedFollower, ref _followerTop, _followerRows.Count, _followers.Count);
_selectedTrait = 0;
_traitTop = 0;
RefreshTraits();
}
else
{
_selectedTrait = Mathf.Clamp(_selectedTrait + delta, 0, Mathf.Max(0, _traits.Count - 1));
KeepVisible(ref _selectedTrait, ref _traitTop, _traitRows.Count, _traits.Count);
}
Refresh();
}
private static void KeepVisible(ref int selected, ref int top, int visibleRows, int count)
{
if (selected < top)
{
top = selected;
}
if (selected >= top + visibleRows)
{
top = selected - visibleRows + 1;
}
top = Mathf.Clamp(top, 0, Mathf.Max(0, count - visibleRows));
}
private void RefreshTraits()
{
_traits.Clear();
if (_followers.Count == 0)
{
return;
}
FollowerInfo follower = _followers[_selectedFollower];
IEnumerable<TraitType> source = from TraitType t in Enum.GetValues(typeof(TraitType))
where (int)t != 0 && (!FollowerTraitTreePlugin.IsUnsafeTrait(t) || FollowerTraitTreePlugin.CanRestoreUnsafeTrait(follower, t))
select t;
switch (_categories[_category])
{
case "Current":
source = ((follower.Traits == null) ? Enumerable.Empty<TraitType>() : follower.Traits.Where((TraitType t) => (int)t > 0).Distinct());
break;
case "Positive":
source = source.Where((TraitType t) => FollowerTrait.GoodTraits.Contains(t));
break;
case "Negative":
source = source.Where((TraitType t) => !FollowerTrait.GoodTraits.Contains(t) && !FollowerTrait.UniqueTraits.Contains(t) && !FollowerTrait.SinTraits.Contains(t));
break;
case "Sin":
source = source.Where((TraitType t) => FollowerTrait.SinTraits.Contains(t));
break;
case "Winter":
source = source.Where((TraitType t) => FollowerTrait.WinterSpecificTraits.Contains(t));
break;
case "Special":
source = source.Where((TraitType t) => FollowerTrait.UniqueTraits.Contains(t) || FollowerTrait.MajorDLCTraits.Contains(t));
break;
}
_traits.AddRange(source.Distinct().OrderBy(FollowerTraitTreePlugin.TraitTitle));
_selectedTrait = Mathf.Clamp(_selectedTrait, 0, Mathf.Max(0, _traits.Count - 1));
KeepVisible(ref _selectedTrait, ref _traitTop, _traitRows.Count, _traits.Count);
}
private void Refresh()
{
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)_root == (Object)null))
{
FollowerInfo val = ((_followers.Count > 0) ? _followers[_selectedFollower] : null);
((TMP_Text)_title).text = "Trait Tree";
((TMP_Text)_subtitle).text = ((val == null) ? "No followers found" : (val.Name + " | " + ((val.Traits != null) ? val.Traits.Count : 0) + " traits"));
((TMP_Text)_modeText).text = "Safe Trait Editing";
((Graphic)_modeText).color = new Color(0.62f, 1f, 0.72f, 1f);
((TMP_Text)_categoryText).text = ((_state == ScreenState.Traits) ? ("< " + _categories[_category] + " >") : "Followers");
RefreshFollowerRows();
RefreshFollowerPreview(val);
RefreshTraitRows(val);
RefreshDetail(val);
((TMP_Text)_footerText).text = (((Object)(object)_promptBar != (Object)null) ? "" : ((_state == ScreenState.Followers) ? "Accept: choose follower Back: close" : "Accept: add/remove Back: followers LB/RB: category"));
}
}
private void RefreshFollowerRows()
{
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < _followerRows.Count; i++)
{
int num = _followerTop + i;
TextMeshProUGUI val = _followerRows[i];
if (num >= _followers.Count)
{
((TMP_Text)val).text = "";
((Component)((TMP_Text)val).transform.parent).gameObject.SetActive(false);
continue;
}
((Component)((TMP_Text)val).transform.parent).gameObject.SetActive(true);
FollowerInfo val2 = _followers[num];
bool flag = _state == ScreenState.Followers && num == _selectedFollower;
((TMP_Text)val).text = (flag ? "> " : " ") + val2.Name + " [" + ((val2.Traits != null) ? val2.Traits.Count : 0) + "]";
((Graphic)val).color = (Color)(flag ? new Color(1f, 0.9f, 0.18f, 1f) : Color.white);
((Graphic)((Component)((TMP_Text)val).transform.parent).GetComponent<Image>()).color = (flag ? new Color(0.32f, 0.06f, 0.05f, 0.92f) : new Color(0.04f, 0.035f, 0.03f, 0.72f));
}
}
private void RefreshTraitRows(FollowerInfo follower)
{
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_0272: Unknown result type (might be due to invalid IL or missing references)
//IL_0277: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_027c: Unknown result type (might be due to invalid IL or missing references)
//IL_0289: Unknown result type (might be due to invalid IL or missing references)
//IL_0309: Unknown result type (might be due to invalid IL or missing references)
//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: 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_0200: Unknown result type (might be due to invalid IL or missing references)
//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_021b: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < _traitRows.Count; i++)
{
int num = _traitTop + i;
TextMeshProUGUI val = _traitRows[i];
if (num >= _traits.Count)
{
((TMP_Text)val).text = "";
((Component)((TMP_Text)val).transform.parent).gameObject.SetActive(false);
((Component)_traitIcons[i]).gameObject.SetActive(false);
if (i < _nativeTraitItems.Count && (Object)(object)_nativeTraitItems[i] != (Object)null)
{
((Component)_nativeTraitItems[i]).gameObject.SetActive(false);
}
continue;
}
((Component)((TMP_Text)val).transform.parent).gameObject.SetActive(true);
TraitType val2 = _traits[num];
bool flag = follower != null && follower.Traits != null && follower.Traits.Contains(val2);
bool flag2 = _state == ScreenState.Traits && num == _selectedTrait;
bool flag3 = FollowerTraitTreePlugin.IsUnsafeTrait(val2) && !FollowerTraitTreePlugin.CanRestoreUnsafeTrait(follower, val2);
((TMP_Text)val).text = (flag2 ? "> " : " ") + (flag ? "[x] " : "[ ] ") + FollowerTraitTreePlugin.TraitTitle(val2) + (flag3 ? " [state]" : "");
((Graphic)val).color = (Color)(flag2 ? new Color(1f, 0.9f, 0.18f, 1f) : (flag3 ? new Color(1f, 0.46f, 0.38f, 1f) : (flag ? new Color(0.62f, 1f, 0.72f, 1f) : Color.white)));
((Graphic)((Component)((TMP_Text)val).transform.parent).GetComponent<Image>()).color = (flag2 ? new Color(0.32f, 0.06f, 0.05f, 0.92f) : new Color(0.04f, 0.035f, 0.03f, 0.72f));
Image val3 = _traitIcons[i];
Sprite val4 = null;
try
{
val4 = FollowerTrait.GetIcon(val2);
}
catch
{
}
IndoctrinationTraitItem val5 = ((i < _nativeTraitItems.Count) ? _nativeTraitItems[i] : null);
if ((Object)(object)val5 != (Object)null)
{
((Component)val3).gameObject.SetActive(false);
((Component)val5).gameObject.SetActive(true);
if (_nativeTraitTypes[i] != val2)
{
val5.Configure(val2);
_nativeTraitTypes[i] = val2;
}
if (_categories[_category] == "Current")
{
ShowNativeTraitPolarity(val5, val2);
}
else
{
val5.SetState((Type)(flag ? 1 : 2));
}
val5.SetDeactivated(false);
}
else
{
val3.sprite = val4;
((Component)val3).gameObject.SetActive((Object)(object)val4 != (Object)null);
}
((Graphic)val3).color = (Color)(flag3 ? new Color(1f, 0.52f, 0.46f, 1f) : Color.white);
}
}
private static void ShowNativeTraitPolarity(IndoctrinationTraitItem item, TraitType trait)
{
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)item == (Object)null))
{
object? obj = AccessTools.Field(typeof(IndoctrinationTraitItem), "_arrow")?.GetValue(item);
Image val = (Image)((obj is Image) ? obj : null);
object? obj2 = AccessTools.Field(typeof(IndoctrinationTraitItem), "_positiveArrow")?.GetValue(item);
Sprite val2 = (Sprite)((obj2 is Sprite) ? obj2 : null);
object? obj3 = AccessTools.Field(typeof(IndoctrinationTraitItem), "_negativeArrow")?.GetValue(item);
Sprite val3 = (Sprite)((obj3 is Sprite) ? obj3 : null);
object? obj4 = AccessTools.Field(typeof(IndoctrinationTraitItem), "manipulationShuffle")?.GetValue(item);
GameObject val4 = (GameObject)((obj4 is GameObject) ? obj4 : null);
object? obj5 = AccessTools.Field(typeof(IndoctrinationTraitItem), "manipulationAdd")?.GetValue(item);
GameObject val5 = (GameObject)((obj5 is GameObject) ? obj5 : null);
object? obj6 = AccessTools.Field(typeof(IndoctrinationTraitItem), "manipulationMinus")?.GetValue(item);
object? obj7 = ((obj6 is GameObject) ? obj6 : null);
if (val4 != null)
{
val4.SetActive(false);
}
if (val5 != null)
{
val5.SetActive(false);
}
if (obj7 != null)
{
((GameObject)obj7).SetActive(false);
}
if ((Object)(object)val != (Object)null)
{
val.sprite = (FollowerTrait.IsPositiveTrait(trait) ? val2 : val3);
((Component)val).gameObject.SetActive(true);
}
}
}
private void RefreshFollowerPreview(FollowerInfo follower)
{
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_previewParent == (Object)null || follower == null || _previewFollowerId == follower.ID)
{
return;
}
if ((Object)(object)_followerPreview != (Object)null)
{
Object.Destroy((Object)(object)((Component)_followerPreview).gameObject);
_followerPreview = null;
}
try
{
UIManager instance = MonoSingleton<UIManager>.Instance;
UIFollowerSummaryMenuController val = (((Object)(object)instance != (Object)null) ? instance.FollowerSummaryMenuTemplate : null);
FollowerInformationBox val2 = (FollowerInformationBox)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
if ((Object)(object)val2 == (Object)null && (Object)(object)instance != (Object)null)
{
val2 = instance.FollowerInformationBoxTemplate;
}
if (!((Object)(object)val2 == (Object)null))
{
_followerPreview = Object.Instantiate<FollowerInformationBox>(val2, _previewParent, false);
((Object)((Component)_followerPreview).gameObject).name = "Native Follower Preview";
((Component)_followerPreview).gameObject.SetActive(true);
Transform transform = ((Component)_followerPreview).transform;
RectTransform val3 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if ((Object)(object)val3 != (Object)null)
{
ApplyAnchors(val3, AnchorFull());
((Transform)val3).localScale = Vector3.one;
}
((FollowerSelectItem)_followerPreview).Configure(follower);
((FollowerSelectItem)_followerPreview).OnFollowerHighlighted = null;
((FollowerSelectItem)_followerPreview).OnFollowerSelected = null;
if ((Object)(object)((FollowerSelectItem)_followerPreview).Button != (Object)null)
{
((UnityEventBase)((Button)((FollowerSelectItem)_followerPreview).Button).onClick).RemoveAllListeners();
((FollowerSelectItem)_followerPreview).Button.OnSelected = null;
((FollowerSelectItem)_followerPreview).Button.OnDeselected = null;
((FollowerSelectItem)_followerPreview).Button.OnConfirmDenied = null;
((Selectable)((FollowerSelectItem)_followerPreview).Button).interactable = false;
}
Graphic[] componentsInChildren = ((Component)_followerPreview).GetComponentsInChildren<Graphic>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].raycastTarget = false;
}
_previewFollowerId = follower.ID;
}
}
catch (Exception ex)
{
FollowerTraitTreePlugin.Log.LogWarning((object)("Could not create native follower preview: " + ex.Message));
}
}
private unsafe void RefreshDetail(FollowerInfo follower)
{
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
if (follower == null)
{
((TMP_Text)_detailText).text = "";
return;
}
if (_state == ScreenState.Followers || _traits.Count == 0)
{
string text = ((follower.Traits == null || follower.Traits.Count == 0) ? "No current traits." : string.Join(", ", follower.Traits.Distinct().Select(FollowerTraitTreePlugin.TraitTitle).Take(12)
.ToArray()));
((TMP_Text)_detailText).text = text;
return;
}
TraitType val = _traits[_selectedTrait];
bool flag = follower.Traits != null && follower.Traits.Contains(val);
string text2;
try
{
text2 = FollowerTrait.GetLocalizedDescription(val, FollowerBrain.FindBrainByID(follower.ID));
}
catch
{
text2 = ((object)(*(TraitType*)(&val))/*cast due to .constrained prefix*/).ToString();
}
if (FollowerTraitTreePlugin.IsUnsafeTrait(val) && !FollowerTraitTreePlugin.CanRestoreUnsafeTrait(follower, val))
{
((TMP_Text)_detailText).text = "State or quest trait.\n\nThis entry can be removed here, but cannot be added. These traits can disable normal follower interactions when assigned outside their vanilla event.\n\n" + text2;
}
else
{
((TMP_Text)_detailText).text = (flag ? "Currently applied. Accept removes it.\n\n" : "Not applied. Accept adds it.\n\n") + text2;
}
}
private void Build()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
//IL_020c: Unknown result type (might be due to invalid IL or missing references)
//IL_024f: Unknown result type (might be due to invalid IL or missing references)
//IL_0268: Unknown result type (might be due to invalid IL or missing references)
//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0313: Unknown result type (might be due to invalid IL or missing references)
//IL_034a: Unknown result type (might be due to invalid IL or missing references)
//IL_0363: Unknown result type (might be due to invalid IL or missing references)
//IL_0396: Unknown result type (might be due to invalid IL or missing references)
//IL_03af: Unknown result type (might be due to invalid IL or missing references)
//IL_03db: Unknown result type (might be due to invalid IL or missing references)
//IL_03e2: Expected O, but got Unknown
//IL_0407: Unknown result type (might be due to invalid IL or missing references)
//IL_041c: Unknown result type (might be due to invalid IL or missing references)
//IL_0427: Unknown result type (might be due to invalid IL or missing references)
//IL_0431: Unknown result type (might be due to invalid IL or missing references)
//IL_0478: Unknown result type (might be due to invalid IL or missing references)
//IL_04bd: Unknown result type (might be due to invalid IL or missing references)
//IL_0543: Unknown result type (might be due to invalid IL or missing references)
//IL_055c: Unknown result type (might be due to invalid IL or missing references)
//IL_0580: Unknown result type (might be due to invalid IL or missing references)
//IL_0599: Unknown result type (might be due to invalid IL or missing references)
//IL_05f4: Unknown result type (might be due to invalid IL or missing references)
//IL_060d: Unknown result type (might be due to invalid IL or missing references)
ClearViewReferences();
TMP_FontAsset font = FindVanillaFont();
_root = new GameObject("Follower Trait Tree Menu");
Object.DontDestroyOnLoad((Object)(object)_root);
Canvas obj = _root.AddComponent<Canvas>();
obj.renderMode = (RenderMode)0;
obj.sortingOrder = 20000;
CanvasScaler obj2 = _root.AddComponent<CanvasScaler>();
obj2.uiScaleMode = (ScaleMode)1;
obj2.referenceResolution = new Vector2(1920f, 1080f);
_root.AddComponent<GraphicRaycaster>();
AddImage("Shade", _root.transform, new Color(0f, 0f, 0f, 0.52f), AnchorFull()).transform.SetAsFirstSibling();
GameObject val = AddImage("Panel", _root.transform, new Color(0.025f, 0.02f, 0.018f, 0.96f), RectFor(0.08f, 0.055f, 0.84f, 0.89f));
Sprite val2 = FindVanillaPanelSprite();
if ((Object)(object)val2 != (Object)null)
{
Image component = val.GetComponent<Image>();
component.sprite = val2;
component.type = (Type)1;
}
AddImage("Top Rule", val.transform, new Color(0.68f, 0.03f, 0.02f, 1f), RectFor(0f, 0.94f, 1f, 0.012f));
_title = AddText("Title", val.transform, font, 42, (FontStyles)1, new Color(1f, 0.9f, 0.18f, 1f), RectFor(0.03f, 0.9f, 0.35f, 0.07f));
_subtitle = AddText("Subtitle", val.transform, font, 20, (FontStyles)0, Color.white, RectFor(0.03f, 0.855f, 0.62f, 0.04f));
_modeText = AddText("Mode", val.transform, font, 21, (FontStyles)1, Color.white, RectFor(0.72f, 0.9f, 0.25f, 0.055f));
((TMP_Text)_modeText).alignment = (TextAlignmentOptions)4100;
_categoryText = AddText("Category", val.transform, font, 25, (FontStyles)1, new Color(1f, 0.9f, 0.18f, 1f), RectFor(0.36f, 0.57f, 0.34f, 0.055f));
((TMP_Text)_categoryText).alignment = (TextAlignmentOptions)514;
((TMP_Text)AddText("Follower Label", val.transform, font, 18, (FontStyles)1, new Color(0.8f, 0.75f, 0.68f, 1f), RectFor(0.03f, 0.81f, 0.25f, 0.04f))).text = "Followers";
((TMP_Text)AddText("Preview Label", val.transform, font, 18, (FontStyles)1, new Color(0.8f, 0.75f, 0.68f, 1f), RectFor(0.32f, 0.81f, 0.4f, 0.04f))).text = "Follower Profile";
((TMP_Text)AddText("Trait Label", val.transform, font, 18, (FontStyles)1, new Color(0.8f, 0.75f, 0.68f, 1f), RectFor(0.34f, 0.525f, 0.36f, 0.035f))).text = "Traits";
GameObject val3 = AddImage("Follower Preview Frame", val.transform, new Color(0.045f, 0.038f, 0.032f, 0.92f), RectFor(0.3f, 0.625f, 0.44f, 0.18f));
if ((Object)(object)val2 != (Object)null)
{
Image component2 = val3.GetComponent<Image>();
component2.sprite = val2;
component2.type = (Type)1;
}
GameObject val4 = new GameObject("Follower Preview Content");
val4.transform.SetParent(val3.transform, false);
RectTransform obj3 = val4.AddComponent<RectTransform>();
obj3.anchorMin = new Vector2(0.02f, 0.04f);
obj3.anchorMax = new Vector2(0.98f, 0.96f);
obj3.offsetMin = Vector2.zero;
obj3.offsetMax = Vector2.zero;
_previewParent = val4.transform;
for (int i = 0; i < 12; i++)
{
_followerRows.Add(AddRow(val.transform, font, RectFor(0.03f, 0.76f - (float)i * 0.053f, 0.25f, 0.045f)));
}
for (int j = 0; j < 12; j++)
{
Image icon;
TextMeshProUGUI val5 = AddTraitRow(val.transform, font, RectFor(0.33f, 0.48f - (float)j * 0.035f, 0.38f, 0.031f), out icon);
_traitRows.Add(val5);
_traitIcons.Add(icon);
IndoctrinationTraitItem item = TryAddNativeTraitItem(((TMP_Text)val5).transform.parent);
_nativeTraitItems.Add(item);
_nativeTraitTypes.Add((TraitType)0);
}
((TMP_Text)AddText("Detail Label", val.transform, font, 18, (FontStyles)1, new Color(0.8f, 0.75f, 0.68f, 1f), RectFor(0.77f, 0.81f, 0.2f, 0.04f))).text = "Trait Details";
_detailText = AddText("Details", val.transform, font, 18, (FontStyles)0, Color.white, RectFor(0.77f, 0.22f, 0.2f, 0.58f));
((TMP_Text)_detailText).alignment = (TextAlignmentOptions)257;
((TMP_Text)_detailText).enableWordWrapping = true;
((TMP_Text)_detailText).overflowMode = (TextOverflowModes)1;
_footerText = AddText("Footer", val.transform, font, 18, (FontStyles)1, new Color(0.9f, 0.86f, 0.78f, 1f), RectFor(0.035f, 0.025f, 0.93f, 0.065f));
((TMP_Text)_footerText).alignment = (TextAlignmentOptions)514;
_promptBar = TryBuildVanillaPromptBar(val.transform, font);
}
private void ClearViewReferences()
{
_followerRows.Clear();
_traitRows.Clear();
_traitIcons.Clear();
_nativeTraitItems.Clear();
_nativeTraitTypes.Clear();
_promptBar = null;
_previewParent = null;
_followerPreview = null;
_previewFollowerId = -1;
_title = null;
_subtitle = null;
_modeText = null;
_categoryText = null;
_detailText = null;
_footerText = null;
}
private static TextMeshProUGUI AddRow(Transform parent, TMP_FontAsset font, Vector4 anchors)
{
//IL_001a: 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_0035: Unknown result type (might be due to invalid IL or missing references)
GameObject val = AddImage("Row", parent, new Color(0.04f, 0.035f, 0.03f, 0.72f), anchors);
TextMeshProUGUI obj = AddInsetText("Text", val.transform, font, 18, (FontStyles)1, Color.white, 10f, 2f, 10f, 2f);
((TMP_Text)obj).alignment = (TextAlignmentOptions)4097;
((TMP_Text)obj).overflowMode = (TextOverflowModes)0;
return obj;
}
internal static TextMeshProUGUI AddTraitRow(Transform parent, TMP_FontAsset font, Vector4 anchors, out Image icon)
{
//IL_001a: 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_0031: 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_007c: Unknown result type (might be due to invalid IL or missing references)
GameObject val = AddImage("Trait Row", parent, new Color(0.04f, 0.035f, 0.03f, 0.72f), anchors);
GameObject val2 = AddImage("Trait Icon", val.transform, Color.white, RectFor(0.018f, 0.1f, 0.12f, 0.8f));
icon = val2.GetComponent<Image>();
icon.preserveAspect = true;
((Graphic)icon).raycastTarget = false;
TextMeshProUGUI obj = AddInsetText("Text", val.transform, font, 16, (FontStyles)1, Color.white, 58f, 1f, 8f, 1f);
((TMP_Text)obj).alignment = (TextAlignmentOptions)4097;
((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
return obj;
}
private static IndoctrinationTraitItem TryAddNativeTraitItem(Transform parent)
{
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: 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)
try
{
UIManager instance = MonoSingleton<UIManager>.Instance;
UIFollowerSummaryMenuController val = (((Object)(object)instance != (Object)null) ? instance.FollowerSummaryMenuTemplate : null);
IndoctrinationTraitItem val2 = (IndoctrinationTraitItem)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
if ((Object)(object)val2 == (Object)null)
{
return null;
}
IndoctrinationTraitItem val3 = Object.Instantiate<IndoctrinationTraitItem>(val2, parent, false);
((Object)((Component)val3).gameObject).name = "Native Trait Item";
((Component)val3).gameObject.SetActive(true);
Transform transform = ((Component)val3).transform;
RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if ((Object)(object)val4 != (Object)null)
{
val4.anchorMin = new Vector2(0.005f, 0.02f);
val4.anchorMax = new Vector2(0.14f, 0.98f);
val4.offsetMin = Vector2.zero;
val4.offsetMax = Vector2.zero;
((Transform)val4).localScale = Vector3.one;
}
if ((Object)(object)val3.Button != (Object)null)
{
((Selectable)val3.Button).interactable = false;
}
StripNativeTraitBacking(val3);
Graphic[] componentsInChildren = ((Component)val3).GetComponentsInChildren<Graphic>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].raycastTarget = false;
}
return val3;
}
catch (Exception ex)
{
FollowerTraitTreePlugin.Log.LogWarning((object)("Could not create native trait item: " + ex.Message));
return null;
}
}
private static void StripNativeTraitBacking(IndoctrinationTraitItem item)
{
object? obj = AccessTools.Field(typeof(IndoctrinationTraitItem), "_icon")?.GetValue(item);
Image val = (Image)((obj is Image) ? obj : null);
object? obj2 = AccessTools.Field(typeof(IndoctrinationTraitItem), "_arrow")?.GetValue(item);
Image val2 = (Image)((obj2 is Image) ? obj2 : null);
object? obj3 = AccessTools.Field(typeof(IndoctrinationTraitItem), "manipulationShuffle")?.GetValue(item);
GameObject val3 = (GameObject)((obj3 is GameObject) ? obj3 : null);
object? obj4 = AccessTools.Field(typeof(IndoctrinationTraitItem), "manipulationAdd")?.GetValue(item);
GameObject val4 = (GameObject)((obj4 is GameObject) ? obj4 : null);
object? obj5 = AccessTools.Field(typeof(IndoctrinationTraitItem), "manipulationMinus")?.GetValue(item);
GameObject val5 = (GameObject)((obj5 is GameObject) ? obj5 : null);
Image[] componentsInChildren = ((Component)item).GetComponentsInChildren<Image>(true);
foreach (Image val6 in componentsInChildren)
{
if (!((Object)(object)val6 == (Object)(object)val) && !((Object)(object)val6 == (Object)(object)val2) && (!((Object)(object)val3 != (Object)null) || !((Component)val6).transform.IsChildOf(val3.transform)) && (!((Object)(object)val4 != (Object)null) || !((Component)val6).transform.IsChildOf(val4.transform)) && (!((Object)(object)val5 != (Object)null) || !((Component)val6).transform.IsChildOf(val5.transform)))
{
((Behaviour)val6).enabled = false;
}
}
}
internal static TextMeshProUGUI AddText(string name, Transform parent, TMP_FontAsset font, int size, FontStyles style, Color color, Vector4 anchors)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: 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_003f: 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)
GameObject val = new GameObject(name);
val.transform.SetParent(parent, false);
ApplyAnchors(val.AddComponent<RectTransform>(), anchors);
TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
if ((Object)(object)font != (Object)null)
{
((TMP_Text)val2).font = font;
}
((TMP_Text)val2).fontSize = size;
((TMP_Text)val2).fontStyle = style;
((Graphic)val2).color = color;
((TMP_Text)val2).alignment = (TextAlignmentOptions)4097;
((Graphic)val2).raycastTarget = false;
return val2;
}
internal static TextMeshProUGUI AddInsetText(string name, Transform parent, TMP_FontAsset font, int size, FontStyles style, Color color, float left, float bottom, float right, float top)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: 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)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
TextMeshProUGUI obj = AddText(name, parent, font, size, style, color, AnchorFull());
RectTransform rectTransform = ((TMP_Text)obj).rectTransform;
rectTransform.offsetMin = new Vector2(left, bottom);
rectTransform.offsetMax = new Vector2(0f - right, 0f - top);
return obj;
}
internal static GameObject AddImage(string name, Transform parent, Color color, Vector4 anchors)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: 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_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
GameObject val = new GameObject(name);
val.transform.SetParent(parent, false);
ApplyAnchors(val.AddComponent<RectTransform>(), anchors);
((Graphic)val.AddComponent<Image>()).color = color;
return val;
}
internal static Vector4 AnchorFull()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
return new Vector4(0f, 0f, 1f, 1f);
}
internal static TMP_FontAsset FindVanillaFont()
{
try
{
UIManager instance = MonoSingleton<UIManager>.Instance;
if ((Object)(object)instance != (Object)null && (Object)(object)instance.FollowerSelectMenuTemplate != (Object)null)
{
TMP_Text componentInChildren = ((Component)instance.FollowerSelectMenuTemplate).GetComponentInChildren<TMP_Text>(true);
if ((Object)(object)componentInChildren != (Object)null)
{
return componentInChildren.font;
}
}
}
catch
{
}
return TMP_Settings.defaultFontAsset;
}
internal static Sprite FindVanillaPanelSprite()
{
try
{
UIManager instance = MonoSingleton<UIManager>.Instance;
if ((Object)(object)instance == (Object)null || (Object)(object)instance.ConfirmationWindowTemplate == (Object)null)
{
return null;
}
Image val = ((IEnumerable<Image>)((Component)instance.ConfirmationWindowTemplate).GetComponentsInChildren<Image>(true)).FirstOrDefault((Func<Image, bool>)((Image image) => (Object)(object)image != (Object)null && (Object)(object)image.sprite != (Object)null && (((Object)image).name.IndexOf("background", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)image).name.IndexOf("backing", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)image).name.IndexOf("panel", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)image).name.IndexOf("window", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)image).name.IndexOf("brush", StringComparison.OrdinalIgnoreCase) >= 0)));
if ((Object)(object)val != (Object)null)
{
return val.sprite;
}
return null;
}
catch
{
return null;
}
}
internal static Vector4 RectFor(float x, float y, float width, float height)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
return new Vector4(x, y, x + width, y + height);
}
internal static void ApplyAnchors(RectTransform rect, Vector4 anchors)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: 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_003a: Unknown result type (might be due to invalid IL or missing references)
rect.anchorMin = new Vector2(anchors.x, anchors.y);
rect.anchorMax = new Vector2(anchors.z, anchors.w);
rect.offsetMin = Vector2.zero;
rect.offsetMax = Vector2.zero;
}
private static GameObject TryBuildVanillaPromptBar(Transform parent, TMP_FontAsset font)
{
//IL_004c: 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)
try
{
UIManager instance = MonoSingleton<UIManager>.Instance;
if ((Object)(object)instance == (Object)null || (Object)(object)instance.FollowerSelectMenuTemplate == (Object)null)
{
return null;
}
MMControlPrompt val = ((Component)instance.FollowerSelectMenuTemplate).GetComponentsInChildren<MMControlPrompt>(true).FirstOrDefault();
if ((Object)(object)val == (Object)null)
{
return null;
}
GameObject val2 = AddImage("Vanilla Control Prompts", parent, Color.clear, RectFor(0.035f, 0.018f, 0.93f, 0.075f));
((Graphic)val2.GetComponent<Image>()).raycastTarget = false;
HorizontalLayoutGroup obj = val2.AddComponent<HorizontalLayoutGroup>();
((HorizontalOrVerticalLayoutGroup)obj).spacing = 18f;
((LayoutGroup)obj).childAlignment = (TextAnchor)4;
((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
AddPrompt(val, val2.transform, font, 38, "Choose / Toggle", 220f);
AddPrompt(val, val2.transform, font, 39, "Back", 135f);
AddPrompt(val, val2.transform, font, 43, "Previous", 175f);
AddPrompt(val, val2.transform, font, 44, "Next", 145f);
return val2;
}
catch (Exception ex)
{
FollowerTraitTreePlugin.Log.LogWarning((object)("Trait Tree could not create vanilla control prompts: " + ex.Message));
return null;
}
}
internal static GameObject AddPrompt(MMControlPrompt prototype, Transform parent, TMP_FontAsset font, int action, string label, float width, int category = 1)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Expected O, but got Unknown
//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("Trait Tree Prompt Item " + action);
val.transform.SetParent(parent, false);
val.AddComponent<RectTransform>();
LayoutElement obj = val.AddComponent<LayoutElement>();
obj.preferredWidth = width;
obj.preferredHeight = 62f;
HorizontalLayoutGroup obj2 = val.AddComponent<HorizontalLayoutGroup>();
((HorizontalOrVerticalLayoutGroup)obj2).spacing = 8f;
((LayoutGroup)obj2).childAlignment = (TextAnchor)3;
((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = false;
((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
MMControlPrompt val2 = Object.Instantiate<MMControlPrompt>(prototype, val.transform, false);
((Object)((Component)val2).gameObject).name = "Trait Tree Prompt " + action;
((Component)val2).gameObject.SetActive(false);
Button[] componentsInChildren = ((Component)val2).GetComponentsInChildren<Button>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
((UnityEventBase)componentsInChildren[i].onClick).RemoveAllListeners();
}
LayoutElement val3 = ((Component)val2).GetComponent<LayoutElement>();
if ((Object)(object)val3 == (Object)null)
{
val3 = ((Component)val2).gameObject.AddComponent<LayoutElement>();
}
val3.preferredWidth = 58f;
val3.preferredHeight = 62f;
val3.flexibleWidth = 0f;
val2.Category = category;
val2.Action = action;
val2.playerFarming = PlayerFarming.Instance;
object? obj3 = AccessTools.Field(typeof(MMControlPrompt), "_actionText")?.GetValue(val2);
TMP_Text val4 = (TMP_Text)((obj3 is TMP_Text) ? obj3 : null);
if ((Object)(object)val4 != (Object)null && val4.transform.IsChildOf(((Component)val2).transform))
{
((Component)val4).gameObject.SetActive(false);
}
TextMeshProUGUI obj4 = AddText("Prompt Label", val.transform, font, 18, (FontStyles)1, new Color(0.9f, 0.86f, 0.78f, 1f), AnchorFull());
((TMP_Text)obj4).text = label;
((TMP_Text)obj4).alignment = (TextAlignmentOptions)4097;
((TMP_Text)obj4).enableWordWrapping = false;
((TMP_Text)obj4).overflowMode = (TextOverflowModes)1;
LayoutElement obj5 = ((Component)obj4).gameObject.AddComponent<LayoutElement>();
obj5.preferredWidth = Mathf.Max(60f, width - 66f);
obj5.preferredHeight = 62f;
obj5.flexibleWidth = 0f;
((Component)val2).gameObject.SetActive(true);
val2.ForceUpdate();
return val;
}
private int GetMove()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
float num = 0f;
try
{
num = InputManager.UI.GetVerticalAxis((PlayerFarming)null);
}
catch
{
}
if (Input.mouseScrollDelta.y > 0.1f)
{
return -1;
}
if (Input.mouseScrollDelta.y < -0.1f)
{
return 1;
}
if (Input.GetKeyDown((KeyCode)273) || Input.GetKeyDown((KeyCode)119))
{
return -1;
}
if (Input.GetKeyDown((KeyCode)274) || Input.GetKeyDown((KeyCode)115))
{
return 1;
}
if (Mathf.Abs(num) < 0.45f)
{
_nextMove = 0f;
return 0;
}
if (Time.unscaledTime < _nextMove)
{
return 0;
}
_nextMove = Time.unscaledTime + 0.18f;
if (!(num > 0f))
{
return 1;
}
return -1;
}
private bool RepairPressed()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return Input.GetKeyDown(_repairKey);
}
private static bool AcceptPressed()
{
try
{
if (InputManager.UI.GetAcceptButtonDown((PlayerFarming)null))
{
return true;
}
}
catch
{
}
if (!Input.GetKeyDown((KeyCode)13))
{
return Input.GetKeyDown((KeyCode)32);
}
return true;
}
private static bool CancelPressed()
{
try
{
if (InputManager.UI.GetCancelButtonDown((PlayerFarming)null))
{
return true;
}
}
catch
{
}
if (!Input.GetKeyDown((KeyCode)27))
{
return Input.GetKeyDown((KeyCode)8);
}
return true;
}
private static bool PageLeftPressed()
{
try
{
if (InputManager.UI.GetPageNavigateLeftDown((PlayerFarming)null))
{
return true;
}
}
catch
{
}
if (!Input.GetKeyDown((KeyCode)276))
{
return Input.GetKeyDown((KeyCode)113);
}
return true;
}
private static bool PageRightPressed()
{
try
{
if (InputManager.UI.GetPageNavigateRightDown((PlayerFarming)null))
{
return true;
}
}
catch
{
}
if (!Input.GetKeyDown((KeyCode)275))
{
return Input.GetKeyDown((KeyCode)101);
}
return true;
}
}
internal sealed class FollowerProfilePanel
{
private readonly FollowerTraitTreePlugin _plugin;
private readonly List<TextMeshProUGUI> _traitRows = new List<TextMeshProUGUI>();
private readonly List<Image> _traitIcons = new List<Image>();
private readonly List<TraitType> _traits = new List<TraitType>();
private GameObject _root;
private FollowerInfo _follower;
private TextMeshProUGUI _nameText;
private TextMeshProUGUI _metaText;
private TextMeshProUGUI _statsText;
private TextMeshProUGUI _statusText;
private TextMeshProUGUI _traitHeader;
private int _traitTop;
private float _nextMove;
private float _ignoreInputUntil;
internal bool IsOpen
{
get
{
if ((Object)(object)_root != (Object)null)
{
return _root.activeSelf;
}
return false;
}
}
internal FollowerProfilePanel(FollowerTraitTreePlugin plugin)
{
_plugin = plugin;
}
internal void Open(FollowerInfo follower)
{
_follower = follower;
_traitTop = 0;
if ((Object)(object)_root == (Object)null)
{
Build();
}
_root.SetActive(true);
_ignoreInputUntil = Time.unscaledTime + 0.15f;
Refresh();
}
internal void Close()
{
if ((Object)(object)_root != (Object)null)
{
GameObject root = _root;
_root = null;
_traitRows.Clear();
_traitIcons.Clear();
Object.Destroy((Object)(object)root);
}
_follower = null;
_plugin.OnMenuClosed();
}
internal void HandleInput()
{
if (Time.unscaledTime < _ignoreInputUntil)
{
return;
}
bool flag = false;
try
{
flag = InputManager.Gameplay.GetInteract2ButtonDown((PlayerFarming)null);
}
catch
{
}
if (CancelPressed() || Input.GetMouseButtonDown(1) || flag)
{
Close();
return;
}
int move = GetMove();
if (move != 0)
{
_traitTop = Mathf.Clamp(_traitTop + move, 0, Mathf.Max(0, _traits.Count - _traitRows.Count));
RefreshRows();
}
}
private void Refresh()
{
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_root == (Object)null || _follower == null)
{
return;
}
FollowerInfo infoByID = FollowerInfo.GetInfoByID(_follower.ID, true);
if (infoByID != null)
{
_follower = infoByID;
}
_traits.Clear();
if (_follower.Traits != null)
{
_traits.AddRange(_follower.Traits.Where((TraitType trait) => (int)trait > 0).Distinct().OrderBy(FollowerTraitTreePlugin.TraitTitle));
}
((TMP_Text)_nameText).text = _follower.Name;
((TMP_Text)_metaText).text = "Level " + _follower.XPLevel + " | Age " + _follower.Age + " | Joined Day " + _follower.DayJoined;
((TMP_Text)_statsText).text = "Faith " + Mathf.RoundToInt(_follower.Faith) + " Happiness " + Mathf.RoundToInt(_follower.Happiness) + "\nAdoration " + Mathf.RoundToInt(_follower.Adoration) + "/100 Pleasure " + _follower.Pleasure + "/65";
List<string> list = new List<string>();
if (_follower.IsDisciple)
{
list.Add("Disciple");
}
if (_follower.MarriedToLeader)
{
list.Add("Married");
}
if (_follower.OldAge)
{
list.Add("Elder");
}
if ((int)_follower.CursedState != 0)
{
list.Add(((object)Unsafe.As<Thought, Thought>(ref _follower.CursedState)/*cast due to .constrained prefix*/).ToString());
}
((TMP_Text)_statusText).text = ((list.Count == 0) ? "Cult Follower" : string.Join(" | ", list.ToArray()));
RefreshRows();
}
private void RefreshRows()
{
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: 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_0152: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0184: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_traitHeader != (Object)null)
{
int num = ((_traits.Count != 0) ? (_traitTop + 1) : 0);
int num2 = Mathf.Min(_traits.Count, _traitTop + _traitRows.Count);
((TMP_Text)_traitHeader).text = ((_traits.Count == 0) ? "Traits (0)" : ("Traits (" + _traits.Count + ") " + num + "-" + num2));
}
for (int i = 0; i < _traitRows.Count; i++)
{
int num3 = _traitTop + i;
TextMeshProUGUI val = _traitRows[i];
Image val2 = _traitIcons[i];
if (num3 >= _traits.Count)
{
((TMP_Text)val).text = "";
((Component)((TMP_Text)val).transform.parent).gameObject.SetActive(false);
((Component)val2).gameObject.SetActive(false);
continue;
}
((Component)((TMP_Text)val).transform.parent).gameObject.SetActive(true);
TraitType val3 = _traits[num3];
((TMP_Text)val).text = FollowerTraitTreePlugin.TraitTitle(val3);
((Graphic)val).color = (Color)(FollowerTraitTreePlugin.IsUnsafeTrait(val3) ? new Color(1f, 0.62f, 0.48f, 1f) : Color.white);
Sprite val4 = null;
try
{
val4 = FollowerTrait.GetIcon(val3);
}
catch
{
}
val2.sprite = val4;
((Graphic)val2).color = Color.white;
((Component)val2).gameObject.SetActive((Object)(object)val4 != (Object)null);
}
}
private void Build()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: 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_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_0190: Unknown result type (might be due to invalid IL or missing references)
//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Unknown result type (might be due to invalid IL or missing references)
//IL_022d: Unknown result type (might be due to invalid IL or missing references)
//IL_0270: Unknown result type (might be due to invalid IL or missing references)
//IL_0289: Unknown result type (might be due to invalid IL or missing references)
//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
//IL_030c: Unknown result type (might be due to invalid IL or missing references)
TMP_FontAsset font = TraitTreeMenu.FindVanillaFont();
_root = new GameObject("Follower Profile Panel");
Object.DontDestroyOnLoad((Object)(object)_root);
Canvas obj = _root.AddComponent<Canvas>();
obj.renderMode = (RenderMode)0;
obj.sortingOrder = 20001;
CanvasScaler obj2 = _root.AddComponent<CanvasScaler>();
obj2.uiScaleMode = (ScaleMode)1;
obj2.referenceResolution = new Vector2(1920f, 1080f);
_root.AddComponent<GraphicRaycaster>();
GameObject val = TraitTreeMenu.AddImage("Profile Panel", _root.transform, new Color(0.025f, 0.02f, 0.018f, 0.97f), TraitTreeMenu.RectFor(0.665f, 0.07f, 0.31f, 0.86f));
Sprite val2 = TraitTreeMenu.FindVanillaPanelSprite();
if ((Object)(object)val2 != (Object)null)
{
Image component = val.GetComponent<Image>();
component.sprite = val2;
component.type = (Type)1;
}
TraitTreeMenu.AddImage("Top Rule", val.transform, new Color(0.68f, 0.03f, 0.02f, 1f), TraitTreeMenu.RectFor(0f, 0.955f, 1f, 0.012f));
((TMP_Text)TraitTreeMenu.AddText("Profile Title", val.transform, font, 20, (FontStyles)1, new Color(0.8f, 0.75f, 0.68f, 1f), TraitTreeMenu.RectFor(0.055f, 0.905f, 0.89f, 0.045f))).text = "Follower Profile";
_nameText = TraitTreeMenu.AddText("Follower Name", val.transform, font, 36, (FontStyles)1, new Color(1f, 0.9f, 0.18f, 1f), TraitTreeMenu.RectFor(0.055f, 0.845f, 0.89f, 0.065f));
_metaText = TraitTreeMenu.AddText("Follower Meta", val.transform, font, 17, (FontStyles)0, Color.white, TraitTreeMenu.RectFor(0.055f, 0.795f, 0.89f, 0.045f));
_statsText = TraitTreeMenu.AddText("Follower Stats", val.transform, font, 18, (FontStyles)1, new Color(0.9f, 0.86f, 0.78f, 1f), TraitTreeMenu.RectFor(0.055f, 0.705f, 0.89f, 0.085f));
((TMP_Text)_statsText).alignment = (TextAlignmentOptions)257;
_statusText = TraitTreeMenu.AddText("Follower Status", val.transform, font, 17, (FontStyles)1, new Color(0.62f, 1f, 0.72f, 1f), TraitTreeMenu.RectFor(0.055f, 0.655f, 0.89f, 0.045f));
_traitHeader = TraitTreeMenu.AddText("Trait Header", val.transform, font, 19, (FontStyles)1, new Color(0.8f, 0.75f, 0.68f, 1f), TraitTreeMenu.RectFor(0.055f, 0.605f, 0.89f, 0.04f));
for (int i = 0; i < 10; i++)
{
Image icon;
TextMeshProUGUI item = TraitTreeMenu.AddTraitRow(val.transform, font, TraitTreeMenu.RectFor(0.055f, 0.552f - (float)i * 0.051f, 0.89f, 0.043f), out icon);
_traitRows.Add(item);
_traitIcons.Add(icon);
}
TryBuildClosePrompt(val.transform, font);
}
private static void TryBuildClosePrompt(Transform parent, TMP_FontAsset font)
{
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
try
{
UIManager instance = MonoSingleton<UIManager>.Instance;
MMControlPrompt val = (((Object)(object)instance != (Object)null && (Object)(object)instance.FollowerSelectMenuTemplate != (Object)null) ? ((Component)instance.FollowerSelectMenuTemplate).GetComponentsInChildren<MMControlPrompt>(true).FirstOrDefault() : null);
if (!((Object)(object)val == (Object)null))
{
GameObject val2 = TraitTreeMenu.AddImage("Profile Prompt", parent, Color.clear, TraitTreeMenu.RectFor(0.055f, 0.018f, 0.89f, 0.07f));
((Graphic)val2.GetComponent<Image>()).raycastTarget = false;
HorizontalLayoutGroup obj = val2.AddComponent<HorizontalLayoutGroup>();
((LayoutGroup)obj).childAlignment = (TextAnchor)5;
((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
TraitTreeMenu.AddPrompt(val, val2.transform, font, 68, "Close Profile", 210f, 0);
}
}
catch (Exception ex)
{
FollowerTraitTreePlugin.Log.LogWarning((object)("Trait Tree could not create the profile close prompt: " + ex.Message));
}
}
private int GetMove()
{
//IL_0000: 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)
if (Input.mouseScrollDelta.y > 0.1f)
{
return -1;
}
if (Input.mouseScrollDelta.y < -0.1f)
{
return 1;
}
if (Input.GetKeyDown((KeyCode)273) || Input.GetKeyDown((KeyCode)119))
{
return -1;
}
if (Input.GetKeyDown((KeyCode)274) || Input.GetKeyDown((KeyCode)115))
{
return 1;
}
float num = 0f;
try
{
num = InputManager.UI.GetVerticalAxis((PlayerFarming)null);
}
catch
{
}
if (Mathf.Abs(num) < 0.45f)
{
_nextMove = 0f;
return 0;
}
if (Time.unscaledTime < _nextMove)
{
return 0;
}
_nextMove = Time.unscaledTime + 0.18f;
if (!(num > 0f))
{
return 1;
}
return -1;
}
private static bool CancelPressed()
{
try
{
if (InputManager.UI.GetCancelButtonDown((PlayerFarming)null))
{
return true;
}
}
catch
{
}
if (!Input.GetKeyDown((KeyCode)27))
{
return Input.GetKeyDown((KeyCode)8);
}
return true;
}
}
internal sealed class TraitProfilePromptMarker : MonoBehaviour
{
}
[HarmonyPatch(typeof(interaction_FollowerInteraction), "GetLabel")]
internal static class FollowerProfileLabelPatch
{
private static void Postfix(interaction_FollowerInteraction __instance)
{
FollowerTraitTreePlugin.Instance?.ConfigureFollowerProfilePrompt(__instance);
}
}
[HarmonyPatch(typeof(Interaction), "OnSecondaryInteract")]
internal static class FollowerProfileSecondaryInteractionPatch
{
private static bool Prefix(Interaction __instance, StateMachine state)
{
interaction_FollowerInteraction val = (interaction_FollowerInteraction)(object)((__instance is interaction_FollowerInteraction) ? __instance : null);
if ((Object)(object)val == (Object)null)
{
return true;
}
FollowerTraitTreePlugin instance = FollowerTraitTreePlugin.Instance;
if (!((Object)(object)instance == (Object)null))
{
return !instance.TryOpenFollowerProfile(val, state);
}
return true;
}
}
internal static class TraitTreeConfig
{
internal static ConfigEntry<bool> Enabled;
internal static ConfigEntry<string> OpenKey;
internal static ConfigEntry<string> RepairKey;
internal static ConfigEntry<bool> EnableTreeInteraction;
internal static ConfigEntry<bool> UnlockCrystalTree;
internal static ConfigEntry<bool> EnableFollowerProfiles;
internal static ConfigEntry<string> TreeStructureTypes;
internal static ConfigEntry<float> InteractionRadius;
internal static ConfigEntry<bool> AutoSaveAfterChange;
internal static ConfigEntry<bool> RepairLegacySozoOnLoad;
internal static void Bind(ConfigFile config)
{
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Expected O, but got Unknown
Enabled = config.Bind<bool>("General", "Enabled", true, "Enable Follower Trait Tree.");
OpenKey = config.Bind<string>("Controls", "OpenKey", "F6", "Fallback keyboard KeyCode used to open the trait tree menu.");
RepairKey = config.Bind<string>("Controls", "RepairKey", "F2", "Fallback keyboard KeyCode used to repair interaction-blocking state traits on the selected follower.");
EnableTreeInteraction = config.Bind<bool>("Trait Tree", "EnableTreeInteraction", true, "Turn the Crystal Tree decoration into an interactable Trait Tree.");
UnlockCrystalTree = config.Bind<bool>("Trait Tree", "UnlockCrystalTree", true, "Unlock and reveal the Crystal Tree decoration while this mod is installed.");
EnableFollowerProfiles = config.Bind<bool>("Follower Profiles", "Enabled", true, "Add View Follower Profile to the unused secondary follower interaction.");
TreeStructureTypes = config.Bind<string>("Trait Tree", "TreeStructureTypes", "DECORATION_CRYSTAL_TREE", "Comma-separated StructureBrain.TYPES values that should behave as Trait Trees.");
InteractionRadius = config.Bind<float>("Trait Tree", "InteractionRadius", 2.5f, new ConfigDescription("Vanilla interaction distance for the Trait Tree.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), Array.Empty<object>()));
AutoSaveAfterChange = config.Bind<bool>("Safety", "AutoSaveAfterChange", true, "Call SaveAndLoad.Save after each trait add/remove.");
RepairLegacySozoOnLoad = config.Bind<bool>("Safety", "RepairLegacySozoOnLoad", true, "Repair incompatible state traits that Follower Trait Tree v0.1.0 may have assigned to Dr. Sozo.");
if (string.Equals(TreeStructureTypes.Value, "DECORATION_TREE,DECORATION_CRYSTAL_TREE,DECORATION_CHRISTMAS_TREE,DECORATION_DLC_WOOLHAVEN_TREE,DECORATION_DLC_YNGYA_TREEPOT", StringComparison.OrdinalIgnoreCase))
{
TreeStructureTypes.Value = "DECORATION_CRYSTAL_TREE";
}
}
}
}