Decompiled source of W and W Inc v0.1.145

plugins/WwInc.Plugin.dll

Decompiled 7 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using Conductor.Data.Registers;
using Conductor.Interfaces;
using Conductor.RoomModifiers;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Configuration;
using TrainworksReloaded.Base;
using TrainworksReloaded.Core;
using TrainworksReloaded.Core.Extensions;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WwInc.Plugin")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.145.0")]
[assembly: AssemblyInformationalVersion("0.1.145+2792d02beb20a9a1adfbd21b3bf4aca85116947c")]
[assembly: AssemblyProduct("WwInc.Plugin")]
[assembly: AssemblyTitle("WwInc.Plugin")]
[assembly: AssemblyVersion("0.1.145.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 WwInc
{
	public abstract class AcademicEffectBase : CardEffectBase
	{
		public override bool CanApplyInPreviewMode => false;

		public override PropDescriptions CreateEditorInspectorDescriptions()
		{
			return PropDescriptions.DisplayNone;
		}
	}
	public sealed class CardEffectAcademicTransfer : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			return p.targets.Count > 0;
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			AcademicRuntime.Core = m;
			CharacterState target = p.targets[0];
			string paramStr = s.GetParamStr();
			if (paramStr == "weakness")
			{
				List<CharacterState> list = new List<CharacterState>();
				m.GetHeroManager().AddCharactersToList(list);
				int num = list.Sum((CharacterState u) => u.GetStatusEffectStacks("spell weakness"));
				foreach (CharacterState item in list)
				{
					item.RemoveStatusEffect("spell weakness", item.GetStatusEffectStacks("spell weakness"), false);
				}
				target.AddStatusEffect("spell weakness", num, (CharacterState)null, false, false);
				yield break;
			}
			if (paramStr == "debuffs")
			{
				foreach (CharacterState item2 in from u in AcademicRuntime.Units(target.GetCurrentRoomIndex(), (Type)2)
					where (Object)(object)u != (Object)(object)target
					select u)
				{
					TransferDebuffs(item2, target);
				}
				yield break;
			}
			throw new InvalidOperationException("Unknown academic transfer: " + paramStr);
		}

		internal static void TransferDebuffs(CharacterState source, CharacterState target)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			List<StatusEffectStack> list = new List<StatusEffectStack>();
			source.GetStatusEffects(ref list, false);
			foreach (StatusEffectStack item in list)
			{
				item.State.GetSourceStatusEffectData();
				if ((int)item.State.GetDisplayCategory() == 1)
				{
					int count = item.Count;
					string statusId = item.State.GetStatusId();
					source.RemoveStatusEffect(statusId, count, false);
					target.AddStatusEffect(statusId, count, (CharacterState)null, false, false);
				}
			}
		}
	}
	public sealed class CardEffectAcademicHealthExchange : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			AcademicRuntime.Core = m;
			return AcademicRuntime.Units(p.selectedRoom, (Type)2).Count >= 2;
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			AcademicRuntime.Core = m;
			List<CharacterState> list = AcademicRuntime.Units(p.selectedRoom, (Type)2);
			if (list.Count >= 2)
			{
				CharacterState val = list[0];
				CharacterState val2 = list[list.Count - 1];
				int hP = val.GetHP();
				int hP2 = val2.GetHP();
				val.SetHealth(Math.Min(hP2, val.GetMaxHP()), val.GetMaxHP());
				val2.SetHealth(Math.Min(hP, val2.GetMaxHP()), val2.GetMaxHP());
				if (hP2 > val.GetMaxHP())
				{
					val.AddStatusEffect("armor", hP2 - val.GetMaxHP(), (CharacterState)null, true, false);
				}
				if (hP > val2.GetMaxHP())
				{
					val2.AddStatusEffect("armor", hP - val2.GetMaxHP(), (CharacterState)null, true, false);
				}
			}
			yield break;
		}
	}
	public sealed class CardEffectAcademicDeskSwap : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			AcademicRuntime.Core = m;
			return AcademicRuntime.Units(p.selectedRoom, (Type)2).Count >= 2;
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			AcademicRuntime.Core = m;
			List<CharacterState> list = AcademicRuntime.Units(p.selectedRoom, (Type)2);
			if (list.Count >= 2)
			{
				CharacterState val = list[list.Count - 1];
				RoomState selectedRoom = p.GetSelectedRoom(m.GetRoomManager());
				selectedRoom.RearrangeCharacter((Type)2, 0, list.Count - 1);
				selectedRoom.RearrangeCharacter((Type)2, list.Count - 2, 0);
				selectedRoom.UpdateSpawnPointPositions((Type)2, -1, false, true);
				yield return m.GetCombatManager().RunUnitTurn(val, (ICharacterManager)(object)m.GetMonsterManager(), (ICharacterManager)(object)m.GetHeroManager(), selectedRoom.GetRoomIndex(), false, (List<CharacterState>)null, true, (Action<int>)null, false);
			}
		}
	}
	public sealed class CardEffectAcademicSabbatical : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			return p.targets.Any((CharacterState u) => !u.HasStatusEffect("untouchable"));
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			AcademicRuntime.Core = m;
			foreach (CharacterState unit in p.targets)
			{
				if (!unit.HasStatusEffect("untouchable"))
				{
					unit.AddStatusEffect("untouchable", 1, (CharacterState)null, true, false);
					AcademicRuntime.NextTurnActions.Add(() => Wake(unit, p.playedCard, s.GetParamInt()));
				}
			}
			yield break;
		}

		private static IEnumerator Wake(CharacterState unit, CardState? card, int extra)
		{
			if (!unit.IsDestroyed && !unit.IsDead)
			{
				unit.RemoveStatusEffect("untouchable", 1, false);
				yield return unit.ApplyHeal(Math.Max(0, unit.GetMaxHP() - unit.GetHP()) / 2 + extra, true, card, (RelicState)null, false, (VfxAtLoc)null, 0);
			}
		}
	}
	public sealed class CardEffectAcademicArmorHonors : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			AcademicRuntime.Core = m;
			foreach (CharacterState unit in p.targets)
			{
				int attackDamage = unit.GetAttackDamage();
				unit.AddStatusEffect("armor", attackDamage, (CharacterState)null, true, false);
				AcademicRuntime.ZeroAttack.Add(unit);
				unit.AddStatusEffect("dazed", 1, (CharacterState)null, true, false);
				AcademicRuntime.EndTurnActions.Add(delegate
				{
					if (!unit.IsDestroyed)
					{
						AcademicRuntime.ZeroAttack.Remove(unit);
					}
				});
			}
			yield break;
		}
	}
	public sealed class CardEffectAcademicConversion : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			AcademicRuntime.Core = m;
			CharacterState val = p.characterThatActivatedAbility ?? p.selfTarget;
			if ((Object)(object)val != (Object)null)
			{
				AcademicRuntime.HealingModes[val] = s.GetParamInt();
			}
			yield break;
		}
	}
	public sealed class CardEffectAcademicConsumeCredits : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			return m.GetCardManager().GetHand(false).Any((CardState c) => c != p.playedCard && (int)c.GetCardType() == 0);
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			if (m.GetSaveManager().PreviewMode)
			{
				yield break;
			}
			AcademicRuntime.Core = m;
			CharacterState unit = p.characterThatActivatedAbility ?? p.selfTarget;
			if (!((Object)(object)unit == (Object)null))
			{
				yield return AcademicRuntime.ChooseHand(p.playedCard, (CardState c) => (int)c.GetCardType() == 0, (CardState chosen) => ResolveCredits(chosen, unit, m));
			}
		}

		private static IEnumerator ResolveCredits(CardState chosen, CharacterState unit, ICoreGameManagers m)
		{
			AcademicRuntime.Core = m;
			int conduit = Math.Max(0, chosen.GetCostWithoutAnyModifications()) * 5;
			yield return m.GetCardManager().ConsumeCardWithoutPlaying(new DiscardCardParams
			{
				discardCard = chosen,
				overrideDiscardEffect = (DiscardEffect)2
			});
			unit.AddStatusEffect("conduit", conduit, (CharacterState)null, true, false);
		}
	}
	public sealed class CardEffectAcademicConduitTransfer : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			return m.GetCardManager().GetHand(false).Any((CardState c) => c != p.playedCard && (int)c.GetCardType() == 0);
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			if (m.GetSaveManager().PreviewMode)
			{
				yield break;
			}
			AcademicRuntime.Core = m;
			yield return AcademicRuntime.ChooseHand(p.playedCard, (CardState c) => (int)c.GetCardType() == 0, delegate(CardState chosen)
			{
				AcademicRuntime.Core = m;
				int num = 0;
				foreach (CharacterState item in AcademicRuntime.AllAllies())
				{
					int statusEffectStacks = item.GetStatusEffectStacks("conduit");
					num += statusEffectStacks;
					item.RemoveStatusEffect("conduit", statusEffectStacks, false);
				}
				AcademicRuntime.ModifyCard(chosen, num, 0, thisTurn: false);
				SpellRules.Explosive(chosen);
			});
		}
	}
	public sealed class CardEffectAcademicEquipmentReturn : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			AcademicRuntime.Core = m;
			foreach (CharacterState unit in p.targets)
			{
				CardState equipment = unit.GetEquipment().FirstOrDefault();
				if (equipment == null)
				{
					continue;
				}
				bool preview = m.GetSaveManager().PreviewMode;
				if (!preview)
				{
					equipment.SetRemoveFromStandByPileOverride((CardPile)3);
				}
				if (preview)
				{
					AcademicRuntime.EquipmentPreviewDepth++;
				}
				try
				{
					yield return unit.RemoveEquipment(m, equipment);
				}
				finally
				{
					if (preview)
					{
						AcademicRuntime.EquipmentPreviewDepth--;
					}
				}
				if (!preview)
				{
					AcademicRuntime.SetFixedCost(equipment, 0, thisTurn: true);
				}
				unit.AddStatusEffect("damage shield", 1, (CharacterState)null, true, false);
			}
		}
	}
	public sealed class CardEffectAcademicOneTurnUpgrade : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			AcademicRuntime.Core = m;
			foreach (CharacterState unit in p.targets)
			{
				CardUpgradeState upgrade = new CardUpgradeState();
				upgrade.Setup(s.GetParamCardUpgradeData(), false, false);
				yield return unit.ApplyCardUpgrade(upgrade, false, "", true, false, (CardState)null, (Action<UpgradeApplicationResult>)null, (TrainRoomAttachmentState)null, false);
				AcademicRuntime.NextTurnActions.Add(() => Remove(unit, upgrade));
			}
		}

		private static IEnumerator Remove(CharacterState unit, CardUpgradeState upgrade)
		{
			if (!unit.IsDestroyed)
			{
				yield return unit.RemoveCardUpgrade(upgrade, "", true, (TrainRoomAttachmentState)null);
			}
		}
	}
	internal static class AcademicMath
	{
		internal static int CreditDamageIncrement(long current, int amount)
		{
			return (int)Math.Max(0L, Math.Min(Math.Max(0, amount), int.MaxValue - Math.Max(0L, current)));
		}

		internal static int OverdamageAmount(int damage, int sustained)
		{
			return (int)Math.Min(2147483647L, Math.Max(0L, (long)damage - (long)Math.Max(0, sustained)));
		}

		internal static int ScaleOverdamage(int excess, int percent)
		{
			return (int)Math.Min(2147483647L, (long)Math.Max(0, excess) * (long)Math.Max(0, percent) / 100);
		}

		internal static int SharedHealing(int damage, int allies)
		{
			if (allies <= 0)
			{
				return 0;
			}
			return Math.Max(0, damage) / allies;
		}

		internal static int ExcessHealing(int healing, int health, int maximum)
		{
			if (healing < 9999)
			{
				return (int)Math.Max(0L, Math.Min(2147483647L, Math.Max(0, healing) - Math.Max(0L, (long)maximum - (long)health)));
			}
			return 0;
		}

		internal static int OverhealArmor(int excess, int maximum)
		{
			return Math.Min(Math.Max(0, excess), Math.Max(0, maximum));
		}

		internal static int ConsumedDamage(int incoming, int perCard, int count)
		{
			return (int)Math.Max(0L, Math.Min(2147483647L, incoming + (long)Math.Max(0, perCard) * (long)Math.Max(0, count)));
		}

		internal static (int count, bool refund) RefundProgress(int count, int kills)
		{
			if (kills <= 0)
			{
				return (count: count, refund: false);
			}
			if (count < 4)
			{
				return (count: count + 1, refund: false);
			}
			return (count: 0, refund: true);
		}

		internal static int EducationPower(int attack, int educators)
		{
			return (int)Math.Min(2147483647L, (long)(Math.Max(0, attack) / 2) * (long)Math.Max(0, educators));
		}

		internal static bool FirstQualifyingSpell(HashSet<string> used, string kind, int floor, int amount)
		{
			if (amount > 0)
			{
				return used.Add(kind + ":" + floor);
			}
			return false;
		}

		internal static int EffectiveX(int paid, int modifier)
		{
			return (int)Math.Max(0L, Math.Min(2147483647L, (long)paid + (long)modifier));
		}

		internal static int ChampionRank(IEnumerable<string> upgrades, string prefix)
		{
			int num = 0;
			foreach (string upgrade in upgrades)
			{
				for (int i = 1; i <= 3; i++)
				{
					if (upgrade.EndsWith(prefix + i, StringComparison.Ordinal))
					{
						num = Math.Max(num, i);
					}
				}
			}
			return num;
		}

		internal static int ChampionAura(int rank, int allies, int perMage = 5)
		{
			return (int)Math.Min(2147483647L, (long)Math.Max(0, rank) * (long)Math.Max(0, perMage) * Math.Max(0, allies));
		}

		internal static (int attack, int health) ServingStats(long conduit)
		{
			int num = (int)Math.Max(0L, Math.Min(2147483646L, conduit));
			return (attack: num, health: num + 1);
		}

		internal static bool Mixed(int left, int right)
		{
			if ((left & 1) == 0 || (right & 2) == 0)
			{
				if ((left & 2) != 0)
				{
					return (right & 1) != 0;
				}
				return false;
			}
			return true;
		}

		internal static bool CanInsertChaperone(int count)
		{
			return count < 7;
		}

		internal static (int discounts, int remainder) Tuition(int previous, int actualDamage)
		{
			long num = (long)Math.Max(0, previous) + (long)Math.Max(0, actualDamage);
			return (discounts: (int)(num / 30), remainder: (int)(num % 30));
		}

		internal static int RedirectionDamage(int previousDazed)
		{
			return checked(Math.Max(0, previousDazed) * 10);
		}
	}
	internal static class AcademicRuntime
	{
		internal sealed class SpellResolution
		{
			internal CardState Card;

			internal int Floor;

			internal bool FirstDamage;

			internal bool WasFrozen;

			internal bool Redirected;

			internal bool Indirect;

			internal readonly HashSet<string> Rules = new HashSet<string>();

			internal readonly List<Action> Cleanup = new List<Action>();

			internal CharacterState? Target;

			internal CharacterState? EnemyBehind;

			internal readonly Dictionary<int, int> Damage = new Dictionary<int, int>();

			internal readonly Dictionary<int, int> Healing = new Dictionary<int, int>();

			internal readonly Dictionary<int, int> Kills = new Dictionary<int, int>();
		}

		internal static ICoreGameManagers Core = null;

		internal static int Turn;

		internal static Trigger ArcaneSlay;

		internal static int ConversionDepth;

		internal static int HostileHealingDepth;

		internal static int EquipmentPreviewDepth;

		internal static CardState? LastPlayedCommonSpell;

		internal static readonly Dictionary<CharacterState, int> HealingModes = new Dictionary<CharacterState, int>();

		internal static readonly Dictionary<CharacterState, int> DamageCredits = new Dictionary<CharacterState, int>();

		internal static readonly List<Action> EndTurnActions = new List<Action>();

		internal static readonly List<Func<IEnumerator>> NextTurnActions = new List<Func<IEnumerator>>();

		internal static readonly Stack<SpellResolution> Frames = new Stack<SpellResolution>();

		internal static bool DamageSpellPlayed;

		internal static CardState? FirstDamageSpell;

		internal static readonly HashSet<CharacterState> ZeroAttack = new HashSet<CharacterState>();

		internal static readonly Dictionary<CharacterState, List<CardState>> BoundForAttack = new Dictionary<CharacterState, List<CardState>>();

		internal static readonly Dictionary<CardState, int> FixedCosts = new Dictionary<CardState, int>();

		internal static bool Simulating
		{
			get
			{
				if (Core != null)
				{
					return Core.GetSaveManager().PreviewMode;
				}
				return false;
			}
		}

		internal static bool Active
		{
			get
			{
				if (Core != null)
				{
					if (Simulating)
					{
						return PreviewScope.Active;
					}
					return true;
				}
				return false;
			}
		}

		internal static string Id(CardState? card)
		{
			return ((card != null) ? card.GetAssetName() : null) ?? "";
		}

		internal static bool Is(CharacterState unit, string id)
		{
			return ((Object)unit.GetSourceCharacterData()).name.EndsWith(id + "_Character", StringComparison.Ordinal);
		}

		internal static List<CharacterState> Units(int floor, Type team = (Type)2)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			List<CharacterState> list = new List<CharacterState>();
			RoomState room = Core.GetRoomManager().GetRoom(floor);
			if ((Object)(object)room != (Object)null)
			{
				room.AddCharactersToList(list, team, false, true);
			}
			return list.Where((CharacterState c) => !c.IsDead && !c.IsDestroyed).ToList();
		}

		internal static IEnumerable<CharacterState> AllAllies()
		{
			List<CharacterState> list = new List<CharacterState>();
			Core.GetMonsterManager().AddCharactersToList(list);
			return list.Where((CharacterState u) => !u.IsDead && !u.IsDestroyed);
		}

		internal static void Reset(CardManager manager)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Core = ((AllGameManagers)AccessTools.Field(typeof(CardManager), "allGameManagers").GetValue(manager)).GetCoreManagers();
			SocialRules.AuraBonuses.Clear();
			ZeroAttack.Clear();
			FixedCosts.Clear();
			BoundForAttack.Clear();
			Turn = 0;
			ConversionDepth = 0;
			HostileHealingDepth = 0;
			EquipmentPreviewDepth = 0;
			Frames.Clear();
			LastPlayedCommonSpell = null;
			HealingModes.Clear();
			SpellRules.Reset();
			MineMineMine.Claimed.Clear();
			DamageCredits.Clear();
			EndTurnActions.Clear();
			NextTurnActions.Clear();
			DamageSpellPlayed = false;
			FirstDamageSpell = null;
			CardEffectAcademicPurgePermit.BeginBattle(Core);
		}

		internal static IEnumerator BeginTurn()
		{
			if (Core != null && !Core.GetSaveManager().PreviewMode)
			{
				Turn++;
				DamageSpellPlayed = false;
				FirstDamageSpell = null;
				HealingModes.Clear();
				Func<IEnumerator>[] array = NextTurnActions.ToArray();
				NextTurnActions.Clear();
				Func<IEnumerator>[] array2 = array;
				foreach (Func<IEnumerator> func in array2)
				{
					yield return func();
				}
				yield return SpellRules.BeginTurn();
				yield return SocialRules.BeginTurn();
				SocialRules.RefreshAuras();
				yield return CateringRules.BeginTurn();
			}
		}

		internal static void EndTurn()
		{
			if (Active)
			{
				if (!DamageSpellPlayed && SpellRules.HasRelic("WW_A04"))
				{
					Core.GetCardManager().AdjustDrawCountModifier(1, (CardState)null, (Action<CardState>)null);
				}
				TurnCleanup.Run(EndTurnActions);
				HealingModes.Clear();
				SpellRules.Pending.RemoveAll((SpellRules.Rule r) => r.Kind == "power");
			}
		}

		internal static void RecordDamage(CharacterState target, int lost, bool died, CardState? card, CharacterState? attacker, int floor)
		{
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Invalid comparison between Unknown and I4
			if (!Active || ConversionDepth != 0)
			{
				return;
			}
			if (!Simulating && lost > 0 && (Object)(object)attacker != (Object)null && Is(attacker, "WW_U18"))
			{
				int value;
				(int, int) tuple = AcademicMath.Tuition(DamageCredits.TryGetValue(attacker, out value) ? value : 0, lost);
				var (num, _) = tuple;
				DamageCredits[attacker] = tuple.Item2;
				if (num > 0)
				{
					CardState[] array = (from c in Core.GetCardManager().GetHand(false)
						where c.HasTrait(typeof(CardTraitFreeze))
						select c).ToArray();
					for (int num2 = 0; num2 < array.Length; num2++)
					{
						ModifyCard(array[num2], 0, num, thisTurn: false);
					}
				}
			}
			if (Frames.Count == 0 || card == null || Frames.Peek().Card != card)
			{
				return;
			}
			SpellResolution spellResolution = Frames.Peek();
			if ((int)target.GetTeamType() == 1)
			{
				spellResolution.Damage[floor] = (spellResolution.Damage.TryGetValue(floor, out var value2) ? (value2 + lost) : lost);
				if (died)
				{
					spellResolution.Kills[floor] = ((!spellResolution.Kills.TryGetValue(floor, out value2)) ? 1 : (value2 + 1));
				}
			}
		}

		internal static void RecordHeal(CharacterState target, int restored, int excess, CardState? source)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			if (Active && ConversionDepth == 0 && Frames.Count != 0 && source != null && Frames.Peek().Card == source && (int)target.GetTeamType() == 2)
			{
				int currentRoomIndex = target.GetCurrentRoomIndex();
				SpellResolution spellResolution = Frames.Peek();
				spellResolution.Healing[currentRoomIndex] = (spellResolution.Healing.TryGetValue(currentRoomIndex, out var value) ? (value + restored) : restored);
			}
		}

		internal static IEnumerator AfterSpell(SpellResolution frame)
		{
			yield return SpellRules.After(frame);
			if (frame.FirstDamage)
			{
				int amount = frame.Damage.Values.Sum();
				foreach (CharacterState unit in from u in AllAllies()
					where Is(u, "WW_U17")
					select u)
				{
					unit.SetAttackDamage(unit.GetAttackDamageWithoutStatusEffectBuffs() + amount);
					EndTurnActions.Add(delegate
					{
						if (!unit.IsDestroyed)
						{
							unit.SetAttackDamage(Math.Max(0, unit.GetAttackDamageWithoutStatusEffectBuffs() - amount));
						}
					});
				}
			}
			foreach (KeyValuePair<int, int> kill in frame.Kills)
			{
				if (kill.Value > 0)
				{
					yield return ArcaneSlayEvent.Dispatch(frame.Card, kill.Key, kill.Value);
				}
			}
			ConversionDepth++;
			try
			{
				if (frame.Indirect)
				{
					yield break;
				}
				foreach (KeyValuePair<int, int> pair in frame.Damage)
				{
					if (AcademicMath.FirstQualifyingSpell(SpellRules.OnceTurn, "U02Damage", pair.Key, pair.Value))
					{
						CharacterState[] array = (from u in Units(pair.Key, (Type)2)
							where Is(u, "WW_U02")
							select u).ToArray();
						for (int num = 0; num < array.Length; num++)
						{
							_ = array[num];
							yield return HealShared(pair.Key, pair.Value, frame.Card);
						}
					}
				}
			}
			finally
			{
				ConversionDepth--;
			}
		}

		internal static IEnumerator HealShared(int floor, int amount, CardState? source)
		{
			CharacterState[] array = Units(floor, (Type)2).ToArray();
			int healing = AcademicMath.SharedHealing(amount, array.Length);
			if (healing <= 0)
			{
				yield break;
			}
			CharacterState[] array2 = array;
			foreach (CharacterState val in array2)
			{
				if (!val.IsDestroyed && val.IsAlive)
				{
					yield return val.ApplyHeal(healing, true, source, (RelicState)null, false, (VfxAtLoc)null, 0);
				}
			}
		}

		internal static CardUpgradeState ModifyCard(CardState card, int power, int discount, bool thisTurn)
		{
			if (FixedCosts.TryGetValue(card, out var value) && discount != 0)
			{
				FixedCosts[card] = Math.Max(0, value - discount);
			}
			CardUpgradeState upgrade = PowerUpgrade(power, card.GetMagicPowerMultiplierFromTraits());
			upgrade.SetCostReduction(discount);
			CardStateModifiers mods = card.GetTemporaryCardStateModifiers();
			mods.AddUpgrade(upgrade, (CardStateModifiers)null);
			card.UpdateCardBodyText((SaveManager)null);
			if (thisTurn)
			{
				EndTurnActions.Add(delegate
				{
					mods.RemoveUpgrade(upgrade);
					if (FixedCosts.TryGetValue(card, out var value2))
					{
						FixedCosts[card] = Math.Max(0, value2 + discount);
					}
					card.UpdateCardBodyText((SaveManager)null);
				});
			}
			return upgrade;
		}

		internal static CardUpgradeState PowerUpgrade(int power, int multiplier = 1)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			CardUpgradeState val = new CardUpgradeState();
			val.Setup();
			if (power != 0)
			{
				CardUpgradeData val2 = ScriptableObject.CreateInstance<CardUpgradeData>();
				AccessTools.Field(typeof(CardUpgradeData), "bonusDamage").SetValue(val2, power);
				AccessTools.Field(typeof(CardUpgradeData), "bonusHeal").SetValue(val2, power);
				AccessTools.Field(typeof(CardUpgradeState), "sourceCardUpgradeData").SetValue(val, val2);
			}
			val.SetAttackDamage(power * multiplier);
			val.SetAdditionalHeal(power * multiplier);
			return val;
		}

		internal static void SetFixedCost(CardState card, int cost, bool thisTurn)
		{
			int old;
			bool previous = FixedCosts.TryGetValue(card, out old);
			FixedCosts[card] = cost;
			if (thisTurn)
			{
				EndTurnActions.Add(delegate
				{
					if (previous)
					{
						FixedCosts[card] = old;
					}
					else
					{
						FixedCosts.Remove(card);
					}
					card.UpdateCardBodyText((SaveManager)null);
				});
			}
			card.UpdateCardBodyText((SaveManager)null);
		}

		internal static void Trait(CardState card, string type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			CardTraitData val = new CardTraitData();
			val.Setup(type);
			Core.GetCardManager().AddTemporaryTraitToCard(card, val, true, false, true);
		}

		internal static IEnumerator ChooseHand(CardState? source, Func<CardState, bool> eligible, Action<CardState> picked)
		{
			return ChooseHand(source, eligible, (CardState c) => Complete(c, picked));
		}

		internal static IEnumerator ChooseHand(CardState? source, Func<CardState, bool> eligible, Func<CardState, IEnumerator> apply)
		{
			CardManager cardManager = Core.GetCardManager();
			if (cardManager.GetHand(false).Any((CardState c) => c != source && eligible(c)))
			{
				yield return cardManager.SelectCardFromHand(new Params
				{
					descriptionKey = "david.wwinc.ChooseCard",
					filterCallback = (FilterCardStateDelegate)((CardState c) => c == source || !eligible(c)),
					cardChosenCallback = (CardStateChosenDelegate)((CardState c, CardManager m) => ApplyChoice(c, source, eligible, apply, m)),
					disableIneligibleCards = true
				}, false);
			}
		}

		private static IEnumerator ApplyChoice(CardState card, CardState? source, Func<CardState, bool> eligible, Func<CardState, IEnumerator> apply, CardManager manager)
		{
			if (card != source && manager.GetHand(false).Contains(card) && eligible(card))
			{
				yield return apply(card);
			}
		}

		private static IEnumerator Complete(CardState card, Action<CardState> picked)
		{
			picked(card);
			yield break;
		}
	}
	internal static class AcademicTooltips
	{
		private static readonly HashSet<string> Cards = new HashSet<string>((from i in Enumerable.Range(1, 32)
			select "WW_S" + i.ToString("00")).Concat(new string[19]
		{
			"WW_C01", "WW_C02", "WW_E01", "WW_E02", "WW_R01", "WW_R02", "WW_U01", "WW_U02", "WW_U03", "WW_U04",
			"WW_U05", "WW_U06", "WW_U08", "WW_U10", "WW_U11", "WW_U13", "WW_U16", "WW_U17", "WW_U18"
		}));

		internal static bool TryCreate(CardState? card, CharacterState? unit, out TooltipContent content)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			content = default(TooltipContent);
			if (card == null)
			{
				return false;
			}
			string asset = AcademicRuntime.Id(card);
			if (!Cards.Any((string id) => asset.EndsWith(id, StringComparison.Ordinal)))
			{
				return false;
			}
			string overrideDescriptionKey = card.GetOverrideDescriptionKey();
			if (string.IsNullOrWhiteSpace(overrideDescriptionKey) || !LocalizationExtensions.HasTranslation(overrideDescriptionKey))
			{
				return false;
			}
			string text = LocalizationExtensions.Localize(overrideDescriptionKey, (ILocalizationParameterContext)new CardEffectLocalizationContext((ILocalizationEffectPower)(object)card, unit, (CardState)null, (IRoomStateModifier)null, (CharacterStatusEffectAdjustments)null));
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			content = new TooltipContent(card.GetTitle(), text, (TooltipDesignType)8, "david.wwinc.effect." + asset, false, false);
			return true;
		}

		internal static bool Reserved(CharacterState unit, out TooltipContent content)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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)
			content = default(TooltipContent);
			List<string> list = new List<string>();
			if (SpellRules.Archived.TryGetValue(unit, out List<CardState> value))
			{
				CardState[] array = value.ToArray();
				foreach (CardState val in array)
				{
					list.Add(val.GetTitle());
				}
			}
			if (list.Count == 0)
			{
				return false;
			}
			string text = ((list.Count == 0) ? LocalizationExtensions.Localize("david.wwinc.ReservedSpellsEmpty", (ILocalizationParameterContext)null) : string.Join("<br>", list));
			content = new TooltipContent(LocalizationExtensions.Localize("david.wwinc.ReservedSpellsTitle", (ILocalizationParameterContext)null), text, (TooltipDesignType)8, "david.wwinc.reserved", false, false);
			return true;
		}

		internal static IEnumerable<(TooltipContent content, bool allowDuplicates)> Append(IEnumerable<(TooltipContent content, bool allowDuplicates)> original, CharacterState unit)
		{
			HashSet<string> seen = new HashSet<string>();
			foreach (var item in original)
			{
				seen.Add(item.content.tooltipId);
				yield return item;
			}
			if (TryCreate(unit.GetSpawnerCard(), unit, out var content) && seen.Add(content.tooltipId))
			{
				yield return (content: content, allowDuplicates: false);
			}
			if (Reserved(unit, out var content2) && seen.Add(content2.tooltipId))
			{
				yield return (content: content2, allowDuplicates: false);
			}
		}
	}
	[HarmonyPatch(typeof(CardTooltipContainer), "AddTooltipsForCardState")]
	internal static class AcademicCardTooltipHook
	{
		private static void Postfix(CardTooltipContainer __instance, CardState cardState)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0025: 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 (AcademicTooltips.TryCreate(cardState, null, out var content))
			{
				TooltipUI obj = ((TooltipContainer)__instance).InstantiateTooltip(content.tooltipId, content.designType, false, false, false);
				if (obj != null)
				{
					obj.Set(content.title, content.body, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(CharacterTooltipHelper), "GetAdditionalTooltipContents")]
	internal static class AcademicCharacterTooltipHook
	{
		private static void Postfix(CharacterState characterState, ref IEnumerable<(TooltipContent content, bool allowDuplicates)> __result)
		{
			__result = AcademicTooltips.Append(__result, characterState);
		}
	}
	public sealed class CardEffectAcademicTome : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		private static bool Eligible(CardState card, CardEffectState effect, ICoreGameManagers managers)
		{
			CardUpgradeData paramCardUpgradeData = effect.GetParamCardUpgradeData();
			if (paramCardUpgradeData != null)
			{
				return paramCardUpgradeData.GetFilters().All((CardUpgradeMaskData filter) => filter.FilterCard<CardState>(card, managers.GetRelicManager()));
			}
			return false;
		}

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			return m.GetCardManager().GetHand(false).Any((CardState c) => c != p.playedCard && Eligible(c, s, m));
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			if (!m.GetSaveManager().PreviewMode)
			{
				AcademicRuntime.Core = m;
				yield return AcademicRuntime.ChooseHand(p.playedCard, (CardState c) => Eligible(c, s, m), delegate(CardState selected)
				{
					CardEffectAddTempCardUpgradeToCardsInHand.TryApplyUpgradeToCard(selected, false, s, p, m);
				});
			}
		}
	}
	public sealed class CardEffectAcademicReturnFrozen : AcademicEffectBase
	{
		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			return p.playedCard != null;
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			if (!m.GetSaveManager().PreviewMode && p.playedCard != null)
			{
				SpellRules.AddRule(p.playedCard, "return_frozen");
			}
			yield break;
		}

		internal static void ProtectUntilNextTurn(CardState card, CardManager manager)
		{
			if (!card.HasTrait(typeof(CardTraitFreeze)))
			{
				AcademicRuntime.Trait(card, "CardTraitFreeze");
			}
			if (!card.HasTrait(typeof(CardTraitUnplayable)))
			{
				AcademicRuntime.Trait(card, "CardTraitUnplayable");
				CardTraitState added = card.GetTemporaryCardStateModifiers().GetTemporaryTraits().Last((CardTraitState t) => t is CardTraitUnplayable);
				AcademicRuntime.NextTurnActions.Add(() => Unlock(card, added, manager));
			}
		}

		private static IEnumerator Unlock(CardState card, CardTraitState added, CardManager manager)
		{
			card.RemoveTemporaryTrait(added);
			card.UpdateCardBodyText((SaveManager)null);
			if (manager.GetHand(false).Contains(card))
			{
				manager.RefreshCardInHand(card, true, false, false);
			}
			yield break;
		}
	}
	internal static class ArcaneSlayEvent
	{
		internal sealed class Data : FireTriggersData
		{
			internal CardState Source;
		}

		private sealed class Context
		{
			internal CharacterState Unit;

			internal CardState Source;
		}

		private static readonly Stack<CardState> enqueuing = new Stack<CardState>();

		private static readonly Stack<Context> executing = new Stack<Context>();

		internal static CardState? EnqueuingSource
		{
			get
			{
				if (enqueuing.Count <= 0)
				{
					return null;
				}
				return enqueuing.Peek();
			}
		}

		internal static IEnumerator Dispatch(CardState source, int floor, int kills)
		{
			enqueuing.Push(source);
			try
			{
				yield return AcademicRuntime.Core.GetCombatManager().ApplyCharacterEffectsForRoom(AcademicRuntime.ArcaneSlay, floor, true, kills, (CharacterState)null);
			}
			finally
			{
				enqueuing.Pop();
			}
		}

		internal static IEnumerator Run(IEnumerator original, CharacterState unit, Data data)
		{
			executing.Push(new Context
			{
				Unit = unit,
				Source = data.Source
			});
			try
			{
				yield return original;
			}
			finally
			{
				executing.Pop();
			}
		}

		internal static CardState? Source(CardEffectParams p)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (executing.Count > 0 && (Object)(object)executing.Peek().Unit == (Object)(object)p.selfTarget)
			{
				CharacterTriggerState sourceCharacterTriggerState = p.sourceCharacterTriggerState;
				if (((sourceCharacterTriggerState != null) ? new Trigger?(sourceCharacterTriggerState.GetTrigger()) : ((Trigger?)null)) == (Trigger?)AcademicRuntime.ArcaneSlay)
				{
					return executing.Peek().Source;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(CombatManager), "QueueTrigger", new Type[]
	{
		typeof(CharacterState),
		typeof(Trigger),
		typeof(CharacterState),
		typeof(bool),
		typeof(bool),
		typeof(FireTriggersData),
		typeof(int),
		typeof(CharacterTriggerState)
	})]
	internal static class ArcaneSlayQueueHook
	{
		private static void Prefix(Trigger trigger, ref FireTriggersData fireTriggersData)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (trigger == AcademicRuntime.ArcaneSlay && fireTriggersData == null)
			{
				CardState enqueuingSource = ArcaneSlayEvent.EnqueuingSource;
				if (enqueuingSource != null)
				{
					fireTriggersData = (FireTriggersData)(object)new ArcaneSlayEvent.Data
					{
						Source = enqueuingSource
					};
				}
			}
		}
	}
	[HarmonyPatch(typeof(CharacterState), "FireTriggers")]
	internal static class ArcaneSlayTriggerHook
	{
		private static void Postfix(CharacterState __instance, Trigger trigger, FireTriggersData fireTriggersData, ref IEnumerator __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (trigger == AcademicRuntime.ArcaneSlay && fireTriggersData is ArcaneSlayEvent.Data data)
			{
				__result = ArcaneSlayEvent.Run(__result, __instance, data);
			}
		}
	}
	public sealed class CardEffectAcademicUpgradeSlayingSpell : AcademicEffectBase
	{
		public override bool CanPlayAfterBossDead => true;

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			return true;
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			if (!m.GetSaveManager().PreviewMode && !AcademicRuntime.Simulating)
			{
				CardState val = ArcaneSlayEvent.Source(p);
				if (val != null && (int)val.GetCardType() == 0 && !val.IsAnyAbility())
				{
					CardUpgradeState val2 = default(CardUpgradeState);
					CardUpgradeHelper.TryApplyUpgradeToCard(val, (CardState)null, s.GetParamCardUpgradeData(), false, p.isFromHiddenTrigger, m, ref val2);
					val.UpdateCardBodyText((SaveManager)null);
					m.GetCardManager().RefreshCardInHand(val, true, false, false);
				}
			}
			yield break;
		}
	}
	internal static class CateringRules
	{
		internal static CharacterData Stand;

		internal static CharacterData Serving;

		internal static bool IsStand(CharacterState unit)
		{
			return ((Object)unit.GetSourceCharacterData()).name.EndsWith("WW_Token_IceCreamStand", StringComparison.Ordinal);
		}

		internal static bool CanSpawn(ICoreGameManagers core, int floor, SpawnPoint? location, int size)
		{
			RoomState room = core.GetRoomManager().GetRoom(floor);
			if ((Object)(object)room != (Object)null && !room.GetIsPyreRoom() && room.IsRoomEnabled() && !room.IsRoomSummonBlocked(core.GetRelicManager()) && !room.WillBeAtCapacity((Type)2, size))
			{
				return core.GetMonsterManager().GetCanSpawnMonster(floor, location, size, false, false);
			}
			return false;
		}

		internal static IEnumerator BeginTurn()
		{
			if (!AcademicRuntime.Active || (Object)(object)Stand == (Object)null || (Object)(object)Serving == (Object)null)
			{
				yield break;
			}
			ICoreGameManagers core = AcademicRuntime.Core;
			SocialRules.RefreshAuras();
			core.GetRoomManager().UpdateEnchantments();
			foreach (int floor in SocialRules.FloorsBottomUp())
			{
				CharacterState[] array = SocialRules.VisualUnits(floor).Where(IsStand).ToArray();
				CharacterState[] array2 = array;
				foreach (CharacterState val in array2)
				{
					if (!val.IsDead && !val.IsDestroyed && val.GetCurrentRoomIndex() == floor && CanSpawn(core, floor, null, Serving.GetSize()))
					{
						long conduit = ((IEnumerable<CharacterState>)AcademicRuntime.Units(floor, (Type)2)).Sum((Func<CharacterState, long>)((CharacterState u) => Math.Max(0, u.GetStatusEffectStacks("conduit"))));
						(int attack, int health) stats = AcademicMath.ServingStats(conduit);
						CharacterState created = null;
						yield return core.GetMonsterManager().CreateMonsterState(Serving, (CardState)null, floor, (Action<CharacterState>)delegate(CharacterState u)
						{
							created = u;
						}, (SpawnMode)1, (SpawnPoint)null, (Action<CharacterState>)null, false, (CharacterData)null, (List<string>)null, (AddStatusEffectParams)null, true, (Action<CharacterState>)null, true, (CardState)null);
						if (!((Object)(object)created == (Object)null))
						{
							CardUpgradeState val2 = new CardUpgradeState();
							val2.Setup();
							val2.SetAttackDamage(stats.attack);
							val2.SetAdditionalHP(stats.health - Serving.GetHealth());
							yield return created.ApplyCardUpgrade(val2, false, "", true, false, (CardState)null, (Action<UpgradeApplicationResult>)null, (TrainRoomAttachmentState)null, false);
						}
					}
				}
			}
		}
	}
	public sealed class CardEffectAcademicCatering : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			int selectedRoom = p.selectedRoom;
			SpawnPoint dropLocation = p.dropLocation;
			CharacterData paramCharacterData = s.GetParamCharacterData();
			return CateringRules.CanSpawn(m, selectedRoom, dropLocation, (paramCharacterData == null) ? 1 : paramCharacterData.GetSize());
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			AcademicRuntime.Core = m;
			CharacterData paramCharacterData = s.GetParamCharacterData();
			if (!((Object)(object)paramCharacterData == (Object)null) && CateringRules.CanSpawn(m, p.selectedRoom, p.dropLocation, paramCharacterData.GetSize()))
			{
				yield return m.GetMonsterManager().CreateMonsterState(paramCharacterData, (CardState)null, p.selectedRoom, (Action<CharacterState>)delegate
				{
				}, (SpawnMode)((p.dropLocation == null) ? 1 : 3), p.dropLocation, (Action<CharacterState>)null, false, (CharacterData)null, (List<string>)null, (AddStatusEffectParams)null, true, (Action<CharacterState>)null, true, p.playedCard);
			}
		}
	}
	internal static class ChampionPathText
	{
		private static readonly string[] Prefixes = new string[2] { "WW_FratBro", "WW_QueenBee" };

		internal static IEnumerable<CardUpgradeState> Selected(CardState? card, CharacterState? unit = null)
		{
			if (card == null)
			{
				return Array.Empty<CardUpgradeState>();
			}
			string text = AcademicRuntime.Id(card);
			if (!text.EndsWith("WW_C01", StringComparison.Ordinal) && !text.EndsWith("WW_C02", StringComparison.Ordinal))
			{
				return Array.Empty<CardUpgradeState>();
			}
			List<CardUpgradeState> list = new List<CardUpgradeState>(card.GetCardStateModifiers().GetCardUpgrades());
			list.AddRange(card.GetTemporaryCardStateModifiers().GetCardUpgrades());
			if ((Object)(object)unit != (Object)null)
			{
				list.AddRange(unit.GetAppliedCardUpgrades());
			}
			List<CardUpgradeState> list2 = new List<CardUpgradeState>();
			string[] prefixes = Prefixes;
			foreach (string prefix in prefixes)
			{
				int rank = AcademicMath.ChampionRank(list.Select((CardUpgradeState u) => u.GetAssetName()), prefix);
				if (rank != 0)
				{
					CardUpgradeState val = ((IEnumerable<CardUpgradeState>)list).FirstOrDefault((Func<CardUpgradeState, bool>)((CardUpgradeState u) => u.GetAssetName().EndsWith(prefix + rank, StringComparison.Ordinal)));
					if (val != null && (Object)(object)val.GetSourceCardUpgradeData() != (Object)null)
					{
						list2.Add(val);
					}
				}
			}
			return list2;
		}

		internal static string Description(CardUpgradeState upgrade, CardState card)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			return LocalizationExtensions.Localize(upgrade.GetUpgradeDescriptionKey(), (ILocalizationParameterContext)new CardEffectLocalizationContext((ILocalizationEffectPower)(object)upgrade.GetSourceCardUpgradeData(), (CharacterState)null, card, (IRoomStateModifier)null, (CharacterStatusEffectAdjustments)null));
		}
	}
	[HarmonyPatch(typeof(CardState), "GenerateCardBodyText")]
	internal static class ChampionPathCardTextHook
	{
		private static void Postfix(CardState __instance, CharacterState associatedCharacterState, ref string generatedText)
		{
			foreach (CardUpgradeState item in ChampionPathText.Selected(__instance, associatedCharacterState))
			{
				string text = ChampionPathText.Description(item, __instance);
				if (!string.IsNullOrWhiteSpace(text))
				{
					generatedText = generatedText + (string.IsNullOrWhiteSpace(generatedText) ? "" : Environment.NewLine) + text;
				}
			}
		}
	}
	[HarmonyPatch(typeof(CharacterTooltipHelper), "GetAdditionalTooltipContents")]
	internal static class ChampionPathTooltipHook
	{
		private static void Postfix(CharacterState characterState, ref IEnumerable<(TooltipContent content, bool allowDuplicates)> __result)
		{
			__result = Append(__result, characterState);
		}

		private static IEnumerable<(TooltipContent content, bool allowDuplicates)> Append(IEnumerable<(TooltipContent content, bool allowDuplicates)> original, CharacterState unit)
		{
			HashSet<string> seen = new HashSet<string>();
			foreach (var item in original)
			{
				seen.Add(item.content.tooltipId);
				yield return item;
			}
			CardState card = ((unit != null) ? unit.GetSpawnerCard() : null);
			foreach (CardUpgradeState item2 in ChampionPathText.Selected(card, unit))
			{
				string text = "david.wwinc.path." + item2.GetAssetName();
				if (seen.Add(text))
				{
					yield return (content: new TooltipContent(item2.GetUpgradeTitle(), ChampionPathText.Description(item2, card), (TooltipDesignType)8, text, false, false), allowDuplicates: false);
				}
			}
		}
	}
	internal sealed class CollectionSnapshot
	{
		private readonly List<(FieldInfo field, object? value)> fields = new List<(FieldInfo, object)>();

		internal CollectionSnapshot(params Type[] owners)
		{
			for (int i = 0; i < owners.Length; i++)
			{
				FieldInfo[] array = owners[i].GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in array)
				{
					if (!fieldInfo.IsLiteral)
					{
						fields.Add((fieldInfo, Clone(fieldInfo.GetValue(null))));
					}
				}
			}
		}

		internal void Restore()
		{
			foreach (var field in fields)
			{
				if (!field.field.IsInitOnly)
				{
					field.field.SetValue(null, field.value);
				}
				else if (IsContainer(field.value))
				{
					Fill(field.field.GetValue(null), field.value);
				}
			}
		}

		private static bool IsContainer(object? value)
		{
			if (value == null)
			{
				return false;
			}
			Type type = value.GetType();
			if (type.IsGenericType)
			{
				return IEnumerableUtility.Contains<Type>((IReadOnlyList<Type>)new Type[4]
				{
					typeof(Dictionary<, >),
					typeof(List<>),
					typeof(HashSet<>),
					typeof(Stack<>)
				}, type.GetGenericTypeDefinition());
			}
			return false;
		}

		private static object? Clone(object? value)
		{
			if (!IsContainer(value))
			{
				return value;
			}
			object? obj = Activator.CreateInstance(value.GetType());
			Fill(obj, value);
			return obj;
		}

		private static void Fill(object target, object source)
		{
			target.GetType().GetMethod("Clear").Invoke(target, null);
			if (target is IDictionary dictionary)
			{
				{
					foreach (DictionaryEntry item in (IDictionary)source)
					{
						dictionary.Add(item.Key, Clone(item.Value));
					}
					return;
				}
			}
			IEnumerable<object> enumerable = ((IEnumerable)source).Cast<object>();
			bool flag = target.GetType().GetGenericTypeDefinition() == typeof(Stack<>);
			if (flag)
			{
				enumerable = enumerable.Reverse();
			}
			MethodInfo method = target.GetType().GetMethod(flag ? "Push" : "Add");
			foreach (object item2 in enumerable)
			{
				method.Invoke(target, new object[1] { Clone(item2) });
			}
		}
	}
	[HarmonyPatch(typeof(CardManager), "SetupCards")]
	internal static class BattleStartHook
	{
		private static void Postfix(CardManager __instance)
		{
			AcademicRuntime.Reset(__instance);
		}
	}
	[HarmonyPatch(typeof(CardManager), "DrawHand")]
	internal static class TurnStartHook
	{
		private static void Postfix(ref IEnumerator __result)
		{
			__result = Run(__result);
		}

		private static IEnumerator Run(IEnumerator original)
		{
			yield return AcademicRuntime.BeginTurn();
			yield return original;
		}
	}
	[HarmonyPatch(typeof(CombatManager), "RunEndMonsterTurn")]
	internal static class TurnEndHook
	{
		private static void Postfix(ref IEnumerator __result)
		{
			__result = Run(__result);
		}

		private static IEnumerator Run(IEnumerator original)
		{
			yield return original;
			AcademicRuntime.EndTurn();
		}
	}
	[HarmonyPatch]
	internal static class SpellResolutionHook
	{
		private static MethodBase TargetMethod()
		{
			return typeof(CombatManager).GetMethods().Single((MethodInfo m) => m.Name == "ApplyEffects" && m.GetParameters().FirstOrDefault()?.ParameterType == typeof(List<CardEffectState>));
		}

		private static void Postfix(CardState playedCard, int selectedRoom, bool fromPlayedCard, CharacterState selfTarget, SpawnPoint dropLocation, ref IEnumerator __result)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (playedCard != null && fromPlayedCard && !playedCard.IsUnitAbility() && (int)playedCard.GetCardType() == 0)
			{
				__result = Run(__result, playedCard, selectedRoom, ((dropLocation != null) ? dropLocation.GetCharacterState() : null) ?? selfTarget);
			}
		}

		private static IEnumerator Run(IEnumerator original, CardState card, int floor, CharacterState target)
		{
			if (!AcademicRuntime.Active)
			{
				yield return original;
				yield break;
			}
			AcademicRuntime.SpellResolution frame = new AcademicRuntime.SpellResolution
			{
				Card = card,
				Floor = floor,
				FirstDamage = (card.GetIsDamageCard() && AcademicRuntime.FirstDamageSpell == null),
				WasFrozen = card.HasTrait(typeof(CardTraitFreeze))
			};
			if ((Object)(object)target != (Object)null && AcademicRuntime.Is(target, "WW_U01") && card.GetEffectStates().Any((CardEffectState e) => ((Enum)e.GetTargetTeamType()).HasFlag((Enum)(object)(Type)1)) && AcademicRuntime.Units(floor, (Type)1).Count > 0)
			{
				int statusEffectStacks = target.GetStatusEffectStacks("dazed");
				frame.Redirected = true;
				if (statusEffectStacks > 0)
				{
					yield return AcademicRuntime.Core.GetCombatManager().ApplyDamageToTarget(AcademicMath.RedirectionDamage(statusEffectStacks), target, default(ApplyDamageToTargetParameters));
				}
				if (!target.IsDestroyed && !target.IsDead)
				{
					target.AddStatusEffect("dazed", 1, (CharacterState)null, true, false);
				}
				AcademicRuntime.Core.GetPlayerManager().AddEnergy(card.GetLastPlayedCost(), false);
				target = AcademicRuntime.Units(floor, (Type)1).FirstOrDefault();
			}
			try
			{
				yield return SpellRules.Before(frame, target);
				if (!frame.Indirect && (int)card.GetRarity() == 0)
				{
					AcademicRuntime.LastPlayedCommonSpell = card;
				}
				if (card.GetIsDamageCard())
				{
					AcademicRuntime.DamageSpellPlayed = true;
					if (AcademicRuntime.FirstDamageSpell == null)
					{
						AcademicRuntime.FirstDamageSpell = card;
					}
				}
				AcademicRuntime.Frames.Push(frame);
				try
				{
					yield return original;
				}
				finally
				{
					AcademicRuntime.Frames.Pop();
				}
				yield return AcademicRuntime.AfterSpell(frame);
			}
			finally
			{
				foreach (Action item in frame.Cleanup)
				{
					item();
				}
			}
		}
	}
	[HarmonyPatch(typeof(CharacterState), "ApplyHeal")]
	internal static class HealHook
	{
		private static void Postfix(CharacterState __instance, int amount, CardState responsibleCard, bool fromMaxHPChange, ref IEnumerator __result)
		{
			__result = Run(__result, __instance, amount, responsibleCard, fromMaxHPChange);
		}

		private static IEnumerator Run(IEnumerator original, CharacterState unit, int amount, CardState source, bool fromMaxHPChange)
		{
			int before = unit.GetHP();
			int healToTarget = unit.GetHealToTarget(amount, source, fromMaxHPChange, false);
			int excess = ((!fromMaxHPChange && amount < 9999) ? AcademicMath.ExcessHealing(healToTarget, before, unit.GetMaxHP()) : 0);
			yield return original;
			if (!unit.IsDestroyed && unit.IsAlive)
			{
				AcademicRuntime.RecordHeal(unit, Math.Max(0, unit.GetHP() - before), excess, source);
				yield return OverhealEvent.Dispatch(unit, excess, source);
			}
		}
	}
	public sealed class CardTraitAcademicConsumedDamage : CardTraitState
	{
		public override PropDescriptions CreateEditorInspectorDescriptions()
		{
			return PropDescriptions.DisplayNone;
		}

		public override int OnApplyingDamage(ApplyingDamageParameters damageParams, ICoreGameManagers coreGameManagers)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			StatValueData statValueData = ((CardTraitState)this).StatValueData;
			statValueData.forPreviewText = false;
			int statValue = coreGameManagers.GetCardStatistics().GetStatValue(statValueData);
			return AcademicMath.ConsumedDamage(damageParams.damage, ((CardTraitState)this).GetParamInt(), statValue);
		}
	}
	public sealed class StatusEffectAcademicDissertation : StatusEffectState
	{
	}
	internal static class DissertationMarker
	{
		internal static string StatusId;

		internal static void Refresh(CharacterState unit)
		{
			if (!unit.IsDestroyed)
			{
				List<(CardState, int)> value;
				int num = ((SpellRules.BoundAttacks.TryGetValue(unit, out value) && value.Count > 0) ? value.Max<(CardState, int)>(((CardState card, int attacks) binding) => binding.attacks) : 0);
				int statusEffectStacks = unit.GetStatusEffectStacks(StatusId);
				if (num > statusEffectStacks)
				{
					unit.AddStatusEffect(StatusId, num - statusEffectStacks, (CharacterState)null, false, false);
				}
				else if (statusEffectStacks > num)
				{
					unit.RemoveStatusEffect(StatusId, statusEffectStacks - num, false);
				}
			}
		}

		internal static string Details(CharacterState unit)
		{
			if (!SpellRules.BoundAttacks.TryGetValue(unit, out List<(CardState, int)> value))
			{
				return "";
			}
			return string.Join("<br>", value.Select<(CardState, int), string>(((CardState card, int attacks) binding) => binding.card.GetTitle() + " — " + string.Format(LocalizationExtensions.Localize("david.wwinc.ReservedAttacks", (ILocalizationParameterContext)null), binding.attacks) + " — " + DissertationTargeting.SideLabel(binding.card)));
		}
	}
	[HarmonyPatch(typeof(TooltipUI), "GetStatusEffectCharacterContent")]
	internal static class DissertationMarkerTooltipHook
	{
		private static void Postfix(StatusEffectState statusEffectState, CharacterState characterState, ref TooltipContent __result)
		{
			if (!(statusEffectState.GetStatusId() != DissertationMarker.StatusId))
			{
				string text = DissertationMarker.Details(characterState);
				if (!string.IsNullOrWhiteSpace(text))
				{
					ref string body = ref __result.body;
					body = body + "<br><br>" + text;
				}
			}
		}
	}
	internal enum DissertationIntent
	{
		Unknown,
		Beneficial,
		Harmful
	}
	internal enum DissertationSide
	{
		Choose,
		Allies,
		Enemies
	}
	internal static class DissertationPolicy
	{
		internal static DissertationSide Resolve(IEnumerable<DissertationIntent> flexibleEffects)
		{
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			foreach (DissertationIntent flexibleEffect in flexibleEffects)
			{
				flag = flag || flexibleEffect == DissertationIntent.Beneficial;
				flag2 = flag2 || flexibleEffect == DissertationIntent.Harmful;
				flag3 = flag3 || flexibleEffect == DissertationIntent.Unknown;
			}
			if (flag3 || (flag && flag2))
			{
				return DissertationSide.Choose;
			}
			if (!flag)
			{
				return DissertationSide.Enemies;
			}
			return DissertationSide.Allies;
		}
	}
	internal static class DissertationTargeting
	{
		internal sealed class Cast
		{
			internal CardState Card;

			internal CharacterState Owner;

			internal CharacterState Enemy;

			internal Type Side;
		}

		internal static CardData AllyChoice = null;

		internal static CardData EnemyChoice = null;

		internal static readonly Stack<Cast> Casts = new Stack<Cast>();

		internal static bool CanBind(CardState card)
		{
			return card.GetEffectStates().Any((CardEffectState e) => (e.GetTargetTeamType() & 3) != 0 || (int)e.GetTargetMode() == 5 || e.GetCardEffect() is CardEffectRewardGold);
		}

		internal static DissertationSide PreferredSide(CardState card)
		{
			return DissertationPolicy.Resolve((from e in card.GetEffectStates()
				where (int)e.GetTargetMode() == 12 && ((Enum)e.GetTargetTeamType()).HasFlag((Enum)(object)(Type)2) && ((Enum)e.GetTargetTeamType()).HasFlag((Enum)(object)(Type)1)
				select e).Select(Intent));
		}

		internal static DissertationIntent Intent(CardEffectState effect)
		{
			//IL_0077: 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_0086: Invalid comparison between Unknown and I4
			ICardEffect cardEffect = effect.GetCardEffect();
			if (cardEffect is CardEffectHealAndDamageRelative)
			{
				return DissertationIntent.Unknown;
			}
			if (cardEffect is CardEffectDamage)
			{
				return DissertationIntent.Harmful;
			}
			if (SpellRules.HealingEffect(effect) || cardEffect is CardEffectRewardGold)
			{
				return DissertationIntent.Beneficial;
			}
			if (cardEffect is CardEffectAddStatusEffect)
			{
				StatusEffectStackData[] paramStatusEffectStackData = effect.GetParamStatusEffectStackData();
				if (paramStatusEffectStackData.Length == 0)
				{
					return DissertationIntent.Unknown;
				}
				DissertationIntent dissertationIntent = DissertationIntent.Unknown;
				StatusEffectStackData[] array = paramStatusEffectStackData;
				foreach (StatusEffectStackData val in array)
				{
					StatusEffectData statusEffectDataById = StatusEffectManager.Instance.GetStatusEffectDataById(val.statusId, true);
					if (statusEffectDataById == null || val.count <= 0)
					{
						return DissertationIntent.Unknown;
					}
					DissertationIntent dissertationIntent2 = (((int)statusEffectDataById.GetDisplayCategory() == 0) ? DissertationIntent.Beneficial : (((int)statusEffectDataById.GetDisplayCategory() == 1) ? DissertationIntent.Harmful : DissertationIntent.Unknown));
					if (dissertationIntent2 == DissertationIntent.Unknown || (dissertationIntent != DissertationIntent.Unknown && dissertationIntent2 != dissertationIntent))
					{
						return DissertationIntent.Unknown;
					}
					dissertationIntent = dissertationIntent2;
				}
				return dissertationIntent;
			}
			if (cardEffect is CardEffectBuffDamage || cardEffect is CardEffectBuffMaxHealth)
			{
				if (effect.GetParamInt() <= 0)
				{
					if (effect.GetParamInt() >= 0)
					{
						return DissertationIntent.Unknown;
					}
					return DissertationIntent.Harmful;
				}
				return DissertationIntent.Beneficial;
			}
			if (cardEffect is CardEffectDebuffDamage || cardEffect is CardEffectDebuffMaxHealth)
			{
				return DissertationIntent.Harmful;
			}
			return DissertationIntent.Unknown;
		}

		internal static IEnumerator Bind(CardState selected, CharacterState owner, ICoreGameManagers core, ISystemManagers systems)
		{
			DissertationSide num = PreferredSide(selected);
			Type value = (Type)((num != DissertationSide.Allies) ? 1 : 2);
			if (num == DissertationSide.Choose)
			{
				CardState allies = new CardState(AllyChoice, core.GetSaveManager(), true, false);
				CardState enemies = new CardState(EnemyChoice, core.GetSaveManager(), true, false);
				CardState choice = null;
				yield return SpellRules.SelectPile(systems, (TargetMode)5, (CardState c) => c == allies || c == enemies, delegate(CardState c)
				{
					choice = c;
				}, cancel: false, new List<CardState> { allies, enemies }, "david.wwinc.DissertationChooseSide");
				if (choice == null)
				{
					yield break;
				}
				value = (Type)((choice != allies) ? 1 : 2);
			}
			if (!owner.IsDestroyed && !owner.IsDead && core.GetCardManager().GetHand(false).Contains(selected))
			{
				core.GetCardManager().MoveToStandByPile(selected, false, false, (RemoveFromStandByCondition)null, (DiscardCardParams)null, (DiscardEffect)0, false);
				SpellRules.ReservedCards.Add(selected);
				SpellRules.BoundSides[selected] = value;
				if (!SpellRules.BoundAttacks.TryGetValue(owner, out List<(CardState, int)> value2))
				{
					value2 = (SpellRules.BoundAttacks[owner] = new List<(CardState, int)>());
				}
				value2.Add((selected, 3));
				DissertationMarker.Refresh(owner);
			}
		}

		internal static string SideLabel(CardState card)
		{
			//IL_003d: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			Type value;
			Type val = ((card.GetEffectStates().Any((CardEffectState e) => (int)e.GetTargetMode() == 12 && ((Enum)e.GetTargetTeamType()).HasFlag((Enum)(object)(Type)2) && ((Enum)e.GetTargetTeamType()).HasFlag((Enum)(object)(Type)1)) && SpellRules.BoundSides.TryGetValue(card, out value)) ? value : card.GetTargetedTeamType((Type)0));
			if (((Enum)val).HasFlag((Enum)(object)(Type)2) && ((Enum)val).HasFlag((Enum)(object)(Type)1))
			{
				return LocalizationExtensions.Localize("david.wwinc.DissertationAllies", (ILocalizationParameterContext)null) + " / " + LocalizationExtensions.Localize("david.wwinc.DissertationEnemies", (ILocalizationParameterContext)null);
			}
			return LocalizationExtensions.Localize(((Enum)val).HasFlag((Enum)(object)(Type)1) ? "david.wwinc.DissertationEnemies" : "david.wwinc.DissertationAllies", (ILocalizationParameterContext)null);
		}

		internal static IEnumerator Repeat(CardState card, int floor, CharacterState owner, CharacterState enemy)
		{
			if (!owner.IsDestroyed && !owner.IsDead)
			{
				Type value;
				Cast cast = new Cast
				{
					Card = card,
					Owner = owner,
					Enemy = enemy,
					Side = (Type)((!SpellRules.BoundSides.TryGetValue(card, out value)) ? 1 : ((int)value))
				};
				CharacterState val = (((int)cast.Side == 2) ? owner : enemy);
				AcademicRuntime.SpellResolution frame = new AcademicRuntime.SpellResolution
				{
					Card = card,
					Floor = floor,
					Target = val,
					Indirect = true
				};
				int previous = SpellRules.EffectFloor;
				SpellRules.EffectFloor = floor;
				Casts.Push(cast);
				AcademicRuntime.Frames.Push(frame);
				try
				{
					yield return AcademicRuntime.Core.GetCombatManager().ApplyEffects(card.GetEffectStates(), floor, card, false, (RelicState)null, owner, (SpawnPoint)null, true, (ApplyPreEffectsVfxAction)null, (ApplyPreEffectsAction)null, (ApplyEffectsAction)null, false, (CharacterState)null, (CharacterState)null, 1, val, false, (CardTriggerType)2, (CharacterTriggerState)null, (CharacterState)null, (RoomState)null, false, false, (CharacterState)null);
				}
				finally
				{
					AcademicRuntime.Frames.Pop();
					Casts.Pop();
					SpellRules.EffectFloor = previous;
				}
				yield return AcademicRuntime.AfterSpell(frame);
			}
		}
	}
	[HarmonyPatch(typeof(TargetHelper), "CheckTargetsOverride")]
	internal static class DissertationTargetOverride
	{
		private static bool Prefix(CardEffectState effectState, List<CharacterState> targets, ref CharacterState overrideTargetCharacter)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Invalid comparison between Unknown and I4
			if (DissertationTargeting.Casts.Count == 0 || (int)effectState.GetTargetMode() != 12)
			{
				return true;
			}
			DissertationTargeting.Cast cast = DissertationTargeting.Casts.Peek();
			if (effectState.GetParentCardState() != cast.Card)
			{
				return true;
			}
			Type targetTeamType = effectState.GetTargetTeamType();
			bool flag = ((Enum)targetTeamType).HasFlag((Enum)(object)(Type)2);
			bool flag2 = ((Enum)targetTeamType).HasFlag((Enum)(object)(Type)1);
			overrideTargetCharacter = ((flag && (!flag2 || (int)cast.Side == 2)) ? cast.Owner : cast.Enemy);
			if (overrideTargetCharacter.IsDestroyed || overrideTargetCharacter.IsDead)
			{
				targets.Clear();
				return false;
			}
			return true;
		}
	}
	internal static class EducationPreview
	{
		internal sealed class Scope
		{
			private readonly CardState card;

			private readonly CardUpgradeState upgrade;

			private bool finished;

			internal Scope(CardState card, int power)
			{
				this.card = card;
				upgrade = AcademicRuntime.PowerUpgrade(power, card.GetMagicPowerMultiplierFromTraits());
				card.GetTemporaryCardStateModifiers().AddUpgrade(upgrade, (CardStateModifiers)null);
				TextDepth++;
			}

			internal void Finish()
			{
				if (finished)
				{
					return;
				}
				finished = true;
				try
				{
					card.GetTemporaryCardStateModifiers().RemoveUpgrade(upgrade);
				}
				finally
				{
					TextDepth--;
				}
			}
		}

		internal static int TextDepth;

		internal static int Power(CardState? card)
		{
			ICoreGameManagers core = AcademicRuntime.Core;
			if (core == null || AcademicRuntime.Simulating || TextDepth > 0 || card == null || !RoomPowerEligibility.Affected(card) || !core.GetCombatManager().IsPlayerActionPhase() || !core.GetCardManager().GetHand(false).Contains(card) || AcademicRuntime.Frames.Any((AcademicRuntime.SpellResolution frame) => frame.Card == card))
			{
				return 0;
			}
			int selectedRoom = core.GetRoomManager().GetSelectedRoom();
			if (selectedRoom >= 0 && !SpellRules.OnceTurn.Contains("FirstSpell:" + selectedRoom))
			{
				return SpellRules.EducationPowerOnFloor(selectedRoom);
			}
			return 0;
		}
	}
	[HarmonyPatch(typeof(CardState), "GetCardText", new Type[]
	{
		typeof(CardStatistics),
		typeof(SaveManager),
		typeof(bool)
	})]
	internal static class EducationTextHook
	{
		private static void Prefix(CardState __instance, ref bool includeCurrentTraitEffectText, out EducationPreview.Scope? __state)
		{
			__state = null;
			int num = EducationPreview.Power(__instance);
			if (num > 0)
			{
				__state = new EducationPreview.Scope(__instance, num);
				includeCurrentTraitEffectText = true;
			}
		}

		private static void Postfix(EducationPreview.Scope? __state)
		{
			__state?.Finish();
		}

		private static void Finalizer(EducationPreview.Scope? __state)
		{
			__state?.Finish();
		}
	}
	[HarmonyPatch(typeof(CardUI), "LateUpdate")]
	internal static class EducationRefreshHook
	{
		internal sealed class View
		{
			internal CardState? Card;

			internal int Power = -1;

			internal int Multiplier;

			internal string Language = "";
		}

		private static readonly ConditionalWeakTable<CardUI, View> views = new ConditionalWeakTable<CardUI, View>();

		private static void Postfix(CardUI __instance, CardStatistics ___currentCardStats)
		{
			CardState cardState = __instance.GetCardState();
			if (cardState != null && !((Object)(object)___currentCardStats == (Object)null) && RoomPowerEligibility.Affected(cardState))
			{
				int num = EducationPreview.Power(cardState);
				int magicPowerMultiplierFromTraits = cardState.GetMagicPowerMultiplierFromTraits();
				string text = LocalizationUtil.CurrentLanguage.ToString();
				View value = views.GetValue(__instance, (CardUI _) => new View());
				if (value.Card != cardState || value.Power != num || value.Multiplier != magicPowerMultiplierFromTraits || !(value.Language == text))
				{
					value.Card = cardState;
					value.Power = num;
					value.Multiplier = magicPowerMultiplierFromTraits;
					value.Language = text;
					__instance.UpdateTextContent(cardState, ___currentCardStats, false);
				}
			}
		}
	}
	internal static class ExcessCredit
	{
		internal static CardData Template = null;

		internal static readonly Dictionary<CardState, CardState> Origins = new Dictionary<CardState, CardState>();

		internal static bool IsCredit(CardState card)
		{
			return AcademicRuntime.Id(card).EndsWith("WW_Token_ExtraCredit", StringComparison.Ordinal);
		}

		internal static CharacterState? Owner(CardState? spell)
		{
			if (spell == null || !Origins.TryGetValue(spell, out CardState card))
			{
				return null;
			}
			return AcademicRuntime.AllAllies().FirstOrDefault((Func<CharacterState, bool>)((CharacterState u) => u.GetSpawnerCard() == card));
		}

		internal static void Generate(CharacterState attacker, int excess, int percent, CardUpgradeData? grantedUpgrade)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			if (!AcademicRuntime.Active || AcademicRuntime.Simulating || attacker.IsDestroyed || !attacker.IsAlive)
			{
				return;
			}
			int num = AcademicMath.ScaleOverdamage(excess, percent);
			CardState spawnerCard = attacker.GetSpawnerCard();
			if (num <= 0 || spawnerCard == null)
			{
				return;
			}
			CardManager cardManager = AcademicRuntime.Core.GetCardManager();
			CardState val = ((IEnumerable<CardState>)cardManager.GetHand(false)).FirstOrDefault((Func<CardState, bool>)IsCredit);
			if (val == null)
			{
				val = cardManager.AddNewCard(Template, (CardPile)((!cardManager.GetBelowHandSize()) ? 1 : 3), false, true, (AddCardUpgradingInfo)null, true);
			}
			if (val == null)
			{
				return;
			}
			if (!Origins.ContainsKey(val))
			{
				Origins[val] = spawnerCard;
			}
			CardStateModifiers cardStateModifiers = val.GetCardStateModifiers();
			if ((Object)(object)grantedUpgrade != (Object)null && !cardStateModifiers.HasUpgrade(((GameData)grantedUpgrade).GetID()))
			{
				CardUpgradeState val2 = new CardUpgradeState();
				val2.Setup(grantedUpgrade, false, false);
				val2.SetAvoidClobberingExistingTraits(true);
				if (CardUpgradeHelper.TryApplyUpgradeToCard(val, spawnerCard, val2, false, AcademicRuntime.Core))
				{
					val.ReapplyMagicPowerScalingFromTraitsToAllExistingUpgrades(AcademicRuntime.Core);
				}
			}
			long current = ((IEnumerable<int>)cardStateModifiers.GetAdditionalDamage()).Sum((Func<int, long>)((int value) => value));
			cardStateModifiers.IncrementAdditionalDamage(AcademicMath.CreditDamageIncrement(current, num));
			val.UpdateDamageText();
			val.UpdateCardBodyText((SaveManager)null);
			cardManager.RefreshCardInHand(val, true, false, false);
		}

		internal static void RewardHandOwner(CardState? spell, int kills, ICoreGameManagers core)
		{
			if (kills > 0 && !core.GetSaveManager().PreviewMode && spell != null && !((Object)(object)Owner(spell) != (Object)null) && Origins.TryGetValue(spell, out CardState value) && core.GetCardManager().GetHand(false).Contains(value))
			{
				CharacterData activeSavePyreCharacterData = core.GetSaveManager().GetActiveSavePyreCharacterData();
				if (!(((activeSavePyreCharacterData != null) ? ((Object)activeSavePyreCharacterData).name : null) != "PyreHeartSavagery"))
				{
					value.GetCardStateModifiers().IncrementAdditionalDamage(kills);
					value.UpdateDamageText();
					value.UpdateCardBodyText((SaveManager)null);
					core.GetCardManager().RefreshCardInHand(value, true, false, false);
				}
			}
		}
	}
	public sealed class CardEffectAcademicAuthoredDamage : CardEffectDamage
	{
		public override IEnumerator ApplyEffect(CardEffectState state, CardEffectParams parameters, ICoreGameManagers core, ISystemManagers systems)
		{
			CharacterState previous = parameters.selfTarget;
			CharacterState selfTarget = ExcessCredit.Owner(parameters.playedCard);
			CharacterState[] victims = parameters.targets.Where((CharacterState u) => !u.IsDestroyed && u.IsAlive && (int)u.GetTeamType() == 1).Distinct().ToArray();
			parameters.selfTarget = selfTarget;
			try
			{
				yield return <>n__0(state, parameters, core, systems);
			}
			finally
			{
				parameters.selfTarget = previous;
			}
			if (!core.GetSaveManager().PreviewMode && !AcademicRuntime.Simulating)
			{
				ExcessCredit.RewardHandOwner(parameters.playedCard, victims.Count((CharacterState u) => (u.IsDestroyed || u.IsDead) && !MineMineMine.Claimed.Contains(u)), core);
			}
		}

		[CompilerGenerated]
		[DebuggerHidden]
		private IEnumerator <>n__0(CardEffectState cardEffectState, CardEffectParams cardEffectParams, ICoreGameManagers coreGameManagers, ISystemManagers sysManagers)
		{
			return ((CardEffectDamage)this).ApplyEffect(cardEffectState, cardEffectParams, coreGameManagers, sysManagers);
		}
	}
	[HarmonyPatch(typeof(CardManager), "AddNewCardCopy")]
	internal static class ExcessCreditCopyHook
	{
		private static void Postfix(CardState sourceCardState, CardState __result)
		{
			if (!AcademicRuntime.Simulating && __result != null && ExcessCredit.Origins.TryGetValue(sourceCardState, out CardState value))
			{
				ExcessCredit.Origins[__result] = value;
			}
		}
	}
	internal sealed class ExcessCreditSave : ISaveData
	{
		[Serializable]
		public sealed class Entry
		{
			public int Spell;

			public int Owner;

			public string SpellData = "";

			public string OwnerData = "";
		}

		[Serializable]
		public sealed class Snapshot
		{
			public List<Entry> Entries = new List<Entry>();
		}

		public string Key => "extra-credit-origins";

		public bool ShouldSerialize()
		{
			if ((Object)(object)AllGameManagers.Instance != (Object)null)
			{
				return ExcessCredit.Origins.Count > 0;
			}
			return false;
		}

		public void Reset()
		{
			ExcessCredit.Origins.Clear();
		}

		public string Serialize()
		{
			List<CardState> deckState = (AllGameManagers.Instance ?? throw new InvalidOperationException("Game managers unavailable for Extra Credit persistence.")).GetCoreManagers().GetSaveManager().GetDeckState();
			Snapshot snapshot = new Snapshot();
			foreach (KeyValuePair<CardState, CardState> origin in ExcessCredit.Origins)
			{
				int num = deckState.IndexOf(origin.Key);
				int num2 = deckState.IndexOf(origin.Value);
				if (num >= 0 && num2 >= 0)
				{
					snapshot.Entries.Add(new Entry
					{
						Spell = num,
						Owner = num2,
						SpellData = origin.Key.GetCardDataID(),
						OwnerData = origin.Value.GetCardDataID()
					});
				}
			}
			return JsonUtility.ToJson((object)snapshot);
		}

		public void Deserialize(string payload)
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Invalid comparison between Unknown and I4
			Reset();
			Snapshot snapshot = JsonUtility.FromJson<Snapshot>(payload);
			if (snapshot?.Entries == null)
			{
				return;
			}
			List<CardState> deckState = (AllGameManagers.Instance ?? throw new InvalidOperationException("Game managers unavailable for Extra Credit persistence.")).GetCoreManagers().GetSaveManager().GetDeckState();
			foreach (Entry entry in snapshot.Entries)
			{
				if (entry.Spell >= 0 && entry.Spell < deckState.Count && entry.Owner >= 0 && entry.Owner < deckState.Count)
				{
					CardState val = deckState[entry.Spell];
					CardState val2 = deckState[entry.Owner];
					if (ExcessCredit.IsCredit(val) && !(val.GetCardDataID() != entry.SpellData) && !(val2.GetCardDataID() != entry.OwnerData) && (int)val2.GetCardType() == 1)
					{
						ExcessCredit.Origins[val] = val2;
					}
				}
			}
		}
	}
	public sealed class StatusEffectAcademicInsurance : StatusEffectState
	{
	}
	public sealed class CardEffectAcademicWizardDraw : AcademicEffectBase, ICardTargetingCardEffect, ICardEffectDrawsCards, ICardEffect
	{
		private readonly CardEffectDrawType nativeDraw = new CardEffectDrawType();

		internal static CardUpgradeData NextUseUpgrade;

		public override bool CanPlayAfterBossDead => false;

		public override bool CanApplyInPreviewMode => true;

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			CardManager cardManager = m.GetCardManager();
			CardUpgradeMaskData filter = s.GetParamCardFilter();
			if (!cardManager.GetDrawingDeckCardsDisabledThisTurn() && cardManager.GetBelowHandSize() && (Object)(object)filter != (Object)null)
			{
				return cardManager.GetDrawPile(false).Concat(cardManager.GetDiscardPile(false)).Any((CardState c) => c != p.playedCard && filter.FilterCard<CardState>(c, m.GetRelicManager()));
			}
			return false;
		}

		public int GetNumCardTargets(CardState card, CardEffectState effect, CardStatistics statistics)
		{
			return nativeDraw.GetNumCardTargets(card, effect, statistics);
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			if (!m.GetSaveManager().PreviewMode && ((CardEffectBase)this).TestEffect(s, p, m))
			{
				AcademicRuntime.Core = m;
				CardUpgradeState val = new CardUpgradeState();
				val.Setup(NextUseUpgrade, false, false);
				val.SetAvoidClobberingExistingTraits(true);
				m.GetCardManager().AddTempCardUpgradeToNextDrawnCard(val);
				yield return ((CardEffectBase)nativeDraw).ApplyEffect(s, p, m, systems);
			}
		}

		internal static int Rank(CharacterState? unit, string prefix)
		{
			if (!((Object)(object)unit == (Object)null))
			{
				return AcademicMath.ChampionRank(from u in ChampionPathText.Selected(unit.GetSpawnerCard(), unit)
					select u.GetAssetName(), prefix);
			}
			return 0;
		}
	}
	public sealed class CardEffectAcademicPurgePermit : AcademicEffectBase
	{
		private static readonly RingPermitLedger Permit = new RingPermitLedger();

		public override bool CanApplyInPreviewMode => true;

		internal static void BeginBattle(ICoreGameManagers core)
		{
			Permit.BeginBattle(Ring(core), SaveManager.IsInUndoModeStatic);
		}

		private static string Ring(ICoreGameManagers core)
		{
			return core.GetSaveManager().GetRunId() + ":" + core.GetSaveManager().GetRunState().GetLoopIndex() + ":" + core.GetSaveManager().GetRunState().GetCurrentDistance();
		}

		private static CardState? Equipment(CardEffectState effect, CardEffectParams parameters)
		{
			CardState? obj = effect.GetParentEquipment();
			if (obj == null)
			{
				CharacterState obj2 = parameters.characterThatActivatedAbility ?? parameters.selfTarget;
				if (obj2 == null)
				{
					return null;
				}
				obj = ((IEnumerable<CardState>)obj2.GetEquipment()).LastOrDefault((Func<CardState, bool>)((CardState card) => AcademicRuntime.Id(card).EndsWith("WW_E01", StringComparison.Ordinal)));
			}
			return obj;
		}

		private static bool Eligible(CardState card, CardEffectState effect, ICoreGameManagers managers, CardState equipment)
		{
			CardUpgradeMaskData paramCardFilter = effect.GetParamCardFilter();
			if (Permit.Available(Ring(managers), equipment) && (Object)(object)paramCardFilter != (Object)null)
			{
				return paramCardFilter.FilterCard<CardState>(card, managers.GetRelicManager());
			}
			return false;
		}

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			CardState equipment = Equipment(s, p);
			if (equipment != null)
			{
				return m.GetCardManager().GetHand(false).Any((CardState c) => c != p.playedCard && Eligible(c, s, m, equipment));
			}
			return false;
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			if (m.GetSaveManager().PreviewMode)
			{
				yield break;
			}
			AcademicRuntime.Core = m;
			CardState equipment = Equipment(s, p);
			if (equipment != null && ((CardEffectBase)this).TestEffect(s, p, m))
			{
				yield return AcademicRuntime.ChooseHand(p.playedCard, (CardState c) => Eligible(c, s, m, equipment), delegate(CardState card)
				{
					AcademicRuntime.Core = m;
					string key = Ring(m);
					AcademicRuntime.Trait(card, "CardTraitSelfPurge");
					Permit.MarkUsed(key, equipment);
				});
			}
		}
	}
	[HarmonyPatch(typeof(CharacterState), "GetAttackDamage")]
	internal static class ZeroAttackHook
	{
		private static void Postfix(CharacterState __instance, ref int __result)
		{
			if (AcademicRuntime.Active && AcademicRuntime.ZeroAttack.Contains(__instance))
			{
				__result = 0;
			}
		}
	}
	internal static class RedirectTargets
	{
		internal static List<CharacterState> InRoom(RoomState? room, Type team)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			List<CharacterState> list = new List<CharacterState>();
			if ((Object)(object)room != (Object)null)
			{
				room.AddCharactersToList(list, team, false, true);
			}
			return list.Where((CharacterState u) => !u.IsDead && !u.IsDestroyed).ToList();
		}
	}
	[HarmonyPatch]
	internal static class EligibleRedirectHook
	{
		private static MethodBase TargetMethod()
		{
			return typeof(TargetHelper).GetMethods().Single((MethodInfo m) => m.Name == "CollectTargets" && m.GetParameters()[0].ParameterType == typeof(CardEffectState));
		}

		private static void Postfix(CardEffectState effectState, CardEffectParams cardEffectParams, ICoreGameManagers coreGameManagers)
		{
			//IL_0025: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Invalid comparison between Unknown and I4
			CardState playedCard = cardEffectParams.playedCard;
			if (playedCard == null || playedCard.IsUnitAbility() || (int)playedCard.GetCardType() != 0 || (coreGameManagers.GetSaveManager().PreviewMode && !PreviewScope.Active))
			{
				return;
			}
			AcademicRuntime.Core = coreGameManagers;
			if (SpellRules.IsAreaEffect(playedCard, effectState))
			{
				cardEffectParams.targets.Clear();
				cardEffectParams.targets.AddRange(RedirectTargets.InRoom(coreGameManagers.GetRoomManager().GetRoom(cardEffectParams.selectedRoom), (Type)1));
			}
			else if (((Enum)effectState.GetTargetTeamType()).HasFlag((Enum)(object)(Type)1) && (int)effectState.GetTargetMode() == 12 && RedirectTargets.InRoom(coreGameManagers.GetRoomManager().GetRoom(cardEffectParams.selectedRoom), (Type)1).Count > 0)
			{
				cardEffectParams.targets.AddRange(from u in RedirectTargets.InRoom(coreGameManagers.GetRoomManager().GetRoom(cardEffectParams.selectedRoom), (Type)2)
					where AcademicRuntime.Is(u, "WW_U01") && !cardEffectParams.targets.Contains(u)
					select u);
			}
		}
	}
	[HarmonyPatch(typeof(TargetHelper), "CheckTargetsOverride")]
	internal static class RedirectTargetHook
	{
		private static bool Prefix(CardEffectState effectState, List<CharacterState> targets, SpawnPoint dropLocation, ref CharacterState overrideTargetCharacter)
		{
			//IL_005a: 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)
			CardState parentCardState = effectState.GetParentCardState();
			if (parentCardState == null || parentCardState.IsUnitAbility())
			{
				return true;
			}
			if (SpellRules.IsAreaEffect(parentCardState, effectState))
			{
				return false;
			}
			if (SpellRules.EffectFloor >= 0)
			{
				return true;
			}
			if (AcademicRuntime.Frames.Count > 0 && AcademicRuntime.Frames.Peek().Card == parentCardState && AcademicRuntime.Frames.Peek().Redirected && ((Enum)effectState.GetTargetTeamType()).HasFlag((Enum)(object)(Type)1))
			{
				overrideTargetCharacter = AcademicRuntime.Frames.Peek().Target;
				return true;
			}
			CharacterState val = ((dropLocation != null) ? dropLocation.GetCharacterState() : null);
			if ((Object)(object)val != (Object)null && AcademicRuntime.Is(val, "WW_U01") && ((Enum)effectState.GetTargetTeamType()).HasFlag((Enum)(object)(Type)1))
			{
				CharacterState val2 = RedirectTargets.InRoom(val.GetCurrentRoom(false), (Type)1).FirstOrDefault();
				if ((Object)(object)val2 != (Object)null)
				{
					overrideTargetCharacter = val2;
				}
			}
			return true;
		}
	}
	public sealed class CardEffectAcademicDiscardForEmber : AcademicEffectBase
	{
		public override bool CanApplyInPreviewMode => true;

		internal static bool Eligible(CardState card)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			CardType cardType = card.GetCardType();
			bool flag = (((int)cardType == 0 || cardType - 5 <= 1) ? true : false);
			if (flag && !card.HasTrait(typeof(CardTraitPersistent)))
			{
				return !card.HasTrait(typeof(CardTraitInfusion));
			}
			return false;
		}

		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			return m.GetCardManager().GetHand(false).Any((CardState c) => c != p.playedCard && Eligible(c));
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			if (!m.GetSaveManager().PreviewMode)
			{
				AcademicRuntime.Core = m;
				yield return AcademicRuntime.ChooseHand(p.playedCard, Eligible, (CardState card) => ResolveWithdrawal(card, p, m));
			}
		}

		private static IEnumerator ResolveWithdrawal(CardState card, CardEffectParams p, ICoreGameManagers m)
		{
			AcademicRuntime.Core = m;
			CardManager manager = m.GetCardManager();
			if (manager.GetHand(false).Contains(card) && Eligible(card))
			{
				int cost = (int)Math.Min(2147483647L, 2L * (long)Math.Max(0, SpellRules.Cost(card)));
				yield return manager.DiscardCard(new DiscardCardParams
				{
					discardCard = card,
					triggeredByCard = true,
					triggeredCard = p.playedCard,
					wasPlayed = false
				}, false);
				if (!manager.GetHand(false).Contains(card))
				{
					m.GetPlayerManager().AddEnergy(cost, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(CombatManager), "GetTargetCharacters")]
	internal static class RedirectUiHook
	{
		private static void Postfix(List<CharacterState> outCharacters, CardState cardState, RoomState room)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (cardState == null || (Object)(object)room == (Object)null || cardState.IsAnyAbility() || (int)cardState.GetCardType() != 0 || !cardState.GetEffectStates().Any((CardEffectState e) => ((Enum)e.GetTargetTeamType()).HasFlag((Enum)(object)(Type)1)) || RedirectTargets.InRoom(room, (Type)1).Count == 0)
			{
				return;
			}
			foreach (CharacterState item in from u in RedirectTargets.InRoom(room, (Type)2)
				where AcademicRuntime.Is(u, "WW_U01")
				select u)
			{
				if (!outCharacters.Contains(item))
				{
					outCharacters.Add(item);
				}
			}
		}
	}
	[HarmonyPatch(typeof(CardState), "GetCost")]
	internal static class FixedCostHook
	{
		private static bool Prefix(CardState __instance, ref int __result)
		{
			if (AcademicRuntime.Active && AcademicRuntime.FixedCosts.TryGetValue(__instance, out var value))
			{
				__result = value;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(CardState), "IsConsumeRemainingEnergyCostType")]
	internal static class FixedXCostHook
	{
		private static void Postfix(CardState __instance, ref bool __result)
		{
			if (AcademicRuntime.Active && AcademicRuntime.FixedCosts.ContainsKey(__instance))
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(CombatManager), "RunUnitTurn")]
	internal static class AttackSequenceHook
	{
		private static void Prefix(CharacterState attackerState, ref Action<int> perAttackVfxCallback, out List<CardState> __state)
		{
			__state = new List<CardState>();
			if (!AcademicRuntime.Active)
			{
				return;
			}
			List<CardState> seen = __state;
			Action<int> original = perAttackVfxCallback;
			perAttackVfxCallback = delegate(int index)
			{
				AcademicRuntime.BoundForAttack[attackerState] = new List<CardState>();
				if (SpellRules.BoundAttacks.TryGetValue(attackerState, out List<(CardState, int)> value))
				{
					(CardState, int)[] array = value.ToArray();
					for (int i = 0; i < array.Length; i++)
					{
						(CardState, int) item = array[i];
						AcademicRuntime.BoundForAttack[attackerState].Add(item.Item1);
						seen.Add(item.Item1);
						value.Remove(item);
						if (item.Item2 > 1)
						{
							value.Add((item.Item1, item.Item2 - 1));
						}
					}
					if (value.Count == 0)
					{
						SpellRules.BoundAttacks.Remove(attackerState);
					}
				}
				DissertationMarker.Refresh(attackerState);
				original?.Invoke(index);
			};
		}

		private static void Postfix(CharacterState attackerState, List<CardState> __state, ref IEnumerator __result)
		{
			__result = Run(__result, attackerState, __state);
		}

		private static IEnumerator Run(IEnumerator original, CharacterState unit, List<CardState> seen)
		{
			try
			{
				yield return original;
			}
			finally
			{
				AcademicRuntime.BoundForAttack.Remove(unit);
			}
			foreach (CardState item in seen.Distinct())
			{
				yield return SpellRules.ReleaseBoundSpell(item);
			}
		}
	}
	internal static class RedirectTeamScope
	{
		internal static readonly Stack<CardState> Cards = new Stack<CardState>();
	}
	[HarmonyPatch(typeof(CharacterTargetValidator), "IsValidTarget")]
	internal static class RedirectTeamValidationHook
	{
		private static void Prefix(CharacterTargetValidator __instance, RoomState selectedRoom, SpawnPointUI selectedSpawnPointUI, out bool __state)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			__state = false;
			CardState activeCard = ((TargetValidator)__instance).GetActiveCard();
			object obj;
			if (selectedSpawnPointUI == null)
			{
				obj = null;
			}
			else
			{
				SpawnPoint parentSpawnPoint = selectedSpawnPointUI.GetParentSpawnPoint();
				obj = ((parentSpawnPoint != null) ? parentSpawnPoint.GetCharacterState() : null);
			}
			CharacterState val = (CharacterState)obj;
			if (activeCard != null && !((Object)(object)selectedRoom == (Object)null) && !((Object)(object)val == (Object)null) && !val.IsDead && !val.IsDestroyed && !activeCard.IsAnyAbility() && (int)activeCard.GetCardType() == 0 && AcademicRuntime.Is(val, "WW_U01") && activeCard.GetEffectStates().Any((CardEffectState e) => ((Enum)e.GetTargetTeamType()).HasFlag((Enum)(object)(Type)1)) && RedirectTargets.InRoom(selectedRoom, (Type)1).Count != 0)
			{
				RedirectTeamScope.Cards.Push(activeCard);
				__state = true;
			}
		}

		private static void Finalizer(bool __state)
		{
			if (__state)
			{
				RedirectTeamScope.Cards.Pop();
			}
		}
	}
	[HarmonyPatch(typeof(CardState), "GetTargetedTeamType")]
	internal static class RedirectCardTeamHook
	{
		private static void Postfix(CardState __instance, ref Type __result)
		{
			if (RedirectTeamScope.Cards.Count > 0 && RedirectTeamScope.Cards.Peek() == __instance)
			{
				__result = (Type)((uint)__result | 2u);
			}
		}
	}
	public sealed class CardEffectAcademicCopyLastCommon : AcademicEffectBase
	{
		public override bool TestEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m)
		{
			CardState lastPlayedCommonSpell = AcademicRuntime.LastPlayedCommonSpell;
			if (lastPlayedCommonSpell != null && lastPlayedCommonSpell.CanBeCopied())
			{
				return m.GetCardManager().GetBelowHandSize();
			}
			return false;
		}

		public override IEnumerator ApplyEffect(CardEffectState s, CardEffectParams p, ICoreGameManagers m, ISystemManagers systems)
		{
			if (!m.GetSaveManager().PreviewMode)
			{
				AcademicRuntime.Core = m;
				CardState lastPlayedCommonSpell = AcademicRuntime.LastPlayedCommonSpell;
				if (lastPlayedCommonSpell != null)
				{
					SpellRules.CopyEphemeral(lastPlayedCommonSpell);
				}
			}
			yield break;
		}
	}
	[HarmonyPatch(typeof(MonsterManager), "RemoveCharacter")]
	internal static class DeathHook
	{
		private static void Prefix(CharacterState removeCharacter, bool death, ref bool vanishUnit)
		{
			if (AcademicRuntime.Active && death && ((Object)removeCharacter.GetSourceCharacterData()).name.Contains("WW_Token_"))
			{
				vanishUnit = true;
			}
		}

		private static void Postfix(CharacterState removeCharacter, bool death, ref IEnumerator __result)
		{
			if (AcademicRuntime.Active && death)
			{
				__result = Run(__result, removeCharacter);
			}
		}

		private static IEnumerator Run(IEnumerator original, CharacterState unit)
		{
			int floor = unit.GetCurrentRoomIndex();
			bool chaperone = SocialRules.Chaperone != null && unit.GetHasSubtype(SocialRules.Chaperone);
			List<CardState> value;
			CardState[] archived = (SpellRules.Archived.TryGetValue(unit, out value) ? value.ToArray() : Array.Empty<CardState>());
			List<(CardState, int)> value2;
			CardState[] bound = (SpellRules.BoundAttacks.TryGetValue(unit, out value2) ? value2.Select<(CardState, int), CardState>(((CardState card, int attacks) b) => b.card).ToArray() : Array.Empty<CardState>());
			if (AcademicRuntime.BoundForAttack.TryGetValue(unit, out List<CardState> value3))
			{
				bound = bound.Concat(value3).Distinct().ToArray();
			}
			yield return original;
			SpellRules.BoundAttacks.Remove(unit);
			CardState[] array = bound;
			foreach (CardState card in array)
			{
				yield return SpellRules.ReleaseBoundSpell(card);
			}
			if (!unit.IsDestroyed)
			{
				DissertationMarker.Refresh(unit);
			}
			if (!AcademicRuntime.Simulating && archived.Length != 0)
			{
				SpellRules.Archived.Remove(unit);
				array = archived;
				foreach (CardState card2 in array)
				{
					yield return SpellRules.Restore(card2, ephemeral: false, attuned: true, zero: true, attunedThisTurn: true);
				}
			}
			if (chaperone && SpellRules.HasRelic("WW_A08") && SpellRules.OnceTurn.Add("A08"))
			{
				foreach (CharacterState item in AcademicRuntime.Units(floor, (Type)2))
				{
					if (item.GetStatusEffectStacks("cooldown") > 0)
					{
						item.RemoveStatusEffect("cooldown", 1, true);
					}
				}
			}
			SocialRules.RefreshAuras();
		}
	}
	[HarmonyPatch(typeof(CharacterState), "GetUnitAbilityCooldown")]
	internal static class PlatonicCooldownHook
	{
		private static void Postfix(CharacterState __instance, ref int __result)
		{
			if (AcademicRuntime.Core == null || SocialRules.Wizard == null || __instance.IsDestroyed)
			{
				return;
			}
			RoomState currentRoom = __instance.GetCurrentRoom(false);
			if ((Object)(object)currentRoom == (Object)null || !currentRoom.GetRoomStateModifiersFromTrainRoomAttachments<RoomStateAcademicPlatonic>((Type)2).Any())
			{
				return;
			}
			List<CharacterState> list = AcademicRuntime.Units(currentRoom.GetRoomIndex(), (Type)2);
			for (int i = 0; i + 1 < list.Count; i++)
			{
				if (SocialRules.Mixed(list[i], list[i + 1]) && ((Object)(object)list[i] == (Object)(object)__instance || (Object)(object)list[i + 1] == (Object)(object)__instance))
				{
					__result = Math.Max(1, __result - 1);
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(CharacterState), "SetSpawnPoint")]
	internal static class AuraPositionHook
	{
		private static void Postfix()
		{
			SocialRules.RefreshAuras();
		}
	}
	[HarmonyPatch(typeof(CharacterState), "ApplyDamage")]
	internal static class UnitAttackHook
	{
		private static void Prefix(ref int damage, ApplyDamageParams damageParams)
		{
			//IL_0008: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (AcademicRuntime.Active && damageParams.damageSourceCard != null && (int)damageParams.damageType != 10 && SpellRules.DamageFactors.TryGetValue(damageParams.damageSourceCard, out var value))
			{
				damage = (int)Math.Floor((float)damage * value);
			}
		}

		private static void Postfix(CharacterState __instance, int damage, ApplyDamageParams damageParams, ref IEnumerator __result)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			__result = Run(__result, __instance, damage, damageParams);
		}

		private static IEnumerator Run(IEnumerator original, CharacterState target, int damage, ApplyDamageParams parameters)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (!AcademicRuntime.Active)
			{
				yield return original;
				yield break;
			}
			CharacterState attacker = parameters.attacker;
			bool direct = (int)parameters.damageType == 4;
			int hp = target.GetHP();
			int floor = target.GetCurrentRoomIndex();
			bool dead = target.IsDead;
			yield return original;
			AcademicRuntime.RecordDamage(target, Math.Max(0, hp - ((!target.IsDestroyed) ? target.GetHP() : 0)), !dead && (target.IsDead || target.IsDestroyed), parameters.damageSourceCard, attacker, floor);
			if ((Object)(object)attacker != (Object)null && direct)
			{
				List<CardState> list = new List<CardState>();
				List<CardState> completed = new List<CardState>();
				List<(CardState, int)> value2;
				if (AcademicRuntime.BoundForAttack.TryGetValue(attacker, out List<CardState> value))
				{
					list.AddRange(value);
				}
				else if (SpellRules.BoundAttacks.TryGetValue(attacker,