Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of VAI TER CEBOLA v1.1.5
plugins/Cebola/BakaMODs.VaiTerCebola.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BakaMODs.VaiTerCebola.Configuration; using BakaMODs.VaiTerCebola.NetcodePatcher; using BakaMODs.VaiTerCebola.Patches; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalLib.Modules; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BakaMODs.VaiTerCebola")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.5.0")] [assembly: AssemblyInformationalVersion("1.1.5+0864a05544691c96bb0f101813317f1ce77b7629")] [assembly: AssemblyProduct("VaiTerCebola")] [assembly: AssemblyTitle("BakaMODs.VaiTerCebola")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.5.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] internal class <Module> { static <Module>() { } } 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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BakaMODs.VaiTerCebola { internal sealed class AudioPlaybackGate { private float nextEligibleTime; internal bool TryPlay(int pickupCount, bool once, bool enabled, bool audible, bool alreadyPlaying, float volume, float now, float cooldown, float clipLength) { if (!enabled || !audible || volume <= 0f || alreadyPlaying || (once && pickupCount != 1) || now < nextEligibleTime) { return false; } nextEligibleTime = now + Math.Max(cooldown, clipLength); return true; } internal void Reset() { nextEligibleTime = 0f; } } public class CebolaEfeitos : NetworkBehaviour { public AudioClip? somInteracao; public AudioClip? somSoltar; public AudioClip? somVendaMaldita; private GrabbableObject item; private AudioSource voice; private ScanNodeProperties? scan; private string scanHeader = "Cebolão Gostoso"; private readonly NetworkVariable<int> pickups = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private readonly NetworkVariable<int> drops = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); private PlayerControllerB? previousHolder; private float nextValueRefresh; private static readonly AudioPlaybackGate audioGate = new AudioPlaybackGate(); private static readonly AudioPlaybackGate dropAudioGate = new AudioPlaybackGate(); private static AudioSource? activeVoice; private void Awake() { item = ((Component)this).GetComponent<GrabbableObject>(); NetworkObject component = ((Component)this).GetComponent<NetworkObject>(); if ((Object)(object)component != (Object)null) { component.AutoObjectParentSync = false; } Rigidbody[] componentsInChildren = ((Component)this).GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody val in componentsInChildren) { val.isKinematic = true; val.useGravity = false; val.interpolation = (RigidbodyInterpolation)0; val.collisionDetectionMode = (CollisionDetectionMode)0; } scan = ((Component)this).GetComponentInChildren<ScanNodeProperties>(true); if ((Object)(object)scan != (Object)null) { scanHeader = scan.headerText; Collider[] componentsInChildren2 = ((Component)scan).GetComponentsInChildren<Collider>(true); foreach (Collider val2 in componentsInChildren2) { val2.isTrigger = true; } } voice = ((Component)this).GetComponent<AudioSource>() ?? ((Component)this).gameObject.AddComponent<AudioSource>(); voice.playOnAwake = false; voice.loop = false; voice.spatialBlend = 1f; voice.dopplerLevel = 0f; voice.spatialize = false; voice.minDistance = 1f; voice.maxDistance = 12f; voice.rolloffMode = (AudioRolloffMode)1; } public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); NetworkVariable<int> obj = pickups; obj.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Combine((Delegate?)(object)obj.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnPickupCountChanged)); NetworkVariable<int> obj2 = drops; obj2.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Combine((Delegate?)(object)obj2.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnDropCountChanged)); } public override void OnNetworkDespawn() { NetworkVariable<int> obj = pickups; obj.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Remove((Delegate?)(object)obj.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnPickupCountChanged)); NetworkVariable<int> obj2 = drops; obj2.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Remove((Delegate?)(object)obj2.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnDropCountChanged)); voice.Stop(); ((NetworkBehaviour)this).OnNetworkDespawn(); } private void OnPickupCountChanged(int previous, int current) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) PluginConfig settings = VaiTerCebolaPlugin.Settings; if (!((Object)(object)somInteracao == (Object)null)) { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; bool audible = (Object)(object)val != (Object)null && Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position) <= voice.maxDistance; if (audioGate.TryPlay(current, settings.PlayOncePerOnion.Value, settings.AudioEnabled.Value, audible, (Object)(object)activeVoice != (Object)null && activeVoice.isPlaying, settings.AudioVolume.Value, Time.unscaledTime, settings.AudioCooldown.Value, somInteracao.length)) { voice.volume = settings.AudioVolume.Value; voice.PlayOneShot(somInteracao); activeVoice = voice; } } } private void OnDropCountChanged(int previous, int current) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)somSoltar == (Object)null) { return; } PluginConfig settings = VaiTerCebolaPlugin.Settings; PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; bool audible = (Object)(object)val != (Object)null && Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position) <= voice.maxDistance; if (dropAudioGate.TryPlay(current, once: false, settings.AudioEnabled.Value, audible, alreadyPlaying: false, settings.AudioVolume.Value, Time.unscaledTime, settings.DropAudioCooldown.Value, 0f)) { if ((Object)(object)activeVoice != (Object)null) { activeVoice.Stop(); } voice.mute = false; voice.volume = settings.AudioVolume.Value; voice.PlayOneShot(somSoltar); activeVoice = voice; } } private void Update() { if (!((Object)(object)item == (Object)null)) { OnionPlayerEffects.ObserveHeldOnion(item); voice.mute = !VaiTerCebolaPlugin.Settings.AudioEnabled.Value; voice.volume = VaiTerCebolaPlugin.Settings.AudioVolume.Value; if (voice.mute && voice.isPlaying) { voice.Stop(); } PlayerControllerB val = (item.isHeld ? item.playerHeldBy : null); if ((Object)(object)val != (Object)(object)previousHolder) { VaiTerCebolaPlugin.Logger.LogInfo((object)string.Format("Onion holder changed: held={0}, pocketed={1}, holder={2}", item.isHeld, item.isPocketed, ((Object)(object)val != (Object)null) ? val.playerClientId.ToString() : "none")); } if (((NetworkBehaviour)this).IsSpawned && ((NetworkBehaviour)this).IsServer && (Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)previousHolder) { NetworkVariable<int> obj = pickups; int value = obj.Value; obj.Value = value + 1; } if (((NetworkBehaviour)this).IsSpawned && ((NetworkBehaviour)this).IsServer && (Object)(object)val == (Object)null && (Object)(object)previousHolder != (Object)null && !item.isPocketed && !item.isHeldByEnemy) { NetworkVariable<int> obj2 = drops; int value = obj2.Value; obj2.Value = value + 1; } previousHolder = val; if (Time.unscaledTime >= nextValueRefresh) { nextValueRefresh = Time.unscaledTime + 1f; AtualizarValorScrap(VaiTerCebolaPlugin.CalcularValorBaseDeScrap()); } } } public void AtualizarValorScrap(int value) { if ((Object)(object)item != (Object)null) { item.scrapValue = value; } if (!((Object)(object)scan == (Object)null)) { scan.scrapValue = value; scan.headerText = scanHeader; scan.subText = $"Valor: ${value} | Venda: ~${350}"; } } public void ScheduleScanRefresh() { nextValueRefresh = 0f; } internal static void ResetAudioSession() { if ((Object)(object)activeVoice != (Object)null) { activeVoice.Stop(); } activeVoice = null; audioGate.Reset(); dropAudioGate.Reset(); } protected override void __initializeVariables() { if (pickups == null) { throw new Exception("CebolaEfeitos.pickups cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)pickups).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)pickups, "pickups"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)pickups); if (drops == null) { throw new Exception("CebolaEfeitos.drops cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)drops).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)drops, "drops"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)drops); ((NetworkBehaviour)this).__initializeVariables(); } protected internal override string __getTypeName() { return "CebolaEfeitos"; } } internal sealed class OnionDizziness { private float amount; private bool wasHolding; internal float Step(bool holding, bool enabled, float current, float deltaTime) { bool flag = holding && enabled; float result = current; if (flag) { if (!wasHolding) { amount = Math.Max(amount, Math.Min(current, 1f)); } amount = Math.Min(amount + deltaTime / 60f, 1f); result = Math.Max(current, amount); } else if (amount > 0f) { float val = Math.Max(0f, amount - deltaTime / 120f); if (current <= amount + 0.001f) { result = Math.Min(current, val); } amount = val; } wasHolding = flag; return result; } internal void Reset() { amount = 0f; wasHolding = false; } } public sealed class OnionPlayerEffects : MonoBehaviour { private PlayerControllerB player; private GrabbableObject? heldOnion; private readonly OnionDizziness dizziness = new OnionDizziness(); private bool wasHolding; private bool showedTip; private float nextLog; internal static void ObserveHeldOnion(GrabbableObject onion) { PlayerControllerB playerHeldBy = onion.playerHeldBy; if (onion.isHeld && !onion.isPocketed && !((Object)(object)playerHeldBy == (Object)null) && IsLocal(playerHeldBy)) { OnionPlayerEffects onionPlayerEffects = ((Component)playerHeldBy).GetComponent<OnionPlayerEffects>(); if ((Object)(object)onionPlayerEffects == (Object)null) { onionPlayerEffects = ((Component)playerHeldBy).gameObject.AddComponent<OnionPlayerEffects>(); onionPlayerEffects.player = playerHeldBy; VaiTerCebolaPlugin.Logger.LogInfo((object)"Onion player effect controller attached to local holder."); } onionPlayerEffects.heldOnion = onion; } } private static bool IsLocal(PlayerControllerB holder) { if (!((Object)(object)GameNetworkManager.Instance != (Object)null) || !((Object)(object)holder == (Object)(object)GameNetworkManager.Instance.localPlayerController)) { if ((Object)(object)StartOfRound.Instance != (Object)null) { return (Object)(object)holder == (Object)(object)StartOfRound.Instance.localPlayerController; } return false; } return true; } private void LateUpdate() { Tick(Time.deltaTime); } internal void Tick(float deltaTime) { if ((Object)(object)player == (Object)null || !IsLocal(player) || player.isPlayerDead) { heldOnion = null; dizziness.Reset(); wasHolding = false; return; } bool flag = (Object)(object)heldOnion != (Object)null && heldOnion.isHeld && !heldOnion.isPocketed && (Object)(object)heldOnion.playerHeldBy == (Object)(object)player; player.drunkness = dizziness.Step(flag, VaiTerCebolaPlugin.Settings.DizzinessEnabled.Value, player.drunkness, deltaTime); if (flag != wasHolding) { VaiTerCebolaPlugin.Logger.LogInfo((object)$"Onion effect: holding={flag}, enabled={VaiTerCebolaPlugin.Settings.DizzinessEnabled.Value}, drunkness={player.drunkness:F3}"); nextLog = Time.unscaledTime + 15f; wasHolding = flag; } if (flag && Time.unscaledTime >= nextLog) { nextLog = Time.unscaledTime + 15f; VaiTerCebolaPlugin.Logger.LogInfo((object)$"Onion effect intensity: {player.drunkness:F3}"); } if (flag && !player.isTypingChat && !player.inTerminalMenu) { if (!showedTip && (Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip("Cebola", "[Q] Silenciar/ativar vozes das cebolas só para você.", false, false, "LC_Tip1"); showedTip = true; } if (Keyboard.current != null && ((ButtonControl)Keyboard.current.qKey).wasPressedThisFrame) { VaiTerCebolaPlugin.Settings.AudioEnabled.Value = !VaiTerCebolaPlugin.Settings.AudioEnabled.Value; } } } private void OnDestroy() { CebolaEfeitos.ResetAudioSession(); } } [BepInPlugin("BakaMODs.VaiTerCebola", "VaiTerCebola", "1.1.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class VaiTerCebolaPlugin : BaseUnityPlugin { internal static ManualLogSource Logger; private readonly Harmony harmony = new Harmony("BakaMODs.VaiTerCebola"); private const string AssetBundleName = "cebolaassets"; private const string ScrapItemAssetPath = "Assets/ModAssets/Cebola/Cebola.asset"; internal const int ValorVendaBase = 350; public static Item? CebolaScrap; public static AssetBundle? ModAssetBundle; internal static PluginConfig Settings; internal static int CalcularValorBaseDeScrap() { float num = 1f; try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null) { num = instance.companyBuyingRate; } } catch { num = 1f; } num = Mathf.Clamp(num, 0.01f, 100f); int num2 = Mathf.Max(1, Mathf.RoundToInt(350f / num)); if (Mathf.RoundToInt((float)num2 * num) == 350) { return num2; } for (int i = 1; i <= 200; i++) { int num3 = num2 + i; if (Mathf.RoundToInt((float)num3 * num) == 350) { return num3; } int num4 = num2 - i; if (num4 > 0 && Mathf.RoundToInt((float)num4 * num) == 350) { return num4; } } return num2; } private void Awake() { //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) Logger = ((BaseUnityPlugin)this).Logger; Settings = new PluginConfig(((BaseUnityPlugin)this).Config); string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? "", "cebolaassets"); ModAssetBundle = AssetBundle.LoadFromFile(text); if ((Object)(object)ModAssetBundle == (Object)null) { Logger.LogError((object)"Falha ao carregar o AssetBundle! Verifique se o arquivo 'cebolaassets' está na pasta do mod."); return; } CebolaScrap = ModAssetBundle.LoadAsset<Item>("Assets/ModAssets/Cebola/Cebola.asset"); if ((Object)(object)CebolaScrap == (Object)null) { Logger.LogError((object)"Falha ao carregar o asset do item 'Assets/ModAssets/Cebola/Cebola.asset' do AssetBundle."); return; } GameObject spawnPrefab = CebolaScrap.spawnPrefab; CebolaEfeitos cebolaEfeitos = (((Object)(object)spawnPrefab != (Object)null) ? spawnPrefab.GetComponent<CebolaEfeitos>() : null); if ((Object)(object)spawnPrefab == (Object)null || (Object)(object)cebolaEfeitos == (Object)null || (Object)(object)spawnPrefab.GetComponent<GrabbableObject>() == (Object)null) { Logger.LogError((object)"Cebola prefab is missing its item/effect component. Registration aborted; check the DLL and asset bundle pair."); return; } ((Behaviour)cebolaEfeitos).enabled = true; NetworkObject component = spawnPrefab.GetComponent<NetworkObject>(); if ((Object)(object)component == (Object)null) { Logger.LogError((object)"Cebola prefab has no NetworkObject; registration aborted."); return; } component.AutoObjectParentSync = false; Logger.LogInfo((object)$"Cebola prefab validated: effects enabled, pickupClip={(Object)(object)cebolaEfeitos.somInteracao != (Object)null}, dropClip={(Object)(object)cebolaEfeitos.somSoltar != (Object)null}"); CebolaScrap.minValue = 350; CebolaScrap.maxValue = 350; CebolaScrap.creditsWorth = 350; CebolaScrap.itemSpawnsOnGround = true; CebolaScrap.restingRotation = Vector3.zero; if ((Object)(object)CebolaScrap.spawnPrefab != (Object)null) { GrabbableObject component2 = CebolaScrap.spawnPrefab.GetComponent<GrabbableObject>(); if ((Object)(object)component2 != (Object)null) { component2.scrapValue = CalcularValorBaseDeScrap(); } BoxCollider component3 = CebolaScrap.spawnPrefab.GetComponent<BoxCollider>(); if ((Object)(object)component3 != (Object)null) { CebolaScrap.verticalOffset = Mathf.Max(0f, (component3.size.y * 0.5f - component3.center.y) * Mathf.Abs(CebolaScrap.spawnPrefab.transform.localScale.y)) + 0.02f; } } Items.RegisterScrap(CebolaScrap, 20, (LevelTypes)(-1)); if ((Object)(object)CebolaScrap.spawnPrefab != (Object)null) { NetworkPrefabs.RegisterNetworkPrefab(CebolaScrap.spawnPrefab); } else { Logger.LogError((object)"spawnPrefab da CebolaScrap é nulo; não foi possível registrar o NetworkPrefab."); } Logger.LogInfo((object)"Cebola registrada como sucata."); harmony.PatchAll(typeof(GrabbableObjectPatch)); harmony.PatchAll(typeof(RoundManagerPatch)); harmony.PatchAll(typeof(DepositItemsDeskPatch)); Logger.LogInfo((object)"Spawn nativo e venda maldita da cebola ativos."); Logger.LogInfo((object)"Plugin BakaMODs.VaiTerCebola foi carregado!"); } } public static class PluginInfo { public const string PLUGIN_GUID = "BakaMODs.VaiTerCebola"; public const string PLUGIN_NAME = "VaiTerCebola"; public const string PLUGIN_VERSION = "1.1.5"; } } namespace BakaMODs.VaiTerCebola.Patches { [HarmonyPatch(typeof(DepositItemsDesk))] internal static class DepositItemsDeskPatch { private static readonly HashSet<GrabbableObject> cursedOnions = new HashSet<GrabbableObject>(); [HarmonyPatch("PlaceItemOnCounter")] [HarmonyPrefix] private static void OnPlaceItemOnCounter(DepositItemsDesk __instance, PlayerControllerB playerWhoTriggered) { GrabbableObject item = (((Object)(object)playerWhoTriggered != (Object)null) ? playerWhoTriggered.currentlyHeldObjectServer : null); if (TryClaimCurse(item, out CebolaEfeitos cebola)) { ((MonoBehaviour)__instance).StartCoroutine(VendaMaldita(__instance, cebola, playerWhoTriggered)); } } internal static bool TryClaimCurse(GrabbableObject? item, out CebolaEfeitos? cebola) { cebola = null; if ((Object)(object)item == (Object)null || !VaiTerCebolaPlugin.Settings.CurseOnDelivery.Value) { return false; } cebola = ((Component)item).GetComponent<CebolaEfeitos>(); if ((Object)(object)cebola != (Object)null) { return cursedOnions.Add(item); } return false; } private static IEnumerator VendaMaldita(DepositItemsDesk desk, CebolaEfeitos cebola, PlayerControllerB player) { AudioClip somVendaMaldita = cebola.somVendaMaldita; float num = 2.5f; if ((Object)(object)somVendaMaldita != (Object)null && (Object)(object)desk.deskAudio != (Object)null) { desk.deskAudio.PlayOneShot(somVendaMaldita); num = somVendaMaldita.length; } yield return (object)new WaitForSeconds(num); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && !singleton.IsServer) { desk.AttackPlayersServerRpc(); } else { desk.Attack(); } if ((Object)(object)player != (Object)null) { yield return (object)new WaitForSeconds(0.15f); player.KillPlayer(Vector3.zero, true, (CauseOfDeath)0, 0, default(Vector3), false); } } } [HarmonyPatch(typeof(GrabbableObject))] internal static class GrabbableObjectPatch { [HarmonyPatch("SetScrapValue")] [HarmonyPostfix] private static void OnSetScrapValue(GrabbableObject __instance, int setValueTo) { CebolaEfeitos cebolaEfeitos = default(CebolaEfeitos); if (((Component)__instance).TryGetComponent<CebolaEfeitos>(ref cebolaEfeitos)) { int num = VaiTerCebolaPlugin.CalcularValorBaseDeScrap(); if (__instance.scrapValue != num) { __instance.scrapValue = num; } cebolaEfeitos.AtualizarValorScrap(num); } } } [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] internal static class RoundManagerPatch { [HarmonyTranspiler] internal static IEnumerable<CodeInstruction> AddOnionsToSpawnPlan(IEnumerable<CodeInstruction> instructions) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); ConstructorInfo constructor = AccessTools.Constructor(typeof(List<Item>), (Type[])null, false); var array = (from entry in list.Select((CodeInstruction instruction, int index) => new { instruction, index }) where entry.instruction.opcode == OpCodes.Newobj && object.Equals(entry.instruction.operand, constructor) select entry).ToArray(); if (array.Length != 1) { VaiTerCebolaPlugin.Logger.LogError((object)"Could not find the native scrap spawn plan. Guaranteed onions were not added; check game/mod compatibility."); return list; } list.InsertRange(array[0].index + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Dup, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(RoundManagerPatch), "AddGuaranteedOnions", (Type[])null, (Type[])null)) }); return list; } internal static void AddGuaranteedOnions(List<Item> spawnPlan) { Item cebolaScrap = VaiTerCebolaPlugin.CebolaScrap; if (!((Object)(object)cebolaScrap == (Object)null)) { int value = VaiTerCebolaPlugin.Settings.GuaranteedOnions.Value; for (int i = 0; i < value; i++) { spawnPlan.Add(cebolaScrap); } if (value > 0) { VaiTerCebolaPlugin.Logger.LogInfo((object)$"Added {value} guaranteed onions to the native scrap spawn plan."); } } } } } namespace BakaMODs.VaiTerCebola.Configuration { public sealed class PluginConfig { public ConfigEntry<bool> AudioEnabled { get; } public ConfigEntry<bool> PlayOncePerOnion { get; } public ConfigEntry<float> AudioCooldown { get; } public ConfigEntry<float> AudioVolume { get; } public ConfigEntry<bool> DizzinessEnabled { get; } public ConfigEntry<bool> CurseOnDelivery { get; } public ConfigEntry<int> GuaranteedOnions { get; } public ConfigEntry<float> DropAudioCooldown { get; } public PluginConfig(ConfigFile cfg) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown GuaranteedOnions = cfg.Bind<int>("Spawn", "GuaranteedOnions", 3, new ConfigDescription("Host setting: extra onions added to native interior scrap generation. 0 uses only random scrap selection. Requires available spawn points.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>())); AudioEnabled = cfg.Bind<bool>("Audio", "Enabled", true, "Local preference. Q while holding an onion toggles all onion voices for you."); PlayOncePerOnion = cfg.Bind<bool>("Audio", "PlayOncePerOnion", true, "Only the first pickup of each spawned onion can play its voice. No replay for late joiners."); AudioCooldown = cfg.Bind<float>("Audio", "CooldownSeconds", 60f, new ConfigDescription("Shared cooldown for all onion voices on this client. Suppressed clips are not queued.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>())); AudioVolume = cfg.Bind<float>("Audio", "Volume", 0.35f, new ConfigDescription("Local onion voice volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); DropAudioCooldown = cfg.Bind<float>("Audio", "DropCooldownSeconds", 5f, new ConfigDescription("Shared interval for drop voices, independent of the pickup cooldown. A drop voice replaces the currently playing onion voice.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>())); DizzinessEnabled = cfg.Bind<bool>("Effects", "DizzinessEnabled", true, "Enable gradual dizziness while holding an onion (local accessibility preference)."); CurseOnDelivery = cfg.Bind<bool>("Effects", "CurseOnDelivery", true, "Placing an onion on the Company counter plays the cursed sale voice and makes the Company attack, killing the player who delivered it and anyone nearby (local preference of the player delivering)."); ConfigEntry<bool> val = cfg.Bind<bool>("Migration", "DizzinessRestored111", false, "Internal migration marker. Restores the onion effect once when upgrading to 1.1.1; later player preferences are preserved."); if (!val.Value) { DizzinessEnabled.Value = true; val.Value = true; cfg.Save(); } } } } namespace BakaMODs.VaiTerCebola.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }