Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of UsableValuables v0.2.0
UsableValuables.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using REPOLib.Modules; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace UsableValuables { internal static class Controller { private static PhysGrabObject cachedBody; private static bool cachedSupported; private static KindId cachedId; private static Component cachedComponent; private static string displayedFor; private static string displayed; private static int shownWait = -1; private static string shownWaitText; internal static void Tick() { PhysGrabber instance = PhysGrabber.instance; if ((Object)(object)instance == (Object)null || !instance.grabbed) { return; } PhysGrabObject val = Refs.Grabbed.Invoke(instance); if ((Object)(object)val == (Object)null) { return; } if ((Object)(object)val != (Object)(object)cachedBody) { cachedBody = val; cachedSupported = Kinds.TryResolve(val, out cachedId, out cachedComponent); displayedFor = null; displayed = null; shownWait = -1; } if (!cachedSupported || (Object)(object)cachedComponent == (Object)null) { return; } Kinds.Info info = Kinds.Get(cachedId); if (!info.Enabled.Value) { return; } string text = Kinds.Prompt(cachedId, cachedComponent); if (text != null) { float num = ((info.Switch || info.Trigger || info.OneShot) ? 0f : State.Remaining(cachedComponent)); if (Plugin.ShowPrompt.Value) { ShowPrompt(num, text); } PlayerController instance2 = PlayerController.instance; if (!((Object)(object)instance2 == (Object)null) && !(Refs.InputDisableTimer.Invoke(instance2) > 0f) && SemiFunc.NoTextInputsActive() && !(num > 0f) && SemiFunc.InputDown((InputKey)2)) { Net.Use(val, cachedId); } } } private static void ShowPrompt(float wait, string prompt) { string text; if (wait > 0.05f) { int num = Mathf.CeilToInt(wait); if (num != shownWait || shownWaitText == null) { shownWait = num; shownWaitText = "<color=#9a9a9a>Ready in " + num + " s</color>"; } text = shownWaitText; } else { if (displayed == null || displayedFor != prompt) { InputManager instance = InputManager.instance; displayed = (((Object)(object)instance != (Object)null) ? instance.InputDisplayReplaceTags(prompt, "<color=#fff><u><b>", "</b></u></color>") : prompt); displayedFor = prompt; } text = displayed; } if ((Object)(object)ItemInfoUI.instance != (Object)null) { ItemInfoUI.instance.ItemInfoText((ItemAttributes)null, text, false); } } } internal static class Creep { private enum Phase { Idle, Twitching, Flying } private sealed class Hand { public PhysGrabObject Body; public PhysGrabObjectImpactDetector Impact; public Phase Phase; public bool Done; public float PrimaryBlockedUntil; public float SecondaryBlockedUntil; public float Progress; public float StillFor; public float NextCheck; public bool MovingNow; public PlayerAvatar Target; public float NextAlert; public float Until; public Vector3 RestPosition; public Quaternion RestRotation; } private sealed class Playback { public PhysGrabObject Body; public AudioSource Source; public float Level; public bool Fading; } private sealed class Flight { public PhysGrabObject Body; public Vector3 LastPosition; public Vector3 PreviousPosition; public float Until; public float Radius; public int Damage; public float RagdollSeconds; public float RagdollForce; public bool Hit; } private const float Grace = 0.35f; private const float FadeIn = 0.6f; private const float FadeOut = 0.8f; private const float FlightSeconds = 2f; private const float HitRadius = 1.2f; private const float FallbackSeconds = 8f; private const float CheckEvery = 0.2f; private const float TurnStart = 15f; private const float TurnEnd = 240f; private const float TurnGain = 3f; private const float TiltSpring = 30f; private const float TiltDamping = 6f; private const float PlaceSpring = 40f; private const float PlaceDamping = 0.5f; private static ConfigEntry<bool> enabled; private static ConfigEntry<float> range; private static ConfigEntry<float> turn; private static ConfigEntry<float> frontOffset; private static ConfigEntry<float> launchSpeed; private static ConfigEntry<int> launchDamage; private static ConfigEntry<float> ragdollSeconds; private static ConfigEntry<float> ragdollForce; private static ConfigEntry<float> behaviourCooldown; private static ConfigEntry<float> volume; private static ConfigEntry<float> falloff; private static readonly Dictionary<int, Hand> hands = new Dictionary<int, Hand>(); private static readonly Dictionary<int, Playback> playbacks = new Dictionary<int, Playback>(); private static readonly List<Flight> flights = new List<Flight>(); private static float Length { get { if (!((Object)(object)UserAudio.Twitch != (Object)null)) { return 8f; } return UserAudio.Twitch.length; } } internal static void Bind(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected O, but got Unknown //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Expected O, but got Unknown //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Expected O, but got Unknown enabled = config.Bind<bool>("Handface", "TwitchEnabled", true, "When nobody holds the handface (and it is not in the cart) it turns slowly to face a player who moves near it, and makes a creeping sound; if that player keeps moving until the sound is over, it is flung at the nearest player, once. Only the host's setting is used."); range = config.Bind<float>("Handface", "TwitchRange", 5f, new ConfigDescription("Metres around the handface within which a moving player sets it off. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>())); turn = config.Bind<float>("Handface", "TwitchTurn", 1f, new ConfigDescription("How fast the handface turns to face the player while it creeps: 1 = slowly at first and quicker and quicker until the throw (from 15 to 240 degrees per second); 0 = it does not turn. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>())); frontOffset = config.Bind<float>("Handface", "FrontOffsetDegrees", 0f, new ConfigDescription("Which side of the handface is its front, the side that turns to face the player: 0 = the way the model faces, 90, 180 or 270 = a quarter, half or three quarters of a turn further round. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 360f), Array.Empty<object>())); launchSpeed = config.Bind<float>("Handface", "LaunchSpeed", 14f, new ConfigDescription("Speed, in metres per second, at which the handface is flung at the player. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 40f), Array.Empty<object>())); launchDamage = config.Bind<int>("Handface", "LaunchDamage", 20, new ConfigDescription("Damage a player takes when the flung handface hits them. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); ragdollSeconds = config.Bind<float>("Handface", "RagdollSeconds", 2f, new ConfigDescription("Seconds the player the flung handface hits stays in ragdoll (the game's tumble). 0 = no ragdoll. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); ragdollForce = config.Bind<float>("Handface", "RagdollForce", 10f, new ConfigDescription("How hard the hit shoves the player, along the way the hand was flying (an impulse: 10 is a solid knock, 0 = they just fall). Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>())); behaviourCooldown = config.Bind<float>("Handface", "BehaviourCooldownSeconds", 4f, new ConfigDescription("The rest between one of the handface's behaviours and the other: after it stops laughing it cannot start creeping, and after it stops creeping it cannot start laughing, for this many seconds. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>())); volume = config.Bind<float>("Handface", "TwitchVolume", 1f, new ConfigDescription("How loud the creeping sound is on your machine (1 = as loud as a sound can be played).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); falloff = config.Bind<float>("Handface", "TwitchFalloff", 1.5f, new ConfigDescription("How far the creeping sound carries on your machine (1 = like the game's own sounds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>())); } private static Hand GetHand(PhysGrabObject body) { int instanceID = ((Object)body).GetInstanceID(); if (!hands.TryGetValue(instanceID, out var value)) { value = new Hand { Body = body, Impact = ((Component)body).GetComponent<PhysGrabObjectImpactDetector>() }; hands[instanceID] = value; } return value; } internal static void Register(PhysGrabObject body) { GetHand(body); } internal static bool PrimaryAllowed(PhysGrabObject body, float now) { Hand hand = GetHand(body); if (!hand.Done && hand.Phase == Phase.Idle) { return now >= hand.PrimaryBlockedUntil; } return false; } internal static void PrimaryEnded(PhysGrabObject body, float now) { GetHand(body).SecondaryBlockedUntil = now + behaviourCooldown.Value; } internal static void Tick(float now) { if (hands.Count == 0) { return; } float deltaTime = Time.deltaTime; List<int> list = null; foreach (KeyValuePair<int, Hand> hand in hands) { Hand value = hand.Value; PhysGrabObject body = value.Body; if ((Object)(object)body == (Object)null || body.dead) { if (list == null) { list = new List<int>(); } list.Add(hand.Key); } else { if (value.Done && value.Phase == Phase.Idle) { continue; } bool flag = !enabled.Value || body.grabbed || ((Object)(object)value.Impact != (Object)null && value.Impact.inCart); switch (value.Phase) { case Phase.Idle: if (!flag && now >= value.SecondaryBlockedUntil && !Mischief.IsLaughing(body) && MovingNear(value, now)) { Begin(value, now); } break; case Phase.Twitching: if (flag) { Settle(value, now); break; } if (MovingNear(value, now)) { value.StillFor = 0f; value.Progress += deltaTime; } else { value.StillFor += deltaTime; } if (value.StillFor > 0.35f) { Settle(value, now); break; } if (now >= value.NextAlert) { value.NextAlert = now + 1f; Mischief.Alert(body); } if (value.Progress >= Length) { Launch(value, now); } break; case Phase.Flying: if (now >= value.Until) { value.Phase = Phase.Idle; } break; } } } if (list == null) { return; } foreach (int item in list) { hands.Remove(item); } } private static bool MovingNear(Hand hand, float now) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_00a8: 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_00b6: Unknown result type (might be due to invalid IL or missing references) if (now < hand.NextCheck) { return hand.MovingNow; } hand.NextCheck = now + 0.2f; hand.MovingNow = false; foreach (PlayerAvatar item in SemiFunc.PlayerGetAllPlayerAvatarWithinRange(range.Value, hand.Body.centerPoint, false, default(LayerMask))) { if ((Object)(object)item != (Object)null && Refs.IsMoving.Invoke(item)) { hand.MovingNow = true; break; } } hand.Target = SemiFunc.PlayerGetNearestPlayerAvatarWithinRange(range.Value * 2f, hand.Body.centerPoint, false, default(LayerMask)); return hand.MovingNow; } private static void Begin(Hand hand, float now) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogDebug((object)"A handface started creeping."); hand.Phase = Phase.Twitching; hand.Progress = 0f; hand.StillFor = 0f; hand.NextAlert = now; if ((Object)(object)hand.Body.rb != (Object)null) { hand.RestPosition = hand.Body.rb.position; hand.RestRotation = hand.Body.rb.rotation; } Net.AnnounceQuirk(hand.Body, Quirk.Handface, QuirkPhase.Twitch, range.Value); } private static void Settle(Hand hand, float now) { hand.Phase = Phase.Idle; hand.Progress = 0f; hand.StillFor = 0f; hand.PrimaryBlockedUntil = now + behaviourCooldown.Value; Net.AnnounceQuirk(hand.Body, Quirk.Handface, QuirkPhase.Settle); } private static void Launch(Hand hand, float now) { //IL_0018: 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) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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_00d8: 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) PhysGrabObject body = hand.Body; PlayerAvatar val = SemiFunc.PlayerGetNearestPlayerAvatarWithinRange(range.Value * 2f, body.centerPoint, false, default(LayerMask)); Rigidbody rb = body.rb; if ((Object)(object)val == (Object)null || (Object)(object)rb == (Object)null) { Settle(hand, now); return; } Plugin.Log.LogDebug((object)"A handface was flung at a player; it is done now."); Vector3 val2 = val.PlayerVisionTarget.VisionTransform.position + Vector3.down * 0.25f - body.centerPoint; val2 = ((((Vector3)(ref val2)).sqrMagnitude < 0.01f) ? Vector3.up : ((Vector3)(ref val2)).normalized); body.OverrideZeroGravity(0.6f); body.OverrideIndestructible(3f); rb.velocity = val2 * launchSpeed.Value; rb.angularVelocity = Random.insideUnitSphere * 12f; hand.Phase = Phase.Flying; hand.Until = now + 2f; hand.Progress = 0f; hand.Done = true; Mischief.Alert(body); Net.AnnounceQuirk(body, Quirk.Handface, QuirkPhase.Launch, 1.2f, launchDamage.Value, 0, ragdollSeconds.Value, ragdollForce.Value); } internal static void FixedTick() { if (turn.Value <= 0f) { return; } foreach (Hand value in hands.Values) { if (value.Phase == Phase.Twitching) { Turn(value); } } } private static void Turn(Hand hand) { //IL_0028: 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_004c: 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_0057: 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_0066: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_0091: 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_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: 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_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023a: 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_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0255: 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_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0294: 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_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) Rigidbody val = (((Object)(object)hand.Body != (Object)null) ? hand.Body.rb : null); if ((Object)(object)val == (Object)null) { return; } if (Vector3.Distance(val.position, hand.RestPosition) > 0.6f) { hand.RestPosition = val.position; } Quaternion val2 = TiltOf(val.rotation * Quaternion.Inverse(hand.RestRotation)); float num = default(float); Vector3 val3 = default(Vector3); ((Quaternion)(ref val2)).ToAngleAxis(ref num, ref val3); if (num > 180f) { num -= 360f; } if (Mathf.Abs(num) > 45f) { hand.RestRotation = val.rotation; num = 0f; } Vector3 val4 = val3 * (num * (MathF.PI / 180f)); float num2 = Mathf.Clamp01(hand.Progress / Length); float num3 = Mathf.Lerp(15f, 240f, num2 * num2) * turn.Value; float num4 = 0f; PlayerAvatar target = hand.Target; if ((Object)(object)target != (Object)null && (Object)(object)target.PlayerVisionTarget != (Object)null && (Object)(object)target.PlayerVisionTarget.VisionTransform != (Object)null) { Vector3 val5 = val.rotation * (Quaternion.Euler(0f, frontOffset.Value, 0f) * Vector3.forward); val5.y = 0f; Vector3 val6 = target.PlayerVisionTarget.VisionTransform.position - val.position; val6.y = 0f; if (((Vector3)(ref val5)).sqrMagnitude > 0.04f && ((Vector3)(ref val6)).sqrMagnitude > 0.04f) { num4 = Mathf.Clamp(Vector3.SignedAngle(val5, val6, Vector3.up) * 3f, 0f - num3, num3) * (MathF.PI / 180f); } } Vector3 angularVelocity = val.angularVelocity; val.AddTorque(-val4 * 30f - new Vector3(angularVelocity.x, 0f, angularVelocity.z) * 6f, (ForceMode)5); val.angularVelocity = new Vector3(angularVelocity.x, num4, angularVelocity.z); Vector3 val7 = val.position - hand.RestPosition; val7.y = 0f; val.AddForce(-val7 * 40f, (ForceMode)5); Vector3 velocity = val.velocity; val.velocity = new Vector3(velocity.x * 0.5f, velocity.y, velocity.z * 0.5f); } private static Quaternion TiltOf(Quaternion rotation) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_002f: 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_0051: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0075: 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) Vector3 val = Vector3.Project(new Vector3(rotation.x, rotation.y, rotation.z), Vector3.up); float num = Mathf.Sqrt(((Vector3)(ref val)).sqrMagnitude + rotation.w * rotation.w); if (num < 1E-05f) { return rotation; } Quaternion val2 = default(Quaternion); ((Quaternion)(ref val2))..ctor(val.x / num, val.y / num, val.z / num, rotation.w / num); return rotation * Quaternion.Inverse(val2); } internal static void ClientTwitch(PhysGrabObject body, Vector3 position, float range) { //IL_0007: 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) if (Mischief.FaceGlitch) { ScreenGlitch.PlayIfNear(position, range); } int key = (((Object)(object)body != (Object)null) ? ((Object)body).GetInstanceID() : 0); Stop(key); AudioSource val = GameAudio.PlayClip(UserAudio.Twitch, ((Object)(object)body != (Object)null) ? ((Component)body).transform : null, position, 0.001f, falloff.Value); if ((Object)(object)val != (Object)null) { playbacks[key] = new Playback { Body = body, Source = val }; } } internal static void ClientSettle(PhysGrabObject body) { if (playbacks.TryGetValue(((Object)(object)body != (Object)null) ? ((Object)body).GetInstanceID() : 0, out var value)) { value.Fading = true; } } internal static void ClientLaunch(PhysGrabObject body, Vector3 position, float radius, int damage, float ragdollSeconds, float ragdollForce) { //IL_0018: 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_0031: 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_0038: Unknown result type (might be due to invalid IL or missing references) Stop(((Object)(object)body != (Object)null) ? ((Object)body).GetInstanceID() : 0); Mischief.Laugh(body, position); flights.Add(new Flight { Body = body, LastPosition = position, PreviousPosition = position, Until = Time.time + 2f, Radius = radius, Damage = damage, RagdollSeconds = ragdollSeconds, RagdollForce = ragdollForce }); } private static void Stop(int key) { if (playbacks.TryGetValue(key, out var value)) { if ((Object)(object)value.Source != (Object)null) { value.Source.Stop(); Object.Destroy((Object)(object)((Component)value.Source).gameObject); } playbacks.Remove(key); } } internal static void ClientTick() { //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) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) float deltaTime = Time.deltaTime; if (playbacks.Count > 0) { List<int> list = null; foreach (KeyValuePair<int, Playback> playback in playbacks) { Playback value = playback.Value; if ((Object)(object)value.Source == (Object)null) { if (list == null) { list = new List<int>(); } list.Add(playback.Key); continue; } if ((Object)(object)value.Body == (Object)null) { value.Fading = true; } value.Level = Mathf.MoveTowards(value.Level, value.Fading ? 0f : 1f, deltaTime / (value.Fading ? 0.8f : 0.6f)); GameAudio.SetVolume(value.Source, value.Level * volume.Value); if (value.Fading && value.Level <= 0.001f) { if (list == null) { list = new List<int>(); } list.Add(playback.Key); } } if (list != null) { foreach (int item in list) { Stop(item); } } } if (flights.Count <= 0) { return; } for (int num = flights.Count - 1; num >= 0; num--) { Flight flight = flights[num]; if (flight.Hit || Time.time >= flight.Until) { flights.RemoveAt(num); } else { flight.PreviousPosition = flight.LastPosition; if ((Object)(object)flight.Body != (Object)null) { flight.LastPosition = flight.Body.centerPoint; } CheckHit(flight); } } } private static void CheckHit(Flight flight) { //IL_004f: 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_0055: 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_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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) PlayerController instance = PlayerController.instance; PlayerAvatar val = (((Object)(object)instance == (Object)null) ? null : instance.playerAvatarScript); if (!((Object)(object)val == (Object)null) && !((Object)(object)val.PlayerVisionTarget == (Object)null) && !((Object)(object)val.PlayerVisionTarget.VisionTransform == (Object)null)) { Vector3 position = val.PlayerVisionTarget.VisionTransform.position; Vector3 val2 = (position + ((Component)instance).transform.position) * 0.5f; if (Mathf.Min(Vector3.Distance(flight.LastPosition, position), Vector3.Distance(flight.LastPosition, val2)) <= flight.Radius) { flight.Hit = true; val.playerHealth.Hurt(flight.Damage, true, -1, false); KnockDown(val, flight, position); } } } private static void KnockDown(PlayerAvatar player, Flight flight, Vector3 eyes) { //IL_003a: 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_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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0059: 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_0060: 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_00ac: 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 (flight.RagdollSeconds <= 0f || Refs.Health.Invoke(player.playerHealth) <= 0) { return; } PlayerTumble val = Refs.Tumble.Invoke(player); if (!((Object)(object)val == (Object)null)) { Vector3 val2 = flight.LastPosition - flight.PreviousPosition; if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f) { val2 = eyes - flight.LastPosition; } Vector3 val3 = ((Vector3)(ref val2)).normalized + Vector3.up * 0.3f; val2 = ((Vector3)(ref val3)).normalized; val.TumbleRequest(true, false); val.TumbleOverrideTime(flight.RagdollSeconds); if (flight.RagdollForce > 0f) { val.TumbleForce(val2 * flight.RagdollForce); } } } } internal static class Explosions { private static readonly string[] Donors = new string[3] { "arctic barrel", "propane", "clown" }; private static ExplosionPreset preset; private static float retryAt; internal static bool Ready() { if ((Object)(object)preset != (Object)null) { return true; } if (Time.time < retryAt) { return false; } retryAt = Time.time + 30f; try { preset = FromDonor(); if ((Object)(object)preset == (Object)null) { ExplosionPreset[] array = Resources.FindObjectsOfTypeAll<ExplosionPreset>(); foreach (ExplosionPreset val in array) { if ((Object)(object)val != (Object)null) { preset = val; break; } } } } catch (Exception ex) { Plugin.Log.LogError((object)("Looking for the game's explosion failed: " + ex)); } if ((Object)(object)preset == (Object)null) { Plugin.Log.LogWarning((object)"The game's explosion effect was not found; the banana bow will not blow up."); } return (Object)(object)preset != (Object)null; } internal static void Spawn(PhysGrabObject source, Vector3 position, float size, int damage, int enemyDamage) { //IL_000d: 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) //IL_0018: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown if (Ready()) { GameObject val = new GameObject("UsableValuables explosion"); val.transform.position = position; ParticleScriptExplosion val2 = val.AddComponent<ParticleScriptExplosion>(); val2.explosionPreset = preset; Refs.ExplosionPrefab.Invoke(val2) = Resources.Load<GameObject>("Effects/Part Prefab Explosion"); if ((Object)(object)source != (Object)null) { Refs.ExplosionCauser.Invoke(val2) = Refs.LastGrabber.Invoke(source); } val2.Spawn(position, size, damage, enemyDamage, 1f, false, false, 1f); Object.Destroy((Object)val, 3f); } } private static ExplosionPreset FromDonor() { RunManager instance = RunManager.instance; if ((Object)(object)instance == (Object)null || instance.levels == null) { return null; } List<string> list = new List<string>(); foreach (Level level in instance.levels) { if ((Object)(object)level == (Object)null || level.ValuablePresets == null) { continue; } foreach (LevelValuables valuablePreset in level.ValuablePresets) { if ((Object)(object)valuablePreset == (Object)null) { continue; } List<PrefabRef>[] array = new List<PrefabRef>[7] { valuablePreset.tiny, valuablePreset.small, valuablePreset.medium, valuablePreset.big, valuablePreset.wide, valuablePreset.tall, valuablePreset.veryTall }; foreach (List<PrefabRef> list2 in array) { if (list2 == null) { continue; } foreach (PrefabRef item in list2) { if (item != null && ((PrefabRef<GameObject>)(object)item).IsValid() && (Object)(object)((PrefabRef<GameObject>)(object)item).Bundle == (Object)null && !list.Contains(((PrefabRef<GameObject>)(object)item).ResourcePath)) { list.Add(((PrefabRef<GameObject>)(object)item).ResourcePath); } } } } } string[] donors = Donors; foreach (string value in donors) { foreach (string item2 in list) { if (item2.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { GameObject val = Resources.Load<GameObject>(item2); ParticleScriptExplosion val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponentInChildren<ParticleScriptExplosion>(true)); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.explosionPreset != (Object)null) { return val2.explosionPreset; } } } } return null; } } internal static class GameAudio { internal sealed class Fuse { private readonly Transform follow; private readonly Vector3 position; private AudioSource loop; private bool stopped; internal Fuse(Transform follow, Vector3 position) { //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_001a: Unknown result type (might be due to invalid IL or missing references) this.follow = follow; this.position = position; Play(fuseIgnite, follow, position, 1f, 1f); } internal void Tick() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!stopped && fuseLoop != null && ((Object)(object)loop == (Object)null || !loop.isPlaying)) { loop = Play(fuseLoop, follow, position, 1f, 1f); } } internal void Stop() { stopped = true; if ((Object)(object)loop != (Object)null) { loop.Stop(); } } } private const string BangPrefab = "Enemies/Enemy - Bang"; private const string FuseIgniteClips = "enemy bang fuse ignite"; private const string FuseLoopClip = "enemy bang fuse loop"; private static Sound fuseIgnite; private static Sound fuseLoop; private static float retryAt; private static readonly Dictionary<AudioClip, Sound> wrappers = new Dictionary<AudioClip, Sound>(); internal static AudioSource PlayClip(AudioClip clip, Transform follow, Vector3 position, float volume, float falloff) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)clip == (Object)null) { return null; } if (!wrappers.TryGetValue(clip, out var value) || value == null) { Sound val = new Sound(); val.Sounds = (AudioClip[])(object)new AudioClip[1] { clip }; val.Volume = 1f; val.VolumeRandom = 0f; val.Pitch = 1f; val.PitchRandom = 0f; val.SpatialBlend = 1f; value = val; wrappers[clip] = value; } return Play(value, follow, position, volume, falloff); } internal static void SetVolume(AudioSource source, float volume) { if (!((Object)(object)source == (Object)null)) { AudioLowPassLogic component = ((Component)source).GetComponent<AudioLowPassLogic>(); if ((Object)(object)component != (Object)null) { Refs.LowPassVolume.Invoke(component) = volume; } source.volume = volume; } } private static AudioSource Play(Sound sound, Transform follow, Vector3 position, float volume, float falloff) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (sound == null) { return null; } if (!((Object)(object)follow != (Object)null)) { return sound.Play(position, volume, falloff, 1f, 1f); } return sound.Play(follow, volume, falloff, 1f, 1f); } internal static Fuse StartFuse(Transform follow, Vector3 position) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) EnsureFuse(); if (fuseIgnite == null && fuseLoop == null) { return null; } return new Fuse(follow, position); } private static void EnsureFuse() { if ((fuseIgnite != null && fuseLoop != null) || Time.time < retryAt) { return; } retryAt = Time.time + 30f; try { GameObject val = Resources.Load<GameObject>("Enemies/Enemy - Bang"); if ((Object)(object)val != (Object)null) { if (fuseIgnite == null) { fuseIgnite = Copy(FindSound(val, (string name) => name.StartsWith("enemy bang fuse ignite", StringComparison.OrdinalIgnoreCase))); } if (fuseLoop == null) { fuseLoop = Copy(FindSound(val, (string name) => string.Equals(name, "enemy bang fuse loop", StringComparison.OrdinalIgnoreCase))); } } if (fuseIgnite == null || fuseLoop == null) { Plugin.Log.LogWarning((object)("The game's bomb-fuse sound was not fully found (ignite: " + (fuseIgnite != null) + ", loop: " + (fuseLoop != null) + "); the banana bow's wind-up will be quieter or silent.")); } } catch (Exception ex) { Plugin.Log.LogError((object)("Looking for the game's fuse sound failed: " + ex)); } } private static Sound FindSound(GameObject prefab, Func<string, bool> matches) { MonoBehaviour[] componentsInChildren = prefab.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } FieldInfo[] fields = ((object)val).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType != typeof(Sound)) { continue; } object? value = fieldInfo.GetValue(val); Sound val2 = (Sound)((value is Sound) ? value : null); if (val2 == null || val2.Sounds == null) { continue; } AudioClip[] sounds = val2.Sounds; foreach (AudioClip val3 in sounds) { if ((Object)(object)val3 != (Object)null && matches(((Object)val3).name)) { return val2; } } } } return null; } private static Sound Copy(Sound source) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_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_0022: 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_003a: 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_0052: 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_006a: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown if (source == null) { return null; } return new Sound { Sounds = source.Sounds, Type = source.Type, Volume = source.Volume, VolumeRandom = source.VolumeRandom, Pitch = source.Pitch, PitchRandom = source.PitchRandom, SpatialBlend = source.SpatialBlend, Doppler = source.Doppler, ReverbMix = source.ReverbMix, FalloffMultiplier = source.FalloffMultiplier, OffscreenVolume = source.OffscreenVolume, OffscreenFalloff = source.OffscreenFalloff }; } } internal static class Haunts { private sealed class HorseState { public PhysGrabObject Body; public bool WasGrabbed; public bool Played; } private sealed class PianoState { public PhysGrabObject Body; public PhysGrabObjectGrabArea Keys; public bool Playing; public float ReleasedAt = -1f; } private sealed class Song { public PhysGrabObject Body; public AudioSource Source; public float Level = 1f; public bool Fading; } private const float PianoFadeOut = 0.6f; private static ConfigEntry<bool> horseEnabled; private static ConfigEntry<float> horseVolume; private static ConfigEntry<float> horseFalloff; private static ConfigEntry<bool> horseGlitch; private static ConfigEntry<bool> pianoEnabled; private static ConfigEntry<float> pianoChance; private static ConfigEntry<float> pianoStopAfterDrop; private static ConfigEntry<float> pianoVolume; private static ConfigEntry<float> pianoFalloff; private static ConfigEntry<bool> pianoGlitch; private static readonly Dictionary<int, HorseState> horses = new Dictionary<int, HorseState>(); private static readonly Dictionary<int, PianoState> pianos = new Dictionary<int, PianoState>(); private static readonly Dictionary<int, Song> songs = new Dictionary<int, Song>(); private static bool songWarningLogged; internal static bool HorseGlitch => horseGlitch.Value; internal static bool PianoGlitch => pianoGlitch.Value; internal static void Bind(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Expected O, but got Unknown horseEnabled = config.Bind<bool>("Horse", "Enabled", true, "The horse valuable does nothing in the game. With this on, it whinnies the first time somebody picks it up, and never again. Only the host's setting is used."); horseVolume = config.Bind<float>("Horse", "Volume", 1f, new ConfigDescription("How loud the whinny is on your machine (1 = as loud as a sound can be played).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); horseFalloff = config.Bind<float>("Horse", "Falloff", 1.5f, new ConfigDescription("How far the whinny carries on your machine (1 = like the game's own sounds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>())); horseGlitch = config.Bind<bool>("Horse", "ScreenGlitch", true, "Whoever picks the horse up gets the screen glitch the game shows when a trap goes off (the one you get when the TV turns on). On your machine only."); pianoEnabled = config.Bind<bool>("Piano", "Enabled", true, "The piano valuable plays notes when you grab its keys, and nothing else. With this on, while somebody holds it by anything but the keys there is a chance each second that it starts playing a song by itself. Only the host's setting is used."); pianoChance = config.Bind<float>("Piano", "StartChancePerSecond", 10f, new ConfigDescription("Chance, in percent, that a piano held by anything but its keys starts playing its song, each second. 0 = never. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); pianoStopAfterDrop = config.Bind<float>("Piano", "StopSecondsAfterDrop", 2f, new ConfigDescription("The song plays for as long as somebody holds the piano (by the keys or not) and stops this many seconds after it was let go of. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>())); pianoVolume = config.Bind<float>("Piano", "Volume", 0.8f, new ConfigDescription("How loud the song is on your machine (1 = as loud as a sound can be played).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); pianoFalloff = config.Bind<float>("Piano", "Falloff", 1.5f, new ConfigDescription("How far the song carries on your machine (1 = like the game's own sounds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>())); pianoGlitch = config.Bind<bool>("Piano", "ScreenGlitch", true, "Whoever holds the piano when the song starts gets the screen glitch the game shows when a trap goes off. On your machine only."); } internal static void RegisterHorse(PhysGrabObject body) { int instanceID = ((Object)body).GetInstanceID(); if (!horses.ContainsKey(instanceID)) { horses[instanceID] = new HorseState { Body = body, WasGrabbed = body.grabbed }; } } internal static void RegisterPiano(PhysGrabObject body) { int instanceID = ((Object)body).GetInstanceID(); if (!pianos.ContainsKey(instanceID)) { pianos[instanceID] = new PianoState { Body = body, Keys = ((Component)body).GetComponentInChildren<PhysGrabObjectGrabArea>(true) }; } } internal static void RollPiano(PhysGrabObject body) { if (!pianoEnabled.Value || !pianos.TryGetValue(((Object)body).GetInstanceID(), out var value) || value.Playing || !HeldOutsideKeys(value) || !Mischief.Chance(pianoChance.Value)) { return; } if ((Object)(object)UserAudio.PianoSong == (Object)null) { if (!songWarningLogged) { songWarningLogged = true; Plugin.Log.LogWarning((object)"The piano has no song to play (no file with \"lassan\" in its name in the audio folder)."); } } else { Plugin.Log.LogDebug((object)"A piano started playing its song."); value.Playing = true; value.ReleasedAt = -1f; Net.AnnounceQuirk(body, Quirk.Piano, QuirkPhase.Start); } } private static bool HeldOutsideKeys(PianoState piano) { foreach (PhysGrabber item in piano.Body.playerGrabbing) { if (!((Object)(object)item == (Object)null) && ((Object)(object)piano.Keys == (Object)null || !piano.Keys.listOfAllGrabbers.Contains(item))) { return true; } } return false; } internal static void Tick(float now) { if (horses.Count > 0) { List<int> list = null; foreach (KeyValuePair<int, HorseState> horse in horses) { HorseState value = horse.Value; if ((Object)(object)value.Body == (Object)null || value.Body.dead) { if (list == null) { list = new List<int>(); } list.Add(horse.Key); continue; } bool grabbed = value.Body.grabbed; if (grabbed && !value.WasGrabbed && !value.Played && horseEnabled.Value) { value.Played = true; Net.AnnounceQuirk(value.Body, Quirk.Horse, QuirkPhase.Start); } value.WasGrabbed = grabbed; } Remove(horses, list); } if (pianos.Count <= 0) { return; } List<int> list2 = null; foreach (KeyValuePair<int, PianoState> piano in pianos) { PianoState value2 = piano.Value; if ((Object)(object)value2.Body == (Object)null || value2.Body.dead) { if (list2 == null) { list2 = new List<int>(); } list2.Add(piano.Key); } else if (value2.Playing) { if (value2.Body.grabbed) { value2.ReleasedAt = -1f; } else if (value2.ReleasedAt < 0f) { value2.ReleasedAt = now; } else if (now - value2.ReleasedAt >= pianoStopAfterDrop.Value) { value2.Playing = false; Net.AnnounceQuirk(value2.Body, Quirk.Piano, QuirkPhase.Settle); } } } Remove(pianos, list2); } private static void Remove<T>(Dictionary<int, T> dictionary, List<int> keys) { if (keys == null) { return; } foreach (int key in keys) { dictionary.Remove(key); } } internal static void ClientHorse(PhysGrabObject body, Vector3 position) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) GameAudio.PlayClip(UserAudio.Horse, ((Object)(object)body != (Object)null) ? ((Component)body).transform : null, position, horseVolume.Value, horseFalloff.Value); if (horseGlitch.Value) { ScreenGlitch.PlayIfHeldHere(body); } } internal static void ClientPianoStart(PhysGrabObject body, Vector3 position) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) int key = (((Object)(object)body != (Object)null) ? ((Object)body).GetInstanceID() : 0); Stop(key); AudioSource val = GameAudio.PlayClip(UserAudio.PianoSong, ((Object)(object)body != (Object)null) ? ((Component)body).transform : null, position, pianoVolume.Value, pianoFalloff.Value); if ((Object)(object)val != (Object)null) { songs[key] = new Song { Body = body, Source = val }; } if (pianoGlitch.Value) { ScreenGlitch.PlayIfHeldHere(body); } } internal static void ClientPianoStop(PhysGrabObject body) { if (songs.TryGetValue(((Object)(object)body != (Object)null) ? ((Object)body).GetInstanceID() : 0, out var value)) { value.Fading = true; } } private static void Stop(int key) { if (songs.TryGetValue(key, out var value)) { if ((Object)(object)value.Source != (Object)null) { value.Source.Stop(); Object.Destroy((Object)(object)((Component)value.Source).gameObject); } songs.Remove(key); } } internal static void ClientTick() { if (songs.Count == 0) { return; } float deltaTime = Time.deltaTime; List<int> list = null; foreach (KeyValuePair<int, Song> song in songs) { Song value = song.Value; if ((Object)(object)value.Source == (Object)null) { if (list == null) { list = new List<int>(); } list.Add(song.Key); continue; } if ((Object)(object)value.Body == (Object)null) { value.Fading = true; } if (!value.Fading) { continue; } value.Level = Mathf.MoveTowards(value.Level, 0f, deltaTime / 0.6f); GameAudio.SetVolume(value.Source, value.Level * pianoVolume.Value); if (value.Level <= 0.001f) { if (list == null) { list = new List<int>(); } list.Add(song.Key); } } if (list == null) { return; } foreach (int item in list) { Stop(item); } } } internal enum KindId : byte { Flashlight = 1, Boombox, Candle, StarWand, WizardStaff, Camera, LevitationPotion, IceSaw, Blender, Jackhammer, ScreamDoll, Flamethrower, FireExtinguisher, Fan, Radio, Gramophone, Television, ToyMonkey, GrandfatherClock } internal static class Kinds { internal sealed class Info { public KindId Id; public string Name; public bool Switch; public bool Trigger; public bool OneShot; public string PromptOn; public string PromptOff; public string PromptEmpty; public ConfigEntry<bool> Enabled; public ConfigEntry<float> Cooldown; public ConfigEntry<float> Reactivate; public ConfigEntry<float> SelfStart; } internal const float SwitchDelay = 0.3f; private const float DefaultChance = 30f; private static readonly Dictionary<KindId, Info> all = new Dictionary<KindId, Info>(); internal static Info Get(KindId id) { return all[id]; } internal static void Bind(ConfigFile config) { AddSwitch(config, KindId.Flashlight, "Flashlight", "Press [interact] to turn off", "Press [interact] to turn on", "The flashlight valuable lights up while you hold it; the key switches it off and on."); AddSwitch(config, KindId.Boombox, "Boombox", "Press [interact] to mute", "Press [interact] to play", "The boombox valuable plays music (and makes you dance) while you hold it; the key mutes it and starts it again.", 30f); AddSwitch(config, KindId.Candle, "Candle", "Press [interact] to blow out the candle", "Press [interact] to light the candle", "The key blows the candle's flame out and lights it again."); AddSwitch(config, KindId.IceSaw, "IceSaw", "Press [interact] to switch the saw off", "Press [interact] to switch the saw on", "The ice saw spins up as soon as you grab it; the key switches it off and on.", 30f); AddSwitch(config, KindId.Blender, "Blender", "Press [interact] to switch the blender off", "Press [interact] to switch the blender on", "The blender starts as soon as you grab it; the key switches it off and on.", 30f); AddSwitch(config, KindId.Jackhammer, "Jackhammer", "Press [interact] to switch the jackhammer off", "Press [interact] to switch the jackhammer on", "The jackhammer starts as soon as you grab it; the key switches it off and on.", 30f); AddSwitch(config, KindId.ScreamDoll, "ScreamDoll", "Press [interact] to silence the doll", "Press [interact] to wake the doll", "The scream doll starts as soon as you grab it; the key silences it and wakes it again.", 30f); AddSwitch(config, KindId.Fan, "Fan", "Press [interact] to switch the fan off", "Press [interact] to switch the fan on", "The arctic fan spins up as soon as you grab it; the key switches it off and on.", 30f); AddOneShot(config, KindId.Radio, "Radio", "Press [interact] to turn the radio on", "The radio valuable is one of the game's traps: it blares and draws enemies, once. The key turns it on at once.", 30f); AddOneShot(config, KindId.Gramophone, "Gramophone", "Press [interact] to start the gramophone", "The gramophone valuable is one of the game's traps: it plays its record and draws enemies, once. The key starts it at once.", 30f); AddOneShot(config, KindId.Television, "Television", "Press [interact] to turn the TV on", "The television valuable is one of the game's traps: it switches on and draws enemies, once. The key switches it on at once.", 30f); AddOneShot(config, KindId.ToyMonkey, "ToyMonkey", "Press [interact] to wind up the monkey", "The toy monkey valuable is one of the game's traps: it bangs its cymbals, hops around and draws enemies, once. The key winds it up at once.", 30f); AddOneShot(config, KindId.GrandfatherClock, "GrandfatherClock", "Press [interact] to ring the clock", "The grandfather clock valuable is one of the game's traps: its bell rings, the screen shakes and enemies come, once. The key rings it at once.", 30f); AddTrigger(config, KindId.Flamethrower, "Flamethrower", "Press [interact] to fire", "Press [interact] to stop", "Out of fuel", "The flamethrower valuable is fired by its trigger and burns fuel until it is empty; the key starts and stops the flames (they also stop if you let go of it)."); AddTrigger(config, KindId.FireExtinguisher, "FireExtinguisher", "Press [interact] to spray", "Press [interact] to stop", "Empty", "The fire extinguisher valuable is fired by its trigger and runs out of fuel; the key starts and stops the spray (it also stops if you let go of it)."); AddAction(config, KindId.StarWand, "StarWand", "Press [interact] to cast a spell", 1.5f, "The key casts the wand's spell, as if you had swung it. Like a swing, every cast costs the wand part of its value."); AddAction(config, KindId.WizardStaff, "WizardStaff", "Press [interact] to fire the staff", 3f, "The key fires the staff's laser."); AddAction(config, KindId.Camera, "Camera", "Press [interact] to use the flash", 6f, "The key sets off the camera's flash (the stunning burst it makes when it takes damage)."); AddAction(config, KindId.LevitationPotion, "LevitationPotion", "Press [interact] to use the potion", 30f, "The key releases the potion's levitation sphere, as if it had been smashed (the potion stays intact)."); } private static Info AddSwitch(ConfigFile config, KindId id, string section, string promptOn, string promptOff, string description, float reactivatePercent = -1f) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown Info info = new Info { Id = id, Name = section, Switch = true, PromptOn = promptOn, PromptOff = promptOff }; info.Enabled = config.Bind<bool>(section, "Enabled", true, description + " Only the host's setting is used."); if (reactivatePercent >= 0f) { info.Reactivate = config.Bind<float>(section, "ReactivateChancePerSecond", reactivatePercent, new ConfigDescription("Chance, in percent, that this valuable switches itself back on each second you keep holding it while it is switched off, the way the game's traps go off by themselves. 0 = never. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); } all[id] = info; return info; } private static Info AddOneShot(ConfigFile config, KindId id, string section, string prompt, string description, float selfStartPercent) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown Info info = new Info { Id = id, Name = section, OneShot = true, PromptOn = prompt, PromptOff = prompt }; info.Enabled = config.Bind<bool>(section, "Enabled", true, description + " Only the host's setting is used."); info.SelfStart = config.Bind<float>(section, "SelfStartChancePerSecond", selfStartPercent, new ConfigDescription("Chance, in percent, that this valuable goes off by itself each second you hold it, until it has gone off (it only goes off once, as in the game). 0 = only with the key, or when the game's own random trigger fires. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); all[id] = info; return info; } private static Info AddTrigger(ConfigFile config, KindId id, string section, string promptStart, string promptStop, string promptEmpty, string description) { Info info = new Info { Id = id, Name = section, Trigger = true, PromptOn = promptStart, PromptOff = promptStop, PromptEmpty = promptEmpty }; info.Enabled = config.Bind<bool>(section, "Enabled", true, description + " Only the host's setting is used."); all[id] = info; return info; } private static Info AddAction(ConfigFile config, KindId id, string section, string prompt, float cooldown, string description) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown Info info = new Info { Id = id, Name = section, Switch = false, PromptOn = prompt, PromptOff = prompt }; info.Enabled = config.Bind<bool>(section, "Enabled", true, description + " Only the host's setting is used."); info.Cooldown = config.Bind<float>(section, "CooldownSeconds", cooldown, new ConfigDescription("Seconds before the same valuable can be used again. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 600f), Array.Empty<object>())); all[id] = info; return info; } internal static bool TryResolve(PhysGrabObject body, out KindId id, out Component component) { id = (KindId)0; component = null; if ((Object)(object)body == (Object)null) { return false; } GameObject gameObject = ((Component)body).gameObject; if (!Match<ValuableFlashlight>(gameObject, KindId.Flashlight, ref id, ref component) && !Match<ValuableBoombox>(gameObject, KindId.Boombox, ref id, ref component) && !Match<ValuableForeverCandle>(gameObject, KindId.Candle, ref id, ref component) && !Match<IceSawValuable>(gameObject, KindId.IceSaw, ref id, ref component) && !Match<BlenderValuable>(gameObject, KindId.Blender, ref id, ref component) && !Match<JackhammerValuable>(gameObject, KindId.Jackhammer, ref id, ref component) && !Match<ScreamDollValuable>(gameObject, KindId.ScreamDoll, ref id, ref component) && !Match<FanTrap>(gameObject, KindId.Fan, ref id, ref component) && !Match<FlamethrowerValuable>(gameObject, KindId.Flamethrower, ref id, ref component) && !Match<FireExtinguisherValuable>(gameObject, KindId.FireExtinguisher, ref id, ref component) && !Match<ValuableStarWand>(gameObject, KindId.StarWand, ref id, ref component) && !Match<ValuableWizardStaff>(gameObject, KindId.WizardStaff, ref id, ref component) && !Match<ValuableCamera>(gameObject, KindId.Camera, ref id, ref component) && !Match<ValuableLevitationPotion>(gameObject, KindId.LevitationPotion, ref id, ref component) && !Match<TrapRadio>(gameObject, KindId.Radio, ref id, ref component) && !Match<TrapGramophone>(gameObject, KindId.Gramophone, ref id, ref component) && !Match<TrapTV>(gameObject, KindId.Television, ref id, ref component) && !Match<ToyMonkeyTrap>(gameObject, KindId.ToyMonkey, ref id, ref component)) { return Match<GrandfatherClockTrap>(gameObject, KindId.GrandfatherClock, ref id, ref component); } return true; } private static bool Match<T>(GameObject go, KindId kind, ref KindId id, ref Component component) where T : Component { T componentInChildren = go.GetComponentInChildren<T>(true); if ((Object)(object)componentInChildren == (Object)null) { return false; } id = kind; component = (Component)(object)componentInChildren; return true; } internal static string Prompt(KindId id, Component component) { Info info = all[id]; if (info.OneShot) { if (!TrapSpent(component)) { return info.PromptOn; } return null; } if (info.Trigger) { if (TriggerEmpty(component)) { return info.PromptEmpty; } if (!TriggerFiring(component)) { return info.PromptOn; } return info.PromptOff; } if (!info.Switch || !State.IsOff(component)) { return info.PromptOn; } return info.PromptOff; } internal static bool TrapSpent(Component component) { Trap val = (Trap)(object)((component is Trap) ? component : null); if (!((Object)(object)val == (Object)null) && !val.trapTriggered) { return val.trapStart; } return true; } internal static bool TriggerFiring(Component component) { FlamethrowerValuable val = (FlamethrowerValuable)(object)((component is FlamethrowerValuable) ? component : null); if ((Object)(object)val != (Object)null) { return Refs.FlamethrowerFiring.Invoke(val); } FireExtinguisherValuable val2 = (FireExtinguisherValuable)(object)((component is FireExtinguisherValuable) ? component : null); if ((Object)(object)val2 != (Object)null) { return Refs.ExtinguisherFiring.Invoke(val2); } return false; } private static bool TriggerEmpty(Component component) { FlamethrowerValuable val = (FlamethrowerValuable)(object)((component is FlamethrowerValuable) ? component : null); if ((Object)(object)val != (Object)null) { return (int)Refs.FlamethrowerState.Invoke(val) == 1; } FireExtinguisherValuable val2 = (FireExtinguisherValuable)(object)((component is FireExtinguisherValuable) ? component : null); if ((Object)(object)val2 != (Object)null) { return (int)Refs.ExtinguisherState.Invoke(val2) == 1; } return false; } internal static void Apply(KindId id, Component component, bool off) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown //IL_00f0: 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_010a: 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_009b: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown try { switch (id) { case KindId.Flashlight: case KindId.Boombox: case KindId.IceSaw: case KindId.Blender: case KindId.Jackhammer: case KindId.ScreamDoll: case KindId.Fan: State.SetOff(component, off, id); break; case KindId.Candle: State.SetOff(component, off, id); SetCandle((ValuableForeverCandle)component, !off); break; case KindId.Radio: case KindId.Gramophone: case KindId.Television: case KindId.ToyMonkey: case KindId.GrandfatherClock: Refs.TrapActivateSync.Invoke(component, null); break; case KindId.Flamethrower: { FlamethrowerValuable val2 = (FlamethrowerValuable)component; if (off) { val2.ReleaseTrigger(); State.Unwatch(component); } else { val2.GrabTrigger(); State.Watch(component, id); } break; } case KindId.FireExtinguisher: { FireExtinguisherValuable val = (FireExtinguisherValuable)component; if (off) { val.ReleaseTrigger(); State.Unwatch(component); } else { val.GrabTrigger(); State.Watch(component, id); } break; } case KindId.StarWand: CastWand((ValuableStarWand)component); break; case KindId.WizardStaff: ((ValuableWizardStaff)component).StaffLaser(); break; case KindId.Camera: ((ValuableCamera)component).Explosion(); break; case KindId.LevitationPotion: ((ValuableLevitationPotion)component).ActivateSphere(); break; } Info info = all[id]; Plugin.Log.LogDebug((object)("Used " + id.ToString() + ((!info.Switch) ? ((!info.Trigger) ? "" : (off ? " (stopped)" : " (started)")) : (off ? " (now off)" : " (now on)")))); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not use " + id.ToString() + ": " + ex)); } } private static void CastWand(ValuableStarWand wand) { Refs.WandCastSpell.Invoke(wand, new object[1] { true }); Refs.WandShootTimer.Invoke(wand) = 0f; Refs.WandReadyToShoot.Invoke(wand) = false; Refs.WandCanShoot.Invoke(wand) = false; } private static void SetCandle(ValuableForeverCandle candle, bool lit) { //IL_013f: Unknown result type (might be due to invalid IL or missing references) PhysGrabObject componentInParent = ((Component)candle).GetComponentInParent<PhysGrabObject>(); CandleFlame[] componentsInChildren = ((Component)(((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).transform : ((Component)candle).transform)).GetComponentsInChildren<CandleFlame>(true); foreach (CandleFlame val in componentsInChildren) { PropLight propLight = val.propLight; if ((Object)(object)propLight != (Object)null) { Light val2 = Refs.LightComponent.Invoke(propLight); float intensity; if (!lit) { State.RememberCandleIntensity(propLight, Refs.OriginalIntensity.Invoke(propLight)); Refs.OriginalIntensity.Invoke(propLight) = 0f; if ((Object)(object)val2 != (Object)null) { val2.intensity = 0f; } } else if (State.TryTakeCandleIntensity(propLight, out intensity)) { Refs.OriginalIntensity.Invoke(propLight) = intensity; if ((Object)(object)val2 != (Object)null) { val2.intensity = intensity; } } } if ((Object)(object)((Component)val).gameObject != (Object)(object)((Component)candle).gameObject && ((Object)(object)componentInParent == (Object)null || (Object)(object)((Component)val).gameObject != (Object)(object)((Component)componentInParent).gameObject)) { ((Component)val).gameObject.SetActive(lit); } } AssetManager instance = AssetManager.instance; Sound val3 = (((Object)(object)instance == (Object)null) ? null : (lit ? instance.soundDeviceTurnOn : instance.soundDeviceTurnOff)); if (val3 != null) { val3.Play(((Component)candle).transform.position, 1f, 1f, 1f, 1f); } } } internal enum Quirk : byte { None, BananaBow, Handface, Horse, Piano } internal enum QuirkPhase : byte { Start = 1, Boom, Twitch, Settle, Launch, Warn } internal static class Mischief { private sealed class Fuse { public PhysGrabObject Body; public float WarnAt; public bool Warned; public float BoomAt; public bool Announced; public float DestroyAt; } private sealed class Laughing { public PhysGrabObject Body; public PhysGrabObjectImpactDetector Impact; public float ReleasedAt = -1f; public float NextAlert; } private sealed class Burning { public PhysGrabObject Body; public GameAudio.Fuse Sound; public float StartedAt; } private sealed class Spasm { public float NextAt; public float Until; } private const float ShakeTorque = 4f; private const float ShakeForce = 8f; private const float SpasmBoost = 2.5f; private static ConfigEntry<bool> bananaEnabled; private static ConfigEntry<float> bananaChance; private static ConfigEntry<float> bananaWindup; private static ConfigEntry<float> bananaSize; private static ConfigEntry<int> bananaDamage; private static ConfigEntry<int> bananaEnemyDamage; private static ConfigEntry<float> bananaWarnVolume; private static ConfigEntry<float> bananaWarnFalloff; private static ConfigEntry<bool> bananaGlitch; private static ConfigEntry<bool> faceEnabled; private static ConfigEntry<bool> faceGlitch; private static ConfigEntry<float> faceChance; private static ConfigEntry<float> faceStopAfterDrop; private static ConfigEntry<float> faceShake; private static ConfigEntry<float> faceAlertRange; private static ConfigEntry<float> faceLaughVolume; private static ConfigEntry<float> faceLaughFalloff; private static readonly Dictionary<int, Fuse> fuses = new Dictionary<int, Fuse>(); private static readonly Dictionary<int, Laughing> laughing = new Dictionary<int, Laughing>(); private static readonly Dictionary<int, Burning> burning = new Dictionary<int, Burning>(); private static readonly Dictionary<int, Quirk> resolved = new Dictionary<int, Quirk>(); private static readonly Dictionary<int, Spasm> spasms = new Dictionary<int, Spasm>(); private static readonly HashSet<int> shaken = new HashSet<int>(); private static float nextRoll; internal static float AlertRange => faceAlertRange.Value; internal static bool FaceGlitch => faceGlitch.Value; private static float WarningSeconds { get { if (!((Object)(object)UserAudio.Warning != (Object)null)) { return 0.8f; } return UserAudio.Warning.length; } } internal static void Bind(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Expected O, but got Unknown //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Expected O, but got Unknown //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Expected O, but got Unknown //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Expected O, but got Unknown //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Expected O, but got Unknown //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Expected O, but got Unknown bananaEnabled = config.Bind<bool>("BananaBow", "Enabled", true, "The banana bow valuable does nothing in the game. With this on, each second somebody holds it there is a small chance a bomb fuse starts burning and it blows up a moment later, and is gone. Only the host's setting is used."); bananaChance = config.Bind<float>("BananaBow", "ExplodeChancePerSecond", 3f, new ConfigDescription("Chance, in percent, that a held banana bow lights its fuse, each second. 0 = never. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); bananaWindup = config.Bind<float>("BananaBow", "WindupSeconds", 2f, new ConfigDescription("Seconds the bomb fuse burns before the \"uh-oh\" warning; the explosion follows as the warning ends (so it goes off this many seconds plus about one after the fuse is lit), whether the banana bow is held or not. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>())); bananaSize = config.Bind<float>("BananaBow", "ExplosionSize", 1f, new ConfigDescription("Size of the explosion (the game's barrel uses 1, the propane tank 0.8, the clown 1.5). Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), Array.Empty<object>())); bananaDamage = config.Bind<int>("BananaBow", "PlayerDamage", 50, new ConfigDescription("Damage the explosion does to players (the game's barrel does 50). Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); bananaEnemyDamage = config.Bind<int>("BananaBow", "EnemyDamage", 100, new ConfigDescription("Damage the explosion does to enemies (the game's barrel does 100). Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 500), Array.Empty<object>())); bananaWarnVolume = config.Bind<float>("BananaBow", "WarningVolume", 1f, new ConfigDescription("How loud the \"uh-oh\" is on your machine (1 = as loud as a sound can be played).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); bananaWarnFalloff = config.Bind<float>("BananaBow", "WarningFalloff", 1.5f, new ConfigDescription("How far the \"uh-oh\" carries on your machine (1 = like the game's own sounds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>())); bananaGlitch = config.Bind<bool>("BananaBow", "ScreenGlitch", true, "Whoever holds the banana bow when its fuse is lit gets the screen glitch the game shows when a trap goes off (the one you get when the TV turns on). On your machine only."); faceGlitch = config.Bind<bool>("Handface", "ScreenGlitch", true, "Whoever holds the handface when it starts laughing, and a player within range when it starts creeping, gets the screen glitch the game shows when a trap goes off (the one you get when the TV turns on). On your machine only."); faceEnabled = config.Bind<bool>("Handface", "Enabled", true, "The handface valuable does nothing in the game. With this on, each second somebody holds it there is a chance it starts laughing loudly and shaking like a cursed doll, which draws enemies until it stops. Only the host's setting is used."); faceChance = config.Bind<float>("Handface", "ActivateChancePerSecond", 15f, new ConfigDescription("Chance, in percent, that a held handface starts laughing and shaking, each second. 0 = never. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); faceStopAfterDrop = config.Bind<float>("Handface", "StopSecondsAfterDrop", 2f, new ConfigDescription("It keeps shaking for as long as somebody holds it, and stops this many seconds after it was let go of (picking it up again in time keeps it going). Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>())); faceShake = config.Bind<float>("Handface", "ShakeStrength", 1f, new ConfigDescription("How hard it shakes: 1 = convulsing like a cursed doll, with short harder spasms (about eight times the game's toy monkey); 0.25 = a gentle tremble; 0 = it does not shake. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); faceAlertRange = config.Bind<float>("Handface", "AlertRange", 35f, new ConfigDescription("Metres around it within which enemies are drawn to the noise, every second, for as long as it shakes or its creeping sound plays (the game's own traps use 35). 0 = it does not alert enemies. Only the host's setting is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); faceLaughVolume = config.Bind<float>("Handface", "LaughVolume", 1f, new ConfigDescription("How loud the laugh is on your machine (1 = as loud as a sound can be played; the game's own sounds are about half that).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); faceLaughFalloff = config.Bind<float>("Handface", "LaughFalloff", 2f, new ConfigDescription("How far the laugh carries on your machine (1 = like the game's own sounds, 2 = twice as far).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>())); Creep.Bind(config); Haunts.Bind(config); } internal static Quirk Resolve(PhysGrabObject body) { if ((Object)(object)body == (Object)null) { return Quirk.None; } int instanceID = ((Object)body).GetInstanceID(); if (resolved.TryGetValue(instanceID, out var value)) { return value; } value = ResolveByName(body); if (resolved.Count > 4000) { resolved.Clear(); } resolved[instanceID] = value; return value; } private static Quirk ResolveByName(PhysGrabObject body) { if ((Object)(object)((Component)body).GetComponentInParent<ValuableObject>() == (Object)null) { return Quirk.None; } string name = ((Object)body).name; string name2 = ((Object)((Component)body).transform.root).name; if (Has(name, "banana bow") || Has(name2, "banana bow")) { return Quirk.BananaBow; } if (Has(name, "handface") || Has(name2, "handface")) { return Quirk.Handface; } if (Has(name, "horse") || Has(name2, "horse")) { return Quirk.Horse; } if (Has(name, "piano") || Has(name2, "piano")) { return Quirk.Piano; } return Quirk.None; } private static bool Has(string name, string part) { if (name != null) { return name.IndexOf(part, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } internal static void Tick() { if (SemiFunc.IsMasterClientOrSingleplayer()) { float time = Time.time; if (time >= nextRoll) { nextRoll = time + 1f; Roll(time); } TickFuses(time); TickFaces(time); Creep.Tick(time); Haunts.Tick(time); } } private static void Roll(float now) { RoundDirector instance = RoundDirector.instance; List<PhysGrabObject> list = (((Object)(object)instance == (Object)null) ? null : Refs.RoundBodies.Invoke(instance)); if (list == null) { return; } for (int i = 0; i < list.Count; i++) { PhysGrabObject val = list[i]; Quirk quirk = Resolve(val); if (quirk == Quirk.None) { continue; } switch (quirk) { case Quirk.Handface: Creep.Register(val); break; case Quirk.Horse: Haunts.RegisterHorse(val); break; case Quirk.Piano: Haunts.RegisterPiano(val); break; } if (val.grabbed && !val.dead) { if (quirk == Quirk.BananaBow && bananaEnabled.Value && Chance(bananaChance.Value)) { LightFuse(val, now); } else if (quirk == Quirk.Handface && faceEnabled.Value && Chance(faceChance.Value)) { StartLaughing(val, now); } else if (quirk == Quirk.Piano) { Haunts.RollPiano(val); } } } } internal static bool Chance(float percent) { if (percent > 0f) { return Random.value * 100f < percent; } return false; } private static void LightFuse(PhysGrabObject body, float now) { int instanceID = ((Object)body).GetInstanceID(); if (!fuses.ContainsKey(instanceID) && Explosions.Ready()) { Plugin.Log.LogDebug((object)"A banana bow lit its fuse."); float num = now + bananaWindup.Value; fuses[instanceID] = new Fuse { Body = body, WarnAt = num, BoomAt = num + WarningSeconds + 0.1f }; Net.AnnounceQuirk(body, Quirk.BananaBow, QuirkPhase.Start); } } private static void TickFuses(float now) { if (fuses.Count == 0) { return; } List<int> list = null; foreach (KeyValuePair<int, Fuse> fuse in fuses) { Fuse value = fuse.Value; if ((Object)(object)value.Body == (Object)null) { if (list == null) { list = new List<int>(); } list.Add(fuse.Key); continue; } if (!value.Warned && now >= value.WarnAt) { value.Warned = true; Net.AnnounceQuirk(value.Body, Quirk.BananaBow, QuirkPhase.Warn); } if (!value.Announced) { if (now >= value.BoomAt) { value.Announced = true; value.DestroyAt = now + 0.25f; Net.AnnounceQuirk(value.Body, Quirk.BananaBow, QuirkPhase.Boom, bananaSize.Value, bananaDamage.Value, bananaEnemyDamage.Value); } } else if (now >= value.DestroyAt) { PhysGrabObjectImpactDetector component = ((Component)value.Body).GetComponent<PhysGrabObjectImpactDetector>(); if ((Object)(object)component != (Object)null) { component.DestroyObject(true); } if (list == null) { list = new List<int>(); } list.Add(fuse.Key); } } if (list == null) { return; } foreach (int item in list) { fuses.Remove(item); } } private static void StartLaughing(PhysGrabObject body, float now) { int instanceID = ((Object)body).GetInstanceID(); if (!laughing.ContainsKey(instanceID) && Creep.PrimaryAllowed(body, now)) { Plugin.Log.LogDebug((object)"A handface started laughing."); laughing[instanceID] = new Laughing { Body = body, Impact = ((Component)body).GetComponent<PhysGrabObjectImpactDetector>() }; Net.AnnounceQuirk(body, Quirk.Handface, QuirkPhase.Start); } } internal static bool IsLaughing(PhysGrabObject body) { if ((Object)(object)body != (Object)null) { return laughing.ContainsKey(((Object)body).GetInstanceID()); } return false; } private static void TickFaces(float now) { if (laughing.Count == 0) { return; } List<int> list = null; foreach (KeyValuePair<int, Laughing> item in laughing) { Laughing value = item.Value; bool flag = (Object)(object)value.Body == (Object)null || value.Body.dead; if (!flag) { if ((Object)(object)value.Impact != (Object)null && value.Impact.inCart) { flag = true; } else if (value.Body.grabbed) { value.ReleasedAt = -1f; } else if (value.ReleasedAt < 0f) { value.ReleasedAt = now; } else if (now - value.ReleasedAt >= faceStopAfterDrop.Value) { flag = true; } } if (flag) { if (list == null) { list = new List<int>(); } list.Add(item.Key); if ((Object)(object)value.Body != (Object)null) { Creep.PrimaryEnded(value.Body, now); } } else if (now >= value.NextAlert) { value.NextAlert = now + 1f; Alert(value.Body); } } if (list == null) { return; } foreach (int item2 in list) { laughing.Remove(item2); } } internal static void Alert(PhysGrabObject body) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) EnemyDirector instance = EnemyDirector.instance; if ((Object)(object)instance != (Object)null && (Object)(object)body != (Object)null && faceAlertRange.Value > 0f) { instance.SetInvestigate(body.centerPoint, faceAlertRange.Value, false); } } internal static void FixedTick() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } shaken.Clear(); foreach (Laughing value in laughing.Values) { Shake(value.Body); } Creep.FixedTick(); } internal static void Shake(PhysGrabObject body) { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_0111: 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) if ((Object)(object)body == (Object)null || faceShake.Value <= 0f) { return; } Rigidbody rb = body.rb; if ((Object)(object)rb == (Object)null || !shaken.Add(((Object)body).GetInstanceID())) { return; } float time = Time.time; int instanceID = ((Object)body).GetInstanceID(); if (!spasms.TryGetValue(instanceID, out var value)) { if (spasms.Count > 64) { spasms.Clear(); } value = new Spasm(); spasms[instanceID] = value; } if (time >= value.NextAt) { value.Until = time + Random.Range(0.08f, 0.2f); value.NextAt = time + Random.Range(0.35f, 1.1f); } float num = faceShake.Value * ((time < value.Until) ? 2.5f : 1f) * Mathf.Max(1f, rb.mass); Vector3 insideUnitSphere = Random.insideUnitSphere; rb.AddTorque(((Vector3)(ref insideUnitSphere)).normalized * (4f * num), (ForceMode)0); rb.AddForce(Random.insideUnitSphere * (8f * num), (ForceMode)0); } internal static void OnEvent(EventData e) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) Player masterClient = PhotonNetwork.MasterClient; if (masterClient != null && e.Sender == masterClient.ActorNumber && e.CustomData is object[] array && array.Length >= 9) { PhotonView val = PhotonView.Find((int)array[0]); PhysGrabObject body = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<PhysGrabObject>()); Vector3 position = default(Vector3); ((Vector3)(ref position))..ctor((float)array[3], (float)array[4], (float)array[5]); Handle(extra1: (array.Length > 9) ? ((float)array[9]) : 0f, extra2: (array.Length > 10) ? ((float)array[10]) : 0f, body: body, quirk: (Quirk)(byte)array[1], phase: (QuirkPhase)(byte)array[2], position: position, size: (float)array[6], damage: (int)array[7], enemyDamage: (int)array[8]); } } internal static void Handle(PhysGrabObject body, Quirk quirk, QuirkPhase phase, Vector3 position, float size, int damage, int enemyDamage, float extra1, float extra2) { //IL_001e: 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) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00ef: 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) //IL_0055: Unknown result type (might be due to invalid IL or missing references) switch (quirk) { case Quirk.BananaBow: switch (phase) { case QuirkPhase.Start: StartWindup(body, position); if (bananaGlitch.Value) { ScreenGlitch.PlayIfHeldHere(body); } break; case QuirkPhase.Warn: GameAudio.PlayClip(UserAudio.Warning, ((Object)(object)body != (Object)null) ? ((Component)body).transform : null, position, bananaWarnVolume.Value, bananaWarnFalloff.Value); break; case QuirkPhase.Boom: Detonate(body, position, size, damage, enemyDamage); break; } break; case Quirk.Handface: switch (phase) { case QuirkPhase.Start: Laugh(body, position); if (faceGlitch.Value) { ScreenGlitch.PlayIfHeldHere(body); } break; case QuirkPhase.Twitch: Creep.ClientTwitch(body, position, size); break; case QuirkPhase.Settle: Creep.ClientSettle(body); break; case QuirkPhase.Launch: Creep.ClientLaunch(body, position, size, damage, extra1, extra2); break; case QuirkPhase.Boom: break; } break; case Quirk.Horse: if (phase == QuirkPhase.Start) { Haunts.ClientHorse(body, position); } break; case Quirk.Piano: switch (phase) { case QuirkPhase.Start: Haunts.ClientPianoStart(body, position); break; case QuirkPhase.Settle: Haunts.ClientPianoStop(body); break; } break; } } internal static void Laugh(PhysGrabObject body, Vector3 position) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) GameAudio.PlayClip(UserAudio.Laugh, ((Object)(object)body != (Object)null) ? ((Component)body).transform : null, position, faceLaughVolume.Value, faceLaughFalloff.Value); } private static void StartWindup(PhysGrabObject body, Vector3 position) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) GameAudio.Fuse fuse = GameAudio.StartFuse(((Object)(object)body != (Object)null) ? ((Component)body).transform : null, position); if (fuse != null && !((Object)(object)body == (Object)null)) { int instanceID = ((Object)body).GetInstanceID(); if (burning.TryGetValue(instanceID, out var value)) { value.Sound.Stop(); } burning[instanceID] = new Burning { Body = body, Sound = fuse, StartedAt = Time.time }; } } private static void Detonate(PhysGrabObject body, Vector3 position, float size, int damage, int enemyDamage) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)body != (Object)null) { int instanceID = ((Object)body).GetInstanceID(); if (burning.TryGetValue(instanceID, out var value)) { value.Sound.Stop(); burning.Remove(instanceID); } } Explosions.Spawn(body, position, size, damage, enemyDamage); } internal static void ClientTick() { if (burning.Count > 0) { List<int> list = null; foreach (KeyValuePair<int, Burning> item in burning) { Burning value = item.Value; if ((Object)(object)value.Body == (Object)null || Time.time - value.StartedAt > bananaWindup.Value + WarningSeconds + 5f) { value.Sound.Stop(); if (list == null) { list = new List<int>(); } list.Add(item.Key); } else { value.Sound.Tick(); } } if (list != null) { foreach (int item2 in list) { burning.Remove(item2); } } } Creep.ClientTick(); Haunts.ClientTick(); } } internal static class Net { private const byte EvRequest = 181; private const byte EvApply = 182; private const byte EvQuirk = 183; private static bool initialized; internal static void Init() { if (!initialized) { initialized = true; PhotonNetwork.NetworkingClient.EventReceived += OnEvent; } } internal static void Use(PhysGrabObject body, KindId id) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_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_007a: Expected O, but got Unknown if (!SemiFunc.IsMultiplayer()) { Host.Handle(body, id, -1); return; } PhotonView component = ((Component)body).GetComponent<PhotonView>(); if (!((Object)(object)component == (Object)null) && component.ViewID != 0) { if (SemiFunc.IsMasterClientOrSingleplayer()) { Host.Handle(body, id, PhotonNetwork.LocalPlayer.ActorNumber); return; } PhotonNetwork.RaiseEvent((byte)181, (object)new object[2] { component.ViewID, (byte)id }, new RaiseEventOptions { Receivers = (ReceiverGroup)2 }, SendOptions.SendReliable); } } internal static void Announce(PhysGrabObject body, KindId id, bool off, float cooldown) { //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_0065: 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_0074: Expected O, but got Unknown if (!SemiFunc.IsMultiplayer()) { Apply(body, id, off, cooldown); return; } PhotonView component = ((Component)body).GetComponent<PhotonView>(); if (!((Object)(object)component == (Object)null) && component.ViewID != 0) { PhotonNetwork.RaiseEvent((byte)182, (object)new object[4] { component.ViewID, (byte)id, off, cooldown }, new RaiseEventOptions { Receivers = (ReceiverGroup)1 }, SendOptions.SendReliable); } } internal static void AnnounceQuirk(PhysGrabObject body, Quirk quirk, QuirkPhase phase, float size = 0f, int damage = 0, int enemyDamage = 0, float extra1 = 0f, float extra2 = 0f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due t