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 = "Block to deploy 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 = "Block to deploy 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 = "Also raise fallen summons — turrets, undead, bees and more",
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 static readonly CardDef Swarm = new CardDef
{
Title = "Swarm",
Description = "Your hive breeds a bigger swarm",
Rarity = (Rarity)1,
Theme = (CardThemeColorType)1,
Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Bees", "+2") }
};
public static readonly CardDef Tiny = new CardDef
{
Title = "Tiny Swarm",
Description = "Your bees shrink down — smaller and harder to hit",
Rarity = (Rarity)1,
Theme = (CardThemeColorType)1,
Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Bee size", "smaller") }
};
public static readonly CardDef Lingering = new CardDef
{
Title = "Lingering Spirit",
Description = "Your ghost lingers far longer before fading",
Rarity = (Rarity)1,
Theme = (CardThemeColorType)4,
Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Ghost lasts", "+5 seconds") }
};
public static readonly CardDef SecondWind = new CardDef
{
Title = "Second Wind",
Description = "If your ghost lands a kill, you come back to life",
Rarity = (Rarity)2,
Theme = (CardThemeColorType)4,
Stats = (CardInfoStat[])(object)new CardInfoStat[1] { CardDef.Stat(isGood: true, "Ghost kill", "you respawn") }
};
}
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 bool damageHalved;
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)
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
if (!PhotonNetwork.OfflineMode || (Object)(object)summoner == (Object)null || (Object)(object)summoner.data == (Object)null)
{
return;
}
int num = Summons.CountLiveSummons(summoner, BotKind.Clone);
Plugin.Log.LogInfo((object)$"Doppelganger: block — {num}/{MaxClones} clone(s) live, you at {((Component)summoner).transform.position}.");
if (num < 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_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
Gun myGun = summoner.data.weaponHandler.gun;
bool share = SharesHealth;
if (!halved)
{
origDamage = myGun.damage;
origMaxHealth = summoner.data.maxHealth;
halved = true;
}
myGun.damage = origDamage * 0.5f;
damageHalved = true;
if (!share)
{
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 + Summons.FacingOffset(summoner, 1.5f);
float cloneHealth = summoner.data.maxHealth;
float fullDamage = origDamage;
bool cloneFullDamage = CloneFullDamage;
Summons.SpawnBot(summoner, pos, Summons.GetColorId(summoner), BotKind.Clone, delegate(GameObject cloneObj)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
CharacterData component = cloneObj.GetComponent<CharacterData>();
Summons.AddAI(cloneObj, anchored: false, canShoot: true, canBlock: false, pos);
Summons.ApplyFace(cloneObj, summoner.playerID);
component.maxHealth = cloneHealth;
component.health = component.maxHealth;
NecroManager.CopyGun(myGun, component.weaponHandler.gun);
NecroManager.CopyValueFields(summoner.data.stats, component.stats, NecroManager.StatFieldsToClone);
if (cloneFullDamage)
{
component.weaponHandler.gun.damage = fullDamage;
}
if (share)
{
cloneObj.AddComponent<SharedHealthLink>().Init(summoner.data, component);
}
});
Plugin.Log.LogInfo((object)($"Doppelganger: split player {summoner.playerID}" + (share ? " (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;
damageHalved = false;
if ((Object)(object)summoner != (Object)null && (Object)(object)summoner.data != (Object)null)
{
summoner.data.weaponHandler.gun.damage = origDamage;
summoner.data.maxHealth = origMaxHealth;
}
}
}
private void OnCloneDied()
{
if (damageHalved && !((Object)(object)summoner == (Object)null) && !((Object)(object)summoner.data == (Object)null) && Summons.CountLiveSummons(summoner, BotKind.Clone) <= 0)
{
summoner.data.weaponHandler.gun.damage = origDamage;
damageHalved = false;
}
}
public static void NotifyPossibleCloneDeath(Player dead)
{
if ((Object)(object)dead == (Object)null)
{
return;
}
SummonedBotTag component = ((Component)dead).GetComponent<SummonedBotTag>();
if ((Object)(object)component == (Object)null || component.kind != BotKind.Clone || (Object)(object)component.master == (Object)null)
{
return;
}
foreach (CloneSummoner item in Active)
{
if ((Object)(object)item.summoner == (Object)(object)component.master)
{
item.OnCloneDied();
break;
}
}
}
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--;
}
}
}
[HarmonyPatch(typeof(CharacterSelectionMenu), "PlayerJoined")]
internal static class CharacterSelectionMenu_PlayerJoined_Patch
{
private static bool Prefix(Player joinedPlayer)
{
if (!((Object)(object)joinedPlayer == (Object)null))
{
return (Object)(object)((Component)joinedPlayer).GetComponent<SummonedBotTag>() == (Object)null;
}
return true;
}
}
[HarmonyPatch(typeof(PlayerManager), "PlayerDied")]
internal static class PlayerManager_PlayerDied_Patch
{
private static void Prefix(Player player)
{
if ((Object)(object)player == (Object)null)
{
return;
}
try
{
RevenantSummoner component = ((Component)player).GetComponent<RevenantSummoner>();
if ((Object)(object)component != (Object)null)
{
component.OnOwnerDied();
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Revenant prefix: " + ex));
}
}
}
[HarmonyPatch(typeof(FollowPlayer), "LateUpdate")]
internal static class FollowPlayer_LateUpdate_Patch
{
private static bool Prefix(FollowPlayer __instance)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Invalid comparison between Unknown and I4
try
{
Player value = Traverse.Create((object)__instance).Field("ownPlayer").GetValue<Player>();
Player val = (((int)__instance.target != 1) ? value : (((Object)(object)PlayerManager.instance != (Object)null) ? PlayerManager.instance.GetOtherPlayer(value) : null));
if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null)
{
return false;
}
}
catch
{
}
return true;
}
}
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 class HiveSummoner : MonoBehaviour
{
public int cardCount;
public int bonusBees;
public int sizeUpgradeCount;
private const float BeeHealthMult = 0.25f;
private const float BeeDamageMult = 0.35f;
private Player owner;
private Block block;
public int BeeCount => 3 + bonusBees;
public float BeeSize => Mathf.Max(0.2f, 0.5f - 0.15f * (float)sizeUpgradeCount);
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 || (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_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_011b: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
Vector3 hivePos = ((Component)owner).transform.position + Summons.FacingOffset(owner, 1.5f);
float hiveHealth = owner.data.maxHealth;
int colorId = Summons.GetColorId(owner);
GameObject hive = Summons.SpawnBot(owner, hivePos, colorId, BotKind.Hive, delegate(GameObject obj)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
CharacterData component = obj.GetComponent<CharacterData>();
Summons.AddAI(obj, anchored: true, canShoot: false, canBlock: false, hivePos);
Summons.ClearFace(obj);
component.maxHealth = hiveHealth;
component.health = component.maxHealth;
});
Gun myGun = owner.data.weaponHandler.gun;
float beeHealth = owner.data.maxHealth * 0.25f;
float beeDamage = myGun.damage * 0.35f;
float beeSize = BeeSize;
for (int num = 0; num < BeeCount; num++)
{
float num2 = ((num % 2 == 0) ? 1f : (-1f)) * (1f + (float)num) * 0.8f;
Vector3 beePos = hivePos + Vector3.right * num2 + Vector3.up * 0.5f;
Summons.SpawnBot(owner, beePos, colorId, BotKind.Bee, delegate(GameObject bee)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
CharacterData component = bee.GetComponent<CharacterData>();
Summons.AddAI(bee, anchored: false, canShoot: true, canBlock: false, beePos, canFly: true);
Summons.ClearFace(bee);
SummonedBotTag component2 = bee.GetComponent<SummonedBotTag>();
if ((Object)(object)component2 != (Object)null)
{
component2.parentSummon = hive;
}
component.maxHealth = beeHealth;
component.health = component.maxHealth;
NecroManager.CopyGun(myGun, component.weaponHandler.gun);
component.weaponHandler.gun.damage = beeDamage;
NecroManager.CopyValueFields(owner.data.stats, component.stats, NecroManager.StatFieldsToClone);
Summons.ApplySize(component, beeSize);
component.jumps = 100;
component.currentJumps = 100;
});
}
Plugin.Log.LogInfo((object)$"Hive: player {owner.playerID} deployed a hive with {BeeCount} bees.");
}
}
public class HiveSwarmCard : UpgradeCard
{
public override BotKind Family => BotKind.Hive;
protected override CardDef Def => CardText.Swarm;
protected override void Apply(Player player)
{
HiveSummoner component = ((Component)player).GetComponent<HiveSummoner>();
if ((Object)(object)component != (Object)null)
{
component.bonusBees += 2;
}
}
protected override void Remove(Player player)
{
HiveSummoner component = ((Component)player).GetComponent<HiveSummoner>();
if ((Object)(object)component != (Object)null)
{
component.bonusBees -= 2;
}
}
}
public class HiveTinyCard : UpgradeCard
{
public override BotKind Family => BotKind.Hive;
protected override CardDef Def => CardText.Tiny;
protected override void Apply(Player player)
{
HiveSummoner component = ((Component)player).GetComponent<HiveSummoner>();
if ((Object)(object)component != (Object)null)
{
component.sizeUpgradeCount++;
}
}
protected override void Remove(Player player)
{
HiveSummoner component = ((Component)player).GetComponent<HiveSummoner>();
if ((Object)(object)component != (Object)null)
{
component.sizeUpgradeCount--;
}
}
}
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_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: 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)
{
Plugin.Log.LogInfo((object)$"Necromancer: {dead.playerID} died with no valid killer — no corpse.");
return;
}
Player val2 = val;
SummonedBotTag component2 = ((Component)val).GetComponent<SummonedBotTag>();
if ((Object)(object)component2 != (Object)null && (Object)(object)component2.master != (Object)null)
{
val2 = component2.master;
}
if (!((Object)(object)val2 == (Object)null))
{
Reanimator component3 = ((Component)val2).GetComponent<Reanimator>();
bool flag = (Object)(object)component3 != (Object)null && component3.EmpowersMinions;
if (!((Object)(object)component != (Object)null) || component.kind == BotKind.Clone || flag)
{
int colorId = (((Object)(object)component != (Object)null && component.colorId >= 0) ? component.colorId : Summons.GetColorId(dead));
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
});
Plugin.Log.LogInfo((object)$"Necromancer: recorded corpse {dead.playerID} for player {val2.playerID}.");
}
}
}
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.8.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.8.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()
{
BuildBase<DoppelgangerCard>();
BuildBase<NecromancerCard>();
BuildBase<TurretCard>();
BuildBase<HiveCard>();
BuildBase<RevenantCard>();
BuildUpgrade<DoppelgangerSwapCard>();
BuildUpgrade<DoppelgangerShareCard>();
BuildUpgrade<DoppelgangerTwinCard>();
BuildUpgrade<DoppelgangerSharpCard>();
BuildUpgrade<DualSentryCard>();
BuildUpgrade<SentryOverclockCard>();
BuildUpgrade<SentryFortifyCard>();
BuildUpgrade<SentryBlockCard>();
BuildUpgrade<NecromancerEmpowerCard>();
BuildUpgrade<NecromancerHarvestCard>();
BuildUpgrade<NecromancerHordeCard>();
BuildUpgrade<HiveSwarmCard>();
BuildUpgrade<HiveTinyCard>();
BuildUpgrade<RevenantDurationCard>();
BuildUpgrade<RevenantRespawnCard>();
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.8.0 loaded.");
}
private static void BuildBase<T>() where T : CustomCard
{
CustomCard.BuildCard<T>((Action<CardInfo>)delegate(CardInfo cardInfo)
{
cardInfo.allowMultiple = false;
});
}
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()
{
Summons.PurgeStragglers();
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;
}
List<NecroManager.Corpse> list = NecroManager.TakeCorpsesFor(owner.playerID);
Plugin.Log.LogInfo((object)$"Necromancer: player {owner.playerID} blocked — {list.Count} corpse(s) to raise.");
foreach (NecroManager.Corpse item in list)
{
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_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_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: 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)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
CharacterData data = c.dead.data;
Gun deadGun = 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;
float botHealth = data.maxHealth * 0.5f;
float botDamage = deadGun.damage * (FullDamage ? 1f : 0.5f);
int faceId = c.faceId;
int colorId = c.colorId;
Summons.SpawnBot(owner, pos, c.colorId, BotKind.Reanimated, delegate(GameObject botObj)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
CharacterData component = botObj.GetComponent<CharacterData>();
Summons.AddAI(botObj, anchored: false, canShoot: true, canBlock: false, pos);
Summons.ClearFace(botObj);
SummonedBotTag component2 = botObj.GetComponent<SummonedBotTag>();
if ((Object)(object)component2 != (Object)null)
{
component2.colorId = colorId;
component2.faceId = faceId;
}
component.maxHealth = botHealth;
component.health = component.maxHealth;
NecroManager.CopyGun(deadGun, component.weaponHandler.gun);
component.weaponHandler.gun.damage = botDamage;
});
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 RevenantDurationCard : UpgradeCard
{
public override BotKind Family => BotKind.Revenant;
protected override CardDef Def => CardText.Lingering;
protected override void Apply(Player player)
{
RevenantSummoner component = ((Component)player).GetComponent<RevenantSummoner>();
if ((Object)(object)component != (Object)null)
{
component.extraDurationCount++;
}
}
protected override void Remove(Player player)
{
RevenantSummoner component = ((Component)player).GetComponent<RevenantSummoner>();
if ((Object)(object)component != (Object)null)
{
component.extraDurationCount--;
}
}
}
public class RevenantRespawnCard : UpgradeCard
{
public override BotKind Family => BotKind.Revenant;
protected override CardDef Def => CardText.SecondWind;
protected override void Apply(Player player)
{
RevenantSummoner component = ((Component)player).GetComponent<RevenantSummoner>();
if ((Object)(object)component != (Object)null)
{
component.respawnOnKillCount++;
}
}
protected override void Remove(Player player)
{
RevenantSummoner component = ((Component)player).GetComponent<RevenantSummoner>();
if ((Object)(object)component != (Object)null)
{
component.respawnOnKillCount--;
}
}
}
public class RevenantSummoner : MonoBehaviour
{
public int cardCount;
public int extraDurationCount;
public int respawnOnKillCount;
private const float BaseSeconds = 10f;
private const float BonusSeconds = 5f;
private Player owner;
private bool subscribed;
public float Duration => 10f + (float)extraDurationCount * 5f;
public bool RespawnsOnKill => respawnOnKillCount > 0;
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)owner == (Object)null || (Object)(object)owner.data == (Object)null || (Object)(object)dead == (Object)null || !RespawnsOnKill || !owner.data.dead || !((Object)(object)dead != (Object)(object)owner) || !((Object)(object)dead.data != (Object)null))
{
return;
}
Player lastSourceOfDamage = dead.data.lastSourceOfDamage;
SummonedBotTag summonedBotTag = (((Object)(object)lastSourceOfDamage != (Object)null) ? ((Component)lastSourceOfDamage).GetComponent<SummonedBotTag>() : null);
if (!((Object)(object)summonedBotTag != (Object)null) || summonedBotTag.kind != BotKind.Revenant || !((Object)(object)summonedBotTag.master == (Object)(object)owner))
{
return;
}
try
{
RespawnOwner();
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Revenant: respawn failed — " + ex));
}
}
public void OnOwnerDied()
{
if (cardCount <= 0 || !PhotonNetwork.OfflineMode || (Object)(object)owner == (Object)null || (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 RespawnOwner()
{
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: 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)
if ((Object)(object)owner.data.healthHandler != (Object)null)
{
owner.data.healthHandler.Revive(true);
}
Plugin.Log.LogInfo((object)$"Revenant: player {owner.playerID} respawned from a ghost kill.");
GameObject liveSummon = Summons.GetLiveSummon(owner, BotKind.Revenant);
if ((Object)(object)liveSummon != (Object)null)
{
CharacterData component = liveSummon.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);
}
}
}
private void SpawnRevenant()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
Vector3 pos = ((Component)owner).transform.position;
Gun myGun = owner.data.weaponHandler.gun;
float ghostHealth = owner.data.maxHealth;
GameObject obj = Summons.SpawnBot(owner, pos, Summons.GetColorId(owner), BotKind.Revenant, delegate(GameObject o)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
CharacterData component2 = o.GetComponent<CharacterData>();
Summons.AddAI(o, anchored: false, canShoot: true, canBlock: false, pos);
Summons.ClearFace(o);
component2.maxHealth = ghostHealth;
component2.health = component2.maxHealth;
NecroManager.CopyGun(myGun, component2.weaponHandler.gun);
NecroManager.CopyValueFields(owner.data.stats, component2.stats, NecroManager.StatFieldsToClone);
});
SummonedBotTag component = obj.GetComponent<SummonedBotTag>();
if ((Object)(object)component != (Object)null)
{
component.survivesMasterDeath = true;
}
Summons.KillAfter(obj, Duration);
Plugin.Log.LogInfo((object)$"Revenant: player {owner.playerID} rose for a last stand.");
}
}
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 class SummonAI : MonoBehaviour
{
public bool isAnchored;
public bool canShoot = true;
public bool canBlock;
public bool canFly;
public Vector3 spawnPos;
public Sprite sprite;
private const float IdleSpeed = 1f;
private const float StuckAfter = 1.25f;
private const float NudgeTime = 0.6f;
private const float FarEnough = 6.5f;
private static readonly FieldInfo KinematicField = typeof(PlayerVelocity).GetField("isKinematic", BindingFlags.Instance | BindingFlags.NonPublic);
private CharacterData data;
private GeneralInput input;
private Block block;
private bool anchored;
private Vector3 anchorPos;
private Vector3 lastPos;
private float stuckTimer;
private float nudgeTimer;
private void Start()
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
data = ((Component)this).GetComponentInParent<CharacterData>();
if (!((Object)(object)data == (Object)null))
{
input = data.input;
block = ((Component)data).GetComponent<Block>();
if (isAnchored)
{
((MonoBehaviour)this).StartCoroutine(AnchorAfterSettle());
return;
}
((Component)this).gameObject.AddComponent<PlayerAI>();
lastPos = ((Component)data).transform.position;
}
}
private void Update()
{
if (!((Object)(object)data == (Object)null) && !((Object)(object)input == (Object)null) && !((Object)(object)PlayerManager.instance == (Object)null))
{
if (isAnchored)
{
UpdateAnchored();
}
else
{
UpdateMobile();
}
}
}
private void LateUpdate()
{
if (!((Object)(object)data == (Object)null))
{
if (isAnchored)
{
AnchorLock();
}
else
{
UnstickNudge();
}
}
}
private IEnumerator AnchorAfterSettle()
{
yield return (object)new WaitForSeconds(0.35f);
if ((Object)(object)data != (Object)null && (Object)(object)data.playerVel != (Object)null)
{
anchorPos = ((Component)data).transform.position;
anchored = true;
if (KinematicField != null)
{
KinematicField.SetValue(data.playerVel, true);
}
}
}
private void AnchorLock()
{
//IL_0022: 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)
if (!anchored || data.dead)
{
return;
}
((Component)data).transform.position = anchorPos;
if ((Object)(object)data.playerVel != (Object)null)
{
data.playerVel.position = Vector2.op_Implicit(anchorPos);
if (KinematicField != null)
{
KinematicField.SetValue(data.playerVel, true);
}
}
}
private void UpdateAnchored()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: 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_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
input.direction = Vector3.zero;
if (!canShoot)
{
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;
}
private void UpdateMobile()
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
Player otherPlayer = PlayerManager.instance.GetOtherPlayer(data.player);
if (!((Object)(object)otherPlayer == (Object)null))
{
if (canBlock && (Object)(object)block != (Object)null)
{
block.TryBlock();
}
if (canFly && ((Component)otherPlayer).transform.position.y > ((Component)this).transform.position.y + 1f)
{
input.jumpWasPressed = true;
}
}
}
private void UnstickNudge()
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: 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_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Unknown result type (might be due to invalid IL or missing references)
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
if (data.dead || (Object)(object)input == (Object)null || (Object)(object)PlayerManager.instance == (Object)null)
{
return;
}
if (!canShoot)
{
input.shootIsPressed = false;
input.shootWasPressed = false;
}
Player otherPlayer = PlayerManager.instance.GetOtherPlayer(data.player);
if ((Object)(object)otherPlayer == (Object)null)
{
return;
}
Vector3 position = ((Component)data).transform.position;
float deltaTime = Time.deltaTime;
float num;
if (!(deltaTime > 0f))
{
num = 0f;
}
else
{
Vector3 val = position - lastPos;
num = ((Vector3)(ref val)).magnitude / deltaTime;
}
float num2 = num;
lastPos = position;
float num3 = Vector2.Distance(Vector2.op_Implicit(position), Vector2.op_Implicit(((Component)otherPlayer).transform.position));
if (nudgeTimer > 0f)
{
nudgeTimer -= deltaTime;
if (num3 <= 6.5f)
{
nudgeTimer = 0f;
return;
}
float num4 = ((Component)otherPlayer).transform.position.x - position.x;
input.direction = new Vector3((num4 >= 0f) ? 1f : (-1f), 0f, 0f);
}
else if (num3 > 6.5f && num2 < 1f)
{
stuckTimer += deltaTime;
if (stuckTimer >= 1.25f)
{
stuckTimer = 0f;
nudgeTimer = 0.6f;
}
}
else
{
stuckTimer = 0f;
}
}
}
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 readonly MethodInfo ConfigureMassAndSize = typeof(CharacterStatModifiers).GetMethod("ConfigureMassAndSize", BindingFlags.Instance | BindingFlags.NonPublic);
private static Type rwfPlayerExt;
private static bool rwfChecked;
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);
CloneSummoner.NotifyPossibleCloneDeath(dead);
}
}
public static GameObject SpawnBot(Player master, Vector3 pos, int colorPlayerId, BotKind kind, Action<GameObject> configure = null)
{
//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)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: 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;
component.dead = false;
PlayerAPI component2 = val.GetComponent<PlayerAPI>();
if ((Object)(object)component2 != (Object)null)
{
((Behaviour)component2).enabled = false;
}
SummonedBotTag summonedBotTag = val.AddComponent<SummonedBotTag>();
summonedBotTag.kind = kind;
summonedBotTag.master = master;
summonedBotTag.colorId = colorPlayerId;
summonedBotTag.faceId = colorPlayerId;
All.Add(val);
SetPos(component, pos);
((MonoBehaviour)TheRunner).StartCoroutine(Setup(component, count, pos, configure));
return val;
}
private static void SetPos(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 static IEnumerator Setup(CharacterData cd, int uniqueId, Vector3 spawnPos, Action<GameObject> configure)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
yield return null;
if ((Object)(object)cd == (Object)null || (Object)(object)cd.player == (Object)null)
{
yield break;
}
int guard = 0;
while (guard++ < 60 && (Object)(object)cd != (Object)null && (Object)(object)cd.player != (Object)null && ((Object)(object)cd.weaponHandler == (Object)null || (Object)(object)cd.weaponHandler.gun == (Object)null || (Object)(object)cd.weaponHandler.gun.player == (Object)null))
{
yield return null;
}
if ((Object)(object)cd == (Object)null || (Object)(object)cd.player == (Object)null)
{
yield break;
}
cd.isPlaying = true;
cd.healthHandler.DestroyOnDeath = false;
try
{
cd.healthHandler.Revive(true);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Summons: revive failed — " + ex));
}
cd.player.playerID = uniqueId;
try
{
configure?.Invoke(((Component)cd).gameObject);
}
catch (Exception ex2)
{
Plugin.Log.LogError((object)("Summons: configure failed — " + ex2));
}
SetPos(cd, spawnPos);
SummonedBotTag component = ((Component)cd).GetComponent<SummonedBotTag>();
if ((Object)(object)component != (Object)null && !component.survivesMasterDeath && (Object)(object)component.master != (Object)null && (Object)(object)component.master.data != (Object)null && component.master.data.dead && !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);
yield break;
}
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 void ApplySize(CharacterData cd, float sizeMult)
{
if ((Object)(object)cd == (Object)null || (Object)(object)cd.stats == (Object)null)
{
return;
}
cd.stats.sizeMultiplier = sizeMult;
try
{
ConfigureMassAndSize?.Invoke(cd.stats, null);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Summons: size failed — " + ex));
}
}
public static int GetColorId(Player p)
{
if ((Object)(object)p == (Object)null)
{
return 0;
}
if (!rwfChecked)
{
rwfChecked = true;
rwfPlayerExt = Type.GetType("RWF.PlayerExtensions, RoundsWithFriends");
}
if (rwfPlayerExt != null)
{
try
{
object obj = rwfPlayerExt.GetMethod("GetAdditionalData")?.Invoke(null, new object[1] { p });
object obj2 = obj?.GetType().GetField("character")?.GetValue(obj);
object obj3 = obj2?.GetType().GetField("colorID")?.GetValue(obj2);
if (obj3 is int)
{
return (int)obj3;
}
}
catch
{
}
}
return p.playerID;
}
public static void ClearFace(GameObject bot)
{
if ((Object)(object)bot == (Object)null)
{
return;
}
CharacterCreatorItemEquipper componentInChildren = bot.GetComponentInChildren<CharacterCreatorItemEquipper>();
if (!((Object)(object)componentInChildren == (Object)null) && !((Object)(object)componentInChildren.itemParent == (Object)null))
{
Transform transform = componentInChildren.itemParent.transform;
for (int num = transform.childCount - 1; num >= 0; num--)
{
Object.Destroy((Object)(object)((Component)transform.GetChild(num)).gameObject);
}
}
}
public static void ApplyFace(GameObject bot, int faceId)
{
CharacterCreatorHandler instance = CharacterCreatorHandler.instance;
if ((Object)(object)bot == (Object)null || (Object)(object)instance == (Object)null || faceId < 0 || faceId >= instance.selectedPlayerFaces.Length)
{
return;
}
PlayerFace val = instance.selectedPlayerFaces[faceId];
if (val != null)
{
CharacterCreatorItemEquipper componentInChildren = bot.GetComponentInChildren<CharacterCreatorItemEquipper>();
if ((Object)(object)componentInChildren != (Object)null)
{
componentInChildren.EquipFace(val);
}
}
}
public static SummonAI AddAI(GameObject bot, bool anchored, bool canShoot, bool canBlock, Vector3 spawnPos, bool canFly = false)
{
//IL_002f: 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)
if ((Object)(object)bot == (Object)null)
{
return null;
}
SummonAI summonAI = bot.AddComponent<SummonAI>();
summonAI.isAnchored = anchored;
summonAI.canShoot = canShoot;
summonAI.canBlock = canBlock;
summonAI.canFly = canFly;
summonAI.spawnPos = spawnPos;
return summonAI;
}
public static Vector3 EnemyOffset(Player owner, float dist)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: 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_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)owner == (Object)null || (Object)(object)PlayerManager.instance == (Object)null)
{
return Vector3.zero;
}
Player otherPlayer = PlayerManager.instance.GetOtherPlayer(owner);
if ((Object)(object)otherPlayer == (Object)null)
{
return Vector3.zero;
}
return new Vector3((((Component)otherPlayer).transform.position.x - ((Component)owner).transform.position.x >= 0f) ? dist : (0f - dist), 0f, 0f);
}
public static Vector3 FacingOffset(Player owner, float dist)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)owner == (Object)null || (Object)(object)owner.data == (Object)null)
{
return Vector3.zero;
}
return new Vector3(((((Object)(object)owner.data.input != (Object)null) ? owner.data.input.aimDirection.x : 0f) < 0f) ? (0f - dist) : dist, 0f, 0f);
}
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()
{
int count = All.Count;
foreach (GameObject item in All)
{
DestroySummon(item);
}
All.Clear();
int num = PurgeStragglers();
Plugin.Log.LogInfo((object)$"Summons: cleanup destroyed {count} tracked, purged {num} straggler(s).");
}
private static void DestroySummon(GameObject o)
{
if ((Object)(object)o == (Object)null)
{
return;
}
try
{
CharacterData component = o.GetComponent<CharacterData>();
if ((Object)(object)component != (Object)null && (Object)(object)component.player != (Object)null && (Object)(object)PlayerManager.instance != (Object)null)
{
PlayerManager.instance.players.Remove(component.player);
}
PhotonNetwork.Destroy(o);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Summons destroy: " + ex));
}
try
{
if ((Object)(object)o != (Object)null)
{
Object.Destroy((Object)(object)o);
}
}
catch
{
}
}
public static int PurgeStragglers()
{
if ((Object)(object)PlayerManager.instance == (Object)null)
{
return 0;
}
int num = 0;
List<Player> players = PlayerManager.instance.players;
for (int num2 = players.Count - 1; num2 >= 0; num2--)
{
Player val = players[num2];
if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).GetComponent<SummonedBotTag>() == (Object)null))
{
players.RemoveAt(num2);
All.Remove(((Component)val).gameObject);
DestroySummon(((Component)val).gameObject);
num++;
}
}
return num;
}
}
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 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;
private Block block;
public int MaxTurrets => 1 + bonusTurrets;
public bool FullDamage => fullDamageCount > 0;
public bool CanBlock => blockCount > 0;
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 || (Object)(object)owner.data == (Object)null || (Object)(object)PlayerAssigner.instance == (Object)null || (Object)(object)PlayerAssigner.instance.playerPrefab == (Object)null || Summons.CountLiveSummons(owner, BotKind.Turret) >= MaxTurrets)
{
return;
}
try
{
SpawnOne();
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Turret: spawn failed — " + ex));
}
}
private void SpawnOne()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//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_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
Vector3 pos = ((Component)owner).transform.position + Summons.FacingOffset(owner, 1.5f);
Gun myGun = owner.data.weaponHandler.gun;
float turretHealth = owner.data.maxHealth * (1f + (float)healthBonusCount);
float turretDamage = myGun.damage * (FullDamage ? 1f : 0.5f);
bool canBlock = CanBlock;
Summons.SpawnBot(owner, pos, Summons.GetColorId(owner), BotKind.Turret, delegate(GameObject obj)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
CharacterData component = obj.GetComponent<CharacterData>();
Summons.AddAI(obj, anchored: true, canShoot: true, canBlock, pos);
Summons.ClearFace(obj);
component.maxHealth = turretHealth;
component.health = component.maxHealth;
NecroManager.CopyGun(myGun, component.weaponHandler.gun);
component.weaponHandler.gun.damage = turretDamage;
});
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,
BotKind.Hive => (Object)(object)((Component)player).GetComponent<HiveSummoner>() != (Object)null,
BotKind.Revenant => (Object)(object)((Component)player).GetComponent<RevenantSummoner>() != (Object)null,
_ => true,
};
}
}
}