Decompiled source of TesticularTorsion v1.1.0

TesticularTorsion.dll

Decompiled 3 weeks ago
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 BepInEx;
using BlackMagicAPI.Enums;
using BlackMagicAPI.Helpers;
using BlackMagicAPI.Managers;
using BlackMagicAPI.Modules.Spells;
using FishNet.Object;
using Steamworks;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("TesticularTorsion")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TesticularTorsion")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6b93a891-7200-4c3e-80f9-8570b94fd510")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace TesticularTorsion;

[BepInPlugin("com.owls8.testiculartorsion", "Testicular Torsion", "1.1.0")]
[BepInProcess("MageArena.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class TesticularTorsion : BaseUnityPlugin
{
	internal class TesticularTorsionData : SpellData
	{
		public override SpellType SpellType => (SpellType)0;

		public override string Name => "Testicular Torsion";

		public override float Cooldown => 15f;

		public override Color GlowColor => Color.magenta;

		public override Texture2D GetMainTexture()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string text = Path.Combine(directoryName, ((SpellData)this).Name.Replace(" ", "") + "_Main.png");
			if (File.Exists(text))
			{
				return Utils.LoadTextureFromDisk(text);
			}
			return Utils.LoadTextureFromResources(Assembly.GetExecutingAssembly(), "BlackMagicAPI.Resources.Items.Item_Main.png");
		}

		public override Texture2D GetEmissionTexture()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string text = Path.Combine(directoryName, ((SpellData)this).Name.Replace(" ", "") + "_Emission.png");
			if (File.Exists(text))
			{
				return Utils.LoadTextureFromDisk(text);
			}
			return Utils.LoadTextureFromResources(Assembly.GetExecutingAssembly(), "BlackMagicAPI.Resources.Items.Item_Emission.png");
		}
	}

	internal class TesticularTorsionLogic : SpellLogic
	{
		[CompilerGenerated]
		private sealed class <FlashbangEffect>d__5 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public float fadeInDuration;

			public float holdDuration;

			public float fadeOutDuration;

			public float maxAlpha;

			private GameObject <canvasObj>5__1;

			private Canvas <canvas>5__2;

			private CanvasScaler <scaler>5__3;

			private GameObject <imageObj>5__4;

			private RectTransform <rect>5__5;

			private Image <image>5__6;

			private float <elapsed>5__7;

			private float <alpha>5__8;

			private float <alpha>5__9;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FlashbangEffect>d__5(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<canvasObj>5__1 = null;
				<canvas>5__2 = null;
				<scaler>5__3 = null;
				<imageObj>5__4 = null;
				<rect>5__5 = null;
				<image>5__6 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Expected O, but got Unknown
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b3: Expected O, but got Unknown
				//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
				//IL_0109: Unknown result type (might be due to invalid IL or missing references)
				//IL_011a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0150: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_020c: Unknown result type (might be due to invalid IL or missing references)
				//IL_021e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0228: Expected O, but got Unknown
				//IL_0284: Unknown result type (might be due to invalid IL or missing references)
				//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<canvasObj>5__1 = new GameObject("FlashbangCanvas");
					<canvas>5__2 = <canvasObj>5__1.AddComponent<Canvas>();
					<canvas>5__2.renderMode = (RenderMode)0;
					<canvas>5__2.sortingOrder = 9999;
					<scaler>5__3 = <canvasObj>5__1.AddComponent<CanvasScaler>();
					<scaler>5__3.uiScaleMode = (ScaleMode)1;
					<canvasObj>5__1.AddComponent<GraphicRaycaster>();
					<imageObj>5__4 = new GameObject("FlashbangImage");
					<imageObj>5__4.transform.SetParent(<canvasObj>5__1.transform, false);
					<rect>5__5 = <imageObj>5__4.AddComponent<RectTransform>();
					<rect>5__5.anchorMin = Vector2.zero;
					<rect>5__5.anchorMax = Vector2.one;
					<rect>5__5.offsetMin = Vector2.zero;
					<rect>5__5.offsetMax = Vector2.zero;
					<image>5__6 = <imageObj>5__4.AddComponent<Image>();
					((Graphic)<image>5__6).color = new Color(1f, 1f, 1f, 0f);
					<elapsed>5__7 = 0f;
					goto IL_01dc;
				case 1:
					<>1__state = -1;
					goto IL_01dc;
				case 2:
					<>1__state = -1;
					<elapsed>5__7 = 0f;
					break;
				case 3:
					{
						<>1__state = -1;
						break;
					}
					IL_01dc:
					if (<elapsed>5__7 < fadeInDuration)
					{
						<alpha>5__8 = Mathf.Lerp(0f, maxAlpha, <elapsed>5__7 / fadeInDuration);
						((Graphic)<image>5__6).color = new Color(1f, 1f, 1f, <alpha>5__8);
						<elapsed>5__7 += Time.deltaTime;
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					((Graphic)<image>5__6).color = new Color(1f, 1f, 1f, maxAlpha);
					<>2__current = (object)new WaitForSeconds(holdDuration);
					<>1__state = 2;
					return true;
				}
				if (<elapsed>5__7 < fadeOutDuration)
				{
					<alpha>5__9 = Mathf.Lerp(maxAlpha, 0f, <elapsed>5__7 / fadeOutDuration);
					((Graphic)<image>5__6).color = new Color(1f, 1f, 1f, <alpha>5__9);
					<elapsed>5__7 += Time.deltaTime;
					<>2__current = null;
					<>1__state = 3;
					return true;
				}
				((Graphic)<image>5__6).color = new Color(1f, 1f, 1f, 0f);
				Object.Destroy((Object)(object)<canvasObj>5__1);
				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 <SubtractTesticularTorsionDebuff>d__4 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public float duration;

			private FieldInfo <stewspeedboostField>5__1;

			private PlayerMovement[] <allPlayers>5__2;

			private PlayerMovement[] <>s__3;

			private int <>s__4;

			private PlayerMovement <player>5__5;

			private float <currentValue>5__6;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SubtractTesticularTorsionDebuff>d__4(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<stewspeedboostField>5__1 = null;
				<allPlayers>5__2 = null;
				<>s__3 = null;
				<player>5__5 = null;
				<>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;
					<>2__current = (object)new WaitForSeconds(duration);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<stewspeedboostField>5__1 = typeof(PlayerMovement).GetField("stewspeedboost", BindingFlags.Instance | BindingFlags.NonPublic);
					if (<stewspeedboostField>5__1 != null)
					{
						<allPlayers>5__2 = Object.FindObjectsByType<PlayerMovement>((FindObjectsSortMode)0);
						<>s__3 = <allPlayers>5__2;
						for (<>s__4 = 0; <>s__4 < <>s__3.Length; <>s__4++)
						{
							<player>5__5 = <>s__3[<>s__4];
							if (((NetworkBehaviour)<player>5__5).IsOwner)
							{
								<currentValue>5__6 = (float)<stewspeedboostField>5__1.GetValue(<player>5__5);
								<stewspeedboostField>5__1.SetValue(<player>5__5, <currentValue>5__6 + 6f);
								break;
							}
							<player>5__5 = null;
						}
						<>s__3 = null;
						<allPlayers>5__2 = null;
					}
					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 <TesticularTorsionDamageTicks>d__3 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public float duration;

			public PlayerMovement targetMovement;

			public int castingLevel;

			private float <damageCooldown>5__1;

			private float <damageTimer>5__2;

			private float <elapsedTime>5__3;

			private float <damageAmount>5__4;

			private float <delta>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TesticularTorsionDamageTicks>d__3(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<damageCooldown>5__1 = 0.3f;
					<damageTimer>5__2 = 0f;
					<elapsedTime>5__3 = 0f;
					<damageAmount>5__4 = 1f;
					break;
				case 1:
					<>1__state = -1;
					<delta>5__5 = Time.deltaTime;
					<elapsedTime>5__3 += <delta>5__5;
					<damageTimer>5__2 -= <delta>5__5;
					break;
				}
				if (<elapsedTime>5__3 < duration)
				{
					if (<damageTimer>5__2 <= 0f && targetMovement.currentSpeed > 0.5f)
					{
						targetMovement.NonRpcDamagePlayer(<damageAmount>5__4 + 0.1f * (float)castingLevel, (GameObject)null, "testiculartorsion");
						<damageTimer>5__2 = <damageCooldown>5__1;
					}
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				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 <TesticularTorsionEffect>d__2 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public PlayerMovement targetMovement;

			public int castingLevel;

			private FieldInfo <stewspeedboostField>5__1;

			private float <debuffDuration>5__2;

			private float <currentValue>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TesticularTorsionEffect>d__2(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<stewspeedboostField>5__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					targetMovement.NonRpcDamagePlayer(12f + (float)(3 * castingLevel), (GameObject)null, "testiculartorsion");
					if (((NetworkBehaviour)targetMovement).IsOwner)
					{
						<stewspeedboostField>5__1 = typeof(PlayerMovement).GetField("stewspeedboost", BindingFlags.Instance | BindingFlags.NonPublic);
						if (<stewspeedboostField>5__1 != null)
						{
							<currentValue>5__3 = (float)<stewspeedboostField>5__1.GetValue(targetMovement);
							<stewspeedboostField>5__1.SetValue(targetMovement, <currentValue>5__3 - 6f);
						}
						<debuffDuration>5__2 = 5f;
						((MonoBehaviour)targetMovement).StartCoroutine(SubtractTesticularTorsionDebuff(<debuffDuration>5__2));
						((MonoBehaviour)targetMovement).StartCoroutine(TesticularTorsionDamageTicks(<debuffDuration>5__2, targetMovement, castingLevel));
						((MonoBehaviour)targetMovement).StartCoroutine(FlashbangEffect());
						PlayFlashSoundLocally();
						<stewspeedboostField>5__1 = null;
					}
					if (affectedPlayers.ContainsKey(targetMovement))
					{
						affectedPlayers[targetMovement] = false;
					}
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					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();
			}
		}

		public static Dictionary<PlayerMovement, bool> affectedPlayers = new Dictionary<PlayerMovement, bool>();

		public override void CastSpell(GameObject playerObj, PageController page, Vector3 spawnPos, Vector3 viewDirectionVector, int castingLevel)
		{
			//IL_002c: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			PlayerMovement component = playerObj.GetComponent<PlayerMovement>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			GameObject[] array = GameObject.FindGameObjectsWithTag("Player");
			Vector3 position = playerObj.transform.position;
			Vector3 forward = playerObj.transform.forward;
			string personaName = SteamFriends.GetPersonaName();
			PlayerMovement val = null;
			PlayerMovement[] array2 = Object.FindObjectsByType<PlayerMovement>((FindObjectsSortMode)0);
			PlayerMovement[] array3 = array2;
			foreach (PlayerMovement val2 in array3)
			{
				if (val2.playername == personaName)
				{
					val = val2;
					break;
				}
			}
			GameObject[] array4 = array;
			foreach (GameObject val3 in array4)
			{
				if ((Object)(object)val3 == (Object)(object)playerObj)
				{
					continue;
				}
				float num = Vector3.Distance(position, val3.transform.position);
				if (num <= 15f)
				{
					PlayerMovement component2 = val3.GetComponent<PlayerMovement>();
					if ((Object)(object)component2 != (Object)null)
					{
						affectedPlayers[component2] = true;
						((MonoBehaviour)component2).StartCoroutine(TesticularTorsionEffect(component2, castingLevel));
						PlayTesticularTorsionSound(component2, 5f);
					}
				}
			}
		}

		[IteratorStateMachine(typeof(<TesticularTorsionEffect>d__2))]
		public static IEnumerator TesticularTorsionEffect(PlayerMovement targetMovement, int castingLevel)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TesticularTorsionEffect>d__2(0)
			{
				targetMovement = targetMovement,
				castingLevel = castingLevel
			};
		}

		[IteratorStateMachine(typeof(<TesticularTorsionDamageTicks>d__3))]
		private static IEnumerator TesticularTorsionDamageTicks(float duration, PlayerMovement targetMovement, int castingLevel)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TesticularTorsionDamageTicks>d__3(0)
			{
				duration = duration,
				targetMovement = targetMovement,
				castingLevel = castingLevel
			};
		}

		[IteratorStateMachine(typeof(<SubtractTesticularTorsionDebuff>d__4))]
		private static IEnumerator SubtractTesticularTorsionDebuff(float duration)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SubtractTesticularTorsionDebuff>d__4(0)
			{
				duration = duration
			};
		}

		[IteratorStateMachine(typeof(<FlashbangEffect>d__5))]
		public static IEnumerator FlashbangEffect(float fadeInDuration = 0.07f, float holdDuration = 0.1f, float fadeOutDuration = 2f, float maxAlpha = 0.8f)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FlashbangEffect>d__5(0)
			{
				fadeInDuration = fadeInDuration,
				holdDuration = holdDuration,
				fadeOutDuration = fadeOutDuration,
				maxAlpha = maxAlpha
			};
		}

		private static void PlayFlashSoundLocally()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)flashSound != (Object)null)
			{
				GameObject val = new GameObject("FlashbangLocalSound");
				AudioSource val2 = val.AddComponent<AudioSource>();
				val2.clip = flashSound;
				val2.volume = 0.9f;
				val2.spatialBlend = 0f;
				val2.Play();
				Object.Destroy((Object)(object)val, flashSound.length + 0.1f);
			}
		}

		private static void PlayTesticularTorsionSound(PlayerMovement player, float duration)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_002c: 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)
			try
			{
				if ((Object)(object)stretchSound != (Object)null)
				{
					GameObject val = new GameObject("TesticularTorsionAudio");
					val.transform.position = ((Component)player).transform.position;
					AudioSource val2 = val.AddComponent<AudioSource>();
					val2.clip = stretchSound;
					val2.volume = 0.6f;
					val2.spatialBlend = 1f;
					val2.rolloffMode = (AudioRolloffMode)1;
					val2.minDistance = 5f;
					val2.maxDistance = 50f;
					val2.Play();
					for (float num = 0f; num < duration; num += Time.deltaTime)
					{
						val.transform.position = ((Component)player).transform.position;
					}
					float num2 = stretchSound.length + 0.1f;
					Object.Destroy((Object)(object)val, num2);
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[TesticularTorsion] Error playing sound: " + ex.Message));
			}
		}
	}

	private static AssetBundle testicularTorsionBundle;

	public static AudioClip stretchSound;

	public static AudioClip flashSound;

	private void Awake()
	{
		LoadTesticularTorsionAssets();
		BlackMagicManager.RegisterSpell((BaseUnityPlugin)(object)this, typeof(TesticularTorsionData), typeof(TesticularTorsionLogic));
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin com.owls8.testiculartorsion is loaded!");
	}

	private void LoadTesticularTorsionAssets()
	{
		try
		{
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			string text = Path.Combine(directoryName, "testebundle");
			if (File.Exists(text))
			{
				testicularTorsionBundle = AssetBundle.LoadFromFile(text);
				if ((Object)(object)testicularTorsionBundle != (Object)null)
				{
					stretchSound = testicularTorsionBundle.LoadAsset<AudioClip>("testesStretch");
					if ((Object)(object)stretchSound == (Object)null)
					{
						Debug.LogWarning((object)"[TesticularTorsion] Could not find 'stretch' audio clip in AssetBundle");
					}
					flashSound = testicularTorsionBundle.LoadAsset<AudioClip>("flashbang");
					if ((Object)(object)flashSound == (Object)null)
					{
						Debug.LogWarning((object)"[TesticularTorsion] Could not find 'flash' audio clip in AssetBundle");
					}
				}
				else
				{
					Debug.LogError((object)"[TesticularTorsion] Failed to load AssetBundle");
				}
			}
			else
			{
				Debug.LogError((object)("[TesticularTorsion] AssetBundle file does not exist at path: " + text));
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TesticularTorsion] Error loading AssetBundle: " + ex.Message));
		}
	}
}