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 EarlyBirdSacrifice v1.0.0
EarlyBirdSacrifice.dll
Decompiled 3 hours agousing 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; } } }