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;
}
}
}