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 CorpseBloomRebornHC v1.0.0
CorpseBloomRebornHC.dll
Decompiled a day agousing System; using System.Collections; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using On.RoR2; using On.RoR2.UI; using RoR2; using RoR2.ContentManagement; using RoR2.UI; using UnityEngine; using UnityEngine.Networking; 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: AssemblyCompany("Serestielle")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("CorpseBloomRebornHC")] [assembly: AssemblyTitle("CorpseBloomRebornHC")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Serestielle.CorpseBloomRebornHC { [BepInPlugin("com.Serestielle.CorpseBloomRebornHC", "CorpseBloomRebornHC", "1.0.0")] [BepInIncompatibility("com.TPDespair.CorpseBloomReborn")] public class CorpseBloomRebornHCPlugin : BaseUnityPlugin { private class Content : IContentPackProvider { private readonly ContentPack contentPack = new ContentPack(); public string identifier => "CorpseBloomRebornHCContent"; public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args) { ReserveBuff = ScriptableObject.CreateInstance<BuffDef>(); ((Object)ReserveBuff).name = "CBReserve"; ReserveBuff.buffColor = new Color(0.65f, 0.35f, 1f); ReserveBuff.canStack = true; ReserveBuff.isHidden = Configuration.HideReserveBuff.Value; ReserveBuff.iconSprite = LegacyResourcesAPI.Load<BuffDef>("BuffDefs/MedkitHeal")?.iconSprite; contentPack.buffDefs.Add((BuffDef[])(object)new BuffDef[1] { ReserveBuff }); args.ReportProgress(1f); yield break; } public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args) { ContentPack.Copy(contentPack, args.output); args.ReportProgress(1f); yield break; } public IEnumerator FinalizeAsync(FinalizeAsyncArgs args) { args.ReportProgress(1f); yield break; } } [CompilerGenerated] private static class <>O { public static Action<CharacterBody> <0>__OnInventoryChanged; public static hook_Heal <1>__InterceptHeal; public static Action <2>__SetLanguageStrings; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static CollectContentPackProvidersDelegate <>9__5_0; public static hook_Awake <>9__5_1; internal void <Awake>b__5_0(AddContentPackProviderDelegate add) { add.Invoke((IContentPackProvider)(object)new Content()); } internal void <Awake>b__5_1(orig_Awake orig, HealthBar self) { orig.Invoke(self); if (Object.op_Implicit((Object)(object)self.barContainer)) { ((Component)self).gameObject.AddComponent<ReserveBar>().healthBar = self; } } } public const string ModVer = "1.0.0"; public const string ModName = "CorpseBloomRebornHC"; public const string ModGuid = "com.Serestielle.CorpseBloomRebornHC"; internal static BuffDef ReserveBuff; private static Hook healHook; public void Awake() { //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_0044: Expected O, but got Unknown //IL_009a: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_008d: 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_0098: 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_00d6: Expected O, but got Unknown RoR2Application.isModded = true; NetworkModCompatibilityHelper.networkModList = NetworkModCompatibilityHelper.networkModList.Append("com.Serestielle.CorpseBloomRebornHC:1.0.0"); Configuration.Init(((BaseUnityPlugin)this).Config); object obj = <>c.<>9__5_0; if (obj == null) { CollectContentPackProvidersDelegate val = delegate(AddContentPackProviderDelegate add) { add.Invoke((IContentPackProvider)(object)new Content()); }; <>c.<>9__5_0 = val; obj = (object)val; } ContentManager.collectContentPackProviders += (CollectContentPackProvidersDelegate)obj; CharacterBody.onBodyInventoryChangedGlobal += ReserveBehavior.OnInventoryChanged; MethodInfo? method = typeof(HealthComponent).GetMethod("Heal"); object obj2 = <>O.<1>__InterceptHeal; if (obj2 == null) { hook_Heal val2 = InterceptHeal; <>O.<1>__InterceptHeal = val2; obj2 = (object)val2; } healHook = new Hook((MethodBase)method, (Delegate)obj2, new HookConfig { Priority = 10000 }); object obj3 = <>c.<>9__5_1; if (obj3 == null) { hook_Awake val3 = delegate(orig_Awake orig, HealthBar self) { orig.Invoke(self); if (Object.op_Implicit((Object)(object)self.barContainer)) { ((Component)self).gameObject.AddComponent<ReserveBar>().healthBar = self; } }; <>c.<>9__5_1 = val3; obj3 = (object)val3; } HealthBar.Awake += (hook_Awake)obj3; Language.onCurrentLanguageChanged += SetLanguageStrings; if (Language.currentLanguage != null) { SetLanguageStrings(); } } private static float InterceptHeal(orig_Heal orig, HealthComponent self, float amount, ProcChainMask procChainMask, bool nonRegen) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) ReserveBehavior reserveBehavior = default(ReserveBehavior); if (nonRegen && NetworkServer.active && !((ProcChainMask)(ref procChainMask)).HasProc((ProcType)13) && !((ProcChainMask)(ref procChainMask)).HasProc((ProcType)31) && ((Component)self).TryGetComponent<ReserveBehavior>(ref reserveBehavior)) { if (self.alive && amount > 0f && !self.body.HasBuff(Buffs.HealingDisabled)) { reserveBehavior.AddReserve(amount); } return 0f; } return orig.Invoke(self, amount, procChainMask, nonRegen); } private static void SetLanguageStrings() { Language.currentLanguage.SetStringByToken("ITEM_REPEATHEAL_PICKUP", GetPickup()); Language.currentLanguage.SetStringByToken("ITEM_REPEATHEAL_DESC", GetDesc()); } private static string GetPickup() { if (Configuration.HealBeforeReserve.Value) { return "Gain extra healing as reserve."; } if (Configuration.HealWhenReserveFull.Value) { return "Store healing to heal over time."; } return "All healing is applied over time."; } private static string Stack(float value) { if (value == 0f) { return ""; } return string.Format(" <style=cStack>({0}{1:0.##}% per stack)</style>", (value > 0f) ? "+" : "", value * 100f); } private static string GetDesc() { string pickup = GetPickup(); pickup += $"\nGain <style=cIsHealing>{Configuration.BaseHealthReserve.Value * 100f:0.##}%</style>{Stack(Configuration.AddedHealthReserve.Value)}"; pickup += " of your <style=cIsHealing>maximum health</style> as <style=cIsHealing>maximum reserve</style>."; pickup += $"\nStore <style=cIsHealing>{Configuration.BaseAbsorbMult.Value * 100f:0.##}%</style>{Stack(Configuration.AddedAbsorbMult.Value)}"; pickup += " of healing as <style=cIsHealing>reserve</style>."; pickup += $"\nCan <style=cIsHealing>heal</style> for <style=cIsHealing>{Configuration.BaseMaxUsageRate.Value * 100f:0.##}%</style>{Stack(Configuration.StackMaxUsageRate.Value)}"; pickup += " of your <style=cIsHealing>maximum health</style> every second from <style=cIsHealing>reserve</style>."; if (Configuration.VanillaUsageBehavior.Value) { pickup += "\n<style=cStack>(Additional stacks further reduce healing rate)</style>"; } float value = Configuration.BaseExportMult.Value; float value2 = Configuration.AddedExportMult.Value; if (value != 1f || value2 != 0f) { string text = ((value2 != 0f) ? ((!(value2 > 0f)) ? ((value > 1f) ? "cIsDamage" : "cDeath") : ((value >= 1f) ? "cIsHealing" : "cIsDamage")) : ((value > 1f) ? "cIsHealing" : "cDeath")); pickup += string.Format("\n\n<style={0}>{1}{2:0.##}%</style>{3} Healing Multiplier.", text, (value >= 1f) ? "+" : "", (value - 1f) * 100f, Stack(value2)); } return pickup; } } public static class Configuration { public static ConfigEntry<bool> HideReserveBuff; public static ConfigEntry<bool> HealBeforeReserve; public static ConfigEntry<bool> HealWhenReserveFull; public static ConfigEntry<float> BaseAbsorbMult; public static ConfigEntry<float> AddedAbsorbMult; public static ConfigEntry<float> BaseExportMult; public static ConfigEntry<float> AddedExportMult; public static ConfigEntry<int> AegisInteraction; public static ConfigEntry<bool> RestoreRejuvBehavior; public static ConfigEntry<float> BaseHealthReserve; public static ConfigEntry<float> AddedHealthReserve; public static ConfigEntry<bool> VanillaUsageBehavior; public static ConfigEntry<float> BaseMaxUsageRate; public static ConfigEntry<float> StackMaxUsageRate; public static ConfigEntry<float> BaseMinUsageRate; public static ConfigEntry<float> StackMinUsageRate; internal static void Init(ConfigFile Config) { HideReserveBuff = Config.Bind<bool>("General", "HideReserveBuff", true, "Set CBReserve buff as hidden, preventing it from being drawn on your active buffs bar."); HealBeforeReserve = Config.Bind<bool>("General", "HealBeforeReserve", false, "If incoming healing should apply to health before going into reserve."); HealWhenReserveFull = Config.Bind<bool>("General", "HealWhenReserveFull", false, "If incoming healing should apply to health after reserve is full."); BaseAbsorbMult = Config.Bind<float>("General", "BaseAbsorbMult", 2f, "Reserve absorption. Base effectiveness of healing going into reserve."); AddedAbsorbMult = Config.Bind<float>("General", "AddedAbsorbMult", 1f, "Increased absorption effect per stack."); BaseExportMult = Config.Bind<float>("General", "BaseExportMult", 1f, "Base effectiveness of healing coming out of reserve."); AddedExportMult = Config.Bind<float>("General", "AddedExportMult", 0f, "Increased healing effect per stack."); AegisInteraction = Config.Bind<int>("General", "AegisInteraction", 1, "How does Aegis affect usage rate. 0 = No Effect, 1 = MaxUsage at MinBarrier / MinUsage at MaxBarrier, 2 = Always MaxUsage. Chooses highest between this and amount going to health (amount going to health is highest between MinUsage and HealMissingHealth capped at MaxUsage)."); RestoreRejuvBehavior = Config.Bind<bool>("General", "RestoreRejuvBehavior", false, "Most healing multipliers used to apply twice when used with Corpsebloom. Set to true to restore this behavior for Rejuvenation Rack."); BaseHealthReserve = Config.Bind<float>("General", "BaseHealthReserve", 1f, "Base reserve gained from health."); AddedHealthReserve = Config.Bind<float>("General", "AddedHealthReserve", 0.5f, "Added reserve gained from health per stack."); VanillaUsageBehavior = Config.Bind<bool>("General", "VanillaUsageBehavior", false, "Scale reserve outputs by 1 / stack count."); BaseMaxUsageRate = Config.Bind<float>("General", "BaseMaxUsageRate", 0.1f, "Base maximum healing output from reserve per second."); StackMaxUsageRate = Config.Bind<float>("General", "StackMaxUsageRate", 0f, "Stack maximum healing output from reserve per second."); BaseMinUsageRate = Config.Bind<float>("General", "BaseMinUsageRate", 0.05f, "Base minimum healing output from reserve per second. Set to 0 to disable reserve decay."); StackMinUsageRate = Config.Bind<float>("General", "StackMinUsageRate", 0f, "Stack minimum healing output from reserve per second."); } } public class ReserveBar : MonoBehaviour { private const float Height = 0.32f; public HealthBar healthBar; private RectTransform bar; private void LateUpdate() { //IL_00ea: Unknown result type (might be due to invalid IL or missing references) float num = 0f; HealthComponent source = healthBar.source; if (Object.op_Implicit((Object)(object)source) && Object.op_Implicit((Object)(object)source.body)) { int buffCount = source.body.GetBuffCount(CorpseBloomRebornHCPlugin.ReserveBuff); if (buffCount > 0) { num = (float)buffCount / 100f * source.fullHealth / source.fullCombinedHealth / source.body.cursePenalty; } } if (num <= 0f) { if (Object.op_Implicit((Object)(object)bar) && ((Component)bar).gameObject.activeSelf) { ((Component)bar).gameObject.SetActive(false); } return; } if (!Object.op_Implicit((Object)(object)bar)) { bar = CreateBar(); } if (!((Component)bar).gameObject.activeSelf) { ((Component)bar).gameObject.SetActive(true); } bar.anchorMax = new Vector2(Mathf.Min(num, 1f), 0.32f); if (((Transform)bar).GetSiblingIndex() != ((Transform)bar).parent.childCount - 1) { ((Transform)bar).SetAsLastSibling(); } } private RectTransform CreateBar() { //IL_0025: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0051: 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_0066: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown RectTransform val = (RectTransform)new GameObject("CorpseBloomReserve", new Type[2] { typeof(RectTransform), typeof(Image) }).transform; ((Transform)val).SetParent((Transform)(object)healthBar.barContainer, false); val.anchorMin = Vector2.zero; val.anchorMax = new Vector2(0f, 0.32f); Vector2 offsetMin = (val.offsetMax = Vector2.zero); val.offsetMin = offsetMin; Image component = ((Component)val).GetComponent<Image>(); ((Graphic)component).color = new Color(0.625f, 0.25f, 1f, 0.65f); ((Graphic)component).raycastTarget = false; return val; } } public class ReserveBehavior : MonoBehaviour { private const float Interval = 0.25f; public float reserve; private CharacterBody body; private HealthComponent healthComponent; private float timer = 0.25f; private float healthMult; private float maxRate; private float minRate; private float absorbMult; private float exportMult; private int aegisState; private float Maximum => Mathf.Max(1f, healthComponent.fullHealth * healthMult); internal static void OnInventoryChanged(CharacterBody body) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { return; } int num = (Object.op_Implicit((Object)(object)body.inventory) ? body.inventory.GetItemCountEffective(Items.RepeatHeal) : 0); ReserveBehavior reserveBehavior = ((Component)body).GetComponent<ReserveBehavior>(); if (num > 0) { if (!Object.op_Implicit((Object)(object)reserveBehavior)) { reserveBehavior = ((Component)body).gameObject.AddComponent<ReserveBehavior>(); } reserveBehavior.Recalculate(body, num); } else if (Object.op_Implicit((Object)(object)reserveBehavior)) { Object.Destroy((Object)(object)reserveBehavior); body.SetBuffCount(CorpseBloomRebornHCPlugin.ReserveBuff.buffIndex, 0); } } private void Recalculate(CharacterBody body, int count) { this.body = body; healthComponent = body.healthComponent; Inventory inventory = body.inventory; int num = count - 1; healthMult = Mathf.Max(0.1f, Configuration.BaseHealthReserve.Value + Configuration.AddedHealthReserve.Value * (float)num); minRate = Mathf.Max(0f, Configuration.BaseMinUsageRate.Value + Configuration.StackMinUsageRate.Value * (float)num); maxRate = Mathf.Max(new float[3] { 0.01f, minRate, Configuration.BaseMaxUsageRate.Value + Configuration.StackMaxUsageRate.Value * (float)num }); if (Configuration.VanillaUsageBehavior.Value) { minRate /= count; maxRate = Mathf.Max(0.01f, maxRate / (float)count); } absorbMult = Mathf.Max(0.1f, Configuration.BaseAbsorbMult.Value + Configuration.AddedAbsorbMult.Value * (float)num); exportMult = Mathf.Max(0.1f, Configuration.BaseExportMult.Value + Configuration.AddedExportMult.Value * (float)num); if (Configuration.RestoreRejuvBehavior.Value) { absorbMult *= 1 + inventory.GetItemCountEffective(Items.IncreaseHealing); } aegisState = ((inventory.GetItemCountEffective(Items.BarrierOnOverHeal) > 0) ? Configuration.AegisInteraction.Value : 0); } public void AddReserve(float amount) { float num = 0f; if (Configuration.HealBeforeReserve.Value) { num = Mathf.Min(amount, (healthComponent.fullHealth - healthComponent.health) / exportMult); amount -= num; } float maximum = Maximum; float num2 = Mathf.Min(amount, Mathf.Max(0f, maximum - reserve) / absorbMult); amount -= num2; if (Configuration.HealWhenReserveFull.Value) { num += amount; } reserve = Mathf.Min(reserve + num2 * absorbMult, maximum); if (num > 0f) { HealFromReserve(num); } } private void HealFromReserve(float amount) { //IL_0002: 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) ProcChainMask val = default(ProcChainMask); ((ProcChainMask)(ref val)).AddProc((ProcType)13); healthComponent.Heal(amount * exportMult, val, true); } private void FixedUpdate() { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)healthComponent) || !healthComponent.alive) { return; } timer -= Time.fixedDeltaTime; if (!(timer > 0f)) { timer = 0.25f; float maximum = Maximum; reserve = Mathf.Min(reserve, maximum); if (!Paused()) { float num = HealAmount(); reserve -= num; HealFromReserve(num); } int num2 = ((reserve > 0f) ? Mathf.Clamp(Mathf.RoundToInt(reserve / maximum * 100f), 1, 100) : 0); if (body.GetBuffCount(CorpseBloomRebornHCPlugin.ReserveBuff) != num2) { body.SetBuffCount(CorpseBloomRebornHCPlugin.ReserveBuff.buffIndex, num2); } } } private bool Paused() { if (reserve <= 0f || body.HasBuff(Buffs.HealingDisabled)) { return true; } if (minRate > 0f || aegisState > 0) { return false; } return healthComponent.health >= healthComponent.fullHealth; } private float HealAmount() { float fullHealth = healthComponent.fullHealth; float num = fullHealth * maxRate * 0.25f; if (aegisState >= 2) { return Mathf.Min(reserve, num); } float num2 = fullHealth * minRate * 0.25f; float num3 = Mathf.Max(num2, (fullHealth - healthComponent.health) / exportMult); if (aegisState == 1) { num3 = Mathf.Max(num3, Mathf.Lerp(num, num2, healthComponent.barrier / healthComponent.fullBarrier)); } return Mathf.Min(new float[3] { reserve, num, num3 }); } } }