Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TasksRevived v1.2.5
Tasks.dll
Decompiled 6 months ago
The result has been truncated due to the large size, download it to view full contents!
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+3bda125dc5aa5a034a0728bb0d20bd1af632a188")] [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.5")] 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.5"; 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