Decompiled source of GabrielAlly v1.3.1

GabrielAlly.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using Configgy;
using HarmonyLib;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GabrielAlly")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GabrielAlly")]
[assembly: AssemblyTitle("GabrielAlly")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace GabrielAlly;

[BepInPlugin("GabrielAlly.adry.ultrakill", "GabrielAlly", "1.3.1")]
public class GabrielAlly : BaseUnityPlugin
{
	public static ManualLogSource Log;

	public static bool IsRespawning = false;

	private static GameObject allyInstance;

	private Harmony harmonyInstance;

	private readonly string[] specialScenes = new string[3] { "intro", "main menu", "bootstrap" };

	public static string IntendedSceneName = null;

	public static string currentAllyPath = "";

	private static bool hasLoggedPlayerDeath = false;

	public static GabrielAlly Instance { get; private set; }

	public static GameObject DefaultPrefab { get; private set; }

	private void Awake()
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		harmonyInstance = new Harmony("GabrielAlly.adry.ultrakill");
		harmonyInstance.PatchAll();
		Log = ((BaseUnityPlugin)this).Logger;
		Log.LogInfo((object)"GabrielAlly mod has been enabled!");
		GameObject defaultPrefab = Addressables.LoadAssetAsync<GameObject>((object)"Assets/Prefabs/Enemies/Gabriel.prefab").WaitForCompletion();
		DefaultPrefab = defaultPrefab;
		((Component)this).gameObject.AddComponent<GabrielAllyConfig>();
	}

	private void OnEnable()
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		SceneManager.sceneLoaded += OnSceneLoaded;
		Application.logMessageReceived += new LogCallback(HandleLog);
	}

	private void OnDisable()
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		SceneManager.sceneLoaded -= OnSceneLoaded;
		Application.logMessageReceived -= new LogCallback(HandleLog);
	}

	private void HandleLog(string logString, string stackTrace, LogType type)
	{
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0203: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0241: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
		if (!((ConfigValueElement<bool>)(object)GabrielAllyConfig.enableMod).Value)
		{
			Log.LogInfo((object)"Mod is disabled. Removing any existing ally instance.");
			if ((Object)(object)allyInstance != (Object)null)
			{
				Object.Destroy((Object)(object)allyInstance);
				allyInstance = null;
			}
			return;
		}
		string text = (IntendedSceneName ?? ((Scene)(ref scene)).name).Trim().ToLower();
		if (text.Equals("intro") || text.Equals("main menu") || text.Equals("bootstrap"))
		{
			Log.LogInfo((object)("Scene '" + text + "' is special. Not spawning ally."));
			if ((Object)(object)allyInstance != (Object)null)
			{
				Object.Destroy((Object)(object)allyInstance);
				allyInstance = null;
			}
			return;
		}
		if ((Object)(object)allyInstance != (Object)null && currentAllyPath == ((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value)
		{
			Log.LogInfo((object)"Ally instance already exists. Not spawning a duplicate.");
			return;
		}
		Log.LogInfo((object)("Scene '" + ((Scene)(ref scene)).name + "' allowed (intended: '" + text + "'). Spawning " + GabrielAllyConfig.selectAlly.GetSelectedIndexName() + "."));
		if ((Object)(object)allyInstance != (Object)null)
		{
			Object.Destroy((Object)(object)allyInstance);
			allyInstance = null;
		}
		NewMovement instance = MonoSingleton<NewMovement>.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			Log.LogWarning((object)"Player (NewMovement.Instance) not found.");
			return;
		}
		Vector3 val = ((Component)instance).transform.position - ((Component)instance).transform.forward * 15f + Vector3.up * 1.25f;
		GameObject val2 = Addressables.LoadAssetAsync<GameObject>((object)((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value).WaitForCompletion();
		if ((Object)(object)val2 == (Object)null)
		{
			Log.LogWarning((object)("Failed to load ally prefab from path: " + ((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value));
			return;
		}
		allyInstance = Object.Instantiate<GameObject>(val2, val, Quaternion.identity);
		allyInstance.AddComponent<GabrielAllyController>();
		currentAllyPath = ((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value;
		EnemyIdentifier component = allyInstance.GetComponent<EnemyIdentifier>();
		if ((Object)(object)component != (Object)null)
		{
			component.ignorePlayer = true;
			component.attackEnemies = true;
			component.fallbackTarget = null;
			component.Bless(true);
			Log.LogInfo((object)(GabrielAllyConfig.selectAlly.GetSelectedIndexName() + " EnemyIdentifier configured: ignorePlayer=true, attackEnemies=true, Blessed applied."));
		}
		Log.LogInfo((object)$"{GabrielAllyConfig.selectAlly.GetSelectedIndexName()} spawned in scene '{((Scene)(ref scene)).name}' at position {val}.");
	}

	private void Update()
	{
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		if (!((ConfigValueElement<bool>)(object)GabrielAllyConfig.enableMod).Value)
		{
			if ((Object)(object)allyInstance != (Object)null)
			{
				Log.LogInfo((object)"Mod disabled via config. Removing ally instance.");
				Object.Destroy((Object)(object)allyInstance);
				allyInstance = null;
			}
			return;
		}
		NewMovement instance = MonoSingleton<NewMovement>.Instance;
		if ((Object)(object)instance != (Object)null && instance.hp <= 0)
		{
			if (!hasLoggedPlayerDeath)
			{
				Log.LogInfo((object)"Player is dead; removing ally instance.");
				hasLoggedPlayerDeath = true;
			}
			if ((Object)(object)allyInstance != (Object)null)
			{
				Object.Destroy((Object)(object)allyInstance);
				allyInstance = null;
			}
			return;
		}
		hasLoggedPlayerDeath = false;
		Scene activeScene;
		if ((Object)(object)allyInstance == (Object)null)
		{
			string text = IntendedSceneName;
			if (text == null)
			{
				activeScene = SceneManager.GetActiveScene();
				text = ((Scene)(ref activeScene)).name;
			}
			string value = text.Trim().ToLower();
			if (!specialScenes.Contains(value))
			{
				UpdateAllyInstance();
			}
		}
		if (GabrielAllyConfig.resetAllyKey.WasPeformed())
		{
			string text2 = IntendedSceneName;
			if (text2 == null)
			{
				activeScene = SceneManager.GetActiveScene();
				text2 = ((Scene)(ref activeScene)).name;
			}
			string value2 = text2.Trim().ToLower();
			if (specialScenes.Contains(value2))
			{
				Log.LogInfo((object)"Reset key pressed in a special scene. Reset is not allowed.");
			}
			else
			{
				Instance.ResetAlly();
			}
		}
	}

	public static IEnumerator RespawnAllyCoroutine(float delay)
	{
		Log.LogInfo((object)(GabrielAllyConfig.selectAlly.GetSelectedIndexName() + " died. Scheduling respawn in 5 seconds."));
		yield return (object)new WaitForSeconds(delay);
		if ((Object)(object)allyInstance != (Object)null && currentAllyPath == ((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value)
		{
			Log.LogInfo((object)"Ally instance already exists during respawn. Aborting duplicate respawn.");
			IsRespawning = false;
			yield break;
		}
		NewMovement player = MonoSingleton<NewMovement>.Instance;
		if ((Object)(object)player == (Object)null)
		{
			Log.LogWarning((object)"Respawn not executed - player not found.");
			IsRespawning = false;
			yield break;
		}
		Vector3 spawnPos = ((Component)player).transform.position - ((Component)player).transform.forward * 15f + Vector3.up * 1.25f;
		GameObject prefab = Addressables.LoadAssetAsync<GameObject>((object)((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value).WaitForCompletion();
		if ((Object)(object)prefab == (Object)null)
		{
			Log.LogWarning((object)"Respawn not executed - ally prefab is not defined.");
			IsRespawning = false;
			yield break;
		}
		GameObject newAlly = Object.Instantiate<GameObject>(prefab, spawnPos, Quaternion.identity);
		newAlly.AddComponent<GabrielAllyController>();
		currentAllyPath = ((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value;
		EnemyIdentifier enemyId = newAlly.GetComponent<EnemyIdentifier>();
		if ((Object)(object)enemyId != (Object)null)
		{
			enemyId.ignorePlayer = true;
			enemyId.attackEnemies = true;
			enemyId.fallbackTarget = null;
			enemyId.Bless(true);
			Log.LogInfo((object)("Respawn - EnemyIdentifier configured for " + GabrielAllyConfig.selectAlly.GetSelectedIndexName() + ": ignorePlayer=true, attackEnemies=true, Blessed applied."));
		}
		allyInstance = newAlly;
		IsRespawning = false;
		Log.LogInfo((object)$"{GabrielAllyConfig.selectAlly.GetSelectedIndexName()} respawned at position {spawnPos}.");
	}

	public void ResetAlly()
	{
		//IL_000a: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		string text = IntendedSceneName;
		if (text == null)
		{
			Scene activeScene = SceneManager.GetActiveScene();
			text = ((Scene)(ref activeScene)).name;
		}
		string value = text.Trim().ToLower();
		if (specialScenes.Contains(value))
		{
			Log.LogInfo((object)"Reset key pressed in a special scene. Reset is not allowed.");
			return;
		}
		Log.LogWarning((object)(GabrielAllyConfig.selectAlly.GetSelectedIndexName() + " instance reset due to reset key press or forced checkpoint."));
		if ((Object)(object)allyInstance != (Object)null)
		{
			Object.Destroy((Object)(object)allyInstance);
			allyInstance = null;
		}
		NewMovement instance = MonoSingleton<NewMovement>.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			Log.LogWarning((object)"Cannot reset ally - player not found.");
			return;
		}
		Vector3 val = ((Component)instance).transform.position - ((Component)instance).transform.forward * 15f + Vector3.up * 1.25f;
		GameObject val2 = Addressables.LoadAssetAsync<GameObject>((object)((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value).WaitForCompletion();
		if ((Object)(object)val2 == (Object)null)
		{
			Log.LogWarning((object)"Cannot reset ally - failed to load prefab.");
			return;
		}
		allyInstance = Object.Instantiate<GameObject>(val2, val, Quaternion.identity);
		allyInstance.AddComponent<GabrielAllyController>();
		currentAllyPath = ((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value;
		EnemyIdentifier component = allyInstance.GetComponent<EnemyIdentifier>();
		if ((Object)(object)component != (Object)null)
		{
			component.ignorePlayer = true;
			component.attackEnemies = true;
			component.fallbackTarget = null;
			component.Bless(true);
		}
		Log.LogInfo((object)$"{GabrielAllyConfig.selectAlly.GetSelectedIndexName()} instance has been reset at position {val}.");
	}

	public void UpdateAllyInstance()
	{
		//IL_000a: 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_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0127: 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_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0208: Unknown result type (might be due to invalid IL or missing references)
		string text = IntendedSceneName;
		if (text == null)
		{
			Scene activeScene = SceneManager.GetActiveScene();
			text = ((Scene)(ref activeScene)).name;
		}
		string text2 = text.Trim().ToLower();
		if (specialScenes.Contains(text2))
		{
			Log.LogInfo((object)("Current scene '" + text2 + "' is special. Not updating ally instance."));
			return;
		}
		if ((Object)(object)allyInstance != (Object)null && currentAllyPath == ((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value)
		{
			Log.LogInfo((object)"Ally instance already exists with the selected prefab. No update needed.");
			return;
		}
		Log.LogInfo((object)("Ally selection changed to: " + GabrielAllyConfig.selectAlly.GetSelectedIndexName() + ". Updating ally instance."));
		if ((Object)(object)allyInstance != (Object)null)
		{
			Object.Destroy((Object)(object)allyInstance);
			allyInstance = null;
		}
		NewMovement instance = MonoSingleton<NewMovement>.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			Log.LogWarning((object)"UpdateAllyInstance: Player (NewMovement.Instance) not found.");
			return;
		}
		Vector3 val = ((Component)instance).transform.position - ((Component)instance).transform.forward * 15f + Vector3.up * 1.25f;
		GameObject val2 = Addressables.LoadAssetAsync<GameObject>((object)((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value).WaitForCompletion();
		if ((Object)(object)val2 == (Object)null)
		{
			Log.LogWarning((object)("UpdateAllyInstance: Failed to load ally prefab from path: " + ((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value));
			return;
		}
		allyInstance = Object.Instantiate<GameObject>(val2, val, Quaternion.identity);
		allyInstance.AddComponent<GabrielAllyController>();
		currentAllyPath = ((ConfigValueElement<string>)(object)GabrielAllyConfig.selectAlly).Value;
		EnemyIdentifier component = allyInstance.GetComponent<EnemyIdentifier>();
		if ((Object)(object)component != (Object)null)
		{
			component.ignorePlayer = true;
			component.attackEnemies = true;
			component.fallbackTarget = null;
			component.Bless(true);
		}
		Log.LogInfo((object)$"Ally instance updated: {GabrielAllyConfig.selectAlly.GetSelectedIndexName()} spawned at position {val}.");
	}
}
[HarmonyPatch(typeof(SceneHelper), "LoadSceneAsync")]
public static class SceneHelper_LoadSceneAsync_Patch
{
	private static void Prefix(string sceneName, bool noSplash)
	{
		GabrielAlly.IntendedSceneName = sceneName.Trim();
		Debug.Log((object)("[Patch] Intended scene name set to: " + GabrielAlly.IntendedSceneName));
	}
}
[HarmonyPatch(typeof(OptionsManager), "RestartCheckpoint")]
public static class OptionsManager_RestartCheckpoint_Patch
{
	private static void Postfix()
	{
		if ((Object)(object)GabrielAlly.Instance != (Object)null && ((ConfigValueElement<bool>)(object)GabrielAllyConfig.enableMod).Value)
		{
			GabrielAlly.Instance.ResetAlly();
			GabrielAlly.Log.LogInfo((object)"Ally instance reset due to forced checkpoint via menu.");
		}
	}
}
public class GabrielAllyController : MonoBehaviour
{
	private enum Mode
	{
		Follow,
		Attack
	}

	public bool hasDied = false;

	private Mode currentMode;

	private EnemyIdentifier enemyId;

	private float timer;

	private float followCooldownTimer;

	private float updateInterval = 0.5f;

	private Vector3 followOffset = Vector3.up * 1.25f;

	private float followCooldown => ((ConfigValueElement<float>)(object)GabrielAllyConfig.followCooldown).Value;

	private float followDistance => ((ConfigValueElement<float>)(object)GabrielAllyConfig.followDistance).Value;

	private float maxDistanceFromPlayer => ((ConfigValueElement<float>)(object)GabrielAllyConfig.maxDistanceFromPlayer).Value;

	private float maxFollowOffsetDistance => ((ConfigValueElement<float>)(object)GabrielAllyConfig.maxFollowOffsetDistance).Value;

	private float attackDistance => ((ConfigValueElement<float>)(object)GabrielAllyConfig.attackDistance).Value;

	private void Awake()
	{
		enemyId = ((Component)this).GetComponent<EnemyIdentifier>();
		currentMode = Mode.Follow;
		hasDied = false;
		if ((Object)(object)enemyId != (Object)null)
		{
			enemyId.ignorePlayer = true;
			enemyId.attackEnemies = true;
			enemyId.fallbackTarget = null;
		}
	}

	private void Update()
	{
		//IL_001d: 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)
		//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_0063: 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_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: 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)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: 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_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: 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_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: 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_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_025b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0260: Unknown result type (might be due to invalid IL or missing references)
		//IL_026d: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f8: 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_0402: Unknown result type (might be due to invalid IL or missing references)
		//IL_0406: Unknown result type (might be due to invalid IL or missing references)
		//IL_040b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0414: Unknown result type (might be due to invalid IL or missing references)
		//IL_0419: Unknown result type (might be due to invalid IL or missing references)
		//IL_0420: Unknown result type (might be due to invalid IL or missing references)
		//IL_042a: Unknown result type (might be due to invalid IL or missing references)
		//IL_042f: Unknown result type (might be due to invalid IL or missing references)
		//IL_043a: Unknown result type (might be due to invalid IL or missing references)
		//IL_043c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0441: Unknown result type (might be due to invalid IL or missing references)
		//IL_044f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0454: Unknown result type (might be due to invalid IL or missing references)
		//IL_0461: Unknown result type (might be due to invalid IL or missing references)
		//IL_033e: Unknown result type (might be due to invalid IL or missing references)
		//IL_034a: Unknown result type (might be due to invalid IL or missing references)
		NewMovement instance = MonoSingleton<NewMovement>.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		if (Vector3.Distance(((Component)this).transform.position, ((Component)instance).transform.position) > maxDistanceFromPlayer)
		{
			Vector3 position = ((Component)instance).transform.position - ((Component)instance).transform.forward * followDistance + followOffset;
			((Component)this).transform.position = position;
			currentMode = Mode.Follow;
			if ((Object)(object)enemyId != (Object)null)
			{
				enemyId.target = null;
			}
			followCooldownTimer = 0f;
			GabrielAlly.Log.LogDebug((object)"Player is too far; teleporting ally behind the player.");
			return;
		}
		if (currentMode == Mode.Follow)
		{
			Vector3 val = ((Component)instance).transform.position - ((Component)instance).transform.forward * followDistance + followOffset;
			if (Vector3.Distance(((Component)this).transform.position, val) > maxFollowOffsetDistance)
			{
				((Component)this).transform.position = val;
			}
			else
			{
				((Component)this).transform.position = Vector3.Lerp(((Component)this).transform.position, val, Time.deltaTime * 5f);
			}
			followCooldownTimer = 0f;
		}
		List<EnemyIdentifier> list = (from e in Object.FindObjectsOfType<EnemyIdentifier>()
			where (Object)(object)((Component)e).GetComponent<GabrielAllyController>() == (Object)null && !e.dead && (int)e.enemyType != 21 && Vector3.Distance(((Component)this).transform.position, ((Component)e).transform.position) <= attackDistance
			select e).ToList();
		if (list.Count > 0)
		{
			currentMode = Mode.Attack;
			followCooldownTimer = 0f;
		}
		else if (currentMode == Mode.Attack)
		{
			followCooldownTimer += Time.deltaTime;
			if (followCooldownTimer >= followCooldown)
			{
				currentMode = Mode.Follow;
			}
		}
		else
		{
			currentMode = Mode.Follow;
			followCooldownTimer = 0f;
		}
		GabrielAlly.Log.LogDebug((object)$"Current mode is {currentMode}.");
		if (currentMode == Mode.Follow)
		{
			Quaternion val2 = Quaternion.LookRotation(((Component)instance).transform.forward);
			((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, val2, Time.deltaTime * 5f);
			if ((Object)(object)enemyId != (Object)null)
			{
				enemyId.target = null;
			}
		}
		else
		{
			if (currentMode != Mode.Attack)
			{
				return;
			}
			timer += Time.deltaTime;
			if (timer >= updateInterval)
			{
				timer = 0f;
				List<EnemyIdentifier> list2 = (from e in Object.FindObjectsOfType<EnemyIdentifier>()
					where (Object)(object)((Component)e).GetComponent<GabrielAllyController>() == (Object)null && !e.dead && (int)e.enemyType != 21 && Vector3.Distance(((Component)this).transform.position, ((Component)e).transform.position) <= attackDistance
					select e).ToList();
				if (list2.Count > 0)
				{
					EnemyIdentifier val3 = null;
					float num = float.MaxValue;
					foreach (EnemyIdentifier item in list2)
					{
						float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)item).transform.position);
						if (num2 < num)
						{
							num = num2;
							val3 = item;
						}
					}
					if ((Object)(object)val3 != (Object)null)
					{
						EnemyTarget component = ((Component)val3).GetComponent<EnemyTarget>();
						if (component != null)
						{
							enemyId.target = component;
						}
					}
				}
				else
				{
					enemyId.target = null;
				}
			}
			if (enemyId.target != null)
			{
				Vector3 val4 = enemyId.target.headPosition - ((Component)this).transform.position;
				Vector3 normalized = ((Vector3)(ref val4)).normalized;
				Transform transform = ((Component)this).transform;
				transform.position += normalized * 10f * Time.deltaTime;
				Quaternion val5 = Quaternion.LookRotation(normalized);
				((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, val5, Time.deltaTime * 10f);
			}
		}
	}
}
[HarmonyPatch(typeof(EnemyIdentifier), "DeliverDamage")]
public class EnemyIdentifier_DeliverDamage_Patch
{
	private static bool Prefix(EnemyIdentifier __instance, GameObject target, Vector3 force, Vector3 hitPoint, float multiplier, bool tryForExplode, float critMultiplier, GameObject sourceWeapon, bool ignoreTotalDamageTakenMultiplier, bool fromExplosion)
	{
		if ((Object)(object)((Component)__instance).GetComponent<GabrielAllyController>() != (Object)null)
		{
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(EnemyIdentifier), "IsTypeFriendly")]
public class EnemyIdentifier_IsTypeFriendly_Patch
{
	private static bool Prefix(EnemyIdentifier __instance, EnemyIdentifier owner, ref bool __result)
	{
		if ((Object)(object)((Component)__instance).GetComponent<GabrielAllyController>() != (Object)null)
		{
			__result = false;
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(EnemyIdentifier), "Death", new Type[] { })]
public class EnemyIdentifier_Death_Patch
{
	private static void Postfix(EnemyIdentifier __instance)
	{
		GabrielAllyController component = ((Component)__instance).GetComponent<GabrielAllyController>();
		if ((Object)(object)component != (Object)null && !component.hasDied)
		{
			component.hasDied = true;
			string text = __instance.hitter ?? "unknown";
			GabrielAlly.Log.LogInfo((object)(GabrielAllyConfig.selectAlly.GetSelectedIndexName() + " died. Cause: " + text));
			if (!GabrielAlly.IsRespawning)
			{
				GabrielAlly.IsRespawning = true;
				((MonoBehaviour)GabrielAlly.Instance).StartCoroutine(GabrielAlly.RespawnAllyCoroutine(5f));
			}
		}
	}
}
[HarmonyPatch(typeof(DeathZone), "GotHit")]
public class DeathZone_GabrielImmune_Patch
{
	private static bool Prefix(DeathZone __instance, Collider other)
	{
		if ((Object)(object)((Component)other).gameObject.GetComponentInParent<GabrielAllyController>() != (Object)null)
		{
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(OutOfBounds), "OnTriggerEnter")]
public class OutOfBounds_GabrielImmunity_Patch
{
	private static bool Prefix(OutOfBounds __instance, Collider other)
	{
		//IL_004e: 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_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)((Component)other).gameObject.GetComponentInParent<GabrielAllyController>() != (Object)null)
		{
			GabrielAlly.Log.LogInfo((object)(GabrielAllyConfig.selectAlly.GetSelectedIndexName() + " detected in OutOfBounds; teleporting it back behind the player."));
			NewMovement instance = MonoSingleton<NewMovement>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				Vector3 position = ((Component)instance).transform.position - ((Component)instance).transform.forward * 15f + Vector3.up * 1.25f;
				((Component)other).transform.position = position;
			}
			return false;
		}
		return true;
	}
}
public class GabrielAllyConfig : MonoBehaviour
{
	[Configgable("General", "Enable Mod", 0, "Enable or disable the GabrielAlly mod. When disabled, the mod will remove any ally instance.")]
	public static ConfigToggle enableMod = new ConfigToggle(true);

	[Configgable("General", "Select Ally", 1, "Select which ally prefab to use as your ally.")]
	public static ConfigDropdown<string> selectAlly = new ConfigDropdown<string>(new string[6] { "Assets/Prefabs/Enemies/Gabriel.prefab", "Assets/Prefabs/Enemies/Gabriel 2nd Variant.prefab", "Assets/Prefabs/Enemies/V2.prefab", "Assets/Prefabs/Enemies/V2 Green Arm Variant.prefab", "Assets/Prefabs/Enemies/MinosPrime.prefab", "Assets/Prefabs/Enemies/SisyphusPrime.prefab" }, new string[6] { "Gabriel", "Gabriel 2nd Variant", "V2", "V2 Green Arm Variant", "MinosPrime", "SisyphusPrime" }, 0);

	[Configgable("General", "Reset Ally Key", 2, "Key to reset the ally instance when pressed (default: G)")]
	public static ConfigKeybind resetAllyKey = new ConfigKeybind((KeyCode)103);

	[Configgable("Advanced", "Follow Distance", 3, "Distance behind the player when following (default: 10, max: 1000)")]
	public static ConfigInputField<float> followDistance = new ConfigInputField<float>(10f, (Func<float, bool>)((float x) => x <= 1000f), (Func<string, ValueTuple<bool, float>>)null);

	[Configgable("Advanced", "Max Distance From Player", 4, "Maximum allowed distance from the player (default: 80, max: 1000)")]
	public static ConfigInputField<float> maxDistanceFromPlayer = new ConfigInputField<float>(80f, (Func<float, bool>)((float x) => x <= 1000f), (Func<string, ValueTuple<bool, float>>)null);

	[Configgable("Advanced", "Max Follow Offset Distance", 5, "Maximum offset distance from the follow position (default: 50, max: 1000)")]
	public static ConfigInputField<float> maxFollowOffsetDistance = new ConfigInputField<float>(50f, (Func<float, bool>)((float x) => x <= 1000f), (Func<string, ValueTuple<bool, float>>)null);

	[Configgable("Advanced", "Attack Distance", 6, "Distance within which the ally detects enemies (default: 80, max: 1000)")]
	public static ConfigInputField<float> attackDistance = new ConfigInputField<float>(80f, (Func<float, bool>)((float x) => x <= 1000f), (Func<string, ValueTuple<bool, float>>)null);

	[Configgable("Advanced", "Follow Cooldown", 7, "Cooldown in seconds before ally returns to follow mode (default: 5, max: 1000)")]
	public static ConfigInputField<float> followCooldown = new ConfigInputField<float>(5f, (Func<float, bool>)((float x) => x <= 1000f), (Func<string, ValueTuple<bool, float>>)null);

	public static GameObject defaultPrefab;

	private void Awake()
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		ConfigBuilder val = new ConfigBuilder("GabrielAlly.GabrielAllyConfig", "GabrielAlly");
		val.BuildAll();
		ConfigDropdown<string> obj = selectAlly;
		((ConfigValueElement<string>)(object)obj).OnValueChanged = (Action<string>)Delegate.Combine(((ConfigValueElement<string>)(object)obj).OnValueChanged, (Action<string>)delegate
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)GabrielAlly.Instance != (Object)null)
			{
				string text = GabrielAlly.IntendedSceneName;
				if (text == null)
				{
					Scene activeScene = SceneManager.GetActiveScene();
					text = ((Scene)(ref activeScene)).name;
				}
				string text2 = text.Trim().ToLower();
				if (!text2.Equals("intro") && !text2.Equals("main menu") && !text2.Equals("bootstrap"))
				{
					GabrielAlly.Instance.UpdateAllyInstance();
				}
				else
				{
					GabrielAlly.Log.LogInfo((object)("Current scene '" + text2 + "' is special. Not updating ally instance."));
				}
			}
		});
	}
}