using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnboundLib; using UnboundLib.Cards; using UnboundLib.GameModes; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 SummonerCards { [HarmonyPatch(typeof(CardChoice), "SpawnUniqueCard")] internal static class CardGatePatch { [ThreadStatic] private static int depth; private static readonly MethodInfo SpawnUnique = AccessTools.Method(typeof(CardChoice), "SpawnUniqueCard", new Type[2] { typeof(Vector3), typeof(Quaternion) }, (Type[])null); private static readonly FieldInfo PickerTypeField = AccessTools.Field(typeof(CardChoice), "pickerType"); private static void Postfix(CardChoice __instance, Vector3 pos, Quaternion rot, ref GameObject __result) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown try { if ((Object)(object)__result == (Object)null || depth > 40 || SpawnUnique == null) { return; } CardInfo component = __result.GetComponent(); Player picker = GetPicker(__instance); if ((Object)(object)component == (Object)null || (Object)(object)picker == (Object)null || UpgradeGate.IsAllowed(component, picker)) { return; } depth++; try { Object.Destroy((Object)(object)__result); __result = (GameObject)SpawnUnique.Invoke(__instance, new object[2] { pos, rot }); } finally { depth--; } } catch (Exception ex) { Plugin.Log.LogError((object)("SummonerCards card gate: " + ex)); } } private static Player GetPicker(CardChoice cc) { //IL_003e: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 int pickrID = cc.pickrID; if (pickrID < 0 || (Object)(object)PlayerManager.instance == (Object)null) { return null; } bool flag = false; if (PickerTypeField != null) { flag = PickerTypeField.GetValue(cc) is PickerType val && (int)val == 0; } if (flag) { Player[] playersInTeam = PlayerManager.instance.GetPlayersInTeam(pickrID); if (playersInTeam == null || playersInTeam.Length == 0) { return null; } return playersInTeam[0]; } List players = PlayerManager.instance.players; if (pickrID >= players.Count) { return null; } return players[pickrID]; } } public class CardDef { public string Title; public string Description; public Rarity Rarity = (Rarity)1; public CardThemeColorType Theme = (CardThemeColorType)3; public CardInfoStat[] Stats = Array.Empty(); public static CardInfoStat Stat(bool isGood, string label, string value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown return new CardInfoStat { positive = isGood, stat = label, amount = value }; } } public static class CardText { public static readonly CardDef Doppelganger = new CardDef { Title = "Doppelganger", Description = "Blocking splits off a clone that fights for you", Rarity = (Rarity)2, Theme = (CardThemeColorType)2, Stats = (CardInfoStat[])(object)new CardInfoStat[2] { CardDef.Stat(isGood: false, "Damage", "-50%"), CardDef.Stat(isGood: false, "Health", "-50%") } }; public static readonly CardDef Necromancer = new CardDef { Title = "Necromancer", Description = "Blocking raises everyone you've killed as allies", Rarity = (Rarity)2, Theme = (CardThemeColorType)4, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: false, "Undead stats", "-50%") } }; public static readonly CardDef Sentry = new CardDef { Title = "Sentry", Description = "Spawn a stationary turret that fires your weapon", Rarity = (Rarity)1, Theme = (CardThemeColorType)3, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: false, "Turret damage", "-50%") } }; public static readonly CardDef Hive = new CardDef { Title = "Hive", Description = "Spawn a bee hive and a swarm that fights for you", Rarity = (Rarity)2, Theme = (CardThemeColorType)1, Stats = (CardInfoStat[])(object)new CardInfoStat[3] { CardDef.Stat(isGood: true, "Bees", "+3"), CardDef.Stat(isGood: false, "Bee damage", "-65%"), CardDef.Stat(isGood: false, "Kill the hive", "swarm dies") } }; public static readonly CardDef Revenant = new CardDef { Title = "Revenant", Description = "Rise as a full-power ghost when you die", Rarity = (Rarity)2, Theme = (CardThemeColorType)4, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: false, "Ghost lasts", "10 seconds") } }; public static readonly CardDef BodyDouble = new CardDef { Title = "Body Double", Description = "Blocking swaps places with your clone", Rarity = (Rarity)1, Theme = (CardThemeColorType)2 }; public static readonly CardDef SplitSoul = new CardDef { Title = "Split Soul", Description = "You and your clone share one health pool", Rarity = (Rarity)1, Theme = (CardThemeColorType)2, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Split", "no health cost") } }; public static readonly CardDef HallOfMirrors = new CardDef { Title = "Hall of Mirrors", Description = "Keep a second clone out at once", Rarity = (Rarity)2, Theme = (CardThemeColorType)2, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Clones", "+1") } }; public static readonly CardDef SharperImage = new CardDef { Title = "Sharper Image", Description = "Your clone deals your full damage", Rarity = (Rarity)1, Theme = (CardThemeColorType)2, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Clone damage", "+100%") } }; public static readonly CardDef TwinSentries = new CardDef { Title = "Twin Sentries", Description = "Deploy a second turret", Rarity = (Rarity)1, Theme = (CardThemeColorType)3, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Turrets", "+1") } }; public static readonly CardDef Overclocked = new CardDef { Title = "Overclocked", Description = "Your turrets fire at full damage", Rarity = (Rarity)2, Theme = (CardThemeColorType)3, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Turret damage", "+100%") } }; public static readonly CardDef Bunkered = new CardDef { Title = "Bunkered", Description = "Your turrets deploy with double health", Rarity = (Rarity)1, Theme = (CardThemeColorType)3, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Turret health", "+100%") } }; public static readonly CardDef Bulwark = new CardDef { Title = "Bulwark", Description = "Your turrets block on their own", Rarity = (Rarity)1, Theme = (CardThemeColorType)3 }; public static readonly CardDef PlagueLord = new CardDef { Title = "Plague Lord", Description = "Raise anything your undead kill, and fallen summons too", Rarity = (Rarity)2, Theme = (CardThemeColorType)4 }; public static readonly CardDef SoulHarvest = new CardDef { Title = "Soul Harvest", Description = "Your undead attack at full damage", Rarity = (Rarity)2, Theme = (CardThemeColorType)4, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Undead damage", "+100%") } }; public static readonly CardDef UndyingHorde = new CardDef { Title = "Undying Horde", Description = "Every corpse rises as two undead", Rarity = (Rarity)1, Theme = (CardThemeColorType)4, Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Undead count", "+1") } }; } public class CloneSummoner : MonoBehaviour { private static readonly List Active = new List(); private const float HalfMult = 0.5f; public int cardCount; public int swapCount; public int shareCount; public int bonusClones; public int cloneFullDamageCount; private Player summoner; private Block block; private bool halved; private float origDamage; private float origMaxHealth; public bool CanSwap => swapCount > 0; public bool SharesHealth => shareCount > 0; public bool CloneFullDamage => cloneFullDamageCount > 0; public int MaxClones => 1 + bonusClones; private void Start() { summoner = ((Component)this).GetComponent(); block = ((Component)this).GetComponent(); if ((Object)(object)block != (Object)null) { Block obj = block; obj.BlockAction = (Action)Delegate.Combine(obj.BlockAction, new Action(OnBlock)); } if (!Active.Contains(this)) { Active.Add(this); } Summons.EnsureHook(); } private void OnDestroy() { if ((Object)(object)block != (Object)null) { Block obj = block; obj.BlockAction = (Action)Delegate.Remove(obj.BlockAction, new Action(OnBlock)); } Active.Remove(this); RestoreStats(); } private void OnBlock(BlockTriggerType triggerType) { if (!PhotonNetwork.OfflineMode || (Object)(object)summoner == (Object)null || (Object)(object)summoner.data == (Object)null) { return; } if (Summons.CountLiveSummons(summoner, BotKind.Clone) < MaxClones) { if (!((Object)(object)PlayerAssigner.instance == (Object)null) && !((Object)(object)PlayerAssigner.instance.playerPrefab == (Object)null)) { try { Summon(); } catch (Exception ex) { Plugin.Log.LogError((object)("Doppelganger: summon failed — " + ex)); } } } else if (CanSwap) { try { SwapWithClone(); } catch (Exception ex2) { Plugin.Log.LogError((object)("Doppelganger: swap failed — " + ex2)); } } } private void Summon() { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) Gun gun = summoner.data.weaponHandler.gun; bool sharesHealth = SharesHealth; if (!halved) { origDamage = gun.damage; origMaxHealth = summoner.data.maxHealth; halved = true; } gun.damage *= 0.5f; if (!sharesHealth) { CharacterData data = summoner.data; data.maxHealth *= 0.5f; summoner.data.health = Mathf.Min(summoner.data.health, summoner.data.maxHealth); } Vector3 pos = ((Component)summoner).transform.position + Vector3.up * 2.5f; GameObject val = Summons.SpawnBot(summoner, pos, summoner.playerID, BotKind.Clone); CharacterData component = val.GetComponent(); val.AddComponent(); component.maxHealth = summoner.data.maxHealth; component.health = component.maxHealth; NecroManager.CopyGun(gun, component.weaponHandler.gun); NecroManager.CopyValueFields(summoner.data.stats, component.stats, NecroManager.StatFieldsToClone); if (CloneFullDamage) { component.weaponHandler.gun.damage = origDamage; } if (sharesHealth) { val.AddComponent().Init(summoner.data, component); } Plugin.Log.LogInfo((object)($"Doppelganger: split player {summoner.playerID}" + (sharesHealth ? " (shared health)." : "."))); } private void SwapWithClone() { //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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) GameObject liveSummon = Summons.GetLiveSummon(summoner, BotKind.Clone); if (!((Object)(object)liveSummon == (Object)null)) { Vector3 position = ((Component)summoner).transform.position; Vector3 position2 = liveSummon.transform.position; Teleport(summoner.data, position2); Teleport(liveSummon.GetComponent(), position); Plugin.Log.LogInfo((object)$"Doppelganger: player {summoner.playerID} swapped with clone."); } } private static void Teleport(CharacterData cd, Vector3 pos) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)cd == (Object)null)) { ((Component)cd).transform.position = pos; if ((Object)(object)cd.playerVel != (Object)null) { cd.playerVel.position = Vector2.op_Implicit(pos); } } } private void RestoreStats() { if (halved) { halved = false; if ((Object)(object)summoner != (Object)null && (Object)(object)summoner.data != (Object)null) { summoner.data.weaponHandler.gun.damage = origDamage; summoner.data.maxHealth = origMaxHealth; } } } public static void RestoreAll() { foreach (CloneSummoner item in Active) { item.RestoreStats(); } } } public class DoppelgangerCard : SummonerCard { protected override CardDef Def => CardText.Doppelganger; public override void OnAddCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { CloneSummoner cloneSummoner = ((Component)player).gameObject.GetComponent(); if ((Object)(object)cloneSummoner == (Object)null) { cloneSummoner = ((Component)player).gameObject.AddComponent(); } cloneSummoner.cardCount++; } public override void OnRemoveCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { CloneSummoner component = ((Component)player).gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.cardCount--; if (component.cardCount <= 0) { Object.Destroy((Object)(object)component); } } } } public class DoppelgangerShareCard : UpgradeCard { public override BotKind Family => BotKind.Clone; protected override CardDef Def => CardText.SplitSoul; protected override void Apply(Player player) { CloneSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.shareCount++; } } protected override void Remove(Player player) { CloneSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.shareCount--; } } } public class DoppelgangerSharpCard : UpgradeCard { public override BotKind Family => BotKind.Clone; protected override CardDef Def => CardText.SharperImage; protected override void Apply(Player player) { CloneSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.cloneFullDamageCount++; } } protected override void Remove(Player player) { CloneSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.cloneFullDamageCount--; } } } public class DoppelgangerSwapCard : UpgradeCard { public override BotKind Family => BotKind.Clone; protected override CardDef Def => CardText.BodyDouble; protected override void Apply(Player player) { CloneSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.swapCount++; } } protected override void Remove(Player player) { CloneSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.swapCount--; } } } public class DoppelgangerTwinCard : UpgradeCard { public override BotKind Family => BotKind.Clone; protected override CardDef Def => CardText.HallOfMirrors; protected override void Apply(Player player) { CloneSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.bonusClones++; } } protected override void Remove(Player player) { CloneSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.bonusClones--; } } } public class DualSentryCard : UpgradeCard { public override BotKind Family => BotKind.Turret; protected override CardDef Def => CardText.TwinSentries; protected override void Apply(Player player) { TurretSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.bonusTurrets++; } } protected override void Remove(Player player) { TurretSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.bonusTurrets--; } } } public class HiveCard : SummonerCard { protected override CardDef Def => CardText.Hive; public override void OnAddCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { HiveSummoner hiveSummoner = ((Component)player).gameObject.GetComponent(); if ((Object)(object)hiveSummoner == (Object)null) { hiveSummoner = ((Component)player).gameObject.AddComponent(); } hiveSummoner.cardCount++; } public override void OnRemoveCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { HiveSummoner component = ((Component)player).gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.cardCount--; if (component.cardCount <= 0) { Object.Destroy((Object)(object)component); } } } } public static class HiveManager { private static readonly List Active = new List(); public static void Register(HiveSummoner s) { if (!Active.Contains(s)) { Active.Add(s); } } public static void Unregister(HiveSummoner s) { Active.Remove(s); } public static void OnBattleStart() { if (!PhotonNetwork.OfflineMode) { return; } foreach (HiveSummoner item in new List(Active)) { if ((Object)(object)item != (Object)null) { item.SpawnHive(); } } } } public class HiveSummoner : MonoBehaviour { public int cardCount; public int bonusBees; private const float BeeHealthMult = 0.25f; private const float BeeDamageMult = 0.35f; private Player owner; public int BeeCount => 3 + bonusBees; private void Start() { owner = ((Component)this).GetComponent(); HiveManager.Register(this); Summons.EnsureHook(); } private void OnDestroy() { HiveManager.Unregister(this); } public void SpawnHive() { if ((Object)(object)owner == (Object)null || (Object)(object)owner.data == (Object)null || (Object)(object)PlayerAssigner.instance == (Object)null || (Object)(object)PlayerAssigner.instance.playerPrefab == (Object)null || Summons.HasLiveSummon(owner, BotKind.Hive)) { return; } try { SpawnOne(); } catch (Exception ex) { Plugin.Log.LogError((object)("Hive: spawn failed — " + ex)); } } private void SpawnOne() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)owner).transform.position + Vector3.up * 1.5f; GameObject val2 = Summons.SpawnBot(owner, val, owner.playerID, BotKind.Hive); CharacterData component = val2.GetComponent(); val2.AddComponent().holdFire = true; component.maxHealth = owner.data.maxHealth; component.health = component.maxHealth; Gun gun = owner.data.weaponHandler.gun; for (int i = 0; i < BeeCount; i++) { float num = ((i % 2 == 0) ? 1f : (-1f)) * (1f + (float)i) * 0.8f; Vector3 pos = val + Vector3.right * num + Vector3.up * 0.5f; GameObject obj = Summons.SpawnBot(owner, pos, owner.playerID, BotKind.Bee); CharacterData component2 = obj.GetComponent(); obj.AddComponent(); SummonedBotTag component3 = obj.GetComponent(); if ((Object)(object)component3 != (Object)null) { component3.parentSummon = val2; } component2.maxHealth = owner.data.maxHealth * 0.25f; component2.health = component2.maxHealth; NecroManager.CopyGun(gun, component2.weaponHandler.gun); component2.weaponHandler.gun.damage = gun.damage * 0.35f; NecroManager.CopyValueFields(owner.data.stats, component2.stats, NecroManager.StatFieldsToClone); } Plugin.Log.LogInfo((object)$"Hive: player {owner.playerID} deployed a hive with {BeeCount} bees."); } } public static class NecroManager { public class Corpse { public int deadPlayerId; public int colorId; public int faceId; public int killerId; public Vector3 pos; public Player dead; } private static readonly List Corpses = new List(); public static readonly string[] StatFieldsToClone = new string[5] { "movementSpeed", "jump", "sizeMultiplier", "gravity", "attackSpeedMultiplier" }; public static void RecordCorpse(Player dead) { //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)dead == (Object)null) { return; } SummonedBotTag component = ((Component)dead).GetComponent(); Player val = (((Object)(object)dead.data != (Object)null) ? dead.data.lastSourceOfDamage : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)dead)) { Player val2 = val; SummonedBotTag component2 = ((Component)val).GetComponent(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.master != (Object)null) { val2 = component2.master; } Reanimator reanimator = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent() : null); bool flag = (Object)(object)reanimator != (Object)null && reanimator.EmpowersMinions; if ((!((Object)(object)component2 != (Object)null) || flag) && (!((Object)(object)component != (Object)null) || component.kind == BotKind.Clone || flag) && !((Object)(object)val2 == (Object)null)) { int colorId = (((Object)(object)component != (Object)null && component.colorId >= 0) ? component.colorId : dead.playerID); int faceId = (((Object)(object)component != (Object)null && component.faceId >= 0) ? component.faceId : dead.playerID); Corpses.Add(new Corpse { deadPlayerId = dead.playerID, colorId = colorId, faceId = faceId, killerId = val2.playerID, pos = ((Component)dead).transform.position, dead = dead }); } } } public static List TakeCorpsesFor(int killerId) { List list = new List(); for (int num = Corpses.Count - 1; num >= 0; num--) { Corpse corpse = Corpses[num]; if (corpse.killerId == killerId) { Corpses.RemoveAt(num); if (!((Object)(object)corpse.dead == (Object)null) && !((Object)(object)corpse.dead.data == (Object)null) && corpse.dead.data.dead) { list.Add(corpse); } } } return list; } public static void ClearCorpses() { Corpses.Clear(); } public static void CopyGun(Gun src, Gun dst) { if (!((Object)(object)src == (Object)null) && !((Object)(object)dst == (Object)null)) { CopyValueFields(src, dst, null); dst.objectsToSpawn = src.objectsToSpawn; dst.projectiles = src.projectiles; } } public static void CopyValueFields(object src, object dst, string[] whitelist) { if (src == null || dst == null) { return; } FieldInfo[] fields = src.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if ((whitelist == null || Array.IndexOf(whitelist, fieldInfo.Name) >= 0) && (fieldInfo.FieldType.IsPrimitive || fieldInfo.FieldType.IsEnum)) { try { fieldInfo.SetValue(dst, fieldInfo.GetValue(src)); } catch { } } } } } public class NecromancerCard : SummonerCard { protected override CardDef Def => CardText.Necromancer; public override void OnAddCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { Reanimator reanimator = ((Component)player).gameObject.GetComponent(); if ((Object)(object)reanimator == (Object)null) { reanimator = ((Component)player).gameObject.AddComponent(); } reanimator.cardCount++; } public override void OnRemoveCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { Reanimator component = ((Component)player).gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.cardCount--; if (component.cardCount <= 0) { Object.Destroy((Object)(object)component); } } } } public class NecromancerEmpowerCard : UpgradeCard { public override BotKind Family => BotKind.Reanimated; protected override CardDef Def => CardText.PlagueLord; protected override void Apply(Player player) { Reanimator component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.empowerCount++; } } protected override void Remove(Player player) { Reanimator component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.empowerCount--; } } } public class NecromancerHarvestCard : UpgradeCard { public override BotKind Family => BotKind.Reanimated; protected override CardDef Def => CardText.SoulHarvest; protected override void Apply(Player player) { Reanimator component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.fullDamageCount++; } } protected override void Remove(Player player) { Reanimator component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.fullDamageCount--; } } } public class NecromancerHordeCard : UpgradeCard { public override BotKind Family => BotKind.Reanimated; protected override CardDef Def => CardText.UndyingHorde; protected override void Apply(Player player) { Reanimator component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.extraRaiseCount++; } } protected override void Remove(Player player) { Reanimator component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.extraRaiseCount--; } } } [BepInPlugin("com.blueflame327.rounds.summonercards", "SummonerCards", "1.7.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("Rounds.exe")] public class Plugin : BaseUnityPlugin { public const string ModId = "com.blueflame327.rounds.summonercards"; public const string ModName = "SummonerCards"; public const string ModVersion = "1.7.0"; internal static ManualLogSource Log; private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; new Harmony("com.blueflame327.rounds.summonercards").PatchAll(); } private void Start() { CustomCard.BuildCard(); CustomCard.BuildCard(); CustomCard.BuildCard(); CustomCard.BuildCard(); CustomCard.BuildCard(); BuildUpgrade(); BuildUpgrade(); BuildUpgrade(); BuildUpgrade(); BuildUpgrade(); BuildUpgrade(); BuildUpgrade(); BuildUpgrade(); BuildUpgrade(); BuildUpgrade(); BuildUpgrade(); GameModeManager.AddHook("BattleStart", (Func)((IGameModeHandler gm) => BattleStart())); GameModeManager.AddHook("PointEnd", (Func)((IGameModeHandler gm) => Cleanup())); GameModeManager.AddHook("RoundEnd", (Func)((IGameModeHandler gm) => Cleanup())); GameModeManager.AddHook("GameEnd", (Func)((IGameModeHandler gm) => Cleanup())); Unbound.RegisterCredits("SummonerCards", new string[1] { "BlueFlame327" }, new string[1] { "GitHub" }, new string[1] { "https://github.com/BlueFlame327/SummonerCards" }); Log.LogInfo((object)"SummonerCards v1.7.0 loaded."); } private static void BuildUpgrade() where T : UpgradeCard { CustomCard.BuildCard((Action)delegate(CardInfo cardInfo) { T component = ((Component)cardInfo).GetComponent(); if (!((Object)(object)component == (Object)null)) { cardInfo.allowMultiple = component.AllowMultiple; UpgradeGate.Register(cardInfo.cardName, component.Family); } }); } private static IEnumerator BattleStart() { TurretManager.OnBattleStart(); HiveManager.OnBattleStart(); yield break; } private static IEnumerator Cleanup() { Summons.OnPointEnd(); NecroManager.ClearCorpses(); CloneSummoner.RestoreAll(); yield break; } } public class Reanimator : MonoBehaviour { public int cardCount; public int empowerCount; public int fullDamageCount; public int extraRaiseCount; private const float HalfMult = 0.5f; private Player owner; private Block block; public bool EmpowersMinions => empowerCount > 0; public bool FullDamage => fullDamageCount > 0; public int RaisesPerCorpse => 1 + extraRaiseCount; private void Start() { owner = ((Component)this).GetComponent(); block = ((Component)this).GetComponent(); if ((Object)(object)block != (Object)null) { Block obj = block; obj.BlockAction = (Action)Delegate.Combine(obj.BlockAction, new Action(OnBlock)); } Summons.EnsureHook(); } private void OnDestroy() { if ((Object)(object)block != (Object)null) { Block obj = block; obj.BlockAction = (Action)Delegate.Remove(obj.BlockAction, new Action(OnBlock)); } } private void OnBlock(BlockTriggerType triggerType) { if (!PhotonNetwork.OfflineMode || (Object)(object)owner == (Object)null) { return; } foreach (NecroManager.Corpse item in NecroManager.TakeCorpsesFor(owner.playerID)) { try { Reanimate(item); } catch (Exception ex) { Plugin.Log.LogError((object)("Necromancer: reanimate failed — " + ex)); } } } private void Reanimate(NecroManager.Corpse c) { int raisesPerCorpse = RaisesPerCorpse; for (int i = 0; i < raisesPerCorpse; i++) { RaiseOne(c, i); } } private void RaiseOne(NecroManager.Corpse c, int index) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) CharacterData data = c.dead.data; Gun gun = data.weaponHandler.gun; float num = ((index % 2 == 0) ? 1f : (-1f)) * (float)index * 1.2f; Vector3 pos = c.pos + Vector3.up * 1.5f + Vector3.right * num; GameObject obj = Summons.SpawnBot(owner, pos, c.colorId, BotKind.Reanimated); CharacterData component = obj.GetComponent(); obj.AddComponent(); ApplyFace(obj, c.faceId); SummonedBotTag component2 = obj.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.colorId = c.colorId; component2.faceId = c.faceId; } component.maxHealth = data.maxHealth * 0.5f; component.health = component.maxHealth; NecroManager.CopyGun(gun, component.weaponHandler.gun); component.weaponHandler.gun.damage = gun.damage * (FullDamage ? 1f : 0.5f); Plugin.Log.LogInfo((object)$"Necromancer: player {owner.playerID} raised {c.deadPlayerId}."); } private static void ApplyFace(GameObject botObj, int deadPlayerId) { CharacterCreatorHandler instance = CharacterCreatorHandler.instance; if ((Object)(object)instance == (Object)null || deadPlayerId < 0 || deadPlayerId >= instance.selectedPlayerFaces.Length) { return; } PlayerFace val = instance.selectedPlayerFaces[deadPlayerId]; if (val != null) { CharacterCreatorItemEquipper componentInChildren = botObj.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.EquipFace(val); } } } } public class RevenantCard : SummonerCard { protected override CardDef Def => CardText.Revenant; public override void OnAddCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { RevenantSummoner revenantSummoner = ((Component)player).gameObject.GetComponent(); if ((Object)(object)revenantSummoner == (Object)null) { revenantSummoner = ((Component)player).gameObject.AddComponent(); } revenantSummoner.cardCount++; } public override void OnRemoveCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { RevenantSummoner component = ((Component)player).gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.cardCount--; if (component.cardCount <= 0) { Object.Destroy((Object)(object)component); } } } } public class RevenantSummoner : MonoBehaviour { public int cardCount; private const float RevenantSeconds = 10f; private Player owner; private bool subscribed; private void Start() { owner = ((Component)this).GetComponent(); Summons.EnsureHook(); if ((Object)(object)PlayerManager.instance != (Object)null) { PlayerManager.instance.AddPlayerDiedAction((Action)OnAnyDeath); subscribed = true; } } private void OnAnyDeath(Player dead, int aliveCount) { if (!subscribed || cardCount <= 0 || !PhotonNetwork.OfflineMode || (Object)(object)dead == (Object)null || (Object)(object)dead != (Object)(object)owner || (Object)(object)owner.data == (Object)null || Summons.HasLiveSummon(owner, BotKind.Revenant)) { return; } try { SpawnRevenant(); } catch (Exception ex) { Plugin.Log.LogError((object)("Revenant: summon failed — " + ex)); } } private void SpawnRevenant() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)owner).transform.position; GameObject obj = Summons.SpawnBot(owner, position, owner.playerID, BotKind.Revenant); SummonedBotTag component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { component.survivesMasterDeath = true; } CharacterData component2 = obj.GetComponent(); obj.AddComponent(); ApplyFace(obj, owner.playerID); Gun gun = owner.data.weaponHandler.gun; component2.maxHealth = owner.data.maxHealth; component2.health = component2.maxHealth; NecroManager.CopyGun(gun, component2.weaponHandler.gun); NecroManager.CopyValueFields(owner.data.stats, component2.stats, NecroManager.StatFieldsToClone); Summons.KillAfter(obj, 10f); Plugin.Log.LogInfo((object)$"Revenant: player {owner.playerID} rose for a last stand."); } private static void ApplyFace(GameObject obj, int faceId) { CharacterCreatorHandler instance = CharacterCreatorHandler.instance; if ((Object)(object)instance == (Object)null || faceId < 0 || faceId >= instance.selectedPlayerFaces.Length) { return; } PlayerFace val = instance.selectedPlayerFaces[faceId]; if (val != null) { CharacterCreatorItemEquipper componentInChildren = obj.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.EquipFace(val); } } } } public class SentryBlockCard : UpgradeCard { public override BotKind Family => BotKind.Turret; protected override CardDef Def => CardText.Bulwark; protected override void Apply(Player player) { TurretSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.blockCount++; } } protected override void Remove(Player player) { TurretSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.blockCount--; } } } public class SentryFortifyCard : UpgradeCard { public override BotKind Family => BotKind.Turret; protected override CardDef Def => CardText.Bunkered; protected override void Apply(Player player) { TurretSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.healthBonusCount++; } } protected override void Remove(Player player) { TurretSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.healthBonusCount--; } } } public class SentryOverclockCard : UpgradeCard { public override BotKind Family => BotKind.Turret; protected override CardDef Def => CardText.Overclocked; protected override void Apply(Player player) { TurretSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.fullDamageCount++; } } protected override void Remove(Player player) { TurretSummoner component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.fullDamageCount--; } } } public class SharedHealthLink : MonoBehaviour { private CharacterData a; private CharacterData b; private float pool; private float lastA; private float lastB; private bool started; public void Init(CharacterData summoner, CharacterData clone) { a = summoner; b = clone; pool = Mathf.Min(a.health, b.health); lastA = a.health; lastB = b.health; started = true; } private void FixedUpdate() { if (!started) { return; } if ((Object)(object)a == (Object)null || (Object)(object)b == (Object)null || (Object)(object)a.player == (Object)null || (Object)(object)b.player == (Object)null) { Done(); return; } if (a.dead || b.dead) { Done(); return; } pool += a.health - lastA + (b.health - lastB); float num = Mathf.Min(a.maxHealth, b.maxHealth); pool = Mathf.Clamp(pool, 0f, num); if (pool <= 0f) { Kill(a); Kill(b); Done(); } else { a.health = pool; b.health = pool; lastA = pool; lastB = pool; } } private static void Kill(CharacterData cd) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)cd == (Object)null) && !cd.dead && !((Object)(object)cd.healthHandler == (Object)null)) { cd.healthHandler.DoDamage(new Vector2(0f, -1f) * 100000f, Vector2.op_Implicit(((Component)cd).transform.position), Color.white, (GameObject)null, (Player)null, false, true, true); } } private void Done() { started = false; Object.Destroy((Object)(object)this); } } public enum BotKind { Clone, Reanimated, Turret, Hive, Bee, Revenant } public class SummonedBotTag : MonoBehaviour { public BotKind kind; public Player master; public int colorId = -1; public int faceId = -1; public GameObject parentSummon; public bool survivesMasterDeath; } public abstract class SummonerCard : CustomCard { protected abstract CardDef Def { get; } protected override string GetTitle() { return Def.Title; } protected override string GetDescription() { return Def.Description; } protected override CardInfoStat[] GetStats() { return Def.Stats; } protected override Rarity GetRarity() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Def.Rarity; } protected override CardThemeColorType GetTheme() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Def.Theme; } protected override GameObject GetCardArt() { return null; } public override string GetModName() { return "SummonerCards"; } } public static class Summons { private class Runner : MonoBehaviour { } private static readonly List All = new List(); private static bool hooked; private static Runner runner; private static Runner TheRunner { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if ((Object)(object)runner == (Object)null) { GameObject val = new GameObject("SummonsRunner"); Object.DontDestroyOnLoad((Object)val); runner = val.AddComponent(); } return runner; } } public static void EnsureHook() { if (!hooked && !((Object)(object)PlayerManager.instance == (Object)null)) { PlayerManager.instance.AddPlayerDiedAction((Action)OnPlayerDied); hooked = true; } } private static void OnPlayerDied(Player dead, int aliveCount) { if (!((Object)(object)dead == (Object)null)) { NecroManager.RecordCorpse(dead); KillByMaster(dead); KillChildrenOf(((Component)dead).gameObject); } } public static GameObject SpawnBot(Player master, Vector3 pos, int colorPlayerId, BotKind kind) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) GameObject val = PhotonNetwork.Instantiate(((Object)PlayerAssigner.instance.playerPrefab).name, pos, Quaternion.identity, (byte)0, (object[])null); CharacterData component = val.GetComponent(); Player player = component.player; player.playerID = colorPlayerId; player.teamID = master.teamID; int count = PlayerManager.instance.players.Count; PlayerManager.RegisterPlayer(player); SetTeamColor.TeamColorThis(val, PlayerSkinBank.GetPlayerSkinColors(colorPlayerId)); component.input.controlledElseWhere = true; component.master = master; PlayerAPI component2 = val.GetComponent(); if ((Object)(object)component2 != (Object)null) { ((Behaviour)component2).enabled = false; } component.isPlaying = true; component.healthHandler.DestroyOnDeath = false; component.healthHandler.Revive(true); SummonedBotTag summonedBotTag = val.AddComponent(); summonedBotTag.kind = kind; summonedBotTag.master = master; summonedBotTag.colorId = colorPlayerId; summonedBotTag.faceId = colorPlayerId; All.Add(val); ((MonoBehaviour)TheRunner).StartCoroutine(Setup(component, count)); return val; } private static IEnumerator Setup(CharacterData cd, int uniqueId) { yield return null; if ((Object)(object)cd == (Object)null || (Object)(object)cd.player == (Object)null) { yield break; } cd.player.playerID = uniqueId; for (int i = 0; i < 10; i++) { if (!((Object)(object)cd != (Object)null)) { break; } if (cd.dead) { break; } cd.isPlaying = true; if ((Object)(object)cd.input != (Object)null) { cd.input.controlledElseWhere = true; } yield return null; } } public static bool HasLiveSummon(Player master, BotKind kind) { return CountLiveSummons(master, kind) > 0; } public static int CountLiveSummons(Player master, BotKind kind) { int num = 0; foreach (GameObject item in All) { if (!((Object)(object)item == (Object)null)) { SummonedBotTag component = item.GetComponent(); CharacterData component2 = item.GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null && (Object)(object)component.master == (Object)(object)master && component.kind == kind && !component2.dead) { num++; } } } return num; } public static GameObject GetLiveSummon(Player master, BotKind kind) { foreach (GameObject item in All) { if (!((Object)(object)item == (Object)null)) { SummonedBotTag component = item.GetComponent(); CharacterData component2 = item.GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null && (Object)(object)component.master == (Object)(object)master && component.kind == kind && !component2.dead) { return item; } } } return null; } public static void KillByMaster(Player master) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) GameObject[] array = All.ToArray(); foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null)) { SummonedBotTag component = val.GetComponent(); CharacterData component2 = val.GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null) && !component.survivesMasterDeath && (Object)(object)component.master == (Object)(object)master && !component2.dead) { component2.healthHandler.DoDamage(new Vector2(0f, -1f) * 100000f, Vector2.op_Implicit(((Component)component2).transform.position), Color.white, (GameObject)null, (Player)null, false, true, true); } } } } public static void KillChildrenOf(GameObject parent) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)parent == (Object)null) { return; } GameObject[] array = All.ToArray(); foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null)) { SummonedBotTag component = val.GetComponent(); CharacterData component2 = val.GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null) && (Object)(object)component.parentSummon == (Object)(object)parent && !component2.dead) { component2.healthHandler.DoDamage(new Vector2(0f, -1f) * 100000f, Vector2.op_Implicit(((Component)component2).transform.position), Color.white, (GameObject)null, (Player)null, false, true, true); } } } } public static void KillAfter(GameObject bot, float seconds) { if (!((Object)(object)bot == (Object)null)) { ((MonoBehaviour)TheRunner).StartCoroutine(KillAfterRoutine(bot, seconds)); } } private static IEnumerator KillAfterRoutine(GameObject bot, float seconds) { yield return (object)new WaitForSeconds(seconds); if (!((Object)(object)bot == (Object)null)) { CharacterData component = bot.GetComponent(); if ((Object)(object)component != (Object)null && !component.dead && (Object)(object)component.healthHandler != (Object)null) { component.healthHandler.DoDamage(new Vector2(0f, -1f) * 100000f, Vector2.op_Implicit(((Component)component).transform.position), Color.white, (GameObject)null, (Player)null, false, true, true); } } } public static void OnPointEnd() { foreach (GameObject item in All) { if (!((Object)(object)item == (Object)null)) { CharacterData component = item.GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.player != (Object)null) { PlayerManager.instance.players.Remove(component.player); } PhotonNetwork.Destroy(item); } } All.Clear(); } } public class TurretAI : MonoBehaviour { private static readonly FieldInfo KinematicField = typeof(PlayerVelocity).GetField("isKinematic", BindingFlags.Instance | BindingFlags.NonPublic); public bool canBlock; public bool holdFire; private CharacterData data; private GeneralInput input; private Block block; private void Start() { data = ((Component)this).GetComponentInParent(); if ((Object)(object)data != (Object)null) { input = data.input; block = ((Component)data).GetComponent(); ((MonoBehaviour)this).StartCoroutine(AnchorAfterSettle()); } } private IEnumerator AnchorAfterSettle() { yield return (object)new WaitForSeconds(0.35f); if ((Object)(object)data != (Object)null && (Object)(object)data.playerVel != (Object)null && KinematicField != null) { KinematicField.SetValue(data.playerVel, true); } } private void Update() { //IL_0030: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)data == (Object)null || (Object)(object)input == (Object)null || (Object)(object)PlayerManager.instance == (Object)null) { return; } input.direction = Vector3.zero; if (holdFire) { input.shootIsPressed = false; input.shootWasPressed = false; return; } Player otherPlayer = PlayerManager.instance.GetOtherPlayer(data.player); if ((Object)(object)otherPlayer == (Object)null) { input.shootIsPressed = false; input.shootWasPressed = false; return; } GeneralInput obj = input; Vector3 val = ((Component)otherPlayer).transform.position - ((Component)this).transform.position; obj.aimDirection = ((Vector3)(ref val)).normalized; if (canBlock && (Object)(object)block != (Object)null) { block.TryBlock(); } bool canSee = PlayerManager.instance.CanSeePlayer(Vector2.op_Implicit(((Component)this).transform.position), otherPlayer).canSee; input.shootIsPressed = canSee; input.shootWasPressed = canSee; } } public class TurretCard : SummonerCard { protected override CardDef Def => CardText.Sentry; public override void OnAddCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { TurretSummoner turretSummoner = ((Component)player).gameObject.GetComponent(); if ((Object)(object)turretSummoner == (Object)null) { turretSummoner = ((Component)player).gameObject.AddComponent(); } turretSummoner.cardCount++; } public override void OnRemoveCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { TurretSummoner component = ((Component)player).gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.cardCount--; if (component.cardCount <= 0) { Object.Destroy((Object)(object)component); } } } } public static class TurretManager { private static readonly List Active = new List(); public static void Register(TurretSummoner s) { if (!Active.Contains(s)) { Active.Add(s); } } public static void Unregister(TurretSummoner s) { Active.Remove(s); } public static void OnBattleStart() { if (!PhotonNetwork.OfflineMode) { return; } foreach (TurretSummoner item in new List(Active)) { if ((Object)(object)item != (Object)null) { item.SpawnTurret(); } } } } public class TurretSummoner : MonoBehaviour { public int cardCount; public int bonusTurrets; public int fullDamageCount; public int healthBonusCount; public int blockCount; private const float TurretDamageMult = 0.5f; private Player owner; public int MaxTurrets => 1 + bonusTurrets; public bool FullDamage => fullDamageCount > 0; public bool CanBlock => blockCount > 0; private void Start() { owner = ((Component)this).GetComponent(); TurretManager.Register(this); Summons.EnsureHook(); } private void OnDestroy() { TurretManager.Unregister(this); } public void SpawnTurret() { if ((Object)(object)owner == (Object)null || (Object)(object)owner.data == (Object)null || (Object)(object)PlayerAssigner.instance == (Object)null || (Object)(object)PlayerAssigner.instance.playerPrefab == (Object)null) { return; } int num = MaxTurrets - Summons.CountLiveSummons(owner, BotKind.Turret); for (int i = 0; i < num; i++) { try { SpawnOne(i); } catch (Exception ex) { Plugin.Log.LogError((object)("Turret: spawn failed — " + ex)); } } } private void SpawnOne(int index) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) float num = ((index % 2 == 0) ? 1f : (-1f)) * (1f + (float)index) * 1.5f; Vector3 pos = ((Component)owner).transform.position + Vector3.up * 1.5f + Vector3.right * num; GameObject obj = Summons.SpawnBot(owner, pos, owner.playerID, BotKind.Turret); CharacterData component = obj.GetComponent(); obj.AddComponent().canBlock = CanBlock; Gun gun = owner.data.weaponHandler.gun; component.maxHealth = owner.data.maxHealth * (1f + (float)healthBonusCount); component.health = component.maxHealth; NecroManager.CopyGun(gun, component.weaponHandler.gun); component.weaponHandler.gun.damage = gun.damage * (FullDamage ? 1f : 0.5f); Plugin.Log.LogInfo((object)$"Turret: player {owner.playerID} deployed a turret."); } } public abstract class UpgradeCard : SummonerCard { public abstract BotKind Family { get; } public virtual bool AllowMultiple => false; protected abstract void Apply(Player player); protected abstract void Remove(Player player); public override void OnAddCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { try { Apply(player); } catch (Exception arg) { Plugin.Log.LogError((object)$"{((CustomCard)this).GetTitle()}: apply failed — {arg}"); } } public override void OnRemoveCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats) { try { Remove(player); } catch (Exception arg) { Plugin.Log.LogError((object)$"{((CustomCard)this).GetTitle()}: remove failed — {arg}"); } } } public static class UpgradeGate { private static readonly Dictionary Requirements = new Dictionary(); public static void Register(string cardName, BotKind family) { if (!string.IsNullOrEmpty(cardName)) { Requirements[cardName] = family; } } public static bool IsAllowed(CardInfo info, Player player) { if ((Object)(object)info == (Object)null || (Object)(object)player == (Object)null) { return true; } string cardName = info.cardName; if (string.IsNullOrEmpty(cardName) || !Requirements.TryGetValue(cardName, out var value)) { return true; } return value switch { BotKind.Clone => (Object)(object)((Component)player).GetComponent() != (Object)null, BotKind.Reanimated => (Object)(object)((Component)player).GetComponent() != (Object)null, BotKind.Turret => (Object)(object)((Component)player).GetComponent() != (Object)null, _ => true, }; } } }