using System;
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 BepInEx;
using BepInEx.Logging;
using COTL_API.CustomFollowerCommand;
using COTL_API.CustomInventory;
using COTL_API.CustomSkins;
using COTL_API.CustomStructures;
using COTL_API.CustomTarotCard;
using COTL_API.Helpers;
using CustomSpineLoader.APIHelper;
using CustomSpineLoader.Commands;
using CustomSpineLoader.SpineLoaderHelper;
using HarmonyLib;
using Lamb.UI;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Spine;
using Spine.Unity;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("CultTweaker")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+cc2ff3a9555536c49cc3af1aa8ffc83f6fbd1a6c")]
[assembly: AssemblyProduct("CultTweaker")]
[assembly: AssemblyTitle("CultTweaker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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 CustomSpineLoader
{
[BepInPlugin("InfernoDragon0.cotl.CustomSpineLoader", "CultTweaker", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[HarmonyPatch]
public class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "InfernoDragon0.cotl.CustomSpineLoader";
public const string PluginName = "CultTweaker";
public const string PluginVer = "1.0.0";
internal static ManualLogSource Log;
internal static readonly Harmony Harmony = new Harmony("InfernoDragon0.cotl.CustomSpineLoader");
internal static string PluginPath;
private void Awake()
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
PluginPath = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
Log.LogInfo((object)"Cult Tweaker is loading! For more information or templates on how to use this mod, go to the NexusMods page!");
CustomFollowerCommandManager.Add((CustomFollowerCommand)(object)new CustomColorCommand());
StructureBuildingOverrideHelper.LoadBuildingOverrides();
Log.LogInfo((object)"Loading Custom Items...");
CustomItemLoader.LoadAllCustomItems();
Log.LogInfo((object)"Loading Custom Meals...");
CustomMealLoader.LoadAllCustomMeals();
Log.LogInfo((object)"Loading Custom Tarots...");
CustomTarotLoader.LoadAllCustomTarots();
Log.LogInfo((object)"Loading Custom Structures...");
CustomStructureLoader.LoadAllCustomStructures();
}
private void OnEnable()
{
Harmony.PatchAll();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded CultTweaker!");
}
private void OnDisable()
{
Harmony.UnpatchSelf();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Unloaded CultTweaker!");
}
}
}
namespace CustomSpineLoader.SpineLoaderHelper
{
public class CustomColorHelper
{
public static Dictionary<int, CustomFollowerColor> CustomColors { get; private set; } = new Dictionary<int, CustomFollowerColor>();
public static Dictionary<int, CustomFollowerSpineSkin> CustomFollowerSkinConfigs { get; private set; } = new Dictionary<int, CustomFollowerSpineSkin>();
public static void LoadCustomColors(int saveSlot)
{
if (!File.Exists(Path.Combine(Plugin.PluginPath, $"CustomColors{saveSlot}.json")))
{
Plugin.Log.LogInfo((object)("Creating new CustomColors.json file for save slot " + saveSlot + "."));
string contents = JsonConvert.SerializeObject((object)CustomColors, (Formatting)1);
File.WriteAllText(Path.Combine(Plugin.PluginPath, $"CustomColors{saveSlot}.json"), contents);
}
else
{
string text = File.ReadAllText(Path.Combine(Plugin.PluginPath, $"CustomColors{saveSlot}.json"));
CustomColors = JsonConvert.DeserializeObject<Dictionary<int, CustomFollowerColor>>(text) ?? new Dictionary<int, CustomFollowerColor>();
}
}
public static void SaveCustomColors()
{
string contents = JsonConvert.SerializeObject((object)CustomColors, (Formatting)1);
File.WriteAllText(Path.Combine(Plugin.PluginPath, $"CustomColors{SaveAndLoad.SAVE_SLOT}.json"), contents);
Plugin.Log.LogInfo((object)"Saved custom colors");
}
public static CustomFollowerColor GetCustomColor(int id)
{
CustomFollowerColor value;
return CustomColors.TryGetValue(id, out value) ? value : null;
}
public static void SetCustomColor(int id, float r, float g, float b, float a)
{
CustomFollowerColor value = new CustomFollowerColor(id, r, g, b, a);
CustomColors[id] = value;
Plugin.Log.LogInfo((object)$"Set custom color for follower {id} to ({r}, {g}, {b}, {a})");
}
public static void RemoveCustomColor(int id)
{
if (CustomColors.ContainsKey(id))
{
CustomColors.Remove(id);
Plugin.Log.LogInfo((object)$"Removed custom color for follower {id}");
}
}
}
[Serializable]
public class CustomFollowerColor
{
public int FollowerId { get; set; }
public float R { get; set; }
public float G { get; set; }
public float B { get; set; }
public float A { get; set; }
public CustomFollowerColor(int id, float r, float g, float b, float a)
{
FollowerId = id;
R = Mathf.Clamp(r, 0f, 1f);
G = Mathf.Clamp(g, 0f, 1f);
B = Mathf.Clamp(b, 0f, 1f);
A = Mathf.Clamp(a, 0f, 1f);
base..ctor();
}
}
[Serializable]
public class CustomFollowerSpineSkin
{
public string SpineName;
public List<string> SkinsApplied;
}
public class FollowerSpineLoader
{
public static void LoadAllFollowerSpines(Material material = null)
{
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Expected O, but got Unknown
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Expected O, but got Unknown
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01ba: Expected O, but got Unknown
//IL_0235: Unknown result type (might be due to invalid IL or missing references)
string path = Path.Combine(Plugin.PluginPath, "FollowerSkins");
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string[] directories = Directory.GetDirectories(path);
string[] array = directories;
foreach (string path2 in array)
{
string fileName = Path.GetFileName(path2);
string[] array2 = (from x in Directory.GetFiles(path2, "*.json", SearchOption.TopDirectoryOnly)
where !x.Contains("config")
select x).ToArray();
string[] files = Directory.GetFiles(path2, "*.png", SearchOption.TopDirectoryOnly);
string[] files2 = Directory.GetFiles(path2, "*.atlas", SearchOption.TopDirectoryOnly);
string[] files3 = Directory.GetFiles(path2, "config.json", SearchOption.TopDirectoryOnly);
List<string> list = new List<string>(1) { "Cat" };
string[] array3 = new string[0];
if (files3.Length != 0)
{
TextAsset val = new TextAsset(File.ReadAllText(files3[0]));
FollowerSpineConfig followerSpineConfig = JsonConvert.DeserializeObject<FollowerSpineConfig>(val.text);
if (followerSpineConfig != null)
{
list = followerSpineConfig.DefaultSkin;
array3 = followerSpineConfig.Skins;
Plugin.Log.LogInfo((object)$"Using default skin: {list}");
Plugin.Log.LogInfo((object)("Using skin list: " + string.Join(", ", array3)));
}
}
if (array2.Length != 0 && files.Length != 0 && files2.Length != 0)
{
Plugin.Log.LogInfo((object)("Reading atlas from " + files2[0]));
TextAsset val2 = new TextAsset(File.ReadAllText(files2[0]));
Plugin.Log.LogInfo((object)("Reading skeleton from " + array2[0]));
TextAsset val3 = new TextAsset(File.ReadAllText(array2[0]));
Texture2D[] array4 = (Texture2D[])(object)new Texture2D[files.Length];
string[] array5 = files;
foreach (string text in array5)
{
Plugin.Log.LogInfo((object)("Reading texture from " + text));
Texture2D val4 = TextureHelper.CreateTextureFromPath(text, (TextureFormat)4, false, false);
((Object)val4).name = Path.GetFileNameWithoutExtension(text);
array4[Array.IndexOf(files, text)] = val4;
}
Material val5 = (Material)(((object)material) ?? ((object)new Material(Shader.Find("Spine/Skeleton"))));
SpineAtlasAsset val6 = SpineAtlasAsset.CreateRuntimeInstance(val2, array4, val5, true);
SkeletonDataAsset val7 = SkeletonDataAsset.CreateRuntimeInstance(val3, (AtlasAssetBase)(object)val6, true, 0.005f);
Plugin.Log.LogInfo((object)("Creating skeleton for " + fileName));
Plugin.Log.LogInfo((object)("Using material name " + ((Object)val5).name));
CustomSkinManager.AddFollowerSpine(fileName, val7);
for (int k = 0; k < list.Count; k++)
{
string text2 = list[k];
}
}
else
{
Plugin.Log.LogInfo((object)("Failed to load follower skin " + fileName + ", ensure that the folder contains at least one of each .json, .png and .atlas file."));
}
}
}
}
public class FollowerSpineConfig
{
public List<string> DefaultSkin { get; set; }
public string[] Skins { get; set; }
public bool InitializeWithoutBase { get; set; } = true;
}
public class PlayerSpineLoader
{
public static void LoadAllPlayerSpines(Material material = null)
{
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Expected O, but got Unknown
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0184: Expected O, but got Unknown
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01ad: Expected O, but got Unknown
//IL_0228: Unknown result type (might be due to invalid IL or missing references)
string path = Path.Combine(Plugin.PluginPath, "PlayerSkins");
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string[] directories = Directory.GetDirectories(path);
string[] array = directories;
foreach (string path2 in array)
{
string fileName = Path.GetFileName(path2);
string[] array2 = (from x in Directory.GetFiles(path2, "*.json", SearchOption.TopDirectoryOnly)
where !x.Contains("config")
select x).ToArray();
string[] files = Directory.GetFiles(path2, "*.png", SearchOption.TopDirectoryOnly);
string[] files2 = Directory.GetFiles(path2, "*.atlas", SearchOption.TopDirectoryOnly);
string[] files3 = Directory.GetFiles(path2, "config.json", SearchOption.TopDirectoryOnly);
string text = "Lamb";
string[] array3 = new string[0];
if (files3.Length != 0)
{
TextAsset val = new TextAsset(File.ReadAllText(files3[0]));
PlayerSpineConfig playerSpineConfig = JsonConvert.DeserializeObject<PlayerSpineConfig>(val.text);
if (playerSpineConfig != null)
{
text = playerSpineConfig.DefaultSkin;
array3 = playerSpineConfig.Skins;
Plugin.Log.LogInfo((object)("Using default skin: " + text));
Plugin.Log.LogInfo((object)("Using skin list: " + string.Join(", ", array3)));
}
}
if (array2.Length != 0 && files.Length != 0 && files2.Length != 0)
{
Plugin.Log.LogInfo((object)("Reading atlas from " + files2[0]));
TextAsset val2 = new TextAsset(File.ReadAllText(files2[0]));
Plugin.Log.LogInfo((object)("Reading skeleton from " + array2[0]));
TextAsset val3 = new TextAsset(File.ReadAllText(array2[0]));
Texture2D[] array4 = (Texture2D[])(object)new Texture2D[files.Length];
string[] array5 = files;
foreach (string text2 in array5)
{
Plugin.Log.LogInfo((object)("Reading texture from " + text2));
Texture2D val4 = TextureHelper.CreateTextureFromPath(text2, (TextureFormat)4, false, false);
((Object)val4).name = Path.GetFileNameWithoutExtension(text2);
array4[Array.IndexOf(files, text2)] = val4;
}
Material val5 = (Material)(((object)material) ?? ((object)new Material(Shader.Find("Spine/Skeleton"))));
SpineAtlasAsset val6 = SpineAtlasAsset.CreateRuntimeInstance(val2, array4, val5, true);
SkeletonDataAsset val7 = SkeletonDataAsset.CreateRuntimeInstance(val3, (AtlasAssetBase)(object)val6, true, 0.005f);
Plugin.Log.LogInfo((object)("Creating skeleton for " + fileName));
Plugin.Log.LogInfo((object)("Using material name " + ((Object)val5).name));
CustomSkinManager.AddPlayerSpine(fileName, val7, array3.ToList());
CustomSkinManager.ChangeSelectedPlayerSpine(fileName + "/" + text);
}
else
{
Plugin.Log.LogInfo((object)("Failed to load player skin " + fileName + ", ensure that the folder contains at least one of each .json, .png and .atlas file."));
}
}
}
}
public class PlayerSpineConfig
{
public string DefaultSkin { get; set; }
public string[] Skins { get; set; }
}
public class StructureBuildingOverrideHelper
{
public static Dictionary<string, List<StructureBuildingOverride>> StructureBuildingOverrides { get; private set; } = new Dictionary<string, List<StructureBuildingOverride>>();
public static void LoadBuildingOverrides()
{
if (!Directory.Exists(Path.Combine(Plugin.PluginPath, "BuildingOverrides")))
{
Directory.CreateDirectory(Path.Combine(Plugin.PluginPath, "BuildingOverrides"));
Plugin.Log.LogInfo((object)"Created BuildingOverrides directory.");
return;
}
string[] directories = Directory.GetDirectories(Path.Combine(Plugin.PluginPath, "BuildingOverrides"));
foreach (string text in directories)
{
string name = new DirectoryInfo(text).Name;
List<StructureBuildingOverride> list = new List<StructureBuildingOverride>();
if (File.Exists(Path.Combine(text, "config.json")))
{
string text2 = File.ReadAllText(Path.Combine(text, "config.json"));
try
{
StructureBuildingOverrideData structureBuildingOverrideData = JsonConvert.DeserializeObject<StructureBuildingOverrideData>(text2) ?? null;
if (structureBuildingOverrideData != null && structureBuildingOverrideData.Overrides != null)
{
list.AddRange(structureBuildingOverrideData.Overrides);
}
}
catch (Exception arg)
{
Plugin.Log.LogError((object)$"Error loading building override from config.json in {text}: {arg}");
}
}
if (list.Count > 0)
{
StructureBuildingOverrides[name] = list;
Plugin.Log.LogInfo((object)$"Loaded {list.Count} overrides for building {name}.");
}
}
}
public static List<CustomStructureBuildingData> GetOverridesForBuilding(string buildingName)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: 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_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: 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_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: 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_00ac: Expected O, but got Unknown
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: 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)
List<StructureBuildingOverride> value;
List<StructureBuildingOverride> list = (StructureBuildingOverrides.TryGetValue(buildingName, out value) ? value : null);
if (list == null)
{
return null;
}
List<CustomStructureBuildingData> list2 = new List<CustomStructureBuildingData>();
foreach (StructureBuildingOverride item in list)
{
CustomStructureBuildingData val = new CustomStructureBuildingData
{
Offset = item.Offset.ToVector3(),
Scale = item.Scale.ToVector3(),
Rotation = item.Rotation.ToVector3(),
Sprite = TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "BuildingOverrides/" + buildingName + "/" + item.SpriteImageName))
};
list2.Add(val);
Plugin.Log.LogInfo((object)$"Custom Spine Loader: Loaded override with sprite {item.SpriteImageName} for building {buildingName}: offset {val.Offset}, scale {val.Scale}, rotation {val.Rotation}.");
}
return list2;
}
}
[Serializable]
public class StructureBuildingOverrideData
{
public List<StructureBuildingOverride> Overrides = new List<StructureBuildingOverride>();
}
[Serializable]
public class StructureBuildingOverride
{
public SerializableVector3 Offset;
public SerializableVector3 Scale;
public SerializableVector3 Rotation;
public string SpriteImageName;
}
[Serializable]
public class SerializableVector3
{
public float X;
public float Y;
public float Z;
public Vector3 ToVector3()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
return new Vector3(X, Y, Z);
}
}
[Serializable]
public class SerializableVector2
{
public float X;
public float Y;
public Vector2 ToVector2()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
return new Vector2(X, Y);
}
}
}
namespace CustomSpineLoader.Patches
{
[HarmonyPatch]
public class SkinSelectorPatch
{
[HarmonyPatch(typeof(PlayerFarming), "Awake")]
[HarmonyPrefix]
private static bool PlayerFarming_Awake(PlayerFarming __instance)
{
Plugin.Log.LogInfo((object)"PlayerFarming Awake called, checking for custom spines...");
Material primaryMaterial = ((SkeletonRenderer)__instance.Spine).skeletonDataAsset.atlasAssets[0].PrimaryMaterial;
Plugin.Log.LogInfo((object)("Test result is " + ((Object)primaryMaterial).name));
Plugin.Log.LogInfo((object)("Test shader is " + ((Object)primaryMaterial.shader).name));
PlayerSpineLoader.LoadAllPlayerSpines(primaryMaterial);
return true;
}
[HarmonyPatch(typeof(FollowerBrain), "SetFollowerCostume", new Type[]
{
typeof(Skeleton),
typeof(int),
typeof(string),
typeof(int),
typeof(FollowerOutfitType),
typeof(FollowerHatType),
typeof(FollowerClothingType),
typeof(FollowerCustomisationType),
typeof(FollowerSpecialType),
typeof(ITEM_TYPE),
typeof(string),
typeof(FollowerInfo)
})]
[HarmonyPostfix]
private static void FollowerBrain_SetFollowerCostume(FollowerBrain __instance, Skeleton skeleton, FollowerInfo info)
{
//IL_00df: 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_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
Plugin.Log.LogInfo((object)"Setting follower costume for");
if (info != null)
{
Plugin.Log.LogInfo((object)$"Follower ID: {info.ID}, Name: {info.Name}");
CustomFollowerColor customColor = CustomColorHelper.GetCustomColor(info.ID);
if (customColor != null)
{
Plugin.Log.LogInfo((object)$"Custom color found for follower {info.ID}: R={customColor.R}, G={customColor.G}, B={customColor.B}, A={customColor.A}");
SkeletonExtensions.SetColor(skeleton.FindSlot("ARM_LEFT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f));
SkeletonExtensions.SetColor(skeleton.FindSlot("LEG_LEFT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f));
SkeletonExtensions.SetColor(skeleton.FindSlot("LEG_RIGHT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f));
SkeletonExtensions.SetColor(skeleton.FindSlot("ARM_RIGHT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f));
SkeletonExtensions.SetColor(skeleton.FindSlot("HEAD_SKIN_BTM"), new Color(customColor.R, customColor.G, customColor.B, 1f));
skeleton.A = customColor.A;
}
}
else
{
Plugin.Log.LogInfo((object)"Follower info is null, skipping costume setting.");
}
}
[HarmonyPatch(typeof(SaveAndLoad), "Load")]
[HarmonyPostfix]
private static void SaveAndLoad_Load(int saveSlot)
{
CustomColorHelper.LoadCustomColors(saveSlot);
}
[HarmonyPatch(typeof(SaveAndLoad), "Save", new Type[] { })]
[HarmonyPostfix]
private static void SaveAndLoad_Save()
{
CustomColorHelper.SaveCustomColors();
}
[HarmonyPatch(typeof(Structure), "Start")]
[HarmonyPostfix]
private static void Structure_Start(Structure __instance)
{
string text = ((object)(TYPES)(ref __instance.Type)).ToString();
List<CustomStructureBuildingData> overridesForBuilding = StructureBuildingOverrideHelper.GetOverridesForBuilding(text);
if (overridesForBuilding != null && overridesForBuilding.Count != 0)
{
Plugin.Log.LogInfo((object)$"Custom Spine Loader: {overridesForBuilding.Count} overrides to building {text}.");
CustomStructureManager.OverrideStructureBuilding(((Component)__instance).gameObject, overridesForBuilding);
}
}
}
}
namespace CustomSpineLoader.Commands
{
public class CustomColorCommand : CustomFollowerCommand
{
public UIFollowerSummaryMenuController _followerSummaryMenuController;
public float currentRed = 1f;
public float currentGreen = 1f;
public float currentBlue = 1f;
public float currentAlpha = 1f;
public bool isCustomColorEnabled = false;
public override string InternalName => "CustomColor_Command";
public override Sprite CommandIcon => TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "Assets/colorwheel.png"));
public override List<FollowerCommandCategory> Categories { get; } = new List<FollowerCommandCategory>(1) { (FollowerCommandCategory)0 };
public override string GetTitle(Follower follower)
{
return "Custom Color";
}
public override string GetDescription(Follower follower)
{
return "Recolor Me!";
}
public override void Execute(interaction_FollowerInteraction interaction, FollowerCommands finalCommand)
{
((MonoBehaviour)interaction).StartCoroutine(interaction.FrameDelayCallback((Action)delegate
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
interaction.follower.Brain.HardSwapToTask((FollowerTask)new FollowerTask_ManualControl());
_followerSummaryMenuController = MonoSingleton<UIManager>.Instance.ShowFollowerSummaryMenu(interaction.follower);
CreateColorUI();
UIFollowerSummaryMenuController followerSummaryMenuController = _followerSummaryMenuController;
((UIMenuBase)followerSummaryMenuController).OnHidden = (Action)Delegate.Combine(((UIMenuBase)followerSummaryMenuController).OnHidden, (Action)delegate
{
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
_followerSummaryMenuController = null;
if (isCustomColorEnabled)
{
CustomColorHelper.SetCustomColor(interaction.follower.Brain.Info.ID, currentRed, currentGreen, currentBlue, currentAlpha);
SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f));
SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("LEG_LEFT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f));
SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("LEG_RIGHT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f));
SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("ARM_RIGHT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f));
SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("HEAD_SKIN_BTM"), new Color(currentRed, currentGreen, currentBlue, 1f));
((SkeletonRenderer)interaction.follower.Spine).skeleton.A = currentAlpha;
}
else
{
CustomColorHelper.RemoveCustomColor(interaction.follower.Brain.Info.ID);
}
interaction.Close(true, true, false);
});
HUD_Manager.Instance.Hide(false, 0, false);
}));
}
public void CreateColorUI()
{
if ((Object)(object)_followerSummaryMenuController == (Object)null)
{
Debug.LogError((object)"Follower Summary Menu Controller is not initialized.");
return;
}
Debug.Log((object)"Creating color picker UI...");
Transform val = ((Component)_followerSummaryMenuController).transform.Find("FollowerSummaryContainer");
Transform val2 = ((val != null) ? val.Find("Left") : null);
Transform val3 = ((val2 != null) ? val2.Find("Transform") : null);
Transform val4 = ((val3 != null) ? val3.Find("Top") : null);
Transform val5 = ((val4 != null) ? val4.Find("Header") : null);
TMP_Text val6 = ((val5 != null) ? ((Component)val5).GetComponent<TMP_Text>() : null);
if ((Object)(object)val6 != (Object)null)
{
val6.text = "Custom Color";
}
Transform val7 = ((val3 != null) ? val3.Find("Content") : null);
Transform val8 = ((val7 != null) ? val7.Find("Scroll View") : null);
Transform val9 = ((val8 != null) ? val8.Find("Viewport") : null);
Transform val10 = ((val9 != null) ? val9.Find("Content") : null);
Transform val11 = ((val10 != null) ? val10.Find("Follower Traits Header") : null);
TMP_Text val12 = ((val11 != null) ? ((Component)val11).GetComponent<TMP_Text>() : null);
if ((Object)(object)val12 != (Object)null)
{
val12.text = "Select Custom Color";
}
Transform val13 = ((val10 != null) ? val10.Find("Follower Traits Content") : null);
if (val13 != null)
{
((Component)val13).gameObject.SetActive(false);
}
Transform val14 = ((val10 != null) ? val10.Find("Cult Traits Header") : null);
TMP_Text val15 = ((val14 != null) ? ((Component)val14).GetComponent<TMP_Text>() : null);
if ((Object)(object)val15 != (Object)null)
{
val15.text = "Body Color";
}
Transform val16 = ((val10 != null) ? val10.Find("Cult Traits Content") : null);
if (val16 != null)
{
((Component)val16).gameObject.SetActive(false);
}
Transform val17 = ((val10 != null) ? val10.Find("Follower Thoughts") : null);
if (val17 != null)
{
((Component)val17).gameObject.SetActive(false);
}
Transform val18 = ((val10 != null) ? val10.Find("Follower Thoughts Content") : null);
if (val18 != null)
{
((Component)val18).gameObject.SetActive(false);
}
Transform val19 = ((val10 != null) ? val10.Find("Spacer") : null);
GameObject gameObject = ((Component)((Transform)((Component)MonoSingleton<UIManager>.Instance.SettingsMenuControllerTemplate._audioSettings).GetComponentInChildren<ScrollRect>().content).GetChild(0)).gameObject;
GameObject gameObject2 = ((Component)((Transform)((Component)MonoSingleton<UIManager>.Instance.SettingsMenuControllerTemplate._graphicsSettings).GetComponentInChildren<ScrollRect>().content).GetChild(4)).gameObject;
GameObject val20 = Object.Instantiate<GameObject>(gameObject, val10);
Transform val21 = Object.Instantiate<Transform>(val19, val10);
GameObject val22 = Object.Instantiate<GameObject>(gameObject, val10);
Transform val23 = Object.Instantiate<Transform>(val19, val10);
GameObject val24 = Object.Instantiate<GameObject>(gameObject, val10);
Transform val25 = Object.Instantiate<Transform>(val19, val10);
GameObject val26 = Object.Instantiate<GameObject>(gameObject, val10);
Transform val27 = Object.Instantiate<Transform>(val19, val10);
GameObject val28 = Object.Instantiate<GameObject>(gameObject2, val10);
TMP_Text componentInChildren = val20.GetComponentInChildren<TMP_Text>();
TMP_Text componentInChildren2 = val22.GetComponentInChildren<TMP_Text>();
TMP_Text componentInChildren3 = val24.GetComponentInChildren<TMP_Text>();
TMP_Text componentInChildren4 = val26.GetComponentInChildren<TMP_Text>();
TMP_Text componentInChildren5 = val28.GetComponentInChildren<TMP_Text>();
MMSlider componentInChildren6 = val20.GetComponentInChildren<MMSlider>();
MMSlider componentInChildren7 = val22.GetComponentInChildren<MMSlider>();
MMSlider componentInChildren8 = val24.GetComponentInChildren<MMSlider>();
MMSlider componentInChildren9 = val26.GetComponentInChildren<MMSlider>();
MMToggle componentInChildren10 = val28.GetComponentInChildren<MMToggle>();
((Object)val20).name = "SliderRed";
((Object)val22).name = "SliderGreen";
((Object)val24).name = "SliderBlue";
((Object)val26).name = "SliderAlpha";
((Object)val28).name = "ToggleCustomColor";
componentInChildren.text = "Red";
componentInChildren2.text = "Green";
componentInChildren3.text = "Blue";
componentInChildren4.text = "Alpha";
componentInChildren5.text = "Enable Custom Color";
((UnityEvent<float>)(object)((Slider)componentInChildren6).onValueChanged).AddListener((UnityAction<float>)delegate(float value)
{
OnSliderValueChanged("Red", value);
});
((UnityEvent<float>)(object)((Slider)componentInChildren7).onValueChanged).AddListener((UnityAction<float>)delegate(float value)
{
OnSliderValueChanged("Green", value);
});
((UnityEvent<float>)(object)((Slider)componentInChildren8).onValueChanged).AddListener((UnityAction<float>)delegate(float value)
{
OnSliderValueChanged("Blue", value);
});
((UnityEvent<float>)(object)((Slider)componentInChildren9).onValueChanged).AddListener((UnityAction<float>)delegate(float value)
{
OnSliderValueChanged("Alpha", value);
});
componentInChildren10.OnValueChanged = (Action<bool>)Delegate.Combine(componentInChildren10.OnValueChanged, new Action<bool>(OnToggleValueChanged));
componentInChildren6._increment = 1;
componentInChildren7._increment = 1;
componentInChildren8._increment = 1;
componentInChildren9._increment = 1;
((Slider)componentInChildren6).value = ((SkeletonRenderer)_followerSummaryMenuController._follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN").R * 100f;
((Slider)componentInChildren7).value = ((SkeletonRenderer)_followerSummaryMenuController._follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN").G * 100f;
((Slider)componentInChildren8).value = ((SkeletonRenderer)_followerSummaryMenuController._follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN").B * 100f;
((Slider)componentInChildren9).value = ((SkeletonRenderer)_followerSummaryMenuController._follower.Spine).skeleton.A * 100f;
CustomFollowerColor customColor = CustomColorHelper.GetCustomColor(_followerSummaryMenuController._follower.Brain.Info.ID);
if (customColor != null)
{
componentInChildren10.Value = true;
componentInChildren10.UpdateState(true);
isCustomColorEnabled = true;
}
else
{
componentInChildren10.Value = false;
componentInChildren10.UpdateState(true);
isCustomColorEnabled = false;
}
}
public void OnToggleValueChanged(bool value)
{
Debug.Log((object)$"Toggle value changed to {value}");
isCustomColorEnabled = value;
}
public void OnSliderValueChanged(string color, float value)
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_024a: Unknown result type (might be due to invalid IL or missing references)
//IL_0255: Unknown result type (might be due to invalid IL or missing references)
//IL_0260: Unknown result type (might be due to invalid IL or missing references)
//IL_026b: Unknown result type (might be due to invalid IL or missing references)
value /= 100f;
Debug.Log((object)$"Slider {color} value changed to {value}");
if ((Object)(object)_followerSummaryMenuController == (Object)null)
{
Debug.LogError((object)"Follower Summary Menu Controller is not initialized.");
return;
}
Follower follower = _followerSummaryMenuController._follower;
SkeletonGraphic followerSpine = _followerSummaryMenuController._infoBox.FollowerSpine;
Color color2 = SkeletonExtensions.GetColor(((SkeletonRenderer)follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN"));
switch (color)
{
case "Red":
currentRed = value;
followerSpine.skeleton.FindSlot("ARM_LEFT_SKIN").R = value;
followerSpine.skeleton.FindSlot("LEG_LEFT_SKIN").R = value;
followerSpine.skeleton.FindSlot("LEG_RIGHT_SKIN").R = value;
followerSpine.skeleton.FindSlot("ARM_RIGHT_SKIN").R = value;
followerSpine.skeleton.FindSlot("HEAD_SKIN_BTM").R = value;
break;
case "Green":
currentGreen = value;
followerSpine.skeleton.FindSlot("ARM_LEFT_SKIN").G = value;
followerSpine.skeleton.FindSlot("LEG_LEFT_SKIN").G = value;
followerSpine.skeleton.FindSlot("LEG_RIGHT_SKIN").G = value;
followerSpine.skeleton.FindSlot("ARM_RIGHT_SKIN").G = value;
followerSpine.skeleton.FindSlot("HEAD_SKIN_BTM").G = value;
break;
case "Blue":
currentBlue = value;
followerSpine.skeleton.FindSlot("ARM_LEFT_SKIN").B = value;
followerSpine.skeleton.FindSlot("LEG_LEFT_SKIN").B = value;
followerSpine.skeleton.FindSlot("LEG_RIGHT_SKIN").B = value;
followerSpine.skeleton.FindSlot("ARM_RIGHT_SKIN").B = value;
followerSpine.skeleton.FindSlot("HEAD_SKIN_BTM").B = value;
break;
case "Alpha":
currentAlpha = value;
((Graphic)followerSpine).color = new Color(((Graphic)followerSpine).color.r, ((Graphic)followerSpine).color.g, ((Graphic)followerSpine).color.b, value);
break;
}
}
}
}
namespace CustomSpineLoader.APIHelper
{
public class CustomItemLoader : Loader<CustomItemConfig>
{
public static List<ITEM_TYPE> loadedItems = new List<ITEM_TYPE>();
public CustomItemLoader()
: base("CustomInventoryItems")
{
}
public static void LoadAllCustomItems()
{
//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
CustomItemLoader customItemLoader = new CustomItemLoader();
List<LoaderResult<CustomItemConfig>> list = customItemLoader.LoadAll();
foreach (LoaderResult<CustomItemConfig> item in list)
{
CustomItemConfig config = item.Config;
string folderName = item.FolderName;
Plugin.Log.LogInfo((object)("Found custom item folder: " + folderName));
string internalName = "CULT_TWEAKER_" + config.ItemName.ToUpper().Replace(" ", "_");
Plugin.Log.LogInfo((object)("Trying to create custom item : " + config.ItemName));
string text = Path.Combine(item.FolderPath, config.SpritePath);
if (!File.Exists(text))
{
Plugin.Log.LogError((object)("Sprite file not found for item " + config.ItemName + " at path: " + text));
continue;
}
Plugin.Log.LogInfo((object)("Loading Sprite via " + text));
try
{
CustomInventoryItem val = (CustomInventoryItem)(object)new CultTweakerCustomItem(internalName, config.ItemName, config.ItemType, config.CanBeRefined, config.RefineryInputQty, config.CustomRefineryDuration, text, config.FuelWeight, config.FoodSatitation, config.IsFish, config.IsFood, config.IsBigFish, config.IsCurrency, config.IsBurnableFuel, config.CanBeGivenToFollower, config.Lore, config.Description, config.AddItemToOfferingShrine, config.AddItemToDungeonChests, config.DungeonChestSpawnChance, config.DungeonChestMinAmount, config.DungeonChestMaxAmount);
Plugin.Log.LogInfo((object)("Successfully created custom item with internal name : " + val.InternalName));
loadedItems.Add(CustomItemManager.Add(val));
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to create custom item : " + config.ItemName));
Plugin.Log.LogError((object)ex);
}
}
}
}
public class CultTweakerCustomItem : CustomInventoryItem
{
private readonly string _internalName;
private readonly string _itemName;
private readonly int _itemType;
private readonly bool _canBeRefined;
private readonly int _refineryInputQty;
private readonly float _customRefineryDuration;
private readonly string _spritePath;
private readonly int _fuelWeight;
private readonly int _foodSatitation;
private readonly bool _isFish;
private readonly bool _isFood;
private readonly bool _isBigFish;
private readonly bool _isCurrency;
private readonly bool _isBurnableFuel;
private readonly bool _canBeGivenToFollower;
private readonly string _lore;
private readonly string _description;
private readonly bool _addItemToOfferingShrine;
private readonly bool _addItemToDungeonChests;
private readonly int _dungeonChestSpawnChance;
private readonly int _dungeonChestMinAmount;
private readonly int _dungeonChestMaxAmount;
public override string InternalName => _internalName;
public override bool CanBeRefined => _canBeRefined;
public override int RefineryInputQty => _refineryInputQty;
public override float CustomRefineryDuration => _customRefineryDuration;
public override Sprite InventoryIcon => TextureHelper.CreateSpriteFromPath(_spritePath);
public override Sprite Sprite => TextureHelper.CreateSpriteFromPath(_spritePath);
public override int FuelWeight => _fuelWeight;
public override int FoodSatitation => _foodSatitation;
public override bool IsFish => _isFish;
public override bool IsFood => _isFood;
public override bool IsBigFish => _isBigFish;
public override bool IsCurrency => _isCurrency;
public override bool IsBurnableFuel => _isBurnableFuel;
public override bool CanBeGivenToFollower => _canBeGivenToFollower;
public override bool AddItemToOfferingShrine => _addItemToOfferingShrine;
public override bool AddItemToDungeonChests => _addItemToDungeonChests;
public override int DungeonChestSpawnChance => _dungeonChestSpawnChance;
public override int DungeonChestMinAmount => _dungeonChestMinAmount;
public override int DungeonChestMaxAmount => _dungeonChestMaxAmount;
public CultTweakerCustomItem(string internalName, string ItemName, int ItemType, bool CanBeRefined, int RefineryInputQty, float CustomRefineryDuration, string SpritePath, int FuelWeight, int FoodSatitation, bool IsFish, bool IsFood, bool IsBigFish, bool IsCurrency, bool IsBurnableFuel, bool CanBeGivenToFollower, string Lore, string Description, bool AddItemToOfferingShrine, bool AddItemToDungeonChests, int DungeonChestSpawnChance, int DungeonChestMinAmount, int DungeonChestMaxAmount)
{
_internalName = internalName;
_itemName = ItemName;
_itemType = ItemType;
_canBeRefined = CanBeRefined;
_refineryInputQty = RefineryInputQty;
_customRefineryDuration = CustomRefineryDuration;
_spritePath = SpritePath;
_fuelWeight = FuelWeight;
_foodSatitation = FoodSatitation;
_isFish = IsFish;
_isFood = IsFood;
_isBigFish = IsBigFish;
_isCurrency = IsCurrency;
_isBurnableFuel = IsBurnableFuel;
_canBeGivenToFollower = CanBeGivenToFollower;
_lore = Lore;
_description = Description;
_addItemToOfferingShrine = AddItemToOfferingShrine;
_addItemToDungeonChests = AddItemToDungeonChests;
_dungeonChestSpawnChance = DungeonChestSpawnChance;
_dungeonChestMinAmount = DungeonChestMinAmount;
_dungeonChestMaxAmount = DungeonChestMaxAmount;
((CustomInventoryItem)this)..ctor();
}
public override string Name()
{
return _itemName;
}
public override string Lore()
{
return _lore;
}
public override string Description()
{
return _description;
}
}
[Serializable]
public class CustomItemConfig
{
public string ItemName;
public int ItemType;
public bool CanBeRefined = false;
public int RefineryInputQty = 15;
public float CustomRefineryDuration = 0f;
public string SpritePath;
public int FuelWeight = 1;
public int FoodSatitation = 75;
public bool IsFish = false;
public bool IsFood = false;
public bool IsBigFish = false;
public bool IsCurrency = false;
public bool IsBurnableFuel = false;
public bool CanBeGivenToFollower = false;
public string Lore = "Custom Item created with CultTweaker.";
public string Description = "This is a custom item created with CultTweaker.";
public bool AddItemToOfferingShrine = false;
public bool AddItemToDungeonChests = false;
public int DungeonChestSpawnChance = 100;
public int DungeonChestMinAmount = 1;
public int DungeonChestMaxAmount = 1;
}
public class CustomMealLoader : Loader<CustomMealConfig>
{
public static List<ITEM_TYPE> loadedMeals = new List<ITEM_TYPE>();
public CustomMealLoader()
: base("CustomMeals")
{
}
public static void LoadAllCustomMeals()
{
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
CustomMealLoader customMealLoader = new CustomMealLoader();
List<LoaderResult<CustomMealConfig>> list = customMealLoader.LoadAll();
foreach (LoaderResult<CustomMealConfig> item in list)
{
CustomMealConfig config = item.Config;
string folderName = item.FolderName;
Plugin.Log.LogInfo((object)("Found custom meal folder: " + folderName));
string internalName = "CULT_TWEAKER_MEAL_" + (config.ItemName ?? "UNKNOWN").ToUpper().Replace(" ", "_");
Plugin.Log.LogInfo((object)("Trying to create custom meal : " + config.ItemName));
string text = (string.IsNullOrEmpty(config.SpritePath) ? string.Empty : Path.Combine(item.FolderPath, config.SpritePath));
if (!string.IsNullOrEmpty(text) && !File.Exists(text))
{
Plugin.Log.LogWarning((object)("Sprite file not found for meal " + config.ItemName + " at path: " + text + ", skipping sprite (this may be optional)"));
}
try
{
CultTweakerCustomMeal cultTweakerCustomMeal = new CultTweakerCustomMeal(internalName, config, text);
Plugin.Log.LogInfo((object)("Successfully created custom meal with internal name : " + ((CustomInventoryItem)cultTweakerCustomMeal).InternalName));
loadedMeals.Add(CustomItemManager.Add((CustomMeal)(object)cultTweakerCustomMeal));
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to create custom meal : " + config.ItemName));
Plugin.Log.LogError((object)ex.ToString());
}
}
}
}
[Serializable]
public class CustomMealConfig : CustomItemConfig
{
public int SatiationLevel = 0;
public float TummyRating = 0f;
public string MealQuality = "NORMAL";
public bool MealSafeToEat = true;
public Dictionary<string, int> Recipe = new Dictionary<string, int>();
public Dictionary<string, int> MealEffectsDictionary = new Dictionary<string, int>();
}
public class CultTweakerCustomMeal : CustomMeal
{
private readonly string _internalName;
private readonly string _mealName;
private readonly string _spritePath;
private readonly int _satiationLevel;
private readonly float _tummyRating;
private readonly bool _safeToEat;
private readonly string _mealQualityString;
private readonly Dictionary<string, int> _recipe;
private readonly Dictionary<string, int> _effects;
private readonly string _lore;
private readonly string _description;
public override string InternalName => _internalName;
public override Sprite InventoryIcon => TextureHelper.CreateSpriteFromPath(_spritePath);
public override Sprite Sprite => TextureHelper.CreateSpriteFromPath(_spritePath);
public override int SatiationLevel => _satiationLevel;
public override float TummyRating => _tummyRating;
public override bool MealSafeToEat => _safeToEat;
public override MealQuality Quality
{
get
{
//IL_0023: 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_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
try
{
return (MealQuality)Enum.Parse(typeof(MealQuality), _mealQualityString, ignoreCase: true);
}
catch
{
return (MealQuality)1;
}
}
}
public override List<List<InventoryItem>> Recipe
{
get
{
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: 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_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Expected O, but got Unknown
List<List<InventoryItem>> list = new List<List<InventoryItem>>();
List<InventoryItem> list2 = new List<InventoryItem>();
foreach (KeyValuePair<string, int> item in _recipe)
{
try
{
ITEM_TYPE val = (ITEM_TYPE)Enum.Parse(typeof(ITEM_TYPE), item.Key, ignoreCase: true);
list2.Add(new InventoryItem(val, item.Value));
}
catch
{
Plugin.Log.LogWarning((object)("Unknown recipe item type: " + item.Key + " for meal " + ((CustomInventoryItem)this).InternalName));
}
}
list.Add(list2);
return list;
}
}
public override MealEffect[] MealEffects
{
get
{
//IL_0037: 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_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
List<MealEffect> list = new List<MealEffect>();
foreach (KeyValuePair<string, int> effect in _effects)
{
try
{
MealEffectType mealEffectType = (MealEffectType)Enum.Parse(typeof(MealEffectType), effect.Key, ignoreCase: true);
list.Add(new MealEffect
{
MealEffectType = mealEffectType,
Chance = effect.Value
});
}
catch
{
Plugin.Log.LogWarning((object)("Unknown meal effect type: " + effect.Key + " for meal " + ((CustomInventoryItem)this).InternalName));
}
}
return list.ToArray();
}
}
public CultTweakerCustomMeal(string internalName, CustomMealConfig cfg, string spritePath)
{
_internalName = internalName;
_mealName = cfg.ItemName ?? internalName;
_spritePath = (string.IsNullOrEmpty(spritePath) ? cfg.SpritePath : spritePath);
_satiationLevel = cfg.SatiationLevel;
_tummyRating = cfg.TummyRating;
_safeToEat = cfg.MealSafeToEat;
_mealQualityString = cfg.MealQuality ?? "NORMAL";
_recipe = cfg.Recipe ?? new Dictionary<string, int>();
_effects = cfg.MealEffectsDictionary ?? new Dictionary<string, int>();
_lore = cfg.Lore ?? "Custom Meal created with CultTweaker.";
_description = cfg.Description ?? "This is a custom meal created with CultTweaker.";
((CustomMeal)this)..ctor();
}
public override string Name()
{
return _mealName;
}
public override string Lore()
{
return _lore;
}
public override string Description()
{
return _description;
}
}
public class CustomQuestLoader
{
}
public class CustomStructureLoader : Loader<CustomStructureConfig>
{
public static List<TYPES> loadedStructures = new List<TYPES>();
public CustomStructureLoader()
: base("CustomStructures")
{
}
public static void LoadAllCustomStructures()
{
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_014f: Expected O, but got Unknown
//IL_01b5: 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)
CustomStructureLoader customStructureLoader = new CustomStructureLoader();
List<LoaderResult<CustomStructureConfig>> list = customStructureLoader.LoadAll();
Vector2Int bounds = default(Vector2Int);
foreach (LoaderResult<CustomStructureConfig> item2 in list)
{
CustomStructureConfig config = item2.Config;
string folderName = item2.FolderName;
Plugin.Log.LogInfo((object)("Found custom structure folder: " + folderName));
string internalName = "CULT_TWEAKER_STRUCTURE_" + config.StructureName.ToUpper().Replace(" ", "_");
string text = Path.Combine(item2.FolderPath, config.SpritePath ?? "");
if (!File.Exists(text))
{
Plugin.Log.LogError((object)("Sprite file not found for structure " + config.StructureName + " at path: " + text));
continue;
}
Plugin.Log.LogInfo((object)("Loading structure sprite via " + text));
try
{
((Vector2Int)(ref bounds))..ctor((int)config.Bounds.X, (int)config.Bounds.Y);
List<CustomStructureBuildingData> buildingParts = new List<CustomStructureBuildingData>();
List<ItemCost> list2 = new List<ItemCost>();
foreach (KeyValuePair<string, int> item3 in config.ItemCost)
{
if (Enum.TryParse<ITEM_TYPE>(item3.Key, out ITEM_TYPE result))
{
ItemCost item = new ItemCost(result, item3.Value);
list2.Add(item);
}
else
{
Plugin.Log.LogError((object)("Invalid item type in ItemCost: " + item3.Key));
}
}
CustomStructure val = (CustomStructure)(object)new CultTweakerCustomStructure(internalName, text, config.BuildDurationMinutes, config.BuildOnlyOne, config.RequiresTempleToBuild, config.CanBeFlipped, bounds, list2, buildingParts);
Plugin.Log.LogInfo((object)("Successfully created custom structure with internal name : " + val.InternalName));
loadedStructures.Add(CustomStructureManager.Add(val));
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to create custom structure : " + config.StructureName));
Plugin.Log.LogError((object)ex);
}
}
}
}
public class CultTweakerCustomStructure : CustomStructure
{
public readonly string _internalName;
public readonly string _spritePath;
public readonly int _buildDurationMinutes;
public readonly bool _buildOnlyOne;
public readonly bool _requiresTempleToBuild;
public readonly bool _canBeFlipped;
public readonly Vector2Int _bounds;
public readonly List<ItemCost> _itemCost;
public readonly List<CustomStructureBuildingData> _buildingParts;
public override string InternalName => _internalName;
public override Sprite Sprite => TextureHelper.CreateSpriteFromPath(_spritePath);
public override List<CustomStructureBuildingData> BuildingParts => _buildingParts;
public override int BuildDurationMinutes => _buildDurationMinutes;
public override Vector2Int Bounds => _bounds;
public override List<ItemCost> Cost => _itemCost;
public CultTweakerCustomStructure(string internalName, string spritePath, int buildDurationMinutes, bool buildOnlyOne, bool requiresTempleToBuild, bool canBeFlipped, Vector2Int bounds, List<ItemCost> itemCost, List<CustomStructureBuildingData> buildingParts)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
_internalName = internalName;
_spritePath = spritePath;
_buildDurationMinutes = buildDurationMinutes;
_buildOnlyOne = buildOnlyOne;
_requiresTempleToBuild = requiresTempleToBuild;
_canBeFlipped = canBeFlipped;
_bounds = bounds;
_itemCost = itemCost;
_buildingParts = buildingParts;
((CustomStructure)this)..ctor();
}
public override bool GetBuildOnlyOne()
{
return _buildOnlyOne;
}
public override bool RequiresTempleToBuild()
{
return _requiresTempleToBuild;
}
public override bool CanBeFlipped()
{
return _canBeFlipped;
}
}
public class CustomStructureConfig
{
public string StructureName;
public string SpritePath;
public List<StructureBuildingOverride> Overrides = new List<StructureBuildingOverride>();
public int BuildDurationMinutes = 30;
public bool BuildOnlyOne = false;
public bool RequiresTempleToBuild = true;
public bool CanBeFlipped = true;
public SerializableVector2 Bounds = new SerializableVector2
{
X = 1f,
Y = 1f
};
public Dictionary<string, int> ItemCost = new Dictionary<string, int>();
}
public class CustomTarotLoader : Loader<CustomTarotConfig>
{
public static List<Card> loadedTarots = new List<Card>();
public CustomTarotLoader()
: base("CustomTarotCards")
{
}
public static void LoadAllCustomTarots()
{
//IL_0196: Unknown result type (might be due to invalid IL or missing references)
CustomTarotLoader customTarotLoader = new CustomTarotLoader();
List<LoaderResult<CustomTarotConfig>> list = customTarotLoader.LoadAll();
foreach (LoaderResult<CustomTarotConfig> item in list)
{
CustomTarotConfig config = item.Config;
string folderName = item.FolderName;
Plugin.Log.LogInfo((object)("Found custom tarot folder: " + folderName));
string internalName = "CULT_TWEAKER_TAROT_" + (config.CardName ?? "UNKNOWN").ToUpper().Replace(" ", "_");
Plugin.Log.LogInfo((object)("Trying to create custom tarot card : " + config.CardName));
string text = (string.IsNullOrEmpty(config.SpritePath) ? string.Empty : Path.Combine(item.FolderPath, config.SpritePath));
if (!string.IsNullOrEmpty(text) && !File.Exists(text))
{
Plugin.Log.LogWarning((object)("Sprite file not found for tarot " + config.CardName + " at path: " + text + ", skipping sprite (this may be optional)"));
}
string text2 = (string.IsNullOrEmpty(config.BackSpritePath) ? string.Empty : Path.Combine(item.FolderPath, config.BackSpritePath));
if (string.IsNullOrEmpty(text2) || !File.Exists(text2))
{
}
try
{
CultTweakerCustomTarot cultTweakerCustomTarot = new CultTweakerCustomTarot(internalName, config, text, text2);
Plugin.Log.LogInfo((object)("Successfully created custom tarot with internal name : " + ((CustomTarotCard)cultTweakerCustomTarot).InternalName));
loadedTarots.Add(CustomTarotCardManager.Add((CustomTarotCard)(object)cultTweakerCustomTarot));
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to create custom tarot : " + config.CardName));
Plugin.Log.LogError((object)ex.ToString());
}
}
}
}
[Serializable]
public class CustomTarotConfig
{
public string CardName;
public string SpritePath;
public string BackSpritePath;
public string Category = "Custom";
public int TarotCardWeight = 150;
public int MaxTarotCardLevel = 0;
public bool IsCursedRelated = false;
public string Lore = "Custom Tarot created with CultTweaker.";
public string Description = "This is a custom tarot created with CultTweaker.";
public float SpiritHeartCount = 0f;
public int SpiritAmmoCount = 0;
public float WeaponDamageMultiplierIncrease = 0f;
public float CurseDamageMultiplierIncrease = 0f;
public float WeaponCritChanceIncrease = 0f;
public int LootIncreaseModifier = 0;
public float MovementSpeedMultiplier = 0f;
public float AttackRateMultiplier = 0f;
public float BlackSoulsMultiplier = 0f;
public float HealChance = 0f;
public float NegateDamageChance = 0f;
public int DamageAllEnemiesAmount = 0;
public int HealthAmountMultiplier = 0;
public float AmmoEfficiency = 0f;
public int BlackSoulsOnDamage = 0;
public string ItemToDropInternalName = null;
public float ChanceOfGainingBlueHeart = 0f;
public float ChanceForRelicsMultiplier = 0f;
public float RelicChargeMultiplier = 0f;
}
public class CultTweakerCustomTarot : CustomTarotCard
{
private readonly string _internalName;
private readonly string _cardName;
private readonly string _spritePath;
private readonly string _backSpritePath;
private readonly CardCategory _category;
private readonly int _tarotCardWeight;
private readonly int _maxTarotCardLevel;
private readonly bool _isCursedRelated;
private readonly string _lore;
private readonly string _description;
private readonly float _spiritHeartCount;
private readonly int _spiritAmmoCount;
private readonly float _weaponDamageMultiplierIncrease;
private readonly float _curseDamageMultiplierIncrease;
private readonly float _weaponCritChanceIncrease;
private readonly int _lootIncreaseModifier;
private readonly float _movementSpeedMultiplier;
private readonly float _attackRateMultiplier;
private readonly float _blackSoulsMultiplier;
private readonly float _healChance;
private readonly float _negateDamageChance;
private readonly int _damageAllEnemiesAmount;
private readonly int _healthAmountMultiplier;
private readonly float _ammoEfficiency;
private readonly int _blackSoulsOnDamage;
private readonly string _itemToDropInternalName;
private readonly float _chanceOfGainingBlueHeart;
private readonly float _chanceForRelicsMultiplier;
private readonly float _relicChargeMultiplier;
public override string InternalName => _internalName;
public override CardCategory Category => _category;
public override Sprite CustomSprite => TextureHelper.CreateSpriteFromPath(_spritePath);
public override Sprite CustomBackSprite => TextureHelper.CreateSpriteFromPath(_backSpritePath);
public override string Skin => "Custom";
public override int TarotCardWeight => _tarotCardWeight;
public override int MaxTarotCardLevel => _maxTarotCardLevel;
public override string AnimationSuffix => "Card " + ((CustomTarotCard)this).InternalName + " Animation Suffix not set";
public override bool IsCursedRelated => _isCursedRelated;
public CultTweakerCustomTarot(string internalName, CustomTarotConfig cfg, string spritePath, string backSpritePath)
{
_internalName = internalName;
_cardName = cfg.CardName ?? internalName;
_spritePath = (string.IsNullOrEmpty(spritePath) ? cfg.SpritePath : spritePath);
_backSpritePath = (string.IsNullOrEmpty(backSpritePath) ? cfg.BackSpritePath : backSpritePath);
_tarotCardWeight = cfg.TarotCardWeight;
_maxTarotCardLevel = cfg.MaxTarotCardLevel;
_isCursedRelated = cfg.IsCursedRelated;
_lore = cfg.Lore;
_description = cfg.Description;
_spiritHeartCount = cfg.SpiritHeartCount;
_spiritAmmoCount = cfg.SpiritAmmoCount;
_weaponDamageMultiplierIncrease = cfg.WeaponDamageMultiplierIncrease;
_curseDamageMultiplierIncrease = cfg.CurseDamageMultiplierIncrease;
_weaponCritChanceIncrease = cfg.WeaponCritChanceIncrease;
_lootIncreaseModifier = cfg.LootIncreaseModifier;
_movementSpeedMultiplier = cfg.MovementSpeedMultiplier;
_attackRateMultiplier = cfg.AttackRateMultiplier;
_blackSoulsMultiplier = cfg.BlackSoulsMultiplier;
_healChance = cfg.HealChance;
_negateDamageChance = cfg.NegateDamageChance;
_damageAllEnemiesAmount = cfg.DamageAllEnemiesAmount;
_healthAmountMultiplier = cfg.HealthAmountMultiplier;
_ammoEfficiency = cfg.AmmoEfficiency;
_blackSoulsOnDamage = cfg.BlackSoulsOnDamage;
_itemToDropInternalName = cfg.ItemToDropInternalName;
_chanceOfGainingBlueHeart = cfg.ChanceOfGainingBlueHeart;
_chanceForRelicsMultiplier = cfg.ChanceForRelicsMultiplier;
_relicChargeMultiplier = cfg.RelicChargeMultiplier;
((CustomTarotCard)this)..ctor();
}
public override string LocalisedName()
{
return _cardName;
}
public override string LocalisedDescription()
{
return _description;
}
public override string LocalisedLore()
{
return _lore;
}
public override float GetSpiritHeartCount(TarotCard card)
{
return _spiritHeartCount;
}
public override int GetSpiritAmmoCount(TarotCard card)
{
return _spiritAmmoCount;
}
public override float GetWeaponDamageMultiplerIncrease(TarotCard card)
{
return _weaponDamageMultiplierIncrease;
}
public override float GetCurseDamageMultiplerIncrease(TarotCard card)
{
return _curseDamageMultiplierIncrease;
}
public override float GetWeaponCritChanceIncrease(TarotCard card)
{
return _weaponCritChanceIncrease;
}
public override int GetLootIncreaseModifier(TarotCard card, ITEM_TYPE itemType)
{
return _lootIncreaseModifier;
}
public override float GetMovementSpeedMultiplier(TarotCard card)
{
return _movementSpeedMultiplier;
}
public override float GetAttackRateMultiplier(TarotCard card)
{
return _attackRateMultiplier;
}
public override float GetBlackSoulsMultiplier(TarotCard card)
{
return _blackSoulsMultiplier;
}
public override float GetHealChance(TarotCard card)
{
return _healChance;
}
public override float GetNegateDamageChance(TarotCard card)
{
return _negateDamageChance;
}
public override int GetDamageAllEnemiesAmount(TarotCard card)
{
return _damageAllEnemiesAmount;
}
public override int GetHealthAmountMultiplier(TarotCard card)
{
return _healthAmountMultiplier;
}
public override float GetAmmoEfficiency(TarotCard card)
{
return _ammoEfficiency;
}
public override int GetBlackSoulsOnDamage(TarotCard card)
{
return _blackSoulsOnDamage;
}
public override InventoryItem GetItemToDrop(TarotCard card)
{
return null;
}
public override float GetChanceOfGainingBlueHeart(TarotCard card)
{
return _chanceOfGainingBlueHeart;
}
public override float GetChanceForRelicsMultiplier(TarotCard card)
{
return _chanceForRelicsMultiplier;
}
public override float GetRelicChargeMultiplier(TarotCard card)
{
return _relicChargeMultiplier;
}
public override void ApplyInstantEffects(TarotCard card)
{
}
}
public class LoaderResult<T>
{
public T Config { get; set; }
public string FolderPath { get; set; }
public string FolderName { get; set; }
}
public class Loader<T>
{
public string FolderName { get; set; }
public string RootPath => Path.Combine(Plugin.PluginPath, FolderName);
public Loader(string folderName)
{
FolderName = folderName;
string rootPath = RootPath;
if (!Directory.Exists(rootPath))
{
Directory.CreateDirectory(rootPath);
}
}
public List<LoaderResult<T>> LoadAll()
{
List<LoaderResult<T>> list = new List<LoaderResult<T>>();
string[] directories = Directory.GetDirectories(RootPath);
Plugin.Log.LogInfo((object)("Found " + directories.Length + " entries to load from " + FolderName + "."));
string[] array = directories;
foreach (string text in array)
{
string fileName = Path.GetFileName(text);
string[] files = Directory.GetFiles(text, "config.json", SearchOption.TopDirectoryOnly);
if (files.Length == 0)
{
Plugin.Log.LogInfo((object)("No config.json found for: " + fileName));
continue;
}
try
{
string text2 = File.ReadAllText(files[0]);
T val = JsonConvert.DeserializeObject<T>(text2);
if (val != null)
{
list.Add(new LoaderResult<T>
{
Config = val,
FolderPath = text,
FolderName = fileName
});
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to parse config.json for: " + fileName));
Plugin.Log.LogError((object)ex);
}
}
return list;
}
}
}