Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Engi and Artificer Tweaks v1.1.0
EngiArtificerTweaks.dll
Decompiled 2 days agousing 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; } } } } }