using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using PEAKLib.Core; using Peak.Afflictions; using Photon.Pun; using Photon.Realtime; using PhotonCustomPropsUtils; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Scoutmasters Rampage")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Scoutmasters Rampage")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("93833b97-8a74-49f6-98d7-bcfbfffef43e")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace ScoutmasterRampage { [BepInPlugin("tony4twentys.scoutmastersrampage", "Scoutmasters Rampage", "3.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class ScoutmasterRampagePlugin : BaseUnityPlugin { [HarmonyPatch(typeof(RunManager), "StartRun")] public class StartRunPatch { private static void Postfix() { if (!((Object)(object)Singleton.Instance == (Object)null) && PhotonNetwork.IsMasterClient) { Instance.RefreshRespawnDelays(); Instance.ResetRunState(); Instance.IncreaseLitFireCount(); } } } [HarmonyPatch(typeof(Scoutmaster), "FixedUpdate")] private static class FixedUpdatePatch { private static bool Prefix(Scoutmaster __instance) { if (ScoutmasterPassOutSupport.IsScoutmasterDisabledForGrabOrPhysics(__instance.character)) { return false; } return true; } } [HarmonyPatch(typeof(CharacterGrabbing), "GrabAction")] public class ScoutmasterGrabActionPatch { private static bool Prefix(CharacterGrabbing __instance, Collision collision) { //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: 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_0124: Invalid comparison between Unknown and I4 //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected I4, but got Unknown //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) if (!__instance.character.data.isScoutmaster || !((MonoBehaviourPun)__instance.character).photonView.IsMine || Object.op_Implicit((Object)(object)__instance.character.data.grabJoint) || !__instance.character.data.isReaching || __instance.character.data.sinceLetGoOfFriend < 0.35f || !Object.op_Implicit((Object)(object)collision.rigidbody)) { return true; } if (!PhotonNetwork.IsMasterClient) { return true; } if (ScoutmasterPassOutSupport.IsScoutmasterDisabledForGrabOrPhysics(__instance.character)) { return false; } Scoutmaster component = ((Component)__instance.character).GetComponent(); if ((Object)(object)component != (Object)null && ScoutmasterNapberrySupport.IsTargetRepellingScoutmaster(component)) { return false; } Character val = default(Character); if (!CharacterRagdoll.TryGetCharacterFromCollider(collision.collider, ref val) || !Object.op_Implicit((Object)(object)val) || (Object)(object)val == (Object)(object)__instance.character) { return false; } BodypartType partType = val.GetPartType(collision.rigidbody); if ((int)partType != -1 && (Object)(object)__instance.character.data.grabbedPlayer == (Object)null && Instance.sinceLastGrabbedTimer >= 3f) { ((MonoBehaviourPun)__instance.character).photonView.RPC("RPCA_GrabAttach", (RpcTarget)0, new object[3] { ((MonoBehaviourPun)val).photonView, (int)partType, ((Component)collision.rigidbody).transform.InverseTransformPoint(((Component)__instance.character.GetBodypart((BodypartType)10).Rig).transform.position) }); Instance.sinceLastGrabbedTimer = 0f; } return false; } } [HarmonyPatch] private static class ScoutmasterIThrowInjuryTranspiler { private static MethodBase TargetMethod() { Type[] nestedTypes = typeof(Scoutmaster).GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); foreach (Type type in nestedTypes) { if (type.Name.Contains("IThrow")) { MethodInfo methodInfo = AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null); if (methodInfo != null) { return methodInfo; } } } throw new Exception("Scoutmasters Rampage: could not find Scoutmaster. MoveNext for GrabInjuryAmount patch."); } private static IEnumerable Transpiler(IEnumerable instructions) { MethodInfo getInjury = AccessTools.Method(typeof(ScoutmasterIThrowInjuryTranspiler), "GetConfiguredGrabInjuryAmount", (Type[])null, (Type[])null); bool replaced = false; foreach (CodeInstruction instruction in instructions) { if (!replaced && instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float value && Mathf.Approximately(value, 0.25f)) { yield return new CodeInstruction(OpCodes.Call, (object)getInjury); replaced = true; } else { yield return instruction; } } if (!replaced) { Debug.LogWarning((object)"[Scoutmasters Rampage] IThrow injury transpiler did not find ldc.r4 0.25 — GrabInjuryAmount may not apply."); } } private static float GetConfiguredGrabInjuryAmount() { if (Instance?.configGrabInjuryAmount == null) { return 0.25f; } return Mathf.Clamp(Instance.configGrabInjuryAmount.Value, 0f, 1f); } } [HarmonyPatch(typeof(Scoutmaster), "DoVisuals")] public static class DoVisualsPatch { private static bool Prefix(Scoutmaster __instance) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (Instance.configDisableScreenEffect.Value || Instance.configScreenEffectPower.Value <= 0f) { __instance.mat.SetFloat("_Strength", 0f); return false; } float num = 0f; if ((Object)(object)__instance.currentTarget != (Object)null) { __instance.currentTarget.data.myersDistance = Vector3.Distance(__instance.character.Center, __instance.currentTarget.Center); } if ((Object)(object)__instance.currentTarget != (Object)null && __instance.currentTarget.IsLocal) { num = Mathf.InverseLerp(50f, 5f, __instance.distanceToTarget); } num *= Instance.configScreenEffectPower.Value; __instance.mat.SetFloat("_Strength", Mathf.Lerp(__instance.mat.GetFloat("_Strength"), num, Time.deltaTime * 0.5f)); return false; } } [HarmonyPatch(typeof(Scoutmaster), "Update")] public class ScoutmasterUpdatePatch { private static bool Prefix(Scoutmaster __instance) { //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient) { return true; } __instance.UpdateAchievement(); __instance.DoVisuals(); if (Instance.HandleFleeing(__instance)) { return false; } if (!Instance.scoutmasterHasSpawned) { return false; } if (ScoutmasterRescueHookSupport.IsPullingScoutmaster(__instance.character)) { return false; } if (Instance.resetInputRequest) { __instance.ResetInput(); Instance.resetInputRequest = false; } if (ScoutmasterPassOutSupport.HandlePassOut(__instance)) { return false; } if (ScoutmasterNapberrySupport.TryOrbRepelMovement(__instance)) { return false; } if ((Object)(object)__instance.character.data.grabbedPlayer == (Object)null) { Instance.sinceLastGrabbedTimer += Time.deltaTime; } __instance.tpCounter += Time.deltaTime; Instance.HandleTargeting(__instance); if ((Object)(object)__instance.currentTarget == (Object)null) { return false; } __instance.CalcVars(); __instance.distanceToTarget = Vector3.Distance(__instance.character.Center, __instance.currentTarget.Center); if (Instance.TryCloseGapTeleport(__instance)) { return false; } Instance.Chase(__instance); return false; } } [HarmonyPatch(typeof(Campfire), "Light_Rpc")] public class CampfireLight_RpcPatch { private static void Postfix(bool updateSegment) { if (updateSegment && PhotonNetwork.IsMasterClient) { Instance.IncreaseLitFireCount(); } } } [HarmonyPatch(typeof(ScoutmasterSpawner), "SpawnScoutmaster")] public class ScoutmasterSpawnerPatch { private static void Postfix() { Scoutmaster val = default(Scoutmaster); if (PhotonNetwork.IsMasterClient && Scoutmaster.GetPrimaryScoutmaster(ref val)) { Instance.scoutmaster = val; Instance.scoutmasterCharacter = val.character; Instance.LogInfo("Scoutmaster reference captured from spawner."); } } } [HarmonyPatch(typeof(Scoutmaster), "TeleportFarAway")] public class ScoutmasterTeleportPatch { private static void Postfix(Scoutmaster __instance) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (Instance.isFleeing && PhotonNetwork.IsMasterClient) { ((Component)__instance).GetComponent().RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { (object)new Vector3(0f, 0f, 5000f), false }); ((Component)__instance).GetComponent().RPC("StopClimbingRpc", (RpcTarget)0, new object[1] { 0f }); __instance.discovered = null; } } } [HarmonyPatch(typeof(Bonkable), "Bonk")] private static class BonkPatch { private static bool Prefix(Bonkable __instance, Collision coll) { //IL_00c3: 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_00cc: 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_0104: Unknown result type (might be due to invalid IL or missing references) Character val = default(Character); if (!CharacterRagdoll.TryGetCharacterFromCollider(coll.collider, ref val) || !Object.op_Implicit((Object)(object)val) || !val.isScoutmaster) { return true; } Scoutmaster component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null || Time.time <= __instance.lastBonkedTime + __instance.bonkCooldown) { return (Object)(object)component != (Object)null; } ScoutmasterBlessingSupport.TryGrantFromBonk(__instance.item); if (!PhotonNetwork.IsMasterClient) { return true; } float num = __instance.bonkForce; if (__instance.bonkMassMultiplier) { num *= ((Component)__instance.item).GetComponent().currentScale; } ScoutmasterRampagePlugin instance = Instance; Character character = val; Vector3 relativeVelocity = coll.relativeVelocity; instance.ApplyScoutmasterBonk(character, component, ((Vector3)(ref relativeVelocity)).normalized, num, __instance.bonkRange, ((ContactPoint)(ref coll.contacts[0])).point); for (int i = 0; i < __instance.bonk.Length; i++) { __instance.bonk[i].Play(((Component)__instance).transform.position); } __instance.lastBonkedTime = Time.time; return false; } } [HarmonyPatch(typeof(BananaPeel), "Update")] private static class UpdatePatch { private static void Postfix(BananaPeel __instance) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) Scoutmaster val = default(Scoutmaster); if ((int)__instance.item.itemState == 0 && PhotonNetwork.IsMasterClient && Scoutmaster.GetPrimaryScoutmaster(ref val) && !(__instance.counter < 3f) && !(Vector3.Distance(val.character.Center, ((Component)__instance).transform.position) > 3f) && val.character.data.isGrounded && !(((Vector3)(ref val.character.data.avarageVelocity)).magnitude < 1.5f)) { __instance.counter = 0f; ((Component)__instance).GetComponent().RPC("RPCA_TriggerBanana", (RpcTarget)0, new object[1] { val.character.view.ViewID }); PhotonNetwork.Destroy(((Component)__instance).gameObject); } } } public const string PluginGuid = "tony4twentys.scoutmastersrampage"; public const string PluginName = "Scoutmasters Rampage"; public const string PluginVersion = "3.0.0"; public const string PhotonCustomPropsPluginGuid = "com.snosz.photoncustompropsutils"; private ConfigEntry configInitialSpawn; private ConfigEntry configFire2Delay; private ConfigEntry configFire3Delay; private ConfigEntry configFire4Delay; private ConfigEntry configFire5Delay; private ConfigEntry configEnableLogs; private ConfigEntry configTeleportDistance; private ConfigEntry configLostSightTeleportTime; private ConfigEntry configTeleportCooldown; private ConfigEntry configTeleportMinDistance; private ConfigEntry configTeleportMaxDistance; private ConfigEntry configTeleportMaxHeight; private ConfigEntry configFleeDuration; private ConfigEntry configSprintDistance; private ConfigEntry configMovementBoostDistance; private ConfigEntry configMovementBoostMultiplier; private ConfigEntry configInstaKillOnGrab; private ConfigEntry configGrabInjuryAmount; private ConfigEntry configClimbSpeed; private ConfigEntry configRunSpeed; private ConfigEntry configFaerieLanternFleeDistance; private ConfigEntry configBonkStunDuration; private ConfigEntry configForceRespawnBehindDistance; private ConfigEntry configSpawnDropHeight; private ConfigEntry configForceScoutmasterRespawn; private ConfigEntry configDisableScreenEffect; private ConfigEntry configScreenEffectPower; private float[] respawnDelays; private int litFireCount = -1; private float respawnEndTime = -1f; private const string LogPrefix = "[Scoutmasters Rampage] "; private float lingerTimer = 0f; private float targetingTimer = 0f; private float sinceLastGrabbedTimer = 0f; private float fleeTimer = 0f; private bool scoutmasterHasSpawned = false; private bool resetInputRequest = false; private const float SpawnRetryDelay = 3f; private const float StuckHorizontalTolerance = 2f; private const float StuckLingerTime = 3f; private const float StuckMinVerticalSeparation = 10f; private const float StuckTeleportMinDistance = 30f; private const float StuckTeleportMaxDistance = 50f; private const float StuckTeleportMaxHeight = 15f; private const float TargetRetargetInterval = 3f; private const float GrabCooldown = 3f; private const float ForceRespawnAirborneHeight = 5f; private const float SpawnGroundRaycastHeight = 150f; private const float SpawnGroundRaycastDepth = 500f; private bool isSpawning = false; private Scoutmaster scoutmaster; private Character scoutmasterCharacter; private bool isFleeing; private bool passOutRetreatTriggersRespawn; private Vector3? fleeAwayFrom; internal static ScoutmasterRampagePlugin Instance { get; private set; } internal float FaerieLanternFleeDistance => configFaerieLanternFleeDistance.Value; internal bool IsFleeing => isFleeing; internal bool IsPassOutRetreatActive => passOutRetreatTriggersRespawn; internal bool IsTargetHoldingLitFaerieLantern(Character target) { object obj; if (target == null) { obj = null; } else { CharacterData data = target.data; obj = ((data != null) ? data.currentItem : null); } return (Object)obj != (Object)null && target.data.currentItem.itemID == 43 && target.data.currentItem.GetData((DataEntryKey)3).Value; } private void Awake() { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) Instance = this; SetupConfig(); ScoutmasterBlowDartSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterRescueHookSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterOverheadStatus.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterAfflictionSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterFallDamageSupport.Initialize(); ScoutmasterPassOutSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterNapberrySupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterWindChillSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterLavaSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterKilnSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterTorchSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterLootSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterBlessingSupport.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterConfigSyncService.Initialize(((BaseUnityPlugin)this).Config); ScoutmasterModAuthorizationService.Initialize(); RefreshRespawnDelays(); try { new Harmony("tony4twentys.scoutmastersrampage").PatchAll(); LogInfo("Plugin initialized and Harmony patches applied."); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Harmony PatchAll failed — some features may not work: {arg}"); } SceneManager.sceneLoaded += OnSceneLoaded; ScoutmasterBlessingSupport.EnsureEventHook(); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (ShouldResetRunStateForScene(scene, mode)) { LogInfo($"Scene '{((Scene)(ref scene)).name}' ({mode}) — resetting run state for a fresh expedition."); ResetRunState(); } TryGetScoutmaster(out var _); ScoutmasterBlessingSupport.EnsureEventHook(); } private static bool ShouldResetRunStateForScene(Scene scene, LoadSceneMode mode) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 if (!((Scene)(ref scene)).IsValid() || string.IsNullOrEmpty(((Scene)(ref scene)).name)) { return false; } if ((int)mode == 1) { return false; } string name = ((Scene)(ref scene)).name; if (name.Equals("Airport", StringComparison.OrdinalIgnoreCase) || name.Equals("Title", StringComparison.OrdinalIgnoreCase) || name.Equals("Pretitle", StringComparison.OrdinalIgnoreCase)) { return true; } return name.StartsWith("Level_", StringComparison.OrdinalIgnoreCase); } private void ResetRunState() { litFireCount = -1; respawnEndTime = -1f; scoutmasterHasSpawned = false; isSpawning = false; isFleeing = false; scoutmaster = null; scoutmasterCharacter = null; lingerTimer = 0f; targetingTimer = 0f; sinceLastGrabbedTimer = 0f; fleeTimer = 0f; passOutRetreatTriggersRespawn = false; fleeAwayFrom = null; ScoutmasterOverheadStatus.Reset(); ScoutmasterPassOutSupport.Reset(); ScoutmasterTorchSupport.Reset(); ScoutmasterAfflictionSupport.ResetStatusSync(); } internal void RefreshRespawnDelaysPublic() { RefreshRespawnDelays(); } private void RefreshRespawnDelays() { respawnDelays = new float[5] { configInitialSpawn.Value, configFire2Delay.Value, configFire3Delay.Value, configFire4Delay.Value, configFire5Delay.Value }; } internal bool TryGetScoutmaster(out Scoutmaster resolved) { if (Scoutmaster.GetPrimaryScoutmaster(ref resolved)) { scoutmaster = resolved; scoutmasterCharacter = resolved.character; return true; } if ((Object)(object)scoutmaster != (Object)null) { resolved = scoutmaster; return true; } resolved = null; return false; } private Character FindFurthestBehindPlayer() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) Character result = null; float num = float.MinValue; Vector3 position; bool hasCampfire = TryGetCurrentCampfirePosition(out position); foreach (Character allCharacter in Character.AllCharacters) { if (IsViablePlayer(allCharacter)) { float behindScore = GetBehindScore(allCharacter, hasCampfire, position); if (behindScore > num) { num = behindScore; result = allCharacter; } } } return result; } private static bool IsViablePlayer(Character character) { return (Object)(object)character != (Object)null && !character.isBot && !character.data.dead && !character.data.fullyPassedOut; } private float GetBehindScore(Character character, bool hasCampfire, Vector3 campfirePos) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (hasCampfire) { float num = Vector3.Distance(character.Center, campfirePos); float num2 = Mathf.Max(0f, campfirePos.y - character.Center.y); return num + num2; } return 0f - character.Center.y; } private bool TryGetCurrentCampfirePosition(out Vector3 position) { //IL_0002: 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) position = default(Vector3); if (!MapHandler.Exists) { return false; } MapHandler instance = Singleton.Instance; if ((Object)(object)instance == (Object)null) { return false; } Campfire val = TryGetCampfireForSegment(instance.currentSegment); if ((Object)(object)val == (Object)null && instance.currentSegment > 0) { val = TryGetCampfireForSegment(instance.currentSegment - 1); } if ((Object)(object)val == (Object)null) { return false; } position = val.Center(); return true; } private static Campfire TryGetCampfireForSegment(int segmentIndex) { if (segmentIndex < 0) { return null; } GameObject campfireRoot = MapHandler.GetCampfireRoot(segmentIndex); if ((Object)(object)campfireRoot == (Object)null) { return null; } return campfireRoot.GetComponentInChildren(true); } private void ForceRespawnScoutmasterFromHotkey() { try { if (!TryGetScoutmaster(out var _)) { LogWarning("F1 force respawn — scoutmaster not found."); return; } Character val = FindFurthestBehindPlayer(); if ((Object)(object)val == (Object)null) { LogWarning("F1 force respawn — no valid players found."); } else { PlaceScoutmasterBehindPlayer(val, "F1 force respawn"); } } catch (Exception ex) { LogWarning("F1 force respawn failed (" + ex.Message + ")."); } } private void PlaceScoutmasterBehindPlayer(Character player, string reason) { if (!TryGetScoutmaster(out var resolved) || (Object)(object)player == (Object)null) { LogWarning("Cannot place Scoutmaster — scoutmaster or target character is missing."); return; } ScoutmasterSegmentSupport.EnsureScoutmasterSpawnable(resolved); isSpawning = false; isFleeing = false; fleeTimer = 0f; scoutmasterHasSpawned = true; ReleaseGrabIfNeeded(resolved); resolved.view.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { -1, 0f }); Vector3 spawnPosition; bool flag = ScoutmasterKilnSupport.TryGetKilnSpawnPosition(player, out spawnPosition); WarpNearPlayer(resolved, player); targetingTimer = 3f; if (flag) { Player owner = player.refs.view.Owner; LogInfo(reason + " — placed on standable kiln ground near " + (((owner != null) ? owner.NickName : null) ?? "Unknown") + "."); } else { object arg = configForceRespawnBehindDistance.Value; Player owner2 = player.refs.view.Owner; LogInfo(string.Format("{0} — placed {1:F0}m behind {2} (furthest behind on climb).", reason, arg, ((owner2 != null) ? owner2.NickName : null) ?? "Unknown")); } resetInputRequest = true; } private void SetupConfig() { //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Expected O, but got Unknown //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Expected O, but got Unknown //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Expected O, but got Unknown configForceScoutmasterRespawn = ((BaseUnityPlugin)this).Config.Bind("General", "ForceScoutmasterRespawn", (KeyCode)282, "Keyboard key the host presses to instantly reposition the scoutmaster. Only works for the master client (host). He is placed behind whichever player is furthest behind on the climb (furthest from the current campfire, with height below the fire counting as extra \"behind\"). Useful if he is stuck, fell off the map, or you need to reset a bad chase. Does not restart spawn timers."); configDisableScreenEffect = ((BaseUnityPlugin)this).Config.Bind("General", "DisableScreenEffect", false, "Turns off the vanilla scoutmaster screen effect (grain/distortion on the targeted player) entirely when true. If false, intensity is controlled by ScreenEffectPower instead."); configScreenEffectPower = ((BaseUnityPlugin)this).Config.Bind("General", "ScreenEffectPower", 0.5f, "Multiplier for the scoutmaster screen effect on the player he is chasing. 0 = no effect, 0.5 = half intensity (default), 1 = full vanilla intensity. Effect ramps up as he gets closer (strongest inside roughly 5m, fades out toward ~50m). DisableScreenEffect overrides this when true."); configInitialSpawn = ((BaseUnityPlugin)this).Config.Bind("Delays", "InitialSpawn", 300f, "Seconds after the expedition starts before the scoutmaster first appears. When the timer ends, he spawns behind the furthest-behind player. Default 300 = 5 minutes. Host-only. Set lower for faster first contact, higher to delay his debut."); configFire2Delay = ((BaseUnityPlugin)this).Config.Bind("Delays", "Fire2Respawn", 600f, "Seconds to wait before respawning the scoutmaster after the first campfire segment is lit. When that fire is lit, he is sent away (flees, then teleports off the map) and returns after this delay. Default 600 = 10 minutes."); configFire3Delay = ((BaseUnityPlugin)this).Config.Bind("Delays", "Fire3Respawn", 900f, "Seconds to wait before respawning the scoutmaster after the second campfire segment is lit. Same flee-then-respawn cycle as other fire delays. Default 900 = 15 minutes."); configFire4Delay = ((BaseUnityPlugin)this).Config.Bind("Delays", "Fire4Respawn", 420f, "Seconds to wait before respawning the scoutmaster after the third campfire segment is lit. Default 420 = 7 minutes."); configFire5Delay = ((BaseUnityPlugin)this).Config.Bind("Delays", "Fire5Respawn", 900f, "Seconds to wait before respawning the scoutmaster after the fourth campfire segment is lit. Also used when the fifth segment (kiln) is lit. Default 900 = 15 minutes."); configEnableLogs = ((BaseUnityPlugin)this).Config.Bind("Debug", "EnableLogs", false, "Writes detailed scoutmaster events to the BepInEx LogOutput.log (spawns, teleports, fire timers, F1 respawns, warnings). Off by default. Turn on only when troubleshooting."); configTeleportDistance = ((BaseUnityPlugin)this).Config.Bind("Chase", "TeleportDistance", 80f, "If the chase target is farther away than this many meters, the scoutmaster attempts a close-gap teleport toward them (landing somewhere between TeleportMinDistance and TeleportMaxDistance away, within TeleportMaxHeight vertically). Lower = he teleports sooner when players spread out. Higher = he runs/climbs longer before blinking. Default matches vanilla ~80m."); configLostSightTeleportTime = ((BaseUnityPlugin)this).Config.Bind("Chase", "LostSightTeleportTime", 30f, "If the scoutmaster has a target but cannot see them for this many seconds, AND no player currently has line-of-sight to him, he teleports closer using the same min/max distance and height rules as normal close teleports. Set to 0 to disable lost-sight teleports entirely. Default 30 seconds."); configTeleportCooldown = ((BaseUnityPlugin)this).Config.Bind("Chase", "TeleportCooldown", 5f, "Minimum seconds between close-gap teleports during chase. The game’s built-in Teleport() also enforces a 5 second floor, so values below 5 will not make in-chase teleports faster—only some internal timers use the lower value. Increase to make him blink less often."); configTeleportMinDistance = ((BaseUnityPlugin)this).Config.Bind("Chase", "TeleportMinDistance", 50f, "Closest the scoutmaster can land to his target when using a close-gap or lost-sight teleport (meters). Prevents him from appearing right on top of players. Default 50."); configTeleportMaxDistance = ((BaseUnityPlugin)this).Config.Bind("Chase", "TeleportMaxDistance", 70f, "Farthest he can land from his target on a close-gap or lost-sight teleport (meters). Works with TeleportMinDistance to define the landing ring around the target. Default 70."); configTeleportMaxHeight = ((BaseUnityPlugin)this).Config.Bind("Chase", "TeleportMaxHeight", 15f, "Maximum vertical difference between the scoutmaster’s landing spot and his target on close-gap / lost-sight teleports (meters). Stops him from teleporting to unrealistic heights above or below the target. Default 15."); configFleeDuration = ((BaseUnityPlugin)this).Config.Bind("Chase", "FleeDuration", 4f, "When a campfire respawn cycle sends the scoutmaster away, he runs from players for this many seconds before teleporting far off the map. Shorter = quicker despawn. Longer = more visible \"retreat\" before he vanishes. Default 4 seconds."); configSprintDistance = ((BaseUnityPlugin)this).Config.Bind("Chase", "SprintDistance", 15f, "While chasing, he holds sprint when farther than this many meters from his target (straight-line distance). Lower = sprints more often. Higher = jogs until he is closer. Default 15."); configMovementBoostDistance = ((BaseUnityPlugin)this).Config.Bind("Chase", "MovementBoostDistance", 15f, "Flat (XZ) distance within which MovementBoostMultiplier kicks in. This is a short-range closing boost when he is already near the target—not the same as ClimbSpeed/RunSpeed. Default 15 meters."); configMovementBoostMultiplier = ((BaseUnityPlugin)this).Config.Bind("Chase", "MovementBoostMultiplier", 1.2f, "Extra ground-speed multiplier only while within MovementBoostDistance of the target (default 1.2 = +20%). Stacks on top of RunSpeed. ClimbSpeed/RunSpeed scale his overall chase pace; this only speeds him up in the last stretch to help close for a grab."); configInstaKillOnGrab = ((BaseUnityPlugin)this).Config.Bind("Chase", "InstaKillOnGrab", false, "When true, grabbing a player instantly kills them (DieInstantly) instead of the normal hold-and-throw. Off by default."); configGrabInjuryAmount = ((BaseUnityPlugin)this).Config.Bind("Chase", "GrabInjuryAmount", 0.25f, new ConfigDescription("Injury status applied to the grabbed player when the scoutmaster finishes his throw. Vanilla default is 0.25. Set to 0 for no throw injury. Ignored when InstaKillOnGrab is true.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); configClimbSpeed = ((BaseUnityPlugin)this).Config.Bind("Chase", "ClimbSpeed", 1f, new ConfigDescription("Adjustment to the scoutmaster’s climb speed while chasing. 1.0 = vanilla. Higher = climbs faster. Capped at 5.0.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); configRunSpeed = ((BaseUnityPlugin)this).Config.Bind("Chase", "RunSpeed", 1f, new ConfigDescription("Adjustment to the scoutmaster’s ground run/walk speed while chasing. 1.0 = vanilla. Stacks with MovementBoostMultiplier when in range. Capped at 5.0.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); configBonkStunDuration = ((BaseUnityPlugin)this).Config.Bind("Interactions", "BonkStunDuration", 5f, "How long the scoutmaster ragdolls/falls when hit by a bonkable object like a coconut (host only). Also interrupts grabs and throws. Default 5 seconds. Blow darts use drowsy afflictions instead."); configFaerieLanternFleeDistance = ((BaseUnityPlugin)this).Config.Bind("Interactions", "FaerieLanternFleeDistance", 20f, "If his target is holding a lit faerie lantern (item ID 43, flare active) and he is within this many meters (flat distance), he walks backward instead of toward them—vanilla-style lantern repel behavior preserved by the mod. Default 20."); configForceRespawnBehindDistance = ((BaseUnityPlugin)this).Config.Bind("ForceRespawn", "BehindDistance", 10f, "Meters behind the furthest-behind player to place the scoutmaster on F1 force respawn and on scheduled fire respawns. \"Behind\" uses the player’s flat look direction. If the player is more than 5m above their ground position (climbing, So Fly, etc.), placement uses their body center instead of ground height."); configSpawnDropHeight = ((BaseUnityPlugin)this).Config.Bind("ForceRespawn", "SpawnDropHeight", 12f, "Meters above the terrain surface to place the scoutmaster when respawning behind a player. He warps in the air and falls to the ground. Helps avoid spawning under the map on uneven terrain."); RefreshRespawnDelays(); } private void Update() { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient) { return; } if (isSpawning && !isFleeing) { HandleIsSpawning(); } if (TryGetScoutmaster(out var resolved)) { ScoutmasterTorchSupport.Tick(resolved); ScoutmasterAfflictionSupport.TickHostStatusSync(resolved.character); if (scoutmasterHasSpawned) { ScoutmasterLavaSupport.TickHostScoutmaster(resolved); } } if (isFleeing && !TryGetScoutmaster(out var _)) { LogWarning("Flee was active but scoutmaster not found — clearing flee so respawn timer can continue."); isFleeing = false; scoutmasterHasSpawned = false; } if (UnityInput.Current.GetKeyDown(configForceScoutmasterRespawn.Value)) { ForceRespawnScoutmasterFromHotkey(); } } private void WaitForValidCharacterAndSpawn() { if (isFleeing) { return; } try { if (!TryGetScoutmaster(out var _)) { LogWarning("Scoutmaster has not spawned yet — retrying soon."); respawnEndTime = 3f; return; } Character val = FindFurthestBehindPlayer(); if ((Object)(object)val == (Object)null) { LogWarning("No valid players found yet — retrying soon."); respawnEndTime = 3f; } else { LogInfo("Valid player found — proceeding with Scoutmaster spawn."); PlaceScoutmasterBehindPlayer(val, "Scheduled spawn"); isSpawning = false; } } catch (Exception ex) { LogWarning($"Scheduled spawn failed ({ex.Message}) — retrying in {3f}s."); respawnEndTime = 3f; } } private static bool IsScoutmasterOnMap(Scoutmaster activeScoutmaster) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)activeScoutmaster?.character == (Object)null) { return false; } return activeScoutmaster.character.Center.z < 4990f; } private void IncreaseLitFireCount() { if (!PhotonNetwork.IsMasterClient) { return; } isSpawning = false; respawnEndTime = -1f; Instance.litFireCount++; LogInfo($"Fire lit. Count: {Instance.litFireCount}"); if (litFireCount >= respawnDelays.Length) { LogInfo("Beyond final fire segment — despawning without new respawn timer."); DespawnScoutmaster(); return; } if (litFireCount == 0) { LogInfo("Starting initial spawn timer (fire 1)."); } else { LogInfo($"Despawning Scoutmaster and setting respawn timer from fire {litFireCount}."); DespawnScoutmaster(); } int num = Mathf.Min(litFireCount, respawnDelays.Length - 1); respawnEndTime = respawnDelays[num]; LogInfo($"Setting respawnEndTime: {respawnEndTime} (delay index {num}). Starting spawn delay"); isSpawning = true; } internal void ForcePassOutImmediateRetreat(Scoutmaster activeScoutmaster) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)activeScoutmaster == (Object)null)) { isFleeing = false; fleeTimer = 0f; passOutRetreatTriggersRespawn = false; fleeAwayFrom = null; ReleaseGrabIfNeeded(activeScoutmaster); activeScoutmaster.currentTarget = null; activeScoutmaster.view.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { -1, 0f }); PhotonView component = ((Component)activeScoutmaster).GetComponent(); component.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { (object)new Vector3(0f, 0f, 5000f), false }); component.RPC("StopClimbingRpc", (RpcTarget)0, new object[1] { 0f }); activeScoutmaster.discovered = null; ScoutmasterPassOutSupport.OnRetreatComplete(activeScoutmaster); scoutmasterHasSpawned = false; isSpawning = true; respawnEndTime = ScoutmasterPassOutSupport.RecoveryRespawnDelay; LogInfo($"Pass-out failsafe — scoutmaster off-map; respawn in {ScoutmasterPassOutSupport.RecoveryRespawnDelay:F0}s."); } } internal void StartPassOutRetreat(Scoutmaster activeScoutmaster) { isFleeing = true; fleeTimer = 0f; passOutRetreatTriggersRespawn = true; fleeAwayFrom = GetNearestPlayerPosition(activeScoutmaster?.character); activeScoutmaster.currentTarget = null; activeScoutmaster.view.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { -1, 0f }); activeScoutmaster.ResetInput(); resetInputRequest = true; } private Vector3? GetNearestPlayerPosition(Character scoutmasterCharacter) { //IL_0052: 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_00a2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)scoutmasterCharacter == (Object)null) { return null; } Character val = null; float num = float.MaxValue; foreach (Character allCharacter in Character.AllCharacters) { if (IsViablePlayer(allCharacter)) { float num2 = Vector3.Distance(scoutmasterCharacter.Center, allCharacter.Center); if (num2 < num) { num = num2; val = allCharacter; } } } return (val != null) ? new Vector3?(val.Center) : ((Vector3?)null); } internal void ReleaseGrabIfNeeded(Scoutmaster activeScoutmaster) { if (!((Object)(object)activeScoutmaster.character.data.grabbedPlayer == (Object)null)) { if (activeScoutmaster.isThrowing) { ((MonoBehaviour)activeScoutmaster).StopCoroutine("IThrow"); activeScoutmaster.isThrowing = false; } activeScoutmaster.character.view.RPC("RPCA_GrabUnattach", (RpcTarget)0, Array.Empty()); activeScoutmaster.character.data.isReaching = false; activeScoutmaster.character.input.useSecondaryIsPressed = false; } } private void WarpNearPlayer(Scoutmaster activeScoutmaster, Character character) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0049: 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_0095: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) Vector3 val; if (ScoutmasterKilnSupport.TryGetKilnSpawnPosition(character, out var spawnPosition)) { val = spawnPosition; } else { Vector3 val2 = character.data.lookDirection_Flat; if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { val2 = -((Component)character).transform.forward; } val2.y = 0f; ((Vector3)(ref val2)).Normalize(); float num = character.Center.y - character.data.groundPos.y; Vector3 val3 = ((num > 5f) ? character.Center : character.data.groundPos); Vector3 horizontalPoint = val3 + val2 * configForceRespawnBehindDistance.Value; val = GetSpawnPositionAboveGround(horizontalPoint, character.Center.y); } PhotonView component = ((Component)activeScoutmaster).GetComponent(); component.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, false }); component.RPC("StopClimbingRpc", (RpcTarget)0, new object[1] { 0f }); } private Vector3 GetSpawnPositionAboveGround(Vector3 horizontalPoint, float referenceHeight) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(referenceHeight, horizontalPoint.y) + 150f; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(horizontalPoint.x, num, horizontalPoint.z); RaycastHit val2 = HelperFunctions.LineCheck(val, val + Vector3.down * 500f, (LayerType)1, 0f, (QueryTriggerInteraction)1); if (Object.op_Implicit((Object)(object)((RaycastHit)(ref val2)).transform)) { return ((RaycastHit)(ref val2)).point + Vector3.up * configSpawnDropHeight.Value; } return horizontalPoint + Vector3.up * configSpawnDropHeight.Value; } public void Chase(Scoutmaster scoutmaster) { //IL_00d7: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) Character anchorPlayer = FindFurthestBehindPlayer() ?? scoutmaster.currentTarget; if (ScoutmasterKilnSupport.TryLostSightStandableTeleport(scoutmaster, anchorPlayer, configLostSightTeleportTime.Value, configTeleportCooldown.Value)) { return; } if (!ScoutmasterKilnSupport.BlocksCloseGapAndStuckTeleports() && configLostSightTeleportTime.Value > 0f && scoutmaster.sinceSeenTarget > configLostSightTeleportTime.Value && !scoutmaster.AnyoneCanSeeMe()) { scoutmaster.sinceSeenTarget = 0f; scoutmaster.tpCounter = Mathf.Max(configTeleportCooldown.Value, 5f); scoutmaster.Teleport(scoutmaster.currentTarget, configTeleportMinDistance.Value, configTeleportMaxDistance.Value, configTeleportMaxHeight.Value); return; } HandleClimbing(scoutmaster, scoutmaster.currentTarget.Center); if (!HandleGrabbedPlayer(scoutmaster)) { scoutmaster.LookAt(scoutmaster.currentTarget.Head); float num = Vector3.Distance(scoutmaster.character.Center, scoutmaster.currentTarget.Center); HandleWalkTowards(scoutmaster, scoutmaster.currentTarget.Head, 1f); scoutmaster.character.input.sprintIsPressed = num > configSprintDistance.Value; if (Vector3.Distance(scoutmaster.character.Center, scoutmaster.currentTarget.Center) < 3f && scoutmaster.character.data.sinceClimb > 1f && scoutmaster.character.data.isGrounded && !ScoutmasterPassOutSupport.IsScoutmasterDisabledForGrabOrPhysics(scoutmaster.character) && !ScoutmasterNapberrySupport.IsTargetRepellingScoutmaster(scoutmaster)) { scoutmaster.character.input.useSecondaryIsPressed = true; Instance.resetInputRequest = true; } } } internal void HandleWalkTowardsPublic(Scoutmaster scoutmaster, Vector3 targetPos, float mult) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) HandleWalkTowards(scoutmaster, targetPos, mult); } private void HandleWalkTowards(Scoutmaster scoutmaster, Vector3 targetPos, float mult) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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) float num = HelperFunctions.FlatDistance(scoutmaster.character.Center, targetPos); float num2 = ((num <= configMovementBoostDistance.Value) ? configMovementBoostMultiplier.Value : 1f); scoutmaster.character.refs.movement.movementModifier = num2 * configRunSpeed.Value; ScoutmasterNapberrySupport.TryModifyChaseWalk(scoutmaster, ref targetPos, ref mult); if (IsTargetHoldingLitFaerieLanternCondition(scoutmaster) && num < configFaerieLanternFleeDistance.Value) { mult = 0f - mult; } scoutmaster.character.input.movementInput = new Vector2(0f, mult); TryToStartWallClimb(scoutmaster.character); if (!scoutmaster.character.data.isClimbing) { RaycastHit val = HelperFunctions.LineCheck(scoutmaster.character.Center, scoutmaster.character.Center + Vector3.down * 3f, (LayerType)1, 0f, (QueryTriggerInteraction)1); if (!((Object)(object)((RaycastHit)(ref val)).transform == (Object)null)) { } } if ((Object)(object)scoutmaster.currentTarget != (Object)null) { HandleStuckAboveOrBelowTarget(scoutmaster); } } private void HandleStuckAboveOrBelowTarget(Scoutmaster scoutmaster) { //IL_0043: 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_006a: 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) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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) if (ScoutmasterKilnSupport.BlocksCloseGapAndStuckTeleports()) { lingerTimer = 0f; } else { if ((Object)(object)((scoutmaster != null) ? scoutmaster.currentTarget : null) == (Object)null) { return; } Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(scoutmaster.character.Center.x, scoutmaster.character.Center.z); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(scoutmaster.currentTarget.Center.x, scoutmaster.currentTarget.Center.z); float num = Vector2.Distance(val, val2); bool flag = num <= 2f; float num2 = Mathf.Abs(scoutmaster.character.Center.y - scoutmaster.currentTarget.Center.y); bool flag2 = num2 >= 10f; if (flag && flag2) { lingerTimer += Time.deltaTime; if (lingerTimer >= 3f) { TryTeleportNearTarget(scoutmaster); lingerTimer = 0f; } } else { lingerTimer = 0f; } } } private bool TryCloseGapTeleport(Scoutmaster scoutmaster) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (ScoutmasterKilnSupport.BlocksCloseGapAndStuckTeleports()) { return false; } if ((Object)(object)scoutmaster.currentTarget == (Object)null) { return false; } if (scoutmaster.tpCounter < configTeleportCooldown.Value) { return false; } float num = Vector3.Distance(scoutmaster.character.Center, scoutmaster.currentTarget.Center); if (num <= configTeleportDistance.Value) { return false; } LogInfo($"Target is {num:F0}m away (threshold {configTeleportDistance.Value:F0}m) — attempting close teleport."); scoutmaster.tpCounter = Mathf.Max(configTeleportCooldown.Value, 5f); scoutmaster.Teleport(scoutmaster.currentTarget, configTeleportMinDistance.Value, configTeleportMaxDistance.Value, configTeleportMaxHeight.Value); return true; } private bool TryTeleportNearTarget(Scoutmaster scoutmaster) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)scoutmaster.currentTarget == (Object)null) { return false; } int num = 50; while (num > 0) { num--; Vector3 onUnitSphere = Random.onUnitSphere; Vector3 val = scoutmaster.currentTarget.Center + Vector3.up * 500f + onUnitSphere * 95f; Vector3 val2 = Vector3.down; if (num < 25) { val = scoutmaster.currentTarget.Center + Vector3.up; val2 = Random.onUnitSphere; } RaycastHit val3 = HelperFunctions.LineCheck(val, val + val2 * 1000f, (LayerType)1, 0f, (QueryTriggerInteraction)1); if (Object.op_Implicit((Object)(object)((RaycastHit)(ref val3)).transform)) { float num2 = Vector3.Distance(((RaycastHit)(ref val3)).point, scoutmaster.currentTarget.Center); float num3 = Mathf.Abs(((RaycastHit)(ref val3)).point.y - scoutmaster.currentTarget.Center.y); if (!scoutmaster.AnyoneCanSeePos(((RaycastHit)(ref val3)).point + Vector3.up) && num2 >= 30f && num2 <= 50f && num3 <= 15f) { scoutmaster.character.view.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { ((RaycastHit)(ref val3)).point + Vector3.up, false }); scoutmaster.character.view.RPC("StopClimbingRpc", (RpcTarget)0, new object[1] { 0f }); scoutmaster.tpCounter = 0f; return true; } } } return false; } private void HandleClimbing(Scoutmaster scoutmaster, Vector3 target) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (!scoutmaster.character.data.isClimbing) { return; } scoutmaster.character.refs.climbing.climbSpeedMod = configClimbSpeed.Value; scoutmaster.ClimbTowards(target, 1f); if (!ScoutmasterKilnSupport.KeepsClimbingTowardTarget() && target.y < scoutmaster.character.Center.y) { RaycastHit val = HelperFunctions.LineCheck(scoutmaster.character.Center, target, (LayerType)1, 0f, (QueryTriggerInteraction)1); if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).transform)) { scoutmaster.character.refs.climbing.StopClimbing(); } } } private bool HandleGrabbedPlayer(Scoutmaster scoutmaster) { if (ScoutmasterPassOutSupport.IsScoutmasterDisabledForGrabOrPhysics(scoutmaster.character)) { ReleaseGrabIfNeeded(scoutmaster); return false; } if (ScoutmasterNapberrySupport.IsTargetRepellingScoutmaster(scoutmaster)) { ReleaseGrabIfNeeded(scoutmaster); scoutmaster.character.input.useSecondaryIsPressed = false; return false; } if ((Object)(object)scoutmaster.character.data.grabbedPlayer != (Object)null) { if (configInstaKillOnGrab.Value) { Character grabbedPlayer = scoutmaster.character.data.grabbedPlayer; if ((Object)(object)grabbedPlayer != (Object)null && !grabbedPlayer.data.dead) { grabbedPlayer.DieInstantly(); } ReleaseGrabIfNeeded(scoutmaster); Instance.resetInputRequest = true; return true; } scoutmaster.HoldPlayer(); Instance.resetInputRequest = true; return true; } return false; } private void HandleIsSpawning() { if (!Instance.isFleeing) { if (Instance.respawnEndTime > 0f) { Instance.respawnEndTime -= Time.deltaTime; } else { Instance.WaitForValidCharacterAndSpawn(); } } } private bool HandleFleeing(Scoutmaster __instance) { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //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_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: 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_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: 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_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) if (Instance.isFleeing) { fleeTimer += Time.deltaTime; if (fleeTimer >= configFleeDuration.Value) { __instance.TeleportFarAway(); fleeTimer = 0f; isFleeing = false; if (passOutRetreatTriggersRespawn) { passOutRetreatTriggersRespawn = false; fleeAwayFrom = null; ScoutmasterPassOutSupport.OnRetreatComplete(__instance); scoutmasterHasSpawned = false; isSpawning = true; respawnEndTime = ScoutmasterPassOutSupport.RecoveryRespawnDelay; LogInfo($"Pass-out retreat complete — scoutmaster will respawn in {ScoutmasterPassOutSupport.RecoveryRespawnDelay:F0}s."); } else { ScoutmasterPassOutSupport.FullyHealScoutmaster(__instance.character); scoutmasterHasSpawned = false; LogInfo("Flee complete — scoutmaster statuses cleared off-map."); } return true; } Vector3 val = default(Vector3); bool flag = false; Vector3 val2; if (fleeAwayFrom.HasValue) { val2 = __instance.character.Center - fleeAwayFrom.Value; Vector3 normalized = ((Vector3)(ref val2)).normalized; val = __instance.character.Center + normalized * 10f; flag = true; } else if ((Object)(object)__instance.currentTarget != (Object)null) { val2 = __instance.character.Center - __instance.currentTarget.Center; Vector3 normalized2 = ((Vector3)(ref val2)).normalized; val = __instance.character.Center + normalized2 * 10f; flag = true; } if (!flag) { Vector3 val3 = __instance.character.data.lookDirection_Flat; if (((Vector3)(ref val3)).sqrMagnitude < 0.01f) { val3 = -((Component)__instance).transform.forward; val3.y = 0f; } val = __instance.character.Center + ((Vector3)(ref val3)).normalized * 10f; } if (__instance.character.data.isClimbing) { Instance.HandleClimbing(__instance, val); return true; } HandleWalkTowards(__instance, val, 1f); __instance.character.input.sprintIsPressed = true; return true; } return false; } private void HandleTargeting(Scoutmaster scoutmaster) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) targetingTimer += Time.deltaTime; if (targetingTimer < 3f) { return; } List allCharacters = Character.AllCharacters; Character val = null; float num = float.MaxValue; foreach (Character item in allCharacters) { if (!item.isBot && !item.data.dead && !item.data.fullyPassedOut && !item.data.passedOut) { float num2 = Vector3.Distance(item.Center, scoutmaster.character.Center); if (num2 < num) { val = item; num = num2; } } } if ((Object)(object)val != (Object)null && (Object)(object)scoutmaster.currentTarget != (Object)(object)val && !scoutmaster.isThrowing) { scoutmaster.view.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { val.view.ViewID, 0f }); } targetingTimer = 0f; } public bool CanClimb(Character character) { if (character.data.sinceClimb < 0.2f) { return false; } if (character.data.isRopeClimbing) { return false; } if (character.data.isVineClimbing) { return false; } return true; } private void TryToStartWallClimb(Character character) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_008c: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) if (!CanClimb(character)) { return; } Vector3 center = character.Center; Vector3 normalized = ((Vector3)(ref character.data.lookDirection_Flat)).normalized; Vector3 val = center + normalized * 1.25f; RaycastHit val2 = HelperFunctions.LineCheck(center, val, (LayerType)1, 0f, (QueryTriggerInteraction)1); if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref val2)).transform)) { val2 = HelperFunctions.LineCheck(center, val, (LayerType)1, 0.05f, (QueryTriggerInteraction)1); } if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref val2)).transform)) { val2 = HelperFunctions.LineCheck(center, val, (LayerType)1, 0.1f, (QueryTriggerInteraction)1); } if (Object.op_Implicit((Object)(object)((RaycastHit)(ref val2)).transform)) { bool flag = !character.refs.climbing.AcceptableGrabAngle(((RaycastHit)(ref val2)).normal, ((RaycastHit)(ref val2)).collider); bool flag2 = !(character.refs.climbing.sinceLastClimbStarted > 1f) && character.OutOfStamina(); if (!(flag || flag2)) { character.data.sinceCanClimb = 0f; character.refs.climbing.sinceLastClimbStarted = 0f; character.view.RPC("StartClimbRpc", (RpcTarget)0, new object[2] { ((RaycastHit)(ref val2)).point, ((RaycastHit)(ref val2)).normal }); } } } public bool IsTargetHoldingLitFaerieLanternCondition(Scoutmaster scoutmaster) { if ((Object)(object)scoutmaster.currentTarget == (Object)null) { return false; } return IsTargetHoldingLitFaerieLantern(scoutmaster.currentTarget); } private void ApplyScoutmasterBonk(Character character, Scoutmaster scoutmaster, Vector3 forceDirection, float forceMagnitude, float forceRange, Vector3 hitPoint) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0066: Unknown result type (might be due to invalid IL or missing references) character.Fall(configBonkStunDuration.Value, 0f); if (scoutmaster.isThrowing) { ((MonoBehaviour)scoutmaster).StopCoroutine("IThrow"); scoutmaster.isThrowing = false; } ReleaseGrabIfNeeded(scoutmaster); if (((Vector3)(ref forceDirection)).sqrMagnitude > 0.0001f) { character.AddForceAtPosition(-((Vector3)(ref forceDirection)).normalized * forceMagnitude, hitPoint, forceRange); } } public IEnumerator WaitAndCallback(float waitSeconds, Action callback) { yield return (object)new WaitForSeconds(waitSeconds); callback?.Invoke(); } private void DespawnScoutmaster() { if (!TryGetScoutmaster(out var resolved)) { scoutmasterHasSpawned = false; isFleeing = false; LogWarning("Despawn requested but scoutmaster not found — respawn timer will still run."); return; } ReleaseGrabIfNeeded(resolved); resolved.currentTarget = null; resolved.view.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { -1, 0f }); fleeAwayFrom = GetNearestPlayerPosition(resolved.character); resetInputRequest = true; if (IsScoutmasterOnMap(resolved)) { isFleeing = true; fleeTimer = 0f; scoutmasterHasSpawned = true; LogInfo("Scoutmaster on map — fleeing before off-map despawn."); } else { isFleeing = false; scoutmasterHasSpawned = false; LogInfo("Scoutmaster already off-map — skipping flee, waiting on respawn timer."); } } internal void LogInfo(string msg) { ConfigEntry obj = configEnableLogs; if (obj != null && obj.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[Scoutmasters Rampage] " + msg)); } } internal void LogWarning(string msg) { ConfigEntry obj = configEnableLogs; if (obj != null && obj.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[Scoutmasters Rampage] " + msg)); } } } internal static class ScoutmasterBlowDartSupport { [HarmonyPatch(typeof(Action_RaycastDart), "FireDart")] private static class BlowDartFireDartPatch { private static bool Prefix(Action_RaycastDart __instance) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) if (!Enabled) { return true; } if (Object.op_Implicit((Object)(object)__instance.shotSFX)) { __instance.shotSFX.Play(((Component)__instance).transform.position); } Physics.Raycast(__instance.spawnTransform.position, ((Component)MainCamera.instance).transform.forward, ref __instance.lineHit, __instance.maxDistance, LayerMask.op_Implicit(HelperFunctions.terrainMapMask), (QueryTriggerInteraction)1); if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref __instance.lineHit)).collider)) { ((RaycastHit)(ref __instance.lineHit)).distance = __instance.maxDistance; ((RaycastHit)(ref __instance.lineHit)).point = __instance.spawnTransform.position + ((Component)MainCamera.instance).transform.forward * __instance.maxDistance; } int num = LayerMask.op_Implicit(HelperFunctions.GetMask((LayerType)6)); __instance.sphereHits = Physics.SphereCastAll(__instance.spawnTransform.position, __instance.dartCollisionSize, ((Component)MainCamera.instance).transform.forward, ((RaycastHit)(ref __instance.lineHit)).distance, num, (QueryTriggerInteraction)1); RaycastHit[] sphereHits = __instance.sphereHits; for (int i = 0; i < sphereHits.Length; i++) { RaycastHit val = sphereHits[i]; if (Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider)) { Character componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && (Object)(object)componentInParent != (Object)(object)((ItemActionBase)__instance).character) { __instance.DartImpact(componentInParent, __instance.spawnTransform.position, ((RaycastHit)(ref val)).point); return false; } } } __instance.DartImpact((Character)null, __instance.spawnTransform.position, ((RaycastHit)(ref __instance.lineHit)).point); return false; } } [HarmonyPatch(typeof(Item), "FinishCastPrimary")] private static class FinishCastPrimaryPostfix { private static void Postfix(Item __instance) { if (Enabled && !((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponentInChildren() == (Object)null)) { CompleteDartItemUse(__instance); } } private static void CompleteDartItemUse(Item item) { Character holderCharacter = item.holderCharacter; if ((Object)(object)holderCharacter == (Object)null || !holderCharacter.IsLocal) { return; } OptionableIntItemData data = item.GetData((DataEntryKey)2); if (data.HasData && data.Value > 0) { Action_ReduceUses componentInChildren = ((Component)item).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { ((ItemActionBase)componentInChildren).RunAction(); data = item.GetData((DataEntryKey)2); } } if (!item.consuming && (!data.HasData || data.Value <= 0)) { Action_Consume componentInChildren2 = ((Component)item).GetComponentInChildren(true); if ((Object)(object)componentInChildren2 != (Object)null) { ((ItemActionBase)componentInChildren2).RunAction(); } else { ((MonoBehaviour)item).StartCoroutine(item.ConsumeDelayed(false)); } } } } private static ConfigEntry configEnabled; internal static bool Enabled => configEnabled?.Value ?? true; internal static void Initialize(ConfigFile config) { configEnabled = config.Bind("Interactions", "BlowDartHitsScoutmaster", true, "When true, blow darts sphere-cast Character+Default layers (same colliders bonks use) so they can hit the scoutmaster."); } } internal static class ScoutmasterRescueHookSupport { [HarmonyPatch(typeof(RescueHook), "GetHit")] private static class GetHitPatch { private static bool Prefix(RescueHook __instance, out Vector3 endFire, ref RaycastHit __result) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) endFire = default(Vector3); if (!Enabled) { return true; } Ray middleScreenRay = GetMiddleScreenRay(); __instance.curRange = __instance.range; if (Vector3.Dot(((Ray)(ref middleScreenRay)).direction, Vector3.up) < 0f) { __instance.curRange = __instance.rangeDownward; } endFire = ((Ray)(ref middleScreenRay)).origin + ((Ray)(ref middleScreenRay)).direction * __instance.curRange; __result = FindBestHit(__instance, middleScreenRay, __instance.curRange); return false; } } [HarmonyPatch(typeof(RescueHook), "Fire")] private static class FirePatch { private static bool Prefix(RescueHook __instance) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_00ea: Unknown result type (might be due to invalid IL or missing references) if (!Enabled) { return true; } __instance.sinceFire = 0f; for (int i = 0; i < __instance.rescueShot.Length; i++) { __instance.rescueShot[i].Play(((Component)__instance).transform.position); } Vector3 val = default(Vector3); RaycastHit hit = __instance.GetHit(ref val); if (Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).transform) && TryResolveCharacterFromCollider(((RaycastHit)(ref hit)).collider, ((ItemComponent)__instance).item.holderCharacter, out var character)) { ((MonoBehaviourPun)__instance).photonView.RPC("RPCA_RescueCharacter", (RpcTarget)0, new object[1] { ((MonoBehaviourPun)character).photonView }); } else if (Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).transform)) { ((MonoBehaviourPun)__instance).photonView.RPC("RPCA_RescueWall", (RpcTarget)0, new object[2] { false, ((RaycastHit)(ref hit)).point }); } else { ((MonoBehaviourPun)__instance).photonView.RPC("RPCA_RescueWall", (RpcTarget)0, new object[2] { true, val }); } return false; } } [HarmonyPatch(typeof(RescueHook), "RPCA_RescueCharacter")] private static class RescueCharacterPatch { private static void Postfix(RescueHook __instance, PhotonView characterView) { if (!Enabled || (Object)(object)characterView == (Object)null) { return; } Character component = ((Component)characterView).GetComponent(); if ((Object)(object)component == (Object)null || !component.data.isScoutmaster) { return; } PulledScoutmaster = component; if (!PhotonNetwork.IsMasterClient) { return; } Scoutmaster component2 = ((Component)component).GetComponent(); if (!((Object)(object)component2 == (Object)null)) { ScoutmasterRampagePlugin.Instance?.ReleaseGrabIfNeeded(component2); if (component2.isThrowing) { ((MonoBehaviour)component2).StopCoroutine("IThrow"); component2.isThrowing = false; } } } } [HarmonyPatch(typeof(RescueHook), "RPCA_LetGo")] private static class LetGoPatch { private static Character lettingGoTarget; private static void Prefix(RescueHook __instance) { lettingGoTarget = __instance.targetPlayer; } private static void Postfix() { if ((Object)(object)lettingGoTarget != (Object)null && lettingGoTarget.data.isScoutmaster) { PulledScoutmaster = null; } lettingGoTarget = null; } } private static ConfigEntry configEnabled; internal static Character PulledScoutmaster { get; private set; } internal static bool Enabled => configEnabled?.Value ?? true; internal static bool IsPullingScoutmaster(Character character) { return (Object)(object)PulledScoutmaster != (Object)null && (Object)(object)PulledScoutmaster == (Object)(object)character; } internal static void Initialize(ConfigFile config) { configEnabled = config.Bind("Interactions", "RescueHookWorksOnScoutmaster", true, "When true, rescue hooks can target and pull the scoutmaster using the same Default-layer bodypart colliders bonks use. Releases grabs while pulling. Host chase AI pauses during the pull."); } private static Ray GetMiddleScreenRay() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) return Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f)); } private static bool TryResolveCharacterFromCollider(Collider collider, Character holder, out Character character) { character = null; if ((Object)(object)collider == (Object)null) { return false; } if (CharacterRagdoll.TryGetCharacterFromCollider(collider, ref character) && (Object)(object)character != (Object)null && (Object)(object)character != (Object)(object)holder) { return true; } character = ((Component)collider).GetComponentInParent(); return (Object)(object)character != (Object)null && (Object)(object)character != (Object)(object)holder; } private static bool ShouldSkipHit(RescueHook hook, RaycastHit hit) { if ((Object)(object)((RaycastHit)(ref hit)).rigidbody == (Object)null) { return false; } Item component = ((Component)((RaycastHit)(ref hit)).rigidbody).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.holderCharacter == (Object)(object)((ItemComponent)hook).item.holderCharacter) { return true; } if (TryResolveCharacterFromCollider(((RaycastHit)(ref hit)).collider, ((ItemComponent)hook).item.holderCharacter, out var character)) { return (Object)(object)character == (Object)(object)((ItemComponent)hook).item.holderCharacter; } return false; } private static RaycastHit FindBestHit(RescueHook hook, Ray ray, float maxRange) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0121: 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_013d: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00f2: Unknown result type (might be due to invalid IL or missing references) int num = LayerMask.op_Implicit(HelperFunctions.GetMask((LayerType)0)); List list = Physics.RaycastAll(ray, maxRange, num, (QueryTriggerInteraction)1).ToList(); RaycastHit result = default(RaycastHit); Character val = null; foreach (RaycastHit item in list) { RaycastHit current = item; if (ShouldSkipHit(hook, current)) { continue; } TryResolveCharacterFromCollider(((RaycastHit)(ref current)).collider, ((ItemComponent)hook).item.holderCharacter, out var character); if ((Object)(object)character != (Object)null && character.data.isScoutmaster) { if ((Object)(object)val == (Object)null || ((RaycastHit)(ref current)).distance < ((RaycastHit)(ref result)).distance) { result = current; val = character; } } else if (!((Object)(object)val != (Object)null) && (((RaycastHit)(ref result)).distance == 0f || ((RaycastHit)(ref current)).distance < ((RaycastHit)(ref result)).distance)) { result = current; } } if ((Object)(object)val != (Object)null) { return result; } if ((Object)(object)((RaycastHit)(ref result)).collider != (Object)null && Vector3.Distance(((Ray)(ref ray)).origin, ((RaycastHit)(ref result)).point) < hook.minRaycastDistance) { return default(RaycastHit); } return result; } } internal static class ScoutmasterOverheadStatus { [HarmonyPatch(typeof(GUIManager), "LateUpdate")] private static class GUIManagerLateUpdatePatch { private static void Postfix(GUIManager __instance) { if (!Enabled || (Object)(object)__instance == (Object)null) { display?.Hide(); return; } if (!TryGetScoutmasterCharacter(out var character)) { display?.Hide(); return; } if (!IsVisibleToLocalPlayer(character)) { display?.Hide(); return; } if (display == null) { display = new ScoutmasterOverheadBarDisplay(); } display.Refresh(__instance, character); } } private sealed class ScoutmasterOverheadBarDisplay { private sealed class StatusSegment { internal GameObject GameObject; internal RectTransform RootRect; internal RectTransform FillRect; internal Image Icon; internal STATUSTYPE StatusType; internal float TargetWidth; internal float LastAppliedWidth = -1f; internal bool IsActive; } private readonly List segments = new List(); private readonly List sampledStatuses = new List(16); private readonly List lastStatuses = new List(16); private GameObject rootObject; private RectTransform rootRect; private RectTransform barContainer; private RectTransform staminaEmpty; private RectTransform staminaFill; private RectTransform extraStaminaFill; private StaminaBar sourceBar; private float lastScale = -1f; private float lastMaxStamina = -1f; private float lastCurrentStamina = -1f; private float lastExtraStamina = -1f; private bool layoutInitialized; private bool isShown; internal void DestroyDisplay() { ClearSegments(); if ((Object)(object)rootObject != (Object)null) { Object.Destroy((Object)(object)rootObject); rootObject = null; rootRect = null; } layoutInitialized = false; isShown = false; } internal void Hide() { if ((Object)(object)rootObject != (Object)null && isShown) { rootObject.SetActive(false); isShown = false; } } internal void Refresh(GUIManager gui, Character targetCharacter) { if ((Object)(object)gui.hudCanvas == (Object)null || (Object)(object)gui.bar == (Object)null) { Hide(); return; } EnsureRoot(((Component)gui.hudCanvas).transform); CharacterAfflictions val = targetCharacter.refs?.afflictions; if ((Object)(object)val == (Object)null || !EnsureSegments(gui.bar)) { Hide(); return; } PositionOverHead(targetCharacter); if (NeedsLayoutUpdate(targetCharacter, val)) { UpdateLayout(targetCharacter, val); } if (!isShown) { rootObject.SetActive(true); isShown = true; } } private void EnsureRoot(Transform canvasTransform) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rootObject != (Object)null)) { rootObject = new GameObject("ScoutmasterOverheadStatus", new Type[1] { typeof(RectTransform) }); rootRect = rootObject.GetComponent(); ((Transform)rootRect).SetParent(canvasTransform, false); rootRect.anchorMin = Vector2.zero; rootRect.anchorMax = Vector2.zero; rootRect.pivot = new Vector2(0.5f, 0.5f); rootRect.sizeDelta = Vector2.zero; rootObject.SetActive(false); isShown = false; } } private void PositionOverHead(Character targetCharacter) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0061: Unknown result type (might be due to invalid IL or missing references) Camera camera = GetCamera(); if (!((Object)(object)camera == (Object)null) && !((Object)(object)rootRect == (Object)null)) { Vector3 head = targetCharacter.Head; head.y += 0.25f; Vector3 position = camera.WorldToScreenPoint(head); position.y += 28f * BarScale; ((Transform)rootRect).position = position; } } private bool EnsureSegments(StaminaBar bar) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_00c2: 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_00f8: 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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) if (bar.afflictions == null || bar.afflictions.Length == 0) { return false; } if ((Object)(object)barContainer != (Object)null && (Object)(object)sourceBar == (Object)(object)bar && segments.Count > 0 && (Object)(object)staminaFill != (Object)null) { return true; } ClearSegments(); sourceBar = bar; GameObject val = new GameObject("ScoutmasterOverheadStaminaBar", new Type[1] { typeof(RectTransform) }); val.transform.SetParent((Transform)(object)rootRect, false); barContainer = val.GetComponent(); barContainer.anchorMin = new Vector2(0.5f, 0.5f); barContainer.anchorMax = new Vector2(0.5f, 0.5f); barContainer.pivot = new Vector2(0.5f, 0.5f); barContainer.anchoredPosition = Vector2.zero; staminaEmpty = CreateColorBar("ScoutmasterOverheadStaminaEmpty", StaminaEmptyColor, bar); staminaFill = CreateColorBar("ScoutmasterOverheadStaminaFill", StaminaFillColor, bar); extraStaminaFill = CreateColorBar("ScoutmasterOverheadExtraStaminaFill", StaminaFillColor, bar); BarAffliction[] afflictions = bar.afflictions; foreach (BarAffliction val2 in afflictions) { if (!((Object)(object)val2 == (Object)null) && ScoutmasterAfflictionSupport.IsVanillaStatusType(val2.afflictionType)) { GameObject val3 = Object.Instantiate(((Component)val2).gameObject, (Transform)(object)barContainer); ((Object)val3).name = "ScoutmasterOverhead" + ((object)Unsafe.As(ref val2.afflictionType)/*cast due to .constrained prefix*/).ToString(); RemoveStaminaInfoText(val3); BarAffliction component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } RectTransform component2 = val3.GetComponent(); ConfigureLeftCenterChild(component2); ((Transform)component2).localScale = Vector3.one; RectTransform val4 = (((Object)(object)component != (Object)null && (Object)(object)component.rtf != (Object)null) ? component.rtf : component2); if ((Object)(object)val4 != (Object)(object)component2) { val4.anchorMin = Vector2.zero; val4.anchorMax = Vector2.one; val4.pivot = new Vector2(0.5f, 0.5f); val4.anchoredPosition = Vector2.zero; val4.sizeDelta = Vector2.zero; val4.offsetMin = Vector2.zero; val4.offsetMax = Vector2.zero; ((Transform)val4).localScale = Vector3.one; } SetRaycastTargets(val3, value: false); segments.Add(new StatusSegment { GameObject = val3, RootRect = component2, FillRect = val4, Icon = (((Object)(object)component != (Object)null) ? component.icon : null), StatusType = (((Object)(object)component != (Object)null) ? component.afflictionType : val2.afflictionType) }); val3.SetActive(false); } } if ((Object)(object)staminaEmpty != (Object)null) { ((Transform)staminaEmpty).SetAsFirstSibling(); } if ((Object)(object)staminaFill != (Object)null) { ((Transform)staminaFill).SetSiblingIndex(1); } layoutInitialized = false; lastStatuses.Clear(); return segments.Count > 0; } private RectTransform CreateColorBar(string objectName, Color color, StaminaBar source) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(objectName, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); val.transform.SetParent((Transform)(object)barContainer, false); RectTransform component = val.GetComponent(); ConfigureLeftCenterChild(component); Image component2 = val.GetComponent(); Image val2 = FindFillImage(((Object)(object)source != (Object)null) ? source.staminaBar : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sprite != (Object)null) { component2.sprite = val2.sprite; component2.type = (Type)1; component2.pixelsPerUnitMultiplier = val2.pixelsPerUnitMultiplier; } ((Graphic)component2).color = color; ((Graphic)component2).raycastTarget = false; val.SetActive(false); return component; } private bool NeedsLayoutUpdate(Character targetCharacter, CharacterAfflictions afflictions) { float barScale = BarScale; float a = Mathf.Clamp01(1f - SumSampledStatuses(afflictions)); float currentStamina = targetCharacter.data.currentStamina; float extraStamina = targetCharacter.data.extraStamina; SampleStatuses(afflictions); if (layoutInitialized && Approximately(barScale, lastScale) && Approximately(a, lastMaxStamina) && Approximately(currentStamina, lastCurrentStamina) && Approximately(extraStamina, lastExtraStamina) && StatusesMatch()) { return false; } lastScale = barScale; lastMaxStamina = a; lastCurrentStamina = currentStamina; lastExtraStamina = extraStamina; CopySampledStatusesToLast(); layoutInitialized = true; return true; } private float SumSampledStatuses(CharacterAfflictions afflictions) { SampleStatuses(afflictions); float num = 0f; for (int i = 0; i < sampledStatuses.Count; i++) { if (sampledStatuses[i] > 0f) { num += sampledStatuses[i]; } } return num; } private void SampleStatuses(CharacterAfflictions afflictions) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) sampledStatuses.Clear(); for (int i = 0; i < segments.Count; i++) { sampledStatuses.Add(afflictions.GetCurrentStatus(segments[i].StatusType)); } } private bool StatusesMatch() { if (lastStatuses.Count != sampledStatuses.Count) { return false; } for (int i = 0; i < sampledStatuses.Count; i++) { if (!Approximately(sampledStatuses[i], lastStatuses[i])) { return false; } } return true; } private void CopySampledStatusesToLast() { lastStatuses.Clear(); for (int i = 0; i < sampledStatuses.Count; i++) { lastStatuses.Add(sampledStatuses[i]); } } private static bool Approximately(float a, float b) { return Mathf.Abs(a - b) <= 0.0025f; } private void UpdateLayout(Character targetCharacter, CharacterAfflictions afflictions) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0.01f, BarScale); float num2 = 118f * num; float num3 = 12f * num; float num4 = 3f * num; float num5 = 2f * num; float num6 = Mathf.Clamp(12f * num, 0f, num2); float num7 = 0f; for (int i = 0; i < sampledStatuses.Count; i++) { if (sampledStatuses[i] > 0f) { num7 += sampledStatuses[i]; } } float num8 = Mathf.Clamp01(1f - num7) * num2; float num9 = Mathf.Max(0f, num2 - num8); float num10 = 0f; bool flag = false; for (int j = 0; j < segments.Count; j++) { StatusSegment statusSegment = segments[j]; float num11 = ((j < sampledStatuses.Count) ? sampledStatuses[j] : afflictions.GetCurrentStatus(statusSegment.StatusType)); if (num11 > 0.01f) { float num12 = num2 * num11; statusSegment.TargetWidth = Mathf.Min(Mathf.Max(num6, num12), Mathf.Max(0f, num9 - num10)); num10 += statusSegment.TargetWidth; flag = statusSegment.TargetWidth > 0.5f || flag; } else { statusSegment.TargetWidth = 0f; } } if (num10 > num9) { num8 = Mathf.Max(0f, num2 - num10); } barContainer.sizeDelta = new Vector2(num2, num3); float num13 = (0f - num2) * 0.5f; float num14 = Mathf.Clamp(targetCharacter.data.currentStamina * num2, 0f, num8); SetLeftBar(staminaEmpty, num13, num8, num3, 0f); SetActiveIfChanged(((Component)staminaEmpty).gameObject, num8 > 0.5f); SetLeftBar(staminaFill, num13, num14, num3, 0f); SetActiveIfChanged(((Component)staminaFill).gameObject, num14 > 0.5f); float num15 = num13 + num8; for (int k = 0; k < segments.Count; k++) { StatusSegment statusSegment2 = segments[k]; if (statusSegment2.TargetWidth <= 0f) { if (statusSegment2.IsActive) { statusSegment2.GameObject.SetActive(false); statusSegment2.IsActive = false; statusSegment2.LastAppliedWidth = -1f; } continue; } float targetWidth = statusSegment2.TargetWidth; if (!statusSegment2.IsActive) { statusSegment2.GameObject.SetActive(true); statusSegment2.IsActive = true; } if (!Approximately(statusSegment2.LastAppliedWidth, targetWidth)) { statusSegment2.RootRect.sizeDelta = new Vector2(targetWidth, num3); statusSegment2.LastAppliedWidth = targetWidth; } statusSegment2.RootRect.anchoredPosition = new Vector2(num15, 0f); num15 += targetWidth; } if ((Object)(object)extraStaminaFill != (Object)null) { float num16 = Mathf.Clamp01(targetCharacter.data.extraStamina) * num2; SetLeftBar(extraStaminaFill, num13, num16, num4, (0f - num3) * 0.5f - num5 - num4 * 0.5f); SetActiveIfChanged(((Component)extraStaminaFill).gameObject, num16 > 0.5f); } bool active = flag || ((Object)(object)staminaFill != (Object)null && ((Component)staminaFill).gameObject.activeSelf) || ((Object)(object)staminaEmpty != (Object)null && ((Component)staminaEmpty).gameObject.activeSelf) || ((Object)(object)extraStaminaFill != (Object)null && ((Component)extraStaminaFill).gameObject.activeSelf); SetActiveIfChanged(((Component)barContainer).gameObject, active); } private static void SetLeftBar(RectTransform rect, float x, float width, float height, float y) { //IL_0010: 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_0037: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rect == (Object)null)) { ((Transform)rect).localScale = Vector3.one; rect.sizeDelta = new Vector2(Mathf.Max(0f, width), height); rect.anchoredPosition = new Vector2(x, y); } } private static void SetActiveIfChanged(GameObject gameObject, bool active) { if ((Object)(object)gameObject != (Object)null && gameObject.activeSelf != active) { gameObject.SetActive(active); } } private void ClearSegments() { segments.Clear(); sampledStatuses.Clear(); lastStatuses.Clear(); staminaFill = null; staminaEmpty = null; extraStaminaFill = null; sourceBar = null; barContainer = null; layoutInitialized = false; lastScale = -1f; lastMaxStamina = -1f; lastCurrentStamina = -1f; lastExtraStamina = -1f; if ((Object)(object)rootRect != (Object)null) { for (int num = ((Transform)rootRect).childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)((Transform)rootRect).GetChild(num)).gameObject); } } } private static void ConfigureLeftCenterChild(RectTransform rect) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = new Vector2(0.5f, 0.5f); rect.anchorMax = new Vector2(0.5f, 0.5f); rect.pivot = new Vector2(0f, 0.5f); rect.anchoredPosition = Vector2.zero; rect.sizeDelta = Vector2.zero; ((Transform)rect).localScale = Vector3.one; } private static void SetRaycastTargets(GameObject gameObject, bool value) { Graphic[] componentsInChildren = gameObject.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].raycastTarget = value; } } private static void RemoveStaminaInfoText(GameObject root) { Transform[] componentsInChildren = root.GetComponentsInChildren(true); for (int num = componentsInChildren.Length - 1; num >= 0; num--) { if (((Object)componentsInChildren[num]).name == "StaminaInfo") { Object.Destroy((Object)(object)((Component)componentsInChildren[num]).gameObject); } } } private static Image FindFillImage(RectTransform root) { if ((Object)(object)root == (Object)null) { return null; } Image[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (((Object)componentsInChildren[i]).name == "Fill") { return componentsInChildren[i]; } } return (componentsInChildren.Length != 0) ? componentsInChildren[0] : null; } } private const float BaseBarWidth = 118f; private const float BaseBarHeight = 12f; private const float BaseExtraStaminaHeight = 3f; private const float BaseExtraStaminaGap = 2f; private const float BaseMinSegmentWidth = 12f; private const float HeadWorldOffsetY = 0.25f; private const float StatusEpsilon = 0.0025f; private const float VisibilityCheckInterval = 0.1f; private static readonly Color StaminaFillColor = new Color(0.35f, 0.78f, 0f, 1f); private static readonly Color StaminaEmptyColor = new Color(0.35f, 0.78f, 0f, 0.35f); private static ConfigEntry configEnabled; private static ConfigEntry configMaxDistance; private static ConfigEntry configBarScale; private static ScoutmasterOverheadBarDisplay display; private static float nextVisibilityCheckTime; private static bool lastVisibilityResult; private static Character lastVisibilityTarget; private static float lastVisibilityMaxDistance; private static Camera cachedCamera; internal static bool Enabled => configEnabled?.Value ?? false; internal static float MaxDistance => configMaxDistance?.Value ?? 80f; internal static float BarScale => configBarScale?.Value ?? 1.5f; internal static void Initialize(ConfigFile config) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown configEnabled = config.Bind("OverheadStatus", "ShowScoutmasterOverheadBar", true, "Shows a stamina/affliction bar above the scoutmaster (similar to Overhead Stamina on players). Self-contained in this mod — no other mods required. Delete ScoutmasterOverheadStatus.cs to remove."); configMaxDistance = config.Bind("OverheadStatus", "MaxDistance", 80f, "Maximum distance (meters) at which the scoutmaster overhead bar is visible."); configBarScale = config.Bind("OverheadStatus", "BarScale", 1.5f, new ConfigDescription("Scale of the overhead bar.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 3f), Array.Empty())); } internal static void Reset() { if (display != null) { display.DestroyDisplay(); display = null; } nextVisibilityCheckTime = 0f; lastVisibilityResult = false; lastVisibilityTarget = null; lastVisibilityMaxDistance = 0f; cachedCamera = null; } private static bool TryGetScoutmasterCharacter(out Character character) { character = null; Scoutmaster val = default(Scoutmaster); if (!Scoutmaster.GetPrimaryScoutmaster(ref val) || (Object)(object)val == (Object)null) { return false; } character = val.character; return (Object)(object)character != (Object)null && character.data.isScoutmaster; } private static Camera GetCamera() { if ((Object)(object)cachedCamera != (Object)null) { return cachedCamera; } if ((Object)(object)MainCamera.instance != (Object)null && (Object)(object)MainCamera.instance.cam != (Object)null) { cachedCamera = MainCamera.instance.cam; return cachedCamera; } cachedCamera = Camera.main; return cachedCamera; } private static bool IsVisibleToLocalPlayer(Character target) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0125: 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_0141: Unknown result type (might be due to invalid IL or missing references) Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null || (Object)(object)target == (Object)null) { return false; } float maxDistance = MaxDistance; float unscaledTime = Time.unscaledTime; if ((Object)(object)lastVisibilityTarget == (Object)(object)target && Mathf.Abs(lastVisibilityMaxDistance - maxDistance) < 0.01f && unscaledTime < nextVisibilityCheckTime) { return lastVisibilityResult; } nextVisibilityCheckTime = unscaledTime + 0.1f; lastVisibilityTarget = target; lastVisibilityMaxDistance = maxDistance; Character val = (((Object)(object)Character.observedCharacter != (Object)null) ? Character.observedCharacter : localCharacter); float num = maxDistance * maxDistance; Vector3 val2 = val.Center - target.Center; if (((Vector3)(ref val2)).sqrMagnitude > num) { lastVisibilityResult = false; return false; } Camera camera = GetCamera(); if ((Object)(object)camera == (Object)null) { lastVisibilityResult = true; return true; } Vector3 val3 = camera.WorldToViewportPoint(target.Head); lastVisibilityResult = val3.z > 0f && val3.x >= -0.1f && val3.x <= 1.1f && val3.y >= -0.1f && val3.y <= 1.1f; return lastVisibilityResult; } } internal static class ScoutmasterAfflictionSupport { [HarmonyPatch(typeof(CharacterAfflictions), "AddStatus")] private static class AddStatusBlockHungerPatch { private static bool Prefix(CharacterAfflictions __instance, STATUSTYPE statusType, float amount) { //IL_003c: 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_005b: Invalid comparison between Unknown and I4 if (!Enabled || !IsScoutmasterCharacter(__instance?.character)) { return true; } if (configBlockCustomStatuses.Value && amount > 0f && !IsVanillaStatusType(statusType)) { return false; } if (amount > 0f && (int)statusType == 1) { return false; } return true; } } [HarmonyPatch(typeof(Character), "UseStamina")] private static class UseStaminaScoutmasterPatch { private static bool Prefix(Character __instance, ref bool __result) { if (!IsScoutmasterCharacter(__instance) || MovementReducesStamina) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Scoutmaster), "ClimbTowards")] private static class ClimbTowardsStaminaPatch { private static bool Prefix(Scoutmaster __instance, Vector3 targetPos, float mult) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (!MovementReducesStamina) { return true; } __instance.LookAt(targetPos); float num = Mathf.Clamp(((Component)__instance.character.GetBodypart((BodypartType)2)).transform.InverseTransformPoint(targetPos).x * 0.25f, -1f, 1f); __instance.character.input.movementInput = new Vector2(num, mult); return false; } } [HarmonyPatch(typeof(CharacterAfflictions), "GetCurrentStatus", new Type[] { typeof(STATUSTYPE) })] [HarmonyPriority(0)] private static class GetCurrentStatusScoutmasterPatch { private static void Postfix(CharacterAfflictions __instance, STATUSTYPE statusType, ref float __result) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (Enabled && configBlockCustomStatuses.Value && IsScoutmasterCharacter(__instance?.character) && !IsVanillaStatusType(statusType)) { __result = 0f; } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPriority(0)] private static class StatusSumScoutmasterPatch { private static void Postfix(CharacterAfflictions __instance, ref float __result) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0051: Invalid comparison between Unknown and I4 //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Invalid comparison between Unknown and I4 if (!Enabled || !configBlockCustomStatuses.Value || !IsScoutmasterCharacter(__instance?.character)) { return; } float num = 0f; foreach (STATUSTYPE vanillaStatusType in VanillaStatusTypes) { if ((int)vanillaStatusType != 1 && (int)vanillaStatusType != 7 && (int)vanillaStatusType != 4 && (int)vanillaStatusType != 9) { num += __instance.GetCurrentStatus(vanillaStatusType); } } __result = num; } } [HarmonyPatch(typeof(CharacterAfflictions), "AddStatus")] private static class AddStatusTranspilerPatch { private static IEnumerable Transpiler(IEnumerable instructions) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(Character), "isScoutmaster"); MethodInfo methodInfo = AccessTools.Method(typeof(ScoutmasterAfflictionSupport), "ShouldBlockScoutmasterStatus", (Type[])null, (Type[])null); List list = new List(instructions); bool flag = false; for (int i = 0; i < list.Count - 1; i++) { if (list[i].opcode == OpCodes.Ldfld && list[i].operand is FieldInfo fieldInfo2 && fieldInfo2 == fieldInfo && (list[i + 1].opcode == OpCodes.Brfalse || list[i + 1].opcode == OpCodes.Brfalse_S)) { list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo)); flag = true; i++; } } if (!flag) { Debug.LogWarning((object)"[Scoutmasters Rampage] ScoutmasterAfflictionSupport: AddStatus transpiler did not find isScoutmaster check."); } return list; } } [HarmonyPatch(typeof(CharacterAfflictions), "Update")] private static class SupernaturalRecoveryPatch { private static void Postfix(CharacterAfflictions __instance) { ApplySupernaturalRecovery(__instance); } } [HarmonyPatch(typeof(CharacterAfflictions), "AddAffliction")] private static class AddAfflictionPrefixPatch { private static bool Prefix(CharacterAfflictions __instance, Affliction affliction, bool fromRPC) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (!Enabled || affliction == null || (Object)(object)__instance?.character == (Object)null || !IsScoutmasterCharacter(__instance.character)) { return true; } if (affliction.worksOnBot) { return true; } Character character = __instance.character; if (character.data.isCarried) { return false; } if (!((MonoBehaviourPun)__instance).photonView.IsMine && !fromRPC) { return false; } Affliction val = affliction.Copy(); Affliction val2 = default(Affliction); if (__instance.HasAfflictionType(val.GetAfflictionType(), ref val2)) { val2.Stack(val); } else { __instance.afflictionList.Add(val); val.character = character; val.OnApplied(); } if (!fromRPC && ((MonoBehaviourPun)__instance).photonView.IsMine) { __instance.PushStatuses((Player)null); } return false; } } private static ConfigEntry configEnabled; private static ConfigEntry configMovementReducesStamina; private static ConfigEntry configBlockCustomStatuses; private static ConfigEntry configSupernaturalRecoveryPerSecond; private static readonly HashSet VanillaStatusTypes = BuildVanillaStatusTypes(); private static float nextStatusSyncTime; private const float StatusSyncInterval = 0.5f; internal static bool Enabled => configEnabled?.Value ?? true; internal static bool MovementReducesStamina => configMovementReducesStamina?.Value ?? false; internal static float SupernaturalRecoveryPerSecond => configSupernaturalRecoveryPerSecond?.Value ?? 0.02f; internal static void Initialize(ConfigFile config) { configEnabled = config.Bind("ScoutmasterPlayerLike", "EnableScoutmasterAfflictions", true, "Master toggle — allows the scoutmaster to receive status effects and afflictions."); configMovementReducesStamina = config.Bind("ScoutmasterPlayerLike", "ScoutmasterMovementReducesStamina", false, "When false (default), sprinting and climbing never drain the scoutmaster’s stamina—vanilla infinite movement. When true, movement drains stamina normally and climbing no longer free-refills his bar."); configBlockCustomStatuses = config.Bind("ScoutmasterPlayerLike", "BlockCustomModStatuses", true, "When true, only vanilla PEAK status types apply to the scoutmaster. Blocks third-party afflictions (e.g. Full Belly Bloated leaking onto the host-owned scoutmaster)."); configSupernaturalRecoveryPerSecond = config.Bind("ScoutmasterPlayerLike", "SupernaturalRecoveryPerSecond", 0.02f, "Per real-time second, each active status bar (drowsy, cold, hot, injury, etc.) is reduced by this amount. All non-zero bars tick down together. Uses deltaTime so framerate does not change the rate. Default 0.02 so Napberry drowsy (0.1/s default) can still build toward a pass-out."); } internal static bool IsScoutmasterCharacter(Character character) { return (Object)(object)character != (Object)null && (character.isScoutmaster || character.data.isScoutmaster); } internal static bool IsVanillaStatusType(STATUSTYPE statusType) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return VanillaStatusTypes.Contains(statusType); } private static HashSet BuildVanillaStatusTypes() { //IL_0092: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet(); string[] array = new string[13] { "Hunger", "Drowsy", "Cold", "Hot", "Injury", "Poison", "Curse", "Weight", "Crab", "Thorns", "Spores", "Sunburn", "Wet" }; for (int i = 0; i < array.Length; i++) { if (Enum.TryParse(array[i], out STATUSTYPE result)) { hashSet.Add(result); } } return hashSet; } internal static bool ShouldBlockScoutmasterStatus(bool isScoutmaster) { if (!isScoutmaster) { return false; } return !Enabled; } internal static void ResetStatusSync() { nextStatusSyncTime = 0f; } internal static void TickHostStatusSync(Character character) { if (Enabled && PhotonNetwork.IsMasterClient && !((Object)(object)character == (Object)null) && IsScoutmasterCharacter(character)) { CharacterAfflictions val = character.refs?.afflictions; if (!((Object)(object)val == (Object)null) && ((MonoBehaviourPun)val).photonView.IsMine && !(Time.time < nextStatusSyncTime)) { nextStatusSyncTime = Time.time + 0.5f; val.PushStatuses((Player)null); } } } internal static void ApplySupernaturalRecovery(CharacterAfflictions afflictions) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_0090: Invalid comparison between Unknown and I4 //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Invalid comparison between Unknown and I4 //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Invalid comparison between Unknown and I4 //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) if (!Enabled || (Object)(object)afflictions?.character == (Object)null || !((MonoBehaviourPun)afflictions).photonView.IsMine || !IsScoutmasterCharacter(afflictions.character)) { return; } float num = SupernaturalRecoveryPerSecond * Time.deltaTime; if (num <= 0f) { return; } bool flag = false; foreach (STATUSTYPE vanillaStatusType in VanillaStatusTypes) { if ((int)vanillaStatusType != 7 && (int)vanillaStatusType != 4 && (int)vanillaStatusType != 9) { float currentStatus = afflictions.GetCurrentStatus(vanillaStatusType); if (!(currentStatus <= 0f)) { flag = true; afflictions.SubtractStatus(vanillaStatusType, Mathf.Min(currentStatus, num), false, true); } } } if (flag && afflictions.character.data.passedOut) { afflictions.PushStatuses((Player)null); } } } internal static class ScoutmasterFallDamageSupport { [HarmonyPatch(typeof(CharacterMovement), "CheckFallDamage")] private static class CheckFallDamagePatch { private static bool Prefix(CharacterMovement __instance) { if (IsScoutmaster(__instance.character)) { return false; } return true; } } internal static void Initialize() { } private static bool IsScoutmaster(Character character) { return (Object)(object)character != (Object)null && character.data.isScoutmaster; } } internal static class ScoutmasterPassOutSupport { internal enum PassOutPhase { None, Down } private static ConfigEntry configEnabled; private static ConfigEntry configRecoveryRespawnDelay; private static ConfigEntry configFailsafeSeconds; private static float passOutDownSince = -1f; internal static PassOutPhase Phase { get; private set; } internal static bool Enabled => configEnabled?.Value ?? true; internal static float RecoveryRespawnDelay => configRecoveryRespawnDelay?.Value ?? 90f; internal static void Initialize(ConfigFile config) { configEnabled = config.Bind("Interactions", "AfflictionPassOutRetreat", true, "When true, passing out from afflictions makes the scoutmaster stay down until he naturally recovers, then flee off-map, clear all statuses, and respawn after PassOutRecoveryDelay seconds. Host only."); configRecoveryRespawnDelay = config.Bind("Interactions", "PassOutRecoveryDelay", 90f, "Seconds the scoutmaster stays off the map after a pass-out retreat before respawning behind the furthest-behind player."); configFailsafeSeconds = config.Bind("Interactions", "PassOutFailsafeSeconds", 20f, "If the scoutmaster stays passed out this long (e.g. stuck in lava), skip recovery and flee off-map immediately."); } internal static void Reset() { Phase = PassOutPhase.None; passOutDownSince = -1f; } internal static bool HandlePassOut(Scoutmaster scoutmaster) { if (!Enabled || !PhotonNetwork.IsMasterClient || (Object)(object)scoutmaster?.character == (Object)null) { return false; } Character character = scoutmaster.character; if (!ScoutmasterAfflictionSupport.IsScoutmasterCharacter(character)) { return false; } ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; if ((Object)(object)instance == (Object)null) { return false; } if (character.data.passedOut || character.data.fullyPassedOut) { if (Phase == PassOutPhase.None) { Phase = PassOutPhase.Down; passOutDownSince = Time.time; instance.ReleaseGrabIfNeeded(scoutmaster); if (scoutmaster.isThrowing) { ((MonoBehaviour)scoutmaster).StopCoroutine("IThrow"); scoutmaster.isThrowing = false; } scoutmaster.currentTarget = null; scoutmaster.view.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { -1, 0f }); ScoutmasterLootSupport.TryDropLoot(scoutmaster); Debug.Log((object)"[Scoutmasters Rampage] Scoutmaster passed out — waiting to recover before retreat."); } else if (passOutDownSince >= 0f && Time.time - passOutDownSince >= configFailsafeSeconds.Value) { passOutDownSince = -1f; Phase = PassOutPhase.None; instance.ForcePassOutImmediateRetreat(scoutmaster); Debug.Log((object)"[Scoutmasters Rampage] Pass-out failsafe — scoutmaster forced off-map."); } return true; } passOutDownSince = -1f; if (Phase == PassOutPhase.Down && !instance.IsFleeing) { Phase = PassOutPhase.None; instance.StartPassOutRetreat(scoutmaster); Debug.Log((object)"[Scoutmasters Rampage] Scoutmaster recovered from pass-out — retreating."); return true; } return false; } internal static void OnRetreatComplete(Scoutmaster scoutmaster) { if (!((Object)(object)scoutmaster?.character == (Object)null)) { FullyHealScoutmaster(scoutmaster.character); Phase = PassOutPhase.None; Debug.Log((object)"[Scoutmasters Rampage] Pass-out retreat complete — scoutmaster fully healed off-map."); } } internal static void FullyHealScoutmaster(Character character) { if (!((Object)(object)character == (Object)null) && PhotonNetwork.IsMasterClient) { CharacterAfflictions val = character.refs?.afflictions; if ((Object)(object)val != (Object)null) { val.ClearAllAfflictions(); ScoutmasterAfflictionSafety.SafeClearStatuses(val, excludeCurse: false); val.RemoveAllThorns(); val.PushStatuses((Player)null); val.PushAfflictions((Player)null); } character.data.passedOut = false; character.data.fullyPassedOut = false; character.data.passOutValue = 0f; character.data.fallSeconds = 0f; character.data.deathTimer = 0f; character.view.RPC("RPCA_UnPassOut", (RpcTarget)0, Array.Empty()); } } internal static bool IsScoutmasterDisabledForGrabOrPhysics(Character character) { return ScoutmasterAfflictionSupport.IsScoutmasterCharacter(character) && (character.data.fallSeconds > 0f || character.data.passedOut || character.data.fullyPassedOut); } } internal static class ScoutmasterAfflictionSafety { [HarmonyPatch(typeof(CharacterAfflictions), "ReleaseFromWebs")] private static class ReleaseFromWebsPatch { private static bool Prefix(CharacterAfflictions __instance) { if (!ScoutmasterAfflictionSupport.IsScoutmasterCharacter(__instance?.character)) { return true; } if (__instance.webWraps == null || __instance.webWraps.Count == 0) { return false; } return true; } } [HarmonyPatch(typeof(CharacterAfflictions), "PlayParticle")] private static class PlayParticlePatch { private static bool Prefix(CharacterAfflictions __instance) { if (!ScoutmasterAfflictionSupport.IsScoutmasterCharacter(__instance?.character)) { return true; } if ((Object)(object)__instance.character?.refs?.customization == (Object)null) { return false; } return true; } } [HarmonyPatch(typeof(CharacterAfflictions), "StartWhirlwind")] private static class StartWhirlwindPatch { private static bool Prefix(CharacterAfflictions __instance) { return !ShouldSkipWhirlwind(__instance); } } [HarmonyPatch(typeof(CharacterAfflictions), "StartWhirlwindRPC")] private static class StartWhirlwindRpcPatch { private static bool Prefix(CharacterAfflictions __instance) { return !ShouldSkipWhirlwind(__instance); } } [HarmonyPatch(typeof(CharacterAfflictions), "StopWhirlwind")] private static class StopWhirlwindPatch { private static bool Prefix(CharacterAfflictions __instance) { return !ShouldSkipWhirlwind(__instance); } } [HarmonyPatch(typeof(CharacterAfflictions), "StopWhirlwindRPC")] private static class StopWhirlwindRpcPatch { private static bool Prefix(CharacterAfflictions __instance) { return !ShouldSkipWhirlwind(__instance); } } [HarmonyPatch(typeof(CharacterAfflictions), "WarnStopWhirlwind")] private static class WarnStopWhirlwindPatch { private static bool Prefix(CharacterAfflictions __instance) { return !ShouldSkipWhirlwind(__instance); } } [HarmonyPatch(typeof(CharacterAfflictions), "WarnStopWhirlwindRPC")] private static class WarnStopWhirlwindRpcPatch { private static bool Prefix(CharacterAfflictions __instance) { return !ShouldSkipWhirlwind(__instance); } } [HarmonyPatch(typeof(CharacterAfflictions), "AddStatus")] private static class AddStatusPlayEffectsPatch { private static void Prefix(CharacterAfflictions __instance, ref bool playEffects) { if (ScoutmasterAfflictionSupport.IsScoutmasterCharacter(__instance?.character)) { playEffects = false; } } } [HarmonyPatch(typeof(Character), "RPCA_PassOut")] private static class RpcaPassOutPatch { private static bool Prefix(Character __instance) { if (!ScoutmasterAfflictionSupport.IsScoutmasterCharacter(__instance)) { return true; } if (!PhotonNetwork.IsMasterClient) { return false; } __instance.UnPassOutCalled = false; __instance.data.passedOut = true; __instance.data.lastPassedOut = Time.time; if ((Object)(object)__instance.refs?.stats != (Object)null) { __instance.refs.stats.justPassedOut = true; __instance.refs.stats.Record(false, 0f); } if ((Object)(object)__instance.refs?.items != (Object)null && PhotonNetwork.IsMasterClient) { __instance.refs.items.droppedItems.Clear(); } Debug.Log((object)"[Scoutmasters Rampage] Scoutmaster RPCA_PassOut (safe bot path)."); return false; } } internal static void SafeClearStatuses(CharacterAfflictions afflictions, bool excludeCurse) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)afflictions == (Object)null) { return; } foreach (STATUSTYPE value in Enum.GetValues(typeof(STATUSTYPE))) { if ((int)value != 7 && (int)value != 4 && (int)value != 9 && (!excludeCurse || (int)value != 5)) { float currentStatus = afflictions.GetCurrentStatus(value); if (!(currentStatus <= 0f)) { afflictions.SubtractStatus(value, currentStatus, false, false); } } } afflictions.PushStatuses((Player)null); } private static bool ShouldSkipWhirlwind(CharacterAfflictions afflictions) { return ScoutmasterAfflictionSupport.IsScoutmasterCharacter(afflictions?.character); } } internal static class ScoutmasterNapberrySupport { [HarmonyPatch(typeof(OrbThatMakesYouSleepy), "Tick")] private static class OrbTickScoutmasterPatch { private static void Postfix(OrbThatMakesYouSleepy __instance) { //IL_0090: 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) Scoutmaster val = default(Scoutmaster); if (configOrbEnabled.Value && PhotonNetwork.IsMasterClient && RunSettings.GetValue((SETTINGTYPE)2500, false) != 0 && !((Object)(object)__instance.fakeBerry == (Object)null) && ((Component)__instance.fakeBerry).gameObject.activeInHierarchy && Scoutmaster.GetPrimaryScoutmaster(ref val) && ScoutmasterAfflictionSupport.IsScoutmasterCharacter(val.character)) { float num = Vector3.Distance(val.character.Center, __instance.orb.position); if (!(num > __instance.maxDistance)) { ApplyOrbRangeDrowsy(val, __instance); } } } } internal const int NapberryItemId = 110; private static ConfigEntry configOrbEnabled; private static ConfigEntry configItemEnabled; private static ConfigEntry configItemFleeDistance; private static ConfigEntry configDrowsyPerSecond; private static ConfigEntry configCharge; private static ConfigEntry configChargeDrainPerSecond; private static readonly Dictionary itemRepelCharge = new Dictionary(); private static readonly List cachedOrbs = new List(); private static float nextOrbCacheTime; private const float OrbCacheInterval = 2f; internal static bool Enabled { get { ConfigEntry obj = configOrbEnabled; return obj == null || obj.Value || (configItemEnabled?.Value ?? true); } } internal static float ItemFleeDistance => configItemFleeDistance?.Value ?? 20f; internal static void Initialize(ConfigFile config) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown configOrbEnabled = config.Bind("Interactions", "NapberryOrbRepel", true, "When true, active napberry hypno orbs repel the scoutmaster and apply drowsy while he is within the orb maxDistance. Host only."); configItemEnabled = config.Bind("Interactions", "NapberryItemRepel", true, "When true, the scoutmaster backs away from his chase target while they hold a NapBerry (item ID 110), and gains drowsy while still in range. Same pattern as the faerie lantern."); configItemFleeDistance = config.Bind("Interactions", "NapberryItemFleeDistance", 20f, "Flat distance within which the scoutmaster walks backward from a target holding NapBerry."); configDrowsyPerSecond = config.Bind("Interactions", "NapberryDrowsyPerSecond", 0.1f, new ConfigDescription("Drowsy status added per second while the scoutmaster is within NapberryItemFleeDistance of a NapBerry holder. Net gain is this value minus SupernaturalRecoveryPerSecond. Capped at 1.0 (full bar).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); configCharge = config.Bind("Interactions", "NapberryCharge", 1f, new ConfigDescription("Hidden charge per NapBerry item instance. Drains while the scoutmaster is repelled by that berry. At 0 the item is consumed. Capped at 1.0.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); configChargeDrainPerSecond = config.Bind("Interactions", "NapberryChargeDrainPerSecond", 0.1f, "Charge drained per second while the scoutmaster backs away from a NapBerry holder. With defaults (charge 1.0, drain 0.1/s) the berry lasts about 10 seconds of repel."); } internal static bool IsTargetRepellingScoutmaster(Scoutmaster scoutmaster) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)((scoutmaster != null) ? scoutmaster.currentTarget : null) == (Object)null || (Object)(object)scoutmaster.character == (Object)null) { return false; } float num = HelperFunctions.FlatDistance(scoutmaster.character.Center, scoutmaster.currentTarget.Center); ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; if ((Object)(object)instance != (Object)null && instance.IsTargetHoldingLitFaerieLantern(scoutmaster.currentTarget) && num < instance.FaerieLanternFleeDistance) { return true; } if (configItemEnabled.Value && IsHoldingActiveNapberry(scoutmaster.currentTarget) && num < ItemFleeDistance) { return true; } return false; } internal static bool TryOrbRepelMovement(Scoutmaster scoutmaster) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) if (!configOrbEnabled.Value || !PhotonNetwork.IsMasterClient || (Object)(object)scoutmaster?.character == (Object)null) { return false; } Character character = scoutmaster.character; if (character.data.passedOut || character.data.fullyPassedOut) { return false; } if (!TryGetOrbRepelPoint(scoutmaster, out var fleePoint)) { return false; } ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; if ((Object)(object)instance == (Object)null) { return false; } scoutmaster.LookAt(fleePoint); instance.HandleWalkTowardsPublic(scoutmaster, fleePoint, 1f); scoutmaster.character.input.sprintIsPressed = true; return true; } internal static bool IsInsideActiveOrbZone(Scoutmaster scoutmaster) { OrbThatMakesYouSleepy matchedOrb; return TryFindActiveOrb(scoutmaster, out matchedOrb); } internal static bool TryModifyChaseWalk(Scoutmaster scoutmaster, ref Vector3 walkTarget, ref float mult) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if (!Enabled || !PhotonNetwork.IsMasterClient || (Object)(object)scoutmaster?.character == (Object)null) { return false; } if (TryGetOrbRepelPoint(scoutmaster, out var fleePoint)) { walkTarget = fleePoint; mult = 1f; return true; } if (!configItemEnabled.Value || (Object)(object)scoutmaster.currentTarget == (Object)null) { return false; } if (!IsHoldingActiveNapberry(scoutmaster.currentTarget)) { return false; } float num = HelperFunctions.FlatDistance(scoutmaster.character.Center, scoutmaster.currentTarget.Center); if (num >= configItemFleeDistance.Value) { return false; } ApplyItemRangeDrowsy(scoutmaster); DrainRepelCharge(scoutmaster.currentTarget.data.currentItem); mult = 0f - Mathf.Abs(mult); return true; } internal static bool TryOrbRepelWithoutTarget(Scoutmaster scoutmaster) { return TryOrbRepelMovement(scoutmaster); } private static bool TryGetOrbRepelPoint(Scoutmaster scoutmaster, out Vector3 fleePoint) { //IL_0002: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_0079: Unknown result type (might be due to invalid IL or missing references) fleePoint = default(Vector3); if (!configOrbEnabled.Value) { return false; } if (!TryFindActiveOrb(scoutmaster, out var matchedOrb)) { return false; } Vector3 val = scoutmaster.character.Center - matchedOrb.orb.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = Random.onUnitSphere; val.y = 0f; } ((Vector3)(ref val)).Normalize(); fleePoint = scoutmaster.character.Center + val * 15f; return true; } private static void RefreshOrbCacheIfNeeded() { if (!(Time.time < nextOrbCacheTime)) { nextOrbCacheTime = Time.time + 2f; cachedOrbs.Clear(); cachedOrbs.AddRange(Object.FindObjectsOfType()); } } private static bool TryFindActiveOrb(Scoutmaster scoutmaster, out OrbThatMakesYouSleepy matchedOrb) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) matchedOrb = null; float num = float.MaxValue; RefreshOrbCacheIfNeeded(); for (int i = 0; i < cachedOrbs.Count; i++) { OrbThatMakesYouSleepy val = cachedOrbs[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.orb == (Object)null) && !((Object)(object)val.fakeBerry == (Object)null) && ((Component)val.fakeBerry).gameObject.activeInHierarchy && RunSettings.GetValue((SETTINGTYPE)2500, false) != 0) { float num2 = Vector3.Distance(scoutmaster.character.Center, val.orb.position); if (!(num2 > val.maxDistance) && !(num2 >= num)) { num = num2; matchedOrb = val; } } } return (Object)(object)matchedOrb != (Object)null; } private static void ApplyOrbRangeDrowsy(Scoutmaster scoutmaster, OrbThatMakesYouSleepy orb) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)scoutmaster?.character?.refs?.afflictions == (Object)null) && ((MonoBehaviourPun)scoutmaster.character).photonView.IsMine) { float num = Vector3.Distance(scoutmaster.character.Center, orb.orb.position); float num2 = Mathf.InverseLerp(orb.maxDistance, 2f, num); float num3 = Mathf.Lerp(orb.minDrowsyPerTick, orb.maxDrowsyPerTick, num2); if (!(num3 <= 0f)) { scoutmaster.character.refs.afflictions.AddStatus((STATUSTYPE)6, num3, false, true, true); } } } private static void ApplyItemRangeDrowsy(Scoutmaster scoutmaster) { if (!((Object)(object)scoutmaster?.character?.refs?.afflictions == (Object)null) && ((MonoBehaviourPun)scoutmaster.character).photonView.IsMine) { float num = configDrowsyPerSecond.Value * Time.deltaTime; if (!(num <= 0f)) { scoutmaster.character.refs.afflictions.AddStatus((STATUSTYPE)6, num, false, true, true); } } } private static float GetRepelCharge(Item item) { if ((Object)(object)item == (Object)null) { return 0f; } int instanceID = ((Object)item).GetInstanceID(); if (!itemRepelCharge.TryGetValue(instanceID, out var value)) { value = configCharge.Value; itemRepelCharge[instanceID] = value; } return value; } private static void DrainRepelCharge(Item item) { if (!((Object)(object)item == (Object)null) && PhotonNetwork.IsMasterClient) { int instanceID = ((Object)item).GetInstanceID(); float num = GetRepelCharge(item) - configChargeDrainPerSecond.Value * Time.deltaTime; if (num <= 0f) { itemRepelCharge.Remove(instanceID); TryConsumeNapberryItem(item, "charge depleted"); } else { itemRepelCharge[instanceID] = num; } } } private static void TryConsumeNapberryItem(Item item, string reason) { if (!((Object)(object)item == (Object)null) && item.itemID == 110 && PhotonNetwork.IsMasterClient) { itemRepelCharge.Remove(((Object)item).GetInstanceID()); ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; if (!((Object)(object)instance == (Object)null)) { ((MonoBehaviour)instance).StartCoroutine(ConsumeNapberryItemCoroutine(item)); Debug.Log((object)("[Scoutmasters Rampage] NapBerry consumed (" + reason + ").")); } } } private static IEnumerator ConsumeNapberryItemCoroutine(Item item) { if ((Object)(object)item == (Object)null) { yield break; } Character holder = item.holderCharacter; Optionable slot = Optionable.None; if ((Object)(object)holder?.refs?.items != (Object)null) { slot = holder.refs.items.currentSelectedSlot; if ((Object)(object)holder.data.currentItem == (Object)(object)item) { holder.refs.items.UnAttachEquippedItem(); } } if ((Object)(object)((holder != null) ? holder.player : null) != (Object)null) { if (slot.IsSome) { holder.player.EmptySlot(slot); } else { TryEmptyNapberrySlot(holder.player); } } if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null && (Object)(object)((MonoBehaviourPun)item).photonView != (Object)null) { PhotonNetwork.Destroy(((Component)item).gameObject); } } private static void TryEmptyNapberrySlot(Player player) { //IL_00d1: 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) if (player?.itemSlots == null) { return; } for (byte b = 0; b < player.itemSlots.Length; b++) { ItemSlot val = player.itemSlots[b]; if (val != null && !val.IsEmpty() && !((Object)(object)val.prefab == (Object)null) && val.prefab.itemID == 110) { player.EmptySlot(Optionable.Some(b)); return; } } if (player.tempFullSlot != null && !player.tempFullSlot.IsEmpty() && (Object)(object)player.tempFullSlot.prefab != (Object)null && player.tempFullSlot.prefab.itemID == 110) { player.EmptySlot(Optionable.Some((byte)250)); } } private static bool IsHoldingActiveNapberry(Character character) { return IsHoldingNapberry(character) && GetRepelCharge(character.data.currentItem) > 0f; } private static bool IsHoldingNapberry(Character character) { object obj; if (character == null) { obj = null; } else { CharacterData data = character.data; obj = ((data != null) ? data.currentItem : null); } return (Object)obj != (Object)null && character.data.currentItem.itemID == 110; } } internal static class ScoutmasterWindChillSupport { [HarmonyPatch(typeof(WindChillZone), "Update")] private static class WindChillUpdatePatch { private static void Postfix(WindChillZone __instance) { //IL_0078: 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_00f1: Unknown result type (might be due to invalid IL or missing references) Scoutmaster val = default(Scoutmaster); if (Enabled && PhotonNetwork.IsMasterClient && __instance.windActive && !(__instance.statusApplicationPerSecond <= 0f) && Scoutmaster.GetPrimaryScoutmaster(ref val) && ScoutmasterAfflictionSupport.IsScoutmasterCharacter(val.character) && ((MonoBehaviourPun)val.character).photonView.IsMine && ((Bounds)(ref __instance.windZoneBounds)).Contains(val.character.Center)) { float windIntensityAtPoint = WindChillZone.GetWindIntensityAtPoint(val.character.Center, __instance.lightVolumeSampleThreshold_lower, __instance.lightVolumeSampleThreshold_margin); float num = windIntensityAtPoint * __instance.statusApplicationPerSecond * Time.deltaTime * Mathf.Clamp01(__instance.hasBeenActiveFor * 0.2f); if (!(num <= 0f)) { val.character.refs.afflictions.AddStatus(__instance.statusType, num, false, true, true); } } } } private static ConfigEntry configEnabled; internal static bool Enabled => configEnabled?.Value ?? true; internal static void Initialize(ConfigFile config) { configEnabled = config.Bind("ScoutmasterPlayerLike", "WindChillAffectsScoutmaster", true, "When true, alpine wind chill zones apply cold (and other configured status) to the scoutmaster using the same rules as players, while wind is active and he is inside the zone bounds. Host only."); } } internal static class ScoutmasterLavaSupport { private static ConfigEntry configEnabled; private static readonly List cachedLava = new List(); private static float nextLavaCacheTime; private static readonly Dictionary heatCounters = new Dictionary(); private const float LavaCacheInterval = 3f; internal static bool Enabled => configEnabled?.Value ?? true; internal static void Initialize(ConfigFile config) { configEnabled = config.Bind("ScoutmasterPlayerLike", "LavaAffectsScoutmaster", true, "When true, Lava heat zones apply Hot (and injury knock-up hits) to the scoutmaster. One host tick per frame (not per lava volume)."); } internal static void TickHostScoutmaster(Scoutmaster scoutmaster) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (!Enabled || !PhotonNetwork.IsMasterClient || (Object)(object)scoutmaster?.character == (Object)null || !((MonoBehaviourPun)scoutmaster.character).photonView.IsMine || !ScoutmasterAfflictionSupport.IsScoutmasterCharacter(scoutmaster.character)) { return; } RefreshLavaCacheIfNeeded(); Character character = scoutmaster.character; bool flag = character.data.passedOut || character.data.fullyPassedOut; for (int i = 0; i < cachedLava.Count; i++) { Lava val = cachedLava[i]; if (!((Object)(object)val == (Object)null) && !val.OutsideBounds(character.Center)) { ApplyHeat(val, character); if (!flag) { ApplyPhysicalEffects(val, character); } } } } private static void RefreshLavaCacheIfNeeded() { if (!(Time.time < nextLavaCacheTime)) { nextLavaCacheTime = Time.time + 3f; cachedLava.Clear(); heatCounters.Clear(); cachedLava.AddRange(Object.FindObjectsOfType()); } } private static void ApplyHeat(Lava lava, Character character) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) float num = character.Center.y - ((Component)lava).transform.position.y; float num2 = 1f - Mathf.Clamp01(num / lava.height); if (!(num2 < 0.01f) && !(lava.heatRate <= 0f)) { if (!heatCounters.TryGetValue(lava, out var value)) { value = 0f; } value += Time.deltaTime; if (value < lava.heatRate) { heatCounters[lava] = value; return; } heatCounters[lava] = 0f; character.refs.afflictions.AddStatus((STATUSTYPE)8, num2 * lava.heat * 1.5f, false, true, true); } } private static void ApplyPhysicalEffects(Lava lava, Character character) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (!(character.Center.y - 0.5f > ((Component)lava).transform.position.y)) { character.AddForce(Vector3.up * 80f, 0.5f, 1f); character.data.sinceGrounded = 0f; character.refs.movement.ApplyExtraDrag(0.8f, true); if (!lava.hitPlayers.Contains(character) && !character.data.dead && !(character.refs.afflictions.statusSum > 1.9f)) { lava.HitPlayer(character); ((MonoBehaviour)lava).StartCoroutine(lava.IHoldPlayer(character)); } } } } internal static class ScoutmasterSegmentSupport { [HarmonyPatch(typeof(MapHandler), "JumpToSegmentLogic")] private static class JumpToSegmentLogicPatch { private static void Postfix(Segment segment) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) OnSegmentChanged(segment); } } internal static void EnsureScoutmasterSpawnable(Scoutmaster scoutmaster) { if ((Object)(object)scoutmaster == (Object)null) { return; } Transform val = ((Component)scoutmaster).transform; while ((Object)(object)val.parent != (Object)null) { if (!((Component)val.parent).gameObject.activeSelf) { val.SetParent((Transform)null, true); break; } val = val.parent; } if (!((Component)scoutmaster).gameObject.activeSelf) { ((Component)scoutmaster).gameObject.SetActive(true); } } internal static void OnSegmentChanged(Segment segment) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient) { return; } Scoutmaster resolved = default(Scoutmaster); if (!Scoutmaster.GetPrimaryScoutmaster(ref resolved)) { ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; if ((Object)(object)instance == (Object)null || !instance.TryGetScoutmaster(out resolved)) { return; } } EnsureScoutmasterSpawnable(resolved); Debug.Log((object)$"[Scoutmasters Rampage] Segment changed to {segment} — ensured scoutmaster is active for spawn/warp."); } } internal static class ScoutmasterKilnSupport { private struct Candidate { internal Vector3 Point; internal float Score; } private const int SearchRaysPerRing = 12; private static readonly float[] SearchRingRadii = new float[8] { 0f, 2f, 5f, 8f, 12f, 18f, 25f, 35f }; private static ConfigEntry configClimbOnlyMode; private static ConfigEntry configMaxStandSlopeAngle; private static ConfigEntry configMaxVerticalDeltaFromPlayer; private static ConfigEntry configSpawnClearanceHeight; private static ConfigEntry configPreferBehindDistance; internal static bool ClimbOnlyModeEnabled => configClimbOnlyMode?.Value ?? true; internal static void Initialize(ConfigFile config) { configClimbOnlyMode = config.Bind("Kiln", "KilnClimbOnlyMode", true, "When true in The Kiln: close-gap and stuck vertical teleports are disabled; spawns and lost-sight recovery use the nearest standable ground near the furthest-behind player instead of random wall hits."); configMaxStandSlopeAngle = config.Bind("Kiln", "KilnMaxStandSlopeAngle", 50f, "Max angle (degrees) between a surface normal and world up to count as standable floor/ledge."); configMaxVerticalDeltaFromPlayer = config.Bind("Kiln", "KilnMaxVerticalDeltaFromPlayer", 12f, "Standable search only keeps points within this many meters of the anchor player's floor height."); configSpawnClearanceHeight = config.Bind("Kiln", "KilnSpawnClearanceHeight", 1.5f, "Meters above standable ground for kiln spawns and lost-sight recovery warps."); configPreferBehindDistance = config.Bind("Kiln", "KilnPreferBehindDistance", 10f, "When multiple standable spots exist, prefer one about this many meters behind the anchor player."); } internal static bool IsInKilnSegment() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 return MapHandler.Exists && (int)Singleton.Instance.GetCurrentSegment() == 4; } internal static bool BlocksCloseGapAndStuckTeleports() { return ClimbOnlyModeEnabled && IsInKilnSegment(); } internal static bool KeepsClimbingTowardTarget() { return ClimbOnlyModeEnabled && IsInKilnSegment(); } internal static bool TryGetKilnSpawnPosition(Character anchorPlayer, out Vector3 spawnPosition) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) spawnPosition = default(Vector3); if (!ClimbOnlyModeEnabled || !IsInKilnSegment() || (Object)(object)anchorPlayer == (Object)null) { return false; } Vector3 preferredFlatDirection = anchorPlayer.data.lookDirection_Flat; if (((Vector3)(ref preferredFlatDirection)).sqrMagnitude < 0.01f) { preferredFlatDirection = -((Component)anchorPlayer).transform.forward; } preferredFlatDirection.y = 0f; ((Vector3)(ref preferredFlatDirection)).Normalize(); if (!TryFindStandableNearAnchor(anchorPlayer, preferredFlatDirection, preferBehind: true, out var bestStandPoint)) { return false; } spawnPosition = bestStandPoint + Vector3.up * GetSpawnClearance(); return true; } internal static bool TryLostSightStandableTeleport(Scoutmaster scoutmaster, Character anchorPlayer, float lostSightSeconds, float teleportCooldown) { //IL_009f: 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_00be: 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_00d2: 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) if (!ClimbOnlyModeEnabled || !IsInKilnSegment() || (Object)(object)scoutmaster?.character == (Object)null || (Object)(object)anchorPlayer == (Object)null || !PhotonNetwork.IsMasterClient || !((MonoBehaviourPun)scoutmaster.character).photonView.IsMine) { return false; } if (lostSightSeconds <= 0f || scoutmaster.sinceSeenTarget <= lostSightSeconds || scoutmaster.AnyoneCanSeeMe()) { return false; } if (scoutmaster.tpCounter < Mathf.Max(teleportCooldown, 5f)) { return false; } if (!TryFindStandableNearAnchor(anchorPlayer, Vector3.zero, preferBehind: false, out var bestStandPoint)) { return false; } Vector3 val = bestStandPoint + Vector3.up * GetSpawnClearance(); scoutmaster.character.view.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, false }); scoutmaster.character.view.RPC("StopClimbingRpc", (RpcTarget)0, new object[1] { 0f }); scoutmaster.sinceSeenTarget = 0f; scoutmaster.tpCounter = 0f; scoutmaster.discovered = null; ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; if (instance != null) { Player owner = anchorPlayer.refs.view.Owner; instance.LogInfo("Kiln lost-sight recovery — warped to standable ground near " + (((owner != null) ? owner.NickName : null) ?? "player") + "."); } return true; } private static float GetSpawnClearance() { return Mathf.Max(0.5f, configSpawnClearanceHeight?.Value ?? 1.5f); } private static float GetMaxSlopeAngle() { return Mathf.Clamp(configMaxStandSlopeAngle?.Value ?? 50f, 5f, 85f); } private static float GetMaxVerticalDelta() { return Mathf.Max(2f, configMaxVerticalDeltaFromPlayer?.Value ?? 12f); } private static bool TryFindStandableNearAnchor(Character anchor, Vector3 preferredFlatDirection, bool preferBehind, out Vector3 bestStandPoint) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0279: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_00e4: 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_00f2: 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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: 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_01e1: Unknown result type (might be due to invalid IL or missing references) bestStandPoint = default(Vector3); if ((Object)(object)anchor == (Object)null) { return false; } float anchorFloorY = GetAnchorFloorY(anchor); float maxVerticalDelta = GetMaxVerticalDelta(); float maxSlopeAngle = GetMaxSlopeAngle(); List list = new List(); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(anchor.Center.x, 0f, anchor.Center.z); if (((Vector3)(ref preferredFlatDirection)).sqrMagnitude > 0.01f) { preferredFlatDirection.y = 0f; ((Vector3)(ref preferredFlatDirection)).Normalize(); } for (int i = 0; i < SearchRingRadii.Length; i++) { float num = SearchRingRadii[i]; int num2 = ((num <= 0f) ? 1 : 12); for (int j = 0; j < num2; j++) { float num3 = 360f / (float)num2 * (float)j; Vector3 val2 = ((num <= 0f) ? Vector3.zero : (Quaternion.Euler(0f, num3, 0f) * Vector3.forward * num)); Vector3 val3 = val + val2; if (!TryRaycastStandable(val3, anchorFloorY, maxSlopeAngle, maxVerticalDelta, out var standPoint)) { continue; } float num4 = Vector2.Distance(new Vector2(val3.x, val3.z), new Vector2(val.x, val.z)); float num5 = 0f; if (preferBehind && ((Vector3)(ref preferredFlatDirection)).sqrMagnitude > 0.01f) { Vector3 val4 = standPoint - anchor.Center; val4.y = 0f; if (((Vector3)(ref val4)).sqrMagnitude > 0.01f) { num5 = Vector3.Dot(((Vector3)(ref val4)).normalized, preferredFlatDirection); } } float num6 = configPreferBehindDistance?.Value ?? 10f; float num7 = (preferBehind ? (0f - Mathf.Abs(num4 - num6)) : (0f - num4)); list.Add(new Candidate { Point = standPoint, Score = num7 + num5 * 5f }); } } if (list.Count == 0) { return false; } list.Sort((Candidate a, Candidate b) => b.Score.CompareTo(a.Score)); bestStandPoint = list[0].Point; return true; } private static float GetAnchorFloorY(Character anchor) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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) //IL_005c: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (anchor.data.isGrounded) { return anchor.data.groundPos.y; } Vector3 val = anchor.Center + Vector3.up * 2f; RaycastHit val2 = HelperFunctions.LineCheck(val, val + Vector3.down * 120f, (LayerType)1, 0f, (QueryTriggerInteraction)1); return Object.op_Implicit((Object)(object)((RaycastHit)(ref val2)).transform) ? ((RaycastHit)(ref val2)).point.y : anchor.Center.y; } private static bool TryRaycastStandable(Vector3 anchorXZ, float floorY, float maxSlope, float maxVerticalDelta, out Vector3 standPoint) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) standPoint = default(Vector3); float num = floorY + 80f; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(anchorXZ.x, num, anchorXZ.z); RaycastHit hit = HelperFunctions.LineCheck(val, val + Vector3.down * 200f, (LayerType)1, 0f, (QueryTriggerInteraction)1); if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).transform) || !IsStandableSurface(hit, maxSlope)) { return false; } if (Mathf.Abs(((RaycastHit)(ref hit)).point.y - floorY) > maxVerticalDelta) { return false; } standPoint = ((RaycastHit)(ref hit)).point; return true; } private static bool IsStandableSurface(RaycastHit hit, float maxSlope) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return Vector3.Angle(((RaycastHit)(ref hit)).normal, Vector3.up) <= maxSlope; } } internal static class ScoutmasterTorchSupport { private const ushort DefaultHeldItemId = 109; private const float DefaultHeldItemStashDistance = 12f; private const string DefaultRandomItems = "109,42,28,77,72,65"; private static ConfigEntry configEnabled; private static ConfigEntry configHeldItemId; private static ConfigEntry configHeldItemStashDistance; private static ConfigEntry configRandomizeHeldItem; private static ConfigEntry configRandomItems; private static Item cachedHeldItem; internal static bool Enabled => configEnabled?.Value ?? false; internal static void Initialize(ConfigFile config) { configEnabled = config.Bind("ScoutmastersHeldItem", "EnableScoutmasterHeldItem", true, "When true, the scoutmaster holds an item whenever he is not climbing or carrying a grabbed player."); configHeldItemId = config.Bind("ScoutmastersHeldItem", "HeldItemId", ((ushort)109).ToString(), "Item ID to spawn in the scoutmaster's hand when RandomizeHeldItem is false (default 109 = Torch)."); configHeldItemStashDistance = config.Bind("ScoutmastersHeldItem", "HeldItemStashDistance", 12f, "When the scoutmaster is within this many meters of his chase target, he stashes the held item so his hands are free to grab. Re-equips after moving away or after a successful grab ends."); configRandomizeHeldItem = config.Bind("ScoutmastersHeldItem", "RandomizeHeldItem", false, "When true, ignores HeldItemId and picks a random ID from RandomItems every time he re-equips after stashing (climb/grab range/etc)."); configRandomItems = config.Bind("ScoutmastersHeldItem", "RandomItems", "109,42,28,77,72,65", "Comma-separated item IDs used when RandomizeHeldItem is true. Defaults: 109=Torch, 42=Lantern, 28=Stick, 77=Scoutmasters Bugle, 72=Stone, 65=Rope Spool."); } internal static void Reset() { DestroyCachedHeldItem(); } internal static void Tick(Scoutmaster scoutmaster) { if (!Enabled || !PhotonNetwork.IsMasterClient || (Object)(object)scoutmaster?.character == (Object)null || !((MonoBehaviourPun)scoutmaster.character).photonView.IsMine || !ScoutmasterAfflictionSupport.IsScoutmasterCharacter(scoutmaster.character)) { return; } Character character = scoutmaster.character; bool flag = ShouldHoldItem(scoutmaster); Item currentItem = character.data.currentItem; bool flag2 = IsOurHeldItem(currentItem); if (flag) { if (ShouldRefreshConfiguredHeldItem(currentItem)) { ReplaceConfiguredHeldItem(character); } else if (!flag2) { TryEquipHeldItem(character); } else if ((Object)(object)currentItem != (Object)null && !IsHeldItemLit(currentItem)) { ScheduleEnsureHeldItemLit(currentItem); } } else if (flag2) { StashHeldItem(character); } } private static bool ShouldHoldItem(Scoutmaster scoutmaster) { Character val = scoutmaster?.character; if ((Object)(object)val == (Object)null || val.data.dead || val.data.passedOut || val.data.fullyPassedOut || ScoutmasterPassOutSupport.IsScoutmasterDisabledForGrabOrPhysics(val)) { return false; } if (val.data.isClimbing || val.data.isRopeClimbing || val.data.isVineClimbing || (Object)(object)val.data.currentClimbHandle != (Object)null) { return false; } if ((Object)(object)val.data.grabbedPlayer != (Object)null) { return false; } if (IsWithinGrabRange(scoutmaster)) { return false; } return true; } private static bool IsWithinGrabRange(Scoutmaster scoutmaster) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) Character val = ((scoutmaster != null) ? scoutmaster.currentTarget : null); Character val2 = scoutmaster?.character; if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || val.data.dead) { return false; } float num = configHeldItemStashDistance?.Value ?? 12f; if (num <= 0f) { return false; } return Vector3.Distance(val2.Center, val.Center) <= num; } private static void TryEquipHeldItem(Character character) { ConfigEntry obj = configRandomizeHeldItem; if (obj != null && obj.Value) { DestroyCachedHeldItem(); SpawnAndEquipHeldItem(character); return; } ushort configuredHeldItemId = GetConfiguredHeldItemId(); if ((Object)(object)cachedHeldItem != (Object)null && cachedHeldItem.itemID != configuredHeldItemId) { DestroyCachedHeldItem(); } if ((Object)(object)cachedHeldItem != (Object)null) { if (ReEquipCachedHeldItem(character)) { return; } DestroyCachedHeldItem(); } SpawnAndEquipHeldItem(character); } private static bool ShouldRefreshConfiguredHeldItem(Item heldItem) { ConfigEntry obj = configRandomizeHeldItem; if ((obj != null && obj.Value) || (Object)(object)heldItem == (Object)null) { return false; } if (!IsOurHeldItem(heldItem)) { return false; } return heldItem.itemID != GetConfiguredHeldItemId(); } private static void ReplaceConfiguredHeldItem(Character character) { Item currentItem = character.data.currentItem; if ((Object)(object)currentItem != (Object)null && IsOurHeldItem(currentItem)) { cachedHeldItem = currentItem; character.refs.items.UnAttachEquippedItem(); } DestroyCachedHeldItem(); SpawnAndEquipHeldItem(character); } private static bool ReEquipCachedHeldItem(Character character) { if ((Object)(object)cachedHeldItem == (Object)null || (Object)(object)((Component)cachedHeldItem).gameObject == (Object)null) { return false; } ((Component)cachedHeldItem).gameObject.SetActive(true); character.refs.items.Equip(cachedHeldItem); if ((Object)(object)character.data.currentItem == (Object)(object)cachedHeldItem) { ScheduleEnsureHeldItemLit(cachedHeldItem); return true; } return false; } private static void SpawnAndEquipHeldItem(Character character) { //IL_0076: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_0092: 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_0095: Unknown result type (might be due to invalid IL or missing references) if (!TryResolveHeldItemId(out var itemId)) { ScoutmasterRampagePlugin.Instance?.LogWarning("Scoutmaster held item: no valid item ID configured."); return; } if (!TryGetPrefabName(itemId, out var prefabName)) { ScoutmasterRampagePlugin.Instance?.LogWarning($"Scoutmaster held item: ItemDatabase has no prefab for item ID {itemId}."); return; } Vector3 val = ((Component)character.GetBodypart((BodypartType)2)).transform.TransformVector(2f * Vector3.forward); Vector3 val2 = character.Center + val; GameObject val3 = PhotonNetwork.InstantiateItemRoom(prefabName, val2, Quaternion.identity); if ((Object)(object)val3 == (Object)null) { ScoutmasterRampagePlugin.Instance?.LogWarning($"Scoutmaster held item spawn failed for prefab '{prefabName}' (ID {itemId})."); return; } Item component = val3.GetComponent(); if ((Object)(object)component == (Object)null) { PhotonNetwork.Destroy(val3.GetComponent()); ScoutmasterRampagePlugin.Instance?.LogWarning("Scoutmaster held item spawn had no Item component."); return; } if (component.itemID != itemId) { ScoutmasterRampagePlugin.Instance?.LogWarning($"Scoutmaster held item prefab '{prefabName}' has itemID {component.itemID}, expected {itemId}."); } cachedHeldItem = component; character.refs.items.Equip(component); if ((Object)(object)character.data.currentItem == (Object)(object)component) { ScoutmasterRampagePlugin.Instance?.LogInfo($"Scoutmaster held item equipped (ID {component.itemID}, prefab '{prefabName}')."); ScheduleEnsureHeldItemLit(component); } else { ScoutmasterRampagePlugin.Instance?.LogWarning("Scoutmaster held item spawned but Equip did not stick."); } } private static bool TryResolveHeldItemId(out ushort itemId) { ConfigEntry obj = configRandomizeHeldItem; if (obj != null && obj.Value) { List list = ParseItemIdList(configRandomItems?.Value); if (list.Count == 0) { itemId = 0; return false; } itemId = list[Random.Range(0, list.Count)]; return true; } itemId = GetConfiguredHeldItemId(); return itemId != 0; } private static ushort GetConfiguredHeldItemId() { return ParseSingleItemId(configHeldItemId?.Value, 109); } private static ushort ParseSingleItemId(string raw, ushort fallback) { if (string.IsNullOrWhiteSpace(raw)) { return fallback; } if (ushort.TryParse(raw.Trim(), out var result) && result != 0) { return result; } return fallback; } private static bool TryGetPrefabName(ushort itemId, out string prefabName) { prefabName = null; MethodInfo methodInfo = AccessTools.Method(AccessTools.TypeByName("ItemDatabase"), "TryGetItem", new Type[2] { typeof(ushort), typeof(Item).MakeByRefType() }, (Type[])null); if (methodInfo == null) { return false; } object[] array = new object[2] { itemId, null }; if (!(bool)methodInfo.Invoke(null, array)) { return false; } object obj = array[1]; Item val = (Item)((obj is Item) ? obj : null); if ((Object)(object)val == (Object)null) { return false; } prefabName = ((Object)((Component)val).gameObject).name; return !string.IsNullOrWhiteSpace(prefabName); } private static List ParseItemIdList(string csv) { List list = new List(); if (string.IsNullOrWhiteSpace(csv)) { return list; } string[] array = csv.Split(new char[3] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { if (ushort.TryParse(array[i].Trim(), out var result) && result != 0 && !list.Contains(result)) { list.Add(result); } } return list; } private static void ScheduleEnsureHeldItemLit(Item item) { ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)item == (Object)null)) { ((MonoBehaviour)instance).StartCoroutine(EnsureHeldItemLitCoroutine(item)); } } private static IEnumerator EnsureHeldItemLitCoroutine(Item item) { for (int i = 0; i < 30; i++) { if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null) { yield break; } if ((int)item.itemState == 1 && (Object)(object)item.rig != (Object)null && !item.rig.isKinematic) { EnsureHeldItemLit(item); yield break; } yield return (object)new WaitForFixedUpdate(); } if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null) { EnsureHeldItemLit(item); } } private static void EnsureHeldItemLit(Item item) { if (!((Object)(object)item == (Object)null) && !((Object)(object)((MonoBehaviourPun)item).photonView == (Object)null) && ((MonoBehaviourPun)item).photonView.IsMine) { Lantern componentInChildren = ((Component)item).GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { TrySetFlareActive(item, value: true); } else if (!componentInChildren.lit || !IsFlareActive(item)) { ((MonoBehaviourPun)item).photonView.RPC("LightLanternRPC", (RpcTarget)0, new object[1] { true }); } } } private static bool IsHeldItemLit(Item item) { if ((Object)(object)item == (Object)null) { return true; } Lantern componentInChildren = ((Component)item).GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { return true; } return componentInChildren.lit || IsFlareActive(item); } private static bool IsFlareActive(Item item) { if ((Object)(object)item == (Object)null || !item.HasData((DataEntryKey)3)) { return false; } return item.GetData((DataEntryKey)3).Value; } private static void TrySetFlareActive(Item item, bool value) { if (!((Object)(object)item == (Object)null) && item.HasData((DataEntryKey)3)) { item.GetData((DataEntryKey)3).Value = value; } } private static void StashHeldItem(Character character) { Item currentItem = character.data.currentItem; if (!IsOurHeldItem(currentItem)) { currentItem = cachedHeldItem; } if ((Object)(object)currentItem == (Object)null) { return; } ConfigEntry obj = configRandomizeHeldItem; if (obj != null && obj.Value) { if ((Object)(object)character.data.currentItem == (Object)(object)currentItem) { character.refs.items.UnAttachEquippedItem(); } cachedHeldItem = currentItem; DestroyCachedHeldItem(); return; } cachedHeldItem = currentItem; if ((Object)(object)character.data.currentItem == (Object)(object)currentItem) { character.refs.items.UnAttachEquippedItem(); } else { character.refs.items.UnAttachItem(); } ((Component)currentItem).gameObject.SetActive(false); ((Component)currentItem).transform.SetParent(((Component)character).transform, true); } private static bool IsOurHeldItem(Item item) { if ((Object)(object)item == (Object)null) { return false; } if ((Object)(object)cachedHeldItem != (Object)null && (Object)(object)item == (Object)(object)cachedHeldItem) { return true; } return IsConfiguredHeldItemId(item.itemID); } private static bool IsConfiguredHeldItemId(ushort itemId) { ConfigEntry obj = configRandomizeHeldItem; if (obj != null && obj.Value) { List list = ParseItemIdList(configRandomItems?.Value); return list.Contains(itemId); } return itemId == GetConfiguredHeldItemId(); } private static void DestroyCachedHeldItem() { if (!((Object)(object)cachedHeldItem == (Object)null)) { if ((Object)(object)((Component)cachedHeldItem).gameObject != (Object)null && (Object)(object)((MonoBehaviourPun)cachedHeldItem).photonView != (Object)null) { PhotonNetwork.Destroy(((Component)cachedHeldItem).gameObject); } cachedHeldItem = null; } } } internal static class ScoutmasterLootSupport { private const string DefaultLootItemIds = "125,6,16,24,18,17,114,27,29,152,33,38,44,98,63,65,107,67,71,73,74,7,0,2,46,154"; private static ConfigEntry configEnabled; private static ConfigEntry configDropChance; private static ConfigEntry configMinCount; private static ConfigEntry configMaxCount; private static ConfigEntry configItemIds; internal static bool Enabled => configEnabled?.Value ?? true; internal static void Initialize(ConfigFile config) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown configEnabled = config.Bind("ScoutmastersLoot", "EnableScoutmastersLoot", true, "When true, the scoutmaster can drop random loot from LootItemIds when he passes out."); configDropChance = config.Bind("ScoutmastersLoot", "LootDropChance", 1f, new ConfigDescription("Chance (0–1) that any loot drops when the scoutmaster passes out. Default 1.0 = always.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); configMinCount = config.Bind("ScoutmastersLoot", "LootMinCount", 1, new ConfigDescription("Minimum number of items to drop on a successful loot roll.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20), Array.Empty())); configMaxCount = config.Bind("ScoutmastersLoot", "LootMaxCount", 3, new ConfigDescription("Maximum number of items to drop on a successful loot roll.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20), Array.Empty())); configItemIds = config.Bind("ScoutmastersLoot", "LootItemIds", "125,6,16,24,18,17,114,27,29,152,33,38,44,98,63,65,107,67,71,73,74,7,0,2,46,154", "CSV of item IDs the scoutmaster can drop on pass-out. One ID is picked at random per dropped item."); } internal static void TryDropLoot(Scoutmaster scoutmaster) { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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) if (!Enabled || !PhotonNetwork.IsMasterClient || (Object)(object)scoutmaster?.character == (Object)null || Random.value > Mathf.Clamp01(configDropChance.Value)) { return; } List list = ParseItemIdList(configItemIds?.Value); if (list.Count == 0) { ScoutmasterRampagePlugin.Instance?.LogWarning("Scoutmasters Loot: LootItemIds is empty — nothing to drop."); return; } int num = Mathf.Max(0, configMinCount.Value); int num2 = Mathf.Max(num, configMaxCount.Value); int num3 = Random.Range(num, num2 + 1); if (num3 <= 0) { return; } Vector3 center = scoutmaster.character.Center; int num4 = 0; for (int i = 0; i < num3; i++) { ushort itemId = list[Random.Range(0, list.Count)]; if (TrySpawnLootItem(itemId, center, i)) { num4++; } } if (num4 > 0) { ScoutmasterRampagePlugin.Instance?.LogInfo($"Scoutmasters Loot: dropped {num4} item(s) at pass-out."); } } private static bool TrySpawnLootItem(ushort itemId, Vector3 origin, int index) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) if (!TryGetPrefabName(itemId, out var prefabName)) { ScoutmasterRampagePlugin.Instance?.LogWarning($"Scoutmasters Loot: no prefab for item ID {itemId}."); return false; } Vector2 val = Random.insideUnitCircle * 1.25f; Vector3 val2 = origin + new Vector3(val.x, 0.6f + (float)index * 0.15f, val.y); GameObject val3 = PhotonNetwork.InstantiateItemRoom(prefabName, val2, Quaternion.identity); if ((Object)(object)val3 == (Object)null) { ScoutmasterRampagePlugin.Instance?.LogWarning($"Scoutmasters Loot: spawn failed for '{prefabName}' (ID {itemId})."); return false; } PhotonView component = val3.GetComponent(); Item component2 = val3.GetComponent(); if ((Object)(object)component != (Object)null) { component.RPC("SetKinematicRPC", (RpcTarget)0, new object[3] { false, val3.transform.position, val3.transform.rotation }); } if ((Object)(object)component2?.rig != (Object)null) { component2.rig.linearVelocity = Random.insideUnitSphere * 1.5f; } return true; } private static bool TryGetPrefabName(ushort itemId, out string prefabName) { prefabName = null; MethodInfo methodInfo = AccessTools.Method(AccessTools.TypeByName("ItemDatabase"), "TryGetItem", new Type[2] { typeof(ushort), typeof(Item).MakeByRefType() }, (Type[])null); if (methodInfo == null) { return false; } object[] array = new object[2] { itemId, null }; if (!(bool)methodInfo.Invoke(null, array)) { return false; } object obj = array[1]; Item val = (Item)((obj is Item) ? obj : null); if ((Object)(object)val == (Object)null) { return false; } prefabName = ((Object)((Component)val).gameObject).name; return !string.IsNullOrWhiteSpace(prefabName); } private static List ParseItemIdList(string csv) { List list = new List(); if (string.IsNullOrWhiteSpace(csv)) { return list; } string[] array = csv.Split(new char[3] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { if (ushort.TryParse(array[i].Trim(), out var result) && !list.Contains(result)) { list.Add(result); } } return list; } } internal static class ScoutmasterBlessingSupport { private const byte BlessingEventCode = 174; private const string DefaultPowers = "InfiniteStamina,Invincibility,FasterBoi,AddBonusStamina,WarpToHighestCharacter"; private const float ClimbBoostAmount = 0.5f; private const float TitleCharDelay = 0.02f; private const float TitleHoldSeconds = 1.75f; private const float TitleFadeSeconds = 0.75f; private static ConfigEntry configEnabled; private static ConfigEntry configChance; private static ConfigEntry configDuration; private static ConfigEntry configPowers; private static bool eventHooked; private static Coroutine titleRoutine; internal static bool Enabled => configEnabled?.Value ?? true; internal static void Initialize(ConfigFile config) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown configEnabled = config.Bind("ScoutmastersBlessing", "EnableScoutmastersBlessing", true, "When true, bonking the scoutmaster can grant the bonker a random Scoutmasters Blessing power."); configChance = config.Bind("ScoutmastersBlessing", "BlessingChance", 0.5f, new ConfigDescription("Chance (0–1) to grant a blessing when the scoutmaster is bonked. Default 0.5 = 50%.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); configDuration = config.Bind("ScoutmastersBlessing", "BlessingDuration", 20f, "Duration in seconds for timed blessings (Infinite Stamina, Invincibility, Faster Boi, Climbing Chalk)."); configPowers = config.Bind("ScoutmastersBlessing", "BlessingPowers", "InfiniteStamina,Invincibility,FasterBoi,AddBonusStamina,WarpToHighestCharacter", "CSV of blessing power IDs. Valid: InfiniteStamina, Invincibility, FasterBoi, ClimbingChalk, AddBonusStamina, WarpToHighestCharacter. Warp is skipped automatically in solo lobbies. ClimbingChalk applies a real climb-speed boost (vanilla chalk affliction has no gameplay effect)."); EnsureEventHook(); } internal static void EnsureEventHook() { if (PhotonNetwork.NetworkingClient != null && !eventHooked) { PhotonNetwork.NetworkingClient.EventReceived += OnPhotonEvent; eventHooked = true; } } internal static void TryGrantFromBonk(Item bonkItem) { EnsureEventHook(); if (!Enabled || (Object)(object)bonkItem == (Object)null || Random.value > Mathf.Clamp01(configChance.Value)) { return; } Character val = ResolveBonker(bonkItem); if ((Object)(object)val == (Object)null || val.data.dead || val.data.isScoutmaster || val.isBot) { string[] obj = new string[5] { "[Scoutmasters Rampage] Scoutmasters Blessing: bonk registered but could not resolve a valid bonker ", $"(thrown={(Object)(object)bonkItem.lastThrownCharacter != (Object)null}, holder={(Object)(object)bonkItem.lastHolderCharacter != (Object)null}, ", "owner=", null, null }; PhotonView photonView = ((MonoBehaviourPun)bonkItem).photonView; object obj2; if (photonView == null) { obj2 = null; } else { Player owner = photonView.Owner; obj2 = ((owner != null) ? owner.NickName : null); } if (obj2 == null) { obj2 = "null"; } obj[3] = (string)obj2; obj[4] = ")."; Debug.LogWarning((object)string.Concat(obj)); } else { if ((Object)(object)((MonoBehaviourPun)val).photonView == (Object)null) { return; } string text = PickRandomPower(val); if (string.IsNullOrEmpty(text)) { Debug.Log((object)"[Scoutmasters Rampage] Scoutmasters Blessing: no valid powers available for this lobby (e.g. Warp-only list in solo)."); return; } float duration = configDuration?.Value ?? 20f; if (val.IsLocal) { ApplyBlessingLocal(val, text, duration); } else { RaiseBlessingEvent(((MonoBehaviourPun)val).photonView.ViewID, text, duration, val); } } } private static Character ResolveBonker(Item bonkItem) { if ((Object)(object)bonkItem.lastThrownCharacter != (Object)null) { return bonkItem.lastThrownCharacter; } if ((Object)(object)bonkItem.lastHolderCharacter != (Object)null) { return bonkItem.lastHolderCharacter; } if ((Object)(object)bonkItem.holderCharacter != (Object)null) { return bonkItem.holderCharacter; } Player val = (((Object)(object)((MonoBehaviourPun)bonkItem).photonView != (Object)null) ? ((MonoBehaviourPun)bonkItem).photonView.Owner : null); if (val != null) { Character playerCharacter = PlayerHandler.GetPlayerCharacter(val); if ((Object)(object)playerCharacter != (Object)null) { return playerCharacter; } } return null; } private static string PickRandomPower(Character rewarded) { List list = ParsePowerList(configPowers?.Value); if (list.Count == 0) { list = ParsePowerList("InfiniteStamina,Invincibility,FasterBoi,AddBonusStamina,WarpToHighestCharacter"); } if ((Object)(object)FindHighestCharacter(rewarded) == (Object)null) { list.RemoveAll((string p) => p.Equals("WarpToHighestCharacter", StringComparison.OrdinalIgnoreCase)); } if (list.Count == 0) { return null; } return list[Random.Range(0, list.Count)]; } private static List ParsePowerList(string csv) { List list = new List(); if (string.IsNullOrWhiteSpace(csv)) { return list; } string[] array = csv.Split(new char[3] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0 && !list.Contains(text) && IsKnownPower(text)) { list.Add(text); } } return list; } private static bool IsKnownPower(string key) { return key.Equals("InfiniteStamina", StringComparison.OrdinalIgnoreCase) || key.Equals("Invincibility", StringComparison.OrdinalIgnoreCase) || key.Equals("FasterBoi", StringComparison.OrdinalIgnoreCase) || key.Equals("ClimbingChalk", StringComparison.OrdinalIgnoreCase) || key.Equals("AddBonusStamina", StringComparison.OrdinalIgnoreCase) || key.Equals("WarpToHighestCharacter", StringComparison.OrdinalIgnoreCase); } private static void RaiseBlessingEvent(int characterViewId, string power, float duration, Character rewarded) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_006d: 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) object[] array = new object[3] { characterViewId, power, duration }; RaiseEventOptions val = new RaiseEventOptions(); if ((Object)(object)((MonoBehaviourPun)rewarded).photonView != (Object)null && ((MonoBehaviourPun)rewarded).photonView.Owner != null) { val.TargetActors = new int[1] { ((MonoBehaviourPun)rewarded).photonView.Owner.ActorNumber }; } else { val.Receivers = (ReceiverGroup)1; } PhotonNetwork.RaiseEvent((byte)174, (object)array, val, SendOptions.SendReliable); } private static void OnPhotonEvent(EventData photonEvent) { if (photonEvent.Code != 174 || !(photonEvent.CustomData is object[] array) || array.Length < 2) { return; } int num = Convert.ToInt32(array[0]); string text = array[1] as string; float duration = ((array.Length >= 3) ? Convert.ToSingle(array[2]) : (configDuration?.Value ?? 20f)); if (!string.IsNullOrEmpty(text)) { PhotonView val = PhotonView.Find(num); Character val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent() : null); if (!((Object)(object)val2 == (Object)null) && val2.IsLocal) { ApplyBlessingLocal(val2, text, duration); } } } private static void ApplyBlessingLocal(Character character, string power, float duration) { string displayName = GetDisplayName(power); bool flag = false; if (power.Equals("WarpToHighestCharacter", StringComparison.OrdinalIgnoreCase)) { flag = TryWarpToHighest(character); } else if (power.Equals("ClimbingChalk", StringComparison.OrdinalIgnoreCase)) { flag = TryApplyClimbSpeedBoost(character, duration); } else { Affliction val = CreateAffliction(power, duration); if (val != null && (Object)(object)character.refs?.afflictions != (Object)null) { character.refs.afflictions.AddAffliction(val, false); flag = true; } } if (!flag) { Debug.LogWarning((object)("[Scoutmasters Rampage] Scoutmasters Blessing failed to apply: " + power)); return; } ShowBlessingTitle(displayName); Debug.Log((object)$"[Scoutmasters Rampage] Scoutmasters Blessing granted: {displayName} ({duration:0.#}s)."); } private static Affliction CreateAffliction(string power, float duration) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_004e: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0075: 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) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown duration = Mathf.Max(0.1f, duration); if (power.Equals("InfiniteStamina", StringComparison.OrdinalIgnoreCase)) { return (Affliction)new Affliction_InfiniteStamina(duration) { drowsyAffliction = null, climbDelay = 0f }; } if (power.Equals("Invincibility", StringComparison.OrdinalIgnoreCase)) { return (Affliction)new Affliction_Invincibility { totalTime = duration, isFromMilk = false }; } if (power.Equals("FasterBoi", StringComparison.OrdinalIgnoreCase)) { return (Affliction)new Affliction_FasterBoi { totalTime = duration, moveSpeedMod = 0.5f, climbSpeedMod = 0.5f, drowsyOnEnd = 0f, climbDelay = 0f }; } if (power.Equals("AddBonusStamina", StringComparison.OrdinalIgnoreCase)) { return (Affliction)new Affliction_AddBonusStamina(1f, 1f); } return null; } private static bool TryApplyClimbSpeedBoost(Character character, float duration) { if ((Object)(object)character?.refs?.climbing == (Object)null) { return false; } CharacterClimbing climbing = character.refs.climbing; climbing.climbSpeedMod += 0.5f; if ((Object)(object)character.refs.ropeHandling != (Object)null) { CharacterRopeHandling ropeHandling = character.refs.ropeHandling; ropeHandling.climbSpeedMod += 0.5f; } if ((Object)(object)character.refs.vineClimbing != (Object)null) { CharacterVineClimbing vineClimbing = character.refs.vineClimbing; vineClimbing.climbSpeedMod += 0.5f; } ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; if ((Object)(object)instance != (Object)null) { ((MonoBehaviour)instance).StartCoroutine(RemoveClimbSpeedBoostAfter(character, Mathf.Max(0.1f, duration))); } return true; } private static IEnumerator RemoveClimbSpeedBoostAfter(Character character, float duration) { yield return (object)new WaitForSeconds(duration); if (character?.refs != null) { if ((Object)(object)character.refs.climbing != (Object)null) { CharacterClimbing climbing = character.refs.climbing; climbing.climbSpeedMod -= 0.5f; } if ((Object)(object)character.refs.ropeHandling != (Object)null) { CharacterRopeHandling ropeHandling = character.refs.ropeHandling; ropeHandling.climbSpeedMod -= 0.5f; } if ((Object)(object)character.refs.vineClimbing != (Object)null) { CharacterVineClimbing vineClimbing = character.refs.vineClimbing; vineClimbing.climbSpeedMod -= 0.5f; } } } private static bool TryWarpToHighest(Character self) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) Character val = FindHighestCharacter(self); if ((Object)(object)val == (Object)null || (Object)(object)((MonoBehaviourPun)self).photonView == (Object)null) { return false; } Vector3 val2 = val.Center + Vector3.up * 0.5f; ((MonoBehaviourPun)self).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val2, true }); return true; } private static Character FindHighestCharacter(Character excluded) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) Character val = null; List allCharacters = Character.AllCharacters; if (allCharacters == null) { return null; } for (int i = 0; i < allCharacters.Count; i++) { Character val2 = allCharacters[i]; if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)excluded) && !val2.isBot && !val2.data.dead && !val2.data.fullyPassedOut && !val2.data.isScoutmaster && ((Object)(object)val == (Object)null || val2.Center.y > val.Center.y)) { val = val2; } } return val; } private static string GetDisplayName(string power) { if (power.Equals("InfiniteStamina", StringComparison.OrdinalIgnoreCase)) { return "Infinite Stamina"; } if (power.Equals("Invincibility", StringComparison.OrdinalIgnoreCase)) { return "Invincibility"; } if (power.Equals("FasterBoi", StringComparison.OrdinalIgnoreCase)) { return "Faster Boi"; } if (power.Equals("ClimbingChalk", StringComparison.OrdinalIgnoreCase)) { return "Climbing Chalk"; } if (power.Equals("AddBonusStamina", StringComparison.OrdinalIgnoreCase)) { return "Bonus Stamina"; } if (power.Equals("WarpToHighestCharacter", StringComparison.OrdinalIgnoreCase)) { return "Warp To Leader"; } return power; } private static void ShowBlessingTitle(string powerDisplayName) { GUIManager instance = GUIManager.instance; ScoutmasterRampagePlugin instance2 = ScoutmasterRampagePlugin.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance2 == (Object)null)) { if (instance._heroRoutine != null) { ((MonoBehaviour)instance).StopCoroutine(instance._heroRoutine); instance._heroRoutine = null; } if (titleRoutine != null) { ((MonoBehaviour)instance2).StopCoroutine(titleRoutine); } titleRoutine = ((MonoBehaviour)instance2).StartCoroutine(BlessingTitleRoutine(instance, "Scoutmasters Blessing:\n" + powerDisplayName)); } } private static IEnumerator BlessingTitleRoutine(GUIManager gui, string heroString) { if ((Object)(object)gui.heroCanvasObject != (Object)null) { gui.heroCanvasObject.SetActive(true); } yield return null; if ((Object)(object)gui.heroObject != (Object)null) { gui.heroObject.SetActive(true); } if ((Object)(object)gui.heroDayText != (Object)null) { ((TMP_Text)gui.heroDayText).text = string.Empty; } if ((Object)(object)gui.heroTimeOfDayText != (Object)null) { ((TMP_Text)gui.heroTimeOfDayText).text = string.Empty; } if ((Object)(object)gui.heroImage != (Object)null) { Color c = ((Graphic)gui.heroImage).color; ((Graphic)gui.heroImage).color = new Color(c.r, c.g, c.b, 1f); } if ((Object)(object)gui.heroShadowImage != (Object)null) { Color c2 = ((Graphic)gui.heroShadowImage).color; ((Graphic)gui.heroShadowImage).color = new Color(c2.r, c2.g, c2.b, 0.12f); } if ((Object)(object)gui.heroBG != (Object)null) { SetGraphicAlpha((Graphic)(object)gui.heroBG, 0.5f); } if ((Object)(object)gui.heroText != (Object)null) { for (int i = 0; i < heroString.Length; i++) { ((TMP_Text)gui.heroText).text = heroString.Substring(0, i + 1); if ((Object)(object)gui.heroCamera != (Object)null) { gui.heroCamera.Render(); } yield return (object)new WaitForSeconds(0.02f); } } yield return (object)new WaitForSeconds(1.75f); float fadeElapsed = 0f; float startImage = (((Object)(object)gui.heroImage != (Object)null) ? ((Graphic)gui.heroImage).color.a : 0f); float startShadow = (((Object)(object)gui.heroShadowImage != (Object)null) ? ((Graphic)gui.heroShadowImage).color.a : 0f); float startBg = (((Object)(object)gui.heroBG != (Object)null) ? ((Graphic)gui.heroBG).color.a : 0f); while (fadeElapsed < 0.75f) { fadeElapsed += Time.deltaTime; float t = Mathf.Clamp01(fadeElapsed / 0.75f); if ((Object)(object)gui.heroImage != (Object)null) { SetGraphicAlpha((Graphic)(object)gui.heroImage, Mathf.Lerp(startImage, 0f, t)); } if ((Object)(object)gui.heroShadowImage != (Object)null) { SetGraphicAlpha((Graphic)(object)gui.heroShadowImage, Mathf.Lerp(startShadow, 0f, t)); } if ((Object)(object)gui.heroBG != (Object)null) { SetGraphicAlpha((Graphic)(object)gui.heroBG, Mathf.Lerp(startBg, 0f, t)); } yield return null; } if ((Object)(object)gui.heroText != (Object)null) { ((TMP_Text)gui.heroText).text = string.Empty; } if ((Object)(object)gui.heroObject != (Object)null) { gui.heroObject.SetActive(false); } if ((Object)(object)gui.heroCanvasObject != (Object)null) { gui.heroCanvasObject.SetActive(false); } titleRoutine = null; } private static void SetGraphicAlpha(Graphic graphic, float alpha) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)graphic == (Object)null)) { Color color = graphic.color; graphic.color = new Color(color.r, color.g, color.b, alpha); } } } internal static class ScoutmasterConfigSyncService { public const int SchemaVersion = 1; public const char PairSeparator = '|'; public const char KeyValueSeparator = '='; private static readonly Dictionary LocalBaseline = new Dictionary(StringComparer.Ordinal); private static bool applyingRemote; private static bool handlersBound; public static bool HasRemoteHostConfig { get; private set; } public static void Initialize(ConfigFile config) { CaptureLocalBaseline(); BindChangeHandlers(config); } public static void ClearRemoteHostConfig() { HasRemoteHostConfig = false; } public static void CaptureLocalBaseline() { ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; ConfigFile val = ((instance != null) ? ((BaseUnityPlugin)instance).Config : null); if (val == null) { return; } LocalBaseline.Clear(); foreach (ConfigEntryBase item in EnumerateSyncableEntries(val)) { LocalBaseline[MakeKey(item.Definition)] = item.GetSerializedValue() ?? string.Empty; } } public static void ApplyLocalAuthoritativeConfig() { ClearRemoteHostConfig(); RestoreBaseline(); ScoutmasterRampagePlugin.Instance?.RefreshRespawnDelaysPublic(); } public static void ApplyRemoteSnapshot(string payload) { if (!PhotonNetwork.IsMasterClient && !string.IsNullOrEmpty(payload)) { if (!TryApplyPayload(payload)) { Debug.LogError((object)"[Scoutmasters Rampage] Failed to apply host config snapshot."); return; } HasRemoteHostConfig = true; ScoutmasterRampagePlugin.Instance?.RefreshRespawnDelaysPublic(); Debug.Log((object)"[Scoutmasters Rampage] Applied host config snapshot."); } } public static string SerializeCurrentConfig() { ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; ConfigFile val = ((instance != null) ? ((BaseUnityPlugin)instance).Config : null); if (val == null) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(1024); AppendPair(stringBuilder, "v", 1.ToString(CultureInfo.InvariantCulture)); foreach (ConfigEntryBase item in EnumerateSyncableEntries(val)) { string key = MakeKey(item.Definition); string stringToEscape = item.GetSerializedValue() ?? string.Empty; AppendPair(stringBuilder, key, Uri.EscapeDataString(stringToEscape)); } return stringBuilder.ToString(); } private static bool TryApplyPayload(string payload) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); string[] array = payload.Split(new char[1] { '|' }); int result = 0; bool flag = false; foreach (string text in array) { if (string.IsNullOrEmpty(text)) { continue; } int num = text.IndexOf('='); if (num > 0) { string text2 = text.Substring(0, num); string text3 = text.Substring(num + 1); if (text2 == "v") { flag = int.TryParse(text3, NumberStyles.Integer, CultureInfo.InvariantCulture, out result); } else { dictionary[text2] = Uri.UnescapeDataString(text3); } } } if (!flag || result != 1) { return false; } ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; ConfigFile val = ((instance != null) ? ((BaseUnityPlugin)instance).Config : null); if (val == null) { return false; } bool saveOnConfigSet = val.SaveOnConfigSet; applyingRemote = true; val.SaveOnConfigSet = false; try { foreach (ConfigEntryBase item in EnumerateSyncableEntries(val)) { string text4 = MakeKey(item.Definition); if (dictionary.TryGetValue(text4, out var value)) { try { item.SetSerializedValue(value); } catch (Exception ex) { Debug.LogWarning((object)("[Scoutmasters Rampage] Could not apply host config '" + text4 + "': " + ex.Message)); } } } } finally { val.SaveOnConfigSet = saveOnConfigSet; applyingRemote = false; } return true; } private static void RestoreBaseline() { ScoutmasterRampagePlugin instance = ScoutmasterRampagePlugin.Instance; ConfigFile val = ((instance != null) ? ((BaseUnityPlugin)instance).Config : null); if (val == null || LocalBaseline.Count == 0) { return; } bool saveOnConfigSet = val.SaveOnConfigSet; applyingRemote = true; val.SaveOnConfigSet = false; try { foreach (ConfigEntryBase item in EnumerateSyncableEntries(val)) { string text = MakeKey(item.Definition); if (LocalBaseline.TryGetValue(text, out var value)) { try { item.SetSerializedValue(value); } catch (Exception ex) { Debug.LogWarning((object)("[Scoutmasters Rampage] Could not restore local config '" + text + "': " + ex.Message)); } } } } finally { val.SaveOnConfigSet = saveOnConfigSet; applyingRemote = false; } } private static void BindChangeHandlers(ConfigFile config) { if (!handlersBound && config != null) { handlersBound = true; config.SettingChanged += OnConfigSettingChanged; } } private static void OnConfigSettingChanged(object sender, SettingChangedEventArgs args) { if (!applyingRemote && ((args != null) ? args.ChangedSetting : null) != null && !IsLocalOnly(args.ChangedSetting.Definition)) { ScoutmasterModAuthorizationService.OnHostConfigChangedLocally(); } } private static IEnumerable EnumerateSyncableEntries(ConfigFile config) { foreach (KeyValuePair pair in config) { if (!IsLocalOnly(pair.Key)) { yield return pair.Value; } } } private static bool IsLocalOnly(ConfigDefinition definition) { if (definition == (ConfigDefinition)null) { return true; } if (string.Equals(definition.Section, "OverheadStatus", StringComparison.OrdinalIgnoreCase)) { return true; } if (string.Equals(definition.Section, "Debug", StringComparison.OrdinalIgnoreCase) && string.Equals(definition.Key, "EnableLogs", StringComparison.OrdinalIgnoreCase)) { return true; } if (string.Equals(definition.Key, "ForceScoutmasterRespawn", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } private static string MakeKey(ConfigDefinition definition) { return definition.Section + "/" + definition.Key; } private static void AppendPair(StringBuilder builder, string key, string value) { if (builder.Length > 0) { builder.Append('|'); } builder.Append(key); builder.Append('='); builder.Append(value ?? string.Empty); } } internal static class ScoutmasterModAuthorizationService { public const string RoomConfigPropertyKey = "scoutmastersRampageConfigV1"; private static PhotonScopedManager photonManager; private static bool photonManagerReady; private static bool hostHasMod; private static string pendingHostConfigPayload; public static bool IsGameplayEnabled { get; private set; } public static void Initialize() { Networking.AddHostHasPluginListeners("tony4twentys.scoutmastersrampage", (Action)OnHostHasMod, (Action)OnHostMissingMod); if (PhotonCustomPropsUtilsPlugin.IsReady) { SetupPhotonManager(); } else { PhotonCustomPropsUtilsPlugin.OnReady += SetupPhotonManager; } if (!PhotonNetwork.InRoom) { SetSoloAuthorized(); } } public static void SetSoloAuthorized() { hostHasMod = true; IsGameplayEnabled = true; ScoutmasterConfigSyncService.ApplyLocalAuthoritativeConfig(); } private static void SetupPhotonManager() { if (photonManagerReady) { return; } photonManagerReady = true; photonManager = PhotonCustomPropsUtilsPlugin.GetManager("tony4twentys.scoutmastersrampage"); photonManager.RegisterOnJoinedRoom((Action)delegate { if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && hostHasMod) { ScoutmasterConfigSyncService.ApplyLocalAuthoritativeConfig(); PublishHostConfigIfMaster(); } }); photonManager.RegisterRoomProperty("scoutmastersRampageConfigV1", (RoomEventType)2, (Action)delegate(string value) { if (!PhotonNetwork.IsMasterClient && !string.IsNullOrEmpty(value)) { if (!hostHasMod) { pendingHostConfigPayload = value; } else { ScoutmasterConfigSyncService.ApplyRemoteSnapshot(value); } } }); } private static void OnHostHasMod() { if (PhotonNetwork.InRoom) { hostHasMod = true; IsGameplayEnabled = true; if (PhotonNetwork.IsMasterClient) { ScoutmasterConfigSyncService.ApplyLocalAuthoritativeConfig(); PublishHostConfigIfMaster(); } else if (!string.IsNullOrEmpty(pendingHostConfigPayload)) { ScoutmasterConfigSyncService.ApplyRemoteSnapshot(pendingHostConfigPayload); pendingHostConfigPayload = null; } } } private static void OnHostMissingMod() { if (PhotonNetwork.InRoom) { hostHasMod = false; IsGameplayEnabled = false; pendingHostConfigPayload = null; ScoutmasterConfigSyncService.ClearRemoteHostConfig(); ScoutmasterConfigSyncService.ApplyLocalAuthoritativeConfig(); } } public static void OnHostConfigChangedLocally() { if (!PhotonNetwork.InRoom) { ScoutmasterConfigSyncService.CaptureLocalBaseline(); } else if (IsGameplayEnabled && PhotonNetwork.IsMasterClient) { ScoutmasterConfigSyncService.CaptureLocalBaseline(); PublishHostConfigIfMaster(); } } private static void PublishHostConfigIfMaster() { if (photonManager != null && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && !((Object)(object)ScoutmasterRampagePlugin.Instance == (Object)null)) { string text = ScoutmasterConfigSyncService.SerializeCurrentConfig(); if (!string.IsNullOrEmpty(text)) { photonManager.SetRoomProperty("scoutmastersRampageConfigV1", (object)text); ScoutmasterRampagePlugin.Instance.LogInfo("Published host config snapshot to room."); } } } } }