Decompiled source of EngineerFourTurrets v1.0.0

plugins/EngineerFourTurrets.dll

Decompiled 3 months ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using RoR2;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace NormalAIPeople.SurvivorTweaks;

[BepInPlugin("normalAIPeople.SurvivorTweaks", "Survivor Tweaks", "1.0.0")]
public sealed class SurvivorTweaksPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "normalAIPeople.SurvivorTweaks";

	public const string PluginName = "Survivor Tweaks";

	public const string PluginVersion = "1.0.0";

	private static ConfigEntry<int> engineerTurretLimit;

	private static ConfigEntry<float> chronoSpreadRadius;

	private static ConfigEntry<int> chronoSpreadTargets;

	private static ConfigEntry<float> chronoSpreadInterval;

	private static ConfigEntry<float> chronoSpreadDamageCoefficient;

	private static ConfigEntry<float> chronoSicknessDuration;

	private static ConfigEntry<float> wandererPostSpecialImmunity;

	private static readonly Dictionary<object, float> nextChronoSpreadTime = new Dictionary<object, float>();

	private void Awake()
	{
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Expected O, but got Unknown
		engineerTurretLimit = ((BaseUnityPlugin)this).Config.Bind<int>("Engineer", "Turret Limit", 4, "Maximum simultaneous Engineer turrets, including the TR90 Railgun Turret.");
		chronoSpreadRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Chrono Legionnaire", "R Spread Radius", 16f, "Radius in metres of each Chrono R spread pulse.");
		chronoSpreadTargets = ((BaseUnityPlugin)this).Config.Bind<int>("Chrono Legionnaire", "R Spread Max Targets", 4, "Maximum nearby enemies infected by one spread pulse.");
		chronoSpreadInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Chrono Legionnaire", "R Spread Interval", 0.75f, "Seconds between spread pulses while Chrono R is tethered to an enemy.");
		chronoSpreadDamageCoefficient = ((BaseUnityPlugin)this).Config.Bind<float>("Chrono Legionnaire", "R Spread Damage Coefficient", 0.6f, "Damage dealt to each newly infected enemy, as a coefficient of Chrono's damage stat.");
		chronoSicknessDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Chrono Legionnaire", "R Spread Sickness Duration", 8f, "Duration in seconds of the spread Chrono Sickness debuff.");
		wandererPostSpecialImmunity = ((BaseUnityPlugin)this).Config.Bind<float>("Wanderer", "R Post-Use Damage Immunity", 1.25f, "Short immunity after Last Breath ends. Prevents the fall/self damage caused by the R transition.");
		Harmony harmony = new Harmony("normalAIPeople.SurvivorTweaks");
		Patch(harmony, typeof(CharacterMaster), "GetDeployableSameSlotLimit", "DeployableLimitPostfix");
		Patch(harmony, "RA2Mod.Survivors.Chrono.States.CastVanishTether", "DoDamage", "ChronoRDoDamagePostfix");
		Patch(harmony, "RA2Mod.Survivors.Chrono.States.CastVanishTether", "OnExit", "ChronoROnExitPostfix");
		Patch(harmony, "UnforgivenMod.Unforgiven.SkillStates.DashSpecial", "OnExit", "WandererROnExitPostfix");
		Patch(harmony, "UnforgivenMod.Unforgiven.SkillStates.Special", "OnExit", "WandererROnExitPostfix");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Survivor Tweaks loaded.");
	}

	private static void Patch(Harmony harmony, Type type, string methodName, string postfixName)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
		if (methodInfo != null)
		{
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SurvivorTweaksPlugin), postfixName, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
	}

	private static void Patch(Harmony harmony, string typeName, string methodName, string postfixName)
	{
		Type type = AccessTools.TypeByName(typeName);
		if (!(type == null))
		{
			Patch(harmony, type, methodName, postfixName);
		}
	}

	private static void DeployableLimitPostfix(CharacterMaster __instance, ref int __result)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		CharacterBody val = (Object.op_Implicit((Object)(object)__instance) ? __instance.GetBody() : null);
		if ((Object)(object)val != (Object)null && val.bodyIndex == BodyCatalog.FindBodyIndex("EngiBody"))
		{
			__result = Math.Max(__result, Math.Max(1, engineerTurretLimit.Value));
		}
	}

	private static void ChronoRDoDamagePostfix(object __instance)
	{
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Expected O, but got Unknown
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0216: Unknown result type (might be due to invalid IL or missing references)
		if (!NetworkServer.active || chronoSpreadRadius.Value <= 0f || chronoSpreadTargets.Value <= 0)
		{
			return;
		}
		float fixedTime = Time.fixedTime;
		if (nextChronoSpreadTime.TryGetValue(__instance, out var value) && fixedTime < value)
		{
			return;
		}
		nextChronoSpreadTime[__instance] = fixedTime + Math.Max(0.05f, chronoSpreadInterval.Value);
		HurtBox value2 = Traverse.Create(__instance).Field("targetHurtBox").GetValue<HurtBox>();
		CharacterBody value3 = Traverse.Create(__instance).Property("characterBody", (object[])null).GetValue<CharacterBody>();
		if ((Object)(object)value2 == (Object)null || (Object)(object)value2.healthComponent == (Object)null || (Object)(object)value3 == (Object)null || (Object)(object)value3.teamComponent == (Object)null)
		{
			return;
		}
		int num = 0;
		HashSet<HealthComponent> hashSet = new HashSet<HealthComponent>();
		SphereSearch val = new SphereSearch();
		val.origin = ((Component)value2).transform.position;
		val.radius = chronoSpreadRadius.Value;
		LayerIndex entityPrecise = LayerIndex.entityPrecise;
		val.mask = ((LayerIndex)(ref entityPrecise)).mask;
		SphereSearch val2 = val;
		HurtBox[] hurtBoxes = val2.RefreshCandidates().FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(value3.teamComponent.teamIndex)).OrderCandidatesByDistance()
			.FilterCandidatesByDistinctHurtBoxEntities()
			.GetHurtBoxes();
		HurtBox[] array = hurtBoxes;
		foreach (HurtBox val3 in array)
		{
			if (num >= chronoSpreadTargets.Value)
			{
				break;
			}
			HealthComponent val4 = (((Object)(object)val3 != (Object)null) ? val3.healthComponent : null);
			CharacterBody val5 = (((Object)(object)val4 != (Object)null) ? val4.body : null);
			if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val5 == (Object)null) && !((Object)(object)val4 == (Object)(object)value2.healthComponent) && val4.alive && hashSet.Add(val4))
			{
				ApplyChronoSickness(val5);
				DealChronoSpreadDamage(value3, val4, ((Component)val3).transform.position);
				num++;
			}
		}
	}

	private static void ChronoROnExitPostfix(object __instance)
	{
		nextChronoSpreadTime.Remove(__instance);
	}

	private static void ApplyChronoSickness(CharacterBody body)
	{
		//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_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Invalid comparison between Unknown and I4
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		BuffIndex val = BuffCatalog.FindBuffIndex("ChronoDebuff");
		if ((int)val != -1)
		{
			BuffDef buffDef = BuffCatalog.GetBuffDef(val);
			if ((Object)(object)buffDef != (Object)null)
			{
				body.AddTimedBuff(buffDef, Math.Max(0.1f, chronoSicknessDuration.Value));
			}
		}
		Type type = AccessTools.TypeByName("RA2Mod.Survivors.Chrono.ChronoItems");
		ItemDef val2 = (ItemDef)((type == null) ? null : /*isinst with value type is only supported in some contexts*/);
		if ((Object)(object)val2 != (Object)null && (Object)(object)body.inventory != (Object)null)
		{
			body.inventory.GiveItem(val2.itemIndex, body.isChampion ? 1 : 2);
		}
	}

	private static void DealChronoSpreadDamage(CharacterBody attacker, HealthComponent victim, Vector3 position)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		//IL_003a: 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)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		if (!(chronoSpreadDamageCoefficient.Value <= 0f))
		{
			DamageInfo val = new DamageInfo();
			val.attacker = ((Component)attacker).gameObject;
			val.inflictor = ((Component)attacker).gameObject;
			val.position = position;
			val.damage = attacker.damage * chronoSpreadDamageCoefficient.Value;
			val.damageColorIndex = (DamageColorIndex)0;
			val.crit = attacker.RollCrit();
			val.force = Vector3.zero;
			val.procChainMask = default(ProcChainMask);
			val.procCoefficient = 0.5f;
			DamageInfo val2 = val;
			victim.TakeDamage(val2);
			GlobalEventManager.instance.OnHitEnemy(val2, ((Component)victim).gameObject);
			GlobalEventManager.instance.OnHitAll(val2, ((Component)victim).gameObject);
		}
	}

	private static void WandererROnExitPostfix(object __instance)
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		if (NetworkServer.active && !(wandererPostSpecialImmunity.Value <= 0f))
		{
			CharacterBody value = Traverse.Create(__instance).Property("characterBody", (object[])null).GetValue<CharacterBody>();
			if ((Object)(object)value != (Object)null && value.bodyIndex == BodyCatalog.FindBodyIndex("UnforgivenBody"))
			{
				value.AddTimedBuff(Buffs.HiddenInvincibility, wandererPostSpecialImmunity.Value);
			}
		}
	}
}