Decompiled source of TasksRevived v1.2.4

Tasks.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using On.EntityStates;
using On.RoR2;
using On.RoR2.UI;
using R2API;
using R2API.Networking;
using R2API.Networking.Interfaces;
using R2API.Utils;
using RoR2;
using RoR2.Artifacts;
using RoR2.Stats;
using RoR2.UI;
using RoR2BepInExPack.GameAssetPathsBetter;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
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: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Tasks")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+5b08c45b6bd7226a94bce6c28bd1872d0c40934d")]
[assembly: AssemblyProduct("Tasks")]
[assembly: AssemblyTitle("Tasks")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Tasks
{
	internal class AirKills : Task
	{
		private int[] kills;

		private int killsNeeded = 3;

		private List<HitGroundDelegate> groundDelegateList = new List<HitGroundDelegate>();

		protected new string description { get; } = "Get 3 kills whilst airborne";


		public override TaskType type { get; } = TaskType.AirKills;


		protected override string name { get; } = "Air Kills";


		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + ".";
		}

		protected override void SetHooks(int numPlayers)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			Debug.Log((object)$"Set Hooks in AirKills. {numPlayers} players");
			base.SetHooks(numPlayers);
			kills = new int[numPlayers];
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
			for (int i = 0; i < totalNumberPlayers; i++)
			{
				CharacterMaster playerCharacterMaster = TasksPlugin.GetPlayerCharacterMaster(i);
				if (playerCharacterMaster == null || playerCharacterMaster.GetBody() == null || playerCharacterMaster.GetBody().characterMotor == null)
				{
					break;
				}
				int tempInt = i;
				HitGroundDelegate item = (HitGroundDelegate)delegate
				{
					PlayerHitGround(tempInt);
				};
				groundDelegateList.Add(item);
				playerCharacterMaster.GetBody().characterMotor.onHitGround += groundDelegateList[tempInt];
			}
		}

		protected override void Unhook()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnKill;
			for (int i = 0; i < totalNumberPlayers; i++)
			{
				CharacterMaster playerCharacterMaster = TasksPlugin.GetPlayerCharacterMaster(i);
				if (playerCharacterMaster == null || playerCharacterMaster.GetBody() == null || playerCharacterMaster.GetBody().characterMotor == null)
				{
					break;
				}
				int index = i;
				playerCharacterMaster.GetBody().characterMotor.onHitGround -= groundDelegateList[index];
			}
			ResetAllKills();
			base.Unhook();
		}

		private void UpdateProgress()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = (float)kills[i] / (float)killsNeeded;
			}
			base.UpdateProgress(progress);
		}

		protected override bool IsComplete(int playerNum)
		{
			return kills[playerNum] >= killsNeeded;
		}

		public void OnKill(DamageReport damageReport)
		{
			if (damageReport == null || damageReport.attackerMaster == null || damageReport.attackerMaster.playerCharacterMasterController == null)
			{
				return;
			}
			int playerNumber = TasksPlugin.GetPlayerNumber(damageReport.attackerMaster);
			if (!damageReport.attackerMaster.GetBody().characterMotor.isGrounded)
			{
				kills[playerNumber]++;
				UpdateProgress();
				if (IsComplete(playerNumber))
				{
					CompleteTask(playerNumber);
					ResetAllKills();
				}
			}
		}

		private void PlayerHitGround(int playerNum)
		{
			UpdateProgress();
			kills[playerNum] = 0;
		}

		private void ResetAllKills()
		{
			if (kills != null)
			{
				for (int i = 0; i < kills.Length; i++)
				{
					kills[i] = 0;
				}
				ResetProgress();
			}
		}
	}
	internal class BabyDrone : Task
	{
		private CharacterMaster[] drones;

		private CharacterMaster createdDrone;

		private bool[] playerFailed;

		private int numPlayersFailed;

		private bool alreadyAwarded;

		public override TaskType type { get; } = TaskType.BabyDrone;


		protected override string name { get; } = "Baby Drone";


		public override bool CanActivate(int numPlayers)
		{
			return true;
		}

		public override string GetDescription()
		{
			return "Keep your drone alive";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			if (winningPlayer < 0)
			{
				return "You failed " + GetStylizedTaskName(name) + " by letting your drone die.";
			}
			return GetStylizedName(winningPlayer) + " kept their drone alive the longest. Completed " + GetStylizedTaskName(name) + ".";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in BabyDrone. {numPlayers} players");
			base.SetHooks(numPlayers);
			drones = (CharacterMaster[])(object)new CharacterMaster[numPlayers];
			playerFailed = new bool[numPlayers];
			numPlayersFailed = 0;
			alreadyAwarded = false;
			for (int i = 0; i < numPlayers; i++)
			{
				playerFailed[i] = false;
				SpawnDrone(i);
			}
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
			ResetProgress();
		}

		protected override void Unhook()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnKill;
			base.Unhook();
		}

		private void Evaluate()
		{
			if (alreadyAwarded)
			{
				return;
			}
			for (int i = 0; i < playerFailed.Length; i++)
			{
				if (!playerFailed[i])
				{
					UpdateProgressMultiWinner();
					CompleteTask(i);
				}
			}
		}

		private void UpdateProgress()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				if (totalNumberPlayers > 1)
				{
					progress[i] = ((!playerFailed[i]) ? (numPlayersFailed / (totalNumberPlayers - 1)) : 0);
				}
				else
				{
					progress[i] = 0f;
				}
			}
			base.UpdateProgress(progress);
		}

		private void UpdateProgressMultiWinner()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = ((!playerFailed[i]) ? 1 : 0);
			}
			base.UpdateProgress(progress);
		}

		public void OnKill(DamageReport damageReport)
		{
			if (damageReport == null || damageReport.victimMaster == null)
			{
				return;
			}
			for (int i = 0; i < drones.Length; i++)
			{
				if (playerFailed[i] || !((Object)(object)damageReport.victimMaster == (Object)(object)drones[i]))
				{
					continue;
				}
				string text = $"BABY_DRONE_{i}";
				ChatMessage.Send(GetDroneDeathMessage(Language.currentLanguage.GetLocalizedStringByToken(text)));
				playerFailed[i] = true;
				numPlayersFailed++;
				UpdateProgress();
				if (totalNumberPlayers > 1)
				{
					if (numPlayersFailed < totalNumberPlayers - 1)
					{
						continue;
					}
					for (int j = 0; j < playerFailed.Length; j++)
					{
						if (!playerFailed[j])
						{
							alreadyAwarded = true;
							CompleteTask(j);
							return;
						}
					}
				}
				else
				{
					CompleteTask(-1);
				}
			}
		}

		private void SpawnDrone(int playerNum)
		{
			//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)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_005e: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			CharacterBody body = TasksPlugin.GetPlayerCharacterMaster(playerNum).GetBody();
			GameObject val = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(Resources.Load<SpawnCard>("SpawnCards/InteractableSpawnCard/iscbrokendrone1"), new DirectorPlacementRule
			{
				placementMode = (PlacementMode)0,
				position = body.transform.position + new Vector3(1f, 0f, 0f)
			}, new Xoroshiro128Plus(0uL)));
			PurchaseInteraction component = val.GetComponent<PurchaseInteraction>();
			component.cost = 0;
			Interactor component2 = ((Component)body).GetComponent<Interactor>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				MasterSummon.Perform += new hook_Perform(GrabDrone);
				component.OnInteractionBegin(component2);
				MasterSummon.Perform -= new hook_Perform(GrabDrone);
				string text = $"BABY_DRONE_{playerNum}";
				Language.currentLanguage.SetStringByToken(text, GetDroneName(playerNum));
				CharacterBody body2 = createdDrone.GetBody();
				body2.baseNameToken = text;
				body2.baseRegen = 0f;
				drones[playerNum] = createdDrone;
				((MonoBehaviour)TasksPlugin.instance).StartCoroutine(DamageDrone(body2));
			}
		}

		private CharacterMaster GrabDrone(orig_Perform orig_Perform, MasterSummon self)
		{
			return createdDrone = orig_Perform.Invoke(self);
		}

		private string GetDroneName(int playerNum)
		{
			string displayName = ((Component)TasksPlugin.GetPlayerCharacterMaster(playerNum)).GetComponent<PlayerCharacterMasterController>().GetDisplayName();
			WeightedSelection<string> val = new WeightedSelection<string>(14);
			val.AddChoice(displayName + " Junior", 1f);
			val.AddChoice(displayName + " Jr.", 1f);
			val.AddChoice("Baby " + displayName, 1f);
			val.AddChoice("Little " + displayName, 1f);
			val.AddChoice("Li'l " + displayName, 1f);
			val.AddChoice(displayName + " the Second", 1f);
			val.AddChoice(displayName + " the Third", 1f);
			val.AddChoice(displayName + " II", 1f);
			val.AddChoice(displayName + " III", 1f);
			val.AddChoice(displayName + " the Younger", 1f);
			val.AddChoice("Mini " + displayName, 1f);
			val.AddChoice(displayName + " Mk II", 1f);
			val.AddChoice(displayName + " 2.0", 1f);
			val.AddChoice(displayName + " (Clone)", 1f);
			return val.Evaluate(Random.value);
		}

		private string GetDroneDeathMessage(string droneName)
		{
			WeightedSelection<string> val = new WeightedSelection<string>(8);
			val.AddChoice(droneName + " died. And it was all your fault.", 1f);
			val.AddChoice(droneName + " died. And you just let it happen.", 1f);
			val.AddChoice(droneName + " died because you didn't love him enough.", 1f);
			val.AddChoice(droneName + " died. Play on an easier difficulty so this doesn't happen again.", 1f);
			val.AddChoice("You killed " + droneName + ". You monster.", 1f);
			val.AddChoice("You let " + droneName + " die. You monster.", 1f);
			val.AddChoice("You let " + droneName + " die. What did he ever do to you?", 1f);
			val.AddChoice(droneName + " said goodbye. When he died.", 1f);
			val.AddChoice(droneName + " died. You can repair him, but it won't be the same " + droneName + ".", 1f);
			val.AddChoice(droneName + " has went to a junkyard in the country.", 1f);
			val.AddChoice(droneName + " has went to a junkyard in the country.", 1f);
			val.AddChoice("MISSION FAILURE! " + droneName + " has been lost.", 1f);
			val.AddChoice("Well, " + droneName + " has been lost. Hope you're happy", 1f);
			val.AddChoice("Well, " + droneName + " is gone. Hope you're happy", 1f);
			val.AddChoice(droneName + " has gone and there shall never be another like him.", 1f);
			val.AddChoice("RIP " + droneName + ", the goodest boy.", 1f);
			val.AddChoice("RIP " + droneName + ".", 1f);
			val.AddChoice("At least " + droneName + " didn't suffer.", 1f);
			val.AddChoice(droneName + " deserved better.", 1f);
			return "<style=cDeath><sprite name=\"Skull\" tint=1> " + val.Evaluate(Random.value) + " <sprite name=\"Skull\" tint=1></style>";
		}

		private IEnumerator DamageDrone(CharacterBody droneBody)
		{
			yield return (object)new WaitForSeconds(1f);
			DamageInfo damageInfo = new DamageInfo
			{
				damage = droneBody.healthComponent.combinedHealth,
				position = droneBody.corePosition,
				force = Vector3.zero,
				damageColorIndex = (DamageColorIndex)0,
				crit = false,
				attacker = null,
				inflictor = null,
				damageType = DamageTypeCombo.op_Implicit((DamageType)3),
				procCoefficient = 0f,
				procChainMask = default(ProcChainMask)
			};
			droneBody.healthComponent.TakeDamage(damageInfo);
		}
	}
	internal class BiggestHit : Task
	{
		private float[] biggestHit;

		protected new string description { get; } = "Biggest hit wins";


		public override TaskType type { get; } = TaskType.BiggestHit;


		protected override string name { get; } = "Biggest Hit";


		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " with the big hit of " + GetStylizedTaskWinStat(biggestHit[winningPlayer].ToString()) + " damage.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in BiggestHit. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.onServerDamageDealt += OnDamage;
			if (biggestHit == null || biggestHit.Length != numPlayers)
			{
				biggestHit = new float[numPlayers];
			}
			Reset();
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
			Reset();
		}

		protected override void Unhook()
		{
			GlobalEventManager.onServerDamageDealt -= OnDamage;
			base.Unhook();
		}

		protected void UpdateProgress()
		{
			float num = 0f;
			for (int i = 0; i < biggestHit.Length; i++)
			{
				if (biggestHit[i] > num)
				{
					num = biggestHit[i];
				}
			}
			if (num > 0f)
			{
				for (int j = 0; j < progress.Length; j++)
				{
					progress[j] = biggestHit[j] / num;
				}
			}
			else
			{
				for (int k = 0; k < progress.Length; k++)
				{
					progress[k] = 0f;
				}
			}
			base.UpdateProgress(progress);
		}

		public void OnDamage(DamageReport report)
		{
			if (report != null && report.attackerMaster != null && report.attackerMaster.playerCharacterMasterController != null)
			{
				int playerNumber = TasksPlugin.GetPlayerNumber(report.attackerMaster);
				float damageDealt = report.damageDealt;
				if (damageDealt > biggestHit[playerNumber])
				{
					biggestHit[playerNumber] = damageDealt;
					UpdateProgress();
				}
			}
		}

		private void Evaluate()
		{
			float num = 0f;
			int playerNum = 0;
			for (int i = 0; i < biggestHit.Length; i++)
			{
				if (biggestHit[i] > num)
				{
					num = biggestHit[i];
					playerNum = i;
				}
			}
			CompleteTask(playerNum);
		}

		private void Reset()
		{
			if (biggestHit != null)
			{
				for (int i = 0; i < biggestHit.Length; i++)
				{
					biggestHit[i] = 0f;
				}
				ResetProgress();
			}
		}
	}
	internal class ConfigManager
	{
		public static ConfigManager instance;

		private ConfigFile config;

		public static ConfigEntry<int> TasksPerPlayer { get; set; }

		public static ConfigEntry<int> AdditionalTasks { get; set; }

		public static ConfigEntry<float> AirKillsWeight { get; set; }

		public static ConfigEntry<float> DamageMultipleWeight { get; set; }

		public static ConfigEntry<float> DamageInTimeWeight { get; set; }

		public static ConfigEntry<float> StayInAirWeight { get; set; }

		public static ConfigEntry<float> BiggestHitWeight { get; set; }

		public static ConfigEntry<float> MostDistanceWeight { get; set; }

		public static ConfigEntry<float> PreonEventWeight { get; set; }

		public static ConfigEntry<float> FarthestAwayWeight { get; set; }

		public static ConfigEntry<float> FailShrineWeight { get; set; }

		public static ConfigEntry<float> OpenChestsWeight { get; set; }

		public static ConfigEntry<float> StartTeleWeight { get; set; }

		public static ConfigEntry<float> UsePrintersWeight { get; set; }

		public static ConfigEntry<float> OrderedSkillsWeight { get; set; }

		public static ConfigEntry<float> BadSkillWeight { get; set; }

		public static ConfigEntry<float> BabyDroneWeight { get; set; }

		public static ConfigEntry<float> DieWeight { get; set; }

		public static ConfigEntry<float> FindLockboxWeight { get; set; }

		public static ConfigEntry<float> HealingItemWeight { get; set; }

		public static ConfigEntry<float> NoJumpWeight { get; set; }

		public static ConfigEntry<float> VeryBestWeight { get; set; }

		public static ConfigEntry<float> FewestElitesWeight { get; set; }

		public static ConfigEntry<float> GetLuckyWeight { get; set; }

		public static ConfigEntry<float> GetLowWeight { get; set; }

		public static ConfigEntry<float> KillStreakWeight { get; set; }

		public static ConfigEntry<float> QuickDrawWeight { get; set; }

		public static ConfigEntry<float> FarKillWeight { get; set; }

		public static ConfigEntry<float> FewEliteWeight { get; set; }

		public ConfigManager()
		{
			if (instance == null)
			{
				instance = this;
			}
		}

		public void Awake()
		{
			SetupWeights();
		}

		public void SetConfigFile(ConfigFile c)
		{
			config = c;
		}

		private void SetupWeights()
		{
			TasksPerPlayer = config.Bind<int>("TaskOptions", "TasksPerPlayer", 1, "Number of tasks per player. Number of tasks: (TasksPerPlayer * number of player) + AdditionalTasks");
			AdditionalTasks = config.Bind<int>("TaskOptions", "AdditionalTasks", 2, "Extra tasks. Number of tasks: (TasksPerPlayer * number of player) + AdditionalTasks");
			AirKillsWeight = config.Bind<float>("TaskWeights", "AirKills", 1.5f, "Relative weight of this task. Bigger number means more likely to roll task. 0 for no chance.");
			DamageMultipleWeight = config.Bind<float>("TaskWeights", "DamageMultiple", 2f, "Relative weight of this task.");
			DamageInTimeWeight = config.Bind<float>("TaskWeights", "DamageInTime", 2f, "Relative weight of this task. Do x damage within y seconds");
			StayInAirWeight = config.Bind<float>("TaskWeights", "StayInAir", 1.5f, "Relative weight of this task.");
			BiggestHitWeight = config.Bind<float>("TaskWeights", "BiggestHit", 2f, "Relative weight of this task.");
			MostDistanceWeight = config.Bind<float>("TaskWeights", "MostDistance", 1f, "Relative weight of this task.");
			PreonEventWeight = config.Bind<float>("TaskWeights", "PreonEvent", 1f, "Relative weight of this task.");
			FarthestAwayWeight = config.Bind<float>("TaskWeights", "FarthestAway", 1.5f, "Relative weight of this task.");
			FailShrineWeight = config.Bind<float>("TaskWeights", "FailShrine", 1f, "Relative weight of this task.");
			OpenChestsWeight = config.Bind<float>("TaskWeights", "OpenChests", 2f, "Relative weight of this task.");
			StartTeleWeight = config.Bind<float>("TaskWeights", "StartTele", 2f, "Relative weight of this task.");
			UsePrintersWeight = config.Bind<float>("TaskWeights", "UsePrinters", 1f, "Relative weight of this task.");
			OrderedSkillsWeight = config.Bind<float>("TaskWeights", "OrderedSkills", 0f, "Relative weight of this task. Use abilities in left-to-right order. This task sucks.");
			BadSkillWeight = config.Bind<float>("TaskWeights", "BadSkill", 0.5f, "Relative weight of this task. Don't use utility skill");
			BabyDroneWeight = config.Bind<float>("TaskWeights", "BabyDrone", 0.75f, "Relative weight of this task. Keep your drone alive");
			DieWeight = config.Bind<float>("TaskWeights", "Die", 0.25f, "Relative weight of this task.");
			FindLockboxWeight = config.Bind<float>("TaskWeights", "FindLockbox", 2f, "Relative weight of this task.");
			HealingItemWeight = config.Bind<float>("TaskWeights", "HealingItem", 1.5f, "Relative weight of this task. Find a healing item");
			NoJumpWeight = config.Bind<float>("TaskWeights", "NoJump", 1f, "Relative weight of this task.");
			VeryBestWeight = config.Bind<float>("TaskWeights", "VeryBest", 1.5f, "Relative weight of this task. Be the very best. Like no one ever was.");
			FewestElitesWeight = config.Bind<float>("TaskWeights", "FewestElites", 1.5f, "Relative weight of this task.");
			GetLuckyWeight = config.Bind<float>("TaskWeights", "GetLucky", 0.5f, "Relative weight of this task.");
			GetLowWeight = config.Bind<float>("TaskWeights", "GetLow", 1.5f, "Relative weight of this task.");
			KillStreakWeight = config.Bind<float>("TaskWeights", "KillStreaks", 1.5f, "Relative weight of this task.");
			QuickDrawWeight = config.Bind<float>("TaskWeights", "QuickDraw", 1.5f, "Relative weight of this task. Kill something that spawned 3s ago");
			FarKillWeight = config.Bind<float>("TaskWeights", "FarKill", 1f, "Relative weight of this task. Kill something far away from where you last left the ground");
			FewEliteWeight = config.Bind<float>("TaskWeights", "FewElites", 1f, "Relative weight of this task. Kill the boss before you kill 10 elites");
		}

		public float GetTaskWeight(TaskType type)
		{
			return type switch
			{
				TaskType.AirKills => AirKillsWeight.Value, 
				TaskType.DamageMultiple => DamageMultipleWeight.Value, 
				TaskType.DamageInTime => DamageInTimeWeight.Value, 
				TaskType.StayInAir => StayInAirWeight.Value, 
				TaskType.BiggestHit => BiggestHitWeight.Value, 
				TaskType.MostDistance => MostDistanceWeight.Value, 
				TaskType.PreonEvent => PreonEventWeight.Value, 
				TaskType.FarthestAway => FarthestAwayWeight.Value, 
				TaskType.FailShrine => FailShrineWeight.Value, 
				TaskType.OpenChests => OpenChestsWeight.Value, 
				TaskType.StartTele => StartTeleWeight.Value, 
				TaskType.UsePrinters => UsePrintersWeight.Value, 
				TaskType.OrderedSkills => OrderedSkillsWeight.Value, 
				TaskType.BadSkill => BadSkillWeight.Value, 
				TaskType.BabyDrone => BabyDroneWeight.Value, 
				TaskType.Die => DieWeight.Value, 
				TaskType.FindLockbox => FindLockboxWeight.Value, 
				TaskType.HealingItem => HealingItemWeight.Value, 
				TaskType.NoJump => NoJumpWeight.Value, 
				TaskType.VeryBest => VeryBestWeight.Value, 
				TaskType.FewestElites => FewestElitesWeight.Value, 
				TaskType.GetLucky => GetLuckyWeight.Value, 
				TaskType.GetLow => GetLowWeight.Value, 
				TaskType.KillStreak => KillStreakWeight.Value, 
				TaskType.QuickDraw => QuickDrawWeight.Value, 
				TaskType.FarKill => FarKillWeight.Value, 
				TaskType.FewElites => FewEliteWeight.Value, 
				_ => 1f, 
			};
		}

		public int GetNumberOfTasks(int numPlayers)
		{
			return numPlayers * TasksPerPlayer.Value + AdditionalTasks.Value;
		}
	}
	internal class DamageMultipleTargets : Task
	{
		private int numToHit = 4;

		private HashSet<GameObject>[] targets;

		protected new string description { get; } = "Have 4 enemies damaged by you alive at once";


		public override TaskType type { get; } = TaskType.DamageMultiple;


		protected override string name { get; } = "Damage Multiple";


		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by having " + GetStylizedTaskWinStat(numToHit.ToString()) + " enemies damaged, but alive, at once.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in DamageMultiple. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.onServerDamageDealt += OnDamage;
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
			targets = new HashSet<GameObject>[numPlayers];
			for (int i = 0; i < targets.Length; i++)
			{
				targets[i] = new HashSet<GameObject>();
			}
		}

		protected override void Unhook()
		{
			GlobalEventManager.onServerDamageDealt -= OnDamage;
			GlobalEventManager.onCharacterDeathGlobal -= OnKill;
			ResetKills();
			base.Unhook();
		}

		private void UpdateProgress()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = (float)targets[i].Count / (float)numToHit;
			}
			base.UpdateProgress(progress);
		}

		public void OnDamage(DamageReport report)
		{
			if (report == null || report.attackerMaster == null || report.attackerMaster.playerCharacterMasterController == null)
			{
				return;
			}
			int playerNumber = TasksPlugin.GetPlayerNumber(report.attackerMaster);
			if (report.victim.alive && !targets[playerNumber].Contains(((Component)report.victim).gameObject))
			{
				targets[playerNumber].Add(((Component)report.victim).gameObject);
				UpdateProgress();
				if (IsComplete(playerNumber))
				{
					CompleteTask(playerNumber);
					ResetKills();
				}
			}
		}

		protected override bool IsComplete(int playerNum)
		{
			return targets[playerNum].Count >= numToHit;
		}

		private void OnKill(DamageReport report)
		{
			if (report != null && report.attackerMaster != null && report.attackerMaster.playerCharacterMasterController != null)
			{
				int playerNumber = TasksPlugin.GetPlayerNumber(report.attackerMaster);
				targets[playerNumber].Remove(((Component)report.victim).gameObject);
				UpdateProgress();
			}
		}

		private void ResetKills()
		{
			if (targets != null)
			{
				for (int i = 0; i < targets.Length; i++)
				{
					targets[i].Clear();
				}
				ResetProgress();
			}
		}
	}
	internal class DealDamageInTime : Task
	{
		private float damageToDeal = 500f;

		private float timeLimit = 5f;

		private float[] currentDamage;

		private bool active = false;

		protected new string description { get; } = "Deal 500 damage in 5 seconds";


		public override TaskType type { get; } = TaskType.DamageInTime;


		protected override string name { get; } = "Damage In Time";


		public override string GetDescription()
		{
			return $"Deal {damageToDeal:N0} damage in 5 seconds";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by dealing " + GetStylizedTaskWinStat(damageToDeal.ToString()) + " damage within 5s.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in DamageInTime. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.onServerDamageDealt += OnDamage;
			damageToDeal = Run.instance.difficultyCoefficient * damageToDeal;
			if (currentDamage == null || currentDamage.Length != numPlayers)
			{
				currentDamage = new float[numPlayers];
			}
			active = true;
			Reset();
		}

		protected override void Unhook()
		{
			GlobalEventManager.onServerDamageDealt -= OnDamage;
			Reset();
			base.Unhook();
		}

		private void UpdateProgress()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = currentDamage[i] / damageToDeal;
			}
			base.UpdateProgress(progress);
		}

		public void OnDamage(DamageReport report)
		{
			if (report != null && report.attackerMaster != null && report.attackerMaster.playerCharacterMasterController != null)
			{
				int playerNumber = TasksPlugin.GetPlayerNumber(report.attackerMaster);
				currentDamage[playerNumber] += report.damageDealt;
				UpdateProgress();
				((MonoBehaviour)TasksPlugin.instance).StartCoroutine(ReduceDamage(report.damageDealt, playerNumber));
				if (IsComplete(playerNumber))
				{
					active = false;
					CompleteTask(playerNumber);
					Reset();
				}
			}
		}

		protected override bool IsComplete(int playerNum)
		{
			return currentDamage[playerNum] >= damageToDeal;
		}

		private IEnumerator ReduceDamage(float damage, int playerNum)
		{
			yield return (object)new WaitForSeconds(timeLimit);
			currentDamage[playerNum] = Mathf.Max(0f, currentDamage[playerNum] - damage);
			if (active)
			{
				UpdateProgress();
			}
		}

		private void Reset()
		{
			if (currentDamage != null)
			{
				for (int i = 0; i < currentDamage.Length; i++)
				{
					currentDamage[i] = 0f;
				}
				ResetProgress();
			}
		}
	}
	internal class Die : Task
	{
		public override TaskType type { get; } = TaskType.Die;


		protected override string name { get; } = "Die";


		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		public override string GetDescription()
		{
			return "Die";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by dying first. Congratulations.";
		}

		protected override void SetHooks(int numPlayers)
		{
			base.SetHooks(numPlayers);
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
		}

		protected override void Unhook()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnKill;
			base.Unhook();
		}

		public void OnKill(DamageReport damageReport)
		{
			if (damageReport != null && damageReport.victimMaster != null)
			{
				int playerNumber = TasksPlugin.GetPlayerNumber(damageReport.victimMaster);
				if (playerNumber > -1)
				{
					CompleteTask(playerNumber);
				}
			}
		}
	}
	internal class DontUseSkill : Task
	{
		private SkillSlot badSkill;

		private bool[] playerFailed;

		private int numPlayersFailed;

		protected new string description { get; } = "Last to use their utility skill wins";


		public override TaskType type { get; } = TaskType.BadSkill;


		protected override string name { get; } = "Bad Skill";


		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by not using their " + GetStylizedTaskWinStat(((object)(SkillSlot)(ref badSkill)).ToString()) + " skill.";
		}

		protected override void SetHooks(int numPlayers)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Debug.Log((object)$"Set Hooks in DontUseSkill. {numPlayers} players");
			base.SetHooks(numPlayers);
			badSkill = (SkillSlot)2;
			playerFailed = new bool[numPlayers];
			Reset();
			TasksPlugin.OnAbilityUsed += AbilityUsed;
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
			Reset();
		}

		protected override void Unhook()
		{
			TasksPlugin.OnAbilityUsed -= AbilityUsed;
			base.Unhook();
		}

		private void Evaluate()
		{
			if (totalNumberPlayers - numPlayersFailed <= 1)
			{
				return;
			}
			for (int i = 0; i < playerFailed.Length; i++)
			{
				if (!playerFailed[i])
				{
					UpdateProgressMultiWinner();
					CompleteTask(i);
				}
			}
		}

		private void UpdateProgress()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = ((!playerFailed[i]) ? (numPlayersFailed / (totalNumberPlayers - 1)) : 0);
			}
			base.UpdateProgress(progress);
		}

		private void UpdateProgressMultiWinner()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = ((!playerFailed[i]) ? 1 : 0);
			}
			base.UpdateProgress(progress);
		}

		private void AbilityUsed(int playerNum, SkillSlot slot)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			if (slot != badSkill || playerFailed[playerNum])
			{
				return;
			}
			Debug.Log((object)$"Player {playerNum} failed BadSkill");
			playerFailed[playerNum] = true;
			numPlayersFailed++;
			UpdateProgress();
			if (numPlayersFailed < totalNumberPlayers - 1)
			{
				return;
			}
			for (int i = 0; i < playerFailed.Length; i++)
			{
				if (!playerFailed[i])
				{
					CompleteTask(i);
					break;
				}
			}
		}

		private void Reset()
		{
			if (playerFailed != null)
			{
				for (int i = 0; i < playerFailed.Length; i++)
				{
					playerFailed[i] = false;
				}
				ResetProgress();
			}
		}
	}
	internal class FailShrine : Task
	{
		protected new string description { get; } = "First to Fail";


		public override TaskType type { get; } = TaskType.FailShrine;


		protected override string name { get; } = "Fail a Chance Shrine";


		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by " + GetStylizedTaskWinStat("failing") + " a chance shrine.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in FailShrine. {numPlayers} players");
			base.SetHooks(numPlayers);
			ShrineChanceBehavior.onShrineChancePurchaseGlobal += OnShrineChancePurchase;
		}

		protected override void Unhook()
		{
			ShrineChanceBehavior.onShrineChancePurchaseGlobal -= OnShrineChancePurchase;
			base.Unhook();
		}

		private void OnShrineChancePurchase(bool failed, Interactor interactor)
		{
			if (!failed)
			{
				return;
			}
			for (int i = 0; i < totalNumberPlayers; i++)
			{
				if ((Object)(object)((Component)TasksPlugin.GetPlayerCharacterMaster(i).GetBody()).GetComponent<Interactor>() == (Object)(object)interactor)
				{
					CompleteTask(i);
					break;
				}
			}
		}
	}
	internal class FarKill : Task
	{
		private int distance = 70;

		private Vector3[] playerGroundPositions;

		private bool active = false;

		public override TaskType type { get; } = TaskType.FarKill;


		protected override string name { get; } = "Far Kill";


		public override string GetDescription()
		{
			return $"Kill an enemy {distance}m from where you left the ground";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by killing something from a ways away.";
		}

		protected override void SetHooks(int numPlayers)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			Debug.Log((object)$"Set hooks in FarKill. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
			playerGroundPositions = (Vector3[])(object)new Vector3[numPlayers];
			for (int i = 0; i < totalNumberPlayers; i++)
			{
				CharacterMaster playerCharacterMaster = TasksPlugin.GetPlayerCharacterMaster(i);
				playerGroundPositions[i] = playerCharacterMaster.GetBody().corePosition;
			}
			active = true;
			((MonoBehaviour)TasksPlugin.instance).StartCoroutine(CalculatePositions());
		}

		protected override void Unhook()
		{
			if (active)
			{
				active = false;
				GlobalEventManager.onCharacterDeathGlobal -= OnKill;
				base.Unhook();
			}
		}

		private void OnKill(DamageReport report)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (report != null && report.attackerMaster != null && report.attackerMaster.playerCharacterMasterController != null)
			{
				int playerNumber = TasksPlugin.GetPlayerNumber(report.attackerMaster);
				float num = Vector3.Distance(report.victimBody.corePosition, playerGroundPositions[playerNumber]);
				if (num > (float)distance)
				{
					CompleteTask(playerNumber);
					return;
				}
				progress[playerNumber] = num / (float)distance;
				UpdateProgress(progress);
			}
		}

		private IEnumerator CalculatePositions()
		{
			while (active)
			{
				for (int i = 0; i < totalNumberPlayers; i++)
				{
					CharacterBody body = TasksPlugin.GetPlayerCharacterMaster(i).GetBody();
					if (body.characterMotor.isGrounded)
					{
						playerGroundPositions[i] = body.corePosition;
					}
				}
				yield return null;
			}
		}
	}
	internal class FarthestAway : Task
	{
		private Vector3[] startPositions;

		private bool active = false;

		private IEnumerator timerRoutine;

		private float winnerDist = 0f;

		protected new string description { get; } = "Farthest away in 20s wins";


		public override TaskType type { get; } = TaskType.FarthestAway;


		protected override string name { get; } = "Farthest From Spawn";


		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by being " + GetStylizedTaskWinStat(winnerDist.ToString("F2")) + "m away in 20 seconds.";
		}

		protected override void SetHooks(int numPlayers)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			Debug.Log((object)$"Set Hooks in FarthestAway. {numPlayers} players");
			base.SetHooks(numPlayers);
			if (startPositions == null || startPositions.Length != numPlayers)
			{
				startPositions = (Vector3[])(object)new Vector3[numPlayers];
			}
			for (int i = 0; i < startPositions.Length; i++)
			{
				if (TasksPlugin.GetPlayerCharacterMaster(i).GetBody() == null)
				{
					Debug.Log((object)$"Task.FarthestAway player body is null. Player: {i}");
					startPositions[i] = Vector3.zero;
				}
				else
				{
					startPositions[i] = TasksPlugin.GetPlayerCharacterMaster(i).GetBody().transform.position;
				}
			}
			timerRoutine = EndTask();
			((MonoBehaviour)TasksPlugin.instance).StartCoroutine(timerRoutine);
			active = true;
		}

		protected override void Unhook()
		{
			if (active)
			{
				active = false;
				if (timerRoutine != null)
				{
					((MonoBehaviour)TasksPlugin.instance).StopCoroutine(timerRoutine);
				}
				base.Unhook();
			}
		}

		private void UpdateProgress(int time)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			float[] array = new float[startPositions.Length];
			float num = 0f;
			if (time > 0)
			{
				for (int i = 0; i < startPositions.Length; i++)
				{
					array[i] = Vector3.Distance(startPositions[i], TasksPlugin.GetPlayerCharacterMaster(i).GetBody().transform.position);
					if (array[i] > num)
					{
						num = array[i];
					}
				}
			}
			if (num > 0f)
			{
				for (int j = 0; j < progress.Length; j++)
				{
					progress[j] = (float)time * (array[j] / num) / 20f;
				}
			}
			else
			{
				for (int k = 0; k < progress.Length; k++)
				{
					progress[k] = 0f;
				}
			}
			base.UpdateProgress(progress);
		}

		private IEnumerator EndTask()
		{
			for (int i = 0; i < 20; i++)
			{
				yield return (object)new WaitForSeconds(1f);
				UpdateProgress(i + 1);
			}
			Evaluate();
		}

		private void Evaluate()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			int playerNum = 0;
			for (int i = 0; i < startPositions.Length; i++)
			{
				CharacterMaster playerCharacterMaster = TasksPlugin.GetPlayerCharacterMaster(i);
				if ((Object)(object)playerCharacterMaster == (Object)null)
				{
					continue;
				}
				CharacterBody body = playerCharacterMaster.GetBody();
				if (!((Object)(object)body == (Object)null))
				{
					Vector3 position = body.transform.position;
					float num2 = Vector3.Distance(startPositions[i], position);
					if (num2 > num)
					{
						num = num2;
						playerNum = i;
					}
				}
			}
			winnerDist = num;
			CompleteTask(playerNum);
			ResetProgress();
		}
	}
	internal class FewElites : Task
	{
		private int[] kills;

		private int maxKills = 5;

		private bool taskFinished = false;

		public override TaskType type { get; } = TaskType.FewElites;


		protected override string name { get; } = "Few Elites";


		public override bool CanActivate(int numPlayers)
		{
			return true;
		}

		public override string GetDescription()
		{
			return "Kill the boss before you kill 5 elites.";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			if (winningPlayer < 0)
			{
				return "You failed " + GetStylizedTaskName(name) + " by killing too many elites.";
			}
			return $"{GetStylizedName(winningPlayer)} completed {GetStylizedTaskName(name)} by killing the boss while only killing {GetStylizedTaskWinStat(kills[winningPlayer].ToString())}/{maxKills} elites.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set hooks in FewElites. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
			BossGroup.onBossGroupDefeatedServer += BossDied;
			kills = new int[numPlayers];
			taskFinished = false;
			Reset();
			UpdateProgress();
		}

		private void BossDied(BossGroup group)
		{
			Evaluate();
			taskFinished = true;
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Reset();
		}

		protected override void Unhook()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnKill;
			BossGroup.onBossGroupDefeatedServer -= BossDied;
			base.Unhook();
		}

		public void OnKill(DamageReport damageReport)
		{
			if (taskFinished || damageReport == null || damageReport.attackerMaster == null || damageReport.attackerMaster.playerCharacterMasterController == null)
			{
				return;
			}
			int playerNumber = TasksPlugin.GetPlayerNumber(damageReport.attackerMaster);
			if (damageReport.victimIsElite)
			{
				kills[playerNumber]++;
				if (totalNumberPlayers == 1 && kills[playerNumber] > maxKills)
				{
					CompleteTask(-1);
				}
			}
			UpdateProgress();
		}

		private void UpdateProgress()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				if (taskFinished)
				{
					progress[i] = 0f;
					continue;
				}
				float num = (float)(maxKills - kills[i]) / (float)maxKills;
				num = Mathf.Max(num, 0f);
				progress[i] = num;
			}
			base.UpdateProgress(progress);
		}

		private void Evaluate()
		{
			if (kills == null)
			{
				return;
			}
			string text = "";
			string text2 = "";
			for (int i = 0; i < kills.Length; i++)
			{
				if (kills[i] <= maxKills)
				{
					CompleteTask(i);
					text += $"{i}, ";
					text2 += $"{kills[i]}, ";
				}
			}
			Debug.Log((object)$"Players {text} won with {text2} /{maxKills} kills");
		}

		private void Reset()
		{
			if (kills != null)
			{
				taskFinished = false;
				for (int i = 0; i < kills.Length; i++)
				{
					kills[i] = 0;
				}
				ResetProgress();
			}
		}
	}
	internal class FewestElites : Task
	{
		private int[] kills;

		public override TaskType type { get; } = TaskType.FewestElites;


		protected override string name { get; } = "Fewest Elites";


		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		public override string GetDescription()
		{
			return "Kill the fewest elites.";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by killing the fewest (" + GetStylizedTaskWinStat(kills[winningPlayer].ToString()) + ") elites.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set hooks in FewestElites. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
			kills = new int[numPlayers];
			Reset();
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
			Reset();
		}

		protected override void Unhook()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnKill;
			base.Unhook();
		}

		public void OnKill(DamageReport damageReport)
		{
			if (damageReport != null && damageReport.attackerMaster != null && damageReport.attackerMaster.playerCharacterMasterController != null)
			{
				int playerNumber = TasksPlugin.GetPlayerNumber(damageReport.attackerMaster);
				if (damageReport.victimIsElite)
				{
					kills[playerNumber]++;
				}
				UpdateProgress();
			}
		}

		private void UpdateProgress()
		{
			int num = 0;
			for (int i = 0; i < kills.Length; i++)
			{
				int num2 = kills[i];
				if (num2 > num)
				{
					num = num2;
				}
			}
			if (num > 0)
			{
				for (int j = 0; j < progress.Length; j++)
				{
					progress[j] = (float)kills[j] / (float)num;
				}
			}
			else
			{
				for (int k = 0; k < progress.Length; k++)
				{
					progress[k] = 0f;
				}
			}
			base.UpdateProgress(progress);
		}

		private void Evaluate()
		{
			if (kills == null)
			{
				return;
			}
			int num = 0;
			int num2 = kills[0];
			for (int i = 1; i < kills.Length; i++)
			{
				int num3 = kills[i];
				if (num3 < num2)
				{
					num = i;
					num2 = num3;
				}
			}
			Debug.Log((object)$"Player {num} won with {num2} elite kills");
			CompleteTask(num);
		}

		private void Reset()
		{
			if (kills != null)
			{
				for (int i = 0; i < kills.Length; i++)
				{
					kills[i] = 0;
				}
				ResetProgress();
			}
		}
	}
	internal class FindLockbox : Task
	{
		public override TaskType type { get; } = TaskType.FindLockbox;


		protected override string name { get; } = "Find Lockbox";


		public override bool CanActivate(int numPlayers)
		{
			int num = 0;
			foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList)
			{
				num += readOnlyInstances.inventory.GetItemCount(Items.TreasureCache);
			}
			return num > 0;
		}

		public override string GetDescription()
		{
			return "Find the Lockbox";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by finding the lockbox first.";
		}

		protected override void SetHooks(int numPlayers)
		{
			base.SetHooks(numPlayers);
			GlobalEventManager.OnInteractionsGlobal += ChestsOpened;
			TasksPlugin.StartLockboxTask();
		}

		protected override void Unhook()
		{
			GlobalEventManager.OnInteractionsGlobal -= ChestsOpened;
			base.Unhook();
		}

		private void ChestsOpened(Interactor interactor, IInteractable interactable, GameObject go)
		{
			int playerNum = 0;
			for (int i = 0; i < totalNumberPlayers; i++)
			{
				if ((Object)(object)((Component)TasksPlugin.GetPlayerCharacterMaster(i).GetBody()).GetComponent<Interactor>() == (Object)(object)interactor)
				{
					playerNum = i;
				}
			}
			if (Object.op_Implicit((Object)(object)((go != null) ? go.GetComponent<ChestBehavior>() : null)) && ((Object)go).name.Contains("Lockbox"))
			{
				CompleteTask(playerNum);
			}
		}
	}
	internal class GetLow : Task
	{
		private float[] lowPercents;

		public override TaskType type { get; } = TaskType.GetLow;


		protected override string name { get; } = "Get Low";


		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		public override string GetDescription()
		{
			return "Get to the lowest life. No dying.";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by getting down to " + GetStylizedTaskWinStat(lowPercents[winningPlayer].ToString("F2")) + "% hp.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in GetLow. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.onServerDamageDealt += OnDamage;
			lowPercents = new float[numPlayers];
			Reset();
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
			Reset();
		}

		protected override void Unhook()
		{
			GlobalEventManager.onServerDamageDealt -= OnDamage;
			base.Unhook();
		}

		private void OnDamage(DamageReport report)
		{
			if (report == null || report.victimMaster == null || report.victim == null || report.victimMaster.playerCharacterMasterController == null)
			{
				return;
			}
			int playerNumber = TasksPlugin.GetPlayerNumber(report.victimMaster);
			float num = 100f * (report.victim.health + report.victim.shield) / report.victim.fullCombinedHealth;
			if (num > 0f)
			{
				if (num < lowPercents[playerNumber])
				{
					lowPercents[playerNumber] = num;
					UpdateProgress();
				}
			}
			else
			{
				lowPercents[playerNumber] = 101f;
				UpdateProgress();
			}
		}

		protected void UpdateProgress()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = (100f - lowPercents[i]) / 100f;
			}
			base.UpdateProgress(progress);
		}

		private void Evaluate()
		{
			float num = 100f;
			int playerNum = 0;
			for (int i = 0; i < lowPercents.Length; i++)
			{
				if (lowPercents[i] < num)
				{
					num = lowPercents[i];
					playerNum = i;
				}
			}
			CompleteTask(playerNum);
		}

		private void Reset()
		{
			if (lowPercents != null)
			{
				for (int i = 0; i < lowPercents.Length; i++)
				{
					lowPercents[i] = 100f;
				}
				ResetProgress();
			}
		}
	}
	internal class GetLucky : Task
	{
		private bool active = false;

		public override TaskType type { get; } = TaskType.GetLucky;


		protected override string name { get; } = "Get Lucky";


		public override bool CanActivate(int numPlayers)
		{
			return true;
		}

		public override string GetDescription()
		{
			return "Be the luckiest.";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by getting " + GetStylizedTaskWinStat("lucky") + ".";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set hooks in GetLucky. {numPlayers} players");
			base.SetHooks(numPlayers);
			active = true;
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
		}

		protected override void Unhook()
		{
			base.Unhook();
		}

		private void Evaluate()
		{
			int playerNum = Random.Range(0, totalNumberPlayers);
			if (totalNumberPlayers == 1)
			{
				playerNum = Random.Range(0, 4);
			}
			if (Object.op_Implicit((Object)(object)TasksPlugin.instance))
			{
				((MonoBehaviour)TasksPlugin.instance).StartCoroutine(RollEvent(playerNum));
			}
		}

		private string GetRollMessage()
		{
			WeightedSelection<string> val = new WeightedSelection<string>(8);
			val.AddChoice("Rolling...", 1f);
			val.AddChoice("Who's going to be the lucky one?", 1f);
			val.AddChoice("Feeling lucky?", 1f);
			val.AddChoice("Choosing the winner. Stand by.", 1f);
			val.AddChoice("Scratching the lottery ticket.", 1f);
			val.AddChoice("Rolling for the winner.", 1f);
			val.AddChoice("Flipping a coin. Call it in the air.", 1f);
			val.AddChoice("Rigging the draw. Please wait.", 1f);
			return "<style=cEvent>" + val.Evaluate(Random.value) + "</style>";
		}

		private string GetWinFlavourMessage(string playerName)
		{
			WeightedSelection<string> val = new WeightedSelection<string>(8);
			playerName = GetStylizedTaskName(playerName);
			val.AddChoice(playerName + " won!", 1f);
			val.AddChoice(playerName + " was the lucky one!", 1f);
			val.AddChoice("Congrats, " + playerName + ".", 1f);
			val.AddChoice("The winner is " + playerName + ".", 1f);
			val.AddChoice("Your winner was " + playerName + ".", 1f);
			val.AddChoice("Congrats, " + playerName + ".", 1f);
			val.AddChoice("It's your lucky day, " + playerName + ".", 1f);
			val.AddChoice("Enjoy your prize, " + playerName + ".", 1f);
			val.AddChoice(playerName + " won, but it was rigged from the start.", 1f);
			val.AddChoice("Everyone loses except for " + playerName + ".", 1f);
			return val.Evaluate(Random.value);
		}

		private IEnumerator RollEvent(int playerNum)
		{
			ChatMessage.Send(GetRollMessage());
			yield return (object)new WaitForSeconds(1.5f);
			string name = "Nobody";
			if (totalNumberPlayers > 1 || playerNum == 0)
			{
				name = Util.GetBestMasterName(TasksPlugin.GetPlayerCharacterMaster(playerNum));
				CompleteTask(playerNum);
			}
			ChatMessage.Send(GetWinFlavourMessage(name));
		}
	}
	internal class HealingItem : Task
	{
		public override TaskType type { get; } = TaskType.HealingItem;


		protected override string name { get; } = "Find a Healing Item";


		public override string GetDescription()
		{
			return "Find a healing item";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by finding a " + GetStylizedTaskWinStat("healing") + " item first.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in HealingItem. {numPlayers} players");
			base.SetHooks(numPlayers);
			Inventory.onServerItemGiven += OnItemGained;
		}

		protected override void Unhook()
		{
			Inventory.onServerItemGiven -= OnItemGained;
			base.Unhook();
		}

		private void OnItemGained(Inventory inventory, ItemIndex item, int count)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (!ItemCatalog.GetItemDef(item).ContainsTag((ItemTag)2))
			{
				return;
			}
			for (int i = 0; i < totalNumberPlayers; i++)
			{
				if ((Object)(object)TasksPlugin.GetPlayerCharacterMaster(i).inventory == (Object)(object)inventory)
				{
					CompleteTask(i);
					break;
				}
			}
		}
	}
	internal class KillStreak : Task
	{
		private int[] bestStreaks;

		private int[] currentStreaks;

		public override TaskType type { get; } = TaskType.KillStreak;


		protected override string name { get; } = "Kill Streak";


		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		public override string GetDescription()
		{
			return "Most kills without getting hit";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " with a streak of " + GetStylizedTaskWinStat(bestStreaks[winningPlayer].ToString()) + ".";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in KillStreak. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.onServerDamageDealt += OnDamage;
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
			bestStreaks = new int[numPlayers];
			currentStreaks = new int[numPlayers];
			Reset();
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
			Reset();
		}

		protected override void Unhook()
		{
			GlobalEventManager.onServerDamageDealt -= OnDamage;
			GlobalEventManager.onCharacterDeathGlobal -= OnKill;
			base.Unhook();
		}

		private void OnDamage(DamageReport report)
		{
			if (report == null || report.victimMaster == null || report.victimMaster.playerCharacterMasterController == null)
			{
				return;
			}
			if (report.damageInfo.attacker == null && !report.isFallDamage)
			{
				Debug.Log((object)"KillStreak. Self damage ignore.");
				return;
			}
			int playerNumber = TasksPlugin.GetPlayerNumber(report.victimMaster);
			if (playerNumber > -1)
			{
				currentStreaks[playerNumber] = 0;
			}
		}

		private void OnKill(DamageReport report)
		{
			if (report != null && report.attackerMaster != null && report.attackerMaster.playerCharacterMasterController != null)
			{
				int playerNumber = TasksPlugin.GetPlayerNumber(report.attackerMaster);
				if (playerNumber > -1)
				{
					currentStreaks[playerNumber]++;
					UpdateStreaks(playerNumber);
				}
			}
		}

		private void UpdateStreaks(int playerNum)
		{
			if (currentStreaks[playerNum] > bestStreaks[playerNum])
			{
				Debug.Log((object)$"Player {playerNum} improved their streak. {bestStreaks[playerNum]} -> {currentStreaks[playerNum]}");
				bestStreaks[playerNum] = currentStreaks[playerNum];
				UpdateProgress();
			}
		}

		protected void UpdateProgress()
		{
			int num = 0;
			for (int i = 0; i < bestStreaks.Length; i++)
			{
				if (bestStreaks[i] > num)
				{
					num = bestStreaks[i];
				}
			}
			if (num > 0)
			{
				for (int j = 0; j < progress.Length; j++)
				{
					progress[j] = (float)bestStreaks[j] / (float)num;
				}
			}
			else
			{
				for (int k = 0; k < progress.Length; k++)
				{
					progress[k] = 0f;
				}
			}
			base.UpdateProgress(progress);
		}

		private void Evaluate()
		{
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < bestStreaks.Length; i++)
			{
				if (bestStreaks[i] > num2)
				{
					num2 = bestStreaks[i];
					num = i;
				}
			}
			Debug.Log((object)$"Player {num} won with a streak of {num2}");
			CompleteTask(num);
		}

		private void Reset()
		{
			if (bestStreaks != null && currentStreaks != null)
			{
				for (int i = 0; i < bestStreaks.Length; i++)
				{
					bestStreaks[i] = 0;
					currentStreaks[i] = 0;
				}
				ResetProgress();
			}
		}
	}
	internal class MostDistance : Task
	{
		private double[] startDistances;

		private double winnerDist;

		protected new string description { get; } = "Most distance wins";


		public override TaskType type { get; } = TaskType.MostDistance;


		protected override string name { get; } = "Most Distance";


		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by covering the most (" + GetStylizedTaskWinStat(winnerDist.ToString("F2")) + "m) distance.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in MostDistance. {numPlayers} players");
			base.SetHooks(numPlayers);
			if (startDistances == null || startDistances.Length != numPlayers)
			{
				startDistances = new double[numPlayers];
			}
			for (int i = 0; i < startDistances.Length; i++)
			{
				StatSheet currentStats = TasksPlugin.GetPlayerCharacterMaster(i).playerStatsComponent.currentStats;
				startDistances[i] = currentStats.GetStatValueDouble(StatDef.totalDistanceTraveled);
			}
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
		}

		protected override void Unhook()
		{
			base.Unhook();
		}

		private void Evaluate()
		{
			double num = 0.0;
			int num2 = 0;
			for (int i = 0; i < startDistances.Length; i++)
			{
				StatSheet currentStats = TasksPlugin.GetPlayerCharacterMaster(i).playerStatsComponent.currentStats;
				double statValueDouble = currentStats.GetStatValueDouble(StatDef.totalDistanceTraveled);
				double num3 = statValueDouble - startDistances[i];
				if (num3 > num)
				{
					num = num3;
					num2 = i;
				}
				Chat.AddMessage($"MostDist({i}): {startDistances[i]} -> {statValueDouble} = {num3}. Winner: {num2} with {num}");
			}
			winnerDist = num;
			CompleteTask(num2);
		}
	}
	internal class NoJump : Task
	{
		private bool[] playerFailed;

		private int numPlayersFailed;

		public override TaskType type { get; } = TaskType.NoJump;


		protected override string name { get; } = "No Jump";


		public override string GetDescription()
		{
			return "Don't jump";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by being the last to jump.";
		}

		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		protected override void SetHooks(int numPlayers)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			Debug.Log((object)$"Set Hooks in NoJump. {numPlayers} players");
			base.SetHooks(numPlayers);
			playerFailed = new bool[numPlayers];
			Reset();
			GenericCharacterMain.ApplyJumpVelocity += new hook_ApplyJumpVelocity(OnJump);
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
			Reset();
		}

		protected override void Unhook()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			GenericCharacterMain.ApplyJumpVelocity -= new hook_ApplyJumpVelocity(OnJump);
			base.Unhook();
		}

		private void Evaluate()
		{
			if (totalNumberPlayers - numPlayersFailed <= 1)
			{
				return;
			}
			for (int i = 0; i < playerFailed.Length; i++)
			{
				if (!playerFailed[i])
				{
					UpdateProgressMultiWinner();
					CompleteTask(i);
				}
			}
		}

		private void UpdateProgress()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = ((!playerFailed[i]) ? (numPlayersFailed / (totalNumberPlayers - 1)) : 0);
			}
			base.UpdateProgress(progress);
		}

		private void UpdateProgressMultiWinner()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = ((!playerFailed[i]) ? 1 : 0);
			}
			base.UpdateProgress(progress);
		}

		private void OnJump(orig_ApplyJumpVelocity orig, CharacterMotor characterMotor, CharacterBody characterBody, float horizontalBonus, float verticalBonus, bool vault = false)
		{
			orig.Invoke(characterMotor, characterBody, horizontalBonus, verticalBonus, vault);
			int playerNumber = TasksPlugin.GetPlayerNumber(characterBody.master);
			if (playerNumber < 0 || playerFailed[playerNumber])
			{
				return;
			}
			Debug.Log((object)$"Player {playerNumber} failed NoJump");
			playerFailed[playerNumber] = true;
			numPlayersFailed++;
			UpdateProgress();
			if (numPlayersFailed < totalNumberPlayers - 1)
			{
				return;
			}
			for (int i = 0; i < playerFailed.Length; i++)
			{
				if (!playerFailed[i])
				{
					CompleteTask(i);
					break;
				}
			}
		}

		private void Reset()
		{
			if (playerFailed != null)
			{
				for (int i = 0; i < playerFailed.Length; i++)
				{
					playerFailed[i] = false;
				}
				ResetProgress();
			}
		}
	}
	internal class OpenChests : Task
	{
		private int[] chestsOpened;

		private int numToOpen = 5;

		protected new string description { get; } = "First to open 5 chests wins (multishops count too)";


		public override TaskType type { get; } = TaskType.OpenChests;


		protected override string name { get; } = "Open 5 Chests";


		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by opening " + GetStylizedTaskWinStat(numToOpen.ToString()) + " chests first.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in OpenChests. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.OnInteractionsGlobal += ChestsOpened;
			chestsOpened = new int[numPlayers];
			Reset();
		}

		protected override void Unhook()
		{
			GlobalEventManager.OnInteractionsGlobal -= ChestsOpened;
			Reset();
			base.Unhook();
		}

		protected void UpdateProgress()
		{
			for (int i = 0; i < progress.Length; i++)
			{
				progress[i] = (float)chestsOpened[i] / (float)numToOpen;
			}
			base.UpdateProgress(progress);
		}

		private void ChestsOpened(Interactor interactor, IInteractable interactable, GameObject go)
		{
			int num = 0;
			for (int i = 0; i < chestsOpened.Length; i++)
			{
				if ((Object)(object)((Component)TasksPlugin.GetPlayerCharacterMaster(i).GetBody()).GetComponent<Interactor>() == (Object)(object)interactor)
				{
					num = i;
				}
			}
			if (Object.op_Implicit((Object)(object)((go != null) ? go.GetComponent<ChestBehavior>() : null)))
			{
				chestsOpened[num]++;
			}
			else if (Object.op_Implicit((Object)(object)((go != null) ? go.GetComponent<ShopTerminalBehavior>() : null)) && ((Object)go).name.Contains("MultiShop"))
			{
				chestsOpened[num]++;
			}
			UpdateProgress();
			if (IsComplete(num))
			{
				CompleteTask(num);
			}
		}

		protected override bool IsComplete(int playerNum)
		{
			return chestsOpened[playerNum] >= numToOpen;
		}

		private void Reset()
		{
			if (chestsOpened != null)
			{
				for (int i = 0; i < chestsOpened.Length; i++)
				{
					chestsOpened[i] = 0;
				}
				ResetProgress();
			}
		}
	}
	internal class OrderedSkills : Task
	{
		private SkillSlot[] order;

		private int[] whereInOrder;

		protected new string description { get; } = "Use skills in order";


		public override TaskType type { get; } = TaskType.OrderedSkills;


		protected override string name { get; } = "Ordered Skills";


		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by using their abilities in order.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in OrderedSkills. {numPlayers} players");
			base.SetHooks(numPlayers);
			SkillSlot[] array = new SkillSlot[4];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			order = (SkillSlot[])(object)array;
			whereInOrder = new int[numPlayers];
			Reset();
			TasksPlugin.OnAbilityUsed += AbilityUsed;
		}

		protected override void Unhook()
		{
			TasksPlugin.OnAbilityUsed -= AbilityUsed;
			Reset();
			base.Unhook();
		}

		private void AbilityUsed(int playerNum, SkillSlot slot)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between I4 and Unknown
			int num = whereInOrder[playerNum];
			if ((int)order[num] == (int)slot)
			{
				whereInOrder[playerNum]++;
				if (whereInOrder[playerNum] >= order.Length)
				{
					CompleteTask(playerNum);
				}
			}
			else
			{
				whereInOrder[playerNum] = 0;
			}
		}

		private void Reset()
		{
			if (whereInOrder != null)
			{
				for (int i = 0; i < whereInOrder.Length; i++)
				{
					whereInOrder[i] = 0;
				}
			}
		}
	}
	internal class PreonEvent : Task
	{
		private int[] kills;

		private int preonIndex = -1;

		protected new string description { get; } = "Most Preon kills wins";


		public override TaskType type { get; } = TaskType.PreonEvent;


		protected override string name { get; } = "Preon Event";


		public override bool CanActivate(int numPlayers)
		{
			return numPlayers > 1;
		}

		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by getting " + GetStylizedTaskWinStat(kills[winningPlayer].ToString()) + " kills with the Preon Accumulator.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in PreonEvent. {numPlayers} players");
			base.SetHooks(numPlayers);
			preonIndex = ProjectileCatalog.FindProjectileIndex("BeamSphere");
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
			if (kills == null || kills.Length != numPlayers)
			{
				kills = new int[numPlayers];
			}
			Reset();
			TasksPlugin.StartPreonEvent();
		}

		protected override void StageEnd()
		{
			base.StageEnd();
			Evaluate();
			TasksPlugin.EndPreonEvent();
			Reset();
		}

		protected override void Unhook()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnKill;
			base.Unhook();
		}

		protected void UpdateProgress()
		{
			int num = 0;
			for (int i = 0; i < kills.Length; i++)
			{
				if (kills[i] > num)
				{
					num = kills[i];
				}
			}
			if (num > 0)
			{
				for (int j = 0; j < progress.Length; j++)
				{
					progress[j] = (float)kills[j] / (float)num;
				}
			}
			else
			{
				for (int k = 0; k < progress.Length; k++)
				{
					progress[k] = 0f;
				}
			}
			base.UpdateProgress(progress);
		}

		public void OnKill(DamageReport damageReport)
		{
			if (damageReport != null && damageReport.attackerMaster != null && damageReport.attackerMaster.playerCharacterMasterController != null)
			{
				int playerNumber = TasksPlugin.GetPlayerNumber(damageReport.attackerMaster);
				if (ProjectileCatalog.GetProjectileIndex(damageReport.damageInfo.inflictor) == preonIndex)
				{
					kills[playerNumber]++;
					UpdateProgress();
				}
			}
		}

		private void Evaluate()
		{
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < kills.Length; i++)
			{
				if (kills[i] > num)
				{
					num = kills[i];
					num2 = i;
				}
			}
			Chat.AddMessage($"Player {num2} won Preon event with {num} kills");
			CompleteTask(num2);
		}

		private void Reset()
		{
			if (kills != null)
			{
				for (int i = 0; i < kills.Length; i++)
				{
					kills[i] = 0;
				}
				ResetProgress();
			}
		}
	}
	internal class QuickDraw : Task
	{
		public override TaskType type { get; } = TaskType.QuickDraw;


		protected override string name { get; } = "Quick Draw";


		public override string GetDescription()
		{
			return "Kill an enemy within 3s of spawning.";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by killing an enemy within " + GetStylizedTaskWinStat("3") + "s of spawning.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in KillStreak. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.onCharacterDeathGlobal += OnKill;
		}

		protected override void Unhook()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnKill;
			base.Unhook();
		}

		private void OnKill(DamageReport report)
		{
			//IL_002e: 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 (report != null && report.attackerMaster != null && report.attackerMaster.playerCharacterMasterController != null)
			{
				float num = FixedTimeStamp.now.t - report.victimBody.localStartTime.t;
				if (num < 3f)
				{
					int playerNumber = TasksPlugin.GetPlayerNumber(report.attackerMaster);
					CompleteTask(playerNumber);
				}
			}
		}
	}
	internal class RewardBuilder
	{
		public static Reward CreateRandomReward()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			WeightedSelection<RewardType> val = new WeightedSelection<RewardType>(8);
			val.AddChoice(RewardType.Item, 2f);
			val.AddChoice(RewardType.TempItem, 1f);
			val.AddChoice(RewardType.Command, 0.5f);
			val.AddChoice(RewardType.Drone, 0.5f);
			RewardType rewardType = val.Evaluate(Random.value);
			List<PickupIndex> list = Run.instance.smallChestDropTierSelector.Evaluate(Random.value);
			PickupIndex item = Run.instance.treasureRng.NextElementUniform<PickupIndex>(list);
			string randomDronePath = GetRandomDronePath();
			Reward result = new Reward(rewardType, item, (rewardType != RewardType.TempItem) ? 1 : 5, _temporary: false, 100, 100, randomDronePath);
			return result;
		}

		public static string GetRandomDronePath()
		{
			WeightedSelection<string> val = new WeightedSelection<string>(8);
			val.AddChoice("iscBrokenDrone1", 4f);
			val.AddChoice("iscBrokenDrone2", 4f);
			val.AddChoice("iscBrokenTurret1", 3f);
			val.AddChoice("iscBrokenFlameDrone", 1f);
			val.AddChoice("iscBrokenEmergencyDrone", 1f);
			val.AddChoice("iscBrokenMissileDrone", 0.5f);
			return val.Evaluate(Random.value);
		}

		public static string GetDroneTexturePath(string spawnCardName)
		{
			return spawnCardName switch
			{
				"iscBrokenDrone1" => "Textures/BodyIcons/texDrone1Icon", 
				"iscBrokenDrone2" => "Textures/BodyIcons/texDrone2Icon", 
				"iscBrokenTurret1" => "Textures/BodyIcons/texTurret1Icon", 
				"iscBrokenFlameDrone" => "Textures/BodyIcons/FlameDroneBody", 
				"iscBrokenEmergencyDrone" => "Textures/BodyIcons/EmergencyDroneBody", 
				"iscBrokenMissileDrone" => "Textures/BodyIcons/texMissileDroneIcon", 
				_ => "Textures/BodyIcons/texDrone1Icon", 
			};
		}

		public static void GivePlayerDrone(int playerNum, string droneSpawnCardName)
		{
			//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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_0064: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			CharacterBody body = TasksPlugin.GetPlayerCharacterMaster(playerNum).GetBody();
			GameObject val = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(Resources.Load<SpawnCard>("SpawnCards/InteractableSpawnCard/" + droneSpawnCardName), new DirectorPlacementRule
			{
				placementMode = (PlacementMode)3,
				position = body.transform.position + new Vector3(1f, 0f, 0f)
			}, new Xoroshiro128Plus(0uL)));
			PurchaseInteraction component = val.GetComponent<PurchaseInteraction>();
			component.cost = 0;
			Interactor component2 = ((Component)body).GetComponent<Interactor>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				component.OnInteractionBegin(component2);
			}
		}
	}
	public struct Reward
	{
		public RewardType type;

		public PickupIndex item;

		public int numItems;

		public bool temporary;

		public int gold;

		public int xp;

		public string dronePath;

		public Reward(RewardType _type, PickupIndex _item, int _numItems, bool _temporary, int _gold, int _xp, string _path)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			type = _type;
			item = _item;
			numItems = _numItems;
			temporary = _temporary;
			gold = _gold;
			xp = _xp;
			dronePath = _path;
		}

		public override string ToString()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return $"{type:g}, {item:g}";
		}
	}
	public struct TempItem
	{
		public PickupIndex item;

		public int count;

		public TempItem(PickupIndex _item, int _count)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			item = _item;
			count = _count;
		}
	}
	public enum RewardType
	{
		Item,
		TempItem,
		Command,
		Gold,
		Xp,
		Drone
	}
	public class TaskInfo : MessageBase
	{
		public int taskType;

		public string description;

		public bool completed;

		public int index;

		public int total;

		public Reward reward;

		public override void Serialize(NetworkWriter writer)
		{
			writer.Write(taskType);
			writer.Write(description);
			writer.Write(completed);
			writer.Write(index);
			writer.Write(total);
			writer.Write((int)reward.type);
			writer.Write(reward.item.value);
			writer.Write(reward.numItems);
			writer.Write(reward.temporary);
			writer.Write(reward.gold);
			writer.Write(reward.xp);
			writer.Write(reward.dronePath);
		}

		public override void Deserialize(NetworkReader reader)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			taskType = reader.ReadInt32();
			description = reader.ReadString();
			completed = reader.ReadBoolean();
			index = reader.ReadInt32();
			total = reader.ReadInt32();
			int type = reader.ReadInt32();
			int num = reader.ReadInt32();
			int numItems = reader.ReadInt32();
			bool temporary = reader.ReadBoolean();
			int gold = reader.ReadInt32();
			int xp = reader.ReadInt32();
			string path = reader.ReadString();
			PickupIndex item = default(PickupIndex);
			((PickupIndex)(ref item))..ctor(num);
			reward = new Reward((RewardType)type, item, numItems, temporary, gold, xp, path);
		}

		public TaskInfo(int _type, string _description, bool _completed, int _index, int _total, Reward _reward)
		{
			taskType = _type;
			description = _description;
			completed = _completed;
			index = _index;
			total = _total;
			reward = _reward;
		}

		public TaskInfo(NetworkReader reader)
		{
			((MessageBase)this).Deserialize(reader);
		}

		public override string ToString()
		{
			return $"TaskInfo: {taskType}, {description}, {completed}, {index}/{total}";
		}
	}
	public class ProgressInfo : MessageBase
	{
		public int taskIndex;

		private float myProgress;

		private float rivalProgress;

		public ProgressInfo(int _taskIndex, float _myProgress, float _rivalProgress)
		{
			taskIndex = _taskIndex;
			myProgress = _myProgress;
			rivalProgress = _rivalProgress;
		}

		public ProgressInfo(int _taskIndex, int _myProgress, int _rivalProgress)
		{
			taskIndex = _taskIndex;
			myProgress = _myProgress;
			rivalProgress = _rivalProgress;
		}

		public float GetMyProgress()
		{
			return myProgress;
		}

		public float GetRivalProgress()
		{
			return rivalProgress;
		}

		public override void Serialize(NetworkWriter writer)
		{
			writer.Write(taskIndex);
			writer.Write(myProgress);
			writer.Write(rivalProgress);
		}

		public override void Deserialize(NetworkReader reader)
		{
			taskIndex = reader.ReadInt32();
			myProgress = reader.ReadSingle();
			rivalProgress = reader.ReadSingle();
		}
	}
	public class TaskCompletionInfo : MessageBase
	{
		public int taskType;

		public string winnerName;

		public TaskCompletionInfo(int _taskType, string _winnerName)
		{
			taskType = _taskType;
			winnerName = _winnerName;
		}

		public override void Serialize(NetworkWriter writer)
		{
			writer.Write(taskType);
			writer.Write(winnerName);
		}

		public override void Deserialize(NetworkReader reader)
		{
			taskType = reader.ReadInt32();
			winnerName = reader.ReadString();
		}
	}
	internal class StartTeleporter : Task
	{
		private float soloTimer;

		private float soloTimeAmountSec = 90f;

		private bool hasFailed = false;

		private bool succeeded = false;

		protected new string description { get; } = "Better be First";


		public override TaskType type { get; } = TaskType.StartTele;


		protected override string name { get; } = "Activate the Teleporter";


		public override bool CanActivate(int numPlayers)
		{
			return true;
		}

		public override string GetDescription()
		{
			return description;
		}

		public override string GetWinMessage(int winningPlayer)
		{
			if (winningPlayer < 0)
			{
				return "You failed " + GetStylizedTaskName(name) + " by not getting to the " + GetStylizedTaskWinStat("teleporter") + " in " + GetStylizedTaskWinStat(soloTimeAmountSec.ToString()) + " seconds.";
			}
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by triggering the " + GetStylizedTaskWinStat("teleporter") + " first.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in StartTele. {numPlayers} players");
			base.SetHooks(numPlayers);
			GlobalEventManager.OnInteractionsGlobal += OnInteraction;
			if (numPlayers == 1)
			{
				StartSolo();
			}
		}

		protected override void Unhook()
		{
			GlobalEventManager.OnInteractionsGlobal -= OnInteraction;
			base.Unhook();
		}

		private void OnInteraction(Interactor interactor, IInteractable interactable, GameObject go)
		{
			int playerNum = 0;
			for (int i = 0; i < totalNumberPlayers; i++)
			{
				if ((Object)(object)((Component)TasksPlugin.GetPlayerCharacterMaster(i).GetBody()).GetComponent<Interactor>() == (Object)(object)interactor)
				{
					playerNum = i;
				}
			}
			if (Object.op_Implicit((Object)(object)((go != null) ? go.GetComponent<TeleporterInteraction>() : null)))
			{
				Evaluate(playerNum);
			}
		}

		private void StartSolo()
		{
			if (Object.op_Implicit((Object)(object)TasksPlugin.instance))
			{
				((MonoBehaviour)TasksPlugin.instance).StartCoroutine(Countdown());
			}
		}

		private IEnumerator Countdown()
		{
			hasFailed = false;
			succeeded = false;
			soloTimer = soloTimeAmountSec;
			for (int i = 0; (float)i < soloTimeAmountSec; i++)
			{
				yield return (object)new WaitForSeconds(1f);
				soloTimer -= 1f;
				UpdateProgressSolo();
			}
			hasFailed = true;
			if (!succeeded)
			{
				CompleteTask(-1);
			}
		}

		private void Evaluate(int playerNum)
		{
			if (totalNumberPlayers > 1)
			{
				CompleteTask(playerNum);
			}
			else if (!hasFailed)
			{
				succeeded = true;
				CompleteTask(playerNum);
			}
		}

		private void UpdateProgressSolo()
		{
			if (succeeded)
			{
				progress[0] = 0f;
			}
			else
			{
				progress[0] = Mathf.Max(0f, soloTimer / soloTimeAmountSec);
			}
			base.UpdateProgress(progress);
		}
	}
	internal class StayInAir : Task
	{
		private CharacterMotor[] motors;

		private CharacterBody[] bodies;

		private float[] timeInAir;

		private float timeToStayInAir;

		protected new string description { get; } = "Stay airborne for 10 seconds";


		public override TaskType type { get; } = TaskType.StayInAir;


		protected override string name { get; } = "Stay Airborne";


		public override string GetDescription()
		{
			return $"Stay in the air for {Math.Round(timeToStayInAir, 1)} seconds";
		}

		public override string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + GetStylizedTaskName(name) + " by staying in the air for " + GetStylizedTaskWinStat(timeToStayInAir.ToString("0.00")) + "s.";
		}

		protected override void SetHooks(int numPlayers)
		{
			Debug.Log((object)$"Set Hooks in Stay Airborne. {numPlayers} players");
			base.SetHooks(numPlayers);
			timeToStayInAir = 2f + Run.instance.difficultyCoefficient;
			if (timeInAir == null || timeInAir.Length != numPlayers)
			{
				timeInAir = new float[numPlayers];
				for (int i = 0; i < timeInAir.Length; i++)
				{
					timeInAir[i] = 0f;
				}
			}
			if (motors == null || motors.Length != numPlayers)
			{
				motors = (CharacterMotor[])(object)new CharacterMotor[numPlayers];
			}
			if (bodies == null || motors.Length != numPlayers)
			{
				bodies = (CharacterBody[])(object)new CharacterBody[numPlayers];
			}
			SetupBodies();
			RoR2Application.onFixedUpdate += AirborneFixedUpdate;
		}

		protected override void Unhook()
		{
			RoR2Application.onFixedUpdate -= AirborneFixedUpdate;
			Reset();
			base.Unhook();
		}

		protected void UpdateProgress()
		{
			if (timeInAir != null && progress != null)
			{
				for (int i = 0; i < progress.Length; i++)
				{
					progress[i] = timeInAir[i] / timeToStayInAir;
				}
				base.UpdateProgress(progress);
			}
		}

		private void AirborneFixedUpdate()
		{
			UpdateProgress();
			for (int i = 0; i < timeInAir.Length; i++)
			{
				timeInAir[i] = ((Object.op_Implicit((Object)(object)motors[i]) && !motors[i].isGrounded && !Object.op_Implicit((Object)(object)bodies[i].currentVehicle)) ? (timeInAir[i] + Time.fixedDeltaTime) : 0f);
				if (IsComplete(i))
				{
					CompleteTask(i);
					Reset();
				}
			}
		}

		protected override bool IsComplete(int playerNum)
		{
			return timeInAir[playerNum] >= timeToStayInAir;
		}

		private void Reset()
		{
			UpdateProgress();
			if (timeInAir != null)
			{
				for (int i = 0; i < timeInAir.Length; i++)
				{
					timeInAir[i] = 0f;
				}
				ResetProgress();
			}
		}

		private void SetupBodies()
		{
			for (int i = 0; i < motors.Length; i++)
			{
				CharacterMaster playerCharacterMaster = TasksPlugin.GetPlayerCharacterMaster(i);
				bodies[i] = playerCharacterMaster.GetBody();
				motors[i] = playerCharacterMaster.GetBody().characterMotor;
			}
		}
	}
	public enum TaskType
	{
		Base,
		AirKills,
		DamageMultiple,
		DamageInTime,
		StayInAir,
		BiggestHit,
		MostDistance,
		PreonEvent,
		FarthestAway,
		FailShrine,
		OpenChests,
		StartTele,
		UsePrinters,
		OrderedSkills,
		BadSkill,
		BabyDrone,
		Die,
		FindLockbox,
		HealingItem,
		NoJump,
		VeryBest,
		FewestElites,
		GetLucky,
		GetLow,
		KillStreak,
		QuickDraw,
		FarKill,
		FewElites
	}
	internal class Task
	{
		private static string myName = "SOLRUN_";

		private static string myMod = "TASKS_";

		protected static string thisClass = "BASE_TASK_";

		protected int totalNumberPlayers;

		protected float[] progress;

		private bool taskActive = false;

		protected string description { get; } = "Base description";


		public virtual TaskType type { get; } = TaskType.Base;


		protected virtual string name { get; } = "Base Task";


		public static event Action<TaskType, int, string> OnCompletion;

		public static event Action<TaskType, float[]> OnUpdateProgress;

		public Task()
		{
			OnInstall();
		}

		protected virtual void SetupName()
		{
		}

		public virtual string GetDescription()
		{
			return description;
		}

		public virtual void OnInstall()
		{
			Run.onRunDestroyGlobal += RunOver;
			TasksPlugin.OnActivate += Activate;
			TasksPlugin.OnDeactivate += Deactivate;
			TasksPlugin.OnCancelAll += CancelAllTasks;
		}

		public virtual void OnUninstall()
		{
			Run.onRunDestroyGlobal -= RunOver;
			TasksPlugin.OnActivate -= Activate;
			TasksPlugin.OnDeactivate -= Deactivate;
			TasksPlugin.OnCancelAll -= CancelAllTasks;
		}

		protected virtual void UpdateProgress(float[] progress)
		{
			if (taskActive)
			{
				Task.OnUpdateProgress?.Invoke(type, progress);
			}
		}

		protected void ResetProgress()
		{
			TasksPlugin instance = TasksPlugin.instance;
			if (instance != null)
			{
				((MonoBehaviour)instance).StartCoroutine(ResetProgressInTime());
			}
		}

		private IEnumerator ResetProgressInTime()
		{
			yield return (object)new WaitForSeconds(4f);
			if (progress != null)
			{
				for (int i = 0; i < progress.Length; i++)
				{
					progress[i] = 0f;
				}
				if (taskActive)
				{
					Task.OnUpdateProgress?.Invoke(type, progress);
				}
				else
				{
					Debug.Log((object)$"{type:g} was inactive. Don't update progress");
				}
			}
		}

		public virtual string GetWinMessage(int winningPlayer)
		{
			return GetStylizedName(winningPlayer) + " completed " + name;
		}

		protected string GetStylizedName(int playerNum)
		{
			return "<color=#ffffff>" + TasksPlugin.GetPlayerName(playerNum) + "</color>";
		}

		protected string GetStylizedTaskName(string taskName)
		{
			return "<style=cIsUtility>" + taskName + "</style>";
		}

		protected string GetStylizedTaskWinStat(string stat)
		{
			return "<style=cIsUtility>" + stat + "</style>";
		}

		protected virtual void CompleteTask(int playerNum)
		{
			Unhook();
			Task.OnCompletion?.Invoke(type, playerNum, GetWinMessage(playerNum));
		}

		protected virtual bool IsComplete(int playerNum)
		{
			return false;
		}

		public virtual bool CanActivate(int numPlayers)
		{
			return true;
		}

		private void Activate(int id, int numPlayers)
		{
			if (id == (int)type)
			{
				totalNumberPlayers = numPlayers;
				progress = new float[numPlayers];
				SetHooks(numPlayers);
				taskActive = true;
			}
		}

		public void Deactivate(int id)
		{
			if (id == (int)type || id < 0)
			{
				taskActive = false;
				StageEnd();
				Unhook();
			}
		}

		public void CancelAllTasks()
		{
			taskActive = false;
			Unhook();
		}

		protected virtual void StageEnd()
		{
		}

		protected virtual void SetHooks(int numPlayers)
		{
		}

		protected virtual void Unhook()
		{
		}

		private void RunOver(Run run)
		{
			Unhook();
			OnUninstall();
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.Solrun.Tasks", "Tasks", "1.2.4")]
	public sealed class TasksPlugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_OnCollisionEnter <0>__TurnOffCommand;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static hook_OnSkillActivated <>9__48_0;

			public static Func<string> <>9__65_1;

			internal void <SetGameHooks>b__48_0(orig_OnSkillActivated orig, CharacterBody self, GenericSkill param)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				if (NetworkServer.active && self.isPlayerControlled)
				{
					int playerNumber = GetPlayerNumber(self.master);
					SkillSlot arg = self.skillLocator.FindSkillSlot(param);
					TasksPlugin.OnAbilityUsed?.Invoke(playerNumber, arg);
				}
				orig.Invoke(self, param);
			}

			internal string <CreateNotification>b__65_1()
			{
				return "Task Complete!";
			}
		}

		public const string MODNAME = "Tasks";

		public const string AUTHOR = "Solrun";

		public const string GUID = "com.Solrun.Tasks";

		public const string VERSION = "1.2.4";

		public static TasksPlugin instance;

		private static List<CharacterMaster> playerCharacterMasters;

		private int totalNumPlayers = 0;

		private int totalNumTasks;

		public Reward[] rewards;

		private List<TempItem>[] TempItemLists;

		private EquipmentIndex[] preonEventEqCache;

		private int[] stageStartTasks;

		private int[] teleStartTasks;

		private Task[] taskCopies;

		private bool telePlaced = false;

		public TaskInfo[] currentTasks;

		public GameObject[] tasksUIObjects;

		public RectTransform[] tasksUIRects;

		public RectTransform[] rivalTasksUIRects;

		private HUD hud;

		private ObjectivePanelController panel;

		private GameObject itemIconPrefabCopy;

		private bool rectWasAlreadyNull = false;

		private bool rivalRectWasAlreadyNull = false;

		public static event Action<int, int> OnActivate;

		public static event Action<int> OnDeactivate;

		public static event Action OnCancelAll;

		public static event Action<int> OnPopup;

		public static event Action<int, SkillSlot> OnAbilityUsed;

		public void InvokeOnPopup(int taskType)
		{
			TasksPlugin.OnPopup?.Invoke(taskType);
		}

		private void Awake()
		{
			Chat.AddMessage("Loaded Task plugin");
			if (instance == null)
			{
				instance = this;
			}
			ConfigManager configManager = new ConfigManager();
			ConfigManager.instance.SetConfigFile(((BaseUnityPlugin)this).Config);
			ConfigManager.instance.Awake();
			Task.OnCompletion += TaskCompletion;
			Task.OnUpdateProgress += UpdateTaskProgress;
			Run.onRunStartGlobal += GameSetup;
			SetupNetworking();
			SetGameHooks();
		}

		private void Start()
		{
		}

		public void Update()
		{
			if (0 == 0)
			{
			}
		}

		private void GameSetup(Run run)
		{
			totalNumTasks = Enum.GetNames(typeof(TaskType)).Length;
			rewards = new Reward[totalNumTasks];
			Debug.Log((object)$"Tasks mod: Number of players: {run.participatingPlayerCount} Living Players: {run.livingPlayerCount}");
			totalNumPlayers = run.participatingPlayerCount;
			playerCharacterMasters = new List<CharacterMaster>(totalNumPlayers);
			rectWasAlreadyNull = false;
			rivalRectWasAlreadyNull = false;
			PopulatePlayerCharaterMasterList();
			if (NetworkServer.active)
			{
				TaskSetup();
				PopulateTempItemLists();
				TasksPlugin.OnCancelAll?.Invoke();
			}
		}

		private void TaskSetup()
		{
			Debug.Log((object)"Creating Task Objects");
			taskCopies = new Task[27];
			AirKills airKills = new AirKills();
			DamageMultipleTargets damageMultipleTargets = new DamageMultipleTargets();
			DealDamageInTime dealDamageInTime = new DealDamageInTime();
			StayInAir stayInAir = new StayInAir();
			BiggestHit biggestHit = new BiggestHit();
			MostDistance mostDistance = new MostDistance();
			PreonEvent preonEvent = new PreonEvent();
			FarthestAway farthestAway = new FarthestAway();
			FailShrine failShrine = new FailShrine();
			OpenChests openChests = new OpenChests();
			StartTeleporter startTeleporter = new StartTeleporter();
			UsePrinters usePrinters = new UsePrinters();
			OrderedSkills orderedSkills = new OrderedSkills();
			DontUseSkill dontUseSkill = new DontUseSkill();
			BabyDrone babyDrone = new BabyDrone();
			Die die = new Die();
			FindLockbox findLockbox = new FindLockbox();
			HealingItem healingItem = new HealingItem();
			NoJump noJump = new NoJump();
			VeryBest veryBest = new VeryBest();
			FewestElites fewestElites = new FewestElites();
			GetLucky getLucky = new GetLucky();
			GetLow getLow = new GetLow();
			KillStreak killStreak = new KillStreak();
			QuickDraw quickDraw = new QuickDraw();
			FarKill farKill = new FarKill();
			FewElites fewElites = new FewElites();
			taskCopies[(int)(airKills.type - 1)] = airKills;
			taskCopies[(int)(damageMultipleTargets.type - 1)] = damageMultipleTargets;
			taskCopies[(int)(dealDamageInTime.type - 1)] = dealDamageInTime;
			taskCopies[(int)(stayInAir.type - 1)] = stayInAir;
			taskCopies[(int)(biggestHit.type - 1)] = biggestHit;
			taskCopies[(int)(mostDistance.type - 1)] = mostDistance;
			taskCopies[(int)(preonEvent.type - 1)] = preonEvent;
			taskCopies[(int)(farthestAway.type - 1)] = farthestAway;
			taskCopies[(int)(failShrine.type - 1)] = failShrine;
			taskCopies[(int)(openChests.type - 1)] = openChests;
			taskCopies[(int)(startTeleporter.type - 1)] = startTeleporter;
			taskCopies[(int)(usePrinters.type - 1)] = usePrinters;
			taskCopies[(int)(orderedSkills.type - 1)] = orderedSkills;
			taskCopies[(int)(dontUseSkill.type - 1)] = dontUseSkill;
			taskCopies[(int)(babyDrone.type - 1)] = babyDrone;
			taskCopies[(int)(die.type - 1)] = die;
			taskCopies[(int)(findLockbox.type - 1)] = findLockbox;
			taskCopies[(int)(healingItem.type - 1)] = healingItem;
			taskCopies[(int)(noJump.type - 1)] = noJump;
			taskCopies[(int)(veryBest.type - 1)] = veryBest;
			taskCopies[(int)(fewestElites.type - 1)] = fewestElites;
			taskCopies[(int)(getLucky.type - 1)] = getLucky;
			taskCopies[(int)(getLow.type - 1)] = getLow;
			taskCopies[(int)(killStreak.type - 1)] = killStreak;
			taskCopies[(int)(quickDraw.type - 1)] = quickDraw;
			taskCopies[(int)(farKill.type - 1)] = farKill;
			taskCopies[(int)(fewElites.type - 1)] = fewElites;
		}

		private void PopulatePlayerCharaterMasterList()
		{
			for (int i = 0; i < CharacterMaster.readOnlyInstancesList.Count; i++)
			{
				if ((Object)(object)CharacterMaster.readOnlyInstancesList[i].playerCharacterMasterController != (Object)null)
				{
					playerCharacterMasters.Add(CharacterMaster.readOnlyInstancesList[i]);
				}
			}
		}

		private void PopulateTempItemLists()
		{
			TempItemLists = new List<TempItem>[CharacterMaster.readOnlyInstancesList.Count];
			for (int i = 0; i < TempItemLists.Length; i++)
			{
				TempItemLists[i] = new List<TempItem>();
			}
		}

		private void SetupNetworking()
		{
			NetworkingAPI.RegisterMessageType<SyncTaskCompletion>();
			NetworkingAPI.RegisterMessageType<SyncTaskEnded>();
			NetworkingAPI.RegisterMessageType<SyncUpdateTask>();
			NetworkingAPI.RegisterMessageType<SyncUpdateProgress>();
		}

		private void SetGameHooks()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			object obj = <>c.<>9__48_0;
			if (obj == null)
			{
				hook_OnSkillActivated val = delegate(orig_OnSkillActivated orig, CharacterBody self, GenericSkill param)
				{
					//IL_0029: Unknown result type (might be due to invalid IL or missing references)
					//IL_002e: Unknown result type (might be due to invalid IL or missing references)
					//IL_003b: Unknown result type (might be due to invalid IL or missing references)
					if (NetworkServer.active && self.isPlayerControlled)
					{
						int playerNumber = GetPlayerNumber(self.master);
						SkillSlot arg = self.skillLocator.FindSkillSlot(param);
						TasksPlugin.OnAbilityUsed?.Invoke(playerNumber, arg);
					}
					orig.Invoke(self, param);
				};
				<>c.<>9__48_0 = val;
				obj = (object)val;
			}
			CharacterBody.OnSkillActivated += (hook_OnSkillActivated)obj;
			GlobalEventManager.OnInteractionsGlobal += delegate(Interactor interactor, IInteractable interactable, GameObject go)
			{
				string text = ((object)interactable).GetType().ToString();
				if (Object.op_Implicit((Object)(object)((go != null) ? go.GetComponent<TeleporterInteraction>() : null)))
				{
					Debug.Log((object)("Interacted with TP. InterType: " + text + " name: " + ((Object)go).name));
				}
				else if (Object.op_Implicit((Object)(object)((go != null) ? go.GetComponent<SceneExitController>() : null)))
				{
					Debug.Log((object)("Interacted with a SceneExitController " + ((Object)go).name));
					StageEnd();
				}
			};
			TeleporterInteraction.onTeleporterFinishGlobal += delegate
			{
				Debug.Log((object)"TP finished and player chose to leave");
				if (NetworkServer.active)
				{
					StageEnd();
				}
			};
			Run.OnServerTeleporterPlaced += (hook_OnServerTeleporterPlaced)delegate(orig_OnServerTeleporterPlaced orig, Run self, SceneDirector director, GameObject teleporter)
			{
				orig.Invoke(self, director, teleporter);
				telePlaced = true;
			};
			HudObjectiveTargetSetter.Update += (hook_Update)delegate(orig_Update orig, HudObjectiveTargetSetter self)
			{
				orig.Invoke(self);
				if ((Object)(object)panel == (Object)null)
				{
					Debug.Log((object)"Panel is null in HudObjSetter.Update");
				}
				if (self.objectivePanelController == null)
				{
					Debug.Log((object)"Task mod: objectivePanelController was null");
				}
				if (Object.op_Implicit((Object)(object)self.objectivePanelController))
				{
					panel = self.objectivePanelController;
				}
			};
			HUD.Awake += (hook_Awake)delegate(orig_Awake orig, HUD self)
			{
				orig.Invoke(self);
				hud = self;
				int numberOfTasks = ConfigManager.instance.GetNumberOfTasks(totalNumPlayers);
				numberOfTasks = Math.Min(numberOfTasks, 7);
				tasksUIObjects = (GameObject[])(object)new GameObject[numberOfTasks];
				tasksUIRects = (RectTransform[])(object)new RectTransform[numberOfTasks];
				rivalTasksUIRects = (RectTransform[])(object)new RectTransform[numberOfTasks];
				if (telePlaced && NetworkServer.active)
				{
					GenerateTasks(numberOfTasks);
				}
			};
			GameOverController.Awake += (hook_Awake)delegate(orig_Awake orig, GameOverController self)
			{
				Debug.Log((object)"GameOverController.Awake");
				CancelAllTasks();
				orig.Invoke(self);
			};
		}

		public void UpdateTasksUI(int taskIndex, string text = "")
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be