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.0.0
ExtraBattleUpgrades.dll
Decompiled 2 hours agousing 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<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; 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."); } 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<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; item.value = MakePriceRange(item.value, PriceMultiplier.Value); Items.RegisterItem(val2); RegisteredUpgrade = Upgrades.RegisterUpgrade(UpgradeId, item, (Action<PlayerAvatar, int>)OnRunStart, (Action<PlayerAvatar, int>)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<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; } } } 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(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); } } } 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 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<PlayerAvatar[]> OwnerStack = new Stack<PlayerAvatar[]>(); private static readonly FieldRef<PhysGrabObject, PlayerAvatar> LastPlayerGrabbing = AccessTools.FieldRefAccess<PhysGrabObject, PlayerAvatar>("lastPlayerGrabbing"); private static readonly FieldRef<PhysGrabObject, float> GrabbedTimer = AccessTools.FieldRefAccess<PhysGrabObject, float>("grabbedTimer"); internal static PlayerAvatar[] CurrentOwners { get { if (OwnerStack.Count != 0) { return OwnerStack.Peek(); } return Array.Empty<PlayerAvatar>(); } } internal static void Push(PlayerAvatar owner) { if ((Object)(object)owner == (Object)null) { OwnerStack.Push(Array.Empty<PlayerAvatar>()); 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<PlayerAvatar>()); return; } List<PlayerAvatar> list = new List<PlayerAvatar>(); 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<PlayerAvatar> list = new List<PlayerAvatar>(); 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<PlayerAvatar> owners, PlayerAvatar owner) { if ((Object)(object)owner != (Object)null && !owners.Contains(owner)) { owners.Add(owner); } } } }