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,
};
}
}
}