Decompiled source of EarlyBirdSacrifice v1.0.0

EarlyBirdSacrifice.dll

Decompiled 3 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using On.RoR2;
using On.RoR2.Artifacts;
using On.RoR2.UI;
using RoR2;
using RoR2.Artifacts;
using RoR2.UI;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("EarlyBirdSacrifice")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("EarlyBirdSacrifice")]
[assembly: AssemblyTitle("EarlyBirdSacrifice")]
[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 EarlyBirdSacrifice
{
	[BepInPlugin("com.FortressForce.earlybirdsacrifice", "EarlyBirdSacrifice", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public class SyncSacrificeMessage : MessageBase
		{
			public float currentKillProgress;

			public int itemsDroppedInStage;

			public float killsNeededPerDrop;

			public int bufferRemainingInStage;

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(currentKillProgress);
				writer.Write(itemsDroppedInStage);
				writer.Write(killsNeededPerDrop);
				writer.Write(bufferRemainingInStage);
			}

			public override void Deserialize(NetworkReader reader)
			{
				currentKillProgress = reader.ReadSingle();
				itemsDroppedInStage = reader.ReadInt32();
				killsNeededPerDrop = reader.ReadSingle();
				bufferRemainingInStage = reader.ReadInt32();
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static NetworkMessageDelegate <0>__OnSyncMessage;
		}

		public const string PluginGUID = "com.FortressForce.earlybirdsacrifice";

		public const string PluginName = "EarlyBirdSacrifice";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		public static ConfigEntry<int> BufferCount;

		public static ConfigEntry<int> BaseKillRequirement;

		public static ConfigEntry<int> KillTaxPerDrop;

		public static ConfigEntry<string> EliteBossDropMode;

		public static ConfigEntry<int> EliteKillWeight;

		public static ConfigEntry<int> BossKillWeight;

		public static ConfigEntry<float> EliteExtraDropChance;

		public static ConfigEntry<float> BossExtraDropChance;

		public static ConfigEntry<bool> ForceConsoleLogging;

		public static ConfigEntry<int> StageBufferBonus;

		public static ConfigEntry<int> StageBonusTax;

		public static ConfigEntry<string> DoppelgangerDropMode;

		public static ConfigEntry<float> DoppelgangerDropChance;

		public static ConfigEntry<float> DoppelgangerBossWeight;

		public static ConfigEntry<float> DoppelgangerLegendaryWeight;

		public static ConfigEntry<float> DoppelgangerUncommonWeight;

		public static ConfigEntry<float> DoppelgangerVoidUncommonWeight;

		public static ConfigEntry<bool> EnableGUI;

		public static ConfigEntry<float> GUIPositionX;

		public static ConfigEntry<float> GUIPositionY;

		public static ConfigEntry<float> GUIFontSize;

		public static ConfigEntry<bool> AutoScaleForSwarms;

		public static ConfigEntry<bool> AutoScaleForSoul;

		private static float currentKillProgress = 0f;

		private static int itemsDroppedInStage = 0;

		private static float killsNeededPerDrop = 1f;

		private static int bufferRemainingInStage = 5;

		private static HGTextMeshProUGUI hudTextComponent = null;

		private void Awake()
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Expected O, but got Unknown
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Expected O, but got Unknown
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Expected O, but got Unknown
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BufferCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "BufferCount", 5, "Number of initial 'free' drops before the kill tax increases.");
			BaseKillRequirement = ((BaseUnityPlugin)this).Config.Bind<int>("General", "BaseKillRequirement", 1, "The initial number of kills required per drop during the first buffer.");
			KillTaxPerDrop = ((BaseUnityPlugin)this).Config.Bind<int>("General", "KillTaxPerDrop", 1, "The additional kills added to the requirement each time the buffer is depleted.");
			EliteBossDropMode = ((BaseUnityPlugin)this).Config.Bind<string>("General", "EliteBossDropMode", "percent", new ConfigDescription("Determines how Elite and Boss/Champion deaths are handled regarding item drops and kill progression.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "percent", "extra credit", "both" }), Array.Empty<object>()));
			EliteKillWeight = ((BaseUnityPlugin)this).Config.Bind<int>("General", "EliteKillWeight", 2, "How many normal kills an Elite enemy counts as toward the progress bar (only active if EliteBossDropMode is 'extra credit' or 'both').");
			BossKillWeight = ((BaseUnityPlugin)this).Config.Bind<int>("General", "BossKillWeight", 5, "How many normal kills a Boss/Champion enemy counts as toward the progress bar (only active if EliteBossDropMode is 'extra credit' or 'both').");
			EliteExtraDropChance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "EliteExtraDropChance", 3f, "Percent chance (0-100) that an Elite enemy triggers an extra lucky drop on death (enabled by default).");
			BossExtraDropChance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "BossExtraDropChance", 30f, "Percent chance (0-100) that a Boss/Champion triggers an extra lucky drop on death (enabled by default).");
			ForceConsoleLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ForceConsoleLogging", false, "Set to true to force progress updates as Info logs (visible by default) in the BepInEx console.");
			StageBufferBonus = ((BaseUnityPlugin)this).Config.Bind<int>("General", "StageBufferBonus", 2, "Additional free drops added to the stage buffer for each stage cleared in the run.");
			StageBonusTax = ((BaseUnityPlugin)this).Config.Bind<int>("General", "StageBonusTax", 1, "Additional base kills required per drop for each stage cleared in the run.");
			DoppelgangerDropMode = ((BaseUnityPlugin)this).Config.Bind<string>("Vengeance", "DoppelgangerDropMode", "Boss", new ConfigDescription("The tier of item dropped by Vengeance doppelgangers on death.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[5] { "Boss", "Legendary", "Void Uncommon", "Uncommon", "Random" }), Array.Empty<object>()));
			DoppelgangerDropChance = ((BaseUnityPlugin)this).Config.Bind<float>("Vengeance", "DoppelgangerDropChance", 100f, "Percent chance (0-100) that a Vengeance doppelganger will drop its configured special item on death.");
			DoppelgangerBossWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Vengeance Weights", "DoppelgangerBossWeight", 40f, "Percentage weight for dropping a Boss item when DoppelgangerDropMode is 'Random'.");
			DoppelgangerLegendaryWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Vengeance Weights", "DoppelgangerLegendaryWeight", 30f, "Percentage weight for dropping a Legendary item when DoppelgangerDropMode is 'Random'.");
			DoppelgangerUncommonWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Vengeance Weights", "DoppelgangerUncommonWeight", 20f, "Percentage weight for dropping an Uncommon item when DoppelgangerDropMode is 'Random'.");
			DoppelgangerVoidUncommonWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Vengeance Weights", "DoppelgangerVoidUncommonWeight", 10f, "Percentage weight for dropping a Void Uncommon item when DoppelgangerDropMode is 'Random'.");
			EnableGUI = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "EnableGUI", true, "Should the on-screen HUD progress text be visible?");
			GUIPositionX = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "GUIPositionX", -40f, "Horizontal anchored position from the right side of the screen.");
			GUIPositionY = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "GUIPositionY", -360f, "Vertical anchored position from the top of the screen (sits perfectly below the teleporter tracker).");
			GUIFontSize = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "GUIFontSize", 14f, "The font size of the HUD tracker text.");
			AutoScaleForSwarms = ((BaseUnityPlugin)this).Config.Bind<bool>("Balance Scaling", "AutoScaleForSwarms", true, "If true, automatically halves the required kills and taxes if the Artifact of Swarms is NOT active (since Swarms doubles spawns).");
			AutoScaleForSoul = ((BaseUnityPlugin)this).Config.Bind<bool>("Balance Scaling", "AutoScaleForSoul", true, "If true, automatically halves the required kills and taxes if the Artifact of Soul is NOT active (since Soul wisps yield extra kills).");
			SacrificeArtifactManager.OnServerCharacterDeath += new hook_OnServerCharacterDeath(SacrificeArtifactManager_OnServerCharacterDeath);
			Run.Start += new hook_Start(Run_Start);
			HUD.Awake += new hook_Awake(HUD_Awake);
			Stage.onStageStartGlobal += OnStageStart;
			Log.LogInfo((object)"EarlyBirdSacrifice has successfully initialized!");
		}

		private void OnDestroy()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			Stage.onStageStartGlobal -= OnStageStart;
			SacrificeArtifactManager.OnServerCharacterDeath -= new hook_OnServerCharacterDeath(SacrificeArtifactManager_OnServerCharacterDeath);
			Run.Start -= new hook_Start(Run_Start);
			HUD.Awake -= new hook_Awake(HUD_Awake);
		}

		private static void LogProgress(string message)
		{
			if (ForceConsoleLogging.Value)
			{
				Log.LogInfo((object)message);
			}
			else
			{
				Log.LogDebug((object)message);
			}
		}

		private void Run_Start(orig_Start orig, Run self)
		{
			orig.Invoke(self);
			if (NetworkServer.active)
			{
				currentKillProgress = 0f;
				itemsDroppedInStage = 0;
				int num = (((Object)(object)self != (Object)null) ? self.stageClearCount : 0);
				float artifactScaleFactor = GetArtifactScaleFactor();
				killsNeededPerDrop = (float)(BaseKillRequirement.Value + num * StageBonusTax.Value) * artifactScaleFactor;
				if (killsNeededPerDrop < 1f)
				{
					killsNeededPerDrop = 1f;
				}
				bufferRemainingInStage = BufferCount.Value + num * StageBufferBonus.Value;
				LogProgress($"New run started! Resetting Early Bird Sacrifice counters. Clear count: {num}. Artifact Scale: {artifactScaleFactor:F2}. Required kills: {killsNeededPerDrop:F1}, Stage buffer size: {bufferRemainingInStage}");
				UpdateHUDText();
				SyncState();
			}
		}

		private void OnStageStart(Stage stage)
		{
			if (NetworkServer.active)
			{
				currentKillProgress = 0f;
				itemsDroppedInStage = 0;
				int num = (((Object)(object)Run.instance != (Object)null) ? Run.instance.stageClearCount : 0);
				float artifactScaleFactor = GetArtifactScaleFactor();
				killsNeededPerDrop = (float)(BaseKillRequirement.Value + num * StageBonusTax.Value) * artifactScaleFactor;
				if (killsNeededPerDrop < 1f)
				{
					killsNeededPerDrop = 1f;
				}
				bufferRemainingInStage = BufferCount.Value + num * StageBufferBonus.Value;
				string text = (((Object)(object)stage != (Object)null && (Object)(object)stage.sceneDef != (Object)null) ? stage.sceneDef.cachedName : "Unknown");
				LogProgress($"New stage entered ({text})! Resetting Early Bird Sacrifice counters. Clear count: {num}. Artifact Scale: {artifactScaleFactor:F2}. Required kills: {killsNeededPerDrop:F1}, Stage buffer size: {bufferRemainingInStage}");
				UpdateHUDText();
				SyncState();
			}
		}

		private static Transform FindChildRecursive(Transform parent, string name)
		{
			if (((Object)parent).name == name)
			{
				return parent;
			}
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform val = FindChildRecursive(parent.GetChild(i), name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private void HUD_Awake(orig_Awake orig, HUD self)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_014c: 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_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Expected O, but got Unknown
			orig.Invoke(self);
			if (!EnableGUI.Value)
			{
				return;
			}
			try
			{
				GameObject val = new GameObject("EarlyBirdSacrificeHUDText");
				val.layer = 5;
				RectTransform val2 = val.AddComponent<RectTransform>();
				Transform val3 = null;
				ObjectivePanelController componentInChildren = ((Component)self).GetComponentInChildren<ObjectivePanelController>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					val3 = ((Component)componentInChildren).transform;
					LogProgress("ObjectivePanelController component found successfully.");
				}
				else
				{
					val3 = FindChildRecursive(((Component)self).transform, "ObjectiveCluster");
					if ((Object)(object)val3 == (Object)null)
					{
						val3 = FindChildRecursive(((Component)self).transform, "ObjectivePanel");
					}
					if ((Object)(object)val3 != (Object)null)
					{
						LogProgress("ObjectiveCluster found via recursive name search: " + ((Object)val3).name);
					}
				}
				if ((Object)(object)val3 != (Object)null)
				{
					val.transform.SetParent(val3, false);
					val.transform.SetAsLastSibling();
					LayoutElement obj = val.AddComponent<LayoutElement>();
					obj.minHeight = 45f;
					obj.preferredHeight = 45f;
					val2.anchorMin = new Vector2(0f, 0f);
					val2.anchorMax = new Vector2(1f, 1f);
					val2.pivot = new Vector2(0.5f, 0.5f);
					LogProgress("HUD Text attached as child of Objective panel.");
				}
				else
				{
					val.transform.SetParent(self.mainContainer.transform, false);
					val2.anchorMin = new Vector2(1f, 1f);
					val2.anchorMax = new Vector2(1f, 1f);
					val2.pivot = new Vector2(1f, 1f);
					val2.anchoredPosition = new Vector2(GUIPositionX.Value, GUIPositionY.Value);
					val2.sizeDelta = new Vector2(250f, 65f);
					LogProgress("Objective Cluster container not found. Falling back to mainContainer manual offsets.");
				}
				hudTextComponent = val.AddComponent<HGTextMeshProUGUI>();
				TMP_FontAsset val4 = null;
				HGTextMeshProUGUI[] componentsInChildren = ((Component)self).GetComponentsInChildren<HGTextMeshProUGUI>(true);
				foreach (HGTextMeshProUGUI val5 in componentsInChildren)
				{
					if ((Object)(object)val5 != (Object)null && (Object)(object)((TMP_Text)val5).font != (Object)null)
					{
						val4 = ((TMP_Text)val5).font;
						break;
					}
				}
				if ((Object)(object)val4 != (Object)null)
				{
					((TMP_Text)hudTextComponent).font = val4;
				}
				((TMP_Text)hudTextComponent).fontSize = GUIFontSize.Value;
				((TMP_Text)hudTextComponent).alignment = (TextAlignmentOptions)258;
				((Graphic)hudTextComponent).color = new Color(0.9f, 0.9f, 0.9f, 1f);
				val.SetActive(true);
				UpdateHUDText();
				try
				{
					if ((Object)(object)NetworkManager.singleton != (Object)null && NetworkManager.singleton.client != null)
					{
						short num = 1337;
						NetworkClient client = NetworkManager.singleton.client;
						if (!client.handlers.ContainsKey(num))
						{
							object obj2 = <>O.<0>__OnSyncMessage;
							if (obj2 == null)
							{
								NetworkMessageDelegate val6 = OnSyncMessage;
								<>O.<0>__OnSyncMessage = val6;
								obj2 = (object)val6;
							}
							client.RegisterHandler(num, (NetworkMessageDelegate)obj2);
							LogProgress("Registered client network sync message handler successfully.");
						}
					}
				}
				catch (Exception ex)
				{
					Log.LogError((object)("Failed to register client message handler: " + ex.Message));
				}
				LogProgress("HUD Text initialized successfully using HGTextMeshProUGUI.");
			}
			catch (Exception ex2)
			{
				Log.LogError((object)("Failed to initialize HUD text: " + ex2.Message));
			}
		}

		private static void UpdateHUDText()
		{
			if ((Object)(object)hudTextComponent == (Object)null)
			{
				return;
			}
			if ((Object)(object)Run.instance == (Object)null || (Object)(object)RunArtifactManager.instance == (Object)null || !RunArtifactManager.instance.IsArtifactEnabled(Artifacts.Sacrifice))
			{
				((TMP_Text)hudTextComponent).text = "";
				return;
			}
			int stageClearCount = Run.instance.stageClearCount;
			float artifactScaleFactor = GetArtifactScaleFactor();
			float num = (float)(BaseKillRequirement.Value + stageClearCount * StageBonusTax.Value) * artifactScaleFactor;
			if (num < 1f)
			{
				num = 1f;
			}
			int num2 = BufferCount.Value + stageClearCount * StageBufferBonus.Value;
			string text = "";
			text = ((bufferRemainingInStage <= 0 || !(killsNeededPerDrop <= num + 0.01f)) ? $"Sacrifice:\n{currentKillProgress:F0}/{killsNeededPerDrop:F0} kills needed" : $"Sacrifice:\n{itemsDroppedInStage}/{num2} drops");
			((TMP_Text)hudTextComponent).text = text;
		}

		private void SacrificeArtifactManager_OnServerCharacterDeath(orig_OnServerCharacterDeath orig, DamageReport damageReport)
		{
			bool flag = false;
			try
			{
				if ((Object)(object)damageReport.victimBody.inventory != (Object)null && damageReport.victimBody.inventory.GetItemCountEffective(Items.InvadingDoppelganger) > 0)
				{
					flag = true;
				}
			}
			catch (Exception)
			{
			}
			if (flag)
			{
				float num = Random.Range(0f, 100f);
				if (num <= DoppelgangerDropChance.Value)
				{
					SpawnSpecialDoppelgangerDrop(damageReport);
				}
				else
				{
					LogProgress($"Vengeance doppelganger killed, but rolled no-drop ({num:F1}% vs {DoppelgangerDropChance.Value}% chance).");
				}
				return;
			}
			string text = (EliteBossDropMode.Value ?? "percent").Trim().ToLowerInvariant();
			bool flag2 = text == "extra credit" || text == "both";
			bool flag3 = text == "percent" || text == "both";
			float num2 = 1f;
			if (damageReport.victimBody.isElite)
			{
				if (flag2)
				{
					num2 = EliteKillWeight.Value;
					LogProgress($"Elite killed! Added {num2} to progress (Drop Mode: {text}).");
				}
				else
				{
					LogProgress("Elite killed! Added 1.0 to progress (Drop Mode: " + text + ").");
				}
				if (flag3)
				{
					float num3 = Random.Range(0f, 100f);
					if (num3 <= EliteExtraDropChance.Value)
					{
						SpawnSacrificeDrop(damageReport);
						Log.LogInfo((object)$"Elite lucky drop triggered ({num3:F1}% roll vs {EliteExtraDropChance.Value}% limit)! Spawned bonus item.");
					}
				}
			}
			else if (damageReport.victimBody.isChampion)
			{
				if (flag2)
				{
					num2 = BossKillWeight.Value;
					LogProgress($"Boss/Champion killed! Added {num2} to progress (Drop Mode: {text}).");
				}
				else
				{
					LogProgress("Boss/Champion killed! Added 1.0 to progress (Drop Mode: " + text + ").");
				}
				if (flag3)
				{
					float num4 = Random.Range(0f, 100f);
					if (num4 <= BossExtraDropChance.Value)
					{
						SpawnSacrificeDrop(damageReport);
						Log.LogInfo((object)$"Boss lucky drop triggered ({num4:F1}% roll vs {BossExtraDropChance.Value}% limit)! Spawned bonus item.");
					}
				}
			}
			currentKillProgress += num2;
			LogProgress($"Progress: {currentKillProgress:F1} / {killsNeededPerDrop:F1} (Buffer Remaining: {bufferRemainingInStage}, Stage Drops: {itemsDroppedInStage})");
			while (currentKillProgress >= killsNeededPerDrop)
			{
				currentKillProgress -= killsNeededPerDrop;
				itemsDroppedInStage++;
				SpawnSacrificeDrop(damageReport);
				bufferRemainingInStage--;
				if (bufferRemainingInStage <= 0)
				{
					bufferRemainingInStage = BufferCount.Value;
					float artifactScaleFactor = GetArtifactScaleFactor();
					float num5 = (float)KillTaxPerDrop.Value * artifactScaleFactor;
					killsNeededPerDrop += num5;
					LogProgress($"Buffer depleted! Refilling buffer to {bufferRemainingInStage} and increasing required kills to {killsNeededPerDrop:F1} (added tax: {num5:F2}).");
				}
			}
			UpdateHUDText();
			SyncState();
		}

		private void SpawnSacrificeDrop(DamageReport damageReport)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PickupDropTable val = (PickupDropTable)typeof(SacrificeArtifactManager).GetField("dropTable", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null);
				Xoroshiro128Plus val2 = (Xoroshiro128Plus)typeof(SacrificeArtifactManager).GetField("treasureRng", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null);
				if ((Object)(object)val != (Object)null && val2 != null)
				{
					UniquePickup val3 = val.GeneratePickup(val2);
					if (val3.pickupIndex != PickupIndex.none)
					{
						Vector3 corePosition = damageReport.victimBody.corePosition;
						Vector3 val4 = Vector3.up * 15f + Random.insideUnitSphere * 2f;
						CreatePickupInfo val5 = default(CreatePickupInfo);
						((CreatePickupInfo)(ref val5)).pickup = val3;
						val5.position = corePosition;
						val5.rotation = Quaternion.identity;
						PickupDropletController.CreatePickupDroplet(val5, corePosition, val4);
					}
				}
				else
				{
					Log.LogError((object)"Could not retrieve Sacrifice drop table or RNG via reflection.");
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to spawn deterministic Sacrifice drop: " + ex.Message));
			}
		}

		private void SpawnSpecialDoppelgangerDrop(DamageReport damageReport)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0245: 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_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Xoroshiro128Plus val = (Xoroshiro128Plus)typeof(SacrificeArtifactManager).GetField("treasureRng", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null);
				if (val == null)
				{
					val = Run.instance.treasureRng;
				}
				string text = (DoppelgangerDropMode.Value ?? "Boss").Trim().ToLowerInvariant();
				List<PickupIndex> list = null;
				string text2 = "";
				switch (text)
				{
				case "boss":
					list = Run.instance.availableBossDropList;
					text2 = "Boss";
					break;
				case "legendary":
					list = Run.instance.availableTier3DropList;
					text2 = "Legendary";
					break;
				case "uncommon":
					list = Run.instance.availableTier2DropList;
					text2 = "Uncommon";
					break;
				case "void uncommon":
				{
					List<PickupIndex> availableVoidTier2DropList2 = Run.instance.availableVoidTier2DropList;
					if (availableVoidTier2DropList2 != null && availableVoidTier2DropList2.Count > 0)
					{
						list = availableVoidTier2DropList2;
						text2 = "Void Uncommon";
					}
					else
					{
						list = Run.instance.availableTier2DropList;
						text2 = "Uncommon (Void Uncommon DLC not active fallback)";
					}
					break;
				}
				case "random":
				{
					float num = Mathf.Max(0f, DoppelgangerBossWeight.Value);
					float num2 = Mathf.Max(0f, DoppelgangerLegendaryWeight.Value);
					float num3 = Mathf.Max(0f, DoppelgangerUncommonWeight.Value);
					float num4 = Mathf.Max(0f, DoppelgangerVoidUncommonWeight.Value);
					List<PickupIndex> availableVoidTier2DropList = Run.instance.availableVoidTier2DropList;
					if (availableVoidTier2DropList == null || availableVoidTier2DropList.Count == 0)
					{
						num4 = 0f;
					}
					float num5 = num + num2 + num3 + num4;
					if (num5 <= 0f)
					{
						num = 1f;
						num5 = 1f;
					}
					float num6 = Random.Range(0f, num5);
					if (num6 < num)
					{
						list = Run.instance.availableBossDropList;
						text2 = "Boss (Random Weight)";
					}
					else if (num6 < num + num2)
					{
						list = Run.instance.availableTier3DropList;
						text2 = "Legendary (Random Weight)";
					}
					else if (num6 < num + num2 + num3)
					{
						list = Run.instance.availableTier2DropList;
						text2 = "Uncommon (Random Weight)";
					}
					else
					{
						list = availableVoidTier2DropList;
						text2 = "Void Uncommon (Random Weight)";
					}
					break;
				}
				}
				if (list != null && list.Count > 0)
				{
					int index = val.RangeInt(0, list.Count);
					PickupIndex val2 = list[index];
					if (val2 != PickupIndex.none)
					{
						Vector3 corePosition = damageReport.victimBody.corePosition;
						Vector3 val3 = Vector3.up * 15f + Random.insideUnitSphere * 2f;
						UniquePickup pickup = default(UniquePickup);
						pickup.pickupIndex = val2;
						CreatePickupInfo val4 = default(CreatePickupInfo);
						((CreatePickupInfo)(ref val4)).pickup = pickup;
						val4.position = corePosition;
						val4.rotation = Quaternion.identity;
						PickupDropletController.CreatePickupDroplet(val4, corePosition, val3);
						Log.LogInfo((object)$"Vengeance doppelganger killed! Spawned special item drop. Tier: {text2}, Item: {val2}.");
					}
				}
				else
				{
					Log.LogError((object)("Vengeance doppelganger drop failed: Selected target pool '" + text2 + "' was null or empty."));
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to spawn doppelganger drop: " + ex.Message));
			}
		}

		private static void OnSyncMessage(NetworkMessage netMsg)
		{
			try
			{
				SyncSacrificeMessage syncSacrificeMessage = netMsg.ReadMessage<SyncSacrificeMessage>();
				if (syncSacrificeMessage != null)
				{
					currentKillProgress = syncSacrificeMessage.currentKillProgress;
					itemsDroppedInStage = syncSacrificeMessage.itemsDroppedInStage;
					killsNeededPerDrop = syncSacrificeMessage.killsNeededPerDrop;
					bufferRemainingInStage = syncSacrificeMessage.bufferRemainingInStage;
					UpdateHUDText();
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to handle SyncSacrificeMessage: " + ex.Message));
			}
		}

		private static void SyncState()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			try
			{
				SyncSacrificeMessage syncSacrificeMessage = new SyncSacrificeMessage
				{
					currentKillProgress = currentKillProgress,
					itemsDroppedInStage = itemsDroppedInStage,
					killsNeededPerDrop = killsNeededPerDrop,
					bufferRemainingInStage = bufferRemainingInStage
				};
				NetworkServer.SendToAll((short)1337, (MessageBase)(object)syncSacrificeMessage);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to send SyncSacrificeMessage: " + ex.Message));
			}
		}

		private static float GetArtifactScaleFactor()
		{
			float num = 1f;
			if ((Object)(object)RunArtifactManager.instance != (Object)null)
			{
				if (AutoScaleForSwarms != null && AutoScaleForSwarms.Value && !RunArtifactManager.instance.IsArtifactEnabled(Artifacts.Swarms))
				{
					num *= 0.5f;
				}
				if (AutoScaleForSoul != null && AutoScaleForSoul.Value && !RunArtifactManager.instance.IsArtifactEnabled(Artifacts.WispOnDeath))
				{
					num *= 0.5f;
				}
			}
			return num;
		}
	}
}