Decompiled source of Engi and Artificer Tweaks v1.1.0

EngiArtificerTweaks.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates.EngiTurret.EngiTurretWeapon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using RoR2.CharacterAI;
using RoR2.Projectile;
using UnityEngine;
using UnityEngine.Networking;

[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("EngiArtificerTweaks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("EngiArtificerTweaks")]
[assembly: AssemblyTitle("EngiArtificerTweaks")]
[assembly: AssemblyVersion("1.1.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 EngiArtificerTweaks
{
	[BepInPlugin("com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class EngiArtificerTweaksPlugin : BaseUnityPlugin
	{
		private struct PingFocus
		{
			public CharacterBody target;

			public float endTime;
		}

		public const string PluginGUID = "com.ewan.EngiArtificerTweaks";

		public const string PluginName = "Engi & Artificer Tweaks";

		public const string PluginVersion = "1.1.0";

		internal static ManualLogSource Logger;

		internal static Harmony HarmonyInstance;

		private const string TurretMasterName = "EngiWalkerTurretMaster";

		private const string StrafeDriverName = "StrafeAndFireAtEnemy";

		private const string FireDriverName = "ChaseAndFireAtEnemy";

		private const string ChaseDriverName = "EngiArtificerTweaks_ChaseEnemy";

		private const float VanillaStrafeMaxDistance = 15f;

		private const string StationaryTurretMasterName = "EngiTurretMaster";

		private static readonly Dictionary<BaseAI, PingFocus> pingFocus = new Dictionary<BaseAI, PingFocus>();

		private static readonly FieldRef<ProjectileExplosion, bool> ExplosionAlive = AccessTools.FieldRefAccess<ProjectileExplosion, bool>("alive");

		private static readonly Action<BaseAI, AISkillDriver[]> SetSkillDrivers = AccessTools.MethodDelegate<Action<BaseAI, AISkillDriver[]>>(AccessTools.PropertySetter(typeof(BaseAI), "skillDrivers"), (object)null, true);

		public static ConfigEntry<float> BeamRange;

		public static ConfigEntry<float> FiringEngagementRange;

		public static ConfigEntry<float> PathfindingChaseRange;

		public static ConfigEntry<bool> SprintWhileChasing;

		public static ConfigEntry<bool> XRayTargeting;

		public static ConfigEntry<bool> PingTargeting;

		public static ConfigEntry<float> PingFocusDuration;

		public static ConfigEntry<float> FlameBoltSpeed;

		public static ConfigEntry<float> PlasmaBoltSpeed;

		public static ConfigEntry<float> NanoBombSpeed;

		public static ConfigEntry<float> NanoSpearSpeed;

		public static ConfigEntry<float> EarthShardSpeed;

		private static Dictionary<string, ConfigEntry<float>> speedByPrefabName;

		private static readonly Dictionary<int, ConfigEntry<float>> speedByProjectileIndex = new Dictionary<int, ConfigEntry<float>>();

		private void Awake()
		{
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			BeamRange = ((BaseUnityPlugin)this).Config.Bind<float>("Engineer Mobile Turrets", "BeamRange", 50f, "Maximum range of the TR58 Carbonizer mobile turret's laser beam (vanilla: 25 m).");
			FiringEngagementRange = ((BaseUnityPlugin)this).Config.Bind<float>("Engineer Mobile Turrets", "FiringEngagementRange", 50f, "Distance at which the mobile turret's AI starts firing at its target (vanilla: 25 m). Keep this at or below BeamRange, or the turret will fire beams that fall short.");
			PathfindingChaseRange = ((BaseUnityPlugin)this).Config.Bind<float>("Engineer Mobile Turrets", "PathfindingChaseRange", 100f, "Distance at which the mobile turret walks toward an enemy it has spotted but can't shoot yet (vanilla: no chasing; the turret just follows you). Set at or below FiringEngagementRange to turn chasing off. Note: the vanilla leash still sends the turret back to you once it is 110 m away from you.");
			SprintWhileChasing = ((BaseUnityPlugin)this).Config.Bind<bool>("Engineer Mobile Turrets", "SprintWhileChasing", true, "Whether the mobile turret sprints while chasing an enemy it can't shoot yet.");
			XRayTargeting = ((BaseUnityPlugin)this).Config.Bind<bool>("Engineer Mobile Turrets", "XRayTargeting", false, "Let mobile turrets spot enemies through walls (vanilla: off; turrets, like monsters, only pick new targets they can see). When on, turrets only fire with a clear shot and otherwise walk around to reach the enemy.");
			PingTargeting = ((BaseUnityPlugin)this).Config.Bind<bool>("Turret Ping Targeting", "PingTargeting", true, "Pinging an enemy makes your Engineer turrets (both kinds) switch to it. They chase it past the normal chase range, but the 110 m leash to you still applies. Pinging anything else, or the enemy dying, ends the focus. Needs the host to have the mod.");
			PingFocusDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Turret Ping Targeting", "PingFocusDuration", 30f, "How many seconds turrets stay focused on a pinged enemy. 0 = until it dies or you ping something else.");
			FlameBoltSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Artificer Projectile Speeds", "FlameBoltSpeed", 160f, "Travel speed of Artificer's Flame Bolt primary (vanilla: 80 m/s).");
			PlasmaBoltSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Artificer Projectile Speeds", "PlasmaBoltSpeed", 160f, "Travel speed of Artificer's Plasma Bolt primary (vanilla: 80 m/s).");
			NanoBombSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Artificer Projectile Speeds", "NanoBombSpeed", 80f, "Travel speed of Artificer's Charged Nano-Bomb secondary (vanilla: 40 m/s).");
			NanoSpearSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Artificer Projectile Speeds", "NanoSpearSpeed", 240f, "Travel speed of Artificer's Cast Nano-Spear secondary (vanilla: 120 m/s).");
			EarthShardSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Artificer Projectile Speeds", "EarthShardSpeed", 240f, "Travel speed of Artificer's Tectonic Shards primary (vanilla: 120 m/s). Shards only live for 0.3 s, so this also sets their range (120 m/s = 36 m, 240 m/s = 72 m).");
			speedByPrefabName = new Dictionary<string, ConfigEntry<float>>
			{
				["MageFireboltBasic"] = FlameBoltSpeed,
				["MageLightningboltBasic"] = PlasmaBoltSpeed,
				["MageLightningBombProjectile"] = NanoBombSpeed,
				["MageIceBombProjectile"] = NanoSpearSpeed,
				["MageEarthShardProjectile"] = EarthShardSpeed
			};
			FiringEngagementRange.SettingChanged += OnTurretAIConfigChanged;
			PathfindingChaseRange.SettingChanged += OnTurretAIConfigChanged;
			SprintWhileChasing.SettingChanged += OnTurretAIConfigChanged;
			XRayTargeting.SettingChanged += OnTurretAIConfigChanged;
			PingTargeting.SettingChanged += OnPingTargetingChanged;
			FlameBoltSpeed.SettingChanged += OnArtificerSpeedConfigChanged;
			PlasmaBoltSpeed.SettingChanged += OnArtificerSpeedConfigChanged;
			NanoBombSpeed.SettingChanged += OnArtificerSpeedConfigChanged;
			NanoSpearSpeed.SettingChanged += OnArtificerSpeedConfigChanged;
			EarthShardSpeed.SettingChanged += OnArtificerSpeedConfigChanged;
			HarmonyInstance = new Harmony("com.ewan.EngiArtificerTweaks");
			HarmonyInstance.PatchAll(typeof(EngiArtificerTweaksPlugin));
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnGameLoaded));
			Run.onRunDestroyGlobal += delegate
			{
				pingFocus.Clear();
			};
			TryInitRiskOfOptions();
			Logger.LogInfo((object)"Engi & Artificer Tweaks v1.1.0 initialized!");
		}

		private void OnDestroy()
		{
			Harmony harmonyInstance = HarmonyInstance;
			if (harmonyInstance != null)
			{
				harmonyInstance.UnpatchSelf();
			}
		}

		private void TryInitRiskOfOptions()
		{
			try
			{
				if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
				{
					InitRiskOfOptions();
				}
				else
				{
					Logger.LogInfo((object)"RiskOfOptions mod not detected; in-game mod options menu integration skipped.");
				}
			}
			catch (Exception arg)
			{
				Logger.LogWarning((object)$"Failed to initialize RiskOfOptions integration: {arg}");
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private void InitRiskOfOptions()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Expected O, but got Unknown
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Expected O, but got Unknown
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Expected O, but got Unknown
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Expected O, but got Unknown
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Expected O, but got Unknown
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Expected O, but got Unknown
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Expected O, but got Unknown
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Expected O, but got Unknown
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Expected O, but got Unknown
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Expected O, but got Unknown
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Expected O, but got Unknown
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Expected O, but got Unknown
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Expected O, but got Unknown
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Expected O, but got Unknown
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0408: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0429: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Expected O, but got Unknown
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_0448: Expected O, but got Unknown
			//IL_044d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0452: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0468: Unknown result type (might be due to invalid IL or missing references)
			//IL_0473: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0489: Unknown result type (might be due to invalid IL or missing references)
			//IL_0494: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a4: Expected O, but got Unknown
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b3: Expected O, but got Unknown
			ModSettingsManager.SetModDescription("Engineer TR58 Carbonizer mobile turret range/chase tweaks and Artificer projectile speeds.", "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			Sprite val = LoadModIconSprite();
			if ((Object)(object)val != (Object)null)
			{
				ModSettingsManager.SetModIcon(val, "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			}
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(BeamRange, new StepSliderConfig
			{
				min = 5f,
				max = 500f,
				increment = 5f,
				FormatString = "{0:0} m",
				category = "Engineer Mobile Turrets",
				name = "Laser Beam Range",
				description = "Maximum range of the mobile turret's laser beam (vanilla: 25 m)."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(FiringEngagementRange, new StepSliderConfig
			{
				min = 5f,
				max = 500f,
				increment = 5f,
				FormatString = "{0:0} m",
				category = "Engineer Mobile Turrets",
				name = "Firing Engagement Range",
				description = "Distance at which the mobile turret starts firing (vanilla: 25 m). Keep at or below Laser Beam Range."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(PathfindingChaseRange, new StepSliderConfig
			{
				min = 0f,
				max = 500f,
				increment = 5f,
				FormatString = "{0:0} m",
				category = "Engineer Mobile Turrets",
				name = "Chase Range",
				description = "Distance at which the mobile turret walks toward enemies it can't shoot yet (vanilla: no chasing). At or below Firing Engagement Range turns chasing off. Turrets still return to you when 110 m away from you."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(SprintWhileChasing, new CheckBoxConfig
			{
				category = "Engineer Mobile Turrets",
				name = "Sprint While Chasing",
				description = "Whether the mobile turret sprints while chasing enemies."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(XRayTargeting, new CheckBoxConfig
			{
				category = "Engineer Mobile Turrets",
				name = "X-Ray Targeting",
				description = "Turrets spot enemies through walls, then walk around to get a clear shot (vanilla: off)."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(PingTargeting, new CheckBoxConfig
			{
				category = "Turret Ping Targeting",
				name = "Turrets Attack Pinged Enemy",
				description = "Pinging an enemy makes your Engineer turrets switch to it and chase it. Pinging anything else ends the focus."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(PingFocusDuration, new StepSliderConfig
			{
				min = 0f,
				max = 120f,
				increment = 5f,
				FormatString = "{0:0} s",
				category = "Turret Ping Targeting",
				name = "Ping Focus Duration",
				description = "Seconds turrets stay on a pinged enemy. 0 = until it dies or you ping something else."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(FlameBoltSpeed, new StepSliderConfig
			{
				min = 10f,
				max = 1000f,
				increment = 5f,
				FormatString = "{0:0} m/s",
				category = "Artificer Projectile Speeds",
				name = "Flame Bolt Speed",
				description = "Projectile speed of Flame Bolt (vanilla: 80 m/s)."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(PlasmaBoltSpeed, new StepSliderConfig
			{
				min = 10f,
				max = 1000f,
				increment = 5f,
				FormatString = "{0:0} m/s",
				category = "Artificer Projectile Speeds",
				name = "Plasma Bolt Speed",
				description = "Projectile speed of Plasma Bolt (vanilla: 80 m/s)."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(NanoBombSpeed, new StepSliderConfig
			{
				min = 10f,
				max = 500f,
				increment = 5f,
				FormatString = "{0:0} m/s",
				category = "Artificer Projectile Speeds",
				name = "Charged Nano-Bomb Speed",
				description = "Projectile speed of Charged Nano-Bomb (vanilla: 40 m/s)."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(NanoSpearSpeed, new StepSliderConfig
			{
				min = 10f,
				max = 1000f,
				increment = 5f,
				FormatString = "{0:0} m/s",
				category = "Artificer Projectile Speeds",
				name = "Cast Nano-Spear Speed",
				description = "Projectile speed of Cast Nano-Spear (vanilla: 120 m/s)."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(EarthShardSpeed, new StepSliderConfig
			{
				min = 10f,
				max = 1000f,
				increment = 5f,
				FormatString = "{0:0} m/s",
				category = "Artificer Projectile Speeds",
				name = "Tectonic Shards Speed",
				description = "Projectile speed of Tectonic Shards (vanilla: 120 m/s). Also sets their range: shards last 0.3 s."
			}), "com.ewan.EngiArtificerTweaks", "Engi & Artificer Tweaks");
		}

		private static Sprite LoadModIconSprite()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				if (string.IsNullOrEmpty(directoryName))
				{
					return null;
				}
				string path = Path.Combine(directoryName, "icon.png");
				if (File.Exists(path))
				{
					byte[] array = File.ReadAllBytes(path);
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
					if (ImageConversion.LoadImage(val, array))
					{
						return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger = Logger;
				if (logger != null)
				{
					logger.LogDebug((object)("Could not load icon sprite: " + ex.Message));
				}
			}
			return null;
		}

		private static void OnGameLoaded()
		{
			((ResourceAvailability)(ref ProjectileCatalog.catalogAvailability)).CallWhenAvailable((Action)delegate
			{
				speedByProjectileIndex.Clear();
				for (int i = 0; i < ProjectileCatalog.projectilePrefabCount; i++)
				{
					GameObject projectilePrefab = ProjectileCatalog.GetProjectilePrefab(i);
					if (Object.op_Implicit((Object)(object)projectilePrefab) && speedByPrefabName.TryGetValue(((Object)projectilePrefab).name, out var value))
					{
						speedByProjectileIndex[i] = value;
					}
				}
				if (speedByProjectileIndex.Count != speedByPrefabName.Count)
				{
					Logger.LogWarning((object)$"Found {speedByProjectileIndex.Count} of {speedByPrefabName.Count} Artificer projectiles in ProjectileCatalog.");
				}
				UpdateArtificerPrefabSpeeds();
			});
		}

		private static void OnTurretAIConfigChanged(object sender, EventArgs e)
		{
			foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList)
			{
				if (Object.op_Implicit((Object)(object)readOnlyInstances) && IsTurretMaster(((Component)readOnlyInstances).gameObject))
				{
					BaseAI component = ((Component)readOnlyInstances).GetComponent<BaseAI>();
					if (Object.op_Implicit((Object)(object)component))
					{
						ApplyTurretSettings(component);
					}
				}
			}
		}

		private static void OnPingTargetingChanged(object sender, EventArgs e)
		{
			if (PingTargeting.Value)
			{
				return;
			}
			List<BaseAI> list = new List<BaseAI>(pingFocus.Keys);
			pingFocus.Clear();
			foreach (BaseAI item in list)
			{
				if (Object.op_Implicit((Object)(object)item) && IsTurretMaster(((Component)item).gameObject))
				{
					ApplyTurretSettings(item);
				}
			}
		}

		private static void OnArtificerSpeedConfigChanged(object sender, EventArgs e)
		{
			UpdateArtificerPrefabSpeeds();
		}

		private static bool IsTurretMaster(GameObject go)
		{
			return ((Object)go).name.StartsWith("EngiWalkerTurretMaster", StringComparison.Ordinal);
		}

		private static bool IsAnyEngiTurretMaster(GameObject go)
		{
			if (!IsTurretMaster(go))
			{
				return ((Object)go).name.StartsWith("EngiTurretMaster", StringComparison.Ordinal);
			}
			return true;
		}

		private static void AddChaseDriver(BaseAI ai)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			AISkillDriver[] skillDrivers = ai.skillDrivers;
			if (skillDrivers != null && !Array.Exists(skillDrivers, (AISkillDriver d) => Object.op_Implicit((Object)(object)d) && d.customName == "EngiArtificerTweaks_ChaseEnemy"))
			{
				int num = Array.FindIndex(skillDrivers, (AISkillDriver d) => Object.op_Implicit((Object)(object)d) && d.customName == "ChaseAndFireAtEnemy");
				if (num < 0)
				{
					Logger.LogWarning((object)"EngiWalkerTurretMaster has no 'ChaseAndFireAtEnemy' AI driver; chase range not applied.");
					return;
				}
				AISkillDriver val = ((Component)ai).gameObject.AddComponent<AISkillDriver>();
				val.customName = "EngiArtificerTweaks_ChaseEnemy";
				val.skillSlot = (SkillSlot)(-1);
				val.moveTargetType = (TargetType)0;
				val.movementType = (MovementType)1;
				val.aimType = (AimType)1;
				val.driverUpdateTimerOverride = 1f;
				val.resetCurrentEnemyOnNextDriverSelection = true;
				List<AISkillDriver> list = new List<AISkillDriver>(skillDrivers);
				list.Insert(num + 1, val);
				SetSkillDrivers(ai, list.ToArray());
			}
		}

		private static void ApplyTurretSettings(BaseAI ai)
		{
			AISkillDriver[] skillDrivers = ai.skillDrivers;
			if (skillDrivers == null)
			{
				return;
			}
			bool flag = pingFocus.ContainsKey(ai);
			ai.xrayVision = XRayTargeting.Value;
			bool selectionRequiresTargetLoS = XRayTargeting.Value || flag;
			float num = Mathf.Max(FiringEngagementRange.Value, 0f);
			float num2 = Mathf.Min(15f, num);
			float maxDistance = (flag ? float.PositiveInfinity : Mathf.Max(PathfindingChaseRange.Value, num));
			AISkillDriver[] array = skillDrivers;
			foreach (AISkillDriver val in array)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					switch (val.customName)
					{
					case "StrafeAndFireAtEnemy":
						val.maxDistance = num2;
						val.selectionRequiresTargetLoS = selectionRequiresTargetLoS;
						break;
					case "ChaseAndFireAtEnemy":
						val.minDistance = num2;
						val.maxDistance = num;
						val.selectionRequiresTargetLoS = selectionRequiresTargetLoS;
						break;
					case "EngiArtificerTweaks_ChaseEnemy":
						val.minDistance = 0f;
						val.maxDistance = maxDistance;
						val.shouldSprint = SprintWhileChasing.Value;
						break;
					}
				}
			}
		}

		private static CharacterBody GetPingedEnemy(GameObject pinged, CharacterMaster pinger)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody val = (Object.op_Implicit((Object)(object)pinged) ? pinged.GetComponent<CharacterBody>() : null);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.healthComponent) || !val.healthComponent.alive || !Object.op_Implicit((Object)(object)val.teamComponent))
			{
				return null;
			}
			if (!TeamManager.IsTeamEnemy(pinger.teamIndex, val.teamComponent.teamIndex))
			{
				return null;
			}
			return val;
		}

		private static ConfigEntry<float> GetSpeedEntry(GameObject projectilePrefab)
		{
			int projectileIndex = ProjectileCatalog.GetProjectileIndex(projectilePrefab);
			if (projectileIndex < 0 || !speedByProjectileIndex.TryGetValue(projectileIndex, out var value))
			{
				return null;
			}
			return value;
		}

		public static void UpdateArtificerPrefabSpeeds()
		{
			if (!((ResourceAvailability)(ref ProjectileCatalog.catalogAvailability)).available)
			{
				return;
			}
			foreach (KeyValuePair<int, ConfigEntry<float>> item in speedByProjectileIndex)
			{
				GameObject projectilePrefab = ProjectileCatalog.GetProjectilePrefab(item.Key);
				ProjectileSimple val = (Object.op_Implicit((Object)(object)projectilePrefab) ? projectilePrefab.GetComponent<ProjectileSimple>() : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					val.desiredForwardSpeed = item.Value.Value;
					Logger.LogDebug((object)$"Set '{((Object)projectilePrefab).name}' desiredForwardSpeed to {item.Value.Value} m/s");
				}
				Rigidbody val2 = (Object.op_Implicit((Object)(object)projectilePrefab) ? projectilePrefab.GetComponent<Rigidbody>() : null);
				if (Object.op_Implicit((Object)(object)val2))
				{
					val2.collisionDetectionMode = (CollisionDetectionMode)2;
				}
			}
		}

		[HarmonyPatch(typeof(BaseAI), "Awake")]
		[HarmonyPostfix]
		private static void BaseAI_Awake_Postfix(BaseAI __instance)
		{
			if (IsTurretMaster(((Component)__instance).gameObject))
			{
				AddChaseDriver(__instance);
				ApplyTurretSettings(__instance);
			}
		}

		[HarmonyPatch(typeof(PingerController), "CmdPing")]
		[HarmonyPostfix]
		private static void PingerController_CmdPing_Postfix(PingerController __instance, [HarmonyArgument(0)] PingInfo pingInfo)
		{
			if (!NetworkServer.active || !PingTargeting.Value)
			{
				return;
			}
			CharacterMaster component = ((Component)__instance).GetComponent<CharacterMaster>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return;
			}
			CharacterBody pingedEnemy = GetPingedEnemy(((PingInfo)(ref pingInfo)).targetGameObject, component);
			float value = PingFocusDuration.Value;
			float endTime = ((value > 0f) ? (Time.fixedTime + value) : float.PositiveInfinity);
			int num = 0;
			foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList)
			{
				if (!Object.op_Implicit((Object)(object)readOnlyInstances) || !Object.op_Implicit((Object)(object)readOnlyInstances.minionOwnership) || (Object)(object)readOnlyInstances.minionOwnership.ownerMaster != (Object)(object)component || !IsAnyEngiTurretMaster(((Component)readOnlyInstances).gameObject))
				{
					continue;
				}
				BaseAI component2 = ((Component)readOnlyInstances).GetComponent<BaseAI>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					if (Object.op_Implicit((Object)(object)pingedEnemy))
					{
						pingFocus[component2] = new PingFocus
						{
							target = pingedEnemy,
							endTime = endTime
						};
						component2.currentEnemy.gameObject = ((Component)pingedEnemy).gameObject;
						num++;
					}
					else if (!pingFocus.Remove(component2))
					{
						continue;
					}
					if (IsTurretMaster(((Component)readOnlyInstances).gameObject))
					{
						ApplyTurretSettings(component2);
					}
				}
			}
			if (Object.op_Implicit((Object)(object)pingedEnemy) && num > 0)
			{
				Logger.LogDebug((object)$"{num} turret(s) focusing pinged enemy '{((Object)pingedEnemy).name}'");
			}
		}

		[HarmonyPatch(typeof(BaseAI), "ManagedFixedUpdate")]
		[HarmonyPrefix]
		private static void BaseAI_ManagedFixedUpdate_Prefix(BaseAI __instance)
		{
			if (pingFocus.Count == 0 || !pingFocus.TryGetValue(__instance, out var value))
			{
				return;
			}
			CharacterBody target = value.target;
			if (!Object.op_Implicit((Object)(object)target) || !Object.op_Implicit((Object)(object)target.healthComponent) || !target.healthComponent.alive || Time.fixedTime > value.endTime)
			{
				pingFocus.Remove(__instance);
				if (IsTurretMaster(((Component)__instance).gameObject))
				{
					ApplyTurretSettings(__instance);
				}
			}
			else if ((Object)(object)__instance.currentEnemy.gameObject != (Object)(object)((Component)target).gameObject)
			{
				__instance.currentEnemy.gameObject = ((Component)target).gameObject;
			}
		}

		[HarmonyPatch(typeof(FireBeam), "OnEnter")]
		[HarmonyPrefix]
		private static void FireBeam_OnEnter_Prefix(FireBeam __instance)
		{
			__instance.maxDistance = BeamRange.Value;
		}

		[HarmonyPatch(typeof(FireBeam), "FixedUpdate")]
		[HarmonyPrefix]
		private static void FireBeam_FixedUpdate_Prefix(FireBeam __instance)
		{
			__instance.maxDistance = BeamRange.Value;
		}

		[HarmonyPatch(typeof(ProjectileImpactExplosion), "OnProjectileImpact")]
		[HarmonyPrefix]
		private static void ProjectileImpactExplosion_OnProjectileImpact_Prefix(ProjectileImpactExplosion __instance, out bool __state)
		{
			__state = ExplosionAlive.Invoke((ProjectileExplosion)(object)__instance);
		}

		[HarmonyPatch(typeof(ProjectileImpactExplosion), "OnProjectileImpact")]
		[HarmonyPostfix]
		private static void ProjectileImpactExplosion_OnProjectileImpact_Postfix(ProjectileImpactExplosion __instance, [HarmonyArgument(0)] ProjectileImpactInfo impactInfo, bool __state)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!__state || ExplosionAlive.Invoke((ProjectileExplosion)(object)__instance))
			{
				return;
			}
			ProjectileController component = ((Component)__instance).GetComponent<ProjectileController>();
			if (Object.op_Implicit((Object)(object)component) && speedByProjectileIndex.ContainsKey(component.catalogIndex))
			{
				Rigidbody component2 = ((Component)__instance).GetComponent<Rigidbody>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					component2.velocity = Vector3.zero;
					component2.position = impactInfo.estimatedPointOfImpact;
				}
				((Component)__instance).transform.position = impactInfo.estimatedPointOfImpact;
			}
		}

		[HarmonyPatch(typeof(ProjectileManager), "FireProjectile", new Type[] { typeof(FireProjectileInfo) })]
		[HarmonyPrefix]
		private static void ProjectileManager_FireProjectile_Prefix([HarmonyArgument(0)] ref FireProjectileInfo fireProjectileInfo)
		{
			if (Object.op_Implicit((Object)(object)fireProjectileInfo.projectilePrefab))
			{
				ConfigEntry<float> speedEntry = GetSpeedEntry(fireProjectileInfo.projectilePrefab);
				if (speedEntry != null)
				{
					((FireProjectileInfo)(ref fireProjectileInfo)).speedOverride = speedEntry.Value;
				}
			}
		}
	}
}