using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.VoidSurvivor.Weapon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using On.RoR2;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using RoR2.Skills;
using RoR2.UI;
using UnityEngine;
using UnityEngine.AddressableAssets;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SupressRework")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+08bbd3a7d90de663ad916caf69871e85548e44b3")]
[assembly: AssemblyProduct("SupressRework")]
[assembly: AssemblyTitle("SupressRework")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace SuppressRework
{
[BepInPlugin("com.renovice.suppressrework", "Suppress Rework", "1.4.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class SuppressRework : BaseUnityPlugin
{
public static ConfigEntry<bool> EnableAllOrNothingScaling;
public static ConfigEntry<bool> EnableEfficientTrades;
public static ConfigEntry<float> MaxHealthSacrifice;
public static ConfigEntry<float> FixedTradeValue;
public static ConfigEntry<int> MaxChargesNormalMode;
public static ConfigEntry<int> MaxChargesCorruptedMode;
public static ConfigEntry<bool> InfiniteChargesNormalMode;
public static ConfigEntry<bool> InfiniteChargesCorruptedMode;
internal static SkillDef _crushHealthDef;
internal static SkillDef _crushCorruptionDef;
internal static ManualLogSource Log;
public static SuppressRework Instance { get; private set; }
public void Awake()
{
//IL_0128: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Expected O, but got Unknown
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Expected O, but got Unknown
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
try
{
EnableAllOrNothingScaling = ((BaseUnityPlugin)this).Config.Bind<bool>("Main", "Enable All-or-Nothing Scaling", false, "If true, the ability consumes your resource bar for a 1:1 reward. If false, it uses a fixed percentage.");
EnableEfficientTrades = ((BaseUnityPlugin)this).Config.Bind<bool>("Main", "Enable Efficient Trades", true, "If true, the ability will not spend more resources than needed to fill the target bar.");
MaxHealthSacrifice = ((BaseUnityPlugin)this).Config.Bind<float>("All-or-Nothing Mode", "Max Health Sacrifice Percent", 50f, "When 'All-or-Nothing' is ON, this is the MAXIMUM percentage of your health you can sacrifice in one go.");
FixedTradeValue = ((BaseUnityPlugin)this).Config.Bind<float>("Fixed Trade Mode", "Fixed Trade Percentage", 35f, "When 'All-or-Nothing' is OFF, this is the percentage of health/corruption that will be traded.");
MaxChargesNormalMode = ((BaseUnityPlugin)this).Config.Bind<int>("Charge Settings", "Max Charges - Suppress", 1, "Maximum charges for the suppress ability (spend corruption to heal in normal mode). No cooldown - you get this many per transformation.");
MaxChargesCorruptedMode = ((BaseUnityPlugin)this).Config.Bind<int>("Charge Settings", "Max Charges - Corrupted Suppress", 2, "Maximum charges for the corrupted suppress ability (sacrifice health for corruption in void mode). No cooldown - you get this many per transformation.");
InfiniteChargesNormalMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Charge Settings", "Infinite Charges - Suppress", true, "If true, suppress ability has infinite charges in normal mode.");
InfiniteChargesCorruptedMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Charge Settings", "Infinite Charges - Corrupted Suppress", false, "If true, corrupted suppress ability has infinite charges in void mode.");
SetupRiskOfOptions();
Harmony val = new Harmony("com.renovice.suppressrework");
val.PatchAll();
SurvivorCatalog.Init += (hook_Init)delegate(orig_Init orig)
{
orig.Invoke();
OnGameLoaded();
};
((BaseUnityPlugin)this).Logger.LogInfo((object)"Suppress Rework v1.4.2 - Performance-Safe Voidfiend Complete Overhaul loaded successfully!");
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"Error in Awake: {arg}");
}
}
private void SetupRiskOfOptions()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Expected O, but got Unknown
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Expected O, but got Unknown
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: 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_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Expected O, but got Unknown
//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_0080: 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_009c: Expected O, but got Unknown
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Expected O, but got Unknown
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: 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_00c0: Expected O, but got Unknown
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Expected O, but got Unknown
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Expected O, but got Unknown
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Expected O, but got Unknown
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Expected O, but got Unknown
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Expected O, but got Unknown
try
{
ModSettingsManager.SetModDescription("A complete overhaul of Voidfiend's Suppress ability with customizable trading mechanics, charge systems, and dynamic tooltips.");
SetModIcon();
ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(EnableAllOrNothingScaling));
ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(EnableEfficientTrades));
ModSettingsManager.AddOption((BaseOption)new SliderOption(MaxHealthSacrifice, new SliderConfig
{
min = 1f,
max = 100f,
FormatString = "{0:0}%"
}));
ModSettingsManager.AddOption((BaseOption)new SliderOption(FixedTradeValue, new SliderConfig
{
min = 1f,
max = 100f,
FormatString = "{0:0}%"
}));
ModSettingsManager.AddOption((BaseOption)new IntSliderOption(MaxChargesNormalMode, new IntSliderConfig
{
min = 0,
max = 20
}));
ModSettingsManager.AddOption((BaseOption)new IntSliderOption(MaxChargesCorruptedMode, new IntSliderConfig
{
min = 0,
max = 20
}));
ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InfiniteChargesNormalMode));
ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InfiniteChargesCorruptedMode));
EnableAllOrNothingScaling.SettingChanged += delegate
{
OnSettingChanged();
};
EnableEfficientTrades.SettingChanged += delegate
{
OnSettingChanged();
};
MaxHealthSacrifice.SettingChanged += delegate
{
OnSettingChanged();
};
FixedTradeValue.SettingChanged += delegate
{
OnSettingChanged();
};
MaxChargesNormalMode.SettingChanged += delegate
{
OnSettingChanged();
};
MaxChargesCorruptedMode.SettingChanged += delegate
{
OnSettingChanged();
};
InfiniteChargesNormalMode.SettingChanged += delegate
{
OnSettingChanged();
};
InfiniteChargesCorruptedMode.SettingChanged += delegate
{
OnSettingChanged();
};
}
catch (Exception arg)
{
Log.LogError((object)$"Error setting up Risk of Options: {arg}");
}
}
private void SetModIcon()
{
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Expected O, but got Unknown
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
try
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
using Stream stream = executingAssembly.GetManifestResourceStream("V8_supressrework.icon.png");
if (stream != null)
{
byte[] array = new byte[stream.Length];
stream.Read(array, 0, array.Length);
Texture2D val = new Texture2D(2, 2);
ImageConversion.LoadImage(val, array);
Sprite modIcon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
ModSettingsManager.SetModIcon(modIcon);
Log.LogInfo((object)"Mod icon set successfully");
}
}
catch (Exception arg)
{
Log.LogError((object)$"Failed to set mod icon: {arg}");
}
}
private void OnSettingChanged()
{
try
{
ModifySkillDefs();
TooltipRefresher.RefreshTooltipsAfterSettingsChange();
Log.LogInfo((object)"Settings changed - skill descriptions should update dynamically");
}
catch (Exception arg)
{
Log.LogError((object)$"Error in OnSettingChanged: {arg}");
}
}
private void OnGameLoaded()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
try
{
_crushHealthDef = Addressables.LoadAssetAsync<SkillDef>((object)"RoR2/DLC1/VoidSurvivor/CrushHealth.asset").WaitForCompletion();
_crushCorruptionDef = Addressables.LoadAssetAsync<SkillDef>((object)"RoR2/DLC1/VoidSurvivor/CrushCorruption.asset").WaitForCompletion();
if ((Object)(object)_crushHealthDef != (Object)null)
{
Log.LogInfo((object)("CrushHealth loaded successfully. Token: " + _crushHealthDef.skillDescriptionToken));
}
else
{
Log.LogError((object)"Failed to load CrushHealth skill definition");
}
if ((Object)(object)_crushCorruptionDef != (Object)null)
{
Log.LogInfo((object)("CrushCorruption loaded successfully. Token: " + _crushCorruptionDef.skillDescriptionToken));
}
else
{
Log.LogError((object)"Failed to load CrushCorruption skill definition");
}
ModifySkillDefs();
}
catch (Exception arg)
{
Log.LogError((object)$"Error in OnGameLoaded: {arg}");
}
}
public void ModifySkillDefs()
{
try
{
if ((Object)(object)_crushHealthDef != (Object)null)
{
if (InfiniteChargesCorruptedMode.Value)
{
_crushHealthDef.baseMaxStock = 1;
_crushHealthDef.rechargeStock = 1;
_crushHealthDef.baseRechargeInterval = 0f;
Log.LogInfo((object)"Corrupted Suppress: Infinite charges enabled (instant recharge)");
}
else
{
_crushHealthDef.baseMaxStock = MaxChargesCorruptedMode.Value;
_crushHealthDef.rechargeStock = 0;
_crushHealthDef.baseRechargeInterval = 0f;
Log.LogInfo((object)$"Corrupted Suppress: {MaxChargesCorruptedMode.Value} charges, no recharge");
}
}
if (!((Object)(object)_crushCorruptionDef != (Object)null))
{
return;
}
if (InfiniteChargesNormalMode.Value)
{
_crushCorruptionDef.baseMaxStock = 1;
_crushCorruptionDef.rechargeStock = 1;
_crushCorruptionDef.baseRechargeInterval = 0f;
Log.LogInfo((object)"Suppress: Infinite charges enabled (instant recharge)");
}
else
{
_crushCorruptionDef.baseMaxStock = MaxChargesNormalMode.Value;
_crushCorruptionDef.rechargeStock = 0;
_crushCorruptionDef.baseRechargeInterval = 0f;
Log.LogInfo((object)$"Suppress: {MaxChargesNormalMode.Value} charges, no recharge");
}
if (((object)_crushCorruptionDef).GetType().Name == "VoidSurvivorSkillDef")
{
FieldInfo field = ((object)_crushCorruptionDef).GetType().GetField("minimumCorruption");
FieldInfo field2 = ((object)_crushCorruptionDef).GetType().GetField("maximumCorruption");
if (field != null)
{
field.SetValue(_crushCorruptionDef, 0.1f);
Log.LogInfo((object)"Set CrushCorruption minimumCorruption to: 0.1");
}
if (field2 != null)
{
field2.SetValue(_crushCorruptionDef, 100f);
Log.LogInfo((object)"Set CrushCorruption maximumCorruption to: 100");
}
}
}
catch (Exception arg)
{
Log.LogError((object)$"Error in ModifySkillDefs: {arg}");
}
}
}
[HarmonyPatch(typeof(CrushBase), "OnEnter")]
public static class CrushBase_OnEnter_Patch
{
private static bool Prefix(CrushBase __instance)
{
try
{
CharacterBody characterBody = ((EntityState)__instance).characterBody;
if ((Object)(object)characterBody == (Object)null)
{
return true;
}
if (!SuppressRework.EnableAllOrNothingScaling.Value)
{
float value = SuppressRework.FixedTradeValue.Value;
if (__instance is CrushHealth)
{
HealthComponent healthComponent = characterBody.healthComponent;
if ((Object)(object)healthComponent != (Object)null && healthComponent.fullHealth > 0f)
{
float num = healthComponent.health / healthComponent.fullHealth * 100f;
if (num < value)
{
ManualLogSource log = SuppressRework.Log;
if (log != null)
{
log.LogWarning((object)$"BLOCKED CrushHealth execution: {num:F1}% < {value}% required");
}
((EntityState)__instance).outer.SetNextStateToMain();
return false;
}
}
}
else if (__instance is CrushCorruption)
{
VoidSurvivorController component = ((Component)characterBody).GetComponent<VoidSurvivorController>();
if ((Object)(object)component != (Object)null)
{
float corruption = component.corruption;
if (corruption < value)
{
ManualLogSource log2 = SuppressRework.Log;
if (log2 != null)
{
log2.LogWarning((object)$"BLOCKED CrushCorruption execution: {corruption:F1}% < {value}% required");
}
((EntityState)__instance).outer.SetNextStateToMain();
return false;
}
}
}
}
float num2 = 0f;
float num3 = 0f;
if (SuppressRework.EnableAllOrNothingScaling.Value)
{
if (__instance is CrushHealth)
{
HealthComponent healthComponent2 = characterBody.healthComponent;
if ((Object)(object)healthComponent2 == (Object)null || healthComponent2.fullHealth <= 0f)
{
ManualLogSource log3 = SuppressRework.Log;
if (log3 != null)
{
log3.LogWarning((object)"CrushHealth: No health component, aborting");
}
((EntityState)__instance).outer.SetNextStateToMain();
return false;
}
float num4 = healthComponent2.health - 1f;
if (num4 <= 0f)
{
ManualLogSource log4 = SuppressRework.Log;
if (log4 != null)
{
log4.LogWarning((object)$"CrushHealth: Insufficient health to sacrifice. Current: {healthComponent2.health:F1}, need at least 2 HP");
}
((EntityState)__instance).outer.SetNextStateToMain();
return false;
}
float val = healthComponent2.fullHealth * (SuppressRework.MaxHealthSacrifice.Value / 100f);
float num5 = Math.Min(num4, val);
if (num5 <= 0.1f)
{
ManualLogSource log5 = SuppressRework.Log;
if (log5 != null)
{
log5.LogWarning((object)$"CrushHealth: Health sacrifice too small ({num5:F2} HP), aborting");
}
((EntityState)__instance).outer.SetNextStateToMain();
return false;
}
float num6 = num5 / healthComponent2.fullHealth;
num2 = 0f - num6;
num3 = num6 * 100f;
ManualLogSource log6 = SuppressRework.Log;
if (log6 != null)
{
log6.LogInfo((object)$"CrushHealth All-or-Nothing: Sacrificing {num5:F1} HP ({num6 * 100f:F1}%) for {num3:F1}% corruption");
}
}
else if (__instance is CrushCorruption)
{
VoidSurvivorController component2 = ((Component)characterBody).GetComponent<VoidSurvivorController>();
if ((Object)(object)component2 == (Object)null)
{
ManualLogSource log7 = SuppressRework.Log;
if (log7 != null)
{
log7.LogWarning((object)"CrushCorruption: No void survivor controller, aborting");
}
((EntityState)__instance).outer.SetNextStateToMain();
return false;
}
float corruption2 = component2.corruption;
if (corruption2 <= 0.1f)
{
ManualLogSource log8 = SuppressRework.Log;
if (log8 != null)
{
log8.LogWarning((object)$"CrushCorruption: Insufficient corruption to spend ({corruption2:F1}%), aborting");
}
((EntityState)__instance).outer.SetNextStateToMain();
return false;
}
float num7 = corruption2 / 100f;
num2 = num7;
num3 = 0f - corruption2;
ManualLogSource log9 = SuppressRework.Log;
if (log9 != null)
{
log9.LogInfo((object)$"CrushCorruption All-or-Nothing: Spending {corruption2:F1}% corruption for {num7 * 100f:F1}% heal");
}
}
}
else
{
float value2 = SuppressRework.FixedTradeValue.Value;
if (__instance is CrushHealth)
{
num2 = 0f - value2 / 100f;
num3 = value2;
ManualLogSource log10 = SuppressRework.Log;
if (log10 != null)
{
log10.LogInfo((object)$"CrushHealth Fixed: sacrificing {value2}% health for {value2}% corruption");
}
}
else if (__instance is CrushCorruption)
{
num2 = value2 / 100f;
num3 = 0f - value2;
ManualLogSource log11 = SuppressRework.Log;
if (log11 != null)
{
log11.LogInfo((object)$"CrushCorruption Fixed: spending {value2}% corruption for {value2}% heal");
}
}
}
if (SuppressRework.EnableEfficientTrades.Value)
{
if (__instance is CrushHealth && num3 > 0f)
{
VoidSurvivorController component3 = ((Component)characterBody).GetComponent<VoidSurvivorController>();
if ((Object)(object)component3 == (Object)null)
{
return true;
}
float num8 = 100f - component3.corruption;
if (num3 > num8)
{
float num9 = num8 / num3;
num3 *= num9;
num2 *= num9;
ManualLogSource log12 = SuppressRework.Log;
if (log12 != null)
{
log12.LogInfo((object)$"CrushHealth scaled down due to corruption cap: scale={num9:F2}");
}
}
}
else if (__instance is CrushCorruption && num2 > 0f)
{
HealthComponent healthComponent3 = characterBody.healthComponent;
if ((Object)(object)healthComponent3 == (Object)null)
{
return true;
}
float num10 = healthComponent3.fullHealth - healthComponent3.health;
float num11 = num10 / healthComponent3.fullHealth;
if (num2 > num11)
{
float num12 = num11 / num2;
num2 *= num12;
num3 *= num12;
ManualLogSource log13 = SuppressRework.Log;
if (log13 != null)
{
log13.LogInfo((object)$"CrushCorruption scaled down due to overheal prevention: scale={num12:F2}");
}
}
}
}
__instance.selfHealFraction = num2;
__instance.corruptionChange = num3;
return true;
}
catch (Exception arg)
{
ManualLogSource log14 = SuppressRework.Log;
if (log14 != null)
{
log14.LogError((object)$"Error in CrushBase_OnEnter_Patch: {arg}");
}
return true;
}
}
}
[HarmonyPatch]
public static class VoidSurvivorSkillDef_HasRequiredCorruption_Patch
{
private static MethodBase TargetMethod()
{
Type type = AccessTools.TypeByName("RoR2.Skills.VoidSurvivorSkillDef");
return AccessTools.Method(type, "HasRequiredCorruption", (Type[])null, (Type[])null);
}
private static bool Prefix(object __instance, GenericSkill skillSlot, ref bool __result)
{
try
{
if (SuppressRework.EnableAllOrNothingScaling.Value)
{
return true;
}
if (__instance == SuppressRework._crushHealthDef)
{
CharacterBody val = ((skillSlot != null) ? skillSlot.characterBody : null);
if ((Object)(object)((val != null) ? val.healthComponent : null) != (Object)null)
{
float num = val.healthComponent.health / val.healthComponent.fullHealth * 100f;
float value = SuppressRework.FixedTradeValue.Value;
__result = num >= value;
return false;
}
}
else if (__instance == SuppressRework._crushCorruptionDef)
{
CharacterBody val2 = ((skillSlot != null) ? skillSlot.characterBody : null);
VoidSurvivorController val3 = ((val2 != null) ? ((Component)val2).GetComponent<VoidSurvivorController>() : null);
if ((Object)(object)val3 != (Object)null)
{
float corruption = val3.corruption;
float value2 = SuppressRework.FixedTradeValue.Value;
__result = corruption >= value2;
return false;
}
}
}
catch (Exception arg)
{
ManualLogSource log = SuppressRework.Log;
if (log != null)
{
log.LogError((object)$"Error in HasRequiredCorruption patch: {arg}");
}
}
return true;
}
}
[HarmonyPatch(typeof(Language), "GetString", new Type[] { typeof(string) })]
public static class Language_GetString_Patch
{
private static string? _crushHealthToken = null;
private static string? _crushCorruptionToken = null;
private static string? _corruptionUpgradeToken = null;
private static readonly HashSet<string> _voidSurvivorTokens = new HashSet<string> { "VOIDSURVIVOR_PRIMARY_DESCRIPTION", "VOIDSURVIVOR_SECONDARY_DESCRIPTION", "VOIDSURVIVOR_UTILITY_DESCRIPTION", "VOIDSURVIVOR_SPECIAL_DESCRIPTION" };
private static bool Prefix(string token, ref string __result)
{
try
{
if (string.IsNullOrEmpty(token) || token.Length < 15)
{
return true;
}
if (_crushHealthToken == null && (Object)(object)SuppressRework._crushHealthDef != (Object)null)
{
_crushHealthToken = SuppressRework._crushHealthDef.skillDescriptionToken;
_crushCorruptionToken = SuppressRework._crushCorruptionDef?.skillDescriptionToken;
if (_crushHealthToken != null)
{
_voidSurvivorTokens.Add(_crushHealthToken);
}
if (_crushCorruptionToken != null)
{
_voidSurvivorTokens.Add(_crushCorruptionToken);
}
}
if (_corruptionUpgradeToken == null && token.Length > 25 && token.Contains("Corruption Upgrade") && token.Contains("Transform to crush"))
{
_corruptionUpgradeToken = token;
_voidSurvivorTokens.Add(token);
ManualLogSource log = SuppressRework.Log;
if (log != null)
{
log.LogInfo((object)("Safely cached corruption upgrade token: " + token));
}
}
if (token == _corruptionUpgradeToken)
{
if (SuppressRework.EnableAllOrNothingScaling.Value)
{
__result = "<style=cKeywordName>□Corruption Upgrade□</style><style=cSub>Transform to crush a portion of your maximum health to gain an equal percentage of Corruption instead.</style>";
}
else
{
string text = $"{SuppressRework.FixedTradeValue.Value:0}";
__result = "<style=cKeywordName>□Corruption Upgrade□</style><style=cSub>Transform to crush " + text + "% health to gain " + text + "% Corruption instead.</style>";
}
return false;
}
if (!_voidSurvivorTokens.Contains(token))
{
return true;
}
bool flag = IsPlayerInVoidModeState();
if (token == _crushCorruptionToken && (Object)(object)SuppressRework._crushCorruptionDef != (Object)null)
{
if (flag)
{
if (SuppressRework.EnableAllOrNothingScaling.Value)
{
__result = "Crush a portion of your <style=cIsHealth>maximum health</style> to gain an equal percentage of <style=cIsVoid>Corruption</style>.";
}
else
{
string text2 = $"{SuppressRework.FixedTradeValue.Value:0}";
__result = "Crush <style=cIsHealth>" + text2 + "% maximum health</style> to gain <style=cIsVoid>" + text2 + "% Corruption</style>.";
}
}
else if (SuppressRework.EnableAllOrNothingScaling.Value)
{
__result = "Crush your entire <style=cIsVoid>Corruption</style> bar to heal yourself for an equal percentage of <style=cIsHealing>maximum health</style>.";
}
else
{
string text3 = $"{SuppressRework.FixedTradeValue.Value:0}";
__result = "Crush <style=cIsVoid>" + text3 + "% Corruption</style> to heal yourself for <style=cIsHealing>" + text3 + "% maximum health</style>.";
}
return false;
}
switch (token)
{
case "VOIDSURVIVOR_PRIMARY_DESCRIPTION":
__result = (flag ? "Fire a short-range beam for <style=cIsDamage>300% damage</style>." : "Fire a slowing long-range beam for <style=cIsDamage>300% damage</style>.");
return false;
case "VOIDSURVIVOR_SECONDARY_DESCRIPTION":
__result = (flag ? "Fire an arcing plasma bomb for <style=cIsDamage>1100% damage</style>." : "Fire a plasma missile for <style=cIsDamage>600% damage</style>. Fully charge it for an <style=cIsDamage>explosive plasma ball</style> instead, dealing <style=cIsDamage>1100% damage</style>.");
return false;
case "VOIDSURVIVOR_UTILITY_DESCRIPTION":
__result = (flag ? "Disappear into the Void, <style=cIsUtility>cleansing all debuffs</style> while moving at a fast forward angle." : "Disappear into the Void, <style=cIsUtility>cleansing all debuffs</style> while moving in an upward arc.");
return false;
default:
if (token == _crushHealthToken && (Object)(object)SuppressRework._crushHealthDef != (Object)null)
{
if (SuppressRework.EnableAllOrNothingScaling.Value)
{
__result = "Crush a portion of your <style=cIsHealth>maximum health</style> to gain an equal percentage of <style=cIsVoid>Corruption</style>.";
}
else
{
string text4 = $"{SuppressRework.FixedTradeValue.Value:0}";
__result = "Crush <style=cIsHealth>" + text4 + "% maximum health</style> to gain <style=cIsVoid>" + text4 + "% Corruption</style>.";
}
return false;
}
break;
}
}
catch (Exception arg)
{
ManualLogSource log2 = SuppressRework.Log;
if (log2 != null)
{
log2.LogError((object)$"Error in Language_GetString_Patch: {arg}");
}
}
return true;
}
private static bool IsPlayerInVoidModeState()
{
try
{
LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
object obj;
if (firstLocalUser == null)
{
obj = null;
}
else
{
PlayerCharacterMasterController cachedMasterController = firstLocalUser.cachedMasterController;
if (cachedMasterController == null)
{
obj = null;
}
else
{
CharacterMaster master = cachedMasterController.master;
obj = ((master != null) ? master.GetBody() : null);
}
}
if ((Object)obj == (Object)null)
{
return false;
}
CharacterBody body = firstLocalUser.cachedMasterController.master.GetBody();
if (body.baseNameToken != "VOIDSURVIVOR_BODY_NAME")
{
return false;
}
VoidSurvivorController component = ((Component)body).GetComponent<VoidSurvivorController>();
if ((Object)(object)component == (Object)null)
{
return false;
}
if ((Object)(object)component.corruptedBuffDef != (Object)null && body.HasBuff(component.corruptedBuffDef))
{
return true;
}
EntityStateMachine corruptionModeStateMachine = component.corruptionModeStateMachine;
if (((corruptionModeStateMachine != null) ? corruptionModeStateMachine.state : null) != null)
{
string name = ((object)component.corruptionModeStateMachine.state).GetType().Name;
if (name == "CorruptMode")
{
return true;
}
}
return component.corruption >= 100f;
}
catch (Exception arg)
{
ManualLogSource log = SuppressRework.Log;
if (log != null)
{
log.LogError((object)$"Error in IsPlayerInVoidModeState: {arg}");
}
return false;
}
}
}
public static class TooltipRefresher
{
public static void RefreshTooltipsAfterSettingsChange()
{
//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
try
{
FieldInfo field = typeof(Language).GetField("currentLanguage", BindingFlags.Static | BindingFlags.NonPublic);
if (field != null)
{
object? value = field.GetValue(null);
Language val = (Language)((value is Language) ? value : null);
if (val != null)
{
FieldInfo field2 = typeof(Language).GetField("stringsByToken", BindingFlags.Instance | BindingFlags.NonPublic);
if (field2 != null)
{
object value2 = field2.GetValue(val);
if (value2 != null)
{
MethodInfo method = value2.GetType().GetMethod("Remove");
if (method != null && (Object)(object)SuppressRework._crushCorruptionDef != (Object)null)
{
method.Invoke(value2, new object[1] { SuppressRework._crushCorruptionDef.skillDescriptionToken });
if ((Object)(object)SuppressRework._crushHealthDef != (Object)null)
{
method.Invoke(value2, new object[1] { SuppressRework._crushHealthDef.skillDescriptionToken });
}
}
}
}
}
}
TooltipProvider[] array = Object.FindObjectsOfType<TooltipProvider>();
TooltipProvider[] array2 = array;
foreach (TooltipProvider val2 in array2)
{
if (val2.bodyToken == null || (!val2.bodyToken.Contains("CRUSH") && !val2.bodyToken.Contains("SPECIAL")))
{
continue;
}
MethodInfo method2 = typeof(TooltipProvider).GetMethod("SetContent", BindingFlags.Instance | BindingFlags.Public);
if (method2 != null)
{
TooltipProvider component = ((Component)val2).GetComponent<TooltipProvider>();
if ((Object)(object)component != (Object)null)
{
method2.Invoke(val2, new object[1] { (object)default(TooltipContent) });
}
}
}
ManualLogSource log = SuppressRework.Log;
if (log != null)
{
log.LogInfo((object)"Cleared tooltip cache to force refresh");
}
}
catch (Exception arg)
{
ManualLogSource log2 = SuppressRework.Log;
if (log2 != null)
{
log2.LogError((object)$"Error refreshing tooltips: {arg}");
}
}
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}