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.InteropServices;
using System.Runtime.Versioning;
using BoneLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using MelonLoader;
using ShellShock;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Main), "ShellShock", "1.0.0", "CooladTheGreat", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: AssemblyTitle("ShellShock")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ShellShock")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("241513f7-06c6-4c07-ba97-cf1bc358eabe")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ShellShock;
public class Main : MelonMod
{
[CompilerGenerated]
private sealed class <PlayHeartbeatCoroutine>d__13 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
private byte[] <wavData>5__1;
private AudioClip <clip>5__2;
private GameObject <audioObj>5__3;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <PlayHeartbeatCoroutine>d__13(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<wavData>5__1 = null;
<clip>5__2 = null;
<audioObj>5__3 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Expected O, but got Unknown
if (<>1__state != 0)
{
return false;
}
<>1__state = -1;
<wavData>5__1 = LoadEmbeddedWAV("ShellShock.Heartbeatsound.Heartbeat.wav");
if (<wavData>5__1 == null)
{
return false;
}
<clip>5__2 = WavUtility.ToAudioClip(<wavData>5__1, "Heartbeat");
if ((Object)(object)<clip>5__2 == (Object)null)
{
return false;
}
<audioObj>5__3 = new GameObject("ShellShock_Heartbeat");
Object.DontDestroyOnLoad((Object)(object)<audioObj>5__3);
heartbeatSource = <audioObj>5__3.AddComponent<AudioSource>();
heartbeatSource.spatialBlend = 0f;
heartbeatSource.volume = 1f;
heartbeatSource.clip = <clip>5__2;
heartbeatSource.loop = true;
heartbeatSource.Play();
MelonLogger.Msg("Heartbeat audio started (looping)");
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <ShellshockWatcher>d__11 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
private float <currentHealth>5__1;
private float <maxHealth>5__2;
private float <thresholdHealth>5__3;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ShellshockWatcher>d__11(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
break;
case 1:
<>1__state = -1;
if (!((Object)(object)Player.RigManager == (Object)null) && !((Object)(object)Player.RigManager.health == (Object)null))
{
<currentHealth>5__1 = Player.RigManager.health.curr_Health;
<maxHealth>5__2 = Player.RigManager.health.max_Health;
<thresholdHealth>5__3 = <maxHealth>5__2 * 0.4f;
if (<currentHealth>5__1 <= <thresholdHealth>5__3 && !isShellshockActive)
{
isShellshockActive = true;
MelonLogger.Msg("ShellShock active: Starting effects.");
StartShellshockEffects();
}
else if (<currentHealth>5__1 > <thresholdHealth>5__3 && isShellshockActive)
{
isShellshockActive = false;
MelonLogger.Msg("ShellShock deactivated: Stopping effects.");
StopShellshockEffects();
}
}
break;
}
<>2__current = (object)new WaitForEndOfFrame();
<>1__state = 1;
return true;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private static AudioLowPassFilter activeListenerFilter;
private static AudioSource heartbeatSource;
private const float ShellshockCutoffFrequency = 800f;
private const float ShellshockThresholdPercent = 40f;
private static bool isShellshockActive;
private static GameObject listenerObject;
private const string HeartbeatResource = "ShellShock.Heartbeatsound.Heartbeat.wav";
public override void OnInitializeMelon()
{
MelonLogger.Msg("ShellShock mod initialized. Watching for low health...");
MelonCoroutines.Start(ShellshockWatcher());
}
private static void FindListenerObject()
{
AudioListener val = Object.FindObjectOfType<AudioListener>();
listenerObject = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null);
if ((Object)(object)listenerObject == (Object)null)
{
MelonLogger.Error("Could not find the AudioListener.");
}
}
private static void StartShellshockEffects()
{
if ((Object)(object)listenerObject == (Object)null)
{
FindListenerObject();
}
if (!((Object)(object)listenerObject == (Object)null))
{
if ((Object)(object)activeListenerFilter == (Object)null)
{
activeListenerFilter = listenerObject.AddComponent<AudioLowPassFilter>();
activeListenerFilter.cutoffFrequency = 800f;
}
StartHeartbeatLoop();
}
}
private static void StopShellshockEffects()
{
if ((Object)(object)activeListenerFilter != (Object)null)
{
Object.Destroy((Object)(object)activeListenerFilter);
activeListenerFilter = null;
}
if ((Object)(object)heartbeatSource != (Object)null)
{
heartbeatSource.Stop();
Object.Destroy((Object)(object)((Component)heartbeatSource).gameObject);
heartbeatSource = null;
}
}
[IteratorStateMachine(typeof(<ShellshockWatcher>d__11))]
private static IEnumerator ShellshockWatcher()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ShellshockWatcher>d__11(0);
}
private static void StartHeartbeatLoop()
{
if (!((Object)(object)heartbeatSource != (Object)null))
{
MelonCoroutines.Start(PlayHeartbeatCoroutine());
}
}
[IteratorStateMachine(typeof(<PlayHeartbeatCoroutine>d__13))]
private static IEnumerator PlayHeartbeatCoroutine()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <PlayHeartbeatCoroutine>d__13(0);
}
private static byte[] LoadEmbeddedWAV(string resourceName)
{
try
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
MelonLogger.Msg("Looking for resource: " + resourceName);
string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
string[] array = manifestResourceNames;
foreach (string text in array)
{
MelonLogger.Msg("Found resource: " + text);
}
using Stream stream = executingAssembly.GetManifestResourceStream(resourceName);
if (stream == null)
{
MelonLogger.Error("Resource '" + resourceName + "' not found!");
return null;
}
byte[] array2 = new byte[stream.Length];
stream.Read(array2, 0, array2.Length);
MelonLogger.Msg($"Loaded WAV: {array2.Length} bytes");
return array2;
}
catch (Exception arg)
{
MelonLogger.Error($"Error loading WAV: {arg}");
return null;
}
}
public override void OnDeinitializeMelon()
{
StopShellshockEffects();
MelonLogger.Msg("ShellShock mod deinitialized.");
}
}
public static class WavUtility
{
public static AudioClip ToAudioClip(byte[] wavBytes, string name = "wav")
{
try
{
if (!IsValidWav(wavBytes))
{
Debug.LogError(Object.op_Implicit("Invalid WAV file format"));
return null;
}
int num = BitConverter.ToInt16(wavBytes, 22);
int num2 = BitConverter.ToInt32(wavBytes, 24);
int num3 = BitConverter.ToInt16(wavBytes, 34);
int num4 = FindDataChunk(wavBytes);
if (num4 == -1)
{
Debug.LogError(Object.op_Implicit("Data chunk not found in WAV file"));
return null;
}
int dataSize = BitConverter.ToInt32(wavBytes, num4 + 4);
int startIndex = num4 + 8;
float[] array;
switch (num3)
{
case 16:
array = Convert16BitToFloat(wavBytes, startIndex, dataSize);
break;
case 8:
array = Convert8BitToFloat(wavBytes, startIndex, dataSize);
break;
case 32:
array = Convert32BitToFloat(wavBytes, startIndex, dataSize);
break;
default:
Debug.LogError(Object.op_Implicit($"Unsupported bit depth: {num3}"));
return null;
}
AudioClip val = AudioClip.Create(name, array.Length / num, num, num2, false);
val.SetData(Il2CppStructArray<float>.op_Implicit(array), 0);
return val;
}
catch (Exception arg)
{
Debug.LogError(Object.op_Implicit($"Error converting WAV to AudioClip: {arg}"));
return null;
}
}
private static bool IsValidWav(byte[] wavBytes)
{
if (wavBytes.Length < 12)
{
return false;
}
if (wavBytes[0] != 82 || wavBytes[1] != 73 || wavBytes[2] != 70 || wavBytes[3] != 70)
{
return false;
}
if (wavBytes[8] != 87 || wavBytes[9] != 65 || wavBytes[10] != 86 || wavBytes[11] != 69)
{
return false;
}
return true;
}
private static int FindDataChunk(byte[] wavBytes)
{
int num;
for (int i = 12; i < wavBytes.Length - 8; i += 8 + num)
{
if (wavBytes[i] == 100 && wavBytes[i + 1] == 97 && wavBytes[i + 2] == 116 && wavBytes[i + 3] == 97)
{
return i;
}
num = BitConverter.ToInt32(wavBytes, i + 4);
}
return -1;
}
private static float[] Convert16BitToFloat(byte[] bytes, int startIndex, int dataSize)
{
int num = dataSize / 2;
float[] array = new float[num];
for (int i = 0; i < num; i++)
{
short num2 = BitConverter.ToInt16(bytes, startIndex + i * 2);
array[i] = (float)num2 / 32768f;
}
return array;
}
private static float[] Convert8BitToFloat(byte[] bytes, int startIndex, int dataSize)
{
float[] array = new float[dataSize];
for (int i = 0; i < dataSize; i++)
{
array[i] = (float)(bytes[startIndex + i] - 128) / 128f;
}
return array;
}
private static float[] Convert32BitToFloat(byte[] bytes, int startIndex, int dataSize)
{
int num = dataSize / 4;
float[] array = new float[num];
for (int i = 0; i < num; i++)
{
float num2 = BitConverter.ToSingle(bytes, startIndex + i * 4);
array[i] = Mathf.Clamp(num2, -1f, 1f);
}
return array;
}
}