Decompiled source of Scoutmasters Rampage v1.0.0

scoutmastersRampage.dll

Decompiled 2 weeks ago
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
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: AssemblyTitle("scoutmastersRampage")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("scoutmastersRampage")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("1d4b7783-e600-4550-bcc2-9d41226bc5c9")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("tony4twentys.scoutmastersrampage", "Scoutmasters Rampage", "1.0.0")]
public class ScoutmasterRampagePlugin : BaseUnityPlugin
{
	private GameObject scoutmasterObject;

	private Character scoutmasterCharacter;

	private Scoutmaster scoutmasterAI;

	private float noTargetTimer = 0f;

	private bool modActive = false;

	private string lastSceneName = "";

	private float gameStartTimer = 0f;

	private bool scoutmasterInitialSpawned = false;

	private float nextSpawnDelayTimer = 0f;

	private int campfireCount = 0;

	private float[] defaultCampfireDelays = new float[4] { 600f, 900f, 900f, 1200f };

	private HashSet<Campfire> litCampfires = new HashSet<Campfire>();

	private const float targetLockDuration = 10f;

	private float targetLockTimer = 0f;

	private bool killedTarget = false;

	private float fallbackRespawnTimer = 0f;

	private bool manualFleeTriggered = false;

	private float lastGrabCheckTime = 0f;

	private int grabEventCount = 0;

	private const int grabThreshold = 5;

	private ConfigEntry<float> configInitialSpawnTime;

	private ConfigEntry<float> configKillCooldown;

	private ConfigEntry<float> configManualFleeCooldown;

	private ConfigEntry<float> configGrabLoopCooldown;

	private ConfigEntry<string> configCampfireDelays;

	private ConfigEntry<KeyCode> configSpawnKey;

	private ConfigEntry<KeyCode> configFleeKey;

	private void Awake()
	{
		configInitialSpawnTime = ((BaseUnityPlugin)this).Config.Bind<float>("General", "InitialSpawnDelay", 300f, "Time (in seconds) until Scoutmaster spawns for the first time.");
		configKillCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Cooldowns", "KillRespawnDelay", 120f, "Cooldown after a player is killed before Scoutmaster respawns.");
		configManualFleeCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Cooldowns", "ManualFleeRespawnDelay", 120f, "Cooldown after manual flee before Scoutmaster respawns.");
		configGrabLoopCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Cooldowns", "GrabLoopRespawnDelay", 10f, "Cooldown after a grab loop is detected.");
		configCampfireDelays = ((BaseUnityPlugin)this).Config.Bind<string>("Cooldowns", "CampfireDelays", "600,900,900,1200", "Comma-separated cooldowns (in seconds) per campfire lighting.");
		configSpawnKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "SpawnKey", (KeyCode)290, "Key used to manually spawn the Scoutmaster.");
		configFleeKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "FleeKey", (KeyCode)289, "Key used to manually trigger Scoutmaster flee.");
	}

	private void Update()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		string name = ((Scene)(ref activeScene)).name;
		if (name != lastSceneName)
		{
			lastSceneName = name;
			if (name == "Airport")
			{
				if (modActive)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)$"[{Time.time:F2}s] Returned to Airport. Resetting state.");
					ResetMod();
				}
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] Game world active. Starting logic.");
				modActive = true;
			}
		}
		if (name == "Airport")
		{
			return;
		}
		if (Input.GetKeyDown(configSpawnKey.Value) && (Object)(object)scoutmasterCharacter == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] {configSpawnKey.Value}: Manually spawning Scoutmaster.");
			SpawnScoutmaster();
			scoutmasterInitialSpawned = true;
		}
		if (Input.GetKeyDown(configFleeKey.Value))
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] {configFleeKey.Value}: Manually triggering flee.");
			TriggerFlee(killed: false);
			manualFleeTriggered = true;
			fallbackRespawnTimer = 0f;
		}
		if (!scoutmasterInitialSpawned)
		{
			gameStartTimer += Time.deltaTime;
			if (gameStartTimer >= configInitialSpawnTime.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] Initial delay passed. Spawning Scoutmaster.");
				SpawnScoutmaster();
				scoutmasterInitialSpawned = true;
			}
		}
		else
		{
			TrackLitCampfires();
		}
		if ((Object)(object)scoutmasterCharacter == (Object)null && nextSpawnDelayTimer > 0f)
		{
			nextSpawnDelayTimer -= Time.deltaTime;
			if (nextSpawnDelayTimer <= 0f)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] Spawn delay expired. Spawning Scoutmaster.");
				SpawnScoutmaster();
			}
		}
		if ((Object)(object)scoutmasterCharacter == (Object)null && (killedTarget || manualFleeTriggered) && nextSpawnDelayTimer <= 0f)
		{
			fallbackRespawnTimer += Time.deltaTime;
			float num = (killedTarget ? configKillCooldown.Value : configManualFleeCooldown.Value);
			if (fallbackRespawnTimer >= num)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] Fallback cooldown passed. Spawning Scoutmaster.");
				killedTarget = false;
				manualFleeTriggered = false;
				fallbackRespawnTimer = 0f;
				SpawnScoutmaster();
			}
		}
		if ((Object)(object)scoutmasterCharacter != (Object)null)
		{
			UpdateTarget();
			MonitorEvasiveMode();
			MonitorGrabLoop();
		}
	}

	private void ResetMod()
	{
		scoutmasterCharacter = null;
		scoutmasterObject = null;
		scoutmasterAI = null;
		gameStartTimer = 0f;
		scoutmasterInitialSpawned = false;
		litCampfires.Clear();
		campfireCount = 0;
		nextSpawnDelayTimer = 0f;
		fallbackRespawnTimer = 0f;
		killedTarget = false;
		manualFleeTriggered = false;
		grabEventCount = 0;
		lastGrabCheckTime = 0f;
	}

	private void MonitorGrabLoop()
	{
		if (!((Object)(object)scoutmasterCharacter != (Object)null) || !((Object)(object)scoutmasterAI != (Object)null))
		{
			return;
		}
		object? obj = ((object)scoutmasterCharacter.data).GetType().GetField("grabbedPlayer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(scoutmasterCharacter.data);
		Character val = (Character)((obj is Character) ? obj : null);
		if ((Object)(object)val != (Object)null && Time.time - lastGrabCheckTime > 1f)
		{
			Player owner = val.refs.view.Owner;
			string arg = ((owner != null) ? owner.NickName : null) ?? "Unknown";
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] Scoutmaster has grabbed {arg}.");
			grabEventCount++;
			lastGrabCheckTime = Time.time;
			if (grabEventCount >= 5)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"[{Time.time:F2}s] Grab loop detected. Triggering flee + {configGrabLoopCooldown.Value}s respawn.");
				TriggerFlee(killed: false);
				nextSpawnDelayTimer = configGrabLoopCooldown.Value;
				grabEventCount = 0;
			}
		}
		else if ((Object)(object)val == (Object)null)
		{
			grabEventCount = 0;
		}
	}

	private void TrackLitCampfires()
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		string[] array = configCampfireDelays.Value.Split(new char[1] { ',' });
		Campfire[] array2 = Object.FindObjectsOfType<Campfire>();
		Campfire[] array3 = array2;
		foreach (Campfire val in array3)
		{
			if (!val.Lit || litCampfires.Contains(val) || ((Component)val).transform.position.y < 250f)
			{
				continue;
			}
			litCampfires.Add(val);
			float result = 0f;
			if (campfireCount < array.Length && float.TryParse(array[campfireCount], out result))
			{
				nextSpawnDelayTimer = result;
			}
			else
			{
				if (campfireCount >= defaultCampfireDelays.Length)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] Extra fire lit. No additional delay.");
					continue;
				}
				nextSpawnDelayTimer = defaultCampfireDelays[campfireCount];
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] Campfire #{campfireCount + 1} lit. Delay set: {nextSpawnDelayTimer}s");
			campfireCount++;
			killedTarget = false;
			TriggerFlee(killed: false);
		}
	}

	private void SpawnScoutmaster()
	{
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: 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_00cd: 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_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: 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_007e: 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_0094: Unknown result type (might be due to invalid IL or missing references)
		if (!PhotonNetwork.IsMasterClient)
		{
			return;
		}
		Character val = null;
		float num = float.MaxValue;
		foreach (Character allCharacter in Character.AllCharacters)
		{
			if (!allCharacter.isBot && !allCharacter.data.dead && !allCharacter.data.fullyPassedOut && ((Component)allCharacter).transform.position.y > 250f && allCharacter.Center.y < num)
			{
				num = allCharacter.Center.y;
				val = allCharacter;
			}
		}
		Vector3 val2 = Vector3.zero;
		Quaternion val3 = Quaternion.identity;
		if ((Object)(object)val != (Object)null)
		{
			Vector3 center = val.Center;
			Vector3 val4 = -((Component)val).transform.forward;
			val2 = center + val4 * 20f;
			val2.y -= 10f;
			val3 = Quaternion.LookRotation(center - val2);
		}
		scoutmasterObject = PhotonNetwork.InstantiateRoomObject("Character_Scoutmaster", val2, val3, (byte)0, (object[])null);
		scoutmasterCharacter = scoutmasterObject.GetComponent<Character>();
		scoutmasterAI = scoutmasterObject.GetComponent<Scoutmaster>();
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"[{Time.time:F2}s] Scoutmaster spawned.");
	}

	private void UpdateTarget()
	{
		//IL_0135: 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)
		if ((Object)(object)scoutmasterCharacter == (Object)null || (Object)(object)scoutmasterAI == (Object)null || scoutmasterCharacter.data.dead)
		{
			return;
		}
		Character currentTarget = scoutmasterAI.currentTarget;
		if ((Object)(object)currentTarget != (Object)null && (currentTarget.data.dead || currentTarget.data.fullyPassedOut))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)$"[{Time.time:F2}s] Target dead/passed out. Triggering flee + fallback.");
			TriggerFlee(killed: true);
			return;
		}
		targetLockTimer += Time.deltaTime;
		if ((Object)(object)currentTarget != (Object)null && targetLockTimer < 10f)
		{
			return;
		}
		Character val = null;
		float num = float.MaxValue;
		foreach (Character allCharacter in Character.AllCharacters)
		{
			if (!allCharacter.isBot && !allCharacter.data.dead && !allCharacter.data.fullyPassedOut && (Object)(object)allCharacter != (Object)(object)scoutmasterCharacter && allCharacter.Center.y < num)
			{
				num = allCharacter.Center.y;
				val = allCharacter;
			}
		}
		if ((Object)(object)val != (Object)null)
		{
			typeof(Scoutmaster).GetMethod("SetCurrentTarget", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(scoutmasterAI, new object[2] { val, 10f });
			targetLockTimer = 0f;
			noTargetTimer = 0f;
		}
		else
		{
			noTargetTimer += Time.deltaTime;
			if (noTargetTimer > 10f)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"[{Time.time:F2}s] No valid targets. Triggering flee.");
				TriggerFlee(killed: false);
			}
		}
	}

	private void MonitorEvasiveMode()
	{
		if (!((Object)(object)scoutmasterAI == (Object)null) && !((Object)(object)scoutmasterAI.currentTarget != (Object)null) && !scoutmasterCharacter.data.fullyPassedOut)
		{
			object? obj = typeof(Scoutmaster).GetField("discovered", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(scoutmasterAI);
			Character val = (Character)((obj is Character) ? obj : null);
			if ((Object)(object)val != (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"[{Time.time:F2}s] Scoutmaster entered evasive mode. Triggering flee.");
				TriggerFlee(killed: false);
			}
		}
	}

	private void TriggerFlee(bool killed)
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0:F2}s] Scoutmaster flee triggered. Cause: {1}\n", Time.time, killed ? "Kill" : "Other"));
		if ((Object)(object)scoutmasterObject != (Object)null)
		{
			PhotonNetwork.Destroy(scoutmasterObject);
		}
		scoutmasterObject = null;
		scoutmasterCharacter = null;
		scoutmasterAI = null;
		if (killed && nextSpawnDelayTimer <= 0f)
		{
			killedTarget = true;
			fallbackRespawnTimer = 0f;
		}
		else if (manualFleeTriggered && nextSpawnDelayTimer <= 0f)
		{
			manualFleeTriggered = true;
			fallbackRespawnTimer = 0f;
		}
	}
}