Decompiled source of SummonerCards v1.7.0

SummonerCards.dll

Decompiled 4 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using 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<CardInfo>();
				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<Player> 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<CardInfoStat>();

		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<CloneSummoner> Active = new List<CloneSummoner>();

		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<Player>();
			block = ((Component)this).GetComponent<Block>();
			if ((Object)(object)block != (Object)null)
			{
				Block obj = block;
				obj.BlockAction = (Action<BlockTriggerType>)Delegate.Combine(obj.BlockAction, new Action<BlockTriggerType>(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<BlockTriggerType>)Delegate.Remove(obj.BlockAction, new Action<BlockTriggerType>(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<CharacterData>();
			val.AddComponent<PlayerAI>();
			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<SharedHealthLink>().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<CharacterData>(), 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<CloneSummoner>();
			if ((Object)(object)cloneSummoner == (Object)null)
			{
				cloneSummoner = ((Component)player).gameObject.AddComponent<CloneSummoner>();
			}
			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<CloneSummoner>();
			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<CloneSummoner>();
			if ((Object)(object)component != (Object)null)
			{
				component.shareCount++;
			}
		}

		protected override void Remove(Player player)
		{
			CloneSummoner component = ((Component)player).GetComponent<CloneSummoner>();
			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<CloneSummoner>();
			if ((Object)(object)component != (Object)null)
			{
				component.cloneFullDamageCount++;
			}
		}

		protected override void Remove(Player player)
		{
			CloneSummoner component = ((Component)player).GetComponent<CloneSummoner>();
			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<CloneSummoner>();
			if ((Object)(object)component != (Object)null)
			{
				component.swapCount++;
			}
		}

		protected override void Remove(Player player)
		{
			CloneSummoner component = ((Component)player).GetComponent<CloneSummoner>();
			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<CloneSummoner>();
			if ((Object)(object)component != (Object)null)
			{
				component.bonusClones++;
			}
		}

		protected override void Remove(Player player)
		{
			CloneSummoner component = ((Component)player).GetComponent<CloneSummoner>();
			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<TurretSummoner>();
			if ((Object)(object)component != (Object)null)
			{
				component.bonusTurrets++;
			}
		}

		protected override void Remove(Player player)
		{
			TurretSummoner component = ((Component)player).GetComponent<TurretSummoner>();
			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<HiveSummoner>();
			if ((Object)(object)hiveSummoner == (Object)null)
			{
				hiveSummoner = ((Component)player).gameObject.AddComponent<HiveSummoner>();
			}
			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<HiveSummoner>();
			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<HiveSummoner> Active = new List<HiveSummoner>();

		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<HiveSummoner>(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<Player>();
			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<CharacterData>();
			val2.AddComponent<TurretAI>().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<CharacterData>();
				obj.AddComponent<PlayerAI>();
				SummonedBotTag component3 = obj.GetComponent<SummonedBotTag>();
				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<Corpse> Corpses = new List<Corpse>();

		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<SummonedBotTag>();
			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<SummonedBotTag>();
				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<Reanimator>() : 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<Corpse> TakeCorpsesFor(int killerId)
		{
			List<Corpse> list = new List<Corpse>();
			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<Reanimator>();
			if ((Object)(object)reanimator == (Object)null)
			{
				reanimator = ((Component)player).gameObject.AddComponent<Reanimator>();
			}
			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<Reanimator>();
			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<Reanimator>();
			if ((Object)(object)component != (Object)null)
			{
				component.empowerCount++;
			}
		}

		protected override void Remove(Player player)
		{
			Reanimator component = ((Component)player).GetComponent<Reanimator>();
			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<Reanimator>();
			if ((Object)(object)component != (Object)null)
			{
				component.fullDamageCount++;
			}
		}

		protected override void Remove(Player player)
		{
			Reanimator component = ((Component)player).GetComponent<Reanimator>();
			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<Reanimator>();
			if ((Object)(object)component != (Object)null)
			{
				component.extraRaiseCount++;
			}
		}

		protected override void Remove(Player player)
		{
			Reanimator component = ((Component)player).GetComponent<Reanimator>();
			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<DoppelgangerCard>();
			CustomCard.BuildCard<NecromancerCard>();
			CustomCard.BuildCard<TurretCard>();
			CustomCard.BuildCard<HiveCard>();
			CustomCard.BuildCard<RevenantCard>();
			BuildUpgrade<DoppelgangerSwapCard>();
			BuildUpgrade<DoppelgangerShareCard>();
			BuildUpgrade<DoppelgangerTwinCard>();
			BuildUpgrade<DoppelgangerSharpCard>();
			BuildUpgrade<DualSentryCard>();
			BuildUpgrade<SentryOverclockCard>();
			BuildUpgrade<SentryFortifyCard>();
			BuildUpgrade<SentryBlockCard>();
			BuildUpgrade<NecromancerEmpowerCard>();
			BuildUpgrade<NecromancerHarvestCard>();
			BuildUpgrade<NecromancerHordeCard>();
			GameModeManager.AddHook("BattleStart", (Func<IGameModeHandler, IEnumerator>)((IGameModeHandler gm) => BattleStart()));
			GameModeManager.AddHook("PointEnd", (Func<IGameModeHandler, IEnumerator>)((IGameModeHandler gm) => Cleanup()));
			GameModeManager.AddHook("RoundEnd", (Func<IGameModeHandler, IEnumerator>)((IGameModeHandler gm) => Cleanup()));
			GameModeManager.AddHook("GameEnd", (Func<IGameModeHandler, IEnumerator>)((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<T>() where T : UpgradeCard
		{
			CustomCard.BuildCard<T>((Action<CardInfo>)delegate(CardInfo cardInfo)
			{
				T component = ((Component)cardInfo).GetComponent<T>();
				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<Player>();
			block = ((Component)this).GetComponent<Block>();
			if ((Object)(object)block != (Object)null)
			{
				Block obj = block;
				obj.BlockAction = (Action<BlockTriggerType>)Delegate.Combine(obj.BlockAction, new Action<BlockTriggerType>(OnBlock));
			}
			Summons.EnsureHook();
		}

		private void OnDestroy()
		{
			if ((Object)(object)block != (Object)null)
			{
				Block obj = block;
				obj.BlockAction = (Action<BlockTriggerType>)Delegate.Remove(obj.BlockAction, new Action<BlockTriggerType>(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<CharacterData>();
			obj.AddComponent<PlayerAI>();
			ApplyFace(obj, c.faceId);
			SummonedBotTag component2 = obj.GetComponent<SummonedBotTag>();
			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<CharacterCreatorItemEquipper>();
				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<RevenantSummoner>();
			if ((Object)(object)revenantSummoner == (Object)null)
			{
				revenantSummoner = ((Component)player).gameObject.AddComponent<RevenantSummoner>();
			}
			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<RevenantSummoner>();
			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<Player>();
			Summons.EnsureHook();
			if ((Object)(object)PlayerManager.instance != (Object)null)
			{
				PlayerManager.instance.AddPlayerDiedAction((Action<Player, int>)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<SummonedBotTag>();
			if ((Object)(object)component != (Object)null)
			{
				component.survivesMasterDeath = true;
			}
			CharacterData component2 = obj.GetComponent<CharacterData>();
			obj.AddComponent<PlayerAI>();
			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<CharacterCreatorItemEquipper>();
				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<TurretSummoner>();
			if ((Object)(object)component != (Object)null)
			{
				component.blockCount++;
			}
		}

		protected override void Remove(Player player)
		{
			TurretSummoner component = ((Component)player).GetComponent<TurretSummoner>();
			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<TurretSummoner>();
			if ((Object)(object)component != (Object)null)
			{
				component.healthBonusCount++;
			}
		}

		protected override void Remove(Player player)
		{
			TurretSummoner component = ((Component)player).GetComponent<TurretSummoner>();
			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<TurretSummoner>();
			if ((Object)(object)component != (Object)null)
			{
				component.fullDamageCount++;
			}
		}

		protected override void Remove(Player player)
		{
			TurretSummoner component = ((Component)player).GetComponent<TurretSummoner>();
			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<GameObject> All = new List<GameObject>();

		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<Runner>();
				}
				return runner;
			}
		}

		public static void EnsureHook()
		{
			if (!hooked && !((Object)(object)PlayerManager.instance == (Object)null))
			{
				PlayerManager.instance.AddPlayerDiedAction((Action<Player, int>)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<CharacterData>();
			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<PlayerAPI>();
			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>();
			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<SummonedBotTag>();
					CharacterData component2 = item.GetComponent<CharacterData>();
					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<SummonedBotTag>();
					CharacterData component2 = item.GetComponent<CharacterData>();
					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<SummonedBotTag>();
					CharacterData component2 = val.GetComponent<CharacterData>();
					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<SummonedBotTag>();
					CharacterData component2 = val.GetComponent<CharacterData>();
					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<CharacterData>();
				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<CharacterData>();
					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<CharacterData>();
			if ((Object)(object)data != (Object)null)
			{
				input = data.input;
				block = ((Component)data).GetComponent<Block>();
				((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<TurretSummoner>();
			if ((Object)(object)turretSummoner == (Object)null)
			{
				turretSummoner = ((Component)player).gameObject.AddComponent<TurretSummoner>();
			}
			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<TurretSummoner>();
			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<TurretSummoner> Active = new List<TurretSummoner>();

		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<TurretSummoner>(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<Player>();
			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<CharacterData>();
			obj.AddComponent<TurretAI>().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<string, BotKind> Requirements = new Dictionary<string, BotKind>();

		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<CloneSummoner>() != (Object)null, 
				BotKind.Reanimated => (Object)(object)((Component)player).GetComponent<Reanimator>() != (Object)null, 
				BotKind.Turret => (Object)(object)((Component)player).GetComponent<TurretSummoner>() != (Object)null, 
				_ => true, 
			};
		}
	}
}