Decompiled source of TurretsShootEverything v1.0.0

TurretsShootEverything.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
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("TurretsShootEverything")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TurretsShootEverything")]
[assembly: AssemblyTitle("TurretsShootEverything")]
[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 TurretsShootEverything
{
	internal static class ModInfo
	{
		public const string GUID = "yourname.TurretsShootEverything";

		public const string NAME = "TurretsShootEverything";

		public const string VERSION = "1.0.0";
	}
	[BepInPlugin("yourname.TurretsShootEverything", "TurretsShootEverything", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static Settings Cfg;

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new Settings(((BaseUnityPlugin)this).Config);
			new Harmony("yourname.TurretsShootEverything").PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"TurretsShootEverything 1.0.0 loaded.");
		}

		private void Start()
		{
			foreach (PluginInfo value in Chainloader.PluginInfos.Values)
			{
				string obj = value.Metadata.Name ?? "";
				if (obj.IndexOf("ToilHead", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					Log.LogInfo((object)("Detected ToilHead (" + value.Metadata.GUID + ") - turret-head enemies will be treated like any other enemy."));
				}
				if (obj.IndexOf("FairAI", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					Log.LogInfo((object)("Detected FairAI (" + value.Metadata.GUID + ") - no AI methods are patched by this mod, so there is no overlap."));
				}
			}
		}
	}
	internal class Settings
	{
		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<float> Range;

		public readonly ConfigEntry<int> Damage;

		public readonly ConfigEntry<float> FireInterval;

		public readonly ConfigEntry<float> ChargeTime;

		public readonly ConfigEntry<bool> SpareEnemiesWithOwnTurret;

		public readonly ConfigEntry<string> IgnoredEnemies;

		private HashSet<string> _ignored = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		public Settings(ConfigFile cfg)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			Enabled = cfg.Bind<bool>("General", "Enabled", true, "Turrets also shoot enemies/monsters (players are still handled by the vanilla turret logic).");
			Range = cfg.Bind<float>("Targeting", "Range", 30f, new ConfigDescription("Maximum distance at which turrets pick enemy targets.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			Damage = cfg.Bind<int>("Targeting", "DamagePerShot", 1, new ConfigDescription("Damage dealt to an enemy per bullet.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
			FireInterval = cfg.Bind<float>("Targeting", "FireInterval", 0.21f, new ConfigDescription("Seconds between bullets (vanilla turret = 0.21).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), Array.Empty<object>()));
			ChargeTime = cfg.Bind<float>("Targeting", "ChargeTime", 1f, new ConfigDescription("Seconds a turret tracks an enemy before it starts firing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			SpareEnemiesWithOwnTurret = cfg.Bind<bool>("Compatibility", "SpareEnemiesWithOwnTurret", false, "If true, enemies that carry their own Turret component (e.g. ToilHead's turret-heads) are NOT targeted by other turrets.");
			IgnoredEnemies = cfg.Bind<string>("Compatibility", "IgnoredEnemies", "", "Comma-separated enemy names (EnemyType.enemyName) that turrets should never shoot. Example: Docile Locust Bees,Manticoil");
			IgnoredEnemies.SettingChanged += delegate
			{
				Rebuild();
			};
			Rebuild();
		}

		private void Rebuild()
		{
			_ignored = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			string[] array = IgnoredEnemies.Value.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					_ignored.Add(text);
				}
			}
		}

		public bool IsIgnored(string enemyName)
		{
			return _ignored.Contains(enemyName ?? "");
		}
	}
	[HarmonyPatch(typeof(Turret), "Update")]
	internal static class TurretUpdatePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Turret __instance)
		{
			TurretEnemyTargeting turretEnemyTargeting = default(TurretEnemyTargeting);
			if (!((Component)__instance).TryGetComponent<TurretEnemyTargeting>(ref turretEnemyTargeting))
			{
				((Component)__instance).gameObject.AddComponent<TurretEnemyTargeting>();
			}
		}
	}
	internal class TurretEnemyTargeting : MonoBehaviour
	{
		private Turret _turret;

		private EnemyAI _target;

		private float _scanTimer;

		private float _chargeTimer;

		private float _fireTimer;

		private float _lostTimer;

		private void Awake()
		{
			_turret = ((Component)this).GetComponent<Turret>();
		}

		private void LateUpdate()
		{
			//IL_004b: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_turret == (Object)null || !Plugin.Cfg.Enabled.Value)
			{
				return;
			}
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsServer)
			{
				return;
			}
			if (!_turret.turretActive || (int)_turret.turretMode != 0)
			{
				ResetTarget();
				return;
			}
			_scanTimer -= Time.deltaTime;
			if ((Object)(object)_target == (Object)null || !IsValid(_target))
			{
				ResetTarget();
				if (_scanTimer <= 0f)
				{
					_scanTimer = 0.25f;
					_target = FindTarget();
				}
				if ((Object)(object)_target == (Object)null)
				{
					return;
				}
			}
			Vector3 point = AimPoint(_target);
			if (!HasLineOfSight(point))
			{
				_lostTimer += Time.deltaTime;
				if (_lostTimer > 0.5f)
				{
					ResetTarget();
				}
				return;
			}
			_lostTimer = 0f;
			RotateTowards(point);
			_chargeTimer += Time.deltaTime;
			if (!(_chargeTimer < Plugin.Cfg.ChargeTime.Value))
			{
				_fireTimer -= Time.deltaTime;
				if (_fireTimer <= 0f)
				{
					_fireTimer = Plugin.Cfg.FireInterval.Value;
					Shoot(point);
				}
			}
		}

		private void ResetTarget()
		{
			_target = null;
			_chargeTimer = 0f;
			_fireTimer = 0f;
			_lostTimer = 0f;
		}

		private static Vector3 AimPoint(EnemyAI e)
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)e).transform.position + Vector3.up * 1f;
		}

		private Vector3 Origin()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_turret.aimPoint != (Object)null))
			{
				return ((Component)_turret).transform.position + Vector3.up * 1.5f;
			}
			return _turret.aimPoint.position;
		}

		private bool IsValid(EnemyAI e)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)e == (Object)null || e.isEnemyDead || !((Component)e).gameObject.activeInHierarchy)
			{
				return false;
			}
			if ((Object)(object)e.enemyType == (Object)null || !e.enemyType.canDie)
			{
				return false;
			}
			if (Plugin.Cfg.IsIgnored(e.enemyType.enemyName))
			{
				return false;
			}
			if ((Object)(object)((Component)_turret).GetComponentInParent<EnemyAI>() == (Object)(object)e)
			{
				return false;
			}
			if (Plugin.Cfg.SpareEnemiesWithOwnTurret.Value && (Object)(object)((Component)e).GetComponentInChildren<Turret>() != (Object)null)
			{
				return false;
			}
			Vector3 val = ((Component)e).transform.position - ((Component)_turret).transform.position;
			return ((Vector3)(ref val)).sqrMagnitude <= Plugin.Cfg.Range.Value * Plugin.Cfg.Range.Value;
		}

		private EnemyAI FindTarget()
		{
			//IL_0049: 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_005e: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			RoundManager instance = RoundManager.Instance;
			if ((Object)(object)instance == (Object)null || instance.SpawnedEnemies == null)
			{
				return null;
			}
			EnemyAI result = null;
			float num = float.MaxValue;
			foreach (EnemyAI spawnedEnemy in instance.SpawnedEnemies)
			{
				if (IsValid(spawnedEnemy))
				{
					Vector3 val = ((Component)spawnedEnemy).transform.position - ((Component)_turret).transform.position;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (!(sqrMagnitude >= num) && HasLineOfSight(AimPoint(spawnedEnemy)))
					{
						result = spawnedEnemy;
						num = sqrMagnitude;
					}
				}
			}
			return result;
		}

		private bool HasLineOfSight(Vector3 point)
		{
			//IL_0001: 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)
			Vector3 val = Origin();
			int num = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-5));
			return !Physics.Linecast(val, point, num, (QueryTriggerInteraction)1);
		}

		private void RotateTowards(Vector3 point)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			Transform turretRod = _turret.turretRod;
			if (!((Object)(object)turretRod == (Object)null))
			{
				Vector3 val = point - turretRod.position;
				val.y = 0f;
				if (!(((Vector3)(ref val)).sqrMagnitude < 0.01f))
				{
					turretRod.rotation = Quaternion.RotateTowards(turretRod.rotation, Quaternion.LookRotation(val), 360f * Time.deltaTime);
				}
			}
		}

		private void Shoot(Vector3 point)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_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_008f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = point - Origin();
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			if ((Object)(object)_turret.bulletParticles != (Object)null)
			{
				_turret.bulletParticles.Play();
			}
			if ((Object)(object)_turret.mainAudio != (Object)null && (Object)(object)_turret.firingSFX != (Object)null)
			{
				_turret.mainAudio.PlayOneShot(_turret.firingSFX);
			}
			try
			{
				_target.HitEnemyOnLocalClient(Plugin.Cfg.Damage.Value, normalized, (PlayerControllerB)null, true, -1);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Hit on " + _target.enemyType.enemyName + " failed: " + ex.Message));
				ResetTarget();
			}
		}
	}
}