Decompiled source of EnemyMutations v1.0.0

EnemyMutations.dll

Decompiled 3 weeks ago
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<float> BaseMutationChance;

		public static ConfigEntry<float> ChanceScalingPerStage;

		public static ConfigEntry<bool> AllowBossMutations;

		public static ConfigEntry<bool> AllowEliteMutations;

		public static ConfigEntry<bool> EnableGiant;

		public static ConfigEntry<bool> EnableTiny;

		public static ConfigEntry<bool> EnableFrenzied;

		public static ConfigEntry<bool> EnableVolatile;

		public static ConfigEntry<bool> EnableTreasure;

		public static ConfigEntry<float> TreasureChance;

		public static ConfigEntry<bool> AnnounceTreasure;

		public static ConfigEntry<float> VolatileBlastDamage;

		public static ConfigEntry<float> VolatileBlastRadius;

		public static ConfigEntry<bool> 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<float>("General", "BaseMutationChance", 12f, new ConfigDescription("Percent chance an enemy spawns mutated on stage 1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			ChanceScalingPerStage = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ChanceScalingPerStage", 2f, new ConfigDescription("Percent added to the mutation chance per stage cleared.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
			AllowBossMutations = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowBossMutations", false, "Whether teleporter and world bosses can roll mutations.");
			AllowEliteMutations = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowEliteMutations", true, "Whether elite enemies can roll mutations on top of their elite affix.");
			EnableGiant = ((BaseUnityPlugin)this).Config.Bind<bool>("Mutations", "EnableGiant", true, "Larger, slower, tankier, more rewarding. Mini-boss moments.");
			EnableTiny = ((BaseUnityPlugin)this).Config.Bind<bool>("Mutations", "EnableTiny", true, "Smaller, faster, harder to hit, less health, small reward bonus.");
			EnableFrenzied = ((BaseUnityPlugin)this).Config.Bind<bool>("Mutations", "EnableFrenzied", true, "Much faster movement and attacks, reduced health. Kill it quickly.");
			EnableVolatile = ((BaseUnityPlugin)this).Config.Bind<bool>("Mutations", "EnableVolatile", true, "Explodes on death. Watch your positioning and kill timing.");
			EnableTreasure = ((BaseUnityPlugin)this).Config.Bind<bool>("Mutations", "EnableTreasure", true, "Rare: tanky, dangerous, drops massively increased gold.");
			TreasureChance = ((BaseUnityPlugin)this).Config.Bind<float>("Mutations", "TreasureChance", 10f, new ConfigDescription("When a mutation rolls, percent chance it upgrades to the rare Treasure mutation.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			AnnounceTreasure = ((BaseUnityPlugin)this).Config.Bind<bool>("Mutations", "AnnounceTreasure", true, "Post a chat message when a Treasure enemy spawns.");
			VolatileBlastDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Mutations", "VolatileBlastDamage", 15f, new ConfigDescription("Volatile death explosion damage as a multiple of the enemy's base damage.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			VolatileBlastRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Mutations", "VolatileBlastRadius", 12f, new ConfigDescription("Volatile death explosion radius in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 40f), Array.Empty<object>()));
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("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<SizeMarker>();
				if (!Object.op_Implicit((Object)(object)sizeMarker))
				{
					sizeMarker = go.AddComponent<SizeMarker>();
					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<MutationMarker>()) || (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<MutationType> list = new List<MutationType>();
				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>();
				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("<color=#ffd700>A Treasure " + self.GetDisplayName() + " has appeared!</color>");
					}
					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<MutationMarker>() : 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<MutationMarker>();
			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<GameObject>("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<MutationMarker>() : 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";
	}
}