Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of HeyBooBoo v1.2.0
HeyBooBoo\TameableBears.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("TameableBears")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0")] [assembly: AssemblyProduct("TameableBears")] [assembly: AssemblyTitle("TameableBears")] [assembly: AssemblyVersion("1.2.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace TameableBears { [DisallowMultipleComponent] public class BearBabySizer : MonoBehaviour { public static ConfigEntry<float> BabyScale; public static ConfigEntry<float> GrowTime; public static ConfigEntry<bool> DebugLog; private const string KeyBabyStart = "bear_baby_start"; private bool _decided; private Vector3 _babyScale = Vector3.one; private void Awake() { //IL_0001: 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_002a: Unknown result type (might be due to invalid IL or missing references) _babyScale = Vector3.one * Mathf.Max(0.05f, BabyScale?.Value ?? 0.3f); } private void Update() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) if (!_decided) { Decide(); } ZNetView component = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } long num = component.GetZDO().GetLong("bear_baby_start", 0L); if (num == 0L) { return; } float num2 = Mathf.Max(1f, GrowTime?.Value ?? 1800f); float num3 = Mathf.Clamp01((float)((ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds / (double)num2)); Vector3 val = ((num3 <= 0f) ? _babyScale : Vector3.Lerp(_babyScale, Vector3.one, num3)); if (((Component)this).transform.localScale != val) { ((Component)this).transform.localScale = val; } if (num3 >= 1f) { if (DebugLog != null && DebugLog.Value) { Debug.Log((object)("[TameableBears] [BabySizer] " + ((Object)((Component)this).gameObject).name + ": finished growing to full size.")); } Object.Destroy((Object)(object)this); } } private void Decide() { Tameable component = ((Component)this).GetComponent<Tameable>(); BaseAI component2 = ((Component)this).GetComponent<BaseAI>(); ZNetView component3 = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null || !component3.IsValid()) { return; } TimeSpan timeSinceSpawned = component2.GetTimeSinceSpawned(); bool flag = component.IsTamed(); if (component3.GetZDO().GetLong("bear_baby_start", 0L) != 0L) { _decided = true; if (DebugLog != null && DebugLog.Value) { Debug.Log((object)("[TameableBears] [BabySizer] " + ((Object)((Component)this).gameObject).name + ": born earlier (zdo key set), resuming growth from started ticks.")); } } else if (flag && timeSinceSpawned.TotalSeconds <= 30.0) { if (component3.IsOwner()) { component3.GetZDO().Set("bear_baby_start", ZNet.instance.GetTime().Ticks); } _decided = true; if (DebugLog != null && DebugLog.Value) { Debug.Log((object)$"[TameableBears] [BabySizer] {((Object)((Component)this).gameObject).name}: newborn detected (age={timeSinceSpawned.TotalSeconds:F1}s, tamed=true), shrinking to baby size."); } } else if (timeSinceSpawned.TotalSeconds > 30.0) { if (DebugLog != null && DebugLog.Value) { Debug.Log((object)$"[TameableBears] [BabySizer] {((Object)((Component)this).gameObject).name}: adult bear (age={timeSinceSpawned.TotalSeconds:F1}s, tamed={flag}), leaving full size."); } Object.Destroy((Object)(object)this); } } } internal static class BearColorConfig { public static ConfigEntry<bool> Enabled; public static ConfigEntry<float> CinnamonChance; public static ConfigEntry<float> BlackChance; public static ConfigEntry<float> WhiteChance; public static ConfigEntry<string> ForceVariant; public static ConfigEntry<string> TintMode; public static ConfigEntry<bool> TintEyes; public static ConfigEntry<bool> ResetColors; public static ConfigEntry<bool> DebugLog; } [DisallowMultipleComponent] public class BearColorizer : MonoBehaviour { private struct Variant { public string Name; public Func<ConfigEntry<float>> Chance; public Color Target; } private const string KeyBabyStart = "bear_baby_start"; private const string KeyVariant = "bear_variant"; private const int NaturalCode = 4; private static readonly Variant[] Variants = new Variant[3] { new Variant { Name = "Cinnamon", Chance = () => BearColorConfig.CinnamonChance, Target = new Color(0.62f, 0.35f, 0.22f) }, new Variant { Name = "Black", Chance = () => BearColorConfig.BlackChance, Target = new Color(0.14f, 0.13f, 0.15f) }, new Variant { Name = "White", Chance = () => BearColorConfig.WhiteChance, Target = new Color(0.97f, 0.97f, 0.98f) } }; private static readonly string[] NonFurHints = new string[8] { "eye", "pupil", "claw", "tooth", "teeth", "nail", "horn", "tongue" }; private static readonly Dictionary<long, Texture2D> TintCache = new Dictionary<long, Texture2D>(); private bool _handled; private const int MaxWaitFrames = 120; private int _waitedFrames; private void Update() { if (!_handled) { TryColorize(); } } private void TryColorize() { if (BearColorConfig.Enabled == null || !BearColorConfig.Enabled.Value) { Finish(); return; } ZNetView component = ((Component)this).GetComponent<ZNetView>(); Tameable component2 = ((Component)this).GetComponent<Tameable>(); BaseAI component3 = ((Component)this).GetComponent<BaseAI>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null || !component.IsValid()) { return; } if (!component2.IsTamed()) { if (_waitedFrames++ >= 120) { Finish(); } return; } ZDO zDO = component.GetZDO(); long num = zDO.GetLong("bear_baby_start", 0L); if (num == 0L) { if (_waitedFrames++ >= 120) { Log("no bear_baby_start on this bear; treating it as natural (never born as a cub)."); Finish(); } return; } double num2 = ((BearBabySizer.GrowTime != null) ? BearBabySizer.GrowTime.Value : 1800f); if (num2 < 1.0) { num2 = 1.0; } bool flag = (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds < num2; int num3 = 0; if (BearColorConfig.ResetColors == null || !BearColorConfig.ResetColors.Value) { num3 = zDO.GetInt("bear_variant", 0); if (num3 < 0 || num3 > 4) { Log($"stored variant {num3} is out of range; discarding and re-rolling."); num3 = 0; } } Variant? variant = null; if (num3 != 4) { if (num3 > 0) { variant = Variants[num3 - 1]; } else { if (!flag) { Finish(); return; } int num4 = RollVariant(); int num5; if (num4 >= 0) { variant = Variants[num4]; num5 = num4 + 1; } else { num5 = 4; } zDO.Set("bear_variant", num5); } } string text = ((BearColorConfig.ForceVariant != null) ? (BearColorConfig.ForceVariant.Value ?? string.Empty).Trim() : string.Empty); if (text.Length > 0) { bool flag2 = false; for (int i = 0; i < Variants.Length; i++) { if (string.Equals(Variants[i].Name, text, StringComparison.OrdinalIgnoreCase)) { variant = Variants[i]; flag2 = true; break; } } if (!flag2) { Log("ForceVariant '" + text + "' is not one of Cinnamon/Black/White; rolling normally."); } } if (variant.HasValue) { ApplyColor(variant.Value); } Finish(); } private void Finish() { _handled = true; Object.Destroy((Object)(object)this); } private double Roll() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)this).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null) ? component.GetZDO() : null); if (val == null) { return -1.0; } ZDOID uid = val.m_uid; ulong userID = (ulong)((ZDOID)(ref uid)).UserID; ulong num = ((ZDOID)(ref uid)).ID; return (double)(Mix(Mix(Mix(Mix((uint)(-1640531527 ^ (int)userID)) ^ (uint)(int)(userID >> 32)) ^ (uint)(int)num) ^ (uint)(int)(num >> 32)) & 0xFFFFFF) / 16777216.0; } private static uint Mix(uint x) { x ^= x >> 16; x *= 2146121005; x ^= x >> 15; x *= 2221713035u; x ^= x >> 16; return x; } private int RollVariant() { double num = Roll(); if (num < 0.0) { return -1; } double num2 = 0.0; for (int i = 0; i < Variants.Length; i++) { ConfigEntry<float> val = Variants[i].Chance(); if (val != null) { num2 += Math.Max(0.0, val.Value); if (num < num2) { Log($"roll={num:F6} cumulative={num2:F4} -> {Variants[i].Name}"); return i; } } } Log($"roll={num:F6} above all bands ({num2:F4}) -> natural colour"); return -1; } private void ApplyColor(Variant variant) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true); bool flag = BearColorConfig.TintEyes == null || BearColorConfig.TintEyes.Value; string a = ((BearColorConfig.TintMode != null) ? (BearColorConfig.TintMode.Value ?? "Texture") : "Texture"); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; Renderer[] array = componentsInChildren; foreach (Renderer val in array) { Material[] materials = val.materials; bool flag2 = false; foreach (Material val2 in materials) { if (!((Object)(object)val2 == (Object)null)) { if (!flag && IsNonFur(val2)) { num3++; } else if (string.Equals(a, "Flat", StringComparison.OrdinalIgnoreCase)) { val2.color = variant.Target; num2++; flag2 = true; } else if (RemapTexture(val2, variant.Target)) { num++; flag2 = true; } else { num4++; Log("could not remap texture on material '" + ((Object)val2).name + "'; falling back to a flat tint, which cannot produce White."); val2.color = variant.Target; num2++; flag2 = true; } } } if (flag2) { val.materials = materials; } } Log($"{variant.Name} cub born! remapped={num} flat={num2} skipped={num3} failed={num4} renderers={componentsInChildren.Length}"); } private static bool IsNonFur(Material material) { string name = ((Object)material).name; if (string.IsNullOrEmpty(name)) { return false; } name = name.ToLowerInvariant(); for (int i = 0; i < NonFurHints.Length; i++) { if (name.Contains(NonFurHints[i])) { return true; } } return false; } private static bool RemapTexture(Material material, Color target) { //IL_0038: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Expected O, but got Unknown //IL_0242: Unknown result type (might be due to invalid IL or missing references) Texture mainTexture = material.mainTexture; if ((Object)(object)mainTexture == (Object)null || mainTexture.width <= 0 || mainTexture.height <= 0) { return false; } RenderTexture val = null; RenderTexture active = RenderTexture.active; Texture2D val2 = null; long key = (long)(((ulong)(uint)((Object)mainTexture).GetInstanceID() << 24) | ((ulong)(uint)Mathf.RoundToInt(target.r * 255f) << 16) | ((ulong)(uint)Mathf.RoundToInt(target.g * 255f) << 8) | (uint)Mathf.RoundToInt(target.b * 255f)); if (TintCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { material.mainTexture = (Texture)(object)value; material.color = Color.white; return true; } try { val = RenderTexture.GetTemporary(mainTexture.width, mainTexture.height, 0, (RenderTextureFormat)0); Graphics.Blit(mainTexture, val); RenderTexture.active = val; val2 = new Texture2D(mainTexture.width, mainTexture.height, (TextureFormat)4, false); val2.ReadPixels(new Rect(0f, 0f, (float)mainTexture.width, (float)mainTexture.height), 0, 0); val2.Apply(false); RenderTexture.active = active; Color32[] pixels = val2.GetPixels32(); float r = target.r; float g = target.g; float b = target.b; for (int i = 0; i < pixels.Length; i++) { Color32 val3 = pixels[i]; float num = (0.299f * (float)(int)val3.r + 0.587f * (float)(int)val3.g + 0.114f * (float)(int)val3.b) / 255f; float num2 = 0.45f + 0.55f * num; pixels[i] = new Color32((byte)Math.Min(255f, r * 255f * num2), (byte)Math.Min(255f, g * 255f * num2), (byte)Math.Min(255f, b * 255f * num2), val3.a); } Texture2D val4 = new Texture2D(mainTexture.width, mainTexture.height, (TextureFormat)4, false); val4.SetPixels32(pixels); val4.Apply(true); ((Object)val4).name = ((Object)mainTexture).name + "_heybooboo_tint"; TintCache[key] = val4; material.mainTexture = (Texture)(object)val4; material.color = Color.white; return true; } catch (Exception ex) { Debug.LogWarning((object)("[TameableBears] [Colors] texture remap failed on '" + ((Object)material).name + "': " + ex.Message)); return false; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { RenderTexture.ReleaseTemporary(val); } if ((Object)(object)val2 != (Object)null) { Object.DestroyImmediate((Object)(object)val2); } } } private static void Log(string message) { if (BearColorConfig.DebugLog != null && BearColorConfig.DebugLog.Value) { Debug.Log((object)("[TameableBears] [Colors] " + message)); } } } internal static class BreedingConfig { public static ConfigEntry<bool> Enabled; public static ConfigEntry<float> FedDuration; public static ConfigEntry<int> MaxCreatures; public static ConfigEntry<float> TotalCheckRange; public static ConfigEntry<float> PartnerCheckRange; public static ConfigEntry<float> PregnancyChance; public static ConfigEntry<int> RequiredLovePoints; public static ConfigEntry<float> PregnancyDuration; public static ConfigEntry<float> UpdateInterval; public static ConfigEntry<bool> Debug; } public static class Breeding { public static string TargetPrefabName; public static void ApplyOverrides(GameObject bear, Tameable tameable, Procreation procreation) { if (BreedingConfig.Enabled != null && BreedingConfig.Enabled.Value) { tameable.m_fedDuration = BreedingConfig.FedDuration.Value; procreation.m_updateInterval = BreedingConfig.UpdateInterval.Value; procreation.m_totalCheckRange = BreedingConfig.TotalCheckRange.Value; procreation.m_maxCreatures = BreedingConfig.MaxCreatures.Value; procreation.m_partnerCheckRange = BreedingConfig.PartnerCheckRange.Value; procreation.m_pregnancyChance = BreedingConfig.PregnancyChance.Value; procreation.m_pregnancyDuration = BreedingConfig.PregnancyDuration.Value; procreation.m_requiredLovePoints = BreedingConfig.RequiredLovePoints.Value; } } } [HarmonyPatch(typeof(Procreation), "Procreate")] internal static class Procreate_DebugPatch { private static readonly Dictionary<int, float> LastLog = new Dictionary<int, float>(); private const float ThrottleSeconds = 20f; private static void Postfix(Procreation __instance) { //IL_00e1: 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_0142: 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) if (BreedingConfig.Debug == null || !BreedingConfig.Debug.Value) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(component.GetZDO().GetPrefab()) : null); string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : null); if (string.IsNullOrEmpty(Breeding.TargetPrefabName) || text != Breeding.TargetPrefabName) { return; } Tameable component2 = ((Component)__instance).GetComponent<Tameable>(); if (!((Object)(object)component2 == (Object)null) && component2.IsTamed()) { float time = Time.time; if (!LastLog.TryGetValue(((Object)__instance).GetInstanceID(), out var value) || !(time - value < 20f)) { LastLog[((Object)__instance).GetInstanceID()] = time; BaseAI component3 = ((Component)__instance).GetComponent<BaseAI>(); Vector3 position = ((Component)__instance).transform.position; long num = component.GetZDO().GetLong(ZDOVars.s_pregnant, 0L); bool flag = num != 0; bool flag2 = flag && (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds > (double)__instance.m_pregnancyDuration; int num2 = (((Object)(object)val != (Object)null) ? SpawnSystem.GetNrOfInstances(val, position, __instance.m_totalCheckRange, false, false) : (-1)); int num3 = (((Object)(object)val != (Object)null) ? SpawnSystem.GetNrOfInstances(val, position, __instance.m_partnerCheckRange, false, true) : (-1)); Debug.Log((object)$"[TameableBears] [Breeding] {text}: owner={component.IsOwner()} tamed={true} hungry={component2.IsHungry()} alert={(Object)(object)component3 != (Object)null && component3.IsAlerted()} love={__instance.GetLovePoints()}/{__instance.m_requiredLovePoints} pregnant={flag} due={flag2} pair={num3} total={num2}/{__instance.m_maxCreatures} (tcr={__instance.m_totalCheckRange} pcr={__instance.m_partnerCheckRange})"); } } } } [BepInPlugin("wayfarers.tameablebears", "HeyBooBoo!", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string GUID = "wayfarers.tameablebears"; public const string Name = "HeyBooBoo!"; public const string Version = "1.2.0"; private void Awake() { BearBabySizer.BabyScale = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "BabyScale", 0.3f, "Spawn scale of newborn (bred) bears. 1.0 = adult size."); BearBabySizer.GrowTime = ((BaseUnityPlugin)this).Config.Bind<float>("Growth", "GrowTime", 1800f, "Seconds for a baby bear to grow to full size. 1800 = one Valheim day."); BearBabySizer.DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Growth", "DebugLog", false, "Log baby-size decisions (newborn detected / finished growing)."); BreedingConfig.Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Breeding", "Enabled", true, "Enable bear breeding."); BreedingConfig.FedDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "FedDuration", 7200f, "Seconds a bear stays 'fed' after eating (breeding is blocked while hungry)."); BreedingConfig.MaxCreatures = ((BaseUnityPlugin)this).Config.Bind<int>("Breeding", "MaxCreatures", 30, "Max bears (tamed+wild, incl. cubs) allowed within TotalCheckRange before breeding stops."); BreedingConfig.TotalCheckRange = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "TotalCheckRange", 20f, "Radius used for the total-bear count."); BreedingConfig.PartnerCheckRange = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "PartnerCheckRange", 30f, "Radius a second tamed bear must be within for a pair."); BreedingConfig.PregnancyChance = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "PregnancyChance", 0.25f, "Chance per tick to gain a love point (0..1)."); BreedingConfig.RequiredLovePoints = ((BaseUnityPlugin)this).Config.Bind<int>("Breeding", "RequiredLovePoints", 5, "Love points needed before the bear gets pregnant."); BreedingConfig.PregnancyDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "PregnancyDuration", 1800f, "Seconds a bear stays pregnant before giving birth. 1800 = one Valheim day."); BreedingConfig.UpdateInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "UpdateInterval", 2f, "Seconds between breeding checks."); BreedingConfig.Debug = ((BaseUnityPlugin)this).Config.Bind<bool>("Breeding", "DebugLog", false, "Log one breeding status line per tamed bear every ~20 seconds."); BearColorConfig.Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Bear Colors", "Enabled", true, "Cubs born to tamed bears can inherit a rare colour variant: Cinnamon, Black & White."); BearColorConfig.CinnamonChance = ((BaseUnityPlugin)this).Config.Bind<float>("Bear Colors", "CinnamonChance", 0.05f, "Chance a newborn cub is Cinnamon (reddish-brown), 0..1. 0.05 = 5%."); BearColorConfig.BlackChance = ((BaseUnityPlugin)this).Config.Bind<float>("Bear Colors", "BlackChance", 0.05f, "Chance a newborn cub is Black, 0..1. 0.05 = 5%."); BearColorConfig.WhiteChance = ((BaseUnityPlugin)this).Config.Bind<float>("Bear Colors", "WhiteChance", 0.05f, "Chance a newborn cub is White, 0..1. 0.05 = 5%."); BearColorConfig.ForceVariant = ((BaseUnityPlugin)this).Config.Bind<string>("Bear Colors", "ForceVariant", "", "Test only: force every newborn cub to Cinnamon, Black or White. Leave empty to roll normally."); BearColorConfig.TintMode = ((BaseUnityPlugin)this).Config.Bind<string>("Bear Colors", "TintMode", "Texture", "Texture = recolour the fur texture, the only mode that can produce White. Flat = multiply the material colour, which can only darken."); BearColorConfig.TintEyes = ((BaseUnityPlugin)this).Config.Bind<bool>("Bear Colors", "TintEyes", false, "Also tint eyes, claws and teeth. Off by default so they keep their natural colour."); BearColorConfig.ResetColors = ((BaseUnityPlugin)this).Config.Bind<bool>("Bear Colors", "ResetColors", false, "Forget every cub's stored colour decision and re-roll from the chances below. Turn this on, load the world, then turn it back off."); BearColorConfig.DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Bear Colors", "DebugLog", false, "Log the roll result and which materials were recoloured."); Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, (string)null); PrefabManager.OnVanillaPrefabsAvailable += MakeBearsTameable; } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= MakeBearsTameable; } private void MakeBearsTameable() { GameObject prefab = Cache.GetPrefab<GameObject>("Wolf"); GameObject val = null; string text = null; string[] array = new string[2] { "Bjorn", "Bear" }; foreach (string text2 in array) { GameObject prefab2 = Cache.GetPrefab<GameObject>(text2); if ((Object)(object)prefab2 != (Object)null && (Object)(object)prefab2.GetComponent<MonsterAI>() != (Object)null) { val = prefab2; text = text2; break; } } if ((Object)(object)prefab == (Object)null || (Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Missing prefabs (wolf={(Object)(object)prefab != (Object)null} bear={(Object)(object)val != (Object)null})"); return; } Tameable component = prefab.GetComponent<Tameable>(); MonsterAI component2 = prefab.GetComponent<MonsterAI>(); MonsterAI component3 = val.GetComponent<MonsterAI>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Missing components (wolfTameable={(Object)(object)component != (Object)null} wolfAI={(Object)(object)component2 != (Object)null} bearAI={(Object)(object)component3 != (Object)null})"); return; } component3.m_consumeItems = new List<ItemDrop>(component2.m_consumeItems); component3.m_consumeRange = component2.m_consumeRange; component3.m_consumeSearchRange = component2.m_consumeSearchRange; component3.m_consumeSearchInterval = component2.m_consumeSearchInterval; if ((Object)(object)val.GetComponent<Tameable>() != (Object)null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Bear already has a Tameable component; nothing to do."); return; } Tameable val2 = val.AddComponent<Tameable>(); val2.m_tamingTime = component.m_tamingTime; val2.m_fedDuration = component.m_fedDuration; val2.m_commandable = component.m_commandable; val2.m_tameText = component.m_tameText; val2.m_nameBeforeText = component.m_nameBeforeText; val2.m_tamingSpeedMultiplierRange = component.m_tamingSpeedMultiplierRange; val2.m_tamingBoostMultiplier = component.m_tamingBoostMultiplier; val2.m_tamedEffect = component.m_tamedEffect; val2.m_sootheEffect = component.m_sootheEffect; val2.m_petEffect = component.m_petEffect; val2.m_randomStartingName = new List<string>(component.m_randomStartingName); Procreation component4 = prefab.GetComponent<Procreation>(); Procreation component5 = val.GetComponent<Procreation>(); if ((Object)(object)component4 != (Object)null && (Object)(object)component5 == (Object)null) { component5 = val.AddComponent<Procreation>(); component5.m_updateInterval = component4.m_updateInterval; component5.m_totalCheckRange = component4.m_totalCheckRange; component5.m_maxCreatures = component4.m_maxCreatures; component5.m_partnerCheckRange = component4.m_partnerCheckRange; component5.m_pregnancyChance = component4.m_pregnancyChance; component5.m_pregnancyDuration = component4.m_pregnancyDuration; component5.m_requiredLovePoints = component4.m_requiredLovePoints; component5.m_offspring = val; component5.m_minOffspringLevel = component4.m_minOffspringLevel; component5.m_spawnOffset = component4.m_spawnOffset; component5.m_spawnOffsetMax = component4.m_spawnOffsetMax; component5.m_spawnRandomDirection = component4.m_spawnRandomDirection; component5.m_birthEffects = component4.m_birthEffects; component5.m_loveEffects = component4.m_loveEffects; Breeding.TargetPrefabName = text; Breeding.ApplyOverrides(val, val2, component5); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Bears can now breed (pairs of fed, tamed bears produce cubs)."); } if ((Object)(object)val.GetComponent<BearBabySizer>() == (Object)null) { val.AddComponent<BearBabySizer>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Baby bears spawn small and grow to full size (" + text + ").")); } if ((Object)(object)val.GetComponent<BearColorizer>() == (Object)null) { val.AddComponent<BearColorizer>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Rare colour variants can appear on cubs (Cinnamon, Black & White)."); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Bears are now tameable! Feed them raw meat, drop it near them, and wait (like wolves)."); } } }