Decompiled source of Downed v2.0.1

Mods/Downed.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BoneLib;
using Il2CppSLZ.Marrow;
using LabFusion.Network;
using LabFusion.Preferences;
using LabFusion.SDK.Gamemodes;
using MelonLoader;
using UnityEngine;
using downed;
using jlib;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Downed), "Downed", "2.0.1", "Jorink", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonColor(255, 255, 0, 255)]
[assembly: MelonAuthorColor(255, 255, 0, 0)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace downed;

public class Downed : MelonMod
{
	private enum PlayerState
	{
		Default,
		Downed,
		Dead
	}

	public const string Version = "2.0.1";

	private const float ReviveDuration = 5f;

	private const float BleedOutDuration = 20f;

	private const float DoubleTapTimer = 0.32f;

	private MelonPreferences_Entry<bool> enableMod;

	private MelonPreferences_Entry<bool> stayRagdolled;

	private PlayerState state;

	private RigManager rig;

	private PhysicsRig physRig;

	private BaseController controller;

	private Grip[] playerGrips = Array.Empty<Grip>();

	private object bleedOutRoutine;

	private float grabStartTime;

	private bool reviveStarted;

	private bool firstSkipped;

	private float lastTimeInput;

	private bool ragdollNextButton;

	private bool isModAllowed
	{
		get
		{
			if (enableMod.Value && Object.op_Implicit((Object)(object)rig))
			{
				return FusionCompat();
			}
			return false;
		}
	}

	private bool isDowned => state == PlayerState.Downed;

	private bool isRagdolled
	{
		get
		{
			if (!physRig.torso.shutdown)
			{
				return !physRig.ballLocoEnabled;
			}
			return true;
		}
	}

	public override void OnInitializeMelon()
	{
		//IL_0005: 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_0030: Unknown result type (might be due to invalid IL or missing references)
		ModPage val = JLib.Register("Downed", Color.magenta);
		enableMod = val.Bool("Enable Mod", true, Color.green, (Action<bool>)null);
		stayRagdolled = val.Bool("Stay Ragdolled (Dead)", false, Color.yellow, (Action<bool>)null);
		Hooking.OnLevelLoaded += OnLevelLoaded;
		Hooking.OnPlayerDamageReceived += OnPlayerDamageReceived;
		Hooking.OnPlayerResurrected += OnPlayerResurrected;
		Hooking.OnPlayerDeath += OnPlayerDeath;
	}

	private void OnLevelLoaded(LevelInfo levelInfo)
	{
		rig = Player.RigManager;
		physRig = Player.PhysicsRig;
		controller = Player.RightController;
		state = PlayerState.Default;
		PhysTorso torso = physRig.torso;
		PhysHand physHand = physRig.leftHand.physHand;
		PhysHand physHand2 = physRig.rightHand.physHand;
		playerGrips = (Grip[])(object)new Grip[9]
		{
			torso.gChest,
			torso.gHead,
			(Grip)torso.gNeck,
			torso.gPelvis,
			torso.gSpine,
			(Grip)physHand.gShoulder,
			(Grip)physHand.gElbow,
			(Grip)physHand2.gShoulder,
			(Grip)physHand2.gElbow
		};
	}

	private bool isLocalRig(RigManager hookRig)
	{
		if (isModAllowed)
		{
			return (Object)(object)hookRig == (Object)(object)Player.RigManager;
		}
		return false;
	}

	public override void OnUpdate()
	{
		if (!isModAllowed)
		{
			return;
		}
		if (isDowned)
		{
			if (!isRagdolled)
			{
				RagdollPlayer();
				StartBleedOut();
			}
			Player_Health playerHealth = JLib.playerHealth;
			if ((Object)(object)playerHealth != (Object)null && playerHealth.regenRoutine != null)
			{
				((MonoBehaviour)playerHealth).StopCoroutine(playerHealth.regenRoutine);
			}
		}
		else
		{
			firstSkipped = false;
		}
		if (state == PlayerState.Dead && !physRig.shutdown)
		{
			physRig.ShutdownRig();
		}
		if (reviveChecks())
		{
			Revive();
		}
	}

	private void RagdollPlayer()
	{
		physRig.RagdollRig();
		physRig.DisableBallLoco();
		physRig.PhysicalLegs();
		physRig.legLf.ShutdownLimb();
		physRig.legRt.ShutdownLimb();
	}

	private void UnragdollPlayer()
	{
		//IL_0043: 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_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		Transform transform = physRig.feet.transform;
		Transform transform2 = physRig.knee.transform;
		Transform pelvis = ((Rig)physRig).m_pelvis;
		physRig.TurnOnRig();
		physRig.UnRagdollRig();
		transform2.SetPositionAndRotation(pelvis.position, pelvis.rotation);
		transform.SetPositionAndRotation(pelvis.position, pelvis.rotation);
	}

	private void OnPlayerDamageReceived(RigManager rig, float damage)
	{
		if (isLocalRig(rig) && !(rig.health.curr_Health > 0f))
		{
			if (state == PlayerState.Default)
			{
				DownPlayer();
			}
			else if (state == PlayerState.Downed)
			{
				KillPlayer();
			}
		}
	}

	private void OnPlayerDeath(RigManager rig)
	{
		if (isLocalRig(rig))
		{
			Revive();
		}
	}

	private void OnPlayerResurrected(RigManager rig)
	{
		if (isLocalRig(rig) && state != PlayerState.Default)
		{
			if (isDowned && !firstSkipped)
			{
				firstSkipped = true;
			}
			else
			{
				Revive();
			}
		}
	}

	private bool FusionCompat()
	{
		if (!JLib.isFusionInstalled)
		{
			return true;
		}
		if (!NetworkInfo.HasServer)
		{
			return true;
		}
		if (GamemodeManager.ActiveGamemode != null)
		{
			return false;
		}
		return !CommonPreferences.Knockout;
	}

	private bool reviveChecks()
	{
		if (forceReviveInput())
		{
			state = PlayerState.Default;
			StopBleedOut();
			if (isRagdolled)
			{
				UnragdollPlayer();
			}
		}
		if (!isDowned || !playerGrips.Any((Grip g) => g.HasAttachedHands()))
		{
			reviveStarted = false;
			return false;
		}
		if (reviveStarted)
		{
			return Time.time - grabStartTime >= 5f;
		}
		reviveStarted = true;
		grabStartTime = Time.time;
		return false;
	}

	private void Revive()
	{
		state = PlayerState.Default;
		StopBleedOut();
		if (isRagdolled && !stayRagdolled.Value)
		{
			UnragdollPlayer();
		}
	}

	private void DownPlayer()
	{
		state = PlayerState.Downed;
		JLib.playerHealth.LifeSavingDamgeDealt();
	}

	private void KillPlayer()
	{
		state = PlayerState.Dead;
		rig.health.curr_Health = 0f;
		rig.health.Dying(5f);
	}

	private bool forceReviveInput()
	{
		bool thumbStickDown = controller.GetThumbStickDown();
		bool flag = Time.time - lastTimeInput > 0.32f;
		if (thumbStickDown && ragdollNextButton)
		{
			if (!flag)
			{
				return true;
			}
		}
		else
		{
			if (thumbStickDown)
			{
				lastTimeInput = Time.time;
				ragdollNextButton = true;
				return false;
			}
			if (!flag)
			{
				return false;
			}
		}
		ragdollNextButton = false;
		lastTimeInput = 0f;
		return false;
	}

	private void StartBleedOut()
	{
		if (bleedOutRoutine == null)
		{
			bleedOutRoutine = MelonCoroutines.Start(BleedOutRoutine());
		}
	}

	private IEnumerator BleedOutRoutine()
	{
		float elapsed = 0f;
		while (isDowned && elapsed < 20f)
		{
			if (!reviveStarted)
			{
				elapsed += Time.deltaTime;
			}
			yield return null;
		}
		if (isDowned)
		{
			KillPlayer();
		}
		bleedOutRoutine = null;
	}

	private void StopBleedOut()
	{
		if (bleedOutRoutine != null)
		{
			MelonCoroutines.Stop(bleedOutRoutine);
			bleedOutRoutine = null;
		}
	}
}