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.0")] public sealed class ExtraBattleUpgradesPlugin : BaseUnityPlugin { public const string PluginGuid = "DarkSpider90.ExtraBattleUpgrades"; public const string PluginName = "Extra Battle Upgrades"; public const string PluginVersion = "1.0.0"; private Harmony _harmony; private bool _statsLabelsReady; 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; } private void Awake() { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; 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.0 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) { 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(); } } private static void SetStatsLabel(StatsManager statsManager, string statsKey, string displayName) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_003e: Expected O, but got Unknown if (statsManager.upgradesInfo.TryGetValue(statsKey, out var value)) { value.displayName = displayName; value.displayNameLocalized = null; } else { statsManager.upgradesInfo.Add(statsKey, new UpgradeInfo { displayName = displayName, displayNameLocalized = null }); } } 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(); _photonView = ((Component)this).GetComponent(); } internal static void Ensure(PlayerAvatar player) { if (!((Object)(object)player == (Object)null) && (Object)(object)((Component)player).GetComponent() == (Object)null) { ((Component)player).gameObject.AddComponent(); } } 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()); } else { ShockGripVisuals.PlayLocal(holder); } } } [PunRPC] private void ShockGripVisualRPC(PhotonMessageInfo info = default(PhotonMessageInfo)) { if ((Object)(object)_player == (Object)null) { _player = ((Component)this).GetComponent(); } ShockGripVisuals.PlayLocal(_player); } } internal static class ShockGripVisuals { private static readonly Dictionary Effects = new Dictionary(); 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(); 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 _bolts = new List(); 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(); 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 _bonusPerLevelFirstTen; private readonly ConfigEntry _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("Armor Upgrade", "Bonus Per Level First Ten", 0.05f, "Damage Reduction per Armor level 1 to 10. 0.05 = 5%."); _bonusPerLevelAfterTen = config.Bind("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 _bonusPerLevelFirstTen; private readonly ConfigEntry _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("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("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 _bonusPerLevelFirstTen; private readonly ConfigEntry _bonusPerLevelAfterTen; private readonly ConfigEntry _holdStabilityEffectMultiplier; private readonly ConfigEntry _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("Overcharge Upgrade", "Bonus Per Level First Ten", 0.1f, "Bonus per Overcharge level from level 1 to 10. 0.10 = 10%."); _bonusPerLevelAfterTen = config.Bind("Overcharge Upgrade", "Bonus Per Level After Ten", 0.05f, "Bonus per Overcharge level after level 10. 0.05 = 5%."); _holdStabilityEffectMultiplier = config.Bind("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("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 _durationLevel1; private readonly ConfigEntry _durationLevel2To3; private readonly ConfigEntry _durationLevel4Plus; private readonly ConfigEntry _cooldownBase; private readonly ConfigEntry _cooldownReductionStartLevel; private readonly ConfigEntry _cooldownReductionPerLevel; private readonly ConfigEntry _cooldownMin; private readonly ConfigEntry _speedMultiplierLevel1To2; private readonly ConfigEntry _speedMultiplierLevel3Plus; 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("Panic Response Upgrade", "Duration Level 1", 5f, "Panic Response duration at level 1, in seconds."); _durationLevel2To3 = config.Bind("Panic Response Upgrade", "Duration Level 2 To 3", 6f, "Panic Response duration from level 2 to level 3, in seconds."); _durationLevel4Plus = config.Bind("Panic Response Upgrade", "Duration Level 4 Plus", 7f, "Panic Response duration from level 4 and above, in seconds."); _cooldownBase = config.Bind("Panic Response Upgrade", "Cooldown Base", 60f, "Base Panic Response cooldown, in seconds."); _cooldownReductionStartLevel = config.Bind("Panic Response Upgrade", "Cooldown Reduction Start Level", 5f, "Level where cooldown reduction starts. Default 5 means level 5+ starts reducing cooldown."); _cooldownReductionPerLevel = config.Bind("Panic Response Upgrade", "Cooldown Reduction Per Level", 5f, "Cooldown reduction per level after the reduction start level, in seconds."); _cooldownMin = config.Bind("Panic Response Upgrade", "Cooldown Minimum", 30f, "Minimum Panic Response cooldown, in seconds."); _speedMultiplierLevel1To2 = config.Bind("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("Panic Response Upgrade", "Speed Multiplier Level 3 Plus", 1.35f, "Speed multiplier from level 3 and above. 1.35 = 35% faster."); } 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 sealed class SecondChanceShopUpgrade : ShopUpgrade { private readonly Dictionary _cooldownEnds = new Dictionary(); private readonly Dictionary _protectionEnds = new Dictionary(); internal const string StatsDictionaryKey = "playerUpgradeSecondChance"; private readonly ConfigEntry _invulnerabilitySecondsPerLevel; private readonly ConfigEntry _invulnerabilityMaxScalingLevel; private readonly ConfigEntry _cooldownBase; private readonly ConfigEntry _cooldownReductionStartLevel; private readonly ConfigEntry _cooldownFastReductionMaxLevel; private readonly ConfigEntry _cooldownReductionPerLevel; private readonly ConfigEntry _cooldownReductionPerExtraLevel; private readonly ConfigEntry _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("Second Chance Upgrade", "Invulnerability Seconds Per Level", 1f, "Invulnerability duration gained per level before the cap. 1 = 1 second."); _invulnerabilityMaxScalingLevel = config.Bind("Second Chance Upgrade", "Invulnerability Max Scaling Level", 5, "Level where invulnerability duration stops increasing."); _cooldownBase = config.Bind("Second Chance Upgrade", "Cooldown Base", 120f, "Base Second Chance cooldown, in seconds."); _cooldownReductionStartLevel = config.Bind("Second Chance Upgrade", "Cooldown Reduction Start Level", 6, "Level where cooldown reduction starts."); _cooldownFastReductionMaxLevel = config.Bind("Second Chance Upgrade", "Cooldown Fast Reduction Max Level", 10, "Last level that uses the main cooldown reduction value."); _cooldownReductionPerLevel = config.Bind("Second Chance Upgrade", "Cooldown Reduction Per Level", 5f, "Cooldown reduction per level during the main reduction range, in seconds."); _cooldownReductionPerExtraLevel = config.Bind("Second Chance Upgrade", "Cooldown Reduction Per Extra Level", 0.5f, "Cooldown reduction per level after the fast reduction range, in seconds."); _cooldownMin = config.Bind("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 _damagePerLevelFirstTen; private readonly ConfigEntry _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("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("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 Enabled { get; } internal ConfigEntry 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(text, "Enabled", true, "Enable the " + _label + " upgrade."); PriceMultiplier = config.Bind(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(_prefabPath); ItemAttributes val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : 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; item.value = MakePriceRange(item.value, PriceMultiplier.Value); Items.RegisterItem(val2); RegisteredUpgrade = Upgrades.RegisterUpgrade(UpgradeId, item, (Action)OnRunStart, (Action)OnUpgradeBought); if (RegisteredUpgrade == null) { ExtraBattleUpgradesPlugin.Log.LogError((object)("Failed to register " + _label + " upgrade with REPOLib.")); } else { ExtraBattleUpgradesPlugin.Log.LogInfo((object)("Registered " + _label + " upgrade.")); } } 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) { if ((Object)(object)player != (Object)null && player == SemiFunc.PlayerAvatarLocal()) { ExtraBattleUpgradesPlugin.Log.LogDebug((object)$"Initialized {_label} level {level} for {SemiFunc.PlayerGetName(player)}."); } } protected virtual void OnUpgradeBought(PlayerAvatar player, int level) { if ((Object)(object)player != (Object)null && player == SemiFunc.PlayerAvatarLocal()) { ExtraBattleUpgradesPlugin.Log.LogDebug((object)$"Applied {_label} level {level} for {SemiFunc.PlayerGetName(player)}."); } } private static Value MakePriceRange(Value source, float multiplier) { Value val = ScriptableObject.CreateInstance(); 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; } } } 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 EnergyTextRef = AccessTools.FieldRefAccess("Text"); private static readonly FieldRef HealthTextRef = AccessTools.FieldRefAccess("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().sizeDelta = size; Image obj = val.AddComponent(); 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 OwnerRef = AccessTools.FieldRefAccess("playerAvatar"); private static readonly FieldRef OverchargeFloatRef = AccessTools.FieldRefAccess("physGrabBeamOverChargeFloat"); private static readonly FieldRef OverchargeByteRef = AccessTools.FieldRefAccess("physGrabBeamOverCharge"); private static readonly FieldRef OverchargeAmountRef = AccessTools.FieldRefAccess("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 EnemyGrabObjectRef = AccessTools.FieldRefAccess("physGrabObject"); private static readonly FieldRef GrabStrengthTimerRef = AccessTools.FieldRefAccess("grabStrengthTimer"); private static readonly FieldRef GrabTimeCurrentRef = AccessTools.FieldRefAccess("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 BuffEnds = new Dictionary(); private static readonly Dictionary CooldownEnds = new Dictionary(); 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(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 PlayerTumbleRef = AccessTools.FieldRefAccess("tumble"); private static readonly FieldRef TumbleBodyRef = AccessTools.FieldRefAccess("physGrabObject"); private static readonly FieldRef HealthRef = AccessTools.FieldRefAccess("health"); private static readonly FieldRef MaxHealthRef = AccessTools.FieldRefAccess("maxHealth"); private static readonly Dictionary PitRescueTimes = new Dictionary(); [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 DamageTimers = new Dictionary(); private static readonly FieldRef EnemyGrabObjectRef = AccessTools.FieldRefAccess("physGrabObject"); private static readonly FieldRef EnemyGrabbedRef = AccessTools.FieldRefAccess("grabbed"); private static readonly FieldRef GrabStrengthTimerRef = AccessTools.FieldRefAccess("grabStrengthTimer"); private static readonly FieldRef LastPlayerGrabbingRef = AccessTools.FieldRefAccess("lastPlayerGrabbing"); private static readonly FieldRef GrabbedTimerRef = AccessTools.FieldRefAccess("grabbedTimer"); private static readonly FieldRef GroundedRef = AccessTools.FieldRefAccess("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() : null); List 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 GetHolders(PhysGrabObject grabObject) { List list = new List(); 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 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(); 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 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(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); } } } namespace ExtraBattleUpgrades.Hud { internal sealed class BattleUpgradeHudConfig { internal ConfigEntry PanicIconEnabled { get; } internal ConfigEntry PanicIconX { get; } internal ConfigEntry PanicIconY { get; } internal ConfigEntry PanicIconSize { get; } internal ConfigEntry SecondChanceIconEnabled { get; } internal ConfigEntry SecondChanceIconX { get; } internal ConfigEntry SecondChanceIconY { get; } internal ConfigEntry SecondChanceIconSize { get; } internal BattleUpgradeHudConfig(ConfigFile config) { PanicIconEnabled = config.Bind("HUD - Panic Response", "Icon Enabled", true, "Show Panic Response HUD icon."); PanicIconX = config.Bind("HUD - Panic Response", "Icon X", 68f, "Panic Response icon local X position."); PanicIconY = config.Bind("HUD - Panic Response", "Icon Y", -23f, "Panic Response icon local Y position."); PanicIconSize = config.Bind("HUD - Panic Response", "Icon Size", 11f, "Panic Response icon size."); SecondChanceIconEnabled = config.Bind("HUD - Second Chance", "Icon Enabled", true, "Show Second Chance HUD icon."); SecondChanceIconX = config.Bind("HUD - Second Chance", "Icon X", 68f, "Second Chance icon local X position."); SecondChanceIconY = config.Bind("HUD - Second Chance", "Icon Y", -23f, "Second Chance icon local Y position."); SecondChanceIconSize = config.Bind("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 type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_lightningSprite != (Object)null) { return _lightningSprite; } Texture2D obj = DrawLightning(); ((Object)obj).name = "ExtraBattleUpgrades_PanicResponse_Lightning"; ((Texture)obj).wrapMode = (TextureWrapMode)1; ((Texture)obj).filterMode = (FilterMode)1; _lightningSprite = Sprite.Create(obj, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f); return _lightningSprite; } internal static Sprite HeartSprite() { //IL_0045: 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) if ((Object)(object)_heartSprite != (Object)null) { return _heartSprite; } Texture2D obj = DrawHeart(); ((Object)obj).name = "ExtraBattleUpgrades_SecondChance_Heart"; ((Texture)obj).wrapMode = (TextureWrapMode)1; ((Texture)obj).filterMode = (FilterMode)1; _heartSprite = Sprite.Create(obj, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f); return _heartSprite; } private static Texture2D DrawLightning() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0049: 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) //IL_005f: 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_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_0093: 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) Texture2D val = NewTransparentTexture(); Vector2[] polygon = (Vector2[])(object)new Vector2[6] { new Vector2(37f, 4f), new Vector2(16f, 34f), new Vector2(30f, 34f), new Vector2(23f, 60f), new Vector2(48f, 25f), new Vector2(34f, 25f) }; DrawGlowPolygon(val, polygon, Color.white, 7f, 0.28f); FillPolygon(val, polygon, Color.white); val.Apply(false, true); return val; } private static Texture2D DrawHeart() { //IL_0067: 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) Texture2D val = NewTransparentTexture(); for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num = ((float)j - 32f) / 24f; float num2 = ((float)i - 28f) / 24f; float num3 = Mathf.Pow(num * num + num2 * num2 - 0.32f, 3f) - num * num * num2 * num2 * num2; if (num3 <= 0f) { val.SetPixel(j, i, Color.white); } else if (num3 <= 0.08f) { float num4 = Mathf.Clamp01(1f - num3 / 0.08f) * 0.28f; val.SetPixel(j, i, new Color(1f, 1f, 1f, num4)); } } } val.Apply(false, true); return val; } private static Texture2D NewTransparentTexture() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[4096]; for (int i = 0; i < array.Length; i++) { array[i] = Color.clear; } val.SetPixels(array); return val; } private static void FillPolygon(Texture2D texture, Vector2[] polygon, Color color) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { if (PointInPolygon(new Vector2((float)j + 0.5f, (float)i + 0.5f), polygon)) { texture.SetPixel(j, i, color); } } } } private static void DrawGlowPolygon(Texture2D texture, Vector2[] polygon, Color color, float radius, float strength) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_004e: 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) for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num = DistanceToPolygon(new Vector2((float)j + 0.5f, (float)i + 0.5f), polygon); if (num <= radius) { float alpha = Mathf.Pow(1f - num / radius, 2f) * strength; Color pixel = texture.GetPixel(j, i); texture.SetPixel(j, i, Blend(pixel, color, alpha)); } } } } private static float DistanceToPolygon(Vector2 point, Vector2[] polygon) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) float num = float.MaxValue; for (int i = 0; i < polygon.Length; i++) { Vector2 a = polygon[i]; Vector2 b = polygon[(i + 1) % polygon.Length]; num = Mathf.Min(num, DistanceToSegment(point, a, b)); } if (PointInPolygon(point, polygon)) { return 0f; } return num; } private static float DistanceToSegment(Vector2 point, Vector2 a, Vector2 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Vector2 val = b - a; float num = Vector2.Dot(point - a, val) / ((Vector2)(ref val)).sqrMagnitude; num = Mathf.Clamp01(num); return Vector2.Distance(point, a + val * num); } private static bool PointInPolygon(Vector2 point, Vector2[] polygon) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) bool flag = false; int num = 0; int num2 = polygon.Length - 1; while (num < polygon.Length) { if (polygon[num].y > point.y != polygon[num2].y > point.y && point.x < (polygon[num2].x - polygon[num].x) * (point.y - polygon[num].y) / (polygon[num2].y - polygon[num].y) + polygon[num].x) { flag = !flag; } num2 = num++; } return flag; } private static Color Blend(Color under, Color over, float alpha) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0067: 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_0075: 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_0021: Unknown result type (might be due to invalid IL or missing references) alpha = Mathf.Clamp01(alpha); float num = alpha + under.a * (1f - alpha); if (num <= 0f) { return Color.clear; } return new Color((over.r * alpha + under.r * under.a * (1f - alpha)) / num, (over.g * alpha + under.g * under.a * (1f - alpha)) / num, (over.b * alpha + under.b * under.a * (1f - alpha)) / num, num); } } } namespace ExtraBattleUpgrades.Combat { internal static class CombatDamageTracker { private static readonly Stack OwnerStack = new Stack(); private static readonly FieldRef LastPlayerGrabbing = AccessTools.FieldRefAccess("lastPlayerGrabbing"); private static readonly FieldRef GrabbedTimer = AccessTools.FieldRefAccess("grabbedTimer"); internal static PlayerAvatar[] CurrentOwners { get { if (OwnerStack.Count != 0) { return OwnerStack.Peek(); } return Array.Empty(); } } internal static void Push(PlayerAvatar owner) { if ((Object)(object)owner == (Object)null) { OwnerStack.Push(Array.Empty()); return; } OwnerStack.Push((PlayerAvatar[])(object)new PlayerAvatar[1] { owner }); } internal static void PushFromPhysGrabObject(PhysGrabObject physGrabObject) { if ((Object)(object)physGrabObject == (Object)null) { OwnerStack.Push(Array.Empty()); return; } List list = new List(); if (physGrabObject.playerGrabbing != null) { foreach (PhysGrabber item in physGrabObject.playerGrabbing) { AddOwner(list, item?.playerAvatar); } } if (list.Count == 0 && GrabbedTimer.Invoke(physGrabObject) > 0f) { AddOwner(list, LastPlayerGrabbing.Invoke(physGrabObject)); } OwnerStack.Push(list.ToArray()); } internal static void Pop() { if (OwnerStack.Count > 0) { OwnerStack.Pop(); } } internal static void ApplyEnergyLeech(int actualDamage, PlayerAvatar[] owners) { if (actualDamage <= 0 || owners == null || owners.Length == 0) { return; } EnergyLeechShopUpgrade energyLeech = ExtraBattleUpgradesPlugin.EnergyLeech; if (energyLeech == null || !energyLeech.Enabled.Value || energyLeech.RegisteredUpgrade == null) { return; } List list = new List(); foreach (PlayerAvatar val in owners) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.playerHealth == (Object)null) && !list.Contains(val)) { int num = energyLeech.HealingFromDamage(actualDamage, val); if (num > 0) { val.playerHealth.HealOther(num, true); list.Add(val); } } } } private static void AddOwner(List owners, PlayerAvatar owner) { if ((Object)(object)owner != (Object)null && !owners.Contains(owner)) { owners.Add(owner); } } } }