using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("MuckMimic")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Some paid chests become a buffed mob that drops the chest's loot. Host-only.")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2+879fc7ac66fec639f2f84b4b7a65d5c61c9ed734")]
[assembly: AssemblyProduct("Mimic")]
[assembly: AssemblyTitle("MuckMimic")]
[assembly: InternalsVisibleTo("MuckMimic.Tests")]
[assembly: AssemblyVersion("0.1.2.0")]
namespace MuckMimic;
[HarmonyPatch(typeof(LootContainerInteract), "ServerExecute", new Type[] { typeof(int) })]
[HarmonyPriority(200)]
internal static class LootContainerServerExecutePatch
{
private static bool Prefix(LootContainerInteract __instance)
{
try
{
return !MimicHost.TryMimic(__instance);
}
catch (Exception arg)
{
MimicPlugin.Log.LogError((object)$"Mimic chest patch failed: {arg}");
bool mimic;
return !(MimicPlugin.Claims.TryGet(__instance, out mimic) && mimic);
}
}
}
internal sealed class MimicClaims
{
private sealed class Box
{
public bool Mimic;
}
private readonly ConditionalWeakTable<object, Box> _claims = new ConditionalWeakTable<object, Box>();
public bool TryGet(object chest, out bool mimic)
{
mimic = false;
if (chest == null)
{
return false;
}
if (!_claims.TryGetValue(chest, out var value))
{
return false;
}
mimic = value.Mimic;
return true;
}
public void Record(object chest, bool mimic)
{
if (chest != null)
{
_claims.GetValue(chest, (object _) => new Box
{
Mimic = mimic
});
}
}
}
internal sealed class MimicConfig
{
public readonly ConfigEntry<bool> Enabled;
public readonly ConfigEntry<float> Chance;
public readonly ConfigEntry<float> MobMultiplier;
public readonly ConfigEntry<int> LateMobFromDay;
public readonly ConfigEntry<string> EarlyMobName;
public readonly ConfigEntry<string> LateMobName;
public readonly ConfigEntry<bool> ExtraWhite;
public readonly ConfigEntry<bool> ChatMessages;
public readonly ConfigEntry<bool> VerboseLogging;
public MimicConfig(ConfigFile cfg)
{
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Expected O, but got Unknown
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Expected O, but got Unknown
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Expected O, but got Unknown
Enabled = cfg.Bind<bool>("Mimic", "Enabled", true, "When false, chests drop loot as usual. Only the host's value is used.");
Chance = cfg.Bind<float>("Mimic", "Chance", 0.06f, new ConfigDescription("Chance from 0 to 1 that a paid chest spawns a mimic instead of loot. The 0.06 default is not from the game. Only the host's value is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
MobMultiplier = cfg.Bind<float>("Mimic", "MobMultiplier", 1.75f, new ConfigDescription("Multiplier passed to the vanilla mob spawn. The Battle Totem uses 1.75, which draws the mob at 1.4 times size and drops 1.25 times mob loot. 1 is allowed and spawns a normal mob, because the game only buffs a multiplier above 1. Only the host's value is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
LateMobFromDay = cfg.Bind<int>("Mimic", "LateMobFromDay", 5, new ConfigDescription("Use LateMobName when GameLoop.currentDay is at least this. In Update 4, currentDay starts at -1 and the first day writes 0, so 5 is the sixth day if you count the opening day as day 1. Only the host's value is used.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
EarlyMobName = cfg.Bind<string>("Mimic", "EarlyMobName", "Goblin", "MobType.name spawned before LateMobFromDay. Update 4 compares kills to the literal Goblin. Only the host's value is used.");
LateMobName = cfg.Bind<string>("Mimic", "LateMobName", "Stone Golem", "MobType.name spawned from LateMobFromDay on. Default Stone Golem, a real Update 4 mob, so every late mimic is a buffed Stone Golem. A name that matches no mob, a boss, or a neutral animal falls back to the Battle Totem pick, and the verbose log lists the real names. Only the host's value is used.");
ExtraWhite = cfg.Bind<bool>("Mimic", "ExtraWhite", true, "When the mimic dies, also drop one White powerup. Only the host's value is used.");
ChatMessages = cfg.Bind<bool>("Mimic", "ChatMessages", true, "Tell the whole lobby, vanilla players included, when a chest turns out to be a mimic and when it drops its loot. Only the host's value is used.");
VerboseLogging = cfg.Bind<bool>("Debug", "VerboseLogging", false, "Log each roll, the mob name table on the first lookup, each spawn, each death, each loot drop, and each stale entry.");
}
public MimicTuning Tuning()
{
return new MimicTuning(Chance.Value, MobMultiplier.Value, LateMobFromDay.Value, EarlyMobName.Value, LateMobName.Value, ExtraWhite.Value);
}
}
internal static class MimicDefaults
{
public const float Chance = 0.06f;
public const float MobMultiplier = 1.75f;
public const int LateMobFromDay = 5;
public const string EarlyMobName = "Goblin";
public const string LateMobName = "Stone Golem";
public const bool ExtraWhite = true;
}
internal static class MimicHost
{
private static readonly Random Rng = new Random();
private static readonly HashSet<string> WarnedNames = new HashSet<string>();
private static bool _loggedMobTable;
public static bool TryMimic(LootContainerInteract chest)
{
if ((Object)(object)chest == (Object)null || !LocalClient.serverOwner)
{
return false;
}
if (!MimicPlugin.Cfg.Enabled.Value)
{
return false;
}
if (MimicPlugin.Claims.TryGet(chest, out var mimic))
{
return mimic;
}
MimicTuning mimicTuning = MimicPlugin.Cfg.Tuning();
bool flag = MimicRoll.IsEligible(chest.price, chest.testPowerup);
float num = 0f;
bool flag2 = false;
if (flag)
{
num = (float)Rng.NextDouble();
flag2 = MimicRoll.Rolls(num, mimicTuning.Chance);
}
if (MimicPlugin.Cfg.VerboseLogging.Value)
{
MimicPlugin.Log.LogInfo((object)(flag ? string.Format("Mimic roll {0} against {1} on a chest priced {2}. Result: {3}.", num, mimicTuning.Chance, chest.price, flag2 ? "mimic" : "normal chest") : $"Mimic skipped a chest priced {chest.price}. Test chest: {chest.testPowerup}."));
}
if (!flag2)
{
MimicPlugin.Claims.Record(chest, mimic: false);
return false;
}
bool flag3 = SpawnMimic(chest, mimicTuning);
MimicPlugin.Claims.Record(chest, flag3);
return flag3;
}
private static bool SpawnMimic(LootContainerInteract chest, MimicTuning tuning)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_020e: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0167: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: 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)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
Vector3 position = ((Component)chest).transform.position;
Vector3 val = Grounded(position);
bool flag = false;
int num = -1;
int[] array = null;
MobManager instance = MobManager.Instance;
try
{
if ((Object)(object)instance == (Object)null || (Object)(object)MobSpawner.Instance == (Object)null)
{
return false;
}
int num2 = ResolveMobType(tuning);
if (num2 < 0)
{
return false;
}
Powerup randomPowerup = ItemManager.Instance.GetRandomPowerup(chest.white, chest.blue, chest.gold);
if ((Object)(object)randomPowerup == (Object)null)
{
return false;
}
int extraWhiteId = -1;
if (tuning.ExtraWhite)
{
Powerup randomPowerup2 = ItemManager.Instance.GetRandomPowerup(1f, 0f, 0f);
if ((Object)(object)randomPowerup2 != (Object)null)
{
extraWhiteId = randomPowerup2.id;
}
}
array = MimicLoot.Ids(randomPowerup.id, tuning.ExtraWhite, extraWhiteId);
num = instance.GetNextId();
MimicPlugin.Claims.Record(chest, mimic: true);
flag = true;
MobSpawner.Instance.ServerSpawnNewMob(num, num2, val, tuning.MobMultiplier, 1f, (BossType)0, -1);
}
catch (Exception arg)
{
MimicPlugin.Log.LogError((object)$"Mimic failed while spawning: {arg}");
if (!flag)
{
return false;
}
}
if ((Object)(object)instance != (Object)null && instance.mobs != null && instance.mobs.ContainsKey(num))
{
MimicPlugin.Ledger.Add(num, array, instance, val.x, val.y, val.z);
if (MimicPlugin.Cfg.VerboseLogging.Value)
{
MimicPlugin.Log.LogInfo((object)string.Format("Mimic spawned mob {0} at ({1}, {2}, {3}) with powerups [{4}].", num, val.x, val.y, val.z, string.Join(", ", array)));
}
Announce("<color=#e8b04a>The chest was a Mimic! Kill it to claim the loot.</color>");
return true;
}
MimicPlugin.Log.LogWarning((object)$"Mimic mob {num} did not register; dropping its loot at the chest.");
DropLoot(array, position);
return true;
}
private static int ResolveMobType(MimicTuning tuning)
{
MobType[] array = (((Object)(object)MobSpawner.Instance != (Object)null) ? MobSpawner.Instance.allMobs : null);
if (array == null)
{
return -1;
}
List<string> list = array.Select((MobType mob) => (!((Object)(object)mob == (Object)null)) ? mob.name : null).ToList();
if (!_loggedMobTable && MimicPlugin.Cfg.VerboseLogging.Value)
{
_loggedMobTable = true;
MimicPlugin.Log.LogInfo((object)("Mimic mob table: " + string.Join(", ", list)));
}
int day = 0;
GameLoop instance = GameLoop.Instance;
if ((Object)(object)instance != (Object)null)
{
day = instance.currentDay;
}
string text = MimicMobPick.PreferredName(day, tuning.LateMobFromDay, tuning.EarlyMobName, tuning.LateMobName);
int num = MimicMobPick.IndexOf(list, text);
if (num >= 0 && Suitable(array[num]))
{
return num;
}
if (num >= 0)
{
if (WarnedNames.Add("bad:" + text))
{
MimicPlugin.Log.LogWarning((object)("Mimic: '" + text + "' is a boss or a neutral animal. Using the Battle Totem pick."));
}
}
else if (WarnedNames.Add(text ?? ""))
{
MimicPlugin.Log.LogWarning((object)("Mimic: no mob named '" + text + "'. Mobs: " + string.Join(", ", list) + ". Using the Battle Totem pick."));
}
try
{
if ((Object)(object)instance == (Object)null)
{
return -1;
}
MobType val = instance.SelectMobToSpawn(true);
return ((Object)(object)val != (Object)null) ? val.id : (-1);
}
catch (Exception arg)
{
MimicPlugin.Log.LogError((object)$"Mimic Battle Totem pick failed: {arg}");
return -1;
}
}
public static void PayOnRemove(MobManager mgr, int mobId)
{
//IL_00e1: 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_00b7: 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)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
if (LocalClient.serverOwner && !((Object)(object)mgr == (Object)null) && MimicPlugin.Ledger.TryGet(mobId, out var pending) && pending.Owner == mgr)
{
Vector3 position = default(Vector3);
((Vector3)(ref position))..ctor(pending.X, pending.Y, pending.Z);
if (mgr.mobs != null && mgr.mobs.TryGetValue(mobId, out var value) && (Object)(object)value != (Object)null)
{
position = ((Component)value).transform.position;
}
MimicPlugin.Ledger.Remove(mobId);
if (MimicPlugin.Cfg.VerboseLogging.Value)
{
MimicPlugin.Log.LogInfo((object)$"Mimic mob {mobId} died. Dropping loot at ({position.x}, {position.y}, {position.z}).");
}
DropLoot(pending.PowerupIds, position);
Announce("<color=#e8b04a>The Mimic dropped its loot.</color>");
}
}
private static void Announce(string line)
{
if (!MimicPlugin.Cfg.ChatMessages.Value)
{
return;
}
try
{
ServerSend.SendChatMessage(-1, "", line);
}
catch (Exception arg)
{
MimicPlugin.Log.LogError((object)$"Mimic chat line failed: {arg}");
}
}
private static bool Suitable(MobType mob)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Invalid comparison between Unknown and I4
if ((Object)(object)mob == (Object)null)
{
return false;
}
if (mob.boss)
{
return false;
}
return (int)mob.behaviour > 0;
}
private static Vector3 Grounded(Vector3 at)
{
//IL_0000: 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_0012: Unknown result type (might be due to invalid IL or missing references)
NavMeshHit val = default(NavMeshHit);
if (NavMesh.SamplePosition(at, ref val, 5f, -1))
{
return ((NavMeshHit)(ref val)).position;
}
return at;
}
public static void DropLoot(int[] ids, Vector3 at)
{
//IL_0007: 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_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: 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_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < ids.Length; i++)
{
Vector3 val = at + new Vector3(MimicLoot.OffsetX(i), 1f, 0f);
int nextId = ItemManager.Instance.GetNextId();
ItemManager.Instance.DropPowerupAtPosition(ids[i], val, nextId);
ServerSend.DropPowerupAtPosition(ids[i], nextId, val);
if (MimicPlugin.Cfg.VerboseLogging.Value)
{
MimicPlugin.Log.LogInfo((object)$"Mimic dropped powerup {ids[i]} as object {nextId} at ({val.x}, {val.y}, {val.z}).");
}
}
}
}
internal sealed class MimicPending
{
public int MobId { get; }
public int[] PowerupIds { get; }
public object Owner { get; }
public float X { get; private set; }
public float Y { get; private set; }
public float Z { get; private set; }
public MimicPending(int mobId, int[] powerupIds, object owner, float x, float y, float z)
{
MobId = mobId;
PowerupIds = powerupIds;
Owner = owner;
X = x;
Y = y;
Z = z;
}
internal void MoveTo(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
}
internal sealed class MimicLedger
{
private readonly Dictionary<int, MimicPending> _entries = new Dictionary<int, MimicPending>();
public int Count => _entries.Count;
public bool Add(int mobId, int[] powerupIds, object owner, float x, float y, float z)
{
if (_entries.ContainsKey(mobId) || powerupIds == null || powerupIds.Length == 0)
{
return false;
}
int[] array = new int[powerupIds.Length];
Array.Copy(powerupIds, array, powerupIds.Length);
_entries[mobId] = new MimicPending(mobId, array, owner, x, y, z);
return true;
}
public List<int> SnapshotIds()
{
List<int> list = new List<int>(_entries.Keys);
list.Sort();
return list;
}
public bool TryGet(int mobId, out MimicPending pending)
{
return _entries.TryGetValue(mobId, out pending);
}
public void Move(int mobId, float x, float y, float z)
{
if (_entries.TryGetValue(mobId, out var value))
{
value.MoveTo(x, y, z);
}
}
public bool Remove(int mobId)
{
return _entries.Remove(mobId);
}
public void Clear()
{
_entries.Clear();
}
}
internal static class MimicLoot
{
public const float DropHeight = 1f;
public const float Spread = 0.75f;
public static int[] Ids(int chestPowerupId, bool extraWhite, int extraWhiteId)
{
if (extraWhite && extraWhiteId >= 0)
{
return new int[2] { chestPowerupId, extraWhiteId };
}
return new int[1] { chestPowerupId };
}
public static float OffsetX(int index)
{
if (index <= 0)
{
return 0f;
}
if (index % 2 == 1)
{
return 0.75f * (float)((index + 1) / 2);
}
return -0.75f * (float)(index / 2);
}
}
internal static class MimicMobPick
{
public static string Normalize(string s)
{
if (s == null)
{
return "";
}
return s.ToLowerInvariant().Replace(" ", "").Replace("_", "")
.Replace("-", "");
}
public static string PreferredName(int day, int lateFromDay, string earlyName, string lateName)
{
if (day < lateFromDay)
{
return earlyName;
}
return lateName;
}
public static int IndexOf(IReadOnlyList<string> names, string wanted)
{
string text = Normalize(wanted);
if (names == null || text.Length == 0)
{
return -1;
}
for (int i = 0; i < names.Count; i++)
{
if (names[i] != null && Normalize(names[i]) == text)
{
return i;
}
}
return -1;
}
}
[BepInPlugin("evan.muck.mimic", "Mimic", "0.1.2")]
public class MimicPlugin : BaseUnityPlugin
{
public const string Guid = "evan.muck.mimic";
public const string Name = "Mimic";
public const string Version = "0.1.2";
internal static ManualLogSource Log;
internal static MimicConfig Cfg;
internal static readonly MimicClaims Claims = new MimicClaims();
internal static readonly MimicLedger Ledger = new MimicLedger();
private void Awake()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Cfg = new MimicConfig(((BaseUnityPlugin)this).Config);
Harmony harmony = new Harmony("evan.muck.mimic");
if (!TryPatch(harmony, typeof(LootContainerServerExecutePatch)))
{
Log.LogError((object)"Mimic disabled: the chest patch failed.");
return;
}
if (!TryPatch(harmony, typeof(MobManagerRemoveMobPatch)))
{
Log.LogWarning((object)"Mimic will drop chest loot from the 0.25 s poll. The RemoveMob patch failed.");
}
MimicRunner.Ensure();
Log.LogInfo((object)"Mimic 0.1.2 loaded. Only the host needs this mod; only the host's [Mimic] settings are used.");
}
private static bool TryPatch(Harmony harmony, Type patchClass)
{
try
{
harmony.CreateClassProcessor(patchClass).Patch();
return true;
}
catch (Exception arg)
{
Log.LogError((object)string.Format("{0} failed to patch {1}: {2}", "Mimic", patchClass.Name, arg));
return false;
}
}
}
internal static class MimicRoll
{
public static bool IsEligible(int price, bool testChest)
{
if (price > 0)
{
return !testChest;
}
return false;
}
public static bool Rolls(float roll, float chance)
{
if (!(chance > 0f))
{
return false;
}
if (chance >= 1f)
{
return true;
}
return roll < chance;
}
}
internal sealed class MimicRunner : MonoBehaviour
{
private static MimicRunner _instance;
private float _timer;
private bool _loggedUpdateFailure;
public static void Ensure()
{
//IL_0013: 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_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
if (!((Object)(object)_instance != (Object)null))
{
GameObject val = new GameObject("MuckMimic")
{
hideFlags = (HideFlags)61
};
Object.DontDestroyOnLoad((Object)val);
_instance = val.AddComponent<MimicRunner>();
}
}
private void OnEnable()
{
SceneManager.activeSceneChanged += OnSceneChanged;
}
private void OnDisable()
{
SceneManager.activeSceneChanged -= OnSceneChanged;
}
private static void OnSceneChanged(Scene previous, Scene next)
{
MimicPlugin.Ledger.Clear();
}
private void Update()
{
try
{
_timer += Time.unscaledDeltaTime;
if (!(_timer < 0.25f))
{
_timer = 0f;
if (LocalClient.serverOwner && MimicPlugin.Ledger.Count != 0)
{
Poll();
}
}
}
catch (Exception arg)
{
_timer = 0f;
if (!_loggedUpdateFailure)
{
_loggedUpdateFailure = true;
MimicPlugin.Log.LogError((object)$"Mimic watch failed: {arg}");
}
}
}
private static void Poll()
{
//IL_009f: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_018c: Unknown result type (might be due to invalid IL or missing references)
MobManager instance = MobManager.Instance;
foreach (int item in MimicPlugin.Ledger.SnapshotIds())
{
try
{
if (!MimicPlugin.Ledger.TryGet(item, out var pending))
{
continue;
}
bool num = (Object)(object)instance != (Object)null && pending.Owner == instance;
Mob value = null;
bool mobPresent = num && instance.mobs != null && instance.mobs.TryGetValue(item, out value) && (Object)(object)value != (Object)null;
switch (MimicWatch.Classify(num, mobPresent))
{
case MimicState.Alive:
{
Vector3 position = ((Component)value).transform.position;
MimicPlugin.Ledger.Move(item, position.x, position.y, position.z);
break;
}
case MimicState.Stale:
MimicPlugin.Ledger.Remove(item);
if (MimicPlugin.Cfg.VerboseLogging.Value)
{
MimicPlugin.Log.LogInfo((object)$"Mimic forgot mob {item}. Its mob manager is gone, so no loot drops.");
}
break;
case MimicState.Dead:
MimicPlugin.Ledger.Remove(item);
if (MimicPlugin.Cfg.VerboseLogging.Value)
{
MimicPlugin.Log.LogInfo((object)$"Mimic mob {item} died. Dropping loot at ({pending.X}, {pending.Y}, {pending.Z}).");
}
MimicHost.DropLoot(pending.PowerupIds, new Vector3(pending.X, pending.Y, pending.Z));
break;
default:
throw new InvalidOperationException("Unknown mimic watch state.");
}
}
catch (Exception arg)
{
MimicPlugin.Log.LogError((object)$"Mimic watch failed for mob {item}: {arg}");
}
}
}
}
internal static class MimicText
{
public const int ChatMaxLength = 120;
public const string Spawned = "<color=#e8b04a>The chest was a Mimic! Kill it to claim the loot.</color>";
public const string Dropped = "<color=#e8b04a>The Mimic dropped its loot.</color>";
}
internal sealed class MimicTuning
{
public float Chance { get; }
public float MobMultiplier { get; }
public int LateMobFromDay { get; }
public string EarlyMobName { get; }
public string LateMobName { get; }
public bool ExtraWhite { get; }
public MimicTuning(float chance, float mobMultiplier, int lateMobFromDay, string earlyMobName, string lateMobName, bool extraWhite)
{
if (float.IsNaN(chance))
{
Chance = 0f;
}
else if (chance < 0f)
{
Chance = 0f;
}
else if (chance > 1f)
{
Chance = 1f;
}
else
{
Chance = chance;
}
if (float.IsNaN(mobMultiplier))
{
MobMultiplier = 1f;
}
else if (mobMultiplier < 1f)
{
MobMultiplier = 1f;
}
else if (mobMultiplier > 10f)
{
MobMultiplier = 10f;
}
else
{
MobMultiplier = mobMultiplier;
}
LateMobFromDay = ((lateMobFromDay >= 0) ? lateMobFromDay : 0);
EarlyMobName = ((earlyMobName == null) ? "" : earlyMobName.Trim());
LateMobName = ((lateMobName == null) ? "" : lateMobName.Trim());
ExtraWhite = extraWhite;
}
}
internal enum MimicState
{
Alive,
Dead,
Stale
}
internal static class MimicWatch
{
public static MimicState Classify(bool ownerMatches, bool mobPresent)
{
if (ownerMatches)
{
if (!mobPresent)
{
return MimicState.Dead;
}
return MimicState.Alive;
}
return MimicState.Stale;
}
}
[HarmonyPatch(typeof(MobManager), "RemoveMob", new Type[] { typeof(int) })]
internal static class MobManagerRemoveMobPatch
{
private static void Prefix(MobManager __instance, int __0)
{
try
{
MimicHost.PayOnRemove(__instance, __0);
}
catch (Exception arg)
{
MimicPlugin.Log.LogError((object)$"Mimic death drop failed for mob {__0}: {arg}");
}
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "MuckMimic";
public const string PLUGIN_NAME = "Mimic";
public const string PLUGIN_VERSION = "0.1.2";
}