using 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(); } 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 maxBonusDamage; public static ConfigEntry maxBonusArmor; public static ConfigEntry disperseCooldownReduction; public static ConfigEntry brambleVolleyDamage; public static ConfigEntry disperseCooldown; public static ConfigEntry harvestEndlagReduction; public static ConfigEntry injectProcCoefficient; public static ConfigEntry injectDamage; public static ConfigEntry enableNewPassive; public static ConfigEntry 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("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("Passive", "Max Bonus Damage", 0.3f, "Maximum percentage damage increase granted when at minimum health"); maxBonusArmor = ((BaseUnityPlugin)this).Config.Bind("Passive", "Max Bonus Armor", 50f, "Maximum armor increase granted when at minimum health"); harvestEndlagReduction = ((BaseUnityPlugin)this).Config.Bind("Existing Skills", "Enable Faster Harvest", true, "If true, halves the endlag of DIRECTIVE: HARVEST"); injectProcCoefficient = ((BaseUnityPlugin)this).Config.Bind("Existing Skills", "DIRECTIVE - Inject Proc Coefficient", 0.8f, "Proc coefficient for DIRECTIVE: INJECT"); brambleVolleyDamage = ((BaseUnityPlugin)this).Config.Bind("Skills - Utility", "Bramble Volley Damage", 10f, "Damage coefficient for Bramble Volley"); disperseCooldown = ((BaseUnityPlugin)this).Config.Bind("Skills - Utility", "Directive Disperse Cooldown", 4.5f, "Base cooldown in seconds for Directive: DISPERSE"); injectDamage = ((BaseUnityPlugin)this).Config.Bind("Existing Skills", "DIRECTIVE - Inject Damage", 0.9f, "Damage coefficient for DIRECTIVE: INJECT"); enableConvalescenceBuff = ((BaseUnityPlugin)this).Config.Bind("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((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 3x{injectDamage.Value * 100f}% damage. The last syringe Weakens and heals for 60% of damage dealt."; LanguageAPI.Add(text, text2); } private void UpdateBrambleVolleyDescription() { string text = "TREEBOT_UTILITY_ALT1_DESCRIPTION"; string text2 = $"20% HP. Fire a Sonic Boom that damages enemies for {brambleVolleyDamage.Value * 100f}% damage. Heals for every target hit."; 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((object)"RoR2/Base/Treebot/TreebotBody.prefab").WaitForCompletion(); SkillLocator component = val.GetComponent(); if (enableNewPassive.Value) { LanguageAPI.Add(text, "Adaptive Plating"); LanguageAPI.Add(text2, $"Gain up to 50 armor and deal up to +{maxBonusDamage.Value * 100f}% damage based on your missing health."); if ((Object)(object)component != (Object)null) { component.passiveSkill.keywordToken = string.Empty; } } else { LanguageAPI.Add(text, "Natural Toxins"); LanguageAPI.Add(text2, "Certain attacks Weaken enemies hit, reducing their movement speed, armor, and damage."); } if (enableConvalescenceBuff.Value) { LanguageAPI.Add(text3, "25% HP. Fire a flower that roots for 200% damage. Heals for every target hit. Direct hits grant Convalescence."); LanguageAPI.Add(text4, "Fire a bolt that deals 330% damage and injects an enemy. On death, drop multiple healing fruits that heal for 25% HP. Direct hits grant Convalescence."); LanguageAPI.Add(text6, "Launch a series of seed bullets into the sky, raining down for 450% damage per second. Every 4 hits grants Convalescence."); LanguageAPI.Add(text5, "15% HP. Launch a mortar into the sky for 450% damage. Each hit grants Convalescence."); } else { LanguageAPI.Add(text3, "25% HP. Fire a flower that roots for 200% damage. Heals for every target hit."); LanguageAPI.Add(text4, "Fire a bolt that deals 330% damage and injects an enemy. On death, drop multiple healing fruits that heal for 25% HP."); LanguageAPI.Add(text6, "Launch a series of seed bullets into the sky, raining down for 450% damage per second."); LanguageAPI.Add(text5, "15% HP. Launch a mortar into the sky for 450% damage."); } } 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, "ConvalescenceReduces current Curse by 15% per stack. Higher stacks have shorter durations."); GameObject val = Addressables.LoadAssetAsync((object)"RoR2/Base/Treebot/TreebotBody.prefab").WaitForCompletion(); SkillLocator component = val.GetComponent(); Action 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(); ((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(); 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(); if ((Object)(object)mortarHitTracker == (Object)null) { mortarHitTracker = ((Component)component).gameObject.AddComponent(); } mortarHitTracker.hits++; if (mortarHitTracker.hits >= 4) { flag = true; mortarHitTracker.hits = 0; } } } if (flag) { ConvalescenceController convalescenceController = ((Component)component).GetComponent(); if ((Object)(object)convalescenceController == (Object)null) { convalescenceController = ((Component)component).gameObject.AddComponent(); 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((object)"RoR2/Base/Treebot/SyringeProjectile.prefab").WaitForCompletion(); if ((Object)(object)val != (Object)null) { val.GetComponent().procCoefficient = injectProcCoefficient.Value; } GameObject val2 = Addressables.LoadAssetAsync((object)"RoR2/Base/Treebot/SyringeProjectileHealing.prefab").WaitForCompletion(); if ((Object)(object)val2 != (Object)null) { val2.GetComponent().procCoefficient = injectProcCoefficient.Value; } } }