using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using Microsoft.CodeAnalysis; using On.RoR2; using RoR2; using UnityEngine; using UnityEngine.Networking; using UnityEngine.SceneManagement; [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("EnemyMutations")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EnemyMutations")] [assembly: AssemblyTitle("EnemyMutations")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 EnemyMutations { [BepInPlugin("dileppy.enemymutations", "EnemyMutations", "1.0.0")] public class EnemyMutationsPlugin : BaseUnityPlugin { public enum MutationType { None, Giant, Tiny, Frenzied, Volatile, Treasure } public class MutationMarker : MonoBehaviour { public MutationType type; public float rewardMult = 1f; } private class SizeMarker : MonoBehaviour { public Vector3 baseScale; } public const string PluginGUID = "dileppy.enemymutations"; public const string PluginName = "EnemyMutations"; public const string PluginVersion = "1.0.0"; public static ConfigEntry BaseMutationChance; public static ConfigEntry ChanceScalingPerStage; public static ConfigEntry AllowBossMutations; public static ConfigEntry AllowEliteMutations; public static ConfigEntry EnableGiant; public static ConfigEntry EnableTiny; public static ConfigEntry EnableFrenzied; public static ConfigEntry EnableVolatile; public static ConfigEntry EnableTreasure; public static ConfigEntry TreasureChance; public static ConfigEntry AnnounceTreasure; public static ConfigEntry VolatileBlastDamage; public static ConfigEntry VolatileBlastRadius; public static ConfigEntry DebugLogging; private static readonly Random rng = new Random(); private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Expected O, but got Unknown //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Expected O, but got Unknown //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Expected O, but got Unknown //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Expected O, but got Unknown BaseMutationChance = ((BaseUnityPlugin)this).Config.Bind("General", "BaseMutationChance", 12f, new ConfigDescription("Percent chance an enemy spawns mutated on stage 1.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ChanceScalingPerStage = ((BaseUnityPlugin)this).Config.Bind("General", "ChanceScalingPerStage", 2f, new ConfigDescription("Percent added to the mutation chance per stage cleared.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20f), Array.Empty())); AllowBossMutations = ((BaseUnityPlugin)this).Config.Bind("General", "AllowBossMutations", false, "Whether teleporter and world bosses can roll mutations."); AllowEliteMutations = ((BaseUnityPlugin)this).Config.Bind("General", "AllowEliteMutations", true, "Whether elite enemies can roll mutations on top of their elite affix."); EnableGiant = ((BaseUnityPlugin)this).Config.Bind("Mutations", "EnableGiant", true, "Larger, slower, tankier, more rewarding. Mini-boss moments."); EnableTiny = ((BaseUnityPlugin)this).Config.Bind("Mutations", "EnableTiny", true, "Smaller, faster, harder to hit, less health, small reward bonus."); EnableFrenzied = ((BaseUnityPlugin)this).Config.Bind("Mutations", "EnableFrenzied", true, "Much faster movement and attacks, reduced health. Kill it quickly."); EnableVolatile = ((BaseUnityPlugin)this).Config.Bind("Mutations", "EnableVolatile", true, "Explodes on death. Watch your positioning and kill timing."); EnableTreasure = ((BaseUnityPlugin)this).Config.Bind("Mutations", "EnableTreasure", true, "Rare: tanky, dangerous, drops massively increased gold."); TreasureChance = ((BaseUnityPlugin)this).Config.Bind("Mutations", "TreasureChance", 10f, new ConfigDescription("When a mutation rolls, percent chance it upgrades to the rare Treasure mutation.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); AnnounceTreasure = ((BaseUnityPlugin)this).Config.Bind("Mutations", "AnnounceTreasure", true, "Post a chat message when a Treasure enemy spawns."); VolatileBlastDamage = ((BaseUnityPlugin)this).Config.Bind("Mutations", "VolatileBlastDamage", 15f, new ConfigDescription("Volatile death explosion damage as a multiple of the enemy's base damage.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); VolatileBlastRadius = ((BaseUnityPlugin)this).Config.Bind("Mutations", "VolatileBlastRadius", 12f, new ConfigDescription("Volatile death explosion radius in meters.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 40f), Array.Empty())); DebugLogging = ((BaseUnityPlugin)this).Config.Bind("Advanced", "DebugLogging", false, "Log every mutation roll to the console."); CharacterBody.Start += new hook_Start(CharacterBody_Start); CharacterBody.RecalculateStats += new hook_RecalculateStats(CharacterBody_RecalculateStats); DeathRewards.OnKilledServer += new hook_OnKilledServer(DeathRewards_OnKilledServer); GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath; ((BaseUnityPlugin)this).Logger.LogInfo((object)"EnemyMutations v1.0.0 loaded. Part of The Petrichor Protocol."); } private void OnDestroy() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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 CharacterBody.Start -= new hook_Start(CharacterBody_Start); CharacterBody.RecalculateStats -= new hook_RecalculateStats(CharacterBody_RecalculateStats); DeathRewards.OnKilledServer -= new hook_OnKilledServer(DeathRewards_OnKilledServer); GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath; } private static bool IsHostileEnemy(CharacterBody body) { //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) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.teamComponent)) { return false; } TeamIndex teamIndex = body.teamComponent.teamIndex; if ((int)teamIndex != 2 && (int)teamIndex != 3) { return (int)teamIndex == 4; } return true; } private static void ApplyAbsoluteScale(GameObject go, float factor) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_004d: 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_003b: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)go)) { return; } Scene scene = go.scene; if (((Scene)(ref scene)).IsValid()) { SizeMarker sizeMarker = go.GetComponent(); if (!Object.op_Implicit((Object)(object)sizeMarker)) { sizeMarker = go.AddComponent(); sizeMarker.baseScale = go.transform.localScale; } go.transform.localScale = sizeMarker.baseScale * factor; } } private void CharacterBody_Start(orig_Start orig, CharacterBody self) { orig.Invoke(self); if (!NetworkServer.active || !IsHostileEnemy(self) || Object.op_Implicit((Object)(object)((Component)self).GetComponent()) || (self.isBoss && !AllowBossMutations.Value) || (self.isElite && !AllowEliteMutations.Value)) { return; } try { int num = (Object.op_Implicit((Object)(object)Run.instance) ? Run.instance.stageClearCount : 0); float num2 = BaseMutationChance.Value + ChanceScalingPerStage.Value * (float)num; if (rng.NextDouble() * 100.0 > (double)num2) { return; } List list = new List(); if (EnableGiant.Value) { list.Add(MutationType.Giant); } if (EnableTiny.Value) { list.Add(MutationType.Tiny); } if (EnableFrenzied.Value) { list.Add(MutationType.Frenzied); } if (EnableVolatile.Value) { list.Add(MutationType.Volatile); } if (list.Count == 0 && !EnableTreasure.Value) { return; } MutationType mutationType; if (EnableTreasure.Value && rng.NextDouble() * 100.0 < (double)TreasureChance.Value) { mutationType = MutationType.Treasure; } else { if (list.Count <= 0) { return; } mutationType = list[rng.Next(list.Count)]; } MutationMarker mutationMarker = ((Component)self).gameObject.AddComponent(); mutationMarker.type = mutationType; switch (mutationType) { case MutationType.Giant: ApplyModelScale(self, 1.75f); mutationMarker.rewardMult = 2f; break; case MutationType.Tiny: ApplyModelScale(self, 0.5f); mutationMarker.rewardMult = 1.3f; break; case MutationType.Frenzied: ApplyModelScale(self, 0.9f); mutationMarker.rewardMult = 1.4f; break; case MutationType.Volatile: ApplyModelScale(self, 1.1f); mutationMarker.rewardMult = 1.5f; break; case MutationType.Treasure: ApplyModelScale(self, 1.2f); mutationMarker.rewardMult = 4f; if (AnnounceTreasure.Value) { Chat.AddMessage("A Treasure " + self.GetDisplayName() + " has appeared!"); } break; } self.RecalculateStats(); if (DebugLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0}: {1} rolled {2} (chance was {3:F0}%)", "EnemyMutations", self.GetDisplayName(), mutationType, num2)); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0}: mutation roll failed: {1}", "EnemyMutations", arg)); } } private static void ApplyModelScale(CharacterBody body, float factor) { ModelLocator modelLocator = body.modelLocator; if (Object.op_Implicit((Object)(object)modelLocator) && Object.op_Implicit((Object)(object)modelLocator.modelTransform)) { ApplyAbsoluteScale(((Component)modelLocator.modelTransform).gameObject, factor); } } private void CharacterBody_RecalculateStats(orig_RecalculateStats orig, CharacterBody self) { orig.Invoke(self); MutationMarker mutationMarker = (Object.op_Implicit((Object)(object)self) ? ((Component)self).GetComponent() : null); if (!((Object)(object)mutationMarker == (Object)null)) { switch (mutationMarker.type) { case MutationType.Giant: self.maxHealth *= 2f; self.damage *= 1.3f; self.moveSpeed *= 0.8f; break; case MutationType.Tiny: self.maxHealth *= 0.6f; self.moveSpeed *= 1.5f; self.attackSpeed *= 1.25f; break; case MutationType.Frenzied: self.maxHealth *= 0.75f; self.moveSpeed *= 1.5f; self.attackSpeed *= 1.5f; self.damage *= 1.1f; break; case MutationType.Volatile: self.maxHealth *= 0.9f; break; case MutationType.Treasure: self.maxHealth *= 2f; self.damage *= 1.25f; break; } } } private void OnCharacterDeath(DamageReport report) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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) //IL_0063: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown if (!NetworkServer.active || (Object)(object)report?.victimBody == (Object)null) { return; } MutationMarker component = ((Component)report.victimBody).GetComponent(); if ((Object)(object)component == (Object)null || component.type != MutationType.Volatile) { return; } try { new BlastAttack { attacker = ((Component)report.victimBody).gameObject, inflictor = ((Component)report.victimBody).gameObject, teamIndex = (TeamIndex)((!Object.op_Implicit((Object)(object)report.victimBody.teamComponent)) ? 2 : ((int)report.victimBody.teamComponent.teamIndex)), baseDamage = report.victimBody.baseDamage * VolatileBlastDamage.Value, baseForce = 800f, position = report.victimBody.corePosition, radius = VolatileBlastRadius.Value, falloffModel = (FalloffModel)1, attackerFiltering = (AttackerFiltering)2 }.Fire(); GameObject val = LegacyResourcesAPI.Load("Prefabs/Effects/OmniEffect/OmniExplosionVFX"); if (Object.op_Implicit((Object)(object)val)) { EffectManager.SpawnEffect(val, new EffectData { origin = report.victimBody.corePosition, scale = VolatileBlastRadius.Value }, true); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0}: volatile blast failed: {1}", "EnemyMutations", arg)); } } private void DeathRewards_OnKilledServer(orig_OnKilledServer orig, DeathRewards self, DamageReport damageReport) { MutationMarker mutationMarker = (Object.op_Implicit((Object)(object)damageReport?.victimBody) ? ((Component)damageReport.victimBody).GetComponent() : null); if ((Object)(object)mutationMarker != (Object)null && mutationMarker.rewardMult != 1f) { self.goldReward = (uint)((float)self.goldReward * mutationMarker.rewardMult); self.expReward = (uint)((float)self.expReward * mutationMarker.rewardMult); } orig.Invoke(self, damageReport); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "EnemyMutations"; public const string PLUGIN_NAME = "EnemyMutations"; public const string PLUGIN_VERSION = "1.0.0"; } }