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 ExtraBattleUpgrades v1.1.0
ExtraBattleUpgrades.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExtraBattleUpgrades.Combat; using ExtraBattleUpgrades.Hud; using ExtraBattleUpgrades.Upgrades; using ExtraBattleUpgrades.Visuals; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using REPOLib.Modules; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ExtraBattleUpgrades { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("DarkSpider90.ExtraBattleUpgrades", "Extra Battle Upgrades", "1.0.5")] public sealed class ExtraBattleUpgradesPlugin : BaseUnityPlugin { public const string PluginGuid = "DarkSpider90.ExtraBattleUpgrades"; public const string PluginName = "Extra Battle Upgrades"; public const string PluginVersion = "1.0.5"; private Harmony _harmony; private bool _statsLabelsReady; private static readonly FieldInfo StatsDictionariesField = AccessTools.Field(typeof(StatsManager), "dictionaryOfDictionaries"); internal static ExtraBattleUpgradesPlugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ArmorShopUpgrade Armor { get; private set; } internal static OverchargeShopUpgrade Overcharge { get; private set; } internal static EnergyLeechShopUpgrade EnergyLeech { get; private set; } internal static ShockGripShopUpgrade ShockGrip { get; private set; } internal static SecondChanceShopUpgrade SecondChance { get; private set; } internal static PanicResponseShopUpgrade PanicResponse { get; private set; } internal static BattleUpgradeHudConfig HudConfig { get; private set; } internal static ConfigEntry<bool> VerboseUpgradeLogging { get; private set; } private void Awake() { //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; VerboseUpgradeLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Debug Log", false, "Enable detailed debug logs for upgrade registration, REPOLib dictionaries, StatsManager, and StatsUI. Keep disabled for clean normal logs."); AssetBundle val = ReadBundledAssets(); ((Object)val).name = "extra_battle_upgrades_assets"; Armor = new ArmorShopUpgrade(((BaseUnityPlugin)this).Config, val); Overcharge = new OverchargeShopUpgrade(((BaseUnityPlugin)this).Config, val); EnergyLeech = new EnergyLeechShopUpgrade(((BaseUnityPlugin)this).Config, val); ShockGrip = new ShockGripShopUpgrade(((BaseUnityPlugin)this).Config, val); SecondChance = new SecondChanceShopUpgrade(((BaseUnityPlugin)this).Config, val); PanicResponse = new PanicResponseShopUpgrade(((BaseUnityPlugin)this).Config, val); HudConfig = new BattleUpgradeHudConfig(((BaseUnityPlugin)this).Config); Armor.Register(); Overcharge.Register(); EnergyLeech.Register(); ShockGrip.Register(); SecondChance.Register(); PanicResponse.Register(); _harmony = new Harmony("DarkSpider90.ExtraBattleUpgrades"); _harmony.PatchAll(); Log.LogInfo((object)"Extra Battle Upgrades v1.0.5 loaded for R.E.P.O. v0.4.0."); } private void Update() { if (!_statsLabelsReady && (Object)(object)StatsManager.instance != (Object)null) { RefreshStatsLabels(StatsManager.instance); _statsLabelsReady = true; } if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)LevelGenerator.Instance == (Object)null)) { _ = LevelGenerator.Instance.Generated; } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void RefreshStatsLabels(StatsManager statsManager) { Diagnostic("RefreshStatsLabels: begin."); SetStatsLabel(statsManager, "playerUpgradeArmor", "Armor"); SetStatsLabel(statsManager, "playerUpgradeOvercharge", "Overcharge"); SetStatsLabel(statsManager, "playerUpgradeEnergyLeech", "Energy Leech"); SetStatsLabel(statsManager, "playerUpgradeShockGrip", "Shock Grip"); SetStatsLabel(statsManager, "playerUpgradeSecondChance", "Second Chance"); SetStatsLabel(statsManager, "playerUpgradePanicResponse", "Panic Response"); if ((Object)(object)StatsUI.instance != (Object)null) { StatsUI.instance.ResetPlayerUpgradeNames(); Diagnostic("RefreshStatsLabels: StatsUI player upgrade name cache reset."); } Diagnostic("RefreshStatsLabels: end."); } private static void SetStatsLabel(StatsManager statsManager, string statsKey, string displayName) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown if (statsManager.upgradesInfo.TryGetValue(statsKey, out var value)) { Diagnostic("SetStatsLabel: update " + statsKey + " -> '" + displayName + "'."); value.displayName = displayName; value.displayNameLocalized = null; } else { Diagnostic("SetStatsLabel: add " + statsKey + " -> '" + displayName + "'."); statsManager.upgradesInfo.Add(statsKey, new UpgradeInfo { displayName = displayName, displayNameLocalized = null }); } } internal static void Diagnostic(string message) { ConfigEntry<bool> verboseUpgradeLogging = VerboseUpgradeLogging; if (verboseUpgradeLogging != null && verboseUpgradeLogging.Value && Log != null) { Log.LogInfo((object)("[UpgradeDiag] " + message)); } } internal static void LogAllUpgradeDictionaryStates(string context) { ConfigEntry<bool> verboseUpgradeLogging = VerboseUpgradeLogging; if (verboseUpgradeLogging == null || !verboseUpgradeLogging.Value) { return; } foreach (PlayerUpgrade playerUpgrade in Upgrades.PlayerUpgrades) { LogUpgradeDictionaryState(context, playerUpgrade, null); } } internal static void LogUpgradeDictionaryState(string context, PlayerUpgrade upgrade, string steamId) { ConfigEntry<bool> verboseUpgradeLogging = VerboseUpgradeLogging; if (verboseUpgradeLogging != null && verboseUpgradeLogging.Value && upgrade != null) { string text = "playerUpgrade" + upgrade.UpgradeId; Dictionary<string, int> dictionary = TryGetStatsDictionary(text); int num = dictionary?.Count ?? (-1); int num2 = upgrade.PlayerDictionary?.Count ?? (-1); string dictionaryValueText = GetDictionaryValueText(dictionary, steamId); string dictionaryValueText2 = GetDictionaryValueText(upgrade.PlayerDictionary, steamId); bool flag = dictionary != null && upgrade.PlayerDictionary != null && dictionary == upgrade.PlayerDictionary; Diagnostic(context + ": upgrade=" + upgrade.UpgradeId + ", statsKey=" + text + ", steamId=" + (steamId ?? "<none>") + ", " + $"statsExists={dictionary != null}, sameDictionary={flag}, " + $"statsCount={num}, repoCount={num2}, statsValue={dictionaryValueText}, repoValue={dictionaryValueText2}"); } } internal static bool EnsureUpgradeDictionaryLinked(PlayerUpgrade upgrade, string context, string steamId = null, int? level = null) { if (upgrade == null || (Object)(object)StatsManager.instance == (Object)null || StatsDictionariesField == null) { Diagnostic($"{context}: cannot link dictionary. upgradeNull={upgrade == null}, statsManagerNull={(Object)(object)StatsManager.instance == (Object)null}, fieldNull={StatsDictionariesField == null}."); return false; } if (!(StatsDictionariesField.GetValue(StatsManager.instance) is SortedDictionary<string, Dictionary<string, int>> sortedDictionary)) { Diagnostic(context + ": cannot link dictionary because StatsManager dictionary storage is unavailable."); return false; } string text = "playerUpgrade" + upgrade.UpgradeId; Dictionary<string, int> dictionary = upgrade.PlayerDictionary ?? new Dictionary<string, int>(); if (!sortedDictionary.TryGetValue(text, out var value)) { value = dictionary; sortedDictionary.Add(text, value); Diagnostic(context + ": created missing StatsManager dictionary " + text + " from REPOLib dictionary."); } else if (value != dictionary) { foreach (KeyValuePair<string, int> item in dictionary) { if (!value.ContainsKey(item.Key)) { value[item.Key] = item.Value; } } upgrade.PlayerDictionary = value; Diagnostic(context + ": linked REPOLib dictionary to existing StatsManager dictionary " + text + "."); } if (!string.IsNullOrWhiteSpace(steamId) && level.HasValue) { int num2 = (value[steamId] = Mathf.Max(level.Value, 0)); upgrade.PlayerDictionary = value; Diagnostic($"{context}: synced {text}[{steamId}]={num2}."); } return true; } internal static Dictionary<string, int> TryGetStatsDictionary(string statsKey) { if ((Object)(object)StatsManager.instance == (Object)null || StatsDictionariesField == null) { return null; } if (StatsDictionariesField.GetValue(StatsManager.instance) is SortedDictionary<string, Dictionary<string, int>> sortedDictionary && sortedDictionary.TryGetValue(statsKey, out var value)) { return value; } return null; } private static string GetDictionaryValueText(Dictionary<string, int> dictionary, string steamId) { if (dictionary == null) { return "<missing>"; } if (string.IsNullOrWhiteSpace(steamId)) { return "<not-requested>"; } if (!dictionary.TryGetValue(steamId, out var value)) { return "<absent>"; } return value.ToString(); } private static AssetBundle ReadBundledAssets() { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ExtraBattleUpgrades.Assets.extra_battle_upgrades_assets"); if (stream == null) { throw new FileNotFoundException("Embedded asset bundle ExtraBattleUpgrades.Assets.extra_battle_upgrades_assets was not found."); } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num == 0) { break; } } AssetBundle obj = AssetBundle.LoadFromMemory(array); if ((Object)(object)obj == (Object)null) { throw new InvalidDataException("Failed to load embedded extra_battle_upgrades_assets asset bundle."); } return obj; } } } namespace ExtraBattleUpgrades.Visuals { internal sealed class ShockGripVisualRelay : MonoBehaviour { private PlayerAvatar _player; private PhotonView _photonView; private void Awake() { _player = ((Component)this).GetComponent<PlayerAvatar>(); _photonView = ((Component)this).GetComponent<PhotonView>(); } internal static void Ensure(PlayerAvatar player) { if (!((Object)(object)player == (Object)null) && (Object)(object)((Component)player).GetComponent<ShockGripVisualRelay>() == (Object)null) { ((Component)player).gameObject.AddComponent<ShockGripVisualRelay>(); } } internal static void Broadcast(PlayerAvatar holder) { if ((Object)(object)holder == (Object)null) { return; } Ensure(holder); PhotonView photonView = holder.photonView; if (!((Object)(object)photonView == (Object)null)) { if (GameManager.Multiplayer()) { photonView.RPC("ShockGripVisualRPC", (RpcTarget)0, Array.Empty<object>()); } else { ShockGripVisuals.PlayLocal(holder); } } } [PunRPC] private void ShockGripVisualRPC(PhotonMessageInfo info = default(PhotonMessageInfo)) { if ((Object)(object)_player == (Object)null) { _player = ((Component)this).GetComponent<PlayerAvatar>(); } ShockGripVisuals.PlayLocal(_player); } } internal static class ShockGripVisuals { private static readonly Dictionary<int, ShockGripBeamEffect> Effects = new Dictionary<int, ShockGripBeamEffect>(); internal static void PlayLocal(PlayerAvatar holder) { if ((Object)(object)holder == (Object)null || (Object)(object)holder.physGrabber == (Object)null) { return; } PhysGrabBeam physGrabBeamComponent = holder.physGrabber.physGrabBeamComponent; if (!((Object)(object)physGrabBeamComponent == (Object)null)) { int instanceID = ((Object)holder).GetInstanceID(); if (!Effects.TryGetValue(instanceID, out var value) || (Object)(object)value == (Object)null) { value = ((Component)physGrabBeamComponent).gameObject.AddComponent<ShockGripBeamEffect>(); value.Setup(physGrabBeamComponent); Effects[instanceID] = value; } value.Play(); } } } internal sealed class ShockGripBeamEffect : MonoBehaviour { private const int BoltCount = 5; private const int PointsPerBolt = 4; private PhysGrabBeam _beam; private readonly List<LineRenderer> _bolts = new List<LineRenderer>(); private float _timer; private float _redrawTimer; private Material _beamMaterial; private Color _beamOriginalColor; private bool _hasBeamOriginalColor; internal void Setup(PhysGrabBeam beam) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) _beam = beam; if ((Object)(object)beam.lineRenderer != (Object)null) { _beamMaterial = ((Renderer)beam.lineRenderer).material; if ((Object)(object)_beamMaterial != (Object)null && _beamMaterial.HasProperty("_Color")) { _beamOriginalColor = _beamMaterial.color; _hasBeamOriginalColor = true; } } Color val3 = default(Color); for (int i = 0; i < 5; i++) { GameObject val = new GameObject($"Extra Battle Upgrades Shock Grip Bolt {i}"); val.transform.SetParent(((Component)beam).transform, false); LineRenderer val2 = val.AddComponent<LineRenderer>(); val2.positionCount = 4; val2.useWorldSpace = true; ((Renderer)val2).enabled = false; ((Renderer)val2).material = new Material(Shader.Find("Sprites/Default")); val2.widthMultiplier = 0.025f; val2.numCapVertices = 2; val2.numCornerVertices = 2; ((Color)(ref val3))..ctor(0.05f, 0.85f, 1f, 0.9f); val2.startColor = val3; val2.endColor = new Color(0.25f, 0.95f, 1f, 0.55f); ((Renderer)val2).material.color = val3; _bolts.Add(val2); } } internal void Play() { _timer = 0.28f; _redrawTimer = 0f; foreach (LineRenderer bolt in _bolts) { ((Renderer)bolt).enabled = true; } } private void LateUpdate() { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_beam == (Object)null || _bolts.Count == 0) { return; } if (_timer <= 0f) { foreach (LineRenderer bolt in _bolts) { ((Renderer)bolt).enabled = false; } RestoreBeamColor(); return; } _timer -= Time.deltaTime; _redrawTimer -= Time.deltaTime; float num = 0.45f + Mathf.Sin(Time.time * 18f) * 0.25f; float num2 = Mathf.Clamp01(_timer / 0.28f); float num3 = Mathf.Clamp01((0.35f + num) * num2); PulseBeamColor(num3); Color val = default(Color); Color endColor = default(Color); foreach (LineRenderer bolt2 in _bolts) { ((Color)(ref val))..ctor(0.05f, 0.85f, 1f, num3); ((Color)(ref endColor))..ctor(0.25f, 0.95f, 1f, num3 * 0.55f); bolt2.startColor = val; bolt2.endColor = endColor; if ((Object)(object)((Renderer)bolt2).material != (Object)null) { ((Renderer)bolt2).material.color = val; } } if (_redrawTimer <= 0f) { _redrawTimer = 0.045f; DrawBolts(); } } private void DrawBolts() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_beam.PhysGrabPointOrigin == (Object)null || (Object)(object)_beam.PhysGrabPoint == (Object)null || (Object)(object)_beam.PhysGrabPointPuller == (Object)null) { Disable(); return; } Vector3 position = _beam.PhysGrabPointOrigin.position; Vector3 val = _beam.PhysGrabPoint.position - position; if (((Vector3)(ref val)).magnitude <= 0.2f) { Disable(); return; } Vector3 normalized = ((Vector3)(ref val)).normalized; Vector3 val2 = (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform.forward : Vector3.forward); Vector3 val3 = Vector3.Cross(normalized, val2); Vector3 normalized2 = ((Vector3)(ref val3)).normalized; if (((Vector3)(ref normalized2)).sqrMagnitude < 0.001f) { val3 = Vector3.Cross(normalized, Vector3.up); normalized2 = ((Vector3)(ref val3)).normalized; } val3 = Vector3.Cross(normalized2, normalized); Vector3 normalized3 = ((Vector3)(ref val3)).normalized; for (int i = 0; i < _bolts.Count; i++) { LineRenderer val4 = _bolts[i]; float num = Random.Range(0.02f, 0.72f); float num2 = Random.Range(0.08f, 0.18f); for (int j = 0; j < 4; j++) { float num3 = (float)j / 3f; float t = Mathf.Clamp01(num + num2 * num3); Vector3 val5 = CalculateBeamPoint(t); float num4 = Random.Range(0.035f, 0.09f); float num5 = Random.Range(0f, MathF.PI * 2f); Vector3 val6 = normalized2 * Mathf.Cos(num5) * num4 + normalized3 * Mathf.Sin(num5) * num4; Vector3 val7 = normalized2 * Random.Range(-0.035f, 0.035f) + normalized3 * Random.Range(-0.035f, 0.035f); val4.SetPosition(j, val5 + val6 + val7); } } } private void Disable() { foreach (LineRenderer bolt in _bolts) { ((Renderer)bolt).enabled = false; } } private Vector3 CalculateBeamPoint(float t) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) Vector3 position = _beam.PhysGrabPointOrigin.position; Vector3 position2 = _beam.PhysGrabPoint.position; Vector3 position3 = _beam.PhysGrabPointPuller.position; _beam.physGrabPointPullerSmoothPosition = Vector3.Lerp(_beam.physGrabPointPullerSmoothPosition, position3, Time.deltaTime * 10f); Vector3 val = _beam.physGrabPointPullerSmoothPosition * _beam.CurveStrength; return Mathf.Pow(1f - t, 2f) * position + 2f * (1f - t) * t * val + Mathf.Pow(t, 2f) * position2; } private void PulseBeamColor(float alpha) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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) if (_hasBeamOriginalColor && !((Object)(object)_beamMaterial == (Object)null)) { Color val = Color.Lerp(new Color(0.05f, 0.85f, 1f, _beamOriginalColor.a), Color.white, 0.65f); float num = Mathf.Sin(Time.time * 22f) * 0.5f + 0.5f; float num2 = Mathf.Clamp01(alpha * num * 0.65f); _beamMaterial.color = Color.Lerp(_beamOriginalColor, val, num2); } } private void RestoreBeamColor() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (_hasBeamOriginalColor && (Object)(object)_beamMaterial != (Object)null) { _beamMaterial.color = _beamOriginalColor; } } } } namespace ExtraBattleUpgrades.Upgrades { internal sealed class ArmorShopUpgrade : ShopUpgrade { internal const string StatsDictionaryKey = "playerUpgradeArmor"; private readonly ConfigEntry<float> _bonusPerLevelFirstTen; private readonly ConfigEntry<float> _bonusPerLevelAfterTen; protected override string UpgradeId => "Armor"; internal ArmorShopUpgrade(ConfigFile config, AssetBundle bundle) : base(config, bundle, "Armor", "assets/extrabattleupgrades/items/item upgrade player armor.prefab", 1f) { _bonusPerLevelFirstTen = config.Bind<float>("Armor Upgrade", "Bonus Per Level First Ten", 0.05f, "Damage Reduction per Armor level 1 to 10. 0.05 = 5%."); _bonusPerLevelAfterTen = config.Bind<float>("Armor Upgrade", "Damage Reduction Per Level After Ten", 0.05f, "Damage reduction per Armor level 10. 0.01 = 1%."); } internal int ReduceDamage(int damage, PlayerAvatar player) { int level = GetLevel(player); if (damage <= 0 || level <= 0) { return damage; } float num = Math.Max(0f, 1f - DamageReduction(level)); return Math.Max(1, (int)Math.Ceiling((float)damage * num)); } private float DamageReduction(int level) { int num = Math.Min(level, 10); int num2 = Math.Max(0, level - 10); return (float)num * Math.Max(0f, _bonusPerLevelFirstTen.Value) + (float)num2 * Math.Max(0f, _bonusPerLevelAfterTen.Value); } } internal sealed class EnergyLeechShopUpgrade : ShopUpgrade { internal const string StatsDictionaryKey = "playerUpgradeEnergyLeech"; private readonly ConfigEntry<float> _bonusPerLevelFirstTen; private readonly ConfigEntry<float> _bonusPerLevelAfterTen; protected override string UpgradeId => "EnergyLeech"; internal EnergyLeechShopUpgrade(ConfigFile config, AssetBundle bundle) : base(config, bundle, "Energy Leech", "assets/extrabattleupgrades/items/item upgrade player energy leech.prefab", 1f) { _bonusPerLevelFirstTen = config.Bind<float>("Energy Leech Upgrade", "Healing Percent Per Level First Ten", 0.025f, "Healing Percent Per Energy Leech level from level 1 to 10. 0.025 = 2.5%."); _bonusPerLevelAfterTen = config.Bind<float>("Energy Leech Upgrade", "Healing Percent Per Level After Ten", 0.01f, "Percent Of Steel HP per Energy Leech level after level 10. 0.01 = 1%."); } internal int HealingFromDamage(int damage, PlayerAvatar player) { int level = GetLevel(player); if (damage <= 0 || level <= 0) { return 0; } return Math.Max(1, (int)Math.Ceiling((float)damage * HealingPercent(level))); } private float HealingPercent(int level) { int num = Math.Min(level, 10); int num2 = Math.Max(0, level - 10); return (float)num * Math.Max(0f, _bonusPerLevelFirstTen.Value) + (float)num2 * Math.Max(0f, _bonusPerLevelAfterTen.Value); } } internal sealed class OverchargeShopUpgrade : ShopUpgrade { internal const string StatsDictionaryKey = "playerUpgradeOvercharge"; private readonly ConfigEntry<float> _bonusPerLevelFirstTen; private readonly ConfigEntry<float> _bonusPerLevelAfterTen; private readonly ConfigEntry<float> _holdStabilityEffectMultiplier; private readonly ConfigEntry<float> _recoveryBasePerSecond; protected override string UpgradeId => "Overcharge"; internal OverchargeShopUpgrade(ConfigFile config, AssetBundle bundle) : base(config, bundle, "Overcharge", "assets/extrabattleupgrades/items/item upgrade player overcharge.prefab", 0.75f) { _bonusPerLevelFirstTen = config.Bind<float>("Overcharge Upgrade", "Bonus Per Level First Ten", 0.1f, "Bonus per Overcharge level from level 1 to 10. 0.10 = 10%."); _bonusPerLevelAfterTen = config.Bind<float>("Overcharge Upgrade", "Bonus Per Level After Ten", 0.05f, "Bonus per Overcharge level after level 10. 0.05 = 5%."); _holdStabilityEffectMultiplier = config.Bind<float>("Overcharge Upgrade", "Hold Stability Effect Multiplier", 0.25f, "How strongly Overcharge affects enemy hold stability. 0.25 = 25% of the Overcharge bonus."); _recoveryBasePerSecond = config.Bind<float>("Overcharge Upgrade", "Recovery Base Per Second", 0.1f, "Base vanilla overcharge recovery per second used by this mod. Default vanilla-like value is 0.1."); } internal float SlowOvercharge(float value, PlayerAvatar player) { int level = GetLevel(player); if (value <= 0f || level <= 0) { return value; } return value / (1f + BonusMultiplier(player)); } internal float BonusMultiplier(PlayerAvatar player) { return BonusTime(GetLevel(player)); } internal float HoldStabilityBonus(PlayerAvatar player) { return BonusMultiplier(player) * _holdStabilityEffectMultiplier.Value; } internal float RecoveryBasePerSecond() { return Mathf.Max(0f, _recoveryBasePerSecond.Value); } private float BonusTime(int level) { if (level <= 0) { return 0f; } int num = Math.Min(level, 10); int num2 = Math.Max(0, level - 10); return (float)num * Mathf.Max(0f, _bonusPerLevelFirstTen.Value) + (float)num2 * Mathf.Max(0f, _bonusPerLevelAfterTen.Value); } } internal sealed class PanicResponseShopUpgrade : ShopUpgrade { internal const string StatsDictionaryKey = "playerUpgradePanicResponse"; private readonly ConfigEntry<float> _durationLevel1; private readonly ConfigEntry<float> _durationLevel2To3; private readonly ConfigEntry<float> _durationLevel4Plus; private readonly ConfigEntry<float> _cooldownBase; private readonly ConfigEntry<float> _cooldownReductionStartLevel; private readonly ConfigEntry<float> _cooldownReductionPerLevel; private readonly ConfigEntry<float> _cooldownMin; private readonly ConfigEntry<float> _speedMultiplierLevel1To2; private readonly ConfigEntry<float> _speedMultiplierLevel3Plus; private readonly ConfigEntry<float> _sprintDrainReductionPerLevelFirstTen; private readonly ConfigEntry<float> _sprintDrainReductionPerLevelAfterTen; private readonly ConfigEntry<float> _sprintDrainMinimumMultiplier; protected override string UpgradeId => "PanicResponse"; internal PanicResponseShopUpgrade(ConfigFile config, AssetBundle bundle) : base(config, bundle, "Panic Response", "assets/extrabattleupgrades/items/item upgrade player panic response.prefab", 1f) { _durationLevel1 = config.Bind<float>("Panic Response Upgrade", "Duration Level 1", 5f, "Panic Response duration at level 1, in seconds."); _durationLevel2To3 = config.Bind<float>("Panic Response Upgrade", "Duration Level 2 To 3", 6f, "Panic Response duration from level 2 to level 3, in seconds."); _durationLevel4Plus = config.Bind<float>("Panic Response Upgrade", "Duration Level 4 Plus", 7f, "Panic Response duration from level 4 and above, in seconds."); _cooldownBase = config.Bind<float>("Panic Response Upgrade", "Cooldown Base", 60f, "Base Panic Response cooldown, in seconds."); _cooldownReductionStartLevel = config.Bind<float>("Panic Response Upgrade", "Cooldown Reduction Start Level", 5f, "Level where cooldown reduction starts. Default 5 means level 5+ starts reducing cooldown."); _cooldownReductionPerLevel = config.Bind<float>("Panic Response Upgrade", "Cooldown Reduction Per Level", 5f, "Cooldown reduction per level after the reduction start level, in seconds."); _cooldownMin = config.Bind<float>("Panic Response Upgrade", "Cooldown Minimum", 30f, "Minimum Panic Response cooldown, in seconds."); _speedMultiplierLevel1To2 = config.Bind<float>("Panic Response Upgrade", "Speed Multiplier Level 1 To 2", 1.2f, "Speed multiplier from level 1 to level 2. 1.2 = 20% faster."); _speedMultiplierLevel3Plus = config.Bind<float>("Panic Response Upgrade", "Speed Multiplier Level 3 Plus", 1.35f, "Speed multiplier from level 3 and above. 1.35 = 35% faster."); _sprintDrainReductionPerLevelFirstTen = config.Bind<float>("Panic Response Upgrade", "Sprint Drain Reduction Per Level First Ten", 0.05f, "Passive sprint stamina drain reduction per Panic Response level from level 1 to 10. 0.05 = 5%."); _sprintDrainReductionPerLevelAfterTen = config.Bind<float>("Panic Response Upgrade", "Sprint Drain Reduction Per Level After Ten", 0.02f, "Passive sprint stamina drain reduction per Panic Response level after level 10. 0.02 = 2%."); _sprintDrainMinimumMultiplier = config.Bind<float>("Panic Response Upgrade", "Sprint Drain Minimum Multiplier", 0.1f, "Minimum sprint stamina drain multiplier. 0.1 = sprint can never cost less than 10% of vanilla."); } internal float DurationSeconds(PlayerAvatar player) { int num = Math.Min(GetLevel(player), 10); if (num <= 0) { return 0f; } if (num == 1) { return Math.Max(0f, _durationLevel1.Value); } if (num <= 3) { return Math.Max(0f, _durationLevel2To3.Value); } return Math.Max(0f, _durationLevel4Plus.Value); } internal float CooldownSeconds(PlayerAvatar player) { int num = Math.Min(GetLevel(player), 10); if (num <= 0) { return 9999f; } float num2 = Math.Max(0f, _cooldownBase.Value); float val = Math.Max(0f, _cooldownMin.Value); int num3 = Math.Max(1, Mathf.RoundToInt(_cooldownReductionStartLevel.Value)); if (num < num3) { return num2; } float num4 = (float)(num - num3 + 1) * Math.Max(0f, _cooldownReductionPerLevel.Value); return Math.Max(val, num2 - num4); } internal float SpeedMultiplier(PlayerAvatar player) { int num = Math.Min(GetLevel(player), 10); if (num <= 0) { return 1f; } if (num <= 2) { return Math.Max(1f, _speedMultiplierLevel1To2.Value); } return Math.Max(1f, _speedMultiplierLevel3Plus.Value); } internal float SprintDrainMultiplier(PlayerAvatar player) { int level = GetLevel(player); if (level <= 0) { return 1f; } int num = Math.Min(level, 10); int num2 = Math.Max(0, level - 10); float num3 = (float)num * Math.Max(0f, _sprintDrainReductionPerLevelFirstTen.Value) + (float)num2 * Math.Max(0f, _sprintDrainReductionPerLevelAfterTen.Value); float num4 = 1f - num3; return Mathf.Max(Mathf.Clamp01(_sprintDrainMinimumMultiplier.Value), num4); } } internal sealed class SecondChanceShopUpgrade : ShopUpgrade { private readonly Dictionary<string, float> _cooldownEnds = new Dictionary<string, float>(); private readonly Dictionary<string, float> _protectionEnds = new Dictionary<string, float>(); internal const string StatsDictionaryKey = "playerUpgradeSecondChance"; private readonly ConfigEntry<float> _invulnerabilitySecondsPerLevel; private readonly ConfigEntry<int> _invulnerabilityMaxScalingLevel; private readonly ConfigEntry<float> _cooldownBase; private readonly ConfigEntry<int> _cooldownReductionStartLevel; private readonly ConfigEntry<int> _cooldownFastReductionMaxLevel; private readonly ConfigEntry<float> _cooldownReductionPerLevel; private readonly ConfigEntry<float> _cooldownReductionPerExtraLevel; private readonly ConfigEntry<float> _cooldownMin; protected override string UpgradeId => "SecondChance"; internal SecondChanceShopUpgrade(ConfigFile config, AssetBundle bundle) : base(config, bundle, "Second Chance", "assets/extrabattleupgrades/items/item upgrade player second chance.prefab", 1f) { _invulnerabilitySecondsPerLevel = config.Bind<float>("Second Chance Upgrade", "Invulnerability Seconds Per Level", 1f, "Invulnerability duration gained per level before the cap. 1 = 1 second."); _invulnerabilityMaxScalingLevel = config.Bind<int>("Second Chance Upgrade", "Invulnerability Max Scaling Level", 5, "Level where invulnerability duration stops increasing."); _cooldownBase = config.Bind<float>("Second Chance Upgrade", "Cooldown Base", 120f, "Base Second Chance cooldown, in seconds."); _cooldownReductionStartLevel = config.Bind<int>("Second Chance Upgrade", "Cooldown Reduction Start Level", 6, "Level where cooldown reduction starts."); _cooldownFastReductionMaxLevel = config.Bind<int>("Second Chance Upgrade", "Cooldown Fast Reduction Max Level", 10, "Last level that uses the main cooldown reduction value."); _cooldownReductionPerLevel = config.Bind<float>("Second Chance Upgrade", "Cooldown Reduction Per Level", 5f, "Cooldown reduction per level during the main reduction range, in seconds."); _cooldownReductionPerExtraLevel = config.Bind<float>("Second Chance Upgrade", "Cooldown Reduction Per Extra Level", 0.5f, "Cooldown reduction per level after the fast reduction range, in seconds."); _cooldownMin = config.Bind<float>("Second Chance Upgrade", "Cooldown Minimum", 30f, "Minimum Second Chance cooldown, in seconds."); } internal bool TryActivate(PlayerAvatar player, out float invulnerabilitySeconds) { invulnerabilitySeconds = 0f; int level = GetLevel(player); if (level <= 0) { return false; } string text = PlayerId(player); if (string.IsNullOrWhiteSpace(text)) { return false; } float time = Time.time; if (_cooldownEnds.TryGetValue(text, out var value) && value > time) { return false; } invulnerabilitySeconds = InvulnerabilitySeconds(level); _protectionEnds[text] = time + invulnerabilitySeconds; _cooldownEnds[text] = time + CooldownSeconds(level); return true; } internal bool TryRescueFromPit(PlayerAvatar player, out float invulnerabilitySeconds, out bool activatedNow) { activatedNow = false; invulnerabilitySeconds = RemainingProtectionSeconds(player); if (invulnerabilitySeconds > 0f) { return true; } activatedNow = TryActivate(player, out invulnerabilitySeconds); return activatedNow; } internal float RemainingProtectionSeconds(PlayerAvatar player) { string text = PlayerId(player); if (string.IsNullOrWhiteSpace(text) || !_protectionEnds.TryGetValue(text, out var value)) { return 0f; } return Math.Max(0f, value - Time.time); } internal float RemainingCooldownSeconds(PlayerAvatar player) { string text = PlayerId(player); if (string.IsNullOrWhiteSpace(text) || !_cooldownEnds.TryGetValue(text, out var value)) { return 0f; } return Math.Max(0f, value - Time.time); } internal bool IsReady(PlayerAvatar player) { if ((Object)(object)player != (Object)null && base.Enabled.Value && base.RegisteredUpgrade != null && GetLevel(player) > 0) { return RemainingCooldownSeconds(player) <= 0f; } return false; } internal bool HasUpgrade(PlayerAvatar player) { if ((Object)(object)player != (Object)null && base.Enabled.Value && base.RegisteredUpgrade != null) { return GetLevel(player) > 0; } return false; } internal void ResetState() { _cooldownEnds.Clear(); _protectionEnds.Clear(); } private float InvulnerabilitySeconds(int level) { int val = Math.Max(1, _invulnerabilityMaxScalingLevel.Value); int num = Math.Min(level, val); return Math.Max(0f, (float)num * _invulnerabilitySecondsPerLevel.Value); } private float CooldownSeconds(int level) { float num = Math.Max(0f, _cooldownBase.Value); float val = Math.Max(0f, _cooldownMin.Value); int num2 = Math.Max(1, _cooldownReductionStartLevel.Value); int num3 = Math.Max(num2, _cooldownFastReductionMaxLevel.Value); float num4 = 0f; if (level >= num2) { int val2 = Math.Min(level, num3) - num2 + 1; num4 += (float)Math.Max(0, val2) * Math.Max(0f, _cooldownReductionPerLevel.Value); } if (level > num3) { int num5 = level - num3; num4 += (float)num5 * Math.Max(0f, _cooldownReductionPerExtraLevel.Value); } return Math.Max(val, num - num4); } private static string PlayerId(PlayerAvatar player) { if ((Object)(object)player == (Object)null) { return string.Empty; } string text = SemiFunc.PlayerGetSteamID(player); if (!string.IsNullOrWhiteSpace(text)) { return text; } return ((Object)player).GetInstanceID().ToString(); } } internal sealed class ShockGripShopUpgrade : ShopUpgrade { internal const string StatsDictionaryKey = "playerUpgradeShockGrip"; private readonly ConfigEntry<int> _damagePerLevelFirstTen; private readonly ConfigEntry<int> _damagePerLevelAfterTen; protected override string UpgradeId => "ShockGrip"; internal ShockGripShopUpgrade(ConfigFile config, AssetBundle bundle) : base(config, bundle, "Shock Grip", "assets/extrabattleupgrades/items/item upgrade player shock grip.prefab", 1f) { _damagePerLevelFirstTen = config.Bind<int>("Shock Grip Upgrade", "Damage Per Level First Ten", 2, "Damage per second gained per Shock Grip level from level 1 to 10."); _damagePerLevelAfterTen = config.Bind<int>("Shock Grip Upgrade", "Damage Per Level After Ten", 1, "Damage per second gained per Shock Grip level after level 10."); } internal int DamagePerSecond(PlayerAvatar player) { int level = GetLevel(player); if (level <= 0) { return 0; } int num = Math.Min(level, 10); int num2 = Math.Max(0, level - 10); return num * Math.Max(0, _damagePerLevelFirstTen.Value) + num2 * Math.Max(0, _damagePerLevelAfterTen.Value); } } internal abstract class ShopUpgrade { private readonly AssetBundle _bundle; private readonly string _prefabPath; private readonly string _label; private readonly float _defaultPriceMultiplier; internal ConfigEntry<bool> Enabled { get; } internal ConfigEntry<float> PriceMultiplier { get; } internal PlayerUpgrade RegisteredUpgrade { get; private set; } protected abstract string UpgradeId { get; } protected ShopUpgrade(ConfigFile config, AssetBundle bundle, string label, string prefabPath, float defaultPriceMultiplier) { _bundle = bundle; _prefabPath = prefabPath; _label = label; _defaultPriceMultiplier = defaultPriceMultiplier; string text = _label + " Upgrade"; Enabled = config.Bind<bool>(text, "Enabled", true, "Enable the " + _label + " upgrade."); PriceMultiplier = config.Bind<float>(text, "Price Multiplier", _defaultPriceMultiplier, "Multiplier applied to the base shop price."); } internal void Register() { if (!Enabled.Value) { ExtraBattleUpgradesPlugin.Log.LogInfo((object)(_label + " upgrade disabled by config.")); return; } GameObject val = _bundle.LoadAsset<GameObject>(_prefabPath); ItemAttributes val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemAttributes>() : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val2.item == (Object)null) { ExtraBattleUpgradesPlugin.Log.LogError((object)("Could not load " + _label + " upgrade prefab '" + _prefabPath + "'.")); return; } Item item = val2.item; LogPrefabDiagnostics(val, val2, item, null, "before runtime item"); Item val3 = (val2.item = CreateRuntimeItem(item)); ((Object)val).name = ((Object)val3).name; LogPrefabDiagnostics(val, val2, item, val3, "after runtime item"); if (SetRuntimeUpgradeId(val)) { EnsureStatsLabel(); Items.RegisterItem(val2); ExtraBattleUpgradesPlugin.Diagnostic("Register " + _label + ": Items.RegisterItem done. itemName=" + ((Object)val3).name + ", displayName=" + val3.itemName + ", upgradeId=" + UpgradeId + "."); RegisteredUpgrade = Upgrades.RegisterUpgrade(UpgradeId, val3, (Action<PlayerAvatar, int>)OnRunStart, (Action<PlayerAvatar, int>)OnUpgradeBought); if (RegisteredUpgrade == null) { ExtraBattleUpgradesPlugin.Log.LogError((object)("Failed to register " + _label + " upgrade with REPOLib.")); return; } ExtraBattleUpgradesPlugin.Log.LogInfo((object)("Registered " + _label + " upgrade.")); ExtraBattleUpgradesPlugin.LogUpgradeDictionaryState("Register " + _label + " POST", RegisteredUpgrade, null); } } internal int GetLevel(PlayerAvatar player) { if (!((Object)(object)player == (Object)null)) { PlayerUpgrade registeredUpgrade = RegisteredUpgrade; if (registeredUpgrade == null) { return 0; } return registeredUpgrade.GetLevel(player); } return 0; } protected virtual void OnRunStart(PlayerAvatar player, int level) { string text = (((Object)(object)player != (Object)null) ? SemiFunc.PlayerGetSteamID(player) : null); ExtraBattleUpgradesPlugin.Diagnostic(string.Format("OnRunStart {0}: player={1}, steamId={2}, level={3}.", _label, PlayerName(player), text ?? "<none>", level)); ExtraBattleUpgradesPlugin.LogUpgradeDictionaryState("OnRunStart " + _label + " PRE SyncStatsLevel", RegisteredUpgrade, text); SyncStatsLevel(player, level); ExtraBattleUpgradesPlugin.LogUpgradeDictionaryState("OnRunStart " + _label + " POST SyncStatsLevel", RegisteredUpgrade, text); if ((Object)(object)player != (Object)null && player == SemiFunc.PlayerAvatarLocal()) { ExtraBattleUpgradesPlugin.Diagnostic($"Initialized {_label} level {level} for {SemiFunc.PlayerGetName(player)}."); } } protected virtual void OnUpgradeBought(PlayerAvatar player, int level) { string text = (((Object)(object)player != (Object)null) ? SemiFunc.PlayerGetSteamID(player) : null); ExtraBattleUpgradesPlugin.Diagnostic(string.Format("OnUpgradeBought {0}: player={1}, steamId={2}, level={3}.", _label, PlayerName(player), text ?? "<none>", level)); ExtraBattleUpgradesPlugin.LogUpgradeDictionaryState("OnUpgradeBought " + _label + " PRE SyncStatsLevel", RegisteredUpgrade, text); SyncStatsLevel(player, level); ExtraBattleUpgradesPlugin.LogUpgradeDictionaryState("OnUpgradeBought " + _label + " POST SyncStatsLevel", RegisteredUpgrade, text); if ((Object)(object)player != (Object)null && player == SemiFunc.PlayerAvatarLocal()) { StatsUI instance = StatsUI.instance; if (instance != null) { instance.ResetPlayerUpgradeNames(); } ExtraBattleUpgradesPlugin.Diagnostic($"Applied {_label} level {level} for {SemiFunc.PlayerGetName(player)}."); } } private static Value MakePriceRange(Value source, float multiplier) { Value val = ScriptableObject.CreateInstance<Value>(); if ((Object)(object)source == (Object)null) { val.valueMin = 100f * multiplier; val.valueMax = 200f * multiplier; return val; } val.valueMin = source.valueMin * multiplier; val.valueMax = source.valueMax * multiplier; return val; } private Item CreateRuntimeItem(Item source) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) Item obj = ScriptableObject.CreateInstance<Item>(); ((Object)obj).name = "Item Upgrade Player " + _label; obj.disabled = false; obj.itemName = _label + " Upgrade"; obj.itemNameLocalized = null; obj.description = source.description; obj.itemType = (itemType)3; obj.emojiIcon = source.emojiIcon; obj.itemVolume = source.itemVolume; obj.itemSecretShopType = source.itemSecretShopType; obj.colorPreset = source.colorPreset; obj.value = MakePriceRange(source.value, PriceMultiplier.Value); obj.maxAmount = ((source.maxAmount > 0) ? source.maxAmount : 10); obj.maxAmountInShop = ((source.maxAmountInShop > 0) ? source.maxAmountInShop : 2); obj.minPlayerCount = ((source.minPlayerCount <= 0) ? 1 : source.minPlayerCount); obj.maxPurchase = source.maxPurchase; obj.maxPurchaseAmount = source.maxPurchaseAmount; obj.spawnRotationOffset = source.spawnRotationOffset; obj.physicalItem = source.physicalItem; return obj; } private void LogPrefabDiagnostics(GameObject prefab, ItemAttributes itemAttributes, Item sourceItem, Item runtimeItem, string stage) { //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) ExtraBattleUpgradesPlugin.Diagnostic("Register " + _label + " " + stage + ": prefab=" + (((Object)(object)prefab != (Object)null) ? ((Object)prefab).name : "<null>") + ", path=" + _prefabPath + ", " + $"hasItemAttributes={(Object)(object)itemAttributes != (Object)null}, hasItem={(Object)(object)itemAttributes?.item != (Object)null}, " + $"hasREPOLibItemUpgrade={(Object)(object)((prefab != null) ? prefab.GetComponent<REPOLibItemUpgrade>() : null) != (Object)null}, " + $"hasItemUpgrade={(Object)(object)((prefab != null) ? prefab.GetComponent<ItemUpgrade>() : null) != (Object)null}, hasItemToggle={(Object)(object)((prefab != null) ? prefab.GetComponent<ItemToggle>() : null) != (Object)null}, " + $"hasPhotonView={(Object)(object)((prefab != null) ? prefab.GetComponent<PhotonView>() : null) != (Object)null}, hasPhysGrabObject={(Object)(object)((prefab != null) ? prefab.GetComponent<PhysGrabObject>() : null) != (Object)null}"); if ((Object)(object)sourceItem != (Object)null) { ExtraBattleUpgradesPlugin.Diagnostic("Register " + _label + " " + stage + " SOURCE Item: name=" + ((Object)sourceItem).name + ", itemName=" + sourceItem.itemName + ", " + $"type={sourceItem.itemType}, volume={sourceItem.itemVolume}, physicalItem={sourceItem.physicalItem}, " + $"maxAmount={sourceItem.maxAmount}, maxAmountInShop={sourceItem.maxAmountInShop}, " + $"maxPurchase={sourceItem.maxPurchase}, maxPurchaseAmount={sourceItem.maxPurchaseAmount}, " + "valueMin=" + (((Object)(object)sourceItem.value != (Object)null) ? sourceItem.value.valueMin.ToString() : "<null>") + ", valueMax=" + (((Object)(object)sourceItem.value != (Object)null) ? sourceItem.value.valueMax.ToString() : "<null>")); } if ((Object)(object)runtimeItem != (Object)null) { ExtraBattleUpgradesPlugin.Diagnostic("Register " + _label + " " + stage + " RUNTIME Item: name=" + ((Object)runtimeItem).name + ", itemName=" + runtimeItem.itemName + ", " + $"type={runtimeItem.itemType}, volume={runtimeItem.itemVolume}, physicalItem={runtimeItem.physicalItem}, " + $"maxAmount={runtimeItem.maxAmount}, maxAmountInShop={runtimeItem.maxAmountInShop}, " + $"maxPurchase={runtimeItem.maxPurchase}, maxPurchaseAmount={runtimeItem.maxPurchaseAmount}, " + "valueMin=" + (((Object)(object)runtimeItem.value != (Object)null) ? runtimeItem.value.valueMin.ToString() : "<null>") + ", valueMax=" + (((Object)(object)runtimeItem.value != (Object)null) ? runtimeItem.value.valueMax.ToString() : "<null>")); } } private bool SetRuntimeUpgradeId(GameObject prefab) { REPOLibItemUpgrade component = prefab.GetComponent<REPOLibItemUpgrade>(); if ((Object)(object)component == (Object)null) { ExtraBattleUpgradesPlugin.Log.LogError((object)("Could not configure " + _label + " upgrade id.")); return false; } FieldInfo field = typeof(REPOLibItemUpgrade).GetField("_upgradeId", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { ExtraBattleUpgradesPlugin.Log.LogError((object)("Could not find REPOLib upgrade id field for " + _label + ".")); return false; } field.SetValue(component, UpgradeId); ExtraBattleUpgradesPlugin.Diagnostic("SetRuntimeUpgradeId " + _label + ": _upgradeId set to " + UpgradeId + "."); return true; } private void EnsureStatsLabel() { //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_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown StatsManager instance = StatsManager.instance; if ((Object)(object)instance == (Object)null) { ExtraBattleUpgradesPlugin.Diagnostic("EnsureStatsLabel " + _label + ": StatsManager.instance is null."); return; } string text = "playerUpgrade" + UpgradeId; if (instance.upgradesInfo.ContainsKey(text)) { ExtraBattleUpgradesPlugin.Diagnostic("EnsureStatsLabel " + _label + ": update existing " + text + "."); instance.upgradesInfo[text].displayName = _label; instance.upgradesInfo[text].displayNameLocalized = null; } else { ExtraBattleUpgradesPlugin.Diagnostic("EnsureStatsLabel " + _label + ": add missing " + text + "."); instance.upgradesInfo.Add(text, new UpgradeInfo { displayName = _label, displayNameLocalized = null }); } } private void SyncStatsLevel(PlayerAvatar player, int level) { if ((Object)(object)player == (Object)null || (Object)(object)StatsManager.instance == (Object)null) { ExtraBattleUpgradesPlugin.Diagnostic($"SyncStatsLevel {_label}: skipped. playerNull={(Object)(object)player == (Object)null}, statsManagerNull={(Object)(object)StatsManager.instance == (Object)null}, level={level}."); return; } string text = SemiFunc.PlayerGetSteamID(player); if (string.IsNullOrWhiteSpace(text)) { ExtraBattleUpgradesPlugin.Diagnostic($"SyncStatsLevel {_label}: skipped because steamId is empty. player={PlayerName(player)}, level={level}."); return; } string text2 = "playerUpgrade" + UpgradeId; ExtraBattleUpgradesPlugin.EnsureUpgradeDictionaryLinked(RegisteredUpgrade, "SyncStatsLevel " + _label + " link", text, level); ExtraBattleUpgradesPlugin.Diagnostic($"SyncStatsLevel {_label}: DictionaryUpdateValue({text2}, {text}, {level})."); StatsManager.instance.DictionaryUpdateValue(text2, text, level); } private static string PlayerName(PlayerAvatar player) { if ((Object)(object)player == (Object)null) { return "<null>"; } return SemiFunc.PlayerGetName(player); } } } namespace ExtraBattleUpgrades.Patches { [HarmonyPatch(typeof(PlayerHealth), "Hurt")] internal static class ArmorDamagePatch { private static void Prefix(ref int damage, PlayerAvatar ___playerAvatar) { ApplyProtection(ref damage, ___playerAvatar); } private static void ApplyProtection(ref int damage, PlayerAvatar player) { if (damage > 0 && !((Object)(object)player == (Object)null) && ExtraBattleUpgradesPlugin.Armor != null && ExtraBattleUpgradesPlugin.Armor.Enabled.Value && ExtraBattleUpgradesPlugin.Armor.RegisteredUpgrade != null) { damage = ExtraBattleUpgradesPlugin.Armor.ReduceDamage(damage, player); } } } [HarmonyPatch] internal static class BattleUpgradeStatusUIPatch { private static readonly Color PanicActiveColor = new Color(0.1f, 0.85f, 1f, 1f); private static readonly Color PanicReadyColor = new Color(1f, 0.25f, 0.75f, 1f); private static readonly Color SecondChanceActiveColor = new Color(0.1f, 0.85f, 1f, 1f); private static readonly Color SecondChanceReadyColor = new Color(1f, 0.86f, 0.05f, 1f); private static readonly Color CooldownColor = new Color(0.45f, 0.45f, 0.45f, 1f); private static readonly FieldRef<EnergyUI, TextMeshProUGUI> EnergyTextRef = AccessTools.FieldRefAccess<EnergyUI, TextMeshProUGUI>("Text"); private static readonly FieldRef<HealthUI, TextMeshProUGUI> HealthTextRef = AccessTools.FieldRefAccess<HealthUI, TextMeshProUGUI>("Text"); private static Image _panicIcon; private static Image _secondChanceIcon; private static Color? _energyDefaultColor; private static Color? _healthDefaultColor; [HarmonyPatch(typeof(EnergyUI), "Update")] [HarmonyPostfix] private static void EnergyUIPostfix(EnergyUI __instance) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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) PlayerAvatar val = PlayerController.instance?.playerAvatarScript; if ((Object)(object)val == (Object)null) { return; } TextMeshProUGUI val2 = EnergyTextRef.Invoke(__instance); if ((Object)(object)val2 == (Object)null) { return; } Color valueOrDefault = _energyDefaultColor.GetValueOrDefault(); if (!_energyDefaultColor.HasValue) { valueOrDefault = ((Graphic)val2).color; _energyDefaultColor = valueOrDefault; } EnsurePanicIcon(((Component)__instance).transform, val2); bool flag = PanicResponsePatch.HasUpgrade(val); bool active = ExtraBattleUpgradesPlugin.HudConfig.PanicIconEnabled.Value && flag; ((Component)_panicIcon).gameObject.SetActive(active); if (flag) { if (PanicResponsePatch.IsActive(val)) { SetTextColor(val2, PanicActiveColor); } else { SetTextColor(val2, _energyDefaultColor.Value); } ((Graphic)_panicIcon).color = (PanicResponsePatch.IsReady(val) ? PanicReadyColor : CooldownColor); } } [HarmonyPatch(typeof(HealthUI), "Update")] [HarmonyPostfix] private static void HealthUIPostfix(HealthUI __instance) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar val = PlayerController.instance?.playerAvatarScript; if ((Object)(object)val == (Object)null) { return; } TextMeshProUGUI val2 = HealthTextRef.Invoke(__instance); if ((Object)(object)val2 == (Object)null) { return; } Color valueOrDefault = _healthDefaultColor.GetValueOrDefault(); if (!_healthDefaultColor.HasValue) { valueOrDefault = ((Graphic)val2).color; _healthDefaultColor = valueOrDefault; } EnsureSecondChanceIcon(((Component)__instance).transform, val2); SecondChanceShopUpgrade secondChance = ExtraBattleUpgradesPlugin.SecondChance; bool flag = secondChance?.HasUpgrade(val) ?? false; bool active = ExtraBattleUpgradesPlugin.HudConfig.SecondChanceIconEnabled.Value && flag; ((Component)_secondChanceIcon).gameObject.SetActive(active); if (flag) { if (secondChance.RemainingProtectionSeconds(val) > 0f) { SetTextColor(val2, SecondChanceActiveColor); } else { SetTextColor(val2, _healthDefaultColor.Value); } ((Graphic)_secondChanceIcon).color = (secondChance.IsReady(val) ? SecondChanceReadyColor : CooldownColor); } } private static void EnsurePanicIcon(Transform parent, TextMeshProUGUI sourceText) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_panicIcon != (Object)null)) { BattleUpgradeHudConfig hudConfig = ExtraBattleUpgradesPlugin.HudConfig; _panicIcon = CreateIcon(((TMP_Text)sourceText).transform, BattleUpgradeIconPainter.LightningSprite(), "Panic Response Icon", new Vector3(hudConfig.PanicIconX.Value, hudConfig.PanicIconY.Value, 0f), new Vector2(hudConfig.PanicIconSize.Value, hudConfig.PanicIconSize.Value)); } } private static void EnsureSecondChanceIcon(Transform parent, TextMeshProUGUI sourceText) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_secondChanceIcon != (Object)null)) { BattleUpgradeHudConfig hudConfig = ExtraBattleUpgradesPlugin.HudConfig; _secondChanceIcon = CreateIcon(((TMP_Text)sourceText).transform, BattleUpgradeIconPainter.HeartSprite(), "Second Chance Icon", new Vector3(hudConfig.SecondChanceIconX.Value, hudConfig.SecondChanceIconY.Value, 0f), new Vector2(hudConfig.SecondChanceIconSize.Value, hudConfig.SecondChanceIconSize.Value)); } } private static Image CreateIcon(Transform parent, Sprite sprite, string objectName, Vector3 localOffset, Vector2 size) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_007a: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(objectName, new Type[1] { typeof(RectTransform) }); Type type = Type.GetType("UnityEngine.CanvasRenderer, UnityEngine.CoreModule"); if (type != null) { val.AddComponent(type); } val.transform.SetParent(parent, false); val.transform.localPosition = localOffset; val.transform.localScale = Vector3.one; val.GetComponent<RectTransform>().sizeDelta = size; Image obj = val.AddComponent<Image>(); obj.sprite = sprite; ((Graphic)obj).color = CooldownColor; ((Graphic)obj).raycastTarget = false; obj.preserveAspect = true; return obj; } private static void SetTextColor(TextMeshProUGUI text, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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) ((Graphic)text).color = color; ((TMP_Text)text).fontMaterial.SetColor(ShaderUtilities.ID_FaceColor, color); ((TMP_Text)text).fontMaterial.SetColor(ShaderUtilities.ID_GlowColor, color); } } [HarmonyPatch(typeof(EnemyHealth), "Hurt")] internal static class EnergyLeechDamagePatch { private readonly struct DamageSnapshot { internal readonly int HealthBefore; internal readonly PlayerAvatar[] Owners; internal DamageSnapshot(int healthBefore, PlayerAvatar[] owners) { HealthBefore = healthBefore; Owners = owners; } } private static void Prefix(int ___healthCurrent, out DamageSnapshot __state) { __state = new DamageSnapshot(___healthCurrent, CombatDamageTracker.CurrentOwners); } private static void Postfix(int ___healthCurrent, DamageSnapshot __state) { CombatDamageTracker.ApplyEnergyLeech(__state.HealthBefore - ___healthCurrent, __state.Owners); } } [HarmonyPatch(typeof(HurtCollider), "EnemyHurt")] internal static class EnergyLeechHurtColliderPatch { private static void Prefix(HurtCollider __instance, PlayerAvatar ___playerCausingHurt, PlayerAvatar ___playerCausingHurtOverride, PhysGrabObject ___parentPhysGrabObject) { if (__instance.deathPit) { CombatDamageTracker.Push(null); } else if ((Object)(object)___playerCausingHurtOverride != (Object)null) { CombatDamageTracker.Push(___playerCausingHurtOverride); } else if ((Object)(object)___parentPhysGrabObject != (Object)null) { CombatDamageTracker.PushFromPhysGrabObject(___parentPhysGrabObject); } else { CombatDamageTracker.Push(___playerCausingHurt); } } private static void Finalizer() { CombatDamageTracker.Pop(); } } [HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "OnCollisionStay")] internal static class EnergyLeechHeldObjectImpactPatch { private static void Prefix(PhysGrabObject ___physGrabObject) { CombatDamageTracker.PushFromPhysGrabObject(___physGrabObject); } private static void Finalizer() { CombatDamageTracker.Pop(); } } [HarmonyPatch(typeof(PhysGrabber))] internal static class OverchargeGrabPatch { private static readonly FieldRef<PhysGrabber, PlayerAvatar> OwnerRef = AccessTools.FieldRefAccess<PhysGrabber, PlayerAvatar>("playerAvatar"); private static readonly FieldRef<PhysGrabber, float> OverchargeFloatRef = AccessTools.FieldRefAccess<PhysGrabber, float>("physGrabBeamOverChargeFloat"); private static readonly FieldRef<PhysGrabber, byte> OverchargeByteRef = AccessTools.FieldRefAccess<PhysGrabber, byte>("physGrabBeamOverCharge"); private static readonly FieldRef<PhysGrabber, float> OverchargeAmountRef = AccessTools.FieldRefAccess<PhysGrabber, float>("physGrabBeamOverChargeAmount"); [HarmonyPatch("PhysGrabOverCharge")] [HarmonyPostfix] private static void ReduceFinalOverchargeGain(PhysGrabber __instance, float __state) { if (TryGetChargeUpgrade(out var player, __instance)) { float value = OverchargeAmountRef.Invoke(__instance); float num = ExtraBattleUpgradesPlugin.Overcharge.SlowOvercharge(value, player); OverchargeAmountRef.Invoke(__instance) = num; float num2 = OverchargeFloatRef.Invoke(__instance); if (!(num2 <= __state)) { float value2 = num2 - __state; float num3 = ExtraBattleUpgradesPlugin.Overcharge.SlowOvercharge(value2, player); OverchargeFloatRef.Invoke(__instance) = Mathf.Clamp01(__state + num3); OverchargeByteRef.Invoke(__instance) = (byte)(OverchargeFloatRef.Invoke(__instance) * 200f); } } } [HarmonyPatch("PhysGrabOverCharge")] [HarmonyPrefix] private static void RememberOverchargeBeforeGain(PhysGrabber __instance, out float __state) { __state = OverchargeFloatRef.Invoke(__instance); } [HarmonyPatch("PhysGrabOverChargeLogic")] [HarmonyPrefix] private static void RememberChargeBeforeTick(float ___physGrabBeamOverChargeFloat, out float __state) { __state = ___physGrabBeamOverChargeFloat; } [HarmonyPatch("PhysGrabOverChargeLogic")] [HarmonyPostfix] private static void ImproveChargeRecovery(PhysGrabber __instance, float __state, ref float ___physGrabBeamOverChargeFloat, ref byte ___physGrabBeamOverCharge) { if (!(__state <= 0f) && !(__state <= ___physGrabBeamOverChargeFloat) && TryGetChargeUpgrade(out var player, __instance)) { float num = ExtraBattleUpgradesPlugin.Overcharge.RecoveryBasePerSecond() * Time.deltaTime; float num2 = ExtraBattleUpgradesPlugin.Overcharge.SlowOvercharge(num, player); float num3 = Math.Max(0f, num - num2); if (!(num3 <= 0f)) { ___physGrabBeamOverChargeFloat = Math.Max(0f, ___physGrabBeamOverChargeFloat - num3); ___physGrabBeamOverCharge = (byte)(___physGrabBeamOverChargeFloat * 200f); } } } private static bool TryGetChargeUpgrade(out PlayerAvatar player, PhysGrabber grabber) { player = OwnerRef.Invoke(grabber); if ((Object)(object)player != (Object)null && ExtraBattleUpgradesPlugin.Overcharge != null && ExtraBattleUpgradesPlugin.Overcharge.Enabled.Value) { return ExtraBattleUpgradesPlugin.Overcharge.RegisteredUpgrade != null; } return false; } } [HarmonyPatch(typeof(EnemyRigidbody), "FixedUpdate")] internal static class OverchargeHoldPatch { private static readonly FieldRef<EnemyRigidbody, PhysGrabObject> EnemyGrabObjectRef = AccessTools.FieldRefAccess<EnemyRigidbody, PhysGrabObject>("physGrabObject"); private static readonly FieldRef<EnemyRigidbody, float> GrabStrengthTimerRef = AccessTools.FieldRefAccess<EnemyRigidbody, float>("grabStrengthTimer"); private static readonly FieldRef<EnemyRigidbody, float> GrabTimeCurrentRef = AccessTools.FieldRefAccess<EnemyRigidbody, float>("grabTimeCurrent"); private static void Prefix(EnemyRigidbody __instance, ref float ___grabStrengthTimer) { PhysGrabObject val = EnemyGrabObjectRef.Invoke(__instance); if ((Object)(object)val == (Object)null || val.playerGrabbing == null || val.playerGrabbing.Count <= 0) { return; } float num = 0f; foreach (PhysGrabber item in val.playerGrabbing) { PlayerAvatar val2 = item?.playerAvatar; if (!((Object)(object)val2 == (Object)null)) { float num2 = ExtraBattleUpgradesPlugin.Overcharge.HoldStabilityBonus(val2); if (num2 > num) { num = num2; } } } if (!(num <= 0f)) { float num3 = GrabTimeCurrentRef.Invoke(__instance); GrabTimeCurrentRef.Invoke(__instance) = Mathf.Max(0f, num3 - Time.fixedDeltaTime * num); if (GrabStrengthTimerRef.Invoke(__instance) > 0f) { ___grabStrengthTimer += Time.fixedDeltaTime * num; } } } } [HarmonyPatch(typeof(PlayerHealth), "Hurt")] internal static class PanicResponsePatch { private readonly struct HurtState { internal readonly int HealthBefore; internal HurtState(int healthBefore) { HealthBefore = healthBefore; } } private static readonly Dictionary<string, float> BuffEnds = new Dictionary<string, float>(); private static readonly Dictionary<string, float> CooldownEnds = new Dictionary<string, float>(); private static void Prefix(int ___health, out HurtState __state) { __state = new HurtState(___health); } private static void Postfix(PlayerAvatar ___playerAvatar, int ___health, HurtState __state) { if (!CanActivate(___playerAvatar, __state.HealthBefore, ___health)) { return; } PanicResponseShopUpgrade panicResponse = ExtraBattleUpgradesPlugin.PanicResponse; if (panicResponse == null) { return; } string key = PlayerId(___playerAvatar); float time = Time.time; if (!CooldownEnds.TryGetValue(key, out var value) || !(value > time)) { float num = panicResponse.DurationSeconds(___playerAvatar); float num2 = panicResponse.CooldownSeconds(___playerAvatar); float num3 = panicResponse.SpeedMultiplier(___playerAvatar); if (!(num <= 0f)) { BuffEnds[key] = time + num; CooldownEnds[key] = time + num2; PlayerController.instance.OverrideSpeed(num3, num); } } } internal static bool IsActive(PlayerAvatar player) { if ((Object)(object)player == (Object)null) { return false; } if (BuffEnds.TryGetValue(PlayerId(player), out var value)) { return value > Time.time; } return false; } private static bool CanActivate(PlayerAvatar player, int healthBefore, int healthAfter) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Invalid comparison between Unknown and I4 if ((Object)(object)player == (Object)null || healthBefore <= 0) { return false; } if (healthAfter >= healthBefore) { return false; } if (GameManager.Multiplayer() && ((Object)(object)player.photonView == (Object)null || !player.photonView.IsMine)) { return false; } if ((Object)(object)GameDirector.instance == (Object)null || (int)GameDirector.instance.currentState != 2) { return false; } PanicResponseShopUpgrade panicResponse = ExtraBattleUpgradesPlugin.PanicResponse; if (panicResponse != null && panicResponse.Enabled.Value && panicResponse.RegisteredUpgrade != null) { return panicResponse.GetLevel(player) > 0; } return false; } private static string PlayerId(PlayerAvatar player) { string text = SemiFunc.PlayerGetSteamID(player); if (!string.IsNullOrWhiteSpace(text)) { return text; } return ((Object)player).GetInstanceID().ToString(); } internal static float RemainingCooldownSeconds(PlayerAvatar player) { if ((Object)(object)player == (Object)null) { return 0f; } string key = PlayerId(player); if (!CooldownEnds.TryGetValue(key, out var value)) { return 0f; } return Mathf.Max(0f, value - Time.time); } internal static bool IsReady(PlayerAvatar player) { PanicResponseShopUpgrade panicResponse = ExtraBattleUpgradesPlugin.PanicResponse; if ((Object)(object)player != (Object)null && panicResponse != null && panicResponse.Enabled.Value && panicResponse.RegisteredUpgrade != null && panicResponse.GetLevel(player) > 0) { return RemainingCooldownSeconds(player) <= 0f; } return false; } internal static bool HasUpgrade(PlayerAvatar player) { PanicResponseShopUpgrade panicResponse = ExtraBattleUpgradesPlugin.PanicResponse; if ((Object)(object)player != (Object)null && panicResponse != null && panicResponse.Enabled.Value && panicResponse.RegisteredUpgrade != null) { return panicResponse.GetLevel(player) > 0; } return false; } internal static void ResetState() { BuffEnds.Clear(); CooldownEnds.Clear(); } } [HarmonyPatch(typeof(PlayerController), "FixedUpdate")] internal static class PanicResponseEnergyPatch { private static void Prefix(PlayerAvatar ___playerAvatarScript) { if (!((Object)(object)___playerAvatarScript == (Object)null) && PanicResponsePatch.IsActive(___playerAvatarScript)) { PlayerController instance = PlayerController.instance; if (!((Object)(object)instance == (Object)null)) { instance.EnergyCurrent = instance.EnergyStart; } } } } [HarmonyPatch(typeof(PlayerController), "FixedUpdate")] internal static class PanicResponseSprintDrainPatch { private static void Prefix(PlayerController __instance, PlayerAvatar ___playerAvatarScript, out float __state) { __state = float.NaN; if ((Object)(object)__instance == (Object)null || (Object)(object)___playerAvatarScript == (Object)null || (GameManager.Multiplayer() && ((Object)(object)___playerAvatarScript.photonView == (Object)null || !___playerAvatarScript.photonView.IsMine))) { return; } PanicResponseShopUpgrade panicResponse = ExtraBattleUpgradesPlugin.PanicResponse; if (panicResponse != null && panicResponse.Enabled.Value && panicResponse.RegisteredUpgrade != null) { float num = panicResponse.SprintDrainMultiplier(___playerAvatarScript); if (!Mathf.Approximately(num, 1f)) { __state = __instance.EnergySprintDrain; __instance.EnergySprintDrain = __state * num; } } } private static void Postfix(PlayerController __instance, float __state) { if (!((Object)(object)__instance == (Object)null) && !float.IsNaN(__state)) { __instance.EnergySprintDrain = __state; } } } [HarmonyPatch(typeof(LevelGenerator), "GenerateDone")] internal static class RunStateResetPatch { private static void Postfix() { PanicResponsePatch.ResetState(); SecondChancePatch.ResetState(); ExtraBattleUpgradesPlugin.SecondChance?.ResetState(); } } [HarmonyPatch(typeof(PlayerHealth), "Hurt")] internal static class SecondChancePatch { private readonly struct RescueState { internal readonly bool Activated; internal readonly float InvulnerabilitySeconds; internal RescueState(bool activated, float invulnerabilitySeconds) { Activated = activated; InvulnerabilitySeconds = invulnerabilitySeconds; } } private static readonly FieldRef<PlayerAvatar, PlayerTumble> PlayerTumbleRef = AccessTools.FieldRefAccess<PlayerAvatar, PlayerTumble>("tumble"); private static readonly FieldRef<PlayerTumble, PhysGrabObject> TumbleBodyRef = AccessTools.FieldRefAccess<PlayerTumble, PhysGrabObject>("physGrabObject"); private static readonly FieldRef<PlayerHealth, int> HealthRef = AccessTools.FieldRefAccess<PlayerHealth, int>("health"); private static readonly FieldRef<PlayerHealth, int> MaxHealthRef = AccessTools.FieldRefAccess<PlayerHealth, int>("maxHealth"); private static readonly Dictionary<int, float> PitRescueTimes = new Dictionary<int, float>(); [HarmonyPriority(0)] private static void Prefix(ref int damage, bool savingGrace, float ___invincibleTimer, PlayerAvatar ___playerAvatar, int ___health, out RescueState __state) { __state = new RescueState(activated: false, 0f); if (CanTryRescue(damage, savingGrace, ___invincibleTimer, ___playerAvatar, ___health)) { SecondChanceShopUpgrade secondChance = ExtraBattleUpgradesPlugin.SecondChance; if (secondChance != null && secondChance.TryActivate(___playerAvatar, out var invulnerabilitySeconds)) { damage = Mathf.Max(0, ___health - 1); __state = new RescueState(activated: true, invulnerabilitySeconds); } } } private static void Postfix(PlayerHealth __instance, PlayerAvatar ___playerAvatar, ref int ___health, RescueState __state) { if (__state.Activated && !((Object)(object)___playerAvatar == (Object)null)) { if (___health <= 0) { ___health = 1; } ApplyProtectionFeel(___playerAvatar, __state.InvulnerabilitySeconds, launchUp: true); } } private static bool CanTryRescue(int damage, bool savingGrace, float invincibleTimer, PlayerAvatar player, int health) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 if (damage <= 0 || (Object)(object)player == (Object)null || health <= 0 || invincibleTimer > 0f) { return false; } if (GameManager.Multiplayer() && ((Object)(object)player.photonView == (Object)null || !player.photonView.IsMine)) { return false; } if ((Object)(object)GameDirector.instance == (Object)null || (int)GameDirector.instance.currentState != 2) { return false; } if (savingGrace && damage <= 25 && health > 5 && health <= 20) { return false; } if (health - damage > 0) { return false; } SecondChanceShopUpgrade secondChance = ExtraBattleUpgradesPlugin.SecondChance; if (secondChance != null && secondChance.Enabled.Value) { return secondChance.RegisteredUpgrade != null; } return false; } internal static bool TryRescueFromPit(PlayerAvatar player) { if (!CanTryPitRescue(player)) { return false; } SecondChanceShopUpgrade secondChance = ExtraBattleUpgradesPlugin.SecondChance; if (secondChance == null || !secondChance.TryRescueFromPit(player, out var invulnerabilitySeconds, out var activatedNow)) { return false; } ForceHealthToOne(player); ApplyProtectionFeel(player, invulnerabilitySeconds, launchUp: true); LaunchFromPit(player, activatedNow); return true; } private static bool CanTryPitRescue(PlayerAvatar player) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 if ((Object)(object)player == (Object)null || (Object)(object)player.playerHealth == (Object)null || (Object)(object)GameDirector.instance == (Object)null) { return false; } if ((int)GameDirector.instance.currentState != 2) { return false; } if (GameManager.Multiplayer() && ((Object)(object)player.photonView == (Object)null || !player.photonView.IsMine)) { return false; } SecondChanceShopUpgrade secondChance = ExtraBattleUpgradesPlugin.SecondChance; if (secondChance != null && secondChance.Enabled.Value) { return secondChance.RegisteredUpgrade != null; } return false; } private static void ForceHealthToOne(PlayerAvatar player) { PlayerHealth playerHealth = player.playerHealth; if (HealthRef.Invoke(playerHealth) != 1) { HealthRef.Invoke(playerHealth) = 1; StatsManager instance = StatsManager.instance; if (instance != null) { instance.SetPlayerHealth(SemiFunc.PlayerGetSteamID(player), 1, false); } } if (GameManager.Multiplayer() && (Object)(object)player.photonView != (Object)null) { player.photonView.RPC("UpdateHealthRPC", (RpcTarget)1, new object[4] { 1, MaxHealthRef.Invoke(playerHealth), true, false }); } } private static void ApplyProtectionFeel(PlayerAvatar player, float invulnerabilitySeconds, bool launchUp) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) PlayerHealth playerHealth = player.playerHealth; playerHealth.InvincibleSet(invulnerabilitySeconds); playerHealth.SetMaterialSpecial(new Color(1f, 0.86f, 0.05f, 1f)); playerHealth.EyeMaterialOverride((EyeOverrideState)4, invulnerabilitySeconds, 50); PlayerTumble val = PlayerTumbleRef.Invoke(player); if (!((Object)(object)val == (Object)null)) { val.TumbleRequest(true, false); val.TumbleOverrideTime(Mathf.Max(0.75f, invulnerabilitySeconds * 0.35f)); if (launchUp) { val.TumbleForce(Vector3.up * 8f); } } } private static void LaunchFromPit(PlayerAvatar player, bool activatedNow) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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_0135: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)player).GetInstanceID(); float time = Time.time; if (PitRescueTimes.TryGetValue(instanceID, out var value) && value > time) { return; } PitRescueTimes[instanceID] = time + 0.25f; PlayerTumble val = PlayerTumbleRef.Invoke(player); PhysGrabObject val2 = (((Object)(object)val != (Object)null) ? TumbleBodyRef.Invoke(val) : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.rb == (Object)null)) { val2.DeathPitEffectCreate(); Vector3 velocity = val2.rb.velocity; if (velocity.y < 0f) { velocity.y = 0f; val2.rb.velocity = velocity; } float num = (activatedNow ? 18f : 14f); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(Random.Range(-2f, 2f), 0f, Random.Range(-2f, 2f)); val2.rb.AddForce((Vector3.up * num + val3) * val2.rb.mass, (ForceMode)1); val2.rb.AddTorque(Random.insideUnitSphere * val2.rb.mass, (ForceMode)1); } } internal static void ResetState() { PitRescueTimes.Clear(); } } [HarmonyPatch(typeof(HurtCollider), "PlayerHurt")] internal static class SecondChanceDeathPitPatch { private static bool Prefix(HurtCollider __instance, PlayerAvatar _player) { if (__instance.deathPit) { return !SecondChancePatch.TryRescueFromPit(_player); } return true; } } [HarmonyPatch(typeof(PlayerHealth), "Update")] internal static class SecondChanceHealthColorPatch { private static readonly int AlbedoColor = Shader.PropertyToID("_AlbedoColor"); private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor"); private static readonly Color ProtectedHealthColor = new Color(1f, 0.86f, 0.05f, 1f); private static void Postfix(PlayerAvatar ___playerAvatar, Material ___healthMaterial) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) SecondChanceShopUpgrade secondChance = ExtraBattleUpgradesPlugin.SecondChance; if (secondChance != null && !((Object)(object)___playerAvatar == (Object)null) && !((Object)(object)___healthMaterial == (Object)null) && !(secondChance.RemainingProtectionSeconds(___playerAvatar) <= 0f)) { ___healthMaterial.SetColor(AlbedoColor, ProtectedHealthColor); Color protectedHealthColor = ProtectedHealthColor; if (___healthMaterial.HasProperty(EmissionColor)) { protectedHealthColor.a = ___healthMaterial.GetColor(EmissionColor).a; } ___healthMaterial.SetColor(EmissionColor, protectedHealthColor); } } } [HarmonyPatch(typeof(EnemyRigidbody), "FixedUpdate")] internal static class ShockGripPatch { private readonly struct ShockTarget { internal readonly int EnemyId; private readonly int _playerId; internal ShockTarget(int enemyId, int playerId) { EnemyId = enemyId; _playerId = playerId; } } private const float DamageTickSeconds = 0.5f; private static readonly Dictionary<ShockTarget, float> DamageTimers = new Dictionary<ShockTarget, float>(); private static readonly FieldRef<EnemyRigidbody, PhysGrabObject> EnemyGrabObjectRef = AccessTools.FieldRefAccess<EnemyRigidbody, PhysGrabObject>("physGrabObject"); private static readonly FieldRef<EnemyRigidbody, bool> EnemyGrabbedRef = AccessTools.FieldRefAccess<EnemyRigidbody, bool>("grabbed"); private static readonly FieldRef<EnemyRigidbody, float> GrabStrengthTimerRef = AccessTools.FieldRefAccess<EnemyRigidbody, float>("grabStrengthTimer"); private static readonly FieldRef<PhysGrabObject, PlayerAvatar> LastPlayerGrabbingRef = AccessTools.FieldRefAccess<PhysGrabObject, PlayerAvatar>("lastPlayerGrabbing"); private static readonly FieldRef<PhysGrabObject, float> GrabbedTimerRef = AccessTools.FieldRefAccess<PhysGrabObject, float>("grabbedTimer"); private static readonly FieldRef<EnemyGrounded, bool> GroundedRef = AccessTools.FieldRefAccess<EnemyGrounded, bool>("grounded"); private static void Postfix(EnemyRigidbody __instance) { if (!CanRunShockGrip()) { return; } Enemy enemy = __instance.enemy; PhysGrabObject grabObject = EnemyGrabObjectRef.Invoke(__instance); EnemyHealth health = (((Object)(object)enemy != (Object)null) ? ((Component)enemy).GetComponent<EnemyHealth>() : null); List<PlayerAvatar> holders = GetHolders(grabObject); if (!CanDamageEnemy(__instance, enemy, grabObject, health, holders)) { ClearEnemyTimers(((Object)__instance).GetInstanceID()); return; } foreach (PlayerAvatar item in holders) { int num = ExtraBattleUpgradesPlugin.ShockGrip.DamagePerSecond(item); if (num > 0) { TickDamage(((Object)__instance).GetInstanceID(), item, health, num); } } } private static List<PlayerAvatar> GetHolders(PhysGrabObject grabObject) { List<PlayerAvatar> list = new List<PlayerAvatar>(); if ((Object)(object)grabObject == (Object)null) { return list; } if (grabObject.playerGrabbing != null) { foreach (PhysGrabber item in grabObject.playerGrabbing) { AddHolder(list, item?.playerAvatar); } } if (list.Count == 0 && GrabbedTimerRef.Invoke(grabObject) > 0f) { AddHolder(list, LastPlayerGrabbingRef.Invoke(grabObject)); } return list; } private static void TickDamage(int enemyId, PlayerAvatar holder, EnemyHealth health, int damagePerSecond) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) ShockTarget key = new ShockTarget(enemyId, ((Object)holder).GetInstanceID()); DamageTimers.TryGetValue(key, out var value); value += Time.fixedDeltaTime; if (value < 0.5f) { DamageTimers[key] = value; return; } DamageTimers[key] = value - 0.5f; int num = Mathf.CeilToInt((float)damagePerSecond * 0.5f); CombatDamageTracker.Push(holder); try { health.Hurt(num, Vector3.up); ShockGripVisuals.PlayLocal(holder); if (GameManager.Multiplayer()) { ShockGripVisualRelay.Broadcast(holder); } } finally { CombatDamageTracker.Pop(); } } private static bool CanRunShockGrip() { if (SemiFunc.IsMasterClientOrSingleplayer() && ExtraBattleUpgradesPlugin.ShockGrip != null && ExtraBattleUpgradesPlugin.ShockGrip.Enabled.Value) { return ExtraBattleUpgradesPlugin.ShockGrip.RegisteredUpgrade != null; } return false; } private static bool CanDamageEnemy(EnemyRigidbody enemyBody, Enemy enemy, PhysGrabObject grabObject, EnemyHealth health, List<PlayerAvatar> holders) { if ((Object)(object)enemyBody == (Object)null || (Object)(object)enemy == (Object)null || (Object)(object)grabObject == (Object)null || (Object)(object)health == (Object)null || holders.Count == 0) { return false; } if (!enemy.IsStunned() && !EnemyGrabbedRef.Invoke(enemyBody) && GrabStrengthTimerRef.Invoke(enemyBody) <= 0f) { return false; } return IsAirborne(enemyBody, enemy, grabObject); } private static bool IsAirborne(EnemyRigidbody enemyBody, Enemy enemy, PhysGrabObject grabObject) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) EnemyGrounded componentInChildren = ((Component)enemy).GetComponentInChildren<EnemyGrounded>(); if ((Object)(object)componentInChildren != (Object)null && !GroundedRef.Invoke(componentInChildren)) { return true; } return !SemiFunc.OnGroundCheck((grabObject.centerPoint != Vector3.zero) ? grabObject.centerPoint : ((Component)enemyBody).transform.position, 0.75f, grabObject); } private static void AddHolder(List<PlayerAvatar> holders, PlayerAvatar holder) { if ((Object)(object)holder != (Object)null && !holders.Contains(holder)) { holders.Add(holder); } } private static void ClearEnemyTimers(int enemyId) { foreach (ShockTarget item in new List<ShockTarget>(DamageTimers.Keys)) { if (item.EnemyId == enemyId) { DamageTimers.Remove(item); } } } } [HarmonyPatch(typeof(PlayerAvatar), "Start")] internal static class ShockGripVisualRelayPatch { private static void Postfix(PlayerAvatar __instance) { ShockGripVisualRelay.Ensure(__instance); } } [HarmonyPatch(typeof(StatsManager), "Start")] internal static class StatsLabelPatch { private static void Postfix(StatsManager __instance) { ExtraBattleUpgradesPlugin.RefreshStatsLabels(__instance); } } [HarmonyPatch(typeof(Upgrades), "RegisterUpgrades")] internal static class RepolibRegisterUpgradesPatch { private static void Prefix() { ExtraBattleUpgradesPlugin.Diagnostic("REPOLib.Upgrades.RegisterUpgrades PRE."); ExtraBattleUpgradesPlugin.LogAllUpgradeDictionaryStates("REPOLib.RegisterUpgrades PRE"); } private static void Postfix() { ExtraBattleUpgradesPlugin.Diagnostic("REPOLib.Upgrades.RegisterUpgrades POST."); ExtraBattleUpgradesPlugin.LogAllUpgradeDictionaryStates("REPOLib.RegisterUpgrades POST before labels"); foreach (PlayerUpgrade playerUpgrade in Upgrades.PlayerUpgrades) { ExtraBattleUpgradesPlugin.EnsureUpgradeDictionaryLinked(playerUpgrade, "REPOLib.RegisterUpgrades POST link"); } if ((Object)(object)StatsManager.instance != (Object)null) { ExtraBattleUpgradesPlugin.RefreshStatsLabels(StatsManager.instance); } ExtraBattleUpgradesPlugin.LogAllUpgradeDictionaryStates("REPOLib.RegisterUpgrades POST after labels"); } } [HarmonyPatch(typeof(PlayerUpgrade))] internal static class PlayerUpgradeDiagnosticsPatch { [HarmonyPatch("SetLevel", new Type[] { typeof(string), typeof(int) })] [HarmonyPrefix] private static void SetLevelPrefix(PlayerUpgrade __instance, string steamId, int level) { ExtraBattleUpgradesPlugin.Diagnostic($"PlayerUpgrade.SetLevel PRE: upgrade={__instance.UpgradeId}, steamId={steamId}, requestedLevel={level}."); ExtraBattleUpgradesPlugin.LogUpgradeDictionaryState("PlayerUpgrade.SetLevel PRE", __instance, steamId); } [HarmonyPatch("SetLevel", new Type[] { typeof(string), typeof(int) })] [HarmonyPostfix] private static void SetLevelPostfix(PlayerUpgrade __instance, string steamId, int level, int __result) { ExtraBattleUpgradesPlugin.Diagnostic($"PlayerUpgrade.SetLevel POST: upgrade={__instance.UpgradeId}, steamId={steamId}, requestedLevel={level}, result={__result}."); ExtraBattleUpgradesPlugin.EnsureUpgradeDictionaryLinked(__instance, "PlayerUpgrade.SetLevel POST link", steamId, __result); ExtraBattleUpgradesPlugin.LogUpgradeDictionaryState("PlayerUpgrade.SetLevel POST", __instance, steamId); } [HarmonyPatch("ApplyUpgrade", new Type[] { typeof(string), typeof(int) })] [HarmonyPrefix] private static void ApplyUpgradePrefix(PlayerUpgrade __instance, string steamId, int level) { ExtraBattleUpgradesPlugin.Diagnostic($"PlayerUpgrade.ApplyUpgrade PRE: upgrade={__instance.UpgradeId}, steamId={steamId}, incomingLevel={level}."); ExtraBattleUpgradesPlugin.LogUpgradeDictionaryState("PlayerUpgrade.ApplyUpgrade PRE", __instance, steamId); } [HarmonyPatch("ApplyUpgrade", new Type[] { typeof(string), typeof(int) })] [HarmonyPostfix] private static void ApplyUpgradePostfix(PlayerUpgrade __instance, string steamId, int level) { ExtraBattleUpgradesPlugin.Diagnostic($"PlayerUpgrade.ApplyUpgrade POST: upgrade={__instance.UpgradeId}, steamId={steamId}, incomingLevel={level}."); ExtraBattleUpgradesPlugin.EnsureUpgradeDictionaryLinked(__instance, "PlayerUpgrade.ApplyUpgrade POST link", steamId, level); ExtraBattleUpgradesPlugin.LogUpgradeDictionaryState("PlayerUpgrade.ApplyUpgrade POST", __instance, steamId); } } [HarmonyPatch(typeof(StatsManager), "DictionaryUpdateValue")] internal static class StatsManagerDictionaryDiagnosticsPatch { private static void Prefix(string dictionaryName, string key, int value) { if (IsUpgradeDictionary(dictionaryName)) { Dictionary<string, int> dictionary = ExtraBattleUpgradesPlugin.TryGetStatsDictionary(dictionaryName); int value2; string text = ((dictionary != null && dictionary.TryGetValue(key, out value2)) ? value2.ToString() : "<absent>"); ExtraBattleUpgradesPlugin.Diagnostic($"StatsManager.DictionaryUpdateValue PRE: dictionary={dictionaryName}, key={key}, oldValue={text}, newValue={value}, exists={dictionary != null}."); } } private static void Postfix(string dictionaryName, string key, int value) { if (IsUpgradeDictionary(dictionaryName)) { Dictionary<string, int> dictionary = ExtraBattleUpgradesPlugin.TryGetStatsDictionary(dictionaryName); int value2; string text = ((dictionary != null && dictionary.TryGetValue(key, out value2)) ? value2.ToString() : "<absent>"); ExtraBattleUpgradesPlugin.Diagnostic($"StatsManager.DictionaryUpdateValue POST: dictionary={dictionaryName}, key={key}, requestedValue={value}, finalValue={text}, exists={dictionary != null}."); } } private static bool IsUpgradeDictionary(string dictionaryName) { return dictionaryName?.StartsWith("playerUpgrade", StringComparison.Ordinal) ?? false; } } [HarmonyPatch(typeof(StatsUI), "Fetch")] internal static class StatsUIFetchDiagnosticsPatch { private static readonly FieldInfo PlayerUpgradesField = AccessTools.Field(typeof(StatsUI), "playerUpgrades"); private static void Prefix() { string text = LocalSteamId(); ExtraBattleUpgradesPlugin.Diagnostic("StatsUI.Fetch PRE: localSteamId=" + text + "."); } private static void Postfix(StatsUI __instance) { string text = LocalSteamId(); Dictionary<string, int> dictionary = PlayerUpgradesField?.GetValue(__instance) as Dictionary<string, int>; ExtraBattleUpgradesPlugin.Diagnostic("StatsUI.Fetch POST: localSteamId=" + text + ", visibleEntries=" + FormatDictionary(dictionary) + "."); } private static string LocalSteamId() { PlayerAvatar val = SemiFunc.PlayerAvatarLocal(); if ((Object)(object)val == (Object)null) { return "<no-local-player>"; } string text = SemiFunc.PlayerGetSteamID(val); if (!string.IsNullOrWhiteSpace(text)) { return text; } return "<empty-local-steamid>"; } private static string FormatDictionary(Dictionary<string, int> dictionary) { if (dictionary == null) { return "<missing-field>"; } if (dictionary.Count == 0) { return "<empty>"; } List<string> list = new List<string>(); foreach (KeyValuePair<string, int> item in dictionary) { list.Add(item.Key + "=" + item.Value); } return string.Join(", ", list); } } } namespace ExtraBattleUpgrades.Hud { internal sealed class BattleUpgradeHudConfig { internal ConfigEntry<bool> PanicIconEnabled { get; } internal ConfigEntry<float> PanicIconX { get; } internal ConfigEntry<float> PanicIconY { get; } internal ConfigEntry<float> PanicIconSize { get; } internal ConfigEntry<bool> SecondChanceIconEnabled { get; } internal ConfigEntry<float> SecondChanceIconX { get; } internal ConfigEntry<float> SecondChanceIconY { get; } internal ConfigEntry<float> SecondChanceIconSize { get; } internal BattleUpgradeHudConfig(ConfigFile config) { PanicIconEnabled = config.Bind<bool>("HUD - Panic Response", "Icon Enabled", true, "Show Panic Response HUD icon."); PanicIconX = config.Bind<float>("HUD - Panic Response", "Icon X", 68f, "Panic Response icon local X position."); PanicIconY = config.Bind<float>("HUD - Panic Response", "Icon Y", -23f, "Panic Response icon local Y position."); PanicIconSize = config.Bind<float>("HUD - Panic Response", "Icon Size", 11f, "Panic Response icon size."); SecondChanceIconEnabled = config.Bind<bool>("HUD - Second Chance", "Icon Enabled", true, "Show Second Chance HUD icon."); SecondChanceIconX = config.Bind<float>("HUD - Second Chance", "Icon X", 68f, "Second Chance icon local X position."); SecondChanceIconY = config.Bind<float>("HUD - Second Chance", "Icon Y", -23f, "Second Chance icon local Y position."); SecondChanceIconSize = config.Bind<float>("HUD - Second Chance", "Icon Size", 15f, "Second Chance icon size."); } } internal static class BattleUpgradeIconPainter { private const int TextureSize = 64; private static Sprite _lightningSprite; private static Sprite _heartSprite; internal static Sprite LightningSprite() { //IL_0045: Unknown result