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 LethalCards v1.0.3
BepInEx/plugins/LethalCards/LethalCards.dll
Decompiled 2 hours 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.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalCards.Boosters; using LethalCards.Cards; using LethalCards.Debugging; using LethalCards.Grading; using LethalCards.NetcodePatcher; using LethalCards.Networking; using LethalCards.Save; using LethalCards.TerminalCommands; using LethalLib.Modules; using Microsoft.CodeAnalysis; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.Utilities; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LethalCards")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3+8635e2e687f19e9feb1aa37688b4a816a08640b3")] [assembly: AssemblyProduct("LethalCards")] [assembly: AssemblyTitle("LethalCards")] [assembly: AssemblyVersion("1.0.3.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] 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 LethalCards { internal static class BalanceConfig { internal const int DefaultGradingCost = 10; internal const int DefaultGradingTurnaroundDays = 3; internal const int DefaultLightBoosterSpawnWeight = 45; internal const int DefaultHeavyBoosterSpawnWeight = 25; internal const int DefaultStandardBoosterBoxSpawnWeight = 20; internal const int DefaultGoldenBoosterBoxSpawnWeight = 10; internal const int DefaultLightBoosterValue = 30; internal const int DefaultHeavyBoosterValue = 50; internal const int DefaultStandardBoosterBoxValue = 75; internal const int DefaultGoldenBoosterBoxValue = 150; private static readonly WeightedRarityTable DefaultLightSlot1 = new WeightedRarityTable(72.5f, 20f, 7.5f, 0f, 0f); private static readonly WeightedRarityTable DefaultLightSlot2 = new WeightedRarityTable(69f, 20f, 7.5f, 2.5f, 1f); private static readonly WeightedRarityTable DefaultLightSlot3 = new WeightedRarityTable(58f, 20f, 15f, 5f, 2f); private static readonly WeightedRarityTable DefaultHeavySlot1 = new WeightedRarityTable(30f, 55f, 10f, 5f, 0f); private static readonly WeightedRarityTable DefaultHeavySlot2 = new WeightedRarityTable(25f, 50f, 15f, 10f, 0f); private static readonly WeightedRarityTable DefaultHeavySlot3 = new WeightedRarityTable(20f, 40f, 20f, 15f, 5f); private static readonly WeightedVariantTable DefaultVariants = new WeightedVariantTable(69f, 25f, 5f, 1f); private static readonly WeightedGodPackTable DefaultGodPack = new WeightedGodPackTable(60f, 40f); private static readonly WeightedBoosterBoxTable DefaultStandardBoxPackMix = new WeightedBoosterBoxTable(90f, 10f); private static readonly WeightedGradeTable DefaultGrades = new WeightedGradeTable(2f, 4f, 6f, 8f, 10f, 12f, 13f, 23f, 17f, 5f); private static readonly float[] GradeMultipliers = new float[11] { 0f, 0f, 0.2f, 0.35f, 0.5f, 0.65f, 0.8f, 1f, 1.5f, 2.5f, 5f }; private static readonly float[] VariantValueMultipliers = new float[5] { 1f, 1f, 1.5f, 2f, 3f }; internal static WeightedRarityTable LightSlot1 { get; private set; } = DefaultLightSlot1; internal static WeightedRarityTable LightSlot2 { get; private set; } = DefaultLightSlot2; internal static WeightedRarityTable LightSlot3 { get; private set; } = DefaultLightSlot3; internal static WeightedRarityTable HeavySlot1 { get; private set; } = DefaultHeavySlot1; internal static WeightedRarityTable HeavySlot2 { get; private set; } = DefaultHeavySlot2; internal static WeightedRarityTable HeavySlot3 { get; private set; } = DefaultHeavySlot3; internal static WeightedVariantTable Variants { get; private set; } = DefaultVariants; internal static WeightedGodPackTable GodPackRarities { get; private set; } = DefaultGodPack; internal static WeightedBoosterBoxTable StandardBoxPackMix { get; private set; } = DefaultStandardBoxPackMix; internal static WeightedGradeTable GradeChances { get; private set; } = DefaultGrades; internal static float HeavyGodPackChancePercent { get; private set; } = 5f; internal static float HeavyGodPackChance => HeavyGodPackChancePercent / 100f; internal static int GradingCost { get; private set; } = 10; internal static int GradingTurnaroundDays { get; private set; } = 3; internal static int LightBoosterSpawnWeight { get; private set; } = 45; internal static int HeavyBoosterSpawnWeight { get; private set; } = 25; internal static int StandardBoosterBoxSpawnWeight { get; private set; } = 20; internal static int GoldenBoosterBoxSpawnWeight { get; private set; } = 10; internal static int LightBoosterValue { get; private set; } = 30; internal static int HeavyBoosterValue { get; private set; } = 50; internal static int StandardBoosterBoxValue { get; private set; } = 75; internal static int GoldenBoosterBoxValue { get; private set; } = 150; internal static void Load(ConfigFile config) { LightSlot1 = BindRarity(config, "Rarity - Light Slot 1", DefaultLightSlot1); LightSlot2 = BindRarity(config, "Rarity - Light Slot 2", DefaultLightSlot2); LightSlot3 = BindRarity(config, "Rarity - Light Slot 3", DefaultLightSlot3); HeavySlot1 = BindRarity(config, "Rarity - Heavy Slot 1", DefaultHeavySlot1); HeavySlot2 = BindRarity(config, "Rarity - Heavy Slot 2", DefaultHeavySlot2); HeavySlot3 = BindRarity(config, "Rarity - Heavy Slot 3", DefaultHeavySlot3); HeavyGodPackChancePercent = ClampFloat(BindFloat(config, "God Pack", "HeavyGodPackChance", 5f, "Direct percent chance for Heavy packs to become God Packs. Clamped to 0-100. Light packs never become God Packs."), 0f, 100f, "God Pack.HeavyGodPackChance"); GodPackRarities = BindGodPack(config, DefaultGodPack); Variants = BindVariants(config, DefaultVariants); BindVariantValues(config); StandardBoxPackMix = BindBoosterBoxMix(config, DefaultStandardBoxPackMix); GradingCost = ClampInt(BindInt(config, "Grading", "GradingCost", 10, "Credits charged by the grading pedestal per submitted card. Clamped to 0 or higher."), 0, int.MaxValue, "Grading.GradingCost"); GradingTurnaroundDays = ClampInt(BindInt(config, "Grading", "GradingTurnaroundDays", 3, "Number of in-game days before submitted grading jobs become ready. Clamped to 0 or higher."), 0, int.MaxValue, "Grading.GradingTurnaroundDays"); for (int i = 1; i <= 10; i++) { GradeMultipliers[i] = ClampFloat(BindFloat(config, "Grading", $"Grade{i}ValueMultiplier", GradeMultipliers[i], "Multiplier applied to a card's ungraded value after this grade is rolled. Negative values are clamped to 0."), 0f, float.MaxValue, $"Grading.Grade{i}ValueMultiplier"); } GradeChances = BindGrades(config, DefaultGrades); LightBoosterSpawnWeight = BindNonNegativeInt(config, "Spawning", "LightBoosterSpawnWeight", 45, "Relative scrap spawn weight for Light Booster packs on all levels. 0 disables natural spawning while preserving item registration. Restart after changing."); HeavyBoosterSpawnWeight = BindNonNegativeInt(config, "Spawning", "HeavyBoosterSpawnWeight", 25, "Relative scrap spawn weight for Heavy Booster packs on all levels. 0 disables natural spawning while preserving item registration. Restart after changing."); StandardBoosterBoxSpawnWeight = BindNonNegativeInt(config, "Spawning", "StandardBoosterBoxSpawnWeight", 20, "Relative scrap spawn weight for Standard Booster Boxes on all levels. 0 disables natural spawning while preserving item registration. Restart after changing."); GoldenBoosterBoxSpawnWeight = BindNonNegativeInt(config, "Spawning", "GoldenBoosterBoxSpawnWeight", 10, "Relative scrap spawn weight for Golden Booster Boxes on all levels. 0 disables natural spawning while preserving item registration. Restart after changing."); LightBoosterValue = BindNonNegativeInt(config, "Economy", "LightBoosterScrapValue", 30, "Fixed scrap value for Light Booster packs. Negative values are clamped to 0."); HeavyBoosterValue = BindNonNegativeInt(config, "Economy", "HeavyBoosterScrapValue", 50, "Fixed scrap value for Heavy Booster packs. Negative values are clamped to 0."); StandardBoosterBoxValue = BindNonNegativeInt(config, "Economy", "StandardBoosterBoxScrapValue", 75, "Fixed scrap value for Standard Booster Boxes. Negative values are clamped to 0."); GoldenBoosterBoxValue = BindNonNegativeInt(config, "Economy", "GoldenBoosterBoxScrapValue", 150, "Fixed scrap value for Golden Booster Boxes. Negative values are clamped to 0."); config.Save(); LogEffectiveValues(); } internal static float GetGradeMultiplier(int grade) { return (grade >= 1 && grade <= 10) ? GradeMultipliers[grade] : 1f; } internal static float GetVariantValueMultiplier(CardVariant variant) { if (1 == 0) { } float result = variant switch { CardVariant.Foil => VariantValueMultipliers[1], CardVariant.AlternateArt => VariantValueMultipliers[2], CardVariant.Misprint => VariantValueMultipliers[3], _ => VariantValueMultipliers[0], }; if (1 == 0) { } return result; } internal static WeightedRarityTable GetRarityTable(BoosterType type, int slotIndex) { WeightedRarityTable result; if (type == BoosterType.Heavy) { if (1 == 0) { } result = slotIndex switch { 0 => HeavySlot1, 1 => HeavySlot2, _ => HeavySlot3, }; if (1 == 0) { } return result; } if (1 == 0) { } result = slotIndex switch { 0 => LightSlot1, 1 => LightSlot2, _ => LightSlot3, }; if (1 == 0) { } return result; } internal static int GetBoosterValue(BoosterType type) { return (type == BoosterType.Heavy) ? HeavyBoosterValue : LightBoosterValue; } internal static int GetBoosterBoxValue(BoosterBoxType type) { return (type == BoosterBoxType.Golden) ? GoldenBoosterBoxValue : StandardBoosterBoxValue; } private static WeightedRarityTable BindRarity(ConfigFile config, string section, WeightedRarityTable defaults) { WeightedRarityTable raw = new WeightedRarityTable(BindFloat(config, section, "CommonChance", defaults.Common, WeightDescription("Common cards")), BindFloat(config, section, "UncommonChance", defaults.Uncommon, WeightDescription("Uncommon cards")), BindFloat(config, section, "RareChance", defaults.Rare, WeightDescription("Rare cards")), BindFloat(config, section, "UltraRareChance", defaults.UltraRare, WeightDescription("Ultra Rare cards")), BindFloat(config, section, "SecretRareChance", defaults.SecretRare, WeightDescription("Secret Rare cards"))); return NormalizeRarity(section, raw, defaults); } private static WeightedVariantTable BindVariants(ConfigFile config, WeightedVariantTable defaults) { WeightedVariantTable raw = new WeightedVariantTable(BindFloat(config, "Variants", "StandardChance", defaults.Standard, WeightDescription("Standard variant")), BindFloat(config, "Variants", "FoilChance", defaults.Foil, WeightDescription("Foil variant")), BindFloat(config, "Variants", "AlternateArtChance", defaults.AlternateArt, WeightDescription("Alternate Art variant")), BindFloat(config, "Variants", "MisprintChance", defaults.Misprint, WeightDescription("Misprint variant"))); return NormalizeVariants(raw, defaults); } private static WeightedGodPackTable BindGodPack(ConfigFile config, WeightedGodPackTable defaults) { WeightedGodPackTable raw = new WeightedGodPackTable(BindFloat(config, "God Pack", "UltraRareChance", defaults.UltraRare, WeightDescription("Ultra Rare God Pack slots")), BindFloat(config, "God Pack", "SecretRareChance", defaults.SecretRare, WeightDescription("Secret Rare God Pack slots"))); return NormalizeGodPack(raw, defaults); } private static void BindVariantValues(ConfigFile config) { VariantValueMultipliers[0] = BindNonNegativeFiniteFloat(config, "Variant Values", "StandardValueMultiplier", 1f, "Literal value multiplier for Standard cards. This affects monetary value only and does not affect pull odds."); VariantValueMultipliers[1] = BindNonNegativeFiniteFloat(config, "Variant Values", "FoilValueMultiplier", 1.5f, "Literal value multiplier for Foil cards. This affects monetary value only and does not affect pull odds."); VariantValueMultipliers[2] = BindNonNegativeFiniteFloat(config, "Variant Values", "AlternateArtValueMultiplier", 2f, "Literal value multiplier for Alternate Art cards. This affects monetary value only and does not affect pull odds."); VariantValueMultipliers[3] = BindNonNegativeFiniteFloat(config, "Variant Values", "MisprintValueMultiplier", 3f, "Literal value multiplier for Misprint cards. This affects monetary value only and does not affect pull odds."); } private static WeightedBoosterBoxTable BindBoosterBoxMix(ConfigFile config, WeightedBoosterBoxTable defaults) { WeightedBoosterBoxTable raw = new WeightedBoosterBoxTable(BindFloat(config, "Booster Boxes", "StandardBoxLightPackChance", defaults.Light, "Relative weight for Light packs in Standard Booster Boxes. Normalized automatically: 90/10 = 90%/10%, 3/1 = 75%/25%."), BindFloat(config, "Booster Boxes", "StandardBoxHeavyPackChance", defaults.Heavy, "Relative weight for Heavy packs in Standard Booster Boxes. Normalized automatically: 90/10 = 90%/10%, 3/1 = 75%/25%.")); return NormalizeBoosterBox(raw, defaults); } private static WeightedGradeTable BindGrades(ConfigFile config, WeightedGradeTable defaults) { float[] array = new float[10]; for (int i = 0; i < array.Length; i++) { array[i] = BindFloat(config, "Grading", $"Grade{i + 1}Chance", defaults.GetWeight(i + 1), "Non-negative grade roll weight. Grade chance weights are normalized automatically and do not need to sum to 100."); } return NormalizeGrades(new WeightedGradeTable(array), defaults); } private static WeightedRarityTable NormalizeRarity(string name, WeightedRarityTable raw, WeightedRarityTable fallback) { float[] weights = ClampWeights(name, raw.ToArray()); float num = Sum(weights); if (num <= 0f) { Plugin.Log.LogWarning((object)("BALANCE CONFIG FALLBACK | " + name + " weights were all zero or invalid; using production defaults.")); return fallback.Normalized(); } return new WeightedRarityTable(weights).Normalized(); } private static WeightedVariantTable NormalizeVariants(WeightedVariantTable raw, WeightedVariantTable fallback) { float[] weights = ClampWeights("Variants", raw.ToArray()); if (Sum(weights) <= 0f) { Plugin.Log.LogWarning((object)"BALANCE CONFIG FALLBACK | Variant weights were all zero or invalid; using production defaults."); return fallback.Normalized(); } return new WeightedVariantTable(weights).Normalized(); } private static WeightedGodPackTable NormalizeGodPack(WeightedGodPackTable raw, WeightedGodPackTable fallback) { float[] weights = ClampWeights("God Pack", raw.ToArray()); if (Sum(weights) <= 0f) { Plugin.Log.LogWarning((object)"BALANCE CONFIG FALLBACK | God Pack Ultra/Secret weights were all zero or invalid; using production defaults."); return fallback.Normalized(); } return new WeightedGodPackTable(weights).Normalized(); } private static WeightedGradeTable NormalizeGrades(WeightedGradeTable raw, WeightedGradeTable fallback) { float[] weights = ClampWeights("Grading grade chances", raw.ToArray()); if (Sum(weights) <= 0f) { Plugin.Log.LogWarning((object)"BALANCE CONFIG FALLBACK | Grade chance weights were all zero or invalid; using production defaults."); return fallback.Normalized(); } return new WeightedGradeTable(weights).Normalized(); } private static WeightedBoosterBoxTable NormalizeBoosterBox(WeightedBoosterBoxTable raw, WeightedBoosterBoxTable fallback) { float[] weights = ClampWeights("Booster Boxes", raw.ToArray()); if (Sum(weights) <= 0f) { Plugin.Log.LogWarning((object)"BALANCE CONFIG FALLBACK | Standard Booster Box Light/Heavy weights were all zero or invalid; using production defaults."); return fallback.Normalized(); } return new WeightedBoosterBoxTable(weights).Normalized(); } private static float[] ClampWeights(string name, float[] weights) { bool flag = false; for (int i = 0; i < weights.Length; i++) { if (!(weights[i] >= 0f)) { weights[i] = 0f; flag = true; } } if (flag) { Plugin.Log.LogWarning((object)("BALANCE CONFIG CLAMPED | " + name + " had negative weights; negatives were treated as 0.")); } return weights; } private static float BindFloat(ConfigFile config, string section, string key, float defaultValue, string description) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown return config.Bind<float>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())).Value; } private static int BindInt(ConfigFile config, string section, string key, int defaultValue, string description) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown return config.Bind<int>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())).Value; } private static int BindNonNegativeInt(ConfigFile config, string section, string key, int defaultValue, string description) { int value = BindInt(config, section, key, defaultValue, description); return ClampInt(value, 0, int.MaxValue, section + "." + key); } private static float BindNonNegativeFiniteFloat(ConfigFile config, string section, string key, float defaultValue, string description) { float num = BindFloat(config, section, key, defaultValue, description); if (float.IsNaN(num) || float.IsInfinity(num)) { Plugin.Log.LogWarning((object)$"BALANCE CONFIG FALLBACK | {section}.{key}={num} was invalid; using default {defaultValue}."); return defaultValue; } return ClampFloat(num, 0f, float.MaxValue, section + "." + key); } private static int ClampInt(int value, int min, int max, string name) { int num = Math.Max(min, Math.Min(max, value)); if (num != value) { Plugin.Log.LogWarning((object)$"BALANCE CONFIG CLAMPED | {name}={value} was clamped to {num}."); } return num; } private static float ClampFloat(float value, float min, float max, string name) { float num = Math.Max(min, Math.Min(max, value)); if (Math.Abs(num - value) > 0.0001f) { Plugin.Log.LogWarning((object)$"BALANCE CONFIG CLAMPED | {name}={value} was clamped to {num}."); } return num; } private static string WeightDescription(string label) { return "Non-negative weight/chance for " + label + ". Tables are normalized automatically and do not need to sum to 100."; } private static float Sum(float[] weights) { float num = 0f; foreach (float num2 in weights) { num += num2; } return num; } private static void LogEffectiveValues() { LogRarity("Light Slot 1", LightSlot1); LogRarity("Light Slot 2", LightSlot2); LogRarity("Light Slot 3", LightSlot3); LogRarity("Heavy Slot 1", HeavySlot1); LogRarity("Heavy Slot 2", HeavySlot2); LogRarity("Heavy Slot 3", HeavySlot3); Plugin.Log.LogInfo((object)$"VARIANT CONFIG EFFECTIVE | Standard={Variants.Standard:F2}% | Foil={Variants.Foil:F2}% | AlternateArt={Variants.AlternateArt:F2}% | Misprint={Variants.Misprint:F2}%"); Plugin.Log.LogInfo((object)$"VARIANT VALUE CONFIG EFFECTIVE | Standard={VariantValueMultipliers[0]:F2}x | Foil={VariantValueMultipliers[1]:F2}x | AlternateArt={VariantValueMultipliers[2]:F2}x | Misprint={VariantValueMultipliers[3]:F2}x"); Plugin.Log.LogInfo((object)$"GOD PACK CONFIG EFFECTIVE | TriggerChance={HeavyGodPackChancePercent:F2}% | UltraRare={GodPackRarities.UltraRare:F2}% | SecretRare={GodPackRarities.SecretRare:F2}%"); Plugin.Log.LogInfo((object)$"BOOSTER BOX CONFIG EFFECTIVE | StandardBoxLight={StandardBoxPackMix.Light:F2}% | StandardBoxHeavy={StandardBoxPackMix.Heavy:F2}% | GoldenBoxHeavy=100.00%"); Plugin.Log.LogInfo((object)$"BALANCE CONFIG EFFECTIVE | GradingCost={GradingCost} | GradingTurnaroundDays={GradingTurnaroundDays} | LightSpawnWeight={LightBoosterSpawnWeight} | HeavySpawnWeight={HeavyBoosterSpawnWeight} | StandardBoxSpawnWeight={StandardBoosterBoxSpawnWeight} | GoldenBoxSpawnWeight={GoldenBoosterBoxSpawnWeight}"); Plugin.Log.LogInfo((object)$"ECONOMY CONFIG EFFECTIVE | LightBoosterValue={LightBoosterValue} | HeavyBoosterValue={HeavyBoosterValue} | StandardBoxValue={StandardBoosterBoxValue} | GoldenBoxValue={GoldenBoosterBoxValue}"); Plugin.Log.LogInfo((object)$"GRADING CHANCE CONFIG EFFECTIVE | Grade1={GradeChances.GetWeight(1):F2}% | Grade2={GradeChances.GetWeight(2):F2}% | Grade3={GradeChances.GetWeight(3):F2}% | Grade4={GradeChances.GetWeight(4):F2}% | Grade5={GradeChances.GetWeight(5):F2}% | Grade6={GradeChances.GetWeight(6):F2}% | Grade7={GradeChances.GetWeight(7):F2}% | Grade8={GradeChances.GetWeight(8):F2}% | Grade9={GradeChances.GetWeight(9):F2}% | Grade10={GradeChances.GetWeight(10):F2}%"); Plugin.Log.LogInfo((object)$"GRADING MULTIPLIER CONFIG EFFECTIVE | Grade1={GradeMultipliers[1]:F2} | Grade2={GradeMultipliers[2]:F2} | Grade3={GradeMultipliers[3]:F2} | Grade4={GradeMultipliers[4]:F2} | Grade5={GradeMultipliers[5]:F2} | Grade6={GradeMultipliers[6]:F2} | Grade7={GradeMultipliers[7]:F2} | Grade8={GradeMultipliers[8]:F2} | Grade9={GradeMultipliers[9]:F2} | Grade10={GradeMultipliers[10]:F2}"); } private static void LogRarity(string label, WeightedRarityTable table) { Plugin.Log.LogInfo((object)$"RARITY CONFIG EFFECTIVE | {label} | Common={table.Common:F2}% | Uncommon={table.Uncommon:F2}% | Rare={table.Rare:F2}% | UltraRare={table.UltraRare:F2}% | SecretRare={table.SecretRare:F2}%"); } } internal readonly struct WeightedRarityTable { internal readonly float Common; internal readonly float Uncommon; internal readonly float Rare; internal readonly float UltraRare; internal readonly float SecretRare; internal WeightedRarityTable(float common, float uncommon, float rare, float ultraRare, float secretRare) { Common = common; Uncommon = uncommon; Rare = rare; UltraRare = ultraRare; SecretRare = secretRare; } internal WeightedRarityTable(float[] weights) : this(weights[0], weights[1], weights[2], weights[3], weights[4]) { } internal CardRarity Roll(Random random) { float num = (float)(random.NextDouble() * 100.0); if (num < Common) { return CardRarity.Common; } if (num < Common + Uncommon) { return CardRarity.Uncommon; } if (num < Common + Uncommon + Rare) { return CardRarity.Rare; } if (num < Common + Uncommon + Rare + UltraRare) { return CardRarity.UltraRare; } return CardRarity.SecretRare; } internal float[] ToArray() { return new float[5] { Common, Uncommon, Rare, UltraRare, SecretRare }; } internal WeightedRarityTable Normalized() { float num = Common + Uncommon + Rare + UltraRare + SecretRare; return new WeightedRarityTable(Common * 100f / num, Uncommon * 100f / num, Rare * 100f / num, UltraRare * 100f / num, SecretRare * 100f / num); } } internal readonly struct WeightedVariantTable { internal readonly float Standard; internal readonly float Foil; internal readonly float AlternateArt; internal readonly float Misprint; internal WeightedVariantTable(float standard, float foil, float alternateArt, float misprint) { Standard = standard; Foil = foil; AlternateArt = alternateArt; Misprint = misprint; } internal WeightedVariantTable(float[] weights) : this(weights[0], weights[1], weights[2], weights[3]) { } internal CardVariant Roll(Random random) { float num = (float)(random.NextDouble() * 100.0); if (num < Standard) { return CardVariant.Standard; } if (num < Standard + Foil) { return CardVariant.Foil; } if (num < Standard + Foil + AlternateArt) { return CardVariant.AlternateArt; } return CardVariant.Misprint; } internal float[] ToArray() { return new float[4] { Standard, Foil, AlternateArt, Misprint }; } internal WeightedVariantTable Normalized() { float num = Standard + Foil + AlternateArt + Misprint; return new WeightedVariantTable(Standard * 100f / num, Foil * 100f / num, AlternateArt * 100f / num, Misprint * 100f / num); } } internal readonly struct WeightedGodPackTable { internal readonly float UltraRare; internal readonly float SecretRare; internal WeightedGodPackTable(float ultraRare, float secretRare) { UltraRare = ultraRare; SecretRare = secretRare; } internal WeightedGodPackTable(float[] weights) : this(weights[0], weights[1]) { } internal CardRarity Roll(Random random) { float num = (float)(random.NextDouble() * 100.0); return (num < UltraRare) ? CardRarity.UltraRare : CardRarity.SecretRare; } internal float[] ToArray() { return new float[2] { UltraRare, SecretRare }; } internal WeightedGodPackTable Normalized() { float num = UltraRare + SecretRare; return new WeightedGodPackTable(UltraRare * 100f / num, SecretRare * 100f / num); } } internal readonly struct WeightedBoosterBoxTable { internal readonly float Light; internal readonly float Heavy; internal WeightedBoosterBoxTable(float light, float heavy) { Light = light; Heavy = heavy; } internal WeightedBoosterBoxTable(float[] weights) : this(weights[0], weights[1]) { } internal BoosterType Roll(float roll) { return (roll * 100f < Heavy) ? BoosterType.Heavy : BoosterType.Light; } internal float[] ToArray() { return new float[2] { Light, Heavy }; } internal WeightedBoosterBoxTable Normalized() { float num = Light + Heavy; return new WeightedBoosterBoxTable(Light * 100f / num, Heavy * 100f / num); } } internal readonly struct WeightedGradeTable { private readonly float[] weights; internal WeightedGradeTable(params float[] weights) { this.weights = weights; } internal int Roll(Random random) { float num = (float)(random.NextDouble() * 100.0); float num2 = 0f; for (int i = 0; i < weights.Length; i++) { num2 += weights[i]; if (num < num2) { return i + 1; } } return 10; } internal float GetWeight(int grade) { return (grade >= 1 && grade <= weights.Length) ? weights[grade - 1] : 0f; } internal float[] ToArray() { return (float[])weights.Clone(); } internal WeightedGradeTable Normalized() { float num = 0f; float[] array = weights; foreach (float num2 in array) { num += num2; } float[] array2 = new float[weights.Length]; for (int j = 0; j < weights.Length; j++) { array2[j] = weights[j] * 100f / num; } return new WeightedGradeTable(array2); } } [BepInPlugin("Hdaddy.LethalCards", "Lethal Cards", "1.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "Hdaddy.LethalCards"; public const string PluginName = "Lethal Cards"; public const string PluginVersion = "1.0.3"; private static readonly Vector3 CardHeldPositionCorrection = new Vector3(0.1f, 0.08f, -0.08f); private static readonly Vector3 BoosterPackHeldPositionCorrection = new Vector3(0.1f, 0.08f, -0.08f); private static readonly Vector3 BoosterBoxHeldPositionCorrection = new Vector3(0.1f, 0.1f, -0.1f); private static readonly HashSet<Item> HeldPositionAdjustedItems = new HashSet<Item>(); private const float CardFloorVerticalOffset = 0.03f; private const float BoosterPackFloorVerticalOffset = 0.06f; private const float BoosterBoxFloorVerticalOffset = 0.15f; internal static ManualLogSource Log = null; internal static Item? LightBoosterItem; internal static Item? HeavyBoosterItem; internal static Item? BoosterBoxItem; internal static Item? GoldenBoosterBoxItem; private Harmony? harmony; private void Awake() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; string text = Path.Combine(Paths.ConfigPath, "LethalCards.cfg"); string[] files = Directory.GetFiles(Paths.ConfigPath, "*.LethalCards.cfg"); if (!File.Exists(text) && files.Length == 1) { File.Copy(files[0], text); Log.LogInfo((object)"Copied existing Lethal Cards settings to LethalCards.cfg; the legacy file is no longer used."); } ConfigFile val = new ConfigFile(text, true); val.Save(); BalanceConfig.Load(val); Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.IsDefined(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false)) { methodInfo.Invoke(null, null); } } } Log.LogInfo((object)"================================="); Log.LogInfo((object)"LETHAL CARDS LOADED"); Log.LogInfo((object)"Version 1.0.3"); Log.LogInfo((object)"================================="); string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); string text2 = Path.Combine(directoryName, "lethalcards"); Log.LogInfo((object)("Loading asset bundle from: " + text2)); AssetBundle val2 = AssetBundle.LoadFromFile(text2); if ((Object)(object)val2 == (Object)null) { Log.LogError((object)"FAILED TO LOAD lethalcards ASSET BUNDLE"); return; } Log.LogInfo((object)"Asset bundle loaded successfully."); BoosterRevealAssets.Load(val2); GradingPedestalSpawner.LoadAssets(val2); GradedCardSlabPresentation.LoadAssets(val2); foreach (CardDefinition item in CardDatabase.Cards.Take(7)) { if (item.AssetName != null) { RegisterCard(val2, item); } } RegisterBooster(val2, "LightBoosterPackItem", BoosterType.Light, BalanceConfig.LightBoosterSpawnWeight); RegisterBooster(val2, "HeavyBoosterPackItem", BoosterType.Heavy, BalanceConfig.HeavyBoosterSpawnWeight); BoosterBoxItem = RegisterBoosterBox(val2, "BoosterBoxItem", BoosterBoxType.Standard, BalanceConfig.StandardBoosterBoxSpawnWeight); GoldenBoosterBoxItem = RegisterBoosterBox(val2, "GoldenBoosterBoxItem", BoosterBoxType.Golden, BalanceConfig.GoldenBoosterBoxSpawnWeight); foreach (CardDefinition item2 in CardDatabase.Cards.Skip(7)) { if (item2.AssetName != null) { RegisterCard(val2, item2); } } Log.LogInfo((object)($"CARD REGISTRY | Definitions={CardDatabase.Cards.Count} | " + $"Implemented={CardDatabase.GetImplementedCards().Count()} | " + string.Join(" | ", ((CardRarity[])Enum.GetValues(typeof(CardRarity))).Select((CardRarity rarity) => $"{rarity}={CardDatabase.GetImplementedCards().Count((CardDefinition card) => card.Rarity == rarity)}")))); harmony = new Harmony("Hdaddy.LethalCards"); harmony.PatchAll(); Log.LogInfo((object)"Harmony debug patches applied."); } private void PrepareCardPrefab(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { Log.LogError((object)"CARD PREFAB PREP FAILED | Prefab was null."); return; } NetworkObject component = prefab.GetComponent<NetworkObject>(); if ((Object)(object)component == (Object)null) { Log.LogError((object)("CARD PREFAB PREP FAILED | Prefab=" + ((Object)prefab).name + " | Reason=NetworkObject missing")); return; } CardInstanceData component2 = prefab.GetComponent<CardInstanceData>(); if ((Object)(object)prefab.GetComponent<GradingReturnData>() == (Object)null) { prefab.AddComponent<GradingReturnData>(); } if ((Object)(object)prefab.GetComponent<NetworkItemConsumption>() == (Object)null) { prefab.AddComponent<NetworkItemConsumption>(); } if ((Object)(object)prefab.GetComponent<CardVariantVisuals>() == (Object)null) { prefab.AddComponent<CardVariantVisuals>(); } if ((Object)(object)component2 == (Object)null) { component2 = prefab.AddComponent<CardInstanceData>(); } } private void RegisterCard(AssetBundle bundle, CardDefinition card) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) Item val = bundle.LoadAsset<Item>(card.AssetName); if ((Object)(object)val == (Object)null || (Object)(object)val.spawnPrefab == (Object)null || (Object)(object)val.spawnPrefab.GetComponent<NetworkObject>() == (Object)null || (Object)(object)val.spawnPrefab.GetComponent<PhysicsProp>() == (Object)null) { Log.LogError((object)("CARD DISABLED | Id=" + card.CardId + " | Asset=" + card.AssetName + " | Missing item, prefab, NetworkObject, or PhysicsProp.")); } else { PrepareCardPrefab(val.spawnPrefab); val.verticalOffset = 0.03f; ApplyHeldPositionCorrection(val, CardHeldPositionCorrection, "Card"); val.saveItemVariable = true; val.canBeInspected = true; NetworkPrefabs.RegisterNetworkPrefab(val.spawnPrefab); Items.RegisterItem(val); card.AttachImplementedItem(val); } } internal static bool EnsureActionTooltip(Item? item, string action) { action = BoosterActionTooltips.Format(action); if ((Object)(object)item == (Object)null) { Log.LogWarning((object)("ACTION TOOLTIP NOT CONFIGURED | Action=\"" + action + "\" | Item reference is null.")); return false; } if (item.toolTips != null && item.toolTips.Length != 0 && item.toolTips[0] == action) { return false; } string[] array = ((item.toolTips == null || item.toolTips.Length == 0) ? new string[1] : ((string[])item.toolTips.Clone())); array[0] = action; item.toolTips = array; return true; } private Item? RegisterBoosterBox(AssetBundle bundle, string assetName, BoosterBoxType type, int spawnWeight) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) Item val = bundle.LoadAsset<Item>(assetName); if ((Object)(object)val == (Object)null || (Object)(object)val.spawnPrefab == (Object)null || (Object)(object)val.spawnPrefab.GetComponent<NetworkObject>() == (Object)null) { Log.LogError((object)("BOOSTER BOX REGISTRATION FAILED | Asset=" + assetName + " | Missing Item, spawn prefab, or NetworkObject.")); return null; } SetFixedScrapValue(val, BalanceConfig.GetBoosterBoxValue(type)); val.verticalOffset = 0.15f; string type2 = ((type == BoosterBoxType.Golden) ? "GoldenBox" : "StandardBox"); ApplyHeldPositionCorrection(val, BoosterBoxHeldPositionCorrection, type2); PhysicsProp component = val.spawnPrefab.GetComponent<PhysicsProp>(); if ((Object)(object)component == (Object)null) { Log.LogError((object)("BOOSTER BOX REGISTRATION FAILED | Asset=" + assetName + " | Missing PhysicsProp.")); return null; } BoosterBoxBehaviour boosterBoxBehaviour = val.spawnPrefab.AddComponent<BoosterBoxBehaviour>(); ((GrabbableObject)boosterBoxBehaviour).itemProperties = ((GrabbableObject)component).itemProperties; if ((Object)(object)((GrabbableObject)boosterBoxBehaviour).itemProperties != (Object)(object)val) { ManualLogSource log = Log; object arg = type; string name = ((Object)val).name; Item itemProperties = ((GrabbableObject)component).itemProperties; log.LogWarning((object)$"BOOSTER BOX ITEM REFERENCE MISMATCH | Type={arg} | Loaded={name} | Original={((itemProperties != null) ? ((Object)itemProperties).name : null)}"); } ((GrabbableObject)boosterBoxBehaviour).grabbable = ((GrabbableObject)component).grabbable; ((GrabbableObject)boosterBoxBehaviour).isInFactory = ((GrabbableObject)component).isInFactory; ((GrabbableObject)boosterBoxBehaviour).mainObjectRenderer = ((GrabbableObject)component).mainObjectRenderer; boosterBoxBehaviour.BoxType = type; if ((Object)(object)((GrabbableObject)boosterBoxBehaviour).itemProperties != (Object)null && (Object)(object)((GrabbableObject)boosterBoxBehaviour).itemProperties != (Object)(object)val) { ((GrabbableObject)boosterBoxBehaviour).itemProperties.verticalOffset = 0.15f; ApplyHeldPositionCorrection(((GrabbableObject)boosterBoxBehaviour).itemProperties, BoosterBoxHeldPositionCorrection, type2); } bool flag = EnsureActionTooltip(val, "Open Box"); if ((Object)(object)((GrabbableObject)boosterBoxBehaviour).itemProperties != (Object)(object)val) { flag |= EnsureActionTooltip(((GrabbableObject)boosterBoxBehaviour).itemProperties, "Open Box"); } val.saveItemVariable = true; Object.DestroyImmediate((Object)(object)component); if ((Object)(object)val.spawnPrefab.GetComponent<NetworkItemConsumption>() == (Object)null) { val.spawnPrefab.AddComponent<NetworkItemConsumption>(); } NetworkPrefabs.RegisterNetworkPrefab(val.spawnPrefab); if (spawnWeight > 0) { Items.RegisterScrap(val, spawnWeight, (LevelTypes)(-1)); } else { Items.RegisterItem(val); } Log.LogInfo((object)$"BOOSTER BOX REGISTERED | Type={type} | SpawnWeight={spawnWeight}"); return val; } private void RegisterBooster(AssetBundle bundle, string assetName, BoosterType packType, int spawnWeight) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) Item val = bundle.LoadAsset<Item>(assetName); if ((Object)(object)val == (Object)null) { Log.LogError((object)("Failed to load booster item: " + assetName)); return; } if ((Object)(object)val.spawnPrefab == (Object)null) { Log.LogError((object)(assetName + " has no spawn prefab.")); return; } SetFixedScrapValue(val, BalanceConfig.GetBoosterValue(packType)); val.verticalOffset = 0.06f; string type = ((packType == BoosterType.Heavy) ? "HeavyPack" : "LightPack"); ApplyHeldPositionCorrection(val, BoosterPackHeldPositionCorrection, type); PhysicsProp component = val.spawnPrefab.GetComponent<PhysicsProp>(); if ((Object)(object)component == (Object)null) { Log.LogError((object)(assetName + " has no PhysicsProp.")); return; } BoosterPackBehaviour boosterPackBehaviour = val.spawnPrefab.AddComponent<BoosterPackBehaviour>(); ((GrabbableObject)boosterPackBehaviour).itemProperties = ((GrabbableObject)component).itemProperties; ((GrabbableObject)boosterPackBehaviour).grabbable = ((GrabbableObject)component).grabbable; ((GrabbableObject)boosterPackBehaviour).isInFactory = ((GrabbableObject)component).isInFactory; ((GrabbableObject)boosterPackBehaviour).mainObjectRenderer = ((GrabbableObject)component).mainObjectRenderer; boosterPackBehaviour.PackType = packType; if ((Object)(object)((GrabbableObject)boosterPackBehaviour).itemProperties != (Object)null && (Object)(object)((GrabbableObject)boosterPackBehaviour).itemProperties != (Object)(object)val) { ((GrabbableObject)boosterPackBehaviour).itemProperties.verticalOffset = 0.06f; ApplyHeldPositionCorrection(((GrabbableObject)boosterPackBehaviour).itemProperties, BoosterPackHeldPositionCorrection, type); } bool flag = EnsureActionTooltip(val, "Rip Pack"); if ((Object)(object)((GrabbableObject)boosterPackBehaviour).itemProperties != (Object)(object)val) { flag |= EnsureActionTooltip(((GrabbableObject)boosterPackBehaviour).itemProperties, "Rip Pack"); } Object.DestroyImmediate((Object)(object)component); if ((Object)(object)val.spawnPrefab.GetComponent<NetworkItemConsumption>() == (Object)null) { val.spawnPrefab.AddComponent<NetworkItemConsumption>(); } Log.LogInfo((object)("Replaced PhysicsProp with " + $"BoosterPackBehaviour for {packType} pack.")); NetworkPrefabs.RegisterNetworkPrefab(val.spawnPrefab); if (spawnWeight > 0) { Items.RegisterScrap(val, spawnWeight, (LevelTypes)(-1)); } else { Items.RegisterItem(val); } switch (packType) { case BoosterType.Light: LightBoosterItem = val; break; case BoosterType.Heavy: HeavyBoosterItem = val; break; } Log.LogInfo((object)($"Registered {packType} booster | " + $"Configured Spawn Weight: {spawnWeight}")); } private static void SetFixedScrapValue(Item item, int value) { item.maxValue = (item.minValue = Math.Max(0, value)); } private static void ApplyHeldPositionCorrection(Item item, Vector3 correction, string type) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (HeldPositionAdjustedItems.Add(item)) { Vector3 positionOffset = item.positionOffset; item.positionOffset += correction; } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "LethalCards"; public const string PLUGIN_NAME = "LethalCards"; public const string PLUGIN_VERSION = "1.0.3"; } } namespace LethalCards.TerminalCommands { [HarmonyPatch(typeof(Terminal))] public static class CollectionTerminalPatch { private sealed class CollectionPageState { public int PageIndex; public bool Browsing; } private const string CollectionCommand = "collection"; private const string CardsCommand = "cards"; private const string HelpSubcommand = "help"; private const int CollectionPageSize = 3; private static ConditionalWeakTable<Terminal, CollectionPageState> CollectionPages = new ConditionalWeakTable<Terminal, CollectionPageState>(); internal static void ResetContext() { CollectionPages = new ConditionalWeakTable<Terminal, CollectionPageState>(); } private static void SetCollectionContext(Terminal terminal, bool browsing) { GradingNetworkSync.CancelStatusRequest(); CollectionPageState value = CollectionPages.GetValue(terminal, (Terminal _) => new CollectionPageState()); if (value.Browsing != browsing) { value.Browsing = browsing; } } [HarmonyPatch("QuitTerminal")] [HarmonyPrefix] private static void QuitPrefix(Terminal __instance) { SetCollectionContext(__instance, browsing: false); } [HarmonyPatch("BeginUsingTerminal")] [HarmonyPrefix] private static void BeginPrefix(Terminal __instance) { SetCollectionContext(__instance, browsing: false); } [HarmonyPatch("OnDisable")] [HarmonyPrefix] private static void DisablePrefix(Terminal __instance) { SetCollectionContext(__instance, browsing: false); } [HarmonyPatch("ParsePlayerSentence")] [HarmonyPrefix] [HarmonyPriority(800)] private static bool ParsePlayerSentencePrefix(Terminal __instance, ref TerminalNode __result) { if ((Object)(object)__instance == (Object)null) { return true; } GradingNetworkSync.CancelStatusRequest(); string text = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded).Trim().ToLowerInvariant(); CollectionPageState value = CollectionPages.GetValue(__instance, (Terminal _) => new CollectionPageState()); if (value.Browsing && (text == "next" || text == "prev" || text == "previous")) { text = "collection " + ((text == "next") ? "next" : "previous"); } if (text == "grading" || text == "grades") { NetworkManager singleton = NetworkManager.Singleton; Plugin.Log.LogInfo((object)($"GRADING COMMAND | Command={text} | IsHost={singleton != null && singleton.IsHost} | " + $"IsServer={singleton != null && singleton.IsServer} | IsClient={singleton != null && singleton.IsClient} | " + "LocalClientId=" + (((Object)(object)singleton != (Object)null) ? singleton.LocalClientId.ToString() : "<none>") + " | " + $"RuntimeJobCount={GradingManager.Jobs.Count}")); SetCollectionContext(__instance, browsing: false); TerminalNode val = ScriptableObject.CreateInstance<TerminalNode>(); val.clearPreviousText = true; if ((Object)(object)singleton != (Object)null && !singleton.IsServer) { val.displayText = "\nLETHAL CARDS GRADING STATUS\n\nRetrieving grading status...\n\n"; if (!GradingNetworkSync.RequestStatus(delegate(int jobCount, string display) { if ((Object)(object)__instance == (Object)null) { Plugin.Log.LogWarning((object)"GRADING RESPONSE BLOCKED | Reason=TerminalDestroyedBeforeDisplay"); } else if (!__instance.terminalInUse) { Plugin.Log.LogWarning((object)"GRADING RESPONSE BLOCKED | Reason=TerminalNoLongerInUse"); } else { TerminalNode val3 = ScriptableObject.CreateInstance<TerminalNode>(); val3.clearPreviousText = true; val3.displayText = display; Plugin.Log.LogInfo((object)$"GRADING CLIENT DISPLAY | JobCount={jobCount} | OutputLength={display?.Length ?? 0}"); __instance.LoadNewNode(val3); } })) { val.displayText = "\nLETHAL CARDS GRADING STATUS\n\nUnable to contact the server. Try grades again.\n\n"; } } else { val.displayText = BuildGradingText(text); } __result = val; return false; } bool flag = text == "cards" || (text.StartsWith("cards", StringComparison.Ordinal) && text.Length > "cards".Length && char.IsWhiteSpace(text["cards".Length])); bool flag2 = flag && text.Substring("cards".Length).Trim() == "help"; if (!flag && text != "collection" && (!text.StartsWith("collection", StringComparison.Ordinal) || text.Length <= "collection".Length || !char.IsWhiteSpace(text["collection".Length]))) { SetCollectionContext(__instance, browsing: false); return true; } SetCollectionContext(__instance, !flag); string query = (flag ? "" : text.Substring("collection".Length).Trim()); Plugin.Log.LogInfo((object)("TERMINAL: LETHAL CARDS command received | Command=" + (flag ? "cards" : "collection"))); TerminalNode val2 = ScriptableObject.CreateInstance<TerminalNode>(); val2.clearPreviousText = true; val2.displayText = ((!flag) ? BuildCollectionResponse(__instance, query) : (flag2 ? BuildHelpText() : "\nUnknown Lethal Cards command.\nType \"cards help\" for available commands.\n\n")); __result = val2; return false; } private static string BuildHelpText() { return "\n=== LETHAL CARDS COMMANDS ===\n\ncollection\nView your discovered cards and variants.\n\ncollection next / previous\nMove between collection pages.\n\ncollection page <number>\nView a specific collection page.\n\ncollection <card name>\nView detailed collection information for one card.\n\nnext / prev / previous\nNavigate while browsing collection.\n\ngrading / grades\nView grading status and ready results.\n\ncards help\nDisplay this help screen.\n\n"; } private static string NormalizeCardName(string value) { return CardDatabase.NormalizeName(value); } private static string BuildCardDetailText(string query) { string text = NormalizeCardName(query); CardDefinition cardDefinition = null; foreach (CardDefinition card in CardDatabase.Cards) { if (text.Length != 0 && !(NormalizeCardName(card.DisplayName) != text)) { if (cardDefinition != null) { return "\nMore than one card matches that name.\nUse \"collection\" to view all cards.\n\n"; } cardDefinition = card; } } if (cardDefinition == null) { return "\nCard not found.\n\nUse \"collection\" to view all cards.\nExample: collection ghost girl\n\n"; } string text2 = cardDefinition.SetNumber.ToString("D3"); bool flag = CollectionManager.HasCard(cardDefinition.CardId); CardVariant[] array = (CardVariant[])Enum.GetValues(typeof(CardVariant)); int num = 0; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(); stringBuilder.AppendLine("=== " + cardDefinition.DisplayName.ToUpperInvariant() + " ==="); stringBuilder.AppendLine(); stringBuilder.AppendLine("Set: " + cardDefinition.SetId); stringBuilder.AppendLine("Set #: " + text2); if (!cardDefinition.IsImplemented) { stringBuilder.AppendLine("Not yet available in packs."); } stringBuilder.AppendLine("Discovered: " + (flag ? "Yes" : "No")); stringBuilder.AppendLine(); stringBuilder.AppendLine("Variants:"); CardVariant[] array2 = array; for (int i = 0; i < array2.Length; i++) { CardVariant variant = array2[i]; bool flag2 = CollectionManager.HasVariant(cardDefinition.CardId, variant); if (flag2) { num++; } string text3 = Regex.Replace(variant.ToString(), "([a-z])([A-Z])", "$1 $2"); stringBuilder.AppendLine("[" + (flag2 ? "X" : " ") + "] " + text3); } stringBuilder.AppendLine(); stringBuilder.AppendLine($"Variants Found: {num} / {array.Length}"); stringBuilder.AppendLine(); return stringBuilder.ToString(); } private static string BuildCollectionResponse(Terminal terminal, string query) { CollectionPageState value = CollectionPages.GetValue(terminal, (Terminal _) => new CollectionPageState()); if (query.Length == 0) { value.PageIndex = 0; } else if (query == "next") { value.PageIndex++; } else if (query == "previous" || query == "prev") { value.PageIndex--; } else { if (!(query == "page") && (!query.StartsWith("page", StringComparison.Ordinal) || query.Length <= 4 || !char.IsWhiteSpace(query[4]))) { return BuildCardDetailText(query); } if (!int.TryParse(query.Substring(4).Trim(), out var result) || result < 1) { return "\nUse \"collection page <number>\" with a positive page number.\n\n"; } value.PageIndex = result - 1; } int num = Math.Max(1, (CardDatabase.Cards.Count + 3 - 1) / 3); value.PageIndex = Math.Max(0, Math.Min(value.PageIndex, num - 1)); return BuildCollectionText(value.PageIndex); } private static string BuildCollectionText(int pageIndex) { StringBuilder stringBuilder = new StringBuilder(); CardVariant[] array = (CardVariant[])Enum.GetValues(typeof(CardVariant)); int num = 0; int num2 = 0; CardDefinition[] array2 = CardDatabase.Cards.OrderBy<CardDefinition, string>((CardDefinition cardDefinition2) => cardDefinition2.SetId, StringComparer.Ordinal).ThenBy((CardDefinition cardDefinition2) => cardDefinition2.SetNumber).ToArray(); int num3 = Math.Max(1, (array2.Length + 3 - 1) / 3); pageIndex = Math.Max(0, Math.Min(pageIndex, num3 - 1)); int num4 = pageIndex * 3; int num5 = Math.Min(num4 + 3, array2.Length); CardDefinition[] array3 = array2; foreach (CardDefinition card in array3) { if (CollectionManager.HasCard(card.CardId)) { num++; } num2 += array.Count((CardVariant variant2) => CollectionManager.HasVariant(card.CardId, variant2)); } stringBuilder.AppendLine(); stringBuilder.AppendLine("=== LETHAL CARDS COLLECTION ==="); stringBuilder.AppendLine($"Page {pageIndex + 1} / {num3}"); stringBuilder.AppendLine(); for (int num7 = num4; num7 < num5; num7++) { CardDefinition cardDefinition = array2[num7]; stringBuilder.AppendLine($"{cardDefinition.SetId}-{cardDefinition.SetNumber:D3} - {cardDefinition.DisplayName}"); if (!cardDefinition.IsImplemented) { stringBuilder.AppendLine(" Not yet available in packs."); } CardVariant[] array4 = array; for (int num8 = 0; num8 < array4.Length; num8++) { CardVariant variant = array4[num8]; bool flag = CollectionManager.HasVariant(cardDefinition.CardId, variant); string text = Regex.Replace(variant.ToString(), "([a-z])([A-Z])", "$1 $2"); stringBuilder.AppendLine(" [" + (flag ? "X" : " ") + "] " + text); } stringBuilder.AppendLine(); } stringBuilder.AppendLine($"Cards Discovered: {num} / {CardDatabase.Cards.Count}"); stringBuilder.AppendLine($"Variants Discovered: {num2} / {CardDatabase.Cards.Count * array.Length}"); if (pageIndex > 0) { stringBuilder.AppendLine("Previous: collection previous"); } if (pageIndex + 1 < num3) { stringBuilder.AppendLine("Next: collection next"); } stringBuilder.AppendLine(); stringBuilder.AppendLine("Type \"collection <card name>\" for details."); stringBuilder.AppendLine("While browsing: next / prev / previous."); stringBuilder.AppendLine("Type \"cards help\" for Lethal Cards commands."); stringBuilder.AppendLine(); return stringBuilder.ToString(); } internal static string BuildGradingText(string command) { StringBuilder stringBuilder = new StringBuilder("\nLETHAL CARDS GRADING STATUS\n\n"); int currentDay = GradingDayManager.CurrentDay; if (GradingManager.Jobs.Count == 0) { stringBuilder.AppendLine("No cards are currently in grading."); } foreach (GradingJob job in GradingManager.Jobs) { long num = (long)currentDay - (long)job.SubmittedDay; string text = ((num <= 0) ? "Processing Order..." : (num switch { 2L => "Shipping Order...", 1L => "Assessing Grade...", _ => "Ready for pickup!", })); bool flag = num >= 3; string displayName = CardNameFormatter.GetDisplayName(CardDatabase.GetById(job.CardId)?.DisplayName ?? job.CardId, job.Variant); stringBuilder.AppendLine(displayName); stringBuilder.AppendLine("Status: " + text); if (flag) { stringBuilder.AppendLine($"Grade: {job.Grade}"); stringBuilder.AppendLine(job.FinalValue.HasValue ? $"Value: ${job.FinalValue.Value}" : "Value: unavailable"); } stringBuilder.AppendLine(); Plugin.Log.LogDebug((object)($"GRADING STATUS | CardId={job.CardId} | Variant={job.Variant} | DisplayName=\"{displayName}\" | SubmittedDay={job.SubmittedDay} | " + $"CurrentDay={currentDay} | DaysElapsed={num} | Status=\"{text}\" | GradeVisible={flag}" + $" | ValueVisible={flag}" + (flag ? $" | Grade={job.Grade} | FinalValue={job.FinalValue}" : ""))); } return stringBuilder.ToString(); } } } namespace LethalCards.Save { public static class SaveIdentityManager { private const string IdentityKey = "LethalCards_SaveIdentity"; private static string currentSaveIdentity = ""; private static string currentSaveName = ""; public static string CurrentSaveIdentity => currentSaveIdentity; public static string GetOrCreateIdentity() { if ((Object)(object)GameNetworkManager.Instance == (Object)null || string.IsNullOrWhiteSpace(GameNetworkManager.Instance.currentSaveFileName)) { Plugin.Log.LogWarning((object)"SAVE IDENTITY | No active save file."); return ""; } string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName; if (!string.IsNullOrWhiteSpace(currentSaveIdentity) && currentSaveName == currentSaveFileName) { return currentSaveIdentity; } try { if (ES3.KeyExists("LethalCards_SaveIdentity", currentSaveFileName)) { currentSaveIdentity = ES3.Load<string>("LethalCards_SaveIdentity", currentSaveFileName); currentSaveName = currentSaveFileName; return currentSaveIdentity; } currentSaveIdentity = Guid.NewGuid().ToString("N"); currentSaveName = currentSaveFileName; ES3.Save<string>("LethalCards_SaveIdentity", currentSaveIdentity, currentSaveFileName); GradingManager.Clear(); GradingDayManager.SetDay(0); CollectionManager.Clear(); CollectionSaveManager.ResetLoadedSave(); return currentSaveIdentity; } catch (Exception arg) { Plugin.Log.LogError((object)("SAVE IDENTITY ERROR | Save=" + currentSaveFileName + " | " + $"Exception={arg}")); return ""; } } public static void ResetRuntimeState() { currentSaveIdentity = ""; currentSaveName = ""; } } } namespace LethalCards.Networking { public class NetworkItemConsumption : NetworkBehaviour { private bool consumed; public static bool IsValidHolder(PlayerControllerB player, GrabbableObject item) { return (Object)(object)player != (Object)null && player.isPlayerControlled && !player.isPlayerDead && (Object)(object)item != (Object)null && ((NetworkBehaviour)item).IsSpawned && item.heldByPlayerOnServer && ((NetworkBehaviour)item).OwnerClientId == player.actualClientId && (Object)(object)player.currentlyHeldObjectServer == (Object)(object)item; } public void ConsumeServer() { if (((NetworkBehaviour)this).IsServer && ((NetworkBehaviour)this).IsSpawned && !consumed) { consumed = true; ClearInventoryClientRpc(); ClearInventory(); ((NetworkBehaviour)this).NetworkObject.Despawn(true); } } [ClientRpc] private void ClearInventoryClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3135002904u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 3135002904u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; ClearInventory(); } } } private void ClearInventory() { GrabbableObject component = ((Component)this).GetComponent<GrabbableObject>(); if ((Object)(object)component == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val == (Object)null) { continue; } bool flag = (Object)(object)val.currentlyHeldObjectServer == (Object)(object)component; bool flag2 = flag; for (int j = 0; j < val.ItemSlots.Length; j++) { if (!((Object)(object)val.ItemSlots[j] != (Object)(object)component)) { flag2 = true; val.ItemSlots[j] = null; if (((NetworkBehaviour)val).IsOwner && (Object)(object)HUDManager.Instance != (Object)null && j < HUDManager.Instance.itemSlotIcons.Length) { ((Behaviour)HUDManager.Instance.itemSlotIcons[j]).enabled = false; } } } if ((Object)(object)val.ItemOnlySlot == (Object)(object)component) { flag2 = true; val.ItemOnlySlot = null; if (((NetworkBehaviour)val).IsOwner && (Object)(object)HUDManager.Instance != (Object)null) { ((Behaviour)HUDManager.Instance.itemOnlySlotIcon).enabled = false; } } if (!flag2) { continue; } val.carryWeight = Mathf.Clamp(val.carryWeight - Mathf.Clamp(component.itemProperties.weight - 1f, 0f, 10f), 1f, 10f); if (flag) { val.currentlyHeldObjectServer = null; val.isHoldingObject = false; val.twoHanded = false; val.twoHandedAnimation = false; val.activatingItem = false; val.playerBodyAnimator.SetBool("cancelHolding", true); val.playerBodyAnimator.ResetTrigger("Throw"); if (((NetworkBehaviour)val).IsOwner && (Object)(object)HUDManager.Instance != (Object)null) { ((Behaviour)HUDManager.Instance.holdingTwoHandedItem).enabled = false; HUDManager.Instance.ClearControlTips(); } } if (((NetworkBehaviour)val).IsOwner) { StartOfRound.Instance.SendChangedWeightEvent(); } } component.isHeld = false; component.heldByPlayerOnServer = false; component.playerHeldBy = null; component.parentObject = null; } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(3135002904u, new RpcReceiveHandler(__rpc_handler_3135002904), "ClearInventoryClientRpc"); ((NetworkBehaviour)this).__initializeRpcs(); } private static void __rpc_handler_3135002904(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { target.__rpc_exec_stage = (__RpcExecStage)1; ((NetworkItemConsumption)(object)target).ClearInventoryClientRpc(); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string __getTypeName() { return "NetworkItemConsumption"; } } [HarmonyPatch(typeof(StartOfRound))] public static class SessionLifecyclePatch { private const float ReturnRestoreSafetyDelay = 0.25f; private const float ReturnPedestalSlowLoadWarning = 5f; private static bool companyActive; private static float nextUpdate; private static float companySceneReadyTime; private static float returnRestoreTime = -1f; private static bool returnReadinessWarningLogged; [HarmonyPatch("Start")] [HarmonyPrefix] private static void StartPrefix() { ResetSession(); } [HarmonyPatch("OnDestroy")] [HarmonyPrefix] private static void DestroyPrefix() { ResetSession(); } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePostfix(StartOfRound __instance) { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.ShutdownInProgress || Time.realtimeSinceStartup < nextUpdate) { return; } nextUpdate = Time.realtimeSinceStartup + 0.25f; CollectionNetworkSync.Initialize(); GradingNetworkSync.Initialize(); if (singleton.IsServer) { CollectionSaveManager.LoadForCurrentSave(); GradingSaveManager.LoadForCurrentSave(); } else { CollectionNetworkSync.EnsureSnapshot(); } if (!__instance.shipIsLeaving && (Object)(object)__instance.currentLevel != (Object)null && __instance.currentLevel.PlanetName.Contains("Gordion", StringComparison.OrdinalIgnoreCase) && (Object)(object)Object.FindObjectOfType<DepositItemsDesk>() != (Object)null) { if (!companyActive) { companyActive = true; companySceneReadyTime = Time.realtimeSinceStartup; returnRestoreTime = -1f; returnReadinessWarningLogged = false; } GradingPedestalSpawner.TrySpawn(); if (singleton.IsServer && GradingPedestalSpawner.IsReturnPedestalReady) { if (returnRestoreTime < 0f) { returnRestoreTime = Time.realtimeSinceStartup + 0.25f; Plugin.Log.LogInfo((object)"GRADING PEDESTALS READY"); } else if (Time.realtimeSinceStartup >= returnRestoreTime) { GradingReturnSpawner.TrySpawnReadyCards(); } } else if (singleton.IsServer) { returnRestoreTime = -1f; if (!returnReadinessWarningLogged && Time.realtimeSinceStartup - companySceneReadyTime >= 5f) { returnReadinessWarningLogged = true; Plugin.Log.LogWarning((object)"GRADING RETURN WAITING | Return pedestal still initializing"); } } } else if (companyActive) { GradingReturnSpawner.Reset(); GradingPedestalSpawner.Reset(); companyActive = false; companySceneReadyTime = 0f; returnRestoreTime = -1f; returnReadinessWarningLogged = false; } } private static void ResetSession() { CollectionTerminalPatch.ResetContext(); GradingReturnSpawner.Reset(); GradingPedestalSpawner.Reset(); CollectionNetworkSync.Shutdown(); GradingNetworkSync.Shutdown(); SaveIdentityManager.ResetRuntimeState(); CollectionSaveManager.ResetLoadedSave(); GradingSaveManager.ResetLoadedSave(); CollectionManager.Clear(); GradingManager.Clear(); GradingDayManager.SetDay(0); DebugSpawnPatch.Reset(); companyActive = false; nextUpdate = 0f; companySceneReadyTime = 0f; returnRestoreTime = -1f; returnReadinessWarningLogged = false; } } } namespace LethalCards.Grading { public static class GradingDayManager { private static int currentDay; public static int CurrentDay => currentDay; public static void AdvanceDay() { currentDay++; Plugin.Log.LogInfo((object)("GRADING DAY ADVANCED | " + $"CurrentDay={currentDay}")); } public static void SetDay(int day) { currentDay = Math.Max(0, day); Plugin.Log.LogInfo((object)("GRADING DAY SET | " + $"CurrentDay={currentDay}")); } } [HarmonyPatch(typeof(TimeOfDay), "OnDayChanged")] public static class GradingDayPatch { [HarmonyPostfix] private static void Postfix() { if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsServer) { GradingDayManager.AdvanceDay(); GradingSaveManager.Save(); Plugin.Log.LogInfo((object)("GRADING DAY CHANGE DETECTED | " + $"CurrentDay={GradingDayManager.CurrentDay}")); } } } public class GradingJob { public string JobId { get; set; } = ""; public string CardId { get; set; } = ""; public CardVariant Variant { get; set; } public int Grade { get; set; } public int SubmittedDay { get; set; } public int ReadyDay { get; set; } public int? FinalValue { get; set; } public void EnsureFinalValue() { if (!FinalValue.HasValue) { CardDefinition byId = CardDatabase.GetById(CardId); if (byId != null) { FinalValue = CardGrading.CalculateGradedValue(new CardPull(byId, Variant, 0).UngradedValue, Grade); } } } } public static class GradingManager { public static readonly bool InstantGradingForTesting = false; private static readonly List<GradingJob> PendingJobs = new List<GradingJob>(); public static int GradingTurnaroundDays => BalanceConfig.GradingTurnaroundDays; public static int GradingCostPerCard => BalanceConfig.GradingCost; public static IReadOnlyList<GradingJob> Jobs => PendingJobs; public static GradingJob CreateJob(CardInstanceData card, int currentDay) { int grade = CardGrading.RollGrade(); GradingJob gradingJob = new GradingJob { JobId = Guid.NewGuid().ToString("N"), CardId = card.CardId, Variant = card.Variant, Grade = grade, SubmittedDay = currentDay, ReadyDay = (InstantGradingForTesting ? currentDay : (currentDay + GradingTurnaroundDays)) }; gradingJob.EnsureFinalValue(); PendingJobs.Add(gradingJob); Plugin.Log.LogInfo((object)("GRADING JOB CREATED | CardId=" + gradingJob.CardId + " | " + $"Variant={gradingJob.Variant} | " + "ResultStored=True | " + $"SubmittedDay={gradingJob.SubmittedDay} | " + $"ReadyDay={gradingJob.ReadyDay}")); GradingSaveManager.Save(); return gradingJob; } public static GradingJob? GetJobById(string jobId) { if (string.IsNullOrEmpty(jobId)) { return null; } foreach (GradingJob pendingJob in PendingJobs) { if (pendingJob.JobId == jobId) { return pendingJob; } } return null; } public static bool ClaimJob(string jobId) { GradingJob jobById = GetJobById(jobId); if (jobById == null) { Plugin.Log.LogWarning((object)("GRADING CLAIM FAILED | JobId=" + jobId + " | Reason=Job not found")); return false; } PendingJobs.Remove(jobById); Plugin.Log.LogInfo((object)("GRADING JOB COLLECTED | RemovedFromActiveStatus=True | JobId=" + jobById.JobId + " | CardId=" + jobById.CardId + " | " + $"Grade={jobById.Grade}")); GradingSaveManager.Save(); return true; } public static IEnumerable<GradingJob> GetReadyJobs(int currentDay) { foreach (GradingJob job in PendingJobs) { if (currentDay >= job.ReadyDay) { yield return job; } } } public static void AddLoadedJob(GradingJob job) { if (job != null) { PendingJobs.Add(job); } } public static void RemoveJob(GradingJob job) { if (PendingJobs.Remove(job)) { GradingSaveManager.Save(); } } public static void Clear() { PendingJobs.Clear(); } } [HarmonyPatch(typeof(StartOfRound), "Start")] public static class GradingNetworkPatch { [HarmonyPostfix] private static void Postfix() { GradingNetworkSync.Initialize(); } } public static class GradingNetworkSync { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__ReceiveStatusRequest; public static HandleNamedMessageDelegate <1>__ReceiveStatusResponse; public static HandleNamedMessageDelegate <2>__ReceivePresentationSuccess; public static HandleNamedMessageDelegate <3>__ReceivePresentationFailure; public static HandleNamedMessageDelegate <4>__ReceiveSubmitRequest; } private const string SubmitMessageName = "LethalCards.GradingSubmit"; private const string PresentationSuccessName = "LethalCards.GradingPresentationSuccess"; private const string PresentationFailureName = "LethalCards.GradingPresentationFailure"; private static NetworkManager? currentManager; private const string StatusRequestName = "LethalCards.GradingStatusRequest"; private const string StatusResponseName = "LethalCards.GradingStatusResponse"; private const int StatusRequestPayloadSize = 8; private const int StatusResponseFixedPayloadSize = 12; private static ulong nextStatusRequest; private static ulong pendingStatusRequest; private static Action<int, string>? pendingStatusCallback; internal static void CancelStatusRequest() { pendingStatusCallback = null; } internal unsafe static bool RequestStatus(Action<int, string> callback) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) Initialize(); if ((Object)(object)currentManager == (Object)null) { Plugin.Log.LogWarning((object)"GRADING REQUEST BLOCKED | Reason=NetworkNotInitialized"); return false; } if (!currentManager.IsConnectedClient) { Plugin.Log.LogWarning((object)"GRADING REQUEST BLOCKED | Reason=ClientNotConnected"); return false; } if (currentManager.IsServer) { Plugin.Log.LogWarning((object)"GRADING REQUEST BLOCKED | Reason=ServerUsesAuthoritativeLocalQueue"); return false; } pendingStatusRequest = ++nextStatusRequest; pendingStatusCallback = callback; FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref pendingStatusRequest, default(ForPrimitives)); currentManager.CustomMessagingManager.SendNamedMessage("LethalCards.GradingStatusRequest", 0uL, val, (NetworkDelivery)3); Plugin.Log.LogInfo((object)($"GRADING CLIENT REQUEST SENT | LocalClientId={currentManager.LocalClientId} | " + "MessageName=LethalCards.GradingStatusRequest")); return true; } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe static void ReceiveStatusRequest(ulong senderClientId, FastBufferReader reader) { //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)currentManager == (Object)null) { Plugin.Log.LogWarning((object)"GRADING REQUEST BLOCKED | Reason=NetworkNotInitialized"); return; } if (!currentManager.IsServer) { Plugin.Log.LogWarning((object)$"GRADING REQUEST BLOCKED | Reason=ReceiverNotServer | SenderClientId={senderClientId}"); return; } if (!currentManager.ConnectedClients.ContainsKey(senderClientId)) { Plugin.Log.LogWarning((object)$"GRADING REQUEST BLOCKED | Reason=SenderNotConnected | SenderClientId={senderClientId}"); return; } int num = ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position; if (num != 8) { Plugin.Log.LogWarning((object)($"GRADING REQUEST BLOCKED | Reason=InvalidPayloadLength | SenderClientId={senderClientId} | " + $"ExpectedLength={8} | ActualLength={num} | " + $"ReaderLength={((FastBufferReader)(ref reader)).Length} | ReaderPosition={((FastBufferReader)(ref reader)).Position}")); return; } ulong num2 = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num2, default(ForPrimitives)); if (num2 == 0) { Plugin.Log.LogWarning((object)$"GRADING REQUEST BLOCKED | Reason=InvalidRequestId | SenderClientId={senderClientId} | RequestId={num2}"); return; } int count = GradingManager.Jobs.Count; Plugin.Log.LogInfo((object)($"GRADING HOST REQUEST RECEIVED | SenderClientId={senderClientId} | " + string.Format("MessageName={0} | RuntimeJobCount={1}", "LethalCards.GradingStatusRequest", count))); string text = CollectionTerminalPatch.BuildGradingText("grades"); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(12 + FastBufferWriter.GetWriteSize(text, false), (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref num2, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref count, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(text, false); currentManager.CustomMessagingManager.SendNamedMessage("LethalCards.GradingStatusResponse", senderClientId, val, (NetworkDelivery)4); Plugin.Log.LogInfo((object)($"GRADING HOST RESPONSE SENT | TargetClientId={senderClientId} | JobCount={count} | " + "MessageName=LethalCards.GradingStatusResponse")); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void ReceiveStatusResponse(ulong senderClientId, FastBufferReader reader) { //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)currentManager == (Object)null) { Plugin.Log.LogWarning((object)"GRADING RESPONSE BLOCKED | Reason=NetworkNotInitialized"); return; } if (currentManager.IsServer) { Plugin.Log.LogWarning((object)$"GRADING RESPONSE BLOCKED | Reason=ReceiverIsServer | SenderClientId={senderClientId}"); return; } if (senderClientId != 0) { Plugin.Log.LogWarning((object)$"GRADING RESPONSE BLOCKED | Reason=SenderIsNotServer | SenderClientId={senderClientId}"); return; } if (pendingStatusCallback == null) { Plugin.Log.LogWarning((object)"GRADING RESPONSE BLOCKED | Reason=NoPendingRequest"); return; } int num = ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position; if (num < 12) { Plugin.Log.LogWarning((object)("GRADING RESPONSE BLOCKED | Reason=InvalidPayloadLength | " + $"MinimumExpectedLength={12} | ActualLength={num} | " + $"ReaderLength={((FastBufferReader)(ref reader)).Length} | ReaderPosition={((FastBufferReader)(ref reader)).Position}")); return; } ulong num2 = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num2, default(ForPrimitives)); if (num2 != pendingStatusRequest) { Plugin.Log.LogWarning((object)$"GRADING RESPONSE BLOCKED | Reason=RequestIdMismatch | Expected={pendingStatusRequest} | Actual={num2}"); return; } int num3 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num3, default(ForPrimitives)); string arg = default(string); ((FastBufferReader)(ref reader)).ReadValueSafe(ref arg, false); Plugin.Log.LogInfo((object)($"GRADING CLIENT RESPONSE RECEIVED | LocalClientId={currentManager.LocalClientId} | " + string.Format("JobCount={0} | MessageName={1}", num3, "LethalCards.GradingStatusResponse"))); Action<int, string> action = pendingStatusCallback; pendingStatusCallback = null; action(num3, arg); } public static void Shutdown() { if ((Object)(object)currentManager != (Object)null) { CustomMessagingManager customMessagingManager = currentManager.CustomMessagingManager; if (customMessagingManager != null) { customMessagingManager.UnregisterNamedMessageHandler("LethalCards.GradingSubmit"); } CustomMessagingManager customMessagingManager2 = currentManager.CustomMessagingManager; if (customMessagingManager2 != null) { customMessagingManager2.UnregisterNamedMessageHandler("LethalCards.GradingStatusRequest"); } CustomMessagingManager customMessagingManager3 = currentManager.CustomMessagingManager; if (customMessagingManager3 != null) { customMessagingManager3.UnregisterNamedMessageHandler("LethalCards.GradingStatusResponse"); } CustomMessagingManager customMessagingManager4 = currentManager.CustomMessagingManager; if (customMessagingManager4 != null) { customMessagingManager4.UnregisterNamedMessageHandler("LethalCards.GradingPresentationSuccess"); } CustomMessagingManager customMessagingManager5 = currentManager.CustomMessagingManager; if (customMessagingManager5 != null) { customMessagingManager5.UnregisterNamedMessageHandler("LethalCards.GradingPresentationFailure"); } } CancelStatusRequest(); currentManager = null; } public static void Initialize() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsListening && !((Object)(object)currentManager == (Object)(object)singleton)) { Shutdown(); currentManager = singleton; CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; object obj = <>O.<0>__ReceiveStatusRequest; if (obj == null) { HandleNamedMessageDelegate val = ReceiveStatusRequest; <>O.<0>__ReceiveStatusRequest = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("LethalCards.GradingStatusRequest", (HandleNamedMessageDelegate)obj); CustomMessagingManager customMessagingManager2 = singleton.CustomMessagingManager; object obj2 = <>O.<1>__ReceiveStatusResponse; if (obj2 == null) { HandleNamedMessageDelegate val2 = ReceiveStatusResponse; <>O.<1>__ReceiveStatusResponse = val2; obj2 = (object)val2; } customMessagingManager2.RegisterNamedMessageHandler("LethalCards.GradingStatusResponse", (HandleNamedMessageDelegate)obj2); CustomMessagingManager customMessagingManager3 = singleton.CustomMessagingManager; object obj3 = <>O.<2>__ReceivePresentationSuccess; if (obj3 == null) { HandleNamedMessageDelegate val3 = ReceivePresentationSuccess; <>O.<2>__ReceivePresentationSuccess = val3; obj3 = (object)val3; } customMessagingManager3.RegisterNamedMessageHandler("LethalCards.GradingPresentationSuccess", (HandleNamedMessageDelegate)obj3); CustomMessagingManager customMessagingManager4 = singleton.CustomMessagingManager; object obj4 = <>O.<3>__ReceivePresentationFailure; if (obj4 == null) { HandleNamedMessageDelegate val4 = ReceivePresentationFailure; <>O.<3>__ReceivePresentationFailure = val4; obj4 = (object)val4; } customMessagingManager4.RegisterNamedMessageHandler("LethalCards.GradingPresentationFailure", (HandleNamedMessageDelegate)obj4); CustomMessagingManager customMessagingManager5 = singleton.CustomMessagingManager; object obj5 = <>O.<4>__ReceiveSubmitRequest; if (obj5 == null) { HandleNamedMessageDelegate val5 = ReceiveSubmitRequest; <>O.<4>__ReceiveSubmitRequest = val5; obj5 = (object)val5; } customMessagingManager5.RegisterNamedMessageHandler("LethalCards.GradingSubmit", (HandleNamedMessageDelegate)obj5); Plugin.Log.LogInfo((object)("GRADING NETWORK INITIALIZED | " + $"IsServer={singleton.IsServer} | IsHost={singleton.IsHost} | IsClient={singleton.IsClient} | " + $"LocalClientId={singleton.LocalClientId} | StatusHandlersRegistered=True")); } } internal unsafe static void BroadcastSubmissionPresentation(string cardId, CardVariant variant) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) NetworkManager val = currentManager; if ((Object)(object)val == (Object)null || !val.IsServer || !val.IsListening) { return; } GradingPedestalSpawner.PlaySubmissionAnimation(cardId, variant); FastBufferWriter val2 = default(FastBufferWriter); foreach (ulong connectedClientsId in val.ConnectedClientsIds) { if (connectedClientsId != 0) { ((FastBufferWriter)(ref val2))..ctor(512, (Allocator)2, -1); try { ((FastBufferWriter)(ref val2)).WriteValueSafe(cardId, false); int num = (int)variant; ((FastBufferWriter)(ref val2)).WriteValueSafe<int>(ref num, default(ForPrimitives)); val.CustomMessagingManager.SendNamedMessage("LethalCards.GradingPresentationSuccess", connectedClientsId, val2, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose(); } } } } internal unsafe static void SendInsufficientCreditsPresentation(ulong clientId) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) NetworkManager val = currentManager; if ((Object)(object)val == (Object)null || !val.IsServer || !val.IsListening) { return; } if (clientId == 0) { GradingPedestalSpawner.PlayInsufficientCreditsAnimation(); } else if (val.ConnectedClients.ContainsKey(clientId)) { FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(1, (Allocator)2, -1); try { val.CustomMessagingManager.SendNamedMessage("LethalCards.GradingPresentationFailure", clientId, val2, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose(); } } } private static void ReceivePresentationSuccess(ulong senderClientId, FastBufferReader reader) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)currentManager == (Object)null) && !currentManager.IsServer && senderClientId == 0) { string cardId = default(string); ((FastBufferReader)(ref reader)).ReadValueSafe(ref cardId, false); int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); if (Enum.IsDefined(typeof(CardVariant), num)) { GradingPedestalSpawner.PlaySubmissionAnimation(cardId, (CardVariant)num); } } } private static void ReceivePresentationFailure(ulong senderClientId, FastBufferReader reader) { if (!((Object)(object)currentManager == (Object)null) && !currentManager.IsServer && senderClientId == 0) { GradingPedestalSpawner.PlayInsufficientCreditsAnimation(); } } public unsafe static void RequestSubmission() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsListening) { return; } if (singleton.IsServer) { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val != (Object)null) { GradingPedestalBehaviour.TrySubmitHeldCardServer(val); } return; } FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(1, (Allocator)2, -1); try { singleton.CustomMessagingManager.SendNamedMessage("LethalCards.GradingSubmit", 0uL, val2, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose(); } } private static void ReceiveSubmitRequest(ulong senderClientId, FastBufferReader reader) { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsServer) { PlayerControllerB val = FindPlayerByClientId(senderClientId); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("GRADING SUBMIT REQUEST REJECTED | " + $"Client={senderClientId} | " + "Reason=Player not found")); } else { GradingPedestalBehaviour.TrySubmitHeldCardServer(val); } } } private static PlayerControllerB? FindPlayerByClientId(ulong clientId) { if ((Object)(object)StartOfRound.Instance == (Object)null) { return null; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; if (allPlayerScripts == null) { return null; } PlayerControllerB[] array = allPlayerScripts; foreach (PlayerControllerB val in array) { if (!((Object)(object)val == (Object)null) && val.actualClientId == clientId) { return val; } } return null; } } internal sealed class GradingPedestalAnimationController : MonoBehaviour { private const string IdleText = "> SUBMIT CARD FOR GRADING"; private const float ScanningDelay = 0.35f; private const float ScanDuration = 3f; private const float PostScanPause = 0.25f; private const float SlotOpenDuration = 0.12f; private const float DropDuration = 0.45f; private const float SuccessDuration = 0.8f; private const float InsufficientCreditsDuration = 1.25f; private const float CursorBlinkInterval = 0.5f; private const float FlickerSpeed = 18f; private const float FlickerAmount = 0.04f; private const float MinGlitchInterval = 4f; private const float MaxGlitchInterval = 9f; private const float GlitchDuration = 0.06f; private const float GlitchBrightness = 0.35f; private const float TextGlitchOffset = 0.05f; private const float TextGlitchStep = 0.015f; private static readonly Color InsufficientCreditsEmission = new Color(4f, 0f, 0f, 1f); private Transform? cardSubmissionAnchor; private GameObject? cardSlotOpening; private TMP_Text? screenText; private GameObject? statusGreen; private GameObject? statusRed; private Transform? scanStartPoint; private Transform? scanEndPoint; private Transform? cardDropPoint; private Transform? scanFanPivot; private GameObject? scanBeamFan; private Light? scanSpotLight; private GameObject? scanBeam; private AudioSource? scanAudioSource; private AudioSource? cardDropAudioSource; private Material? screenMaterial; private RectTransform? screenTextRect; private GameObject? presentationCard; private Coroutine? animationRoutine; private Coroutine? glitchRoutine; private Color idleEmissionColor; private Color currentBaseEmissionColor; private Vector2 screenTextBasePosition; private Vector3 cardSlotFullScale; private Quaternion scanFanBaseRotation; private float nextGlitchTime; private float glitchMultiplier = 1f; private float cursorBlinkTimer; private bool cursorVisible = true; private bool initialized; internal bool Initialize() { //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) if (initialized) { return true; } cardSubmissionAnchor = ResolveTransform("CardSubmissionAnchor"); cardSlotOpening = ResolveObject("CardSlotOpening"); Transform val = ResolveTransform("DisplayScreen"); Transform val2 = ResolveTransform("ScreenText"); screenText = ((val2 != null) ? ((Component)val2).GetComponent<TMP_Text>() : null) ?? ((val2 != null) ? ((Component)val2).GetComponentInChildren<TMP_Text>(true) : null); if ((Object)(object)screenText == (Object)null) { WarnMissing("ScreenText TMP component"); } Renderer val3 = ((val != null) ? ((Component)val).GetComponent<Renderer>() : null) ?? ((val != null) ? ((Component)val).GetComponentInChildren<Renderer>(true) : null); if ((Object)(object)val3 == (Object)null) { WarnMissing("DisplayScreen renderer"); } else { screenMaterial = val3.material; if (screenMaterial.HasProperty("_EmissiveColor")) { idleEmissionColor = screenMaterial.GetColor("_EmissiveColor"); currentBaseEmissionColor = idleEmissionColor; } } statusGreen = ResolveObject("StatusGreen"); statusRed = ResolveObject("StatusRed"); scanStartPoint = ResolveTransform("ScanStartPoint"); scanEndPoint = ResolveTransform("ScanEndPoint"); cardDropPoint = ResolveTransform("CardDropPoint"); scanFanPivot = ResolveTransform("ScanFanPivot"); scanBeamFan = ResolveObject("ScanBeamFan"); Transform val4 = ResolveTransform("ScanSpotLight"); scanSpotLight = ((val4 != null) ? ((Component)val4).GetComponent<Light>() : null) ?? ((val4 != null) ? ((Component)val4).GetComponentInChildren<Light>(true) : null); if ((Object)(object)scanSpotLight == (Object)null) { WarnMissing("ScanSpotLight Light component"); } scanBeam = ResolveObject("ScanBeam"); scanAudioSource = ResolveAudioSource("ScanAudioSource"); cardDropAudioSource = ResolveAudioSource("CardDropAudioSource"); if ((Object)(object)cardSlotOpening != (Object)null) { cardSlotFullScale = cardSlotOpening.transform.localScale; } if ((Object)(object)scanFanPivot != (Object)null) { scanFanBaseRotation = scanFanPivot.localRotation; } if ((Object)(object)screenText != (Object)null) { screenTextRect = screenText.rectTransform; screenTextBasePosition = screenTextRect.anchoredPosition; } nextGlitchTime = Time.time + Random.Range(4f, 9f); initialized = true; SetIdleState(); Plugin.Log.LogInfo((object)"GRADING PEDESTAL ANIMATION READY"); return true; } internal void PlaySubmission(string cardId, CardVariant variant) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) if (!initialized) { Initialize(); } if (animationRoutine != null) { return; } CardDefinition byId = CardDatabase.GetById(cardId); if ((Object)(object)byId?.ItemAsset?.spawnPrefab == (Object)null || (Object)(object)cardSubmissionAnchor == (Object)null || (Object)(object)cardDropPoint == (Object)null) { Plugin.Log.LogWarning((object)("GRADING PEDESTAL PRESENTATION SKIPPED | CardId=" + cardId + " | Missing card prefab or animation anchor")); return; } presentationCard = CreateVisualOnlyCard(byId.ItemAsset.spawnPrefab, variant); if ((Object)(object)presentationCard == (Object)null) { Plugin.Log.LogWarning((object)("GRADING PEDESTAL PRESENTATION SKIPPED | CardId=" + cardId + " | Visual clone failed")); return; } presentationCard.transform.position = cardSubmissionAnchor.position; presentationCard.transform.rotation = cardSubmissionAnchor.rotation; animationRoutine = ((MonoBehaviour)this).StartCoroutine(SubmissionSequence()); } internal void PlayInsufficientCredits() { if (!initialized) { Initialize(); } if (animationRoutine == null) { animationRoutine = ((MonoBehaviour)this).StartCoroutine(InsufficientCreditsSequence()); } } private void Update() { //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) if (!initialized) { return; } if (animationRoutine == null) { cursorBlinkTimer += Time.deltaTime; if (cursorBlinkTimer >= 0.5f) { cursorBlinkTimer = 0f; cursorVisible = !cursorVisible; if ((Object)(object)screenText != (Object)null) { screenText.text = "> SUBMIT CARD FOR GRADING" + (cursorVisible ? "_" : string.Empty); } } } if (Time.time >= nextGlitchTime) { if (glitchRoutine == null) { glitchRoutine = ((MonoBehaviour)this).StartCoroutine(ScreenGlitch()); } nextGlitchTime = Time.time + Random.Range(4f, 9f); } if ((Object)(object)screenMaterial != (Object)null && screenMaterial.HasProperty("_EmissiveColor")) { float num = Mathf.PerlinNoise(Time.time * 18f, 0f); float num2 = 1f + (num - 0.5f) * 2f * 0.04f; screenMaterial.SetColor("_EmissiveColor", currentBaseEmissionColor * num2 * glitchMultiplier); } } private IEnumerator SubmissionSequence() { SetScannerState(active: false); SetStatus(green: false, red: true); SetScreenText("SCANNING"); yield return (object)new WaitForSeconds(0.35f); if ((Object)(object)scanBeam != (Object)null && (Object)(object)scanStartPoint != (Object)null) { scanBeam.transform.position = scanStartPoint.position; } SetScannerState(active: true); AudioSource? obj = scanAudioSource; if (obj != null) { obj.Play(); } float elapsed = 0f; while (elapsed < 3f) { elapsed += Time.deltaTime; float t = Mathf.Clamp01(elapsed / 3f); int dots = Mathf.Clamp(Mathf.FloorToInt(t * 4f), 0, 3); SetScreenText("SCANNING" + new string('.', dots)); if ((Object)(object)scanBeam != (Object)null && (Object)(object)scanStartPoint != (Object)null && (Object)(object)scanEndPoint != (Object)null) { Vector3 scanPosition = Vector3.Lerp(scanStartPoint.position, scanEndPoint.position, t); scanBeam.transform.position = scanPosition; AimScanFan(scanPosition); } yield return null; } if ((Object)(object)scanBeam != (Object)null && (Object)(object)scanEndPoint != (Object)null) { scanBeam.transform.position = scanEndPoint.position; } SetScreenText("SCANNING..."); yield return (object)new WaitForSeconds(0.25f); SetScannerState(active: false); AudioSource? obj2 = scanAudioSource; if (obj2 != null) { obj2.Stop(); } yield return AnimateCardSlot(open: true); if ((Object)(object)presentationCard != (Object)null && (Object)(object)cardDropPoint != (Object)null) { Vector3 start = presentationCard.transform.position; Quaternion rotation = presentationCard.transform.rotation; AudioSource? obj3 = cardDropAudioSource; if (obj3 != null) { obj3.Play(); } elapsed = 0f; while (elapsed < 0.45f) { elapsed += Time.deltaTime; float t2 = Mathf.Clamp01(elapsed / 0.45f); t2 *= t2; presentationCard.transform.position = Vector3.Lerp(start, cardDropPoint.position, t2); presentationCard.transform.rotation = rotation; yield return null; } } DestroyPresentationCard(); yield return AnimateCardSlot(open: false); SetStatus(green: true, red: false); SetScreenText("SUBMISSION COMPLETE!"); yield return (object)new WaitForSeconds(0.8f); animationRoutine = null; SetIdleState(); } private IEnumerator InsufficientCreditsSequence() { SetScannerState(active: false); AudioSource? obj = scanAudioSource; if (obj != null) { obj.Stop(); } SetStatus(green: false, red: true); currentBaseEmissionColor = InsufficientCreditsEmission; ApplyBaseEmission(); SetScreenText("NOT ENOUGH\nCREDITS"); yield return (object)new WaitForSeconds(1.25f); currentBaseEmissionColor = idleEmissionColor; ApplyBaseEmission(); animationRoutine = null; SetIdleState(); } private IEnumerator ScreenGlitch() { glitchMultiplier = 0.35f; if ((Object)(object)screenTextRect != (Object)null) { for (float elapsed = 0f; elapsed < 0.06f; elapsed += 0.015f) { screenTextRect.anchoredPosition = screenTextBasePosition + new Vector2(Random.Range(-0.05f, 0.05f), Random.Range(-0.0125f, 0.0125f)); yield return (object)new WaitForSeconds(0.015f); } screenTextRect.anchoredPosition = screenTextBasePosition; } else { yield return (object)new WaitForSeconds(0.06f