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 RexEnhancements v1.0.1
RexEnhancements.dll
Decompiled an hour agousing System; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using EntityStates.Treebot; using EntityStates.Treebot.Weapon; using On.EntityStates.Treebot; using On.EntityStates.Treebot.Weapon; using On.RoR2; using R2API; using RoR2; using RoR2.Projectile; using RoR2.Skills; 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("RexEnhancements")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0a0c35b111d7a92f4e395054c60dd8e097f717b0")] [assembly: AssemblyProduct("RexEnhancements")] [assembly: AssemblyTitle("RexEnhancements")] [assembly: AssemblyVersion("1.0.0.0")] namespace RexEnhancements; [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.Sagittariod.RexEnhancements", "Rex Enhancements", "1.0.0")] public class RexEnhancementsPlugin : BaseUnityPlugin { public class MortarHitTracker : MonoBehaviour { public int hits = 0; } public class ConvalescenceController : MonoBehaviour { public CharacterBody body; public BuffDef buffDef; public float remainingTime = 0f; private void Awake() { body = ((Component)this).GetComponent<CharacterBody>(); } public void AddStack() { if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)buffDef)) { int buffCount = body.GetBuffCount(buffDef); float num = 9f * Mathf.Pow(0.815f, (float)buffCount); remainingTime += num; UpdateBuffStacks(); } } private void FixedUpdate() { if (remainingTime > 0f) { remainingTime -= Time.fixedDeltaTime; if (remainingTime <= 0f) { remainingTime = 0f; ClearBuffs(); Object.Destroy((Object)(object)this); } else { UpdateBuffStacks(); } } } private void UpdateBuffStacks() { if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)buffDef)) { int stacksForTime = GetStacksForTime(remainingTime); int i; for (i = body.GetBuffCount(buffDef); i < stacksForTime; i++) { body.AddBuff(buffDef); } while (i > stacksForTime) { body.RemoveBuff(buffDef); i--; } } } private void ClearBuffs() { if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)buffDef)) { for (int num = body.GetBuffCount(buffDef); num > 0; num--) { body.RemoveBuff(buffDef); } } } public static int GetStacksForTime(float t) { if (t <= 0f) { return 0; } int num = 0; float num2 = 0f; float num3 = 10f; while (t > num2) { num++; num2 += num3; num3 *= 0.815f; if (num > 100) { break; } } return num; } } public static ConfigEntry<float> maxBonusDamage; public static ConfigEntry<float> maxBonusArmor; public static ConfigEntry<bool> disperseCooldownReduction; public static ConfigEntry<float> brambleVolleyDamage; public static ConfigEntry<float> disperseCooldown; public static ConfigEntry<bool> harvestEndlagReduction; public static ConfigEntry<float> injectProcCoefficient; public static ConfigEntry<float> injectDamage; public static ConfigEntry<bool> enableNewPassive; public static ConfigEntry<bool> enableConvalescenceBuff; public static BuffDef curseCleanserBuff; public void Awake() { //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) enableNewPassive = ((BaseUnityPlugin)this).Config.Bind<bool>("Passive", "Enable New Passive", true, "If true, grants a new passive which increases armor and damage based on missing health"); maxBonusDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Passive", "Max Bonus Damage", 0.3f, "Maximum percentage damage increase granted when at minimum health"); maxBonusArmor = ((BaseUnityPlugin)this).Config.Bind<float>("Passive", "Max Bonus Armor", 50f, "Maximum armor increase granted when at minimum health"); harvestEndlagReduction = ((BaseUnityPlugin)this).Config.Bind<bool>("Existing Skills", "Enable Faster Harvest", true, "If true, halves the endlag of DIRECTIVE: HARVEST"); injectProcCoefficient = ((BaseUnityPlugin)this).Config.Bind<float>("Existing Skills", "DIRECTIVE - Inject Proc Coefficient", 0.8f, "Proc coefficient for DIRECTIVE: INJECT"); brambleVolleyDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Skills - Utility", "Bramble Volley Damage", 10f, "Damage coefficient for Bramble Volley"); disperseCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Skills - Utility", "Directive Disperse Cooldown", 4.5f, "Base cooldown in seconds for Directive: DISPERSE"); injectDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Existing Skills", "DIRECTIVE - Inject Damage", 0.9f, "Damage coefficient for DIRECTIVE: INJECT"); enableConvalescenceBuff = ((BaseUnityPlugin)this).Config.Bind<bool>("Existing Skills", "Enable Convalescence Buff", true, "If true, specific abilities grant the Convalescence buff which temporarily reduce Curse"); CharacterBody.RecalculateStats += new hook_RecalculateStats(CharacterBody_RecalculateStats); TreebotFireFruitSeed.OnEnter += new hook_OnEnter(TreebotFireFruitSeed_OnEnter); FireSyringe.OnEnter += new hook_OnEnter(FireSyringe_OnEnter); GlobalEventManager.OnHitEnemy += new hook_OnHitEnemy(GlobalEventManager_OnHitEnemy); FirePlantSonicBoom.OnEnter += new hook_OnEnter(FirePlantSonicBoom_OnEnter); Addressables.LoadAssetAsync<SkillDef>((object)"RoR2/Base/Treebot/TreebotBodySonicBoom.asset").WaitForCompletion().baseRechargeInterval = disperseCooldown.Value; ModifyPrefabs(); UpdateMiscLanguage(); UpdateInjectDescription(); UpdateBrambleVolleyDescription(); SetupConvalescenceKeyword(); SetupBuff(); } private void UpdateInjectDescription() { string text = "TREEBOT_PRIMARY_DESCRIPTION"; string text2 = $"Fire 3 syringes for <style=cIsDamage>3x{injectDamage.Value * 100f}% damage</style>. The last syringe <style=cIsDamage>Weakens</style> and <style=cIsHealing>heals for 60% of damage dealt</style>."; LanguageAPI.Add(text, text2); } private void UpdateBrambleVolleyDescription() { string text = "TREEBOT_UTILITY_ALT1_DESCRIPTION"; string text2 = $"<style=cIsHealth>20% HP</style>. Fire a <style=cIsUtility>Sonic Boom</style> that damages enemies for <style=cIsDamage>{brambleVolleyDamage.Value * 100f}% damage</style>. <style=cIsHealing>Heals for every target hit</style>."; LanguageAPI.Add(text, text2); } private void UpdateMiscLanguage() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) string text = "TREEBOT_PASSIVE_NAME"; string text2 = "TREEBOT_PASSIVE_DESCRIPTION"; string text3 = "TREEBOT_SPECIAL_DESCRIPTION"; string text4 = "TREEBOT_SPECIAL_ALT1_DESCRIPTION"; string text5 = "TREEBOT_SECONDARY_DESCRIPTION"; string text6 = "TREEBOT_SECONDARY_ALT1_DESCRIPTION"; GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/Treebot/TreebotBody.prefab").WaitForCompletion(); SkillLocator component = val.GetComponent<SkillLocator>(); if (enableNewPassive.Value) { LanguageAPI.Add(text, "Adaptive Plating"); LanguageAPI.Add(text2, $"Gain up to <style=cIsUtility>50 armor</style> and deal up to <style=cIsDamage>+{maxBonusDamage.Value * 100f}% damage</style> based on your <style=cIsHealth>missing health</style>."); if ((Object)(object)component != (Object)null) { component.passiveSkill.keywordToken = string.Empty; } } else { LanguageAPI.Add(text, "Natural Toxins"); LanguageAPI.Add(text2, "Certain attacks <style=cIsDamage>Weaken</style> enemies hit, reducing their movement speed, armor, and damage."); } if (enableConvalescenceBuff.Value) { LanguageAPI.Add(text3, "<style=cIsHealth>25% HP</style>. Fire a flower that <style=cIsDamage>roots</style> for <style=cIsDamage>200% damage</style>. <style=cIsHealing>Heals for every target hit</style>. <style=cIsUtility>Direct hits grant Convalescence.</style>"); LanguageAPI.Add(text4, "Fire a bolt that deals <style=cIsDamage>330% damage</style> and <style=cIsDamage>injects</style> an enemy. On death, drop multiple <style=cIsHealing>healing fruits</style> that heal for <style=cIsHealing>25% HP</style>. <style=cIsUtility>Direct hits grant Convalescence.</style>"); LanguageAPI.Add(text6, "Launch a series of seed bullets into the sky, raining down for <style=cIsDamage>450% damage per second</style>. <style=cIsUtility>Every 4 hits grants Convalescence.</style>"); LanguageAPI.Add(text5, "<style=cIsHealth>15% HP</style>. Launch a mortar into the sky for <style=cIsDamage>450% damage</style>. <style=cIsUtility>Each hit grants Convalescence.</style>"); } else { LanguageAPI.Add(text3, "<style=cIsHealth>25% HP</style>. Fire a flower that <style=cIsDamage>roots</style> for <style=cIsDamage>200% damage</style>. <style=cIsHealing>Heals for every target hit</style>."); LanguageAPI.Add(text4, "Fire a bolt that deals <style=cIsDamage>330% damage</style> and <style=cIsDamage>injects</style> an enemy. On death, drop multiple <style=cIsHealing>healing fruits</style> that heal for <style=cIsHealing>25% HP</style>."); LanguageAPI.Add(text6, "Launch a series of seed bullets into the sky, raining down for <style=cIsDamage>450% damage per second</style>."); LanguageAPI.Add(text5, "<style=cIsHealth>15% HP</style>. Launch a mortar into the sky for <style=cIsDamage>450% damage</style>."); } } private void SetupConvalescenceKeyword() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) string keywordToken = "KEYWORD_CONVALESCENCE"; if (!enableConvalescenceBuff.Value) { return; } LanguageAPI.Add(keywordToken, "<style=cKeywordName>Convalescence</style><style=cSub>Reduces current <style=cIsHealth>Curse</style> by 15% per stack. Higher stacks have shorter durations.</style>"); GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/Treebot/TreebotBody.prefab").WaitForCompletion(); SkillLocator component = val.GetComponent<SkillLocator>(); Action<SkillFamily> action = delegate(SkillFamily family) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Variant[] variants = family.variants; foreach (Variant val2 in variants) { SkillDef skillDef = val2.skillDef; if ((Object)(object)skillDef != (Object)null && !skillDef.keywordTokens.Contains(keywordToken)) { skillDef.keywordTokens = skillDef.keywordTokens.Append(keywordToken).ToArray(); } } }; if ((Object)(object)component != (Object)null) { action(component.secondary.skillFamily); action(component.special.skillFamily); } } private void SetupBuff() { curseCleanserBuff = ScriptableObject.CreateInstance<BuffDef>(); ((Object)curseCleanserBuff).name = "Convalescence"; curseCleanserBuff.canStack = true; curseCleanserBuff.isDebuff = false; curseCleanserBuff.isHidden = false; curseCleanserBuff.iconSprite = LoadSpriteFromManifest("Convalescence.png"); ContentAddition.AddBuffDef(curseCleanserBuff); } private void GlobalEventManager_OnHitEnemy(orig_OnHitEnemy orig, GlobalEventManager self, DamageInfo damageInfo, GameObject victim) { orig.Invoke(self, damageInfo, victim); if (!enableConvalescenceBuff.Value || !((Object)(object)damageInfo.attacker != (Object)null)) { return; } CharacterBody component = damageInfo.attacker.GetComponent<CharacterBody>(); if (!((Object)(object)component != (Object)null) || !(component.baseNameToken == "TREEBOT_BODY_NAME")) { return; } bool flag = false; if ((Object)(object)damageInfo.inflictor != (Object)null) { string name = ((Object)damageInfo.inflictor).name; if (name.Contains("TreebotFruitSeed") || name.Contains("TreebotMortar2") || name.Contains("TreebotFlower")) { flag = true; } else if (name.Contains("TreebotMortar")) { MortarHitTracker mortarHitTracker = ((Component)component).GetComponent<MortarHitTracker>(); if ((Object)(object)mortarHitTracker == (Object)null) { mortarHitTracker = ((Component)component).gameObject.AddComponent<MortarHitTracker>(); } mortarHitTracker.hits++; if (mortarHitTracker.hits >= 4) { flag = true; mortarHitTracker.hits = 0; } } } if (flag) { ConvalescenceController convalescenceController = ((Component)component).GetComponent<ConvalescenceController>(); if ((Object)(object)convalescenceController == (Object)null) { convalescenceController = ((Component)component).gameObject.AddComponent<ConvalescenceController>(); convalescenceController.buffDef = curseCleanserBuff; } convalescenceController.AddStack(); } } private Sprite LoadSpriteFromManifest(string fileName) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_006a: 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) string name = "RexEnhancements." + fileName; using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name); 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); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } return null; } private void CharacterBody_RecalculateStats(orig_RecalculateStats orig, CharacterBody self) { orig.Invoke(self); if (self.baseNameToken == "TREEBOT_BODY_NAME" && (Object)(object)self.healthComponent != (Object)null) { if (enableNewPassive.Value && self.healthComponent.fullHealth > 0f) { float num = self.healthComponent.health / self.healthComponent.fullHealth; float num2 = 1f + maxBonusDamage.Value * (1f - num); float num3 = maxBonusArmor.Value * (1f - num); typeof(CharacterBody).GetProperty("damage").SetValue(self, self.damage * num2); typeof(CharacterBody).GetProperty("armor").SetValue(self, self.armor + num3); } int buffCount = self.GetBuffCount(curseCleanserBuff); if (buffCount > 0 && self.cursePenalty > 1f && enableConvalescenceBuff.Value) { float cursePenalty = self.cursePenalty; float num4 = self.maxHealth * cursePenalty; float num5 = num4 - self.maxHealth; float num6 = num5 * Mathf.Pow(0.85f, (float)buffCount); float num7 = num4 - num6; float num8 = num4 / num7; typeof(CharacterBody).GetProperty("maxHealth").SetValue(self, num7); typeof(CharacterBody).GetProperty("cursePenalty").SetValue(self, num8); } } } private void TreebotFireFruitSeed_OnEnter(orig_OnEnter orig, TreebotFireFruitSeed self) { if (harvestEndlagReduction.Value) { self.baseDuration = 0.5f; } orig.Invoke(self); } private void FirePlantSonicBoom_OnEnter(orig_OnEnter orig, FirePlantSonicBoom self) { FirePlantSonicBoom.damageCoefficient = brambleVolleyDamage.Value; orig.Invoke(self); } private void FireSyringe_OnEnter(orig_OnEnter orig, FireSyringe self) { FireSyringe.damageCoefficient = injectDamage.Value; orig.Invoke(self); } private void ModifyPrefabs() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_003e: Unknown result type (might be due to invalid IL or missing references) GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/Treebot/SyringeProjectile.prefab").WaitForCompletion(); if ((Object)(object)val != (Object)null) { val.GetComponent<ProjectileController>().procCoefficient = injectProcCoefficient.Value; } GameObject val2 = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/Treebot/SyringeProjectileHealing.prefab").WaitForCompletion(); if ((Object)(object)val2 != (Object)null) { val2.GetComponent<ProjectileController>().procCoefficient = injectProcCoefficient.Value; } } }