Decompiled source of Chaos Mod v1.0.2

ChaosMod.dll

Decompiled 6 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ChaosMod.Activator;
using ChaosMod.Activator.Activators;
using ChaosMod.Effects;
using ChaosMod.Patches;
using ChaosMod.Twitch;
using ChaosMod.Utils;
using ChaosMod.WebServer;
using GameNetcodeStuff;
using HarmonyLib;
using TMPro;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ChaosMod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ChaosMod")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ccf8b636-9ef1-4e0a-8427-16098d9a92d3")]
[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 ChaosMod
{
	[BepInPlugin("SliceCraft.ChaosMod", "Chaos Mod", "1.0.0")]
	public class ChaosMod : BaseUnityPlugin
	{
		private const string modGUID = "SliceCraft.ChaosMod";

		private const string modName = "Chaos Mod";

		private const string modVersion = "1.0.0";

		public static ConfigEntry<int> ConfigTimeBetweenEffects;

		public static ConfigEntry<string> ConfigActivator;

		public static ConfigEntry<int> ConfigDelayBeforeSpawn;

		public static ConfigEntry<string> ConfigTwitchOptionsShowcase;

		public string twitchOauthToken;

		public string twitchOauthUsername;

		private readonly Harmony harmony = new Harmony("SliceCraft.ChaosMod");

		private static ChaosMod Instance;

		internal ManualLogSource logsource;

		internal TwitchIRCClient twitchIRCClient;

		internal HttpServer webServer;

		public static ChaosMod getInstance()
		{
			return Instance;
		}

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			logsource = Logger.CreateLogSource("SliceCraft.ChaosMod");
			harmony.PatchAll(typeof(ChaosMod));
			harmony.PatchAll(typeof(MenuManagerPatch));
			harmony.PatchAll(typeof(StartOfRoundPatch));
			harmony.PatchAll(typeof(PlayerControllerBPatch));
			harmony.PatchAll(typeof(RoundManagerPatch));
			harmony.PatchAll(typeof(GameNetworkManagerPatch));
			logsource.LogInfo((object)"Chaos Mod loaded");
			webServer = new HttpServer();
			ConfigTimeBetweenEffects = ((BaseUnityPlugin)this).Config.Bind<int>("Timer", "TimeBetweenEffects", 30, "The amount of time between choosing what effect to execute next.");
			ConfigActivator = ((BaseUnityPlugin)this).Config.Bind<string>("Timer", "Activator", "random", "The system that chooses how effects are chosen. Available activators: 'random', 'twitch'");
			ConfigDelayBeforeSpawn = ((BaseUnityPlugin)this).Config.Bind<int>("EnemySpawns", "DelayBeforeSpawn", 3, "The amount of seconds that will be waited when spawning enemies. Value can't be changed to above 10, if the value is above 10 it will still use 10 seconds. This it to prevent monsters from insta killing the player. This delay does not apply for every spawn effect, this does not apply to YIPPEEE for example.");
			ConfigTwitchOptionsShowcase = ((BaseUnityPlugin)this).Config.Bind<string>("Twitch", "OptionsShowcase", "onscreen", "The way voting options will be shown to the chat. Available options are: 'onscreen', 'chatmessage'");
		}
	}
}
namespace ChaosMod.WebServer
{
	internal class HttpServer
	{
		private HttpListener listener;

		public bool IsEnabled { get; }

		public bool IsSupported { get; }

		public HttpServer()
		{
			if (!HttpListener.IsSupported)
			{
				ChaosMod.getInstance().logsource.LogInfo((object)"HttpListener is not supported");
				return;
			}
			ChaosMod.getInstance().logsource.LogInfo((object)"Attempting to start httpserver");
			IsSupported = true;
			listener = new HttpListener();
			listener.Prefixes.Add("http://localhost:8000/");
			listener.Start();
			listener.BeginGetContext(HandleContext, null);
			ChaosMod.getInstance().logsource.LogInfo((object)"Httpserver running");
		}

		public void HandleContext(IAsyncResult iftAr)
		{
			ChaosMod.getInstance().logsource.LogInfo((object)"Received request");
			HttpListenerContext httpListenerContext = listener.EndGetContext(iftAr);
			listener.BeginGetContext(HandleContext, null);
			HttpListenerResponse response = httpListenerContext.Response;
			HttpListenerRequest request = httpListenerContext.Request;
			switch (request.Url.AbsolutePath)
			{
			case "/":
				HandleMainPage(httpListenerContext, request, response);
				break;
			case "/oauth":
				HandleOauthPage(httpListenerContext, request, response);
				break;
			case "/finished":
				HandleFinishedPage(httpListenerContext, request, response);
				break;
			case "/api":
				HandleAPI(httpListenerContext, request, response);
				break;
			default:
				HandleNotFound(httpListenerContext, request, response);
				break;
			}
			ChaosMod.getInstance().logsource.LogInfo((object)request.Url.AbsolutePath);
		}

		private void HandleMainPage(HttpListenerContext context, HttpListenerRequest request, HttpListenerResponse response)
		{
			WriteResponse(response, "<html><body><script>window.location.href='https://id.twitch.tv/oauth2/authorize?client_id=sq2intgw715qqv89nwhf12o8fl4o3u&redirect_uri=http://localhost:8000/oauth&response_type=token&scope=chat:read+chat:edit';</script></body></html>");
		}

		private void HandleOauthPage(HttpListenerContext context, HttpListenerRequest request, HttpListenerResponse response)
		{
			WriteResponse(response, "<html><body><p>Authenticating!</p><script>fetch(\"https://api.twitch.tv/helix/users\", {method: 'get',headers: new Headers({'Authorization': 'Bearer ' + document.location.hash.split('=')[1].split('&')[0],'Client-Id': 'sq2intgw715qqv89nwhf12o8fl4o3u'})}).then(res => {res.json().then(json => {fetch('http://localhost:8000/api?token=' + document.location.hash.split('=')[1].split('&')[0] + '&username=' + json.data[0].login).then(() => {document.location.href='http://localhost:8000/finished'});});});</script></body></html>");
		}

		private void HandleFinishedPage(HttpListenerContext context, HttpListenerRequest request, HttpListenerResponse response)
		{
			WriteResponse(response, "<html><body><p>Authenticated with Twitch, you can close this page!</p></body></html>");
		}

		private void HandleAPI(HttpListenerContext context, HttpListenerRequest request, HttpListenerResponse response)
		{
			ChaosMod.getInstance().twitchOauthToken = "oauth:" + request.QueryString.Get("token");
			ChaosMod.getInstance().twitchOauthUsername = request.QueryString.Get("username");
			ChaosMod.getInstance().twitchIRCClient?.Disconnect();
			if (TimerSystem.GetEnabled())
			{
				ChaosMod.getInstance().twitchIRCClient = new TwitchIRCClient();
				ChaosMod.getInstance().twitchIRCClient.ConnectToTwitch();
			}
			WriteResponse(response, "<html><body><p>Authenticated with Twitch, you can close this page! If the mod doesn't start please press Ctrl + P</p></body></html>");
		}

		private void HandleNotFound(HttpListenerContext context, HttpListenerRequest request, HttpListenerResponse response)
		{
			WriteResponse(response, "<html><body><p>Page wasn't found!</p></body></html>");
		}

		private void WriteResponse(HttpListenerResponse response, string responseString)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(responseString);
			response.ContentLength64 = bytes.Length;
			Stream outputStream = response.OutputStream;
			outputStream.Write(bytes, 0, bytes.Length);
			outputStream.Close();
		}
	}
}
namespace ChaosMod.Utils
{
	internal class ReflectionUtil
	{
		public static void CallFunction(object o, string methodName, params object[] args)
		{
			o.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(o, args);
		}
	}
	internal class SpawnEnemyUtil
	{
		public static void SpawnEnemy(Vector3 enemyPos, int? enemyNumber, int enemySpawns = 1, bool spawnInside = true)
		{
			//IL_004e: 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)
			if (!enemyNumber.HasValue)
			{
				Random random = new Random();
				enemyNumber = random.Next(RoundManager.Instance.currentLevel.Enemies.Count);
			}
			if (spawnInside)
			{
				SpawnEnemyInside(enemyPos, enemyNumber.Value, enemySpawns);
			}
			else
			{
				SpawnEnemyOutside(enemyPos, enemyNumber.Value, enemySpawns);
			}
		}

		private static void SpawnEnemyInside(Vector3 enemyPos, int enemyNumber, int enemySpawns = 1)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < enemySpawns; i++)
			{
				RoundManager.Instance.SpawnEnemyOnServer(enemyPos, 0f, enemyNumber);
			}
		}

		private static void SpawnEnemyOutside(Vector3 enemyPos, int enemyNumber, int enemySpawns = 1)
		{
			//IL_002b: 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)
			Random random = new Random();
			int num = random.Next(RoundManager.Instance.insideAINodes.Length);
			Vector3 position = RoundManager.Instance.insideAINodes[num].transform.position;
			SpawnEnemyInside(position, enemyNumber, enemySpawns);
		}
	}
}
namespace ChaosMod.Twitch
{
	internal class TwitchIRCClient
	{
		private TcpClient Twitch;

		private StreamReader Reader;

		private StreamWriter Writer;

		private const string URL = "irc.chat.twitch.tv";

		private const int PORT = 6697;

		private string User = ChaosMod.getInstance().twitchOauthUsername;

		private string OAuth = ChaosMod.getInstance().twitchOauthToken;

		private string Channel = ChaosMod.getInstance().twitchOauthUsername;

		private Timer task = null;

		public void ConnectToTwitch()
		{
			if (ChaosMod.getInstance().twitchOauthToken == null || ChaosMod.getInstance().twitchOauthUsername == null)
			{
				ChaosMod.getInstance().twitchIRCClient = null;
				HUDManager.Instance.DisplayTip("Twitch Error", "Chaos Mod has not been authenticated with Twitch. Open the webpage by pressing CTRL+I or go to http://localhost:8000", true, false, "LC_Tip1");
				TimerSystem.Disable();
				return;
			}
			Twitch = new TcpClient("irc.chat.twitch.tv", 6697);
			SslStream sslStream = new SslStream(Twitch.GetStream(), leaveInnerStreamOpen: false, ValidateServerCertificate, null);
			sslStream.AuthenticateAsClient("irc.chat.twitch.tv");
			Reader = new StreamReader(sslStream);
			Writer = new StreamWriter(sslStream);
			Writer.WriteLine("PASS " + OAuth);
			Writer.WriteLine("NICK " + User);
			Writer.WriteLine("JOIN #" + Channel);
			Writer.Flush();
			task = new Timer(SendPing, null, 30000, 30000);
		}

		public void Update()
		{
			if (Twitch == null)
			{
				return;
			}
			while (Twitch.Available > 0)
			{
				string text = Reader.ReadLine();
				ChaosMod.getInstance().logsource.LogInfo((object)text);
				if (text.StartsWith("PING"))
				{
					Writer.WriteLine("PONG" + text.Substring(4));
					Writer.Flush();
					break;
				}
				if (TimerSystem.GetActivator() == null || !TimerSystem.GetActivator().getName().Equals("twitch") || text.Split(new char[1] { ':' }).Length < 3)
				{
					break;
				}
				string sender = text.Split(new char[1] { ':' })[1].Split(new char[1] { '!' })[0];
				string text2 = text.Split(new char[1] { ':' })[2];
				if (((TwitchActivator)TimerSystem.GetActivator()).highNumbers)
				{
					if (text2.Equals("4"))
					{
						((TwitchActivator)TimerSystem.GetActivator()).VoteEffect(sender, 0);
					}
					else if (text2.Equals("5"))
					{
						((TwitchActivator)TimerSystem.GetActivator()).VoteEffect(sender, 1);
					}
					else if (text2.Equals("6"))
					{
						((TwitchActivator)TimerSystem.GetActivator()).VoteEffect(sender, 2);
					}
				}
				else if (text2.Equals("1"))
				{
					((TwitchActivator)TimerSystem.GetActivator()).VoteEffect(sender, 0);
				}
				else if (text2.Equals("2"))
				{
					((TwitchActivator)TimerSystem.GetActivator()).VoteEffect(sender, 1);
				}
				else if (text2.Equals("3"))
				{
					((TwitchActivator)TimerSystem.GetActivator()).VoteEffect(sender, 2);
				}
			}
		}

		public void SendPing(object o)
		{
			ChaosMod.getInstance().logsource.LogInfo((object)"Sending ping");
			Writer.WriteLine("PING");
			Writer.Flush();
		}

		public void sendMessage(string message)
		{
			Writer.WriteLine("PRIVMSG #" + Channel + " :" + message);
			Writer.Flush();
		}

		public void Disconnect()
		{
			Twitch.Close();
		}

		private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
		{
			return sslPolicyErrors == SslPolicyErrors.None;
		}
	}
}
namespace ChaosMod.Patches
{
	[HarmonyPatch(typeof(GameNetworkManager))]
	internal class GameNetworkManagerPatch
	{
		[HarmonyPatch("StartHost")]
		[HarmonyPostfix]
		private static void StartHostPatch()
		{
			if ((ChaosMod.getInstance().twitchOauthToken == null || ChaosMod.getInstance().twitchOauthUsername == null) && ChaosMod.ConfigActivator.Value == "twitch")
			{
				Application.OpenURL("http://localhost:8000");
			}
		}

		[HarmonyPatch("Disconnect")]
		[HarmonyPostfix]
		private static void DisconnectPatch()
		{
			TimerSystem.Disable();
		}
	}
	[HarmonyPatch(typeof(MenuManager))]
	internal class MenuManagerPatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPrefix]
		private static void AwakePatch()
		{
			if (ChaosMod.ConfigTwitchOptionsShowcase.Value == "newwindow")
			{
				Display.displays[1].Activate();
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal class PlayerControllerBPatch
	{
		private static bool infinitSprintEnabled;

		private static bool noStaminaEnabled;

		private static bool oneHitExplode;

		private static bool singleUseFallImmunity;

		private static bool isInvincible;

		private static Landmine explodeQueued;

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void infiniteSprintPatch(ref float ___sprintMeter)
		{
			if (!infinitSprintEnabled || !noStaminaEnabled)
			{
				if (infinitSprintEnabled)
				{
					___sprintMeter = 1f;
				}
				else if (noStaminaEnabled)
				{
					___sprintMeter = 0f;
				}
			}
			if ((Object)(object)explodeQueued != (Object)null)
			{
				explodeQueued.ExplodeMineServerRpc();
			}
		}

		[HarmonyPatch("KillPlayer")]
		[HarmonyPostfix]
		private static void KillPlayerPatch()
		{
			if (GameNetworkManager.Instance.localPlayerController.isPlayerDead)
			{
				TimerSystem.Disable();
			}
		}

		[HarmonyPatch("DamagePlayer")]
		[HarmonyPostfix]
		private static void DamagePlayerPatch()
		{
			//IL_0071: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!oneHitExplode)
			{
				return;
			}
			SpawnableMapObject[] spawnableMapObjects = StartOfRound.Instance.currentLevel.spawnableMapObjects;
			if (spawnableMapObjects.Length == 0)
			{
				return;
			}
			SpawnableMapObject[] array = spawnableMapObjects;
			foreach (SpawnableMapObject val in array)
			{
				if ((Object)(object)val.prefabToSpawn.GetComponentInChildren<Landmine>() != (Object)null)
				{
					GameObject val2 = Object.Instantiate<GameObject>(val.prefabToSpawn, ((Component)GameNetworkManager.Instance.localPlayerController.thisPlayerBody).transform.position, Quaternion.Euler(Vector3.zero));
					val2.SetActive(true);
					val2.GetComponent<NetworkObject>().Spawn(true);
					val2.GetComponentInChildren<Landmine>().ExplodeMineServerRpc();
					val2.GetComponentInChildren<Landmine>().Detonate();
					break;
				}
			}
		}

		[HarmonyPatch("PlayerHitGroundEffects")]
		[HarmonyPrefix]
		private static void PlayerHitGroundEffectsPatch()
		{
			if (singleUseFallImmunity)
			{
				GameNetworkManager.Instance.localPlayerController.ResetFallGravity();
				singleUseFallImmunity = false;
			}
		}

		[HarmonyPatch("AllowPlayerDeath")]
		[HarmonyPrefix]
		private static bool AllowPlayerDeathPatch(ref bool __result)
		{
			if (isInvincible)
			{
				__result = false;
				return false;
			}
			return true;
		}

		public static void setInfiniteSprint(bool set)
		{
			infinitSprintEnabled = set;
		}

		public static void SetNoStamina(bool set)
		{
			noStaminaEnabled = set;
		}

		public static void setOneHitExplode(bool set)
		{
			oneHitExplode = set;
		}

		public static void SetSingleUseFallImmunity(bool set)
		{
			singleUseFallImmunity = set;
		}

		public static void SetInvincible(bool set)
		{
			isInvincible = set;
		}
	}
	[HarmonyPatch(typeof(RoundManager))]
	internal class RoundManagerPatch
	{
		private static KeyboardShortcut shortcut1 = new KeyboardShortcut((KeyCode)112, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 });

		private static KeyboardShortcut shortcut2 = new KeyboardShortcut((KeyCode)111, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 });

		private static KeyboardShortcut shortcut3 = new KeyboardShortcut((KeyCode)105, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 });

		[HarmonyPatch("Update")]
		[HarmonyPrefix]
		private static void UpdatePatch()
		{
			TimerSystem.Update();
			bool flag = StartOfRound.Instance.currentLevelID != 3;
			bool flag2 = !GameNetworkManager.Instance.localPlayerController.isPlayerDead;
			bool flag3 = !StartOfRound.Instance.inShipPhase;
			if (((KeyboardShortcut)(ref shortcut1)).IsDown() && flag && flag2 && flag3 && GameNetworkManager.Instance.isHostingGame)
			{
				TimerSystem.Disable();
				HUDManager.Instance.DisplayTip("Chaos Mod", "The mod has been reset", false, false, "LC_Tip1");
				TimerSystem.Enable();
			}
			if (((KeyboardShortcut)(ref shortcut2)).IsDown())
			{
				TimerSystem.Disable();
				HUDManager.Instance.DisplayTip("Chaos Mod", "The mod has been turned off. Turn on with Ctrl + P", false, false, "LC_Tip1");
			}
			if (((KeyboardShortcut)(ref shortcut3)).IsDown() && ChaosMod.ConfigActivator.Value == "twitch")
			{
				Application.OpenURL("http://localhost:8000");
			}
			ChaosMod.getInstance().twitchIRCClient?.Update();
			if (TimerSystem.GetActivator() != null && TimerSystem.GetActivator().getName().Equals("twitch"))
			{
				((TwitchActivator)TimerSystem.GetActivator()).RefreshEffectText();
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal class StartOfRoundPatch
	{
		[HarmonyPatch("openingDoorsSequence")]
		[HarmonyPrefix]
		private static void openingDoorsSequencePatch()
		{
			if (StartOfRound.Instance.currentLevelID != 3 && GameNetworkManager.Instance.isHostingGame && !GameNetworkManager.Instance.localPlayerController.isPlayerDead)
			{
				TimerSystem.Enable();
			}
		}

		[HarmonyPatch("EndGameServerRpc")]
		[HarmonyPostfix]
		private static void EndGameServerRpcPatch()
		{
			TimerSystem.Disable();
		}
	}
}
namespace ChaosMod.Effects
{
	internal class DamageRouletteEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Damage Roulette";
		}

		public override void StartEffect()
		{
			//IL_007b: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			Random random = new Random();
			if (GameNetworkManager.Instance.localPlayerController.health < 25 && random.Next(101) < 50)
			{
				Landmine.SpawnExplosion(GameNetworkManager.Instance.localPlayerController.thisPlayerBody.position, false, 1f, 1f, 50, 0f, (GameObject)null);
				return;
			}
			int num = random.Next(30);
			GameNetworkManager.Instance.localPlayerController.DamagePlayer(11 + num, true, true, (CauseOfDeath)0, 0, false, default(Vector3));
		}
	}
	internal class DisableControlsEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Disable Controls";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 10000L;
		}

		public override void StartEffect()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			MovementActions movement = GameNetworkManager.Instance.localPlayerController.playerActions.Movement;
			((MovementActions)(ref movement)).Disable();
			IngamePlayerSettings.Instance.playerInput.actions.Disable();
		}

		public override void StopEffect()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			MovementActions movement = GameNetworkManager.Instance.localPlayerController.playerActions.Movement;
			((MovementActions)(ref movement)).Enable();
			IngamePlayerSettings.Instance.playerInput.actions.Enable();
		}
	}
	internal class DropEverythingEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Drop Everything";
		}

		public override void StartEffect()
		{
			GameNetworkManager.Instance.localPlayerController.DropAllHeldItemsAndSync();
		}
	}
	internal class DropHelpfulItemEffect : Effect
	{
		private int itemIndex;

		public DropHelpfulItemEffect()
		{
			Random random = new Random();
			do
			{
				itemIndex = random.Next(StartOfRound.Instance.allItemsList.itemsList.Count);
			}
			while (StartOfRound.Instance.allItemsList.itemsList[itemIndex].isScrap);
		}

		public override string GetEffectName()
		{
			return "Drop " + StartOfRound.Instance.allItemsList.itemsList[itemIndex].itemName;
		}

		public override void StartEffect()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(StartOfRound.Instance.allItemsList.itemsList[itemIndex].spawnPrefab, GameNetworkManager.Instance.localPlayerController.thisPlayerBody.position, Quaternion.identity, StartOfRound.Instance.propsContainer);
			val.GetComponent<GrabbableObject>().fallTime = 0f;
			val.GetComponent<NetworkObject>().Spawn(false);
		}
	}
	internal class DropScrapEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Drop Scrap";
		}

		public override void StartEffect()
		{
			//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)
			for (int i = 0; i < 2; i++)
			{
				Random random = new Random();
				int index;
				do
				{
					index = random.Next(StartOfRound.Instance.allItemsList.itemsList.Count);
				}
				while (!StartOfRound.Instance.allItemsList.itemsList[index].isScrap);
				GameObject val = Object.Instantiate<GameObject>(StartOfRound.Instance.allItemsList.itemsList[index].spawnPrefab, GameNetworkManager.Instance.localPlayerController.thisPlayerBody.position, Quaternion.identity, StartOfRound.Instance.propsContainer);
				val.GetComponent<GrabbableObject>().fallTime = 0f;
				val.GetComponent<GrabbableObject>().SetScrapValue(50);
				val.GetComponent<NetworkObject>().Spawn(false);
			}
		}
	}
	internal class EnemiesVoteToLeaveEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Enemies vote to leave";
		}

		public override void StartEffect()
		{
			TimeOfDay.Instance.VoteShipToLeaveEarly();
		}

		public override bool IsAllowedToRun()
		{
			return TimeOfDay.Instance.currentDayTime >= 540f;
		}
	}
	internal class ExtraDayEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Extra Day";
		}

		public override void StartEffect()
		{
			TimeOfDay instance = TimeOfDay.Instance;
			instance.timeUntilDeadline += TimeOfDay.Instance.totalTime;
			HUDManager.Instance.DisplayDaysLeft((int)Mathf.Floor(TimeOfDay.Instance.timeUntilDeadline / TimeOfDay.Instance.totalTime));
			ReflectionUtil.CallFunction(TimeOfDay.Instance, "SyncGlobalTimeOnNetwork", null);
		}

		public override bool IsAllowedToRun()
		{
			return ChaosMod.ConfigActivator.Value != "random";
		}
	}
	internal class FasterEffectsEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Faster Effects";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 40000L;
		}

		public override void StartEffect()
		{
			TimerSystem.SetHalfEffectTime(set: true);
		}

		public override void StopEffect()
		{
			TimerSystem.SetHalfEffectTime(set: false);
			TimerSystem.SetLastTimerRun(TimerSystem.GetLastTimerRun() - ChaosMod.ConfigTimeBetweenEffects.Value / 2 * 1000);
		}
	}
	internal class HealEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Heal";
		}

		public override void StartEffect()
		{
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			localPlayerController.health += 40;
			if (GameNetworkManager.Instance.localPlayerController.health > 100)
			{
				GameNetworkManager.Instance.localPlayerController.health = 100;
			}
			GameNetworkManager.Instance.localPlayerController.HealServerRpc();
			HUDManager.Instance.UpdateHealthUI(GameNetworkManager.Instance.localPlayerController.health, false);
		}
	}
	internal class InfiniteSprintEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Infinite Sprint";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 20000L;
		}

		public override void StartEffect()
		{
			PlayerControllerBPatch.setInfiniteSprint(set: true);
		}

		public override void StopEffect()
		{
			PlayerControllerBPatch.setInfiniteSprint(set: false);
		}
	}
	internal class InvinicibilityEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Invinicibility";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 20000L;
		}

		public override void StartEffect()
		{
			PlayerControllerBPatch.SetInvincible(set: true);
		}

		public override void StopEffect()
		{
			PlayerControllerBPatch.SetInvincible(set: false);
		}
	}
	internal class InvisibleEnemiesEffect : Effect
	{
		private List<EnemyAI> enemies = new List<EnemyAI>();

		public override string GetEffectName()
		{
			return "Invisible Enemies";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 20000L;
		}

		public override void StartEffect()
		{
			List<EnemyAI> list = Object.FindObjectsOfType<EnemyAI>().ToList();
			foreach (EnemyAI item in list)
			{
				if (!item.isEnemyDead)
				{
					enemies.Add(item);
					for (int i = 0; i < item.skinnedMeshRenderers.Length; i++)
					{
						((Component)item.skinnedMeshRenderers[i]).gameObject.SetActive(false);
					}
				}
			}
		}

		public override void StopEffect()
		{
			foreach (EnemyAI enemy in enemies)
			{
				if (!enemy.isEnemyDead)
				{
					for (int i = 0; i < enemy.skinnedMeshRenderers.Length; i++)
					{
						((Component)enemy.skinnedMeshRenderers[i]).gameObject.SetActive(true);
					}
				}
			}
		}
	}
	internal class NoStaminaEffect : Effect
	{
		public override string GetEffectName()
		{
			return "No Stamina";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 20000L;
		}

		public override void StartEffect()
		{
			PlayerControllerBPatch.SetNoStamina(set: true);
		}

		public override void StopEffect()
		{
			PlayerControllerBPatch.SetNoStamina(set: false);
		}
	}
	internal class OneHitExplosionsEffect : Effect
	{
		public override string GetEffectName()
		{
			return "One Hit Explode";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 30000L;
		}

		public override void StartEffect()
		{
			PlayerControllerBPatch.setOneHitExplode(set: true);
		}

		public override void StopEffect()
		{
			PlayerControllerBPatch.setOneHitExplode(set: false);
		}

		public override bool IsAllowedToRun()
		{
			return true;
		}
	}
	internal class RandomEffectEffect : Effect
	{
		private bool effectStarted = false;

		private Effect effect = null;

		public RandomEffectEffect()
		{
			Random random = new Random();
			Array values = Enum.GetValues(typeof(AllEffects.Effects));
			Effect effect;
			do
			{
				AllEffects.Effects effects = (AllEffects.Effects)values.GetValue(random.Next(values.Length));
				effect = AllEffects.InstantiateEffect(effects);
			}
			while (effect != null && !effect.IsAllowedToRun());
			this.effect = effect;
		}

		public override void ResetEffectStartTime()
		{
			effect?.ResetEffectStartTime();
		}

		public override long GetEffectLength()
		{
			if (effectStarted)
			{
				return effect.GetEffectLength();
			}
			return 0L;
		}

		public override long GetEffectStartTime()
		{
			if (effectStarted)
			{
				return effect.GetEffectStartTime();
			}
			return 0L;
		}

		public override void StartEffect()
		{
			effectStarted = true;
			effect.StartEffect();
		}

		public override void StopEffect()
		{
			if (effectStarted)
			{
				effect.StopEffect();
			}
		}

		public override void UpdateEffect()
		{
			if (effectStarted)
			{
				effect.UpdateEffect();
			}
		}

		public override bool IsAllowedToRun()
		{
			if (effectStarted)
			{
				return effect.IsAllowedToRun();
			}
			return true;
		}

		public override string GetEffectName()
		{
			if (effectStarted)
			{
				return effect.GetEffectName();
			}
			return "Random Effect";
		}

		public override bool IsTimedEffect()
		{
			if (effectStarted)
			{
				return effect.IsTimedEffect();
			}
			return false;
		}
	}
	internal class RandomOutfitEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Random Outfit";
		}

		public override void StartEffect()
		{
			List<UnlockableSuit> list = Object.FindObjectsOfType<UnlockableSuit>().ToList();
			Random random = new Random();
			int index = random.Next(list.Count);
			list[index].SwitchSuitToThis(GameNetworkManager.Instance.localPlayerController);
			UnlockableSuit.SwitchSuitForPlayer(GameNetworkManager.Instance.localPlayerController, list[index].syncedSuitID.Value, true);
		}
	}
	internal class RandomTeleportEffect : Effect
	{
		private bool fakeTeleport = false;

		private Vector3 oldPosition;

		private bool oldInside;

		private string effectName = "Random Teleport";

		public RandomTeleportEffect()
		{
			Random random = new Random();
			int num = random.Next(100);
			if (num > 80)
			{
				fakeTeleport = true;
			}
		}

		public override string GetEffectName()
		{
			return effectName;
		}

		public override bool IsTimedEffect()
		{
			return fakeTeleport;
		}

		public override long GetEffectLength()
		{
			return 3000L;
		}

		public override bool HideEffectTimer()
		{
			return true;
		}

		public override void StartEffect()
		{
			//IL_0066: 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_0086: 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)
			if (fakeTeleport)
			{
				oldPosition = ((Component)GameNetworkManager.Instance.localPlayerController).transform.position;
				oldInside = GameNetworkManager.Instance.localPlayerController.isInsideFactory;
			}
			Random random = new Random();
			int num = random.Next(RoundManager.Instance.insideAINodes.Length);
			Vector3 position = RoundManager.Instance.insideAINodes[num].transform.position;
			GameNetworkManager.Instance.localPlayerController.isInsideFactory = true;
			GameNetworkManager.Instance.localPlayerController.TeleportPlayer(position, false, 0f, false, true);
		}

		public override void StopEffect()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (fakeTeleport)
			{
				GameNetworkManager.Instance.localPlayerController.isInsideFactory = oldInside;
				GameNetworkManager.Instance.localPlayerController.TeleportPlayer(oldPosition, false, 0f, false, true);
				effectName = "Fake Teleport";
			}
		}
	}
	internal class RemoveHolidingItemsEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Remove Holding Items";
		}

		public override void StartEffect()
		{
			for (int i = 0; i < GameNetworkManager.Instance.localPlayerController.ItemSlots.Count(); i++)
			{
				if (!((Object)(object)GameNetworkManager.Instance.localPlayerController.ItemSlots[i] == (Object)null))
				{
					GameNetworkManager.Instance.localPlayerController.DestroyItemInSlotAndSync(i);
				}
			}
			GameNetworkManager.Instance.localPlayerController.DropAllHeldItemsAndSync();
			GameNetworkManager.Instance.localPlayerController.carryWeight = 1f;
		}
	}
	internal class SpawnEnemyEffect : Effect
	{
		private readonly int enemyNumber;

		public SpawnEnemyEffect()
		{
			Random random = new Random();
			enemyNumber = random.Next(RoundManager.Instance.currentLevel.Enemies.Count);
		}

		public override string GetEffectName()
		{
			return "Spawn " + ((Object)RoundManager.Instance.currentLevel.Enemies[enemyNumber].enemyType).name;
		}

		public override void StartEffect()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			SpawnEnemyUtil.SpawnEnemy(TimerSystem.GetPositionTracker().GetOldPosition(ChaosMod.ConfigDelayBeforeSpawn.Value), enemyNumber, 1, GameNetworkManager.Instance.localPlayerController.isInsideFactory);
		}

		public override void StopEffect()
		{
		}
	}
	internal class AttractivePlayerEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Attractive Player";
		}

		public override void StartEffect()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			bool isInsideFactory = GameNetworkManager.Instance.localPlayerController.isInsideFactory;
			List<EnemyAI> list = Object.FindObjectsOfType<EnemyAI>().ToList();
			foreach (EnemyAI item in list)
			{
				if (((isInsideFactory && !item.isOutside) || (!isInsideFactory && item.isOutside)) && !item.isEnemyDead)
				{
					item.SetMovingTowardsTargetPlayer(GameNetworkManager.Instance.localPlayerController);
					item.SetDestinationToPosition(((Component)GameNetworkManager.Instance.localPlayerController).transform.position, true);
				}
			}
		}
	}
	internal class SpinningEnemiesEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Spinning Enemies";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 20000L;
		}

		public override void UpdateEffect()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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)
			List<EnemyAI> list = Object.FindObjectsOfType<EnemyAI>().ToList();
			foreach (EnemyAI item in list)
			{
				if (!item.isEnemyDead)
				{
					((Component)item).gameObject.transform.eulerAngles = new Vector3(((Component)item).gameObject.transform.eulerAngles.x, ((Component)item).gameObject.transform.eulerAngles.y + 50f, ((Component)item).gameObject.transform.eulerAngles.z);
				}
			}
		}
	}
	internal class SuperJumpEffect : Effect
	{
		private float oldForce = 5f;

		public override string GetEffectName()
		{
			return "Super Jump";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 20000L;
		}

		public override void StartEffect()
		{
			oldForce = GameNetworkManager.Instance.localPlayerController.jumpForce;
			GameNetworkManager.Instance.localPlayerController.jumpForce = 40f;
			PlayerControllerBPatch.SetSingleUseFallImmunity(set: true);
		}

		public override void UpdateEffect()
		{
			PlayerControllerBPatch.SetSingleUseFallImmunity(set: true);
		}

		public override void StopEffect()
		{
			GameNetworkManager.Instance.localPlayerController.jumpForce = oldForce;
			if (GameNetworkManager.Instance.localPlayerController.thisController.isGrounded)
			{
				PlayerControllerBPatch.SetSingleUseFallImmunity(set: false);
			}
		}
	}
	internal class TeleportToHeavenEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Teleport To Heaven";
		}

		public override void StartEffect()
		{
			//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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			if (GameNetworkManager.Instance.localPlayerController.isInsideFactory)
			{
				GameNetworkManager.Instance.localPlayerController.isInsideFactory = false;
				GameNetworkManager.Instance.localPlayerController.TeleportPlayer(new Vector3(0f, 700f, 0f), false, 0f, false, true);
				PlayerControllerBPatch.SetSingleUseFallImmunity(set: true);
			}
			else
			{
				Vector3 position = GameNetworkManager.Instance.localPlayerController.thisPlayerBody.position;
				GameNetworkManager.Instance.localPlayerController.TeleportPlayer(new Vector3(position.x, position.y + 700f, position.z), false, 0f, false, true);
				PlayerControllerBPatch.SetSingleUseFallImmunity(set: true);
			}
		}
	}
	internal class TeleportToShipEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Teleport to Ship";
		}

		public override void StartEffect()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			GameNetworkManager.Instance.localPlayerController.isInsideFactory = false;
			GameNetworkManager.Instance.localPlayerController.TeleportPlayer(StartOfRound.Instance.playerSpawnPositions[0].position, false, 0f, false, true);
		}
	}
	internal class UnlockUnlockableEffect : Effect
	{
		public override string GetEffectName()
		{
			return "Unlock Ship Upgrade";
		}

		public override void StartEffect()
		{
			bool flag = false;
			for (int i = 0; i < StartOfRound.Instance.unlockablesList.unlockables.Count; i++)
			{
				if (!StartOfRound.Instance.unlockablesList.unlockables[i].alreadyUnlocked && !StartOfRound.Instance.unlockablesList.unlockables[i].hasBeenUnlockedByPlayer)
				{
					flag = true;
				}
			}
			if (!flag)
			{
				HUDManager.Instance.DisplayTip("Random unlock", "All upgrades have already been unlocked so couldn't unlock any more :(", false, false, "LC_Tip1");
				return;
			}
			int num;
			UnlockableItem val;
			do
			{
				Random random = new Random();
				num = random.Next(StartOfRound.Instance.unlockablesList.unlockables.Count);
				val = StartOfRound.Instance.unlockablesList.unlockables[num];
				ChaosMod.getInstance().logsource.LogInfo((object)val.unlockableName);
			}
			while (val.alreadyUnlocked || val.hasBeenUnlockedByPlayer);
			StartOfRound.Instance.BuyShipUnlockableServerRpc(num, Object.FindObjectOfType<Terminal>().groupCredits);
		}

		public override void StopEffect()
		{
		}
	}
	internal class UTurnEffect : Effect
	{
		public override string GetEffectName()
		{
			return "U Turn";
		}

		public override void StartEffect()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			GameNetworkManager.Instance.localPlayerController.TeleportPlayer(((Component)GameNetworkManager.Instance.localPlayerController.thisPlayerBody).transform.position, true, ((Component)GameNetworkManager.Instance.localPlayerController.thisPlayerBody).transform.eulerAngles.y + 180f, false, true);
		}
	}
	internal class WarpSpeedEffect : Effect
	{
		private float oldSpeed = 4.6f;

		public override string GetEffectName()
		{
			return "Warp Speed";
		}

		public override bool IsTimedEffect()
		{
			return true;
		}

		public override long GetEffectLength()
		{
			return 30000L;
		}

		public override void StartEffect()
		{
			oldSpeed = GameNetworkManager.Instance.localPlayerController.movementSpeed;
			GameNetworkManager.Instance.localPlayerController.movementSpeed = 20f;
		}

		public override void StopEffect()
		{
			GameNetworkManager.Instance.localPlayerController.movementSpeed = oldSpeed;
		}
	}
	internal class YIPPEEEEEffect : Effect
	{
		public override string GetEffectName()
		{
			return "YIPPEEEE";
		}

		public override void StartEffect()
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			int? enemyNumber = null;
			for (int i = 0; i < RoundManager.Instance.currentLevel.Enemies.Count; i++)
			{
				SpawnableEnemyWithRarity val = RoundManager.Instance.currentLevel.Enemies[i];
				if (val.enemyType.enemyName.Equals("Hoarding bug"))
				{
					enemyNumber = i;
				}
			}
			if (enemyNumber.HasValue)
			{
				SpawnEnemyUtil.SpawnEnemy(GameNetworkManager.Instance.localPlayerController.thisPlayerBody.position, enemyNumber, 10, GameNetworkManager.Instance.localPlayerController.isInsideFactory);
			}
		}
	}
}
namespace ChaosMod.Activator
{
	internal interface Activator
	{
		string getName();

		void Start();

		Effect ChooseEffect();

		void Stop();
	}
	internal class AllActivators
	{
		private static Dictionary<string, Activator> activators;

		static AllActivators()
		{
			activators = new Dictionary<string, Activator>();
			activators.Add("random", new RandomActivator());
			activators.Add("twitch", new TwitchActivator());
		}

		public static Dictionary<string, Activator> GetActivators()
		{
			return activators;
		}
	}
	internal abstract class Effect
	{
		private long effectStartTime = 0L;

		public Effect()
		{
			ResetEffectStartTime();
		}

		public virtual void ResetEffectStartTime()
		{
			effectStartTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
		}

		public virtual long GetEffectLength()
		{
			return 0L;
		}

		public virtual long GetEffectStartTime()
		{
			return effectStartTime;
		}

		public virtual void StartEffect()
		{
		}

		public virtual void StopEffect()
		{
		}

		public virtual void UpdateEffect()
		{
		}

		public virtual bool IsAllowedToRun()
		{
			return true;
		}

		public virtual bool HideEffectTimer()
		{
			return false;
		}

		public abstract string GetEffectName();

		public virtual bool IsTimedEffect()
		{
			return false;
		}
	}
	internal class PositionTracker
	{
		private long lastTimeTracked = 0L;

		private List<Vector3> positionHistory = new List<Vector3>();

		private List<bool> insideHistory = new List<bool>();

		public void Update()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if (lastTimeTracked + 1000 < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
			{
				lastTimeTracked = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
				PushHistoryDown();
				positionHistory.Insert(0, ((Component)GameNetworkManager.Instance.localPlayerController.thisPlayerBody).transform.position);
				insideHistory.Insert(0, GameNetworkManager.Instance.localPlayerController.isInsideFactory);
			}
		}

		public Vector3 GetOldPosition(int secondsAgo)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (secondsAgo > 10)
			{
				secondsAgo = 10;
			}
			if (secondsAgo < 1)
			{
				secondsAgo = 1;
			}
			return positionHistory[secondsAgo - 1];
		}

		public bool GetOldInside(int secondsAgo)
		{
			if (secondsAgo > 10)
			{
				secondsAgo = 10;
			}
			if (secondsAgo < 1)
			{
				secondsAgo = 1;
			}
			return insideHistory[secondsAgo - 1];
		}

		private void PushHistoryDown()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			for (int num = ((positionHistory.Count > 10) ? 9 : (positionHistory.Count - 2)); num >= 0; num--)
			{
				positionHistory[num + 1] = positionHistory[num];
				insideHistory[num + 1] = insideHistory[num];
			}
		}

		public PositionTracker()
		{
			lastTimeTracked = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
		}
	}
	internal class AllEffects
	{
		public enum Effects
		{
			InfiniteSprint,
			SpawnEnemy,
			DamageRoulette,
			Heal,
			RandomTeleport,
			YIPPEEEEE,
			RemoveHoldingItems,
			DropEverything,
			UnlockUnlockable,
			FasterEffects,
			OneHitExplosions,
			AttractivePlayer,
			WarpSpeed,
			DisableControls,
			DropHelpfulItemEffect,
			DropScrapEffect,
			SpinningEnemiesEffect,
			RandomOutfitEffect,
			TeleportToShipEffect,
			NoStaminaEffect,
			EnemiesVoteToLeaveEffect,
			TeleportToHeavenEffect,
			UTurnEffect,
			InvisibleEnemiesEffect,
			ExtraDayEffect
		}

		public static Effect InstantiateEffect(Effects effect)
		{
			return effect switch
			{
				Effects.InfiniteSprint => new InfiniteSprintEffect(), 
				Effects.SpawnEnemy => new SpawnEnemyEffect(), 
				Effects.DamageRoulette => new DamageRouletteEffect(), 
				Effects.Heal => new HealEffect(), 
				Effects.RandomTeleport => new RandomTeleportEffect(), 
				Effects.YIPPEEEEE => new YIPPEEEEEffect(), 
				Effects.RemoveHoldingItems => new RemoveHolidingItemsEffect(), 
				Effects.DropEverything => new DropEverythingEffect(), 
				Effects.UnlockUnlockable => new UnlockUnlockableEffect(), 
				Effects.FasterEffects => new FasterEffectsEffect(), 
				Effects.OneHitExplosions => new OneHitExplosionsEffect(), 
				Effects.AttractivePlayer => new AttractivePlayerEffect(), 
				Effects.WarpSpeed => new WarpSpeedEffect(), 
				Effects.DisableControls => new DisableControlsEffect(), 
				Effects.DropHelpfulItemEffect => new DropHelpfulItemEffect(), 
				Effects.DropScrapEffect => new DropScrapEffect(), 
				Effects.SpinningEnemiesEffect => new SpinningEnemiesEffect(), 
				Effects.RandomOutfitEffect => new RandomOutfitEffect(), 
				Effects.TeleportToShipEffect => new TeleportToShipEffect(), 
				Effects.NoStaminaEffect => new NoStaminaEffect(), 
				Effects.EnemiesVoteToLeaveEffect => new EnemiesVoteToLeaveEffect(), 
				Effects.TeleportToHeavenEffect => new TeleportToHeavenEffect(), 
				Effects.UTurnEffect => new UTurnEffect(), 
				Effects.InvisibleEnemiesEffect => new InvisibleEnemiesEffect(), 
				Effects.ExtraDayEffect => new ExtraDayEffect(), 
				_ => null, 
			};
		}
	}
	internal class TimerSystem
	{
		private static Activator activator = null;

		private static List<Effect> activeEffects = new List<Effect>();

		private static List<Effect> effectHistory = new List<Effect>();

		private static long lastTimerRun = 0L;

		private static bool enabled = false;

		private static PositionTracker positionTracker = null;

		private static TextMeshProUGUI effectText = null;

		private static Camera secondDisplayCamera = null;

		private static bool halfEffectWaitTime = false;

		public static void Update()
		{
			if (!enabled || activator == null || positionTracker == null)
			{
				return;
			}
			positionTracker.Update();
			List<Effect> list = new List<Effect>();
			foreach (Effect activeEffect in activeEffects)
			{
				try
				{
					activeEffect.UpdateEffect();
				}
				catch (Exception ex)
				{
					ChaosMod.getInstance().logsource.LogError((object)ex);
				}
				if (activeEffect.GetEffectLength() + activeEffect.GetEffectStartTime() < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
				{
					try
					{
						activeEffect.StopEffect();
					}
					catch (Exception ex2)
					{
						ChaosMod.getInstance().logsource.LogError((object)ex2);
					}
					list.Add(activeEffect);
				}
			}
			foreach (Effect item in list)
			{
				activeEffects.Remove(item);
			}
			if (lastTimerRun + (halfEffectWaitTime ? (ChaosMod.ConfigTimeBetweenEffects.Value / 2 * 1000) : (ChaosMod.ConfigTimeBetweenEffects.Value * 1000)) < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
			{
				ChaosMod.getInstance().logsource.LogInfo((object)"Choosing effect");
				Effect effect = activator.ChooseEffect();
				bool flag = false;
				foreach (Effect activeEffect2 in activeEffects)
				{
					if (activeEffect2.GetEffectName() == effect.GetEffectName())
					{
						flag = true;
						activeEffect2.ResetEffectStartTime();
						break;
					}
				}
				if (!flag)
				{
					try
					{
						effect.ResetEffectStartTime();
						effect.StartEffect();
					}
					catch (Exception ex3)
					{
						ChaosMod.getInstance().logsource.LogError((object)ex3);
					}
					effectHistory.Add(effect);
					if (effect.IsTimedEffect())
					{
						activeEffects.Add(effect);
					}
				}
				lastTimerRun = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
			}
			UpdateEffectList();
		}

		public static void Enable()
		{
			if (enabled)
			{
				Disable();
			}
			if ((Object)(object)effectText == (Object)null)
			{
				AddTextElement();
			}
			ChaosMod.getInstance().logsource.LogInfo((object)"Enabling the mod");
			if (!AllActivators.GetActivators().ContainsKey(ChaosMod.ConfigActivator.Value))
			{
				HUDManager.Instance.DisplayTip("Chaos Mod", "An invalid activator was specified in the config. Chaos Mod has been disabled!", true, false, "LC_Tip1");
				return;
			}
			activator = AllActivators.GetActivators()[ChaosMod.ConfigActivator.Value];
			lastTimerRun = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
			positionTracker = new PositionTracker();
			enabled = true;
			activator.Start();
		}

		public static void Disable()
		{
			if (!enabled)
			{
				return;
			}
			ChaosMod.getInstance().logsource.LogInfo((object)"Disabling the mod");
			if (ChaosMod.getInstance().twitchIRCClient != null)
			{
				ChaosMod.getInstance().twitchIRCClient.Disconnect();
				ChaosMod.getInstance().twitchIRCClient = null;
			}
			foreach (Effect activeEffect in activeEffects)
			{
				try
				{
					activeEffect.StopEffect();
				}
				catch (Exception ex)
				{
					ChaosMod.getInstance().logsource.LogError((object)ex);
				}
			}
			((TMP_Text)effectText).text = "";
			activator.Stop();
			activator = null;
			positionTracker = null;
			lastTimerRun = 0L;
			activeEffects = new List<Effect>();
			effectHistory = new List<Effect>();
			PlayerControllerBPatch.setInfiniteSprint(set: false);
			PlayerControllerBPatch.SetNoStamina(set: false);
			PlayerControllerBPatch.setOneHitExplode(set: false);
			PlayerControllerBPatch.SetSingleUseFallImmunity(set: false);
			PlayerControllerBPatch.SetInvincible(set: false);
			halfEffectWaitTime = false;
			enabled = false;
		}

		private static void AddTextElement()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject();
			val.transform.parent = HUDManager.Instance.HUDContainer.transform;
			((Object)val).name = "ChaosModEffectHistory";
			Vector3 localScale = val.transform.localScale;
			localScale.x = 1f;
			localScale.y = 1f;
			localScale.z = 1f;
			val.transform.localScale = localScale;
			Vector3 localPosition = val.transform.localPosition;
			localPosition.x = -330f;
			localPosition.y = 40f;
			localPosition.z = 0f;
			val.transform.localPosition = localPosition;
			effectText = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)effectText).text = "";
			((TMP_Text)effectText).fontSize = 15f;
			((TMP_Text)effectText).lineSpacing = 30f;
		}

		private static void UpdateEffectList()
		{
			if (effectHistory.Count == 0)
			{
				return;
			}
			string text = "";
			foreach (Effect activeEffect in activeEffects)
			{
				if (!activeEffect.HideEffectTimer())
				{
					text = text + "(" + (activeEffect.GetEffectStartTime() + activeEffect.GetEffectLength() - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) / 1000 + " sec) " + activeEffect.GetEffectName() + "\n";
				}
			}
			Effect effect = effectHistory[effectHistory.Count - 1];
			if (!effect.IsTimedEffect() || effect.HideEffectTimer())
			{
				text = text + effect.GetEffectName() + "\n";
			}
			((TMP_Text)effectText).text = text;
		}

		public static void UpdateEffectListAdvanced()
		{
			Effect effect = effectHistory[effectHistory.Count - 1];
			if ((activeEffects.Count > 5 && effect.IsTimedEffect()) || (activeEffects.Count > 4 && !effect.IsTimedEffect()))
			{
				string text = "";
				foreach (Effect activeEffect in activeEffects)
				{
					text = text + ((activeEffect.IsTimedEffect() && (activeEffect.GetEffectStartTime() + activeEffect.GetEffectLength() - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + 1000) / 1000 >= 1) ? ("(" + (activeEffect.GetEffectStartTime() + activeEffect.GetEffectLength() - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) / 1000 + " sec) ") : "") + activeEffect.GetEffectName() + "\n";
				}
				if (!effect.IsTimedEffect())
				{
					text = text + ((effect.IsTimedEffect() && (effect.GetEffectStartTime() + effect.GetEffectLength() - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + 1000) / 1000 >= 1) ? ("(" + (effect.GetEffectStartTime() + effect.GetEffectLength() - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) / 1000 + " sec) ") : "") + effect.GetEffectName() + "\n";
				}
				((TMP_Text)effectText).text = text;
				return;
			}
			List<Effect> list = new List<Effect>();
			for (int i = ((effectHistory.Count - 6 >= 0) ? (effectHistory.Count - 6) : 0); i < effectHistory.Count; i++)
			{
				Effect item = effectHistory[i];
				list.Add(item);
			}
			int num = activeEffects.Count - 1;
			while (num >= 0 && !list.Contains(activeEffects[num]))
			{
				int num2 = list.Count - 1;
				if (num2 > list.Count - 6)
				{
					Effect effect2 = list[num2];
					if (effect2.IsTimedEffect())
					{
						PushEffectDownIntoNonTimedAdvanced(list, effect2);
					}
					list[num2] = activeEffects[num];
				}
				num--;
			}
			string text2 = "";
			foreach (Effect item2 in list)
			{
				text2 = text2 + ((item2.IsTimedEffect() && (item2.GetEffectStartTime() + item2.GetEffectLength() - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + 1000) / 1000 >= 1) ? ("(" + (item2.GetEffectStartTime() + item2.GetEffectLength() - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) / 1000 + " sec) ") : "") + item2.GetEffectName() + "\n";
			}
			((TMP_Text)effectText).text = text2;
		}

		private static void PushEffectDownIntoNonTimedAdvanced(List<Effect> effectList, Effect effect)
		{
			bool flag = false;
			for (int num = effectList.Count - 1; num > 0; num--)
			{
				if (flag)
				{
					if (effectList[num].IsTimedEffect())
					{
						PushEffectDownIntoNonTimedAdvanced(effectList, effectList[num]);
					}
					effectList[num] = effect;
					break;
				}
				if (effectList[num] == effect)
				{
					flag = true;
				}
			}
		}

		public static long GetLastTimerRun()
		{
			return lastTimerRun;
		}

		public static void SetLastTimerRun(long newTimer)
		{
			lastTimerRun = newTimer;
		}

		public static Activator GetActivator()
		{
			return activator;
		}

		public static List<Effect> GetActiveEffects()
		{
			return activeEffects;
		}

		public static PositionTracker GetPositionTracker()
		{
			return positionTracker;
		}

		public static bool GetHalfEffectTime()
		{
			return halfEffectWaitTime;
		}

		public static void SetHalfEffectTime(bool set)
		{
			halfEffectWaitTime = set;
		}

		public static bool GetEnabled()
		{
			return enabled;
		}
	}
}
namespace ChaosMod.Activator.Activators
{
	internal class RandomActivator : Activator
	{
		public string getName()
		{
			return "random";
		}

		public void Start()
		{
		}

		public void Stop()
		{
		}

		public Effect ChooseEffect()
		{
			Random random = new Random();
			Array values = Enum.GetValues(typeof(AllEffects.Effects));
			Effect effect2;
			do
			{
				AllEffects.Effects effect = (AllEffects.Effects)values.GetValue(random.Next(values.Length));
				effect2 = AllEffects.InstantiateEffect(effect);
			}
			while (effect2 != null && !effect2.IsAllowedToRun());
			return effect2;
		}
	}
	internal class TwitchActivator : Activator
	{
		private List<Effect> chosenEffects = new List<Effect>();

		private List<string> votedPlayers = new List<string>();

		private List<int> votedIndexes = new List<int>();

		public bool highNumbers = true;

		private static TextMeshProUGUI twitchText;

		private bool stopped = false;

		public string getName()
		{
			return "twitch";
		}

		public void Start()
		{
			if (ChaosMod.getInstance().twitchIRCClient == null)
			{
				ChaosMod.getInstance().twitchIRCClient = new TwitchIRCClient();
				ChaosMod.getInstance().twitchIRCClient.ConnectToTwitch();
			}
			if (!stopped)
			{
				highNumbers = true;
				if (ChaosMod.ConfigTwitchOptionsShowcase.Value != "chatmessage" && (Object)(object)twitchText == (Object)null)
				{
					AddTextElement();
				}
				ChooseNewEffectList();
			}
		}

		public void Stop()
		{
			if ((Object)(object)twitchText != (Object)null)
			{
				((TMP_Text)twitchText).text = "";
			}
			stopped = true;
		}

		public Effect ChooseEffect()
		{
			Random random = new Random();
			int index = ((votedIndexes.Count <= 0) ? random.Next(chosenEffects.Count) : votedIndexes[random.Next(votedIndexes.Count)]);
			Effect result = chosenEffects[index];
			ChooseNewEffectList();
			return result;
		}

		private void ChooseNewEffectList()
		{
			highNumbers = !highNumbers;
			votedIndexes = new List<int>();
			votedPlayers = new List<string>();
			Random random = new Random();
			Array values = Enum.GetValues(typeof(AllEffects.Effects));
			chosenEffects = new List<Effect>();
			while (chosenEffects.Count < 3)
			{
				int index = random.Next(values.Length);
				AllEffects.Effects effect = (AllEffects.Effects)values.GetValue(index);
				Effect effect2 = AllEffects.InstantiateEffect(effect);
				bool flag = false;
				foreach (Effect chosenEffect in chosenEffects)
				{
					if (effect2 == null || chosenEffect.GetEffectName() == effect2.GetEffectName())
					{
						flag = true;
					}
				}
				if (!flag && effect2.IsAllowedToRun())
				{
					chosenEffects.Add(effect2);
				}
			}
			if (ChaosMod.ConfigTwitchOptionsShowcase.Value == "chatmessage")
			{
				string text = "";
				for (int i = 0; i < chosenEffects.Count; i++)
				{
					text = text + ((!highNumbers) ? (i + 1) : (i + 4)) + ". " + chosenEffects[i].GetEffectName() + ". ";
				}
				text += "Vote by typing the number in chat";
				ChaosMod.getInstance().twitchIRCClient.sendMessage(text);
			}
			else
			{
				RefreshEffectText();
			}
		}

		private int GetAmountOfEffectVotes(int index)
		{
			int num = 0;
			for (int i = 0; i < votedIndexes.Count; i++)
			{
				if (votedIndexes[i] == index)
				{
					num++;
				}
			}
			return num;
		}

		public void VoteEffect(string sender, int vote)
		{
			for (int i = 0; i < votedPlayers.Count; i++)
			{
				if (sender.Equals(votedPlayers[i]))
				{
					return;
				}
			}
			votedPlayers.Add(sender);
			votedIndexes.Add(vote);
			RefreshEffectText();
		}

		public void RefreshEffectText()
		{
			if (!(ChaosMod.ConfigTwitchOptionsShowcase.Value == "chatmessage"))
			{
				((TMP_Text)twitchText).text = "";
				for (int i = 0; i < chosenEffects.Count; i++)
				{
					TextMeshProUGUI val = twitchText;
					((TMP_Text)val).text = ((TMP_Text)val).text + ((!highNumbers) ? (i + 1) : (i + 4)) + ". " + chosenEffects[i].GetEffectName() + " (" + GetAmountOfEffectVotes(i) + " votes)\n";
				}
				TextMeshProUGUI obj = twitchText;
				((TMP_Text)obj).text = ((TMP_Text)obj).text + "Vote by typing the number in chat\nTime left: " + (TimerSystem.GetLastTimerRun() + (TimerSystem.GetHalfEffectTime() ? (ChaosMod.ConfigTimeBetweenEffects.Value / 2 * 1000) : (ChaosMod.ConfigTimeBetweenEffects.Value * 1000)) + 1000 - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) / 1000 + " seconds";
			}
		}

		private void AddTextElement()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject();
			val.transform.parent = HUDManager.Instance.HUDContainer.transform;
			((Object)val).name = "ChaosModTwitchText";
			Vector3 localScale = val.transform.localScale;
			localScale.x = 1f;
			localScale.y = 1f;
			localScale.z = 1f;
			val.transform.localScale = localScale;
			Vector3 localPosition = val.transform.localPosition;
			localPosition.x = 350f;
			localPosition.y = 220f;
			localPosition.z = 0f;
			val.transform.localPosition = localPosition;
			twitchText = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)twitchText).text = "";
			((TMP_Text)twitchText).fontSize = 13f;
			((TMP_Text)twitchText).lineSpacing = 30f;
		}
	}
}