Decompiled source of H3TVR v2.0.6
H3TVR.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using FistVR; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using Valve.VR; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace H3TVR { public class AirdropManager : MonoBehaviour { private H3TVRImproved plugin; private ManualLogSource logger; private const string CrateId = "Crate_Wood_1"; private const float SpawnHeight = 40f; private const float ParachuteSlowdown = 0.2f; public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource) { plugin = pluginInstance; logger = logSource; ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Airdrop Manager initialized."); } } public void CallAirdrop(string username) { ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)("Airdrop called in by " + username + "!")); } ((MonoBehaviour)this).StartCoroutine(AirdropSequence()); } private IEnumerator AirdropSequence() { if ((Object)(object)GM.CurrentPlayerBody == (Object)null) { ManualLogSource obj = logger; if (obj != null) { obj.LogError((object)"Cannot start airdrop: Player body not found."); } yield break; } Vector3 spawnPos = ((Component)GM.CurrentPlayerBody).transform.position + Vector3.up * 40f; if (!IM.OD.ContainsKey("Crate_Wood_1")) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)"Cannot start airdrop: Crate template 'Crate_Wood_1' not found."); } yield break; } FVRObject crateTemplate = IM.OD["Crate_Wood_1"]; GameObject crateGO = Object.Instantiate<GameObject>(((AnvilAsset)crateTemplate).GetGameObject(), spawnPos, Quaternion.identity); Rigidbody rb = crateGO.GetComponent<Rigidbody>(); if ((Object)(object)rb == (Object)null) { ManualLogSource obj3 = logger; if (obj3 != null) { obj3.LogError((object)"Airdrop crate has no Rigidbody!"); } Object.Destroy((Object)(object)crateGO); yield break; } rb.drag = 0.2f; bool isHelpful = Random.value < 0.7f; yield return (object)new WaitUntil((Func<bool>)(() => (Object)(object)crateGO == (Object)null || crateGO.transform.position.y < ((Component)GM.CurrentPlayerBody).transform.position.y + 2f)); if ((Object)(object)crateGO != (Object)null) { PopulateCrate(crateGO.transform.position, isHelpful); crateGO.SendMessage("Damage", (object)1000f, (SendMessageOptions)1); ManualLogSource obj4 = logger; if (obj4 != null) { obj4.LogInfo((object)"Airdrop has landed!"); } } } private void PopulateCrate(Vector3 position, bool isHelpful) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (isHelpful) { ManualLogSource obj = logger; if (obj != null) { obj.LogInfo((object)"Airdrop is... HELPFUL!"); } SpawnRandomHelpfulItem(position); SpawnItem("Health_Sausage", position + Vector3.up * 0.1f); } else { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogInfo((object)"Airdrop is... a TROLL!"); } SpawnItem("PinnedGrenadeM67", position); } } private void SpawnRandomHelpfulItem(Vector3 position) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[3] { "MeatBatBaseball", "Health_Sausage", "SuppressorBottle" }; string itemId = array[Random.Range(0, array.Length)]; SpawnItem(itemId, position); } private void SpawnItem(string itemId, Vector3 position) { //IL_0024: 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) try { if (IM.OD.ContainsKey(itemId)) { FVRObject val = IM.OD[itemId]; Object.Instantiate<GameObject>(((AnvilAsset)val).GetGameObject(), position, Quaternion.identity); return; } ManualLogSource obj = logger; if (obj != null) { obj.LogWarning((object)("Item '" + itemId + "' not found in ObjectDictionary")); } } catch (Exception ex) { ManualLogSource obj2 = logger; if (obj2 != null) { obj2.LogError((object)("Failed to spawn item '" + itemId + "': " + ex.Message)); } } } } public class ConfigurationManager { private readonly ConfigFile config; private readonly ManualLogSource logger; private float cachedMaxSlomo; private float cachedSlomoWaitTime; private float cachedSlomoScaleSpeed; private float cachedSlomoReturnSpeed; private bool cachedSlomoUseRamp; private string cachedSlomoRampCurve; private float cachedSlomoRampDuration; private float cachedSlomoReturnRampDuration; private bool cachedEnableInfiniteTokens; private bool cachedDisableEncryptionNodes; private bool cachedDisableAllEncryptions; public ConfigEntry<float> MaxSlomo { get; private set; } public ConfigEntry<float> SlomoWaitTime { get; private set; } public ConfigEntry<float> SlomoScaleSpeed { get; private set; } public ConfigEntry<float> SlomoReturnSpeed { get; private set; } public ConfigEntry<bool> SlomoVRControllerEnabled { get; private set; } public ConfigEntry<string> SlomoVRButton { get; private set; } public ConfigEntry<bool> SlomoAffectsMovement { get; private set; } public ConfigEntry<float> SlomoMovementScale { get; private set; } public ConfigEntry<bool> SlomoUseRampSpeed { get; private set; } public ConfigEntry<string> SlomoRampCurve { get; private set; } public ConfigEntry<float> SlomoRampDuration { get; private set; } public ConfigEntry<float> SlomoReturnRampDuration { get; private set; } public ConfigEntry<bool> EnableKillSlomo { get; private set; } public ConfigEntry<bool> SlomoAffectsAudio { get; private set; } public ConfigEntry<bool> UseItemManagerForGunRandomization { get; private set; } public ConfigEntry<string> GunList { get; private set; } public ConfigEntry<string> MagazineList { get; private set; } public ConfigEntry<float> ShurikenScale { get; private set; } public ConfigEntry<int> ShurikenMinCount { get; private set; } public ConfigEntry<int> ShurikenMaxCount { get; private set; } public ConfigEntry<int> PillowMinCount { get; private set; } public ConfigEntry<int> PillowMaxCount { get; private set; } public ConfigEntry<bool> PillowGrenadeEnabled { get; private set; } public ConfigEntry<float> PillowGrenadeChance { get; private set; } public ConfigEntry<float> PillowGrenadeArmedChance { get; private set; } public ConfigEntry<bool> PillowZeroGravityEnabled { get; private set; } public ConfigEntry<float> PillowZeroGravityChance { get; private set; } public ConfigEntry<float> PillowZeroGravityDuration { get; private set; } public ConfigEntry<bool> PillowSlomoEnabled { get; private set; } public ConfigEntry<float> PillowSlomoChance { get; private set; } public ConfigEntry<float> PillowSlomoDuration { get; private set; } public ConfigEntry<int> DangerCloseMinCount { get; private set; } public ConfigEntry<int> DangerCloseMaxCount { get; private set; } public Dictionary<string, ConfigEntry<KeyCode>> KeyBindings { get; private set; } = new Dictionary<string, ConfigEntry<KeyCode>>(); public ConfigEntry<bool> EnableInfiniteTokens { get; private set; } public ConfigEntry<bool> DisableEncryptionNodes { get; private set; } public ConfigEntry<bool> DisableAllEncryptions { get; private set; } public ConfigEntry<bool> DisableEncryptionType1 { get; private set; } public ConfigEntry<bool> DisableEncryptionType2 { get; private set; } public ConfigEntry<bool> DisableEncryptionType3 { get; private set; } public ConfigEntry<bool> AutoCompleteEncryption { get; private set; } public ConfigEntry<float> EncryptionCompletionDelay { get; private set; } public float CachedMaxSlomo => cachedMaxSlomo; public float CachedSlomoWaitTime => cachedSlomoWaitTime; public float CachedSlomoScaleSpeed => cachedSlomoScaleSpeed; public float CachedSlomoReturnSpeed => cachedSlomoReturnSpeed; public bool CachedSlomoUseRamp => cachedSlomoUseRamp; public string CachedSlomoRampCurve => cachedSlomoRampCurve; public float CachedSlomoRampDuration => cachedSlomoRampDuration; public float CachedSlomoReturnRampDuration => cachedSlomoReturnRampDuration; public bool CachedSlomoAffectsAudio => true; public float CachedSlomoAudioPitchScale => 1f; public bool CachedSlomoAudioPreservePitch => false; public bool CachedSlomoAffectsAudioSpeed => false; public float CachedSlomoAudioSpeedScale => 1f; public string CachedSlomoAudioMode => "Both"; public bool CachedEnableInfiniteTokens => cachedEnableInfiniteTokens; public bool CachedDisableEncryptionNodes => cachedDisableEncryptionNodes; public bool CachedDisableAllEncryptions => cachedDisableAllEncryptions; public ConfigurationManager(ConfigFile configFile, ManualLogSource logSource) { config = configFile; logger = logSource; } public void InitializeAll() { InitializeSlomoConfig(); InitializeGunRandomizationConfig(); InitializeSpawnConfigurations(); InitializeKeyBindings(); logger.LogInfo((object)"ConfigurationManager: All configuration entries initialized"); } private void InitializeSlomoConfig() { MaxSlomo = config.Bind<float>("Slomo", "MaxSlowmoScale", 0.1f, "Maximum slomo scale (0.01 = 1% speed, 0.1 = 10% speed)"); SlomoWaitTime = config.Bind<float>("Slomo", "WaitTime", 2f, "Time to wait at max slomo before returning to normal speed"); SlomoScaleSpeed = config.Bind<float>("Slomo", "ScaleDownSpeed", 1f, "Speed at which time slows down (higher = faster transition)"); SlomoReturnSpeed = config.Bind<float>("Slomo", "ReturnSpeed", 0.33f, "Speed at which time returns to normal (higher = faster return)"); SlomoVRControllerEnabled = config.Bind<bool>("Slomo", "VRControllerEnabled", true, "Enable VR controller button to trigger slomo"); SlomoVRButton = config.Bind<string>("Slomo", "VRButton", "LeftX", "VR button to trigger slomo"); SlomoAffectsMovement = config.Bind<bool>("Slomo", "AffectsMovement", true, "Whether slomo affects player movement speed"); SlomoMovementScale = config.Bind<float>("Slomo", "MovementScale", 0.3f, "Movement speed multiplier during slomo"); SlomoUseRampSpeed = config.Bind<bool>("Slomo.Ramp", "UseRampSpeed", true, "Enable smooth ramp speed transitions for slomo (more cinematic)"); SlomoRampCurve = config.Bind<string>("Slomo.Ramp", "RampCurve", "EaseInOut", "Curve type for slomo ramp: Linear, EaseIn, EaseOut, EaseInOut, Smooth, Cinematic"); SlomoRampDuration = config.Bind<float>("Slomo.Ramp", "RampDuration", 0.5f, "Duration in seconds for slomo to ramp down to max slow speed"); SlomoReturnRampDuration = config.Bind<float>("Slomo.Ramp", "ReturnRampDuration", 0.8f, "Duration in seconds for slomo to ramp back to normal speed"); EnableKillSlomo = config.Bind<bool>("Slomo", "EnableKillSlomo", true, "Enable slow motion effect on enemy kill."); } private void InitializeGunRandomizationConfig() { UseItemManagerForGunRandomization = config.Bind<bool>("GunRandomization", "UseItemManager", true, "Use ItemManager for gun randomization (includes all H3VR and modded guns). If false, uses GunList/MagazineList config files."); GunList = config.Bind<string>("General", "GunList", "DefaultGunList", "List of guns"); MagazineList = config.Bind<string>("General", "MagazineList", "DefaultMagazineList", "List of magazines"); } private void InitializeSpawnConfigurations() { ShurikenScale = config.Bind<float>("Shuriken", "Scale", 1f, "Scale multiplier for spawned shuriken"); ShurikenMinCount = config.Bind<int>("Shuriken", "MinCount", 1, "Minimum number of shuriken to spawn"); ShurikenMaxCount = config.Bind<int>("Shuriken", "MaxCount", 3, "Maximum number of shuriken to spawn"); PillowMinCount = config.Bind<int>("Pillow", "MinCount", 1, "Minimum number of pillows to spawn"); PillowMaxCount = config.Bind<int>("Pillow", "MaxCount", 3, "Maximum number of pillows to spawn"); PillowGrenadeEnabled = config.Bind<bool>("Pillow", "GrenadeEnabled", true, "Enable pillow grenade effect"); PillowGrenadeChance = config.Bind<float>("Pillow", "GrenadeChance", 0.1f, "Chance for pillow to spawn grenade"); PillowGrenadeArmedChance = config.Bind<float>("Pillow", "GrenadeArmedChance", 0.3f, "Chance for pillow grenade to be armed"); PillowZeroGravityEnabled = config.Bind<bool>("Pillow", "ZeroGEnabled", true, "Enable pillow zero gravity effect"); PillowZeroGravityChance = config.Bind<float>("Pillow", "ZeroGChance", 0.15f, "Chance for pillow to trigger zero gravity"); PillowZeroGravityDuration = config.Bind<float>("Pillow", "ZeroGDuration", 10f, "Duration of pillow zero gravity effect"); PillowSlomoEnabled = config.Bind<bool>("Pillow", "SlomoEnabled", true, "Enable pillow slow motion effect"); PillowSlomoChance = config.Bind<float>("Pillow", "SlomoChance", 0.2f, "Chance for pillow to trigger slow motion"); PillowSlomoDuration = config.Bind<float>("Pillow", "SlomoDuration", 8f, "Duration of pillow slow motion effect"); DangerCloseMinCount = config.Bind<int>("DangerClose", "MinCount", 1, "Minimum danger close rounds"); DangerCloseMaxCount = config.Bind<int>("DangerClose", "MaxCount", 5, "Maximum danger close rounds"); EnableInfiniteTokens = config.Bind<bool>("TakeAndHold", "InfiniteTokens", false, "Enable infinite tokens in Take and Hold mode"); DisableEncryptionNodes = config.Bind<bool>("TakeAndHold", "DisableEncryptionNodes", false, "Disable encryption nodes in Take and Hold mode for easier gameplay"); DisableAllEncryptions = config.Bind<bool>("TakeAndHold.Encryption", "DisableAllEncryptions", false, "Master switch: Disable ALL encryption nodes (overrides specific settings)"); DisableEncryptionType1 = config.Bind<bool>("TakeAndHold.Encryption", "DisableType1", false, "Disable Type 1 encryption nodes (pattern matching)"); DisableEncryptionType2 = config.Bind<bool>("TakeAndHold.Encryption", "DisableType2", false, "Disable Type 2 encryption nodes (sequence)"); DisableEncryptionType3 = config.Bind<bool>("TakeAndHold.Encryption", "DisableType3", false, "Disable Type 3 encryption nodes (timed)"); AutoCompleteEncryption = config.Bind<bool>("TakeAndHold.Encryption", "AutoComplete", false, "Automatically complete enabled encryption nodes after delay"); EncryptionCompletionDelay = config.Bind<float>("TakeAndHold.Encryption", "CompletionDelay", 2f, "Delay in seconds before auto-completing encryption (if AutoComplete enabled)"); } private void InitializeKeyBindings() { //IL_02a5: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, KeyValuePair<KeyCode, string>> dictionary = new Dictionary<string, KeyValuePair<KeyCode, string>> { { "SpawnWonderfulToy", new KeyValuePair<KeyCode, string>((KeyCode)257, "Spawn Wonderful Toy") }, { "SpawnJeditToy", new KeyValuePair<KeyCode, string>((KeyCode)258, "Spawn Jedit Toy") }, { "SpawnHydration", new KeyValuePair<KeyCode, string>((KeyCode)259, "Spawn Hydration") }, { "SpawnPillow", new KeyValuePair<KeyCode, string>((KeyCode)260, "Spawn Pillow") }, { "SpawnShuri", new KeyValuePair<KeyCode, string>((KeyCode)261, "Spawn Shuriken") }, { "SpawnFlash", new KeyValuePair<KeyCode, string>((KeyCode)262, "Spawn Flash") }, { "SpawnFlash2", new KeyValuePair<KeyCode, string>((KeyCode)263, "Spawn Flash2") }, { "SpawnSkittySubGun", new KeyValuePair<KeyCode, string>((KeyCode)264, "Spawn Random Gun (Small)") }, { "SpawnSkittyBigGun", new KeyValuePair<KeyCode, string>((KeyCode)265, "Spawn Random Gun (Large)") }, { "SpawnNadeRain", new KeyValuePair<KeyCode, string>((KeyCode)267, "Spawn Grenade Rain") }, { "DangerCloseBarrage", new KeyValuePair<KeyCode, string>((KeyCode)268, "Danger Close Barrage") }, { "DestroyHeld", new KeyValuePair<KeyCode, string>((KeyCode)269, "Destroy Held Item") }, { "DestroyQuickbelt", new KeyValuePair<KeyCode, string>((KeyCode)270, "Drop Quickbelt Items") }, { "TriggerSlomo", new KeyValuePair<KeyCode, string>((KeyCode)102, "Trigger Slow Motion") }, { "TriggerZeroG", new KeyValuePair<KeyCode, string>((KeyCode)103, "Trigger Zero Gravity") }, { "ToggleFireMode", new KeyValuePair<KeyCode, string>((KeyCode)116, "Toggle Fire Mode") }, { "BoostMalfunction", new KeyValuePair<KeyCode, string>((KeyCode)121, "Boost Malfunction") }, { "ShowStats", new KeyValuePair<KeyCode, string>((KeyCode)9, "Show Stats") }, { "SpawnAirStrike", new KeyValuePair<KeyCode, string>((KeyCode)291, "Spawn Air Strike Smoke Grenade") }, { "SpawnTitanMachine", new KeyValuePair<KeyCode, string>((KeyCode)292, "Spawn Titan Machine (AI Enemy)") }, { "SpawnNuke", new KeyValuePair<KeyCode, string>((KeyCode)110, "Spawn Nuke (Massive Explosion)") }, { "EmptyHeldGunChamber", new KeyValuePair<KeyCode, string>((KeyCode)101, "Empty Held Gun Chamber") }, { "SwapHeldGun", new KeyValuePair<KeyCode, string>((KeyCode)293, "Swap Held Gun for Random Gun") } }; foreach (KeyValuePair<string, KeyValuePair<KeyCode, string>> item in dictionary) { KeyBindings[item.Key] = config.Bind<KeyCode>("KeyBindings", "KeyBindFor" + item.Key, item.Value.Key, item.Value.Value); } } public void RefreshCachedValues() { cachedMaxSlomo = MaxSlomo.Value; cachedSlomoWaitTime = SlomoWaitTime.Value; cachedSlomoScaleSpeed = SlomoScaleSpeed.Value; cachedSlomoReturnSpeed = SlomoReturnSpeed.Value; cachedSlomoUseRamp = SlomoUseRampSpeed.Value; cachedSlomoRampCurve = SlomoRampCurve.Value; cachedSlomoRampDuration = SlomoRampDuration.Value; cachedSlomoReturnRampDuration = SlomoReturnRampDuration.Value; cachedEnableInfiniteTokens = EnableInfiniteTokens.Value; cachedDisableEncryptionNodes = DisableEncryptionNodes.Value; cachedDisableAllEncryptions = DisableAllEncryptions.Value; } } [BepInPlugin("com.MrBeam.h3tvr", "H3TVR", "1.1.4")] [BepInProcess("h3vr.exe")] public class H3TVRImproved : BaseUnityPlugin { private enum EncryptionType { Unknown, Pattern, Sequence, Timed } private const float SlowdownFactor = 0.001f; private const float SlowdownLength = 6f; private const float ZeroGWaitTime = 6f; private const float RealisticFallTime = 1f; private const float MalfunctionBoostDuration = 120f; private const float ForcedMalfunctionChance = 0.75f; private string slomoStatus = "Off"; private string zeroGStatus = "Off"; private bool malfunctionBoostActive; private float malfunctionBoostEndTime; private float slomoRampStartTime; private float slomoRampStartValue; private bool isRamping; private ConfigEntry<float> maxSlomo; private ConfigEntry<float> slomoWaitTime; private ConfigEntry<float> slomoScaleSpeed; private ConfigEntry<float> slomoReturnSpeed; private ConfigEntry<bool> slomoVRControllerEnabled; private ConfigEntry<string> slomoVRButton; private ConfigEntry<bool> slomoAffectsMovement; private ConfigEntry<float> slomoMovementScale; private ConfigEntry<bool> slomoUseRampSpeed; private ConfigEntry<string> slomoRampCurve; private ConfigEntry<float> slomoRampDuration; private ConfigEntry<float> slomoReturnRampDuration; private ConfigEntry<bool> enableKillSlomo; private const bool slomoAffectsAudio = true; private const float slomoAudioPitchScale = 1f; private const bool slomoAudioPreservePitch = false; private const bool slomoAffectsAudioSpeed = false; private const float slomoAudioSpeedScale = 1f; private const string slomoAudioMode = "Both"; private ConfigEntry<bool> useItemManagerForGunRandomization; private ConfigEntry<string> gunList; private ConfigEntry<string> magazineList; private ConfigEntry<float> shurikenScale; private ConfigEntry<int> shurikenMinCount; private ConfigEntry<int> shurikenMaxCount; private ConfigEntry<int> pillowMinCount; private ConfigEntry<int> pillowMaxCount; private ConfigEntry<bool> pillowGrenadeEnabled; private ConfigEntry<float> pillowGrenadeChance; private ConfigEntry<float> pillowGrenadeArmedChance; private ConfigEntry<bool> pillowZeroGravityEnabled; private ConfigEntry<float> pillowZeroGravityChance; private ConfigEntry<float> pillowZeroGravityDuration; private ConfigEntry<bool> pillowSlomoEnabled; private ConfigEntry<float> pillowSlomoChance; private ConfigEntry<float> pillowSlomoDuration; private ConfigEntry<int> dangerCloseMinCount; private ConfigEntry<int> dangerCloseMaxCount; private ConfigEntry<int> airStrikeGrenadeCount; private ConfigEntry<float> airStrikePinPullChance; private readonly Dictionary<string, ConfigEntry<KeyCode>> keyBindings = new Dictionary<string, ConfigEntry<KeyCode>>(); private ConfigEntry<bool> enableInfiniteTokens; private ConfigEntry<bool> disableEncryptionNodes; private ConfigEntry<bool> disableAllEncryptions; private ConfigEntry<bool> disableEncryptionType1; private ConfigEntry<bool> disableEncryptionType2; private ConfigEntry<bool> disableEncryptionType3; private ConfigEntry<bool> autoCompleteEncryption; private ConfigEntry<float> encryptionCompletionDelay; private SlomoMovementController slomoMovementController; private readonly Hooks hooks = new Hooks(); private InputHandler inputHandler; private SpawnManager spawnManager; private EffectsManager effectsManager; private WeaponManager weaponManager; private AudioManager audioManager; private AirdropManager airdropManager; private static Dictionary<AudioSource, float> originalAudioSpeeds = new Dictionary<AudioSource, float>(); public H3TVRImproved() { hooks.Hook(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading H3TVR Enhanced Edition (Standalone Mode)"); } private void Awake() { try { OptionalDependencyManager.Initialize(((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Logger.LogInfo((object)"H3TVR Enhanced Edition (Standalone Mode) is loading..."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 1: Initializing configuration..."); InitializeConfiguration(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 2: Initializing optional dependencies..."); InitializeOptionalDependencies(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 3: Initializing components..."); InitializeComponents(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 3.6: Initializing Airdrop Manager..."); InitializeAirdropManager(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 5: Initializing SpawnManager..."); if ((Object)(object)spawnManager != (Object)null) { spawnManager.Initialize(this, ((BaseUnityPlugin)this).Logger, audioManager); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SpawnManager initialized successfully"); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Cannot initialize SpawnManager - spawnManager: {(Object)(object)spawnManager != (Object)null}"); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 6: Initializing Twitch integration..."); InitializeTwitchIntegration(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"H3TVR Enhanced Edition loaded successfully!"); ((BaseUnityPlugin)this).Logger.LogInfo((object)OptionalDependencyManager.GetDependencyStatusReport()); if (MeatyceiverIntegrationManager.IsIntegrationEnabled()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Meatyceiver 2 Integration: ACTIVE"); ((BaseUnityPlugin)this).Logger.LogInfo((object)MeatyceiverIntegrationManager.GetTransformationStats()); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error during H3TVR initialization: " + ex.Message)); ((BaseUnityPlugin)this).Logger.LogError((object)("Stack trace: " + ex.StackTrace)); try { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Attempting fallback initialization..."); InitializeConfiguration(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"H3TVR running in fallback mode with basic functionality"); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Critical error - H3TVR cannot initialize: " + ex2.Message)); } } } private void InitializeConfiguration() { maxSlomo = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "MaxSlowmoScale", 0.1f, "Maximum slomo scale (0.01 = 1% speed, 0.1 = 10% speed)"); slomoWaitTime = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "WaitTime", 2f, "Time to wait at max slomo before returning to normal speed"); slomoScaleSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "ScaleDownSpeed", 1f, "Speed at which time slows down (higher = faster transition)"); slomoReturnSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "ReturnSpeed", 0.33f, "Speed at which time returns to normal (higher = faster return)"); slomoVRControllerEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Slomo", "VRControllerEnabled", true, "Enable VR controller button to trigger slomo"); slomoVRButton = ((BaseUnityPlugin)this).Config.Bind<string>("Slomo", "VRButton", "LeftX", "VR button to trigger slomo"); slomoAffectsMovement = ((BaseUnityPlugin)this).Config.Bind<bool>("Slomo", "AffectsMovement", true, "Whether slomo affects player movement speed"); slomoMovementScale = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "MovementScale", 0.3f, "Movement speed multiplier during slomo"); slomoUseRampSpeed = ((BaseUnityPlugin)this).Config.Bind<bool>("Slomo.Ramp", "UseRampSpeed", true, "Enable smooth ramp speed transitions for slomo (more cinematic)"); slomoRampCurve = ((BaseUnityPlugin)this).Config.Bind<string>("Slomo.Ramp", "RampCurve", "EaseInOut", "Curve type for slomo ramp: Linear, EaseIn, EaseOut, EaseInOut, Smooth, Cinematic"); slomoRampDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo.Ramp", "RampDuration", 0.5f, "Duration in seconds for slomo to ramp down to max slow speed"); slomoReturnRampDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo.Ramp", "ReturnRampDuration", 0.8f, "Duration in seconds for slomo to ramp back to normal speed"); enableKillSlomo = ((BaseUnityPlugin)this).Config.Bind<bool>("Slomo", "EnableKillSlomo", true, "Enable slow motion effect on enemy kill."); useItemManagerForGunRandomization = ((BaseUnityPlugin)this).Config.Bind<bool>("GunRandomization", "UseItemManager", true, "Use ItemManager for gun randomization (includes all H3VR and modded guns). If false, uses GunList/MagazineList config files."); gunList = ((BaseUnityPlugin)this).Config.Bind<string>("General", "GunList", "DefaultGunList", "List of guns"); magazineList = ((BaseUnityPlugin)this).Config.Bind<string>("General", "MagazineList", "DefaultMagazineList", "List of magazines"); InitializeSpawnConfigurations(); InitializeKeyBindings(); } private void InitializeSpawnConfigurations() { shurikenScale = ((BaseUnityPlugin)this).Config.Bind<float>("Shuriken", "Scale", 1f, "Scale multiplier for spawned shuriken"); shurikenMinCount = ((BaseUnityPlugin)this).Config.Bind<int>("Shuriken", "MinCount", 1, "Minimum number of shuriken to spawn"); shurikenMaxCount = ((BaseUnityPlugin)this).Config.Bind<int>("Shuriken", "MaxCount", 3, "Maximum number of shuriken to spawn"); pillowMinCount = ((BaseUnityPlugin)this).Config.Bind<int>("Pillow", "MinCount", 1, "Minimum number of pillows to spawn"); pillowMaxCount = ((BaseUnityPlugin)this).Config.Bind<int>("Pillow", "MaxCount", 3, "Maximum number of pillows to spawn"); pillowGrenadeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Pillow", "GrenadeEnabled", true, "Enable pillow grenade effect"); pillowGrenadeChance = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "GrenadeChance", 0.1f, "Chance for pillow to spawn grenade"); pillowGrenadeArmedChance = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "GrenadeArmedChance", 0.3f, "Chance for pillow grenade to be armed"); pillowZeroGravityEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Pillow", "ZeroGEnabled", true, "Enable pillow zero gravity effect"); pillowZeroGravityChance = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "ZeroGChance", 0.15f, "Chance for pillow to trigger zero gravity"); pillowZeroGravityDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "ZeroGDuration", 10f, "Duration of pillow zero gravity effect"); pillowSlomoEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Pillow", "SlomoEnabled", true, "Enable pillow slow motion effect"); pillowSlomoChance = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "SlomoChance", 0.2f, "Chance for pillow to trigger slow motion"); pillowSlomoDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "SlomoDuration", 8f, "Duration of pillow slow motion effect"); dangerCloseMinCount = ((BaseUnityPlugin)this).Config.Bind<int>("DangerClose", "MinCount", 1, "Minimum danger close rounds"); dangerCloseMaxCount = ((BaseUnityPlugin)this).Config.Bind<int>("DangerClose", "MaxCount", 5, "Maximum danger close rounds"); airStrikeGrenadeCount = ((BaseUnityPlugin)this).Config.Bind<int>("AirStrike", "GrenadeCount", 1, "Number of air strike grenades to spawn per redeem"); airStrikePinPullChance = ((BaseUnityPlugin)this).Config.Bind<float>("AirStrike", "PinPullChance", 1f, "Chance (0.0 - 1.0) that each spawned air strike grenade has its pin pulled and is armed"); enableInfiniteTokens = ((BaseUnityPlugin)this).Config.Bind<bool>("TakeAndHold", "InfiniteTokens", false, "Enable infinite tokens in Take and Hold mode"); disableEncryptionNodes = ((BaseUnityPlugin)this).Config.Bind<bool>("TakeAndHold", "DisableEncryptionNodes", false, "Disable encryption nodes in Take and Hold mode for easier gameplay"); disableAllEncryptions = ((BaseUnityPlugin)this).Config.Bind<bool>("TakeAndHold.Encryption", "DisableAllEncryptions", false, "Master switch: Disable ALL encryption nodes (overrides specific settings)"); disableEncryptionType1 = ((BaseUnityPlugin)this).Config.Bind<bool>("TakeAndHold.Encryption", "DisableType1", false, "Disable Type 1 encryption nodes (pattern matching)"); disableEncryptionType2 = ((BaseUnityPlugin)this).Config.Bind<bool>("TakeAndHold.Encryption", "DisableType2", false, "Disable Type 2 encryption nodes (sequence)"); disableEncryptionType3 = ((BaseUnityPlugin)this).Config.Bind<bool>("TakeAndHold.Encryption", "DisableType3", false, "Disable Type 3 encryption nodes (timed)"); autoCompleteEncryption = ((BaseUnityPlugin)this).Config.Bind<bool>("TakeAndHold.Encryption", "AutoComplete", false, "Automatically complete enabled encryption nodes after delay"); encryptionCompletionDelay = ((BaseUnityPlugin)this).Config.Bind<float>("TakeAndHold.Encryption", "CompletionDelay", 2f, "Delay in seconds before auto-completing encryption (if AutoComplete enabled)"); } private void InitializeKeyBindings() { //IL_0275: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, KeyValuePair<KeyCode, string>> dictionary = new Dictionary<string, KeyValuePair<KeyCode, string>> { { "SpawnWonderfulToy", new KeyValuePair<KeyCode, string>((KeyCode)257, "Spawn Wonderful Toy") }, { "SpawnJeditToy", new KeyValuePair<KeyCode, string>((KeyCode)258, "Spawn Jedit Toy") }, { "SpawnHydration", new KeyValuePair<KeyCode, string>((KeyCode)259, "Spawn Hydration") }, { "SpawnPillow", new KeyValuePair<KeyCode, string>((KeyCode)260, "Spawn Pillow") }, { "SpawnShuri", new KeyValuePair<KeyCode, string>((KeyCode)261, "Spawn Shuriken") }, { "SpawnFlash", new KeyValuePair<KeyCode, string>((KeyCode)262, "Spawn Flash") }, { "SpawnFlash2", new KeyValuePair<KeyCode, string>((KeyCode)263, "Spawn Flash2") }, { "SpawnSkittySubGun", new KeyValuePair<KeyCode, string>((KeyCode)264, "Spawn Random Gun (Small)") }, { "SpawnSkittyBigGun", new KeyValuePair<KeyCode, string>((KeyCode)265, "Spawn Random Gun (Large)") }, { "SpawnNadeRain", new KeyValuePair<KeyCode, string>((KeyCode)267, "Spawn Grenade Rain") }, { "DangerCloseBarrage", new KeyValuePair<KeyCode, string>((KeyCode)268, "Danger Close Barrage") }, { "DestroyHeld", new KeyValuePair<KeyCode, string>((KeyCode)269, "Destroy Held Item") }, { "DestroyQuickbelt", new KeyValuePair<KeyCode, string>((KeyCode)270, "Drop Quickbelt Items") }, { "TriggerSlomo", new KeyValuePair<KeyCode, string>((KeyCode)102, "Trigger Slow Motion") }, { "TriggerZeroG", new KeyValuePair<KeyCode, string>((KeyCode)103, "Trigger Zero Gravity") }, { "ToggleFireMode", new KeyValuePair<KeyCode, string>((KeyCode)116, "Toggle Fire Mode") }, { "BoostMalfunction", new KeyValuePair<KeyCode, string>((KeyCode)121, "Boost Malfunction") }, { "ShowStats", new KeyValuePair<KeyCode, string>((KeyCode)9, "Show Stats") }, { "SpawnAirStrike", new KeyValuePair<KeyCode, string>((KeyCode)291, "Spawn Air Strike Smoke Grenade") }, { "SpawnTitanMachine", new KeyValuePair<KeyCode, string>((KeyCode)292, "Spawn Titan Machine (AI Enemy)") }, { "SwapHeldGun", new KeyValuePair<KeyCode, string>((KeyCode)293, "Swap Held Gun for Random Gun") } }; foreach (KeyValuePair<string, KeyValuePair<KeyCode, string>> item in dictionary) { keyBindings[item.Key] = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("KeyBindings", "KeyBindFor" + item.Key, item.Value.Key, item.Value.Value); } } private void InitializeOptionalDependencies() { try { OptionalDependencyManager.Initialize(((BaseUnityPlugin)this).Logger); MeatyceiverIntegrationManager.Initialize(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config); StovepipeIntegrationManager.Initialize(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config); if (OptionalDependencyManager.HasAnyDependencies()) { int availableDependencyCount = OptionalDependencyManager.GetAvailableDependencyCount(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[H3TVRImproved] Enhanced functionality active with {availableDependencyCount} optional dependencies"); if (OptionalDependencyManager.IsStovepipeAvailable) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[H3TVRImproved] Stovepipe integration active - realistic weapon malfunctions enabled"); } if (OptionalDependencyManager.IsMeatyceiver2Available) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[H3TVRImproved] Meatyceiver 2 integration active - weapon transformations enabled"); } } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[H3TVRImproved] Running in standard mode - no optional dependencies found"); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[H3TVRImproved] Error initializing optional dependencies: " + ex.Message)); } } private void InitializeAirdropManager() { airdropManager = ((Component)this).gameObject.AddComponent<AirdropManager>(); airdropManager.Initialize(this, ((BaseUnityPlugin)this).Logger); } private void InitializeComponents() { try { slomoMovementController = ((Component)this).gameObject.AddComponent<SlomoMovementController>(); slomoMovementController.Initialize(slomoMovementScale.Value, slomoAffectsMovement.Value, ((BaseUnityPlugin)this).Logger); inputHandler = ((Component)this).gameObject.AddComponent<InputHandler>(); spawnManager = ((Component)this).gameObject.AddComponent<SpawnManager>(); effectsManager = ((Component)this).gameObject.AddComponent<EffectsManager>(); weaponManager = ((Component)this).gameObject.AddComponent<WeaponManager>(); audioManager = ((Component)this).gameObject.AddComponent<AudioManager>(); audioManager.Initialize(this, ((BaseUnityPlugin)this).Logger); inputHandler.Initialize(keyBindings, this); effectsManager.Initialize(this, slomoMovementController, ((BaseUnityPlugin)this).Logger); weaponManager.Initialize(this, ((BaseUnityPlugin)this).Logger, audioManager); ((BaseUnityPlugin)this).Logger.LogInfo((object)"All components initialized successfully"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error initializing components: " + ex.Message)); ((BaseUnityPlugin)this).Logger.LogError((object)("Stack trace: " + ex.StackTrace)); } } private void InitializeTwitchIntegration() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Twitch integration disabled"); } public void Update() { HandleSlomoStateMachine(); HandleZeroGravityStateMachine(); HandleMalfunctionBoost(); HandleInfiniteTokens(); weaponManager?.UpdateScaleModifiers(); } private void OnDestroy() { } private void HandleSlomoStateMachine() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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) try { switch (slomoStatus) { case "Slowing": ((BaseUnityPlugin)this).Logger.LogInfo((object)"Slowing!"); effectsManager.SlomoScaleDown(); break; case "Wait": ((BaseUnityPlugin)this).Logger.LogInfo((object)"Waiting!"); slomoStatus = "Paused"; try { audioManager?.PlaySlomoSound("active"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Audio error during slomo: " + ex.Message)); } ((MonoBehaviour)this).StartCoroutine(effectsManager.SlomoWait(delegate { slomoStatus = "Return"; })); break; case "Return": ((BaseUnityPlugin)this).Logger.LogInfo((object)"Returning!"); effectsManager.SlomoReturn(); break; } if (Time.timeScale == 1f) { if (slomoStatus != "Off") { try { audioManager?.PlaySlomoSound("end"); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Audio error ending slomo: " + ex2.Message)); } } slomoStatus = "Off"; } slomoMovementController?.UpdateMovementScale(Time.timeScale); } catch (Exception ex3) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error in slomo state machine: " + ex3.Message)); slomoStatus = "Off"; } } private void HandleZeroGravityStateMachine() { if (zeroGStatus == "On") { ((MonoBehaviour)this).StartCoroutine(effectsManager.ZeroGWait(delegate { zeroGStatus = "Falling"; effectsManager.RealisticFall(); })); } if (zeroGStatus == "Falling") { ((MonoBehaviour)this).StartCoroutine(effectsManager.RealisticFallWait(delegate { effectsManager.ZeroGravityBumpUp(); zeroGStatus = "Off"; })); } } private void HandleMalfunctionBoost() { if (malfunctionBoostActive) { if (Time.time >= malfunctionBoostEndTime) { malfunctionBoostActive = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Meatyceiver malfunction boost ended."); } else { weaponManager.ApplyMalfunctionLogic(); } } } private void HandleInfiniteTokens() { if (!enableInfiniteTokens.Value && !disableEncryptionNodes.Value && !disableAllEncryptions.Value) { return; } try { if ((Object)(object)GM.TNH_Manager != (Object)null && (Object)(object)GM.TNH_Manager.m_curHoldPoint != (Object)null) { if (enableInfiniteTokens.Value) { GM.TNH_Manager.m_numTokens = 999; } if (disableAllEncryptions.Value || disableEncryptionNodes.Value) { DisableEncryptionNodes(); } else if (disableEncryptionType1.Value || disableEncryptionType2.Value || disableEncryptionType3.Value) { DisableSpecificEncryptionNodes(); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error in HandleInfiniteTokens: " + ex.Message)); } } private void DisableEncryptionNodes() { try { if ((Object)(object)GM.TNH_Manager == (Object)null || (Object)(object)GM.TNH_Manager.m_curHoldPoint == (Object)null) { return; } TNH_HoldPoint curHoldPoint = GM.TNH_Manager.m_curHoldPoint; if ((Object)(object)curHoldPoint.m_systemNode != (Object)null && !curHoldPoint.m_systemNode.m_hasActivated) { if (autoCompleteEncryption.Value) { ((MonoBehaviour)this).StartCoroutine(AutoCompleteEncryptionDelayed(curHoldPoint.m_systemNode, encryptionCompletionDelay.Value)); ((BaseUnityPlugin)this).Logger.LogDebug((object)$"[TNH] Auto-completing all encryptions after {encryptionCompletionDelay.Value}s delay"); } else { CompleteEncryptionNode(curHoldPoint.m_systemNode); ((BaseUnityPlugin)this).Logger.LogDebug((object)"[TNH] Disabled all encryption nodes"); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Error disabling encryption nodes: " + ex.Message)); } } private void DisableSpecificEncryptionNodes() { try { if ((Object)(object)GM.TNH_Manager == (Object)null || (Object)(object)GM.TNH_Manager.m_curHoldPoint == (Object)null) { return; } TNH_HoldPoint curHoldPoint = GM.TNH_Manager.m_curHoldPoint; if (!((Object)(object)curHoldPoint.m_systemNode != (Object)null) || curHoldPoint.m_systemNode.m_hasActivated) { return; } TNH_HoldPointSystemNode systemNode = curHoldPoint.m_systemNode; EncryptionType encryptionType = DetectEncryptionType(systemNode); bool flag = false; string text = ""; switch (encryptionType) { case EncryptionType.Pattern: if (disableEncryptionType1.Value) { flag = true; text = "Pattern"; } break; case EncryptionType.Sequence: if (disableEncryptionType2.Value) { flag = true; text = "Sequence"; } break; case EncryptionType.Timed: if (disableEncryptionType3.Value) { flag = true; text = "Timed"; } break; case EncryptionType.Unknown: if (disableEncryptionType1.Value || disableEncryptionType2.Value || disableEncryptionType3.Value) { flag = true; text = "Unknown"; } break; } if (flag) { if (autoCompleteEncryption.Value) { ((MonoBehaviour)this).StartCoroutine(AutoCompleteEncryptionDelayed(systemNode, encryptionCompletionDelay.Value)); ((BaseUnityPlugin)this).Logger.LogDebug((object)$"[TNH] Auto-completing {text} encryption after {encryptionCompletionDelay.Value}s delay"); } else { CompleteEncryptionNode(systemNode); ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Disabled " + text + " encryption")); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Error disabling specific encryption: " + ex.Message)); } } private EncryptionType DetectEncryptionType(TNH_HoldPointSystemNode encryptionNode) { try { if ((Object)(object)encryptionNode == (Object)null) { return EncryptionType.Unknown; } return EncryptionType.Unknown; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Error detecting encryption type: " + ex.Message)); return EncryptionType.Unknown; } } private void CompleteEncryptionNode(TNH_HoldPointSystemNode encryptionNode) { try { if (!((Object)(object)encryptionNode == (Object)null) && (Object)(object)((Component)encryptionNode).gameObject != (Object)null) { ((Component)encryptionNode).gameObject.SetActive(false); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Error completing encryption node: " + ex.Message)); } } private IEnumerator AutoCompleteEncryptionDelayed(TNH_HoldPointSystemNode encryptionNode, float delay) { yield return (object)new WaitForSeconds(delay); try { if ((Object)(object)encryptionNode != (Object)null && (Object)(object)((Component)encryptionNode).gameObject != (Object)null && ((Component)encryptionNode).gameObject.activeSelf) { CompleteEncryptionNode(encryptionNode); ((BaseUnityPlugin)this).Logger.LogDebug((object)$"[TNH] Auto-completed encryption after {delay}s delay"); } } catch (Exception ex) { Exception ex2 = ex; ((BaseUnityPlugin)this).Logger.LogDebug((object)("[TNH] Error auto-completing encryption: " + ex2.Message)); } } public void TriggerSlomo() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) slomoStatus = "Slowing"; slomoRampStartTime = Time.unscaledTime; slomoRampStartValue = Time.timeScale; isRamping = true; audioManager?.PlaySlomoSound(); } public void TriggerZeroGravity() { effectsManager.ZeroGravityBumpDown(); } public void ActivateMalfunctionBoost() { weaponManager.ActivateMalfunctionBoost(ref malfunctionBoostActive, ref malfunctionBoostEndTime); } public SpawnManager GetSpawnManager() { return spawnManager; } public WeaponManager GetWeaponManager() { return weaponManager; } public EffectsManager GetEffectsManager() { return effectsManager; } public AudioManager GetAudioManager() { return audioManager; } public AirdropManager GetAirdropManager() { return airdropManager; } public void GetShurikenConfig(out int min, out int max) { min = shurikenMinCount.Value; max = shurikenMaxCount.Value; } public float GetShurikenScale() { return shurikenScale.Value; } public void GetPillowConfig(out int min, out int max) { min = pillowMinCount.Value; max = pillowMaxCount.Value; } public void GetDangerCloseConfig(out int min, out int max) { min = dangerCloseMinCount.Value; max = dangerCloseMaxCount.Value; } public void GetAirStrikeConfig(out int count, out float pinPullChance) { count = ((airStrikeGrenadeCount == null) ? 1 : Mathf.Max(1, airStrikeGrenadeCount.Value)); pinPullChance = ((airStrikePinPullChance != null) ? Mathf.Clamp01(airStrikePinPullChance.Value) : 1f); } public void GetPillowGrenadeConfig(out bool enabled, out float chance, out float armedChance) { enabled = pillowGrenadeEnabled.Value; chance = pillowGrenadeChance.Value; armedChance = pillowGrenadeArmedChance.Value; } public void GetPillowZeroGravityConfig(out bool enabled, out float chance, out float duration) { enabled = pillowZeroGravityEnabled.Value; chance = pillowZeroGravityChance.Value; duration = pillowZeroGravityDuration.Value; } public void GetPillowSlomoConfig(out bool enabled, out float chance, out float duration) { enabled = pillowSlomoEnabled.Value; chance = pillowSlomoChance.Value; duration = pillowSlomoDuration.Value; } public bool UseItemManagerForGuns() { return useItemManagerForGunRandomization.Value; } public bool IsKillSlomoEnabled() { return enableKillSlomo.Value; } public void GetGunLists(out string gunListValue, out string magListValue) { gunListValue = gunList.Value; magListValue = magazineList.Value; } public void GetSlomoConfig(out float maxSlomoValue, out float waitTime, out float scaleSpeed, out float returnSpeed) { maxSlomoValue = maxSlomo.Value; waitTime = slomoWaitTime.Value; scaleSpeed = slomoScaleSpeed.Value; returnSpeed = slomoReturnSpeed.Value; } public void GetSlomoRampConfig(out bool useRamp, out string curve, out float rampDuration, out float returnDuration) { useRamp = slomoUseRampSpeed.Value; curve = slomoRampCurve.Value; rampDuration = slomoRampDuration.Value; returnDuration = slomoReturnRampDuration.Value; } public void GetSlomoAudioConfig(out bool affectsAudio, out float pitchScale, out bool preservePitch) { affectsAudio = true; pitchScale = 1f; preservePitch = false; } public void GetSlomoAudioConfigComplete(out bool affectsAudio, out float pitchScale, out bool preservePitch, out bool affectsSpeed, out float speedScale, out string mode) { affectsAudio = true; pitchScale = 1f; preservePitch = false; affectsSpeed = false; speedScale = 1f; mode = "Both"; } public void GetSlomoMovementConfig(out bool affectsMovement, out float movementScale) { affectsMovement = slomoAffectsMovement.Value; movementScale = slomoMovementScale.Value; } public void UpdateSlomoMovementSettings() { slomoMovementController?.UpdateSettings(slomoMovementScale.Value, slomoAffectsMovement.Value); } public void SetSlomoStatus(string status) { slomoStatus = status; } public bool IsInfiniteTokensEnabled() { return enableInfiniteTokens != null && enableInfiniteTokens.Value; } public bool IsEncryptionDisabled() { return disableEncryptionNodes != null && disableEncryptionNodes.Value; } public void SetInfiniteTokens(bool enabled) { if (enableInfiniteTokens != null) { enableInfiniteTokens.Value = enabled; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Infinite tokens " + (enabled ? "enabled" : "disabled"))); } } public void SetEncryptionNodes(bool disabled) { if (disableEncryptionNodes != null) { disableEncryptionNodes.Value = disabled; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Encryption nodes " + (disabled ? "disabled" : "enabled"))); } } public void GetSlomoVRConfig(out bool vrEnabled, out string vrButton) { vrEnabled = slomoVRControllerEnabled.Value; vrButton = slomoVRButton.Value; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPrefix] public static void FixPitch(AudioSource __instance, ref float value) { H3TVRImproved h3TVRImproved = Object.FindObjectOfType<H3TVRImproved>(); if ((Object)(object)h3TVRImproved == (Object)null) { return; } if (Time.timeScale >= 0.99f && Time.timeScale <= 1.01f) { if (originalAudioSpeeds.ContainsKey(__instance)) { originalAudioSpeeds.Remove(__instance); } return; } h3TVRImproved.GetSlomoAudioConfigComplete(out bool affectsAudio, out float pitchScale, out bool preservePitch, out bool affectsSpeed, out float speedScale, out string mode); if (!affectsAudio) { return; } if (!originalAudioSpeeds.ContainsKey(__instance)) { originalAudioSpeeds[__instance] = 1f; } switch (mode.ToLower()) { case "pitchonly": ApplyPitchAdjustment(ref value, preservePitch, pitchScale); break; case "speedonly": ApplySpeedAdjustment(__instance, speedScale); value = 1f; break; case "both": ApplyPitchAdjustment(ref value, preservePitch, pitchScale); if (affectsSpeed) { ApplySpeedAdjustment(__instance, speedScale); } break; case "independent": ApplyPitchAdjustment(ref value, preservePitch, pitchScale); if (affectsSpeed) { ApplySpeedAdjustment(__instance, speedScale); } break; default: ApplyPitchAdjustment(ref value, preservePitch, pitchScale); if (affectsSpeed) { ApplySpeedAdjustment(__instance, speedScale); } break; } value = Mathf.Clamp(value, 0.1f, 3f); } private static void ApplyPitchAdjustment(ref float pitch, bool preservePitch, float pitchScale) { if (preservePitch) { pitch *= 1f / Time.timeScale; return; } float num = pitch * (Time.timeScale * pitchScale); pitch = Mathf.Clamp(num, 0.1f, 3f); } private static void ApplySpeedAdjustment(AudioSource source, float speedScale) { if ((Object)(object)source == (Object)null || (Object)(object)source.clip == (Object)null) { return; } try { float num = Time.timeScale * speedScale; num = Mathf.Clamp(num, 0.1f, 3f); if (source.isPlaying && num < 0.95f) { float num2 = source.time / source.clip.length; int num3 = Mathf.RoundToInt((float)source.timeSamples * num); if (Mathf.Abs(num3 - source.timeSamples) > 100) { source.timeSamples = Mathf.Clamp(num3, 0, source.clip.samples - 1); } } } catch (Exception ex) { Debug.LogError((object)("Error applying speed adjustment: " + ex.Message)); } } } internal static class PluginInfo { internal const string NAME = "H3TVR"; internal const string GUID = "com.MrBeam.h3tvr"; internal const string VERSION = "1.1.4"; } public static class MeatyceiverIntegrationManager { public enum WeaponQuality { Common, Uncommon, Rare, Epic, Legendary, Artifact } private static ManualLogSource logger; private static bool initialized = false; private static Type meatyceiverType; private static object meatyceiverInstance; private static MethodInfo transformMethod; private static MethodInfo checkCompatibilityMethod; private static MethodInfo isTransformedMethod; private static MethodInfo getQualityMethod; private static MethodInfo setQualityMethod; private static PropertyInfo transformChanceProperty; private static FieldInfo enabledField; private static ConfigFile config; private static Dictionary<string, ConfigEntry<float>> chanceConfigs; private static Dictionary<string, ConfigEntry<bool>> featureConfigs; private static Dictionary<string, ConfigEntry<float>> multiplierConfigs; private static Dictionary<string, ConfigEntry<int>> intConfigs; private static readonly Dictionary<string, bool> transformationCache = new Dictionary<string, bool>(); private static readonly Dictionary<string, DateTime> transformationTimes = new Dictionary<string, DateTime>(); private static readonly Dictionary<string, DateTime> transformationCooldowns = new Dictionary<string, DateTime>(); private static readonly Dictionary<string, WeaponQuality> weaponQualities = new Dictionary<string, WeaponQuality>(); private static DateTime lastCacheClear = DateTime.Now; private const string MEATYCEIVER2_GUID = "Potatoes.Meatyceiver_2"; private const string MEATYCEIVER_LEGACY_GUID = "potatoes1286.meatyceiver"; private const string MEATYCEIVER_ALPHA_GUID = "potatoes.meatyceiver.alpha"; public static bool IsMeatyceiver2Available { get; private set; } = false; public static string DetectedVersion { get; private set; } = "Unknown"; public static string DetectedApiVersion { get; private set; } = "Unknown"; public static int TotalTransformationAttempts { get; private set; } = 0; public static int SuccessfulTransformations { get; private set; } = 0; public static int CachedResults { get; private set; } = 0; public static int CooldownBlocked { get; private set; } = 0; public static int QualityPreserved { get; private set; } = 0; public static Dictionary<string, int> TransformationsByContext { get; private set; } = new Dictionary<string, int>(); public static Dictionary<string, int> TransformationsByWeaponType { get; private set; } = new Dictionary<string, int>(); public static void Initialize(ManualLogSource logSource, ConfigFile configFile) { if (!initialized) { logger = logSource; config = configFile; logger.LogInfo((object)"[MeatyceiverIntegration] Initializing Meatyceiver 2 integration..."); InitializeConfiguration(); DetectMeatyceiver2(); if (IsMeatyceiver2Available) { CacheMeatyceiverMethods(); InitializeCompatibilityLayer(); logger.LogInfo((object)("[MeatyceiverIntegration] Successfully initialized with Meatyceiver 2 " + DetectedVersion + " (API: " + DetectedApiVersion + ")")); } else { logger.LogInfo((object)"[MeatyceiverIntegration] Meatyceiver 2 not detected - integration disabled"); } initialized = true; } } private static void InitializeConfiguration() { chanceConfigs = new Dictionary<string, ConfigEntry<float>>(); featureConfigs = new Dictionary<string, ConfigEntry<bool>>(); multiplierConfigs = new Dictionary<string, ConfigEntry<float>>(); intConfigs = new Dictionary<string, ConfigEntry<int>>(); chanceConfigs["Normal"] = config.Bind<float>("Meatyceiver 2", "ChanceNormal", 0.02f, "Normal transformation chance"); chanceConfigs["Elite"] = config.Bind<float>("Meatyceiver 2", "ChanceElite", 0.01f, "Elite sosig transformation chance"); chanceConfigs["Chaos"] = config.Bind<float>("Meatyceiver 2", "ChanceChaos", 0.15f, "Chaos mode transformation chance"); chanceConfigs["Player"] = config.Bind<float>("Meatyceiver 2", "ChancePlayer", 0.05f, "Player weapon transformation chance"); chanceConfigs["SosigWeapon"] = config.Bind<float>("Meatyceiver 2", "ChanceSosigWeapon", 0.03f, "Sosig weapon transformation chance"); chanceConfigs["EnemyWeapon"] = config.Bind<float>("Meatyceiver 2", "ChanceEnemyWeapon", 0.04f, "Enemy weapon transformation chance"); chanceConfigs["AllyWeapon"] = config.Bind<float>("Meatyceiver 2", "ChanceAllyWeapon", 0.02f, "Ally weapon transformation chance"); chanceConfigs["BossWeapon"] = config.Bind<float>("Meatyceiver 2", "ChanceBossWeapon", 0.001f, "Boss weapon transformation chance"); chanceConfigs["RareWeapon"] = config.Bind<float>("Meatyceiver 2", "ChanceRareWeapon", 0.005f, "Rare weapon transformation chance"); chanceConfigs["LegendaryWeapon"] = config.Bind<float>("Meatyceiver 2", "ChanceLegendaryWeapon", 0.001f, "Legendary weapon transformation chance"); multiplierConfigs["Pistol"] = config.Bind<float>("Meatyceiver 2", "PistolMultiplier", 1.2f, "Pistol transformation multiplier"); multiplierConfigs["Rifle"] = config.Bind<float>("Meatyceiver 2", "RifleMultiplier", 1f, "Rifle transformation multiplier"); multiplierConfigs["Shotgun"] = config.Bind<float>("Meatyceiver 2", "ShotgunMultiplier", 0.8f, "Shotgun transformation multiplier"); multiplierConfigs["SMG"] = config.Bind<float>("Meatyceiver 2", "SMGMultiplier", 1.5f, "SMG transformation multiplier"); multiplierConfigs["Sniper"] = config.Bind<float>("Meatyceiver 2", "SniperMultiplier", 0.5f, "Sniper transformation multiplier"); multiplierConfigs["LMG"] = config.Bind<float>("Meatyceiver 2", "LMGMultiplier", 0.7f, "LMG transformation multiplier"); multiplierConfigs["AssaultRifle"] = config.Bind<float>("Meatyceiver 2", "AssaultRifleMultiplier", 0.9f, "Assault rifle transformation multiplier"); multiplierConfigs["CommonQuality"] = config.Bind<float>("Meatyceiver 2", "CommonQualityMultiplier", 1f, "Common quality transformation multiplier"); multiplierConfigs["UncommonQuality"] = config.Bind<float>("Meatyceiver 2", "UncommonQualityMultiplier", 0.8f, "Uncommon quality transformation multiplier"); multiplierConfigs["RareQuality"] = config.Bind<float>("Meatyceiver 2", "RareQualityMultiplier", 0.6f, "Rare quality transformation multiplier"); multiplierConfigs["EpicQuality"] = config.Bind<float>("Meatyceiver 2", "EpicQualityMultiplier", 0.4f, "Epic quality transformation multiplier"); multiplierConfigs["LegendaryQuality"] = config.Bind<float>("Meatyceiver 2", "LegendaryQualityMultiplier", 0.2f, "Legendary quality transformation multiplier"); multiplierConfigs["ArtifactQuality"] = config.Bind<float>("Meatyceiver 2", "ArtifactQualityMultiplier", 0.1f, "Artifact quality transformation multiplier"); featureConfigs["Enabled"] = config.Bind<bool>("Meatyceiver 2", "Enabled", true, "Enable Meatyceiver 2 integration"); featureConfigs["ForceTransformOnChaos"] = config.Bind<bool>("Meatyceiver 2", "ForceTransformOnChaos", false, "Force transformation in chaos mode"); featureConfigs["AllowMultipleTransforms"] = config.Bind<bool>("Meatyceiver 2", "AllowMultipleTransforms", false, "Allow multiple transformations"); featureConfigs["PreserveAmmo"] = config.Bind<bool>("Meatyceiver 2", "PreserveAmmo", true, "Preserve ammo during transformation"); featureConfigs["PreserveAttachments"] = config.Bind<bool>("Meatyceiver 2", "PreserveAttachments", true, "Preserve attachments during transformation"); featureConfigs["PreserveQuality"] = config.Bind<bool>("Meatyceiver 2", "PreserveQuality", true, "Preserve weapon quality during transformation"); featureConfigs["PlayTransformSound"] = config.Bind<bool>("Meatyceiver 2", "PlayTransformSound", true, "Play transformation sound effects"); featureConfigs["ShowTransformParticles"] = config.Bind<bool>("Meatyceiver 2", "ShowTransformParticles", true, "Show transformation particle effects"); featureConfigs["EnableCaching"] = config.Bind<bool>("Meatyceiver 2", "EnableCaching", true, "Enable transformation result caching"); featureConfigs["EnableCooldowns"] = config.Bind<bool>("Meatyceiver 2", "EnableCooldowns", true, "Enable transformation cooldowns"); featureConfigs["RespectOriginalChances"] = config.Bind<bool>("Meatyceiver 2", "RespectOriginalChances", true, "Respect Meatyceiver 2's original chances"); featureConfigs["UseContextualLogic"] = config.Bind<bool>("Meatyceiver 2", "UseContextualLogic", true, "Use H3TVR contextual logic"); featureConfigs["UseQualityBasedChances"] = config.Bind<bool>("Meatyceiver 2", "UseQualityBasedChances", true, "Use weapon quality to modify transformation chances"); featureConfigs["EnableBatchTransformation"] = config.Bind<bool>("Meatyceiver 2", "EnableBatchTransformation", true, "Enable batch transformation support"); featureConfigs["DebugMode"] = config.Bind<bool>("Meatyceiver 2", "DebugMode", false, "Enable debug mode"); featureConfigs["VerboseLogging"] = config.Bind<bool>("Meatyceiver 2", "VerboseLogging", false, "Enable verbose logging"); intConfigs["CooldownSeconds"] = config.Bind<int>("Meatyceiver 2", "CooldownSeconds", 30, "Cooldown between transformations (seconds)"); intConfigs["CacheLifetimeMinutes"] = config.Bind<int>("Meatyceiver 2", "CacheLifetimeMinutes", 10, "Cache entry lifetime in minutes"); intConfigs["MaxCacheSize"] = config.Bind<int>("Meatyceiver 2", "MaxCacheSize", 1000, "Maximum number of cached entries"); intConfigs["BatchSize"] = config.Bind<int>("Meatyceiver 2", "BatchSize", 10, "Maximum weapons to transform in a single batch"); } private static void DetectMeatyceiver2() { try { Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos; if (pluginInfos.ContainsKey("Potatoes.Meatyceiver_2")) { IsMeatyceiver2Available = true; DetectedVersion = pluginInfos["Potatoes.Meatyceiver_2"].Metadata.Version.ToString(); logger.LogInfo((object)("[MeatyceiverIntegration] Meatyceiver 2 detected via BepInEx: v" + DetectedVersion)); } else if (pluginInfos.ContainsKey("potatoes1286.meatyceiver")) { IsMeatyceiver2Available = true; DetectedVersion = pluginInfos["potatoes1286.meatyceiver"].Metadata.Version.ToString(); logger.LogInfo((object)("[MeatyceiverIntegration] Meatyceiver detected via legacy GUID: v" + DetectedVersion)); } else if (pluginInfos.ContainsKey("potatoes.meatyceiver.alpha")) { IsMeatyceiver2Available = true; DetectedVersion = pluginInfos["potatoes.meatyceiver.alpha"].Metadata.Version.ToString(); logger.LogInfo((object)("[MeatyceiverIntegration] Meatyceiver Alpha detected via GUID: v" + DetectedVersion)); } else { DetectViaReflection(); } } catch (Exception ex) { logger.LogError((object)("[MeatyceiverIntegration] Error during Meatyceiver 2 detection: " + ex.Message)); IsMeatyceiver2Available = false; } } private static void DetectViaReflection() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] array = assemblies; foreach (Assembly assembly in array) { try { Type[] types = assembly.GetTypes(); Type[] array2 = types; foreach (Type type in array2) { if (IsMeatyceiverType(type)) { meatyceiverType = type; IsMeatyceiver2Available = true; DetectedVersion = assembly.GetName().Version?.ToString() ?? "Unknown"; logger.LogInfo((object)("[MeatyceiverIntegration] Meatyceiver detected via reflection: " + type.FullName)); return; } } } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not scan assembly " + assembly.FullName + ": " + ex.Message)); } } } private static bool IsMeatyceiverType(Type type) { if ((object)type == null) { return false; } string text = type.Name.ToLower(); string text2 = type.Namespace?.ToLower() ?? ""; return text.Contains("meatyceiver") || text.Contains("meatyreceiver") || text.Contains("meattransform") || text2.Contains("meatyceiver") || text2.Contains("potatoes") || (text.Contains("meat") && (text.Contains("weapon") || text.Contains("transform"))); } private static void CacheMeatyceiverMethods() { if ((object)meatyceiverType == null) { return; } try { FieldInfo field = meatyceiverType.GetField("Instance", BindingFlags.Static | BindingFlags.Public); if ((object)field == null) { field = meatyceiverType.GetField("instance", BindingFlags.Static | BindingFlags.Public); } if ((object)field != null) { meatyceiverInstance = field.GetValue(null); logger.LogDebug((object)"[MeatyceiverIntegration] Found Meatyceiver instance"); } MethodInfo[] methods = meatyceiverType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { string text = methodInfo.Name.ToLower(); if ((text.Contains("transform") || text.Contains("meat")) && !text.Contains("check") && !text.Contains("is")) { transformMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached transform method: " + methodInfo.Name)); } else if (text.Contains("check") || text.Contains("compatible") || text.Contains("can")) { checkCompatibilityMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached compatibility method: " + methodInfo.Name)); } else if (text.Contains("is") && (text.Contains("transform") || text.Contains("meat"))) { isTransformedMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached is-transformed method: " + methodInfo.Name)); } else if (text.Contains("quality") && text.Contains("get")) { getQualityMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached get quality method: " + methodInfo.Name)); } else if (text.Contains("quality") && text.Contains("set")) { setQualityMethod = methodInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached set quality method: " + methodInfo.Name)); } } PropertyInfo[] properties = meatyceiverType.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); PropertyInfo[] array2 = properties; foreach (PropertyInfo propertyInfo in array2) { string text2 = propertyInfo.Name.ToLower(); if (text2.Contains("chance") || text2.Contains("probability")) { transformChanceProperty = propertyInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached chance property: " + propertyInfo.Name)); } } FieldInfo[] fields = meatyceiverType.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); FieldInfo[] array3 = fields; foreach (FieldInfo fieldInfo in array3) { string text3 = fieldInfo.Name.ToLower(); if (text3.Contains("enabled") || text3.Contains("active")) { enabledField = fieldInfo; logger.LogDebug((object)("[MeatyceiverIntegration] Cached enabled field: " + fieldInfo.Name)); } } } catch (Exception ex) { logger.LogWarning((object)("[MeatyceiverIntegration] Error caching Meatyceiver methods: " + ex.Message)); } } private static void InitializeCompatibilityLayer() { try { if ((object)getQualityMethod != null && (object)setQualityMethod != null) { DetectedApiVersion = "2.0+"; logger.LogDebug((object)"[MeatyceiverIntegration] Detected advanced API with quality support"); } else if ((object)transformMethod != null) { DetectedApiVersion = "1.5+"; logger.LogDebug((object)"[MeatyceiverIntegration] Detected basic transformation API"); } else { DetectedApiVersion = "1.0"; logger.LogWarning((object)"[MeatyceiverIntegration] Limited API detected - some features may not work"); } } catch (Exception ex) { logger.LogWarning((object)("[MeatyceiverIntegration] Error initializing compatibility layer: " + ex.Message)); DetectedApiVersion = "Unknown"; } } public static bool TryTransformWeapon(FVRFireArm firearm, string context = "Normal", float customChance = -1f, bool forceTransform = false) { //IL_025d: 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) if (!IsIntegrationEnabled() || (Object)(object)firearm == (Object)null) { return false; } TotalTransformationAttempts++; try { string weaponKey = GetWeaponKey(firearm); if (featureConfigs["EnableCooldowns"].Value && IsOnCooldown(weaponKey) && !forceTransform) { CooldownBlocked++; if (featureConfigs["VerboseLogging"].Value) { logger.LogDebug((object)("[MeatyceiverIntegration] Transformation blocked by cooldown for " + weaponKey)); } return false; } if (featureConfigs["EnableCaching"].Value && transformationCache.ContainsKey(weaponKey)) { CachedResults++; bool flag = transformationCache[weaponKey]; if (featureConfigs["VerboseLogging"].Value) { logger.LogDebug((object)$"[MeatyceiverIntegration] Using cached result for {weaponKey}: {flag}"); } return flag; } if (!CanWeaponBeTransformed(firearm) && !forceTransform) { CacheResult(weaponKey, result: false); return false; } float num = ((customChance >= 0f) ? customChance : CalculateTransformationChance(firearm, context)); if (!forceTransform && Random.value > num) { if (featureConfigs["VerboseLogging"].Value) { logger.LogDebug((object)$"[MeatyceiverIntegration] Transformation chance failed: {num:P2}"); } CacheResult(weaponKey, result: false); return false; } bool flag2 = PerformTransformation(firearm, context); if (flag2) { SuccessfulTransformations++; UpdateTransformationStatistics(context, firearm); if (featureConfigs["EnableCooldowns"].Value) { SetCooldown(weaponKey); } logger.LogInfo((object)("[MeatyceiverIntegration] Successfully transformed " + ((Object)firearm).name + " (context: " + context + ")")); if (featureConfigs["PlayTransformSound"].Value) { PlayTransformationSound(((Component)firearm).transform.position); } if (featureConfigs["ShowTransformParticles"].Value) { ShowTransformationParticles(((Component)firearm).transform.position); } } CacheResult(weaponKey, flag2); return flag2; } catch (Exception ex) { logger.LogError((object)("[MeatyceiverIntegration] Error during weapon transformation: " + ex.Message)); return false; } } public static Dictionary<FVRFireArm, bool> TryTransformWeaponsBatch(List<FVRFireArm> firearms, string context = "Normal", float customChance = -1f, bool forceTransform = false) { Dictionary<FVRFireArm, bool> dictionary = new Dictionary<FVRFireArm, bool>(); if (!IsIntegrationEnabled() || !featureConfigs["EnableBatchTransformation"].Value) { foreach (FVRFireArm firearm in firearms) { dictionary[firearm] = false; } return dictionary; } int batchSize = intConfigs["BatchSize"].Value; List<List<FVRFireArm>> list = (from x in firearms.Select((FVRFireArm x, int i) => new { Index = i, Value = x }) group x by x.Index / batchSize into x select x.Select(v => v.Value).ToList()).ToList(); foreach (List<FVRFireArm> item in list) { foreach (FVRFireArm item2 in item) { dictionary[item2] = TryTransformWeapon(item2, context, customChance, forceTransform); } } logger.LogDebug((object)$"[MeatyceiverIntegration] Batch transformation completed: {dictionary.Count((KeyValuePair<FVRFireArm, bool> r) => r.Value)}/{dictionary.Count} successful"); return dictionary; } public static bool CanWeaponBeTransformed(FVRFireArm firearm) { if (!IsIntegrationEnabled() || (Object)(object)firearm == (Object)null) { return false; } try { if ((object)checkCompatibilityMethod != null) { return (bool)checkCompatibilityMethod.Invoke(meatyceiverInstance, new object[1] { firearm }); } if (IsWeaponAlreadyTransformed(firearm)) { return featureConfigs["AllowMultipleTransforms"].Value; } string text = ((Object)firearm).name.ToLower(); return !text.Contains("meat") && !text.Contains("flesh") && !text.Contains("organic") && !text.Contains("bio"); } catch (Exception ex) { logger.LogError((object)("[MeatyceiverIntegration] Error checking weapon compatibility: " + ex.Message)); return false; } } public static bool IsWeaponAlreadyTransformed(FVRFireArm firearm) { if ((Object)(object)firearm == (Object)null) { return false; } try { if ((object)isTransformedMethod != null) { return (bool)isTransformedMethod.Invoke(meatyceiverInstance, new object[1] { firearm }); } string text = ((Object)firearm).name.ToLower(); return text.Contains("meat") || text.Contains("flesh") || text.Contains("organic"); } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Error checking transformation status: " + ex.Message)); return false; } } public static WeaponQuality GetWeaponQuality(FVRFireArm firearm) { if ((Object)(object)firearm == (Object)null) { return WeaponQuality.Common; } try { string weaponKey = GetWeaponKey(firearm); if (weaponQualities.ContainsKey(weaponKey)) { return weaponQualities[weaponKey]; } if ((object)getQualityMethod != null && getQualityMethod.Invoke(meatyceiverInstance, new object[1] { firearm }) is int val) { WeaponQuality weaponQuality = (WeaponQuality)Math.Min(val, 5); weaponQualities[weaponKey] = weaponQuality; return weaponQuality; } WeaponQuality weaponQuality2 = DetectWeaponQualityFallback(firearm); weaponQualities[weaponKey] = weaponQuality2; return weaponQuality2; } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Error getting weapon quality: " + ex.Message)); return WeaponQuality.Common; } } public static string GetTransformationStats() { float num = ((TotalTransformationAttempts > 0) ? ((float)SuccessfulTransformations / (float)TotalTransformationAttempts * 100f) : 0f); string text = string.Join(", ", TransformationsByContext.Select<KeyValuePair<string, int>, string>((KeyValuePair<string, int> kvp) => $"{kvp.Key}: {kvp.Value}").ToArray()); string text2 = string.Join(", ", TransformationsByWeaponType.Select<KeyValuePair<string, int>, string>((KeyValuePair<string, int> kvp) => $"{kvp.Key}: {kvp.Value}").ToArray()); return "Meatyceiver 2 Integration Stats:\n• Status: " + (IsMeatyceiver2Available ? "✓ Active" : "✗ Not Available") + "\n• Version: " + DetectedVersion + " (API: " + DetectedApiVersion + ")\n" + $"• Attempts: {TotalTransformationAttempts}\n" + $"• Successes: {SuccessfulTransformations}\n" + $"• Success Rate: {num:F1}%\n" + $"• Cached Results: {CachedResults}\n" + $"• Cooldown Blocked: {CooldownBlocked}\n" + $"• Quality Preserved: {QualityPreserved}\n" + $"• Cache Size: {transformationCache.Count}\n" + "• By Context: " + text + "\n• By Weapon Type: " + text2; } public static void ClearCache() { transformationCache.Clear(); transformationTimes.Clear(); transformationCooldowns.Clear(); weaponQualities.Clear(); CachedResults = 0; logger.LogDebug((object)"[MeatyceiverIntegration] Cache cleared"); } public static bool IsIntegrationEnabled() { return IsMeatyceiver2Available && featureConfigs["Enabled"].Value; } public static string GetCompatibilityInfo() { if (!IsMeatyceiver2Available) { return "Meatyceiver 2 not detected"; } List<string> list = new List<string>(); if ((object)transformMethod != null) { list.Add("Basic Transformation"); } if ((object)checkCompatibilityMethod != null) { list.Add("Compatibility Checking"); } if ((object)isTransformedMethod != null) { list.Add("Transform Status Detection"); } if ((object)getQualityMethod != null) { list.Add("Quality Reading"); } if ((object)setQualityMethod != null) { list.Add("Quality Setting"); } return "Meatyceiver 2 Compatibility:\n• Version: " + DetectedVersion + "\n• API Version: " + DetectedApiVersion + "\n" + list.Count + "• Available Features: " + string.Join(", ", list.ToArray()) + "\n• Integration Status: " + (IsIntegrationEnabled() ? "Active" : "Disabled"); } public static bool GetFeatureConfig(string key) { if (!featureConfigs.ContainsKey(key)) { return false; } return featureConfigs[key].Value; } public static float GetChanceConfig(string key) { if (!chanceConfigs.ContainsKey(key)) { return 0.02f; } return chanceConfigs[key].Value; } public static float GetMultiplierConfig(string key) { if (!multiplierConfigs.ContainsKey(key)) { return 1f; } return multiplierConfigs[key].Value; } private static float CalculateTransformationChance(FVRFireArm firearm, string context) { float num = 0.02f; if (chanceConfigs.ContainsKey(context)) { num = chanceConfigs[context].Value; } else { context = context.ToLower(); num = (context.Contains("chaos") ? chanceConfigs["Chaos"].Value : ((context.Contains("elite") || context.Contains("boss")) ? chanceConfigs["Elite"].Value : (context.Contains("player") ? chanceConfigs["Player"].Value : (context.Contains("enemy") ? chanceConfigs["EnemyWeapon"].Value : ((!context.Contains("ally")) ? chanceConfigs["Normal"].Value : chanceConfigs["AllyWeapon"].Value))))); } float weaponCategoryMultiplier = GetWeaponCategoryMultiplier(firearm); float num2 = 1f; if (featureConfigs["UseQualityBasedChances"].Value) { num2 = GetQualityMultiplier(firearm); } float num3 = num * weaponCategoryMultiplier * num2; if (featureConfigs["RespectOriginalChances"].Value && (object)transformChanceProperty != null) { try { float val = (float)transformChanceProperty.GetValue(meatyceiverInstance, null); num3 = Math.Min(num3, val); } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not get original chance: " + ex.Message)); } } if (featureConfigs["DebugMode"].Value) { logger.LogDebug((object)$"[MeatyceiverIntegration] Calculated chance for {((Object)firearm).name} ({context}): {num3:P2} (base: {num:P2}, category: {weaponCategoryMultiplier:F2}, quality: {num2:F2})"); } return Mathf.Clamp01(num3); } private static float GetWeaponCategoryMultiplier(FVRFireArm firearm) { string text = ((Object)firearm).name.ToLower(); if (text.Contains("pistol") || text.Contains("handgun")) { return multiplierConfigs["Pistol"].Value; } if (text.Contains("shotgun")) { return multiplierConfigs["Shotgun"].Value; } if (text.Contains("smg") || text.Contains("submachine")) { return multiplierConfigs["SMG"].Value; } if (text.Contains("sniper") || text.Contains("precision")) { return multiplierConfigs["Sniper"].Value; } if (text.Contains("lmg") || text.Contains("machinegun")) { return multiplierConfigs["LMG"].Value; } if (text.Contains("assault") || text.Contains("carbine")) { return multiplierConfigs["AssaultRifle"].Value; } if (text.Contains("rifle")) { return multiplierConfigs["Rifle"].Value; } return 1f; } private static float GetQualityMultiplier(FVRFireArm firearm) { return GetWeaponQuality(firearm) switch { WeaponQuality.Common => multiplierConfigs["CommonQuality"].Value, WeaponQuality.Uncommon => multiplierConfigs["UncommonQuality"].Value, WeaponQuality.Rare => multiplierConfigs["RareQuality"].Value, WeaponQuality.Epic => multiplierConfigs["EpicQuality"].Value, WeaponQuality.Legendary => multiplierConfigs["LegendaryQuality"].Value, WeaponQuality.Artifact => multiplierConfigs["ArtifactQuality"].Value, _ => 1f, }; } private static WeaponQuality DetectWeaponQualityFallback(FVRFireArm firearm) { string text = ((Object)firearm).name.ToLower(); if (text.Contains("legendary") || text.Contains("mythic") || text.Contains("unique")) { return WeaponQuality.Legendary; } if (text.Contains("epic") || text.Contains("purple") || text.Contains("elite")) { return WeaponQuality.Epic; } if (text.Contains("rare") || text.Contains("blue") || text.Contains("special")) { return WeaponQuality.Rare; } if (text.Contains("uncommon") || text.Contains("green") || text.Contains("enhanced")) { return WeaponQuality.Uncommon; } return WeaponQuality.Common; } private static bool PerformTransformation(FVRFireArm firearm, string context) { if ((object)transformMethod == null) { logger.LogWarning((object)"[MeatyceiverIntegration] No transform method available"); return false; } try { int num = 0; WeaponQuality weaponQuality = WeaponQuality.Common; List<FVRFireArmAttachment> list = new List<FVRFireArmAttachment>(); if (featureConfigs["PreserveAmmo"].Value && (Object)(object)firearm.Magazine != (Object)null) { num = firearm.Magazine.m_numRounds; } if (featureConfigs["PreserveQuality"].Value) { weaponQuality = GetWeaponQuality(firearm); } if (featureConfigs["PreserveAttachments"].Value) { list.AddRange(((Component)firearm).GetComponentsInChildren<FVRFireArmAttachment>()); } object obj = transformMethod.Invoke(meatyceiverInstance, new object[1] { firearm }); bool flag = !(obj is bool) || (bool)obj; if (flag) { if (featureConfigs["PreserveAmmo"].Value && (Object)(object)firearm.Magazine != (Object)null && num > 0) { firearm.Magazine.m_numRounds = num; } if (featureConfigs["PreserveQuality"].Value && (object)setQualityMethod != null && weaponQuality > WeaponQuality.Common) { try { setQualityMethod.Invoke(meatyceiverInstance, new object[2] { firearm, (int)weaponQuality }); QualityPreserved++; } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not preserve quality: " + ex.Message)); } } } return flag; } catch (Exception ex2) { logger.LogError((object)("[MeatyceiverIntegration] Transformation failed: " + ex2.Message)); return false; } } private static bool IsOnCooldown(string weaponKey) { if (!transformationCooldowns.ContainsKey(weaponKey)) { return false; } DateTime dateTime = transformationCooldowns[weaponKey].AddSeconds(intConfigs["CooldownSeconds"].Value); return DateTime.Now < dateTime; } private static void SetCooldown(string weaponKey) { transformationCooldowns[weaponKey] = DateTime.Now; } private static void UpdateTransformationStatistics(string context, FVRFireArm firearm) { if (!TransformationsByContext.ContainsKey(context)) { TransformationsByContext[context] = 0; } TransformationsByContext[context]++; string weaponTypeName = GetWeaponTypeName(firearm); if (!TransformationsByWeaponType.ContainsKey(weaponTypeName)) { TransformationsByWeaponType[weaponTypeName] = 0; } TransformationsByWeaponType[weaponTypeName]++; } private static string GetWeaponTypeName(FVRFireArm firearm) { string text = ((Object)firearm).name.ToLower(); if (text.Contains("pistol") || text.Contains("handgun")) { return "Pistol"; } if (text.Contains("shotgun")) { return "Shotgun"; } if (text.Contains("smg") || text.Contains("submachine")) { return "SMG"; } if (text.Contains("sniper")) { return "Sniper"; } if (text.Contains("lmg")) { return "LMG"; } if (text.Contains("rifle")) { return "Rifle"; } return "Unknown"; } private static void PlayTransformationSound(Vector3 position) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) try { AudioManager audioManager = Object.FindObjectOfType<AudioManager>(); if ((Object)(object)audioManager != (Object)null) { audioManager.PlayWeaponSpawnSound("transformation", position); } else { logger.LogDebug((object)$"[MeatyceiverIntegration] Playing transformation sound at {position}"); } } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not play transformation sound: " + ex.Message)); } } private static void ShowTransformationParticles(Vector3 position) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) try { EffectsManager effectsManager = Object.FindObjectOfType<EffectsManager>(); if ((Object)(object)effectsManager != (Object)null) { logger.LogDebug((object)$"[MeatyceiverIntegration] Showing transformation particles at {position}"); } else { logger.LogDebug((object)$"[MeatyceiverIntegration] Showing transformation particles at {position}"); } } catch (Exception ex) { logger.LogDebug((object)("[MeatyceiverIntegration] Could not show transformation particles: " + ex.Message)); } } private static string GetWeaponKey(FVRFireArm firearm) { try { if (((FVRPhysicalObject)firearm).ObjectWrapper?.ItemID != null) { return ((FVRPhysicalObject)firearm).ObjectWrapper.ItemID; } return ((Object)((Component)firearm).gameObject).GetInstanceID().ToString(); } catch { return ((object)firearm).GetHashCode().ToString(); } } private static void CacheResult(string weaponKey, bool result) { if (featureConfigs["EnableCaching"].Value) { transformationCache[weaponKey] = result; transformationTimes[weaponKey] = DateTime.Now; if (transformationCache.Count > intConfigs["MaxCacheSize"].Value) { CleanOldCacheEntries(forceClear: true); } if ((DateTime.Now - lastCacheClear).TotalMinutes > 5.0) { CleanOldCacheEntries(); lastCacheClear = DateTime.Now; } } } private static void CleanOldCacheEntries(bool forceClear = false) { DateTime dateTime = DateTime.Now.AddMinutes(-intConfigs["CacheLifetimeMinutes"].Value); List<string> list = new List<string>(); foreach (KeyValuePair<string, DateTime> transformationTime in transformationTimes) { if (transformationTime.Value < dateTime || forceClear) { list.Add(transformationTime.Key); } } if (forceClear && list.Count < transformationCache.Count / 2) { IEnumerable<KeyValuePair<string, DateTime>> source = transformationTimes.OrderBy<KeyValuePair<string, DateTime>, DateTime>((KeyValuePair<string, DateTime> kvp) => kvp.Value).Take(transformationCache.Count / 2); list.AddRange(source.Select((KeyValuePair<string, DateTime> kvp) => kvp.Key)); } foreach (string item in list) { transformationCache.Remove(item); transformationTimes.Remove(item); weaponQualities.Remove(item); } if (list.Count > 0) { logger.LogDebug((object)$"[MeatyceiverIntegration] Cleaned {list.Count} cache entries"); } } } public static class StovepipeIntegrationManager { public enum MalfunctionType { None, Stovepipe, DoubleFeed, FailureToFeed, FailureToEject, FailureToFire, HangFire, SquibLoad, SlamFire, OutOfBattery, BrokenExtractor, DirtyGun, AmmoIssue } public enum WeaponCategory { Unknown, Pistol, Rifle, Shotgun, SMG, LMG, AssaultRifle, Sniper, Revolver, Bolt, Pump } private static ManualLogSource logger; private static bool initialized = false; private static Type stovepipeType; private static object stovepipeInstance; private static MethodInfo forceMalfunctionMethod; private static MethodInfo checkCompatibilityMethod; private static MethodInfo getJamStateMethod; private static MethodInfo clearJamMethod; private static MethodInfo setJamChanceMethod; private static MethodInfo getMalfunctionTypeMethod; private static PropertyInfo malfunctionChanceProperty; private static PropertyInfo jamStateProperty; private static FieldInfo enabledField; private static ConfigFile config; private static Dictionary<string, ConfigEntry<float>> chanceConfigs; private static Dictionary<string, ConfigEntry<bool>> featureConfigs; private static Dictionary<string, ConfigEntry<float>> multiplierConfigs; private static Dictionary<string, ConfigEntry<int>> intConfigs; private static readonly Dictionary<string, bool> jamCapabilityCache = new Dictionary<string, bool>(); private static readonly Dictionary<string, DateTime> lastJamTimes = new Dictionary<string, DateTime>(); private static readonly Dictionary<string, MalfunctionType> lastMalfunctionTypes = new Dictionary<string, MalfunctionType>(); private static readonly Dictionary<string, DateTime> jamCooldowns = new Dictionary<string, DateTime>(); private static DateTime lastCacheClear = DateTime.Now; private const string STOVEPIPE_GUID = "dll.stovepipe"; private const string STOVEPIPE_LEGACY_GUID = "stovepipe.weapon.jams"; private const string STOVEPIPE_ALPHA_GUID = "stovepipe.alpha"; private const string STOVEPIPE_BETA_GUID = "stovepipe.beta"; public static bool IsStovepipeAvailable { get; private set; } = false; public static string DetectedVersion { get; private set; } = "Unknown"; public static string DetectedApiVersion { get; private set; } = "Unknown"; public static int TotalMalfunctionAttempts { get; private set; } = 0; public static int SuccessfulMalfunctions { get; private set; } = 0; public static int CachedResults { get; private set; } = 0; public static int CooldownBlocked { get; private set; } = 0; public static int JamsCleared { get; private set; } = 0; public static Dictionary<string, int> MalfunctionsByContext { get; private set; } = new Dictionary<string, int>(); public static Dictionary<string, int> MalfunctionsByWeaponType { get; private set; } = new Dictionary<string, int>(); public static Dictionary<MalfunctionType, int> MalfunctionsByType { get; private set; } = new Dictionary<MalfunctionType, int>(); public static void Initialize(ManualLogSource logSource, ConfigFile configFile) { if (!initialized) { logger = logSource; config = configFile; logger.LogInfo((object)"[StovepipeIntegration] Initializing Stovepipe integration..."); InitializeConfiguration(); DetectStovepipe(); if (IsStovepipeAvailable) { CacheStovepipeMethods(); InitializeCompatibilityLayer(); logger.LogInfo((object)("[StovepipeIntegration] Successfully initialized with Stovepipe " + DetectedVersion + " (API: " + DetectedApiVersion + ")")); } else { logger.LogInfo((object)"[StovepipeIntegration] Stovepipe not detected - integration disabled"); } initialized = true; } } private static void InitializeConfiguration() { chanceConfigs = new Dictionary<string, ConfigEntry<float>>(); featureConfigs = new Dictionary<string, ConfigEntry<bool>>(); multiplierConfigs = new Dictionary<string, ConfigEntry<float>>(); intConfigs = new Dictionary<string, ConfigEntry<int>>(); chanceConfigs["Normal"] = config.Bind<float>("Stovepipe", "ChanceNormal", 0.01f, "Normal malfunction chance"); chanceConfigs["Combat"] = config.Bind<float>("Stovepipe", "ChanceCombat", 0.03f, "Combat stress malfunction chance"); chanceConfigs["Dirty"] = config.Bind<float>("Stovepipe", "ChanceDirty", 0.08f, "Dirty weapon malfunction chance"); chanceConfigs["Player"] = config.Bind<float>("Stovepipe", "ChancePlayer", 0.02f, "Player weapon malfunction chance"); chanceConfigs["Enemy"] = config.Bind<float>("Stovepipe", "ChanceEnemy", 0.04f, "Enemy weapon malfunction chance"); chanceConfigs["Ally"] = config.Bind<float>("Stovepipe", "ChanceAlly", 0.015f, "Ally weapon malfunction chance"); chanceConfigs["Elite"] = config.Bind<float>("Stovepipe", "ChanceElite", 0.005f, "Elite weapon malfunction chance"); chanceConfigs["Boss"] = config.Bind<float>("Stovepipe", "ChanceBoss", 0.001f, "Boss weapon malfunction chance"); chanceConfigs["WornOut"] = config.Bind<float>("Stovepipe", "ChanceWornOut", 0.12f, "Worn out weapon malfunction chance"); chanceConfigs["Overheated"] = config.Bind<float>("Stovepipe", "ChanceOverheated", 0.06f, "Overheated weapon malfunction chance"); multiplierConfigs["Pistol"] = config.Bind<float>("Stovepipe", "PistolMultiplier", 1.2f, "Pistol malfunction multiplier"); multiplierConfigs["Rifle"] = config.Bind<float>("Stovepipe", "RifleMultiplier", 0.8f, "Rifle malfunction multiplier"); multiplierConfigs["Shotgun"] = config.Bind<float>("Stovepipe", "ShotgunMultiplier", 0.6f, "Shotgun malfunction multiplier"); multiplierConfigs["SMG"] = config.Bind<float>("Stovepipe", "SMGMultiplier", 1.4f, "SMG malfunction multiplier"); multiplierConfigs["LMG"] = config.Bind<float>("Stovepipe", "LMGMultiplier", 1.1f, "LMG malfunction multiplier"); multiplierConfigs["AssaultRifle"] = config.Bind<float>("Stovepipe", "AssaultRifleMultiplier", 0.9f, "Assault rifle malfunction multiplier"); multiplierConfigs["Sniper"] = config.Bind<float>("Stovepipe", "SniperMultiplier", 0.7f, "Sniper rifle malfunction multiplier"); multiplierConfigs["Revolver"] = config.Bind<float>("Stovepipe", "RevolverMultiplier", 0.3f, "Revolver malfunction multiplier"); multiplierConfigs["Bolt"] = config.Bind<float>("Stovepipe", "BoltMultiplier", 0.2f, "Bolt action malfunction multiplier"); multiplierConfigs["Pump"] = config.Bind<float>("Stovepipe", "PumpMultiplier", 0.4f, "Pump action malfunction multiplier"); multiplierConfigs["StovepipeChance"] = config.Bind<float>("Stovepipe", "StovepipeChance", 1.5f, "Stovepipe jam chance multiplier"); multiplierConfigs["DoubleFeedChance"] = config.Bind<float>("Stovepipe", "DoubleFeedChance", 1f, "Double feed chance multiplier"); multiplierConfigs["FailureToFeedChance"] = config.Bind<float>("Stovepipe", "FailureToFeedChance", 1.2f, "Failure to feed chance multiplier"); multiplierConfigs["FailureToEjectChance"] = config.Bind<float>("Stovepipe", "FailureToEjectChance", 1.1f, "Failure to eject chance multiplier"); multiplierConfigs["FailureToFireChance"] = config.Bind<float>("Stovepipe", "FailureToFireChance", 0.8f, "Failure to fire chance multiplier"); multiplierConfigs["HangFireChance"] = config.Bind<float>("Stovepipe", "HangFireChance", 0.3f, "Hang fire chance multiplier"); featureConfigs["Enabled"] = config.Bind<bool>("Stovepipe", "Enabled", true, "Enable Stovepipe integration"); featureConfigs["AutoClearJams"] = config.Bind<bool>("Stovepipe", "AutoClearJams", false, "Automatically clear jams after delay"); featureConfigs["ContextualMalfunctions"] = config.Bind<bool>("Stovepipe", "ContextualMalfunctions", true, "Use contextual malfunction logic"); featureConfigs["RealisticJamTypes"] = config.Bind<bool>("Stovepipe", "RealisticJamTypes", true, "Use realistic jam types based on weapon"); featureConfigs["EnableCooldowns"] = config.Bind<bool>("Stovepipe", "EnableCooldowns", true, "Enable jam cooldowns"); featureConfigs["EnableCaching"] = config.Bind<bool>("Stovepipe", "EnableCaching", true, "Enable jam capability caching"); featureConfigs["DirtAccumulation"] = config.Bind<bool>("Stovepipe", "DirtAccumulation", true, "Enable dirt accumulation system"); featureConfigs["HeatBuildup"] = config.Bind<bool>("Stovepipe", "HeatBuildup", true, "Enable heat buildup system"); featureConfigs["AmmoQualityAffectsJams"] = config.Bind<bool>("Stovepipe", "AmmoQualityAffectsJams", true, "Ammunition quality affects jam chance"); featureConfigs["WeaponConditionTracking"] = config.Bind<bool>("Stovepipe", "WeaponConditionTracking", true, "Track weapon condition for jam chances"); featureConfigs["PlayMalfunctionSounds"] = config.Bind<bool>("Stovepipe", "PlayMalfunctionSounds", true, "Play malfunction sound effects"); featureConfigs["ShowMalfunctionParticles"] = config.Bind<bool>("Stovepipe", "ShowMalfunctionParticles", true, "Show malfunction particle effects"); featureConfigs["EnableBatchJamming"] = config.Bind<bool>("Stovepipe", "EnableBatchJamming", true, "Enable batch jamming support"); featureConfigs["DebugMode"] = config.Bind<bool>("Stovepipe", "DebugMode", false, "Enable debug mode"); featureConfigs["VerboseLogging"] = config.Bind<bool>("Stovepipe", "VerboseLogging", false, "Enable verbose logging"); intConfigs["JamCooldownSeconds"] = config.Bind<int>("Stovepipe", "JamCooldownSeconds", 5, "Cooldown between jams (seconds)"); intConfigs["AutoClearDelaySeconds"] = config.Bind<int>("Stovepipe", "AutoClearDelaySeconds", 15, "Auto clear jam delay (seconds)"); intConfigs["CacheLifetimeMinutes"] = config.Bind<int>("Stovepipe", "CacheLifetimeMinutes", 15, "Cache entry lifetime in minutes"); intConfigs["MaxCacheSize"] = config.Bind<int>("Stovepipe", "MaxCacheSize", 500, "Maximum number of cached entries"); intConfigs["BatchSize"] = config.Bind<int>("Stovepipe", "BatchSize", 5, "Maximum weapons to jam in a single batch"); intConfigs["MaxDirtLevel"] = config.Bind<int>("Stovepipe", "MaxDirtLevel", 100, "Maximum dirt accumulation level"); intConfigs["MaxHeatLevel"] = config.Bind<int>("Stovepipe", "MaxHeatLevel", 100, "Maximum heat buildup level"); } private static void DetectStovepipe() { try { Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos; if (pluginInfos.ContainsKey("dll.stovepipe")) { IsStovepipeAvailable = true; DetectedVersion = pluginInfos["dll.stovepipe"].Metadata.Version.ToString(); logger.LogInfo((object)("[StovepipeIntegra