Decompiled source of MobFriendlyFire v1.2.4

MobFriendlyFire.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("MobFriendlyFire")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MobFriendlyFire")]
[assembly: AssemblyTitle("MobFriendlyFire")]
[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 MobFriendlyFire
{
	[BepInPlugin("hergey.MobFriendlyFire", "MobFriendlyFire", "1.2.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "hergey.MobFriendlyFire";

		public const string Version = "1.2.4";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> DamageMultiplier;

		internal static ConfigEntry<float> HitChance;

		internal static ConfigEntry<bool> Projectiles;

		internal static ConfigEntry<bool> Explosions;

		internal static ConfigEntry<bool> ExemptBosses;

		internal static ConfigEntry<string> Excluded;

		internal static ConfigEntry<float> GrudgeChance;

		internal static ConfigEntry<float> GrudgeSeconds;

		private static HashSet<string> excludedNames = new HashSet<string>();

		private void Awake()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: 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_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Expected O, but got Unknown
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Expected O, but got Unknown
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, new ConfigDescription("Les coups des monstres sauvages blessent aussi leurs alliés (sans changer leurs cibles).", (AcceptableValueBase)null, new object[1] { val }));
			DamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "Damage multiplier", 0.6f, new ConfigDescription("Part des dégâts infligés à un allié (1 = 100 %, 0.5 = moitié).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), new object[1] { val }));
			HitChance = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "Hit chance", 1f, new ConfigDescription("Chance qu'un coup qui touche un allié le blesse vraiment (1 = toujours, 0.5 = une fois sur deux).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { val }));
			Projectiles = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Projectiles", true, new ConfigDescription("Flèches, pierres et autres projectiles de monstres touchent aussi leurs alliés.", (AcceptableValueBase)null, new object[1] { val }));
			Explosions = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Explosions", true, new ConfigDescription("Explosions et zones (poison, feu...) touchent aussi les monstres du même type que leur auteur.", (AcceptableValueBase)null, new object[1] { val }));
			ExemptBosses = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Exempt bosses", true, new ConfigDescription("Les boss ne blessent pas leurs alliés et ne prennent pas de dégâts de leurs alliés.", (AcceptableValueBase)null, new object[1] { val }));
			Excluded = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "Excluded creatures", "", new ConfigDescription("Noms de prefab exclus, séparés par des virgules (ex : Greydwarf_Shaman, Troll). Un monstre exclu ne blesse pas ses alliés et n'est pas blessé par eux.", (AcceptableValueBase)null, new object[1] { val }));
			GrudgeChance = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Grudge", "Chance", 0.2f, new ConfigDescription("Chance qu'un monstre blessé par un allié se retourne contre lui (0 = jamais, 1 = toujours).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { val }));
			GrudgeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Grudge", "Duration seconds", 8f, new ConfigDescription("Durée pendant laquelle le monstre rancunier traite l'allié qui l'a blessé comme un ennemi.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), new object[1] { val }));
			ParseExcluded();
			Excluded.SettingChanged += delegate
			{
				ParseExcluded();
			};
			new Harmony("hergey.MobFriendlyFire").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)(string.Format("MobFriendlyFire {0} chargé : actif={1}, dégâts={2:0.##}, chance={3:0.##}, ", "1.2.4", Enabled.Value, DamageMultiplier.Value, HitChance.Value) + $"projectiles={Projectiles.Value}, explosions={Explosions.Value}, boss exemptés={ExemptBosses.Value}, " + string.Format("rancune={0:0.##} ({1:0.#} s), exclus=[{2}]", GrudgeChance.Value, GrudgeSeconds.Value, string.Join(", ", excludedNames))));
		}

		private static void ParseExcluded()
		{
			excludedNames = new HashSet<string>(from s in Excluded.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
				select s.Trim() into s
				where s.Length > 0
				select s, StringComparer.OrdinalIgnoreCase);
		}

		internal static bool IsExcluded(Character c)
		{
			if (excludedNames.Count > 0)
			{
				return excludedNames.Contains(Utils.GetPrefabName(((Component)c).gameObject));
			}
			return false;
		}

		internal static bool IsWildMob(Character c)
		{
			if (Enabled.Value && (Object)(object)c != (Object)null && !c.IsPlayer() && !c.IsTamed() && (!ExemptBosses.Value || !c.IsBoss()))
			{
				return !IsExcluded(c);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Attack))]
	internal static class AttackPatch
	{
		private static readonly FieldRef<Attack, Humanoid> AttackerRef = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character");

		[HarmonyPrefix]
		[HarmonyPatch("DoMeleeAttack")]
		private static void MeleePrefix(Attack __instance)
		{
			Apply(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch("DoAreaAttack")]
		private static void AreaPrefix(Attack __instance)
		{
			Apply(__instance);
		}

		private static void Apply(Attack attack)
		{
			if (Plugin.IsWildMob((Character)(object)AttackerRef.Invoke(attack)))
			{
				attack.m_hitFriendly = true;
			}
		}
	}
	[HarmonyPatch(typeof(Projectile), "Setup")]
	internal static class ProjectilePatch
	{
		private static void Postfix(Projectile __instance, Character owner)
		{
			if (Plugin.Projectiles.Value && Plugin.IsWildMob(owner))
			{
				__instance.m_hitFriendly = true;
				__instance.m_noDamageFriendly = false;
			}
		}
	}
	[HarmonyPatch(typeof(Aoe), "Setup")]
	internal static class AoePatch
	{
		private static void Postfix(Aoe __instance, Character owner)
		{
			if (Plugin.Explosions.Value && Plugin.IsWildMob(owner))
			{
				__instance.m_hitFriendly = true;
				__instance.m_hitSame = true;
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class DamagePatch
	{
		private static bool Prefix(Character __instance, HitData hit)
		{
			if (!Plugin.Enabled.Value || hit == null || __instance.IsPlayer())
			{
				return true;
			}
			Character attacker = hit.GetAttacker();
			if ((Object)(object)attacker == (Object)null || (Object)(object)attacker == (Object)(object)__instance || attacker.IsPlayer() || attacker.IsTamed() || BaseAI.IsEnemy(attacker, __instance))
			{
				return true;
			}
			if ((Plugin.ExemptBosses.Value && __instance.IsBoss()) || Plugin.IsExcluded(__instance))
			{
				return false;
			}
			if (Random.value >= Plugin.HitChance.Value)
			{
				return false;
			}
			if (Plugin.DamageMultiplier.Value != 1f)
			{
				hit.ApplyModifier(Plugin.DamageMultiplier.Value);
			}
			return true;
		}
	}
	internal static class Grudges
	{
		private static readonly Dictionary<(int victim, int attacker), float> until = new Dictionary<(int, int), float>();

		internal static void Add(Character victim, Character attacker)
		{
			until[(((Object)victim).GetInstanceID(), ((Object)attacker).GetInstanceID())] = Time.time + Plugin.GrudgeSeconds.Value;
		}

		internal static bool Has(Character a, Character b)
		{
			if (until.Count == 0 || (Object)(object)a == (Object)null || (Object)(object)b == (Object)null)
			{
				return false;
			}
			(int, int) key = (((Object)a).GetInstanceID(), ((Object)b).GetInstanceID());
			if (!until.TryGetValue(key, out var value))
			{
				return false;
			}
			if (Time.time <= value)
			{
				return true;
			}
			until.Remove(key);
			return false;
		}
	}
	[HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[]
	{
		typeof(Character),
		typeof(Character)
	})]
	internal static class IsEnemyPatch
	{
		private static void Postfix(Character a, Character b, ref bool __result)
		{
			if (!__result && Grudges.Has(a, b))
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(MonsterAI), "OnDamaged")]
	internal static class GrudgePatch
	{
		private static readonly FieldRef<MonsterAI, Character> TargetRef = AccessTools.FieldRefAccess<MonsterAI, Character>("m_targetCreature");

		private static void Postfix(MonsterAI __instance, Character attacker)
		{
			if (!(Plugin.GrudgeChance.Value <= 0f) && !((Object)(object)attacker == (Object)null))
			{
				Character component = ((Component)__instance).GetComponent<Character>();
				if (Plugin.IsWildMob(component) && Plugin.IsWildMob(attacker) && !BaseAI.IsEnemy(component, attacker) && !(Random.value >= Plugin.GrudgeChance.Value))
				{
					Grudges.Add(component, attacker);
					TargetRef.Invoke(__instance) = attacker;
				}
			}
		}
	}
}