Decompiled source of Random Clan v0.1.0

plugins/Random_Clan.Plugin.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Configuration;
using Random_Clan.Plugin.Constants;
using Random_Clan.Plugin.Copying;
using Random_Clan.Plugin.Extensions;
using Random_Clan.Plugin.Modifications;
using Random_Clan.Plugin.Modifications.Cards;
using Random_Clan.Plugin.Modifications.Champions;
using Random_Clan.Plugin.Modifications.Rooms;
using Random_Clan.Plugin.Modifications.Units;
using Random_Clan.Plugin.Snapshots;
using SimpleInjector;
using TrainworksReloaded.Base;
using TrainworksReloaded.Base.Card;
using TrainworksReloaded.Base.CardUpgrade;
using TrainworksReloaded.Base.Class;
using TrainworksReloaded.Base.Prefab;
using TrainworksReloaded.Base.StatusEffects;
using TrainworksReloaded.Base.Trait;
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("Random_Clan.Plugin")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+373b3bd938ba4c0ac939d8fbaf9b57a04a82ed91")]
[assembly: AssemblyProduct("Random_Clan.Plugin")]
[assembly: AssemblyTitle("Random_Clan.Plugin")]
[assembly: AssemblyVersion("0.1.0.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 Random_Clan.Plugin
{
	public sealed class ClanRandomizer
	{
		private readonly struct DonorKey : IEquatable<DonorKey>
		{
			public CardType Type { get; }

			public CollectableRarity Rarity { get; }

			public bool Banner { get; }

			public DonorKey(CardType type, CollectableRarity rarity, bool banner)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				Type = type;
				Rarity = rarity;
				Banner = banner;
			}

			public bool Equals(DonorKey other)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//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_0017: Unknown result type (might be due to invalid IL or missing references)
				if (Type == other.Type && Rarity == other.Rarity)
				{
					return Banner == other.Banner;
				}
				return false;
			}

			public override bool Equals(object? obj)
			{
				if (obj is DonorKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Expected I4, but got Unknown
				return (Type * 397) ^ (Rarity * 397) ^ Banner;
			}
		}

		private sealed class DonorPools
		{
			public Dictionary<DonorKey, List<CardData>> ByKey { get; } = new Dictionary<DonorKey, List<CardData>>();

			public List<CardData> Starters { get; } = new List<CardData>();

			public List<CardData> Champions { get; } = new List<CardData>();
		}

		private readonly CardDataRegister _cards;

		private readonly CardTraitDataRegister _traits;

		private readonly ClassDataRegister _classes;

		private readonly CardUpgradeRegister _upgrades;

		private readonly StatusEffectDataRegister _statuses;

		private readonly CardPoolRegister _cardPools;

		private readonly GameDataClient _client;

		private readonly ModificationRegistry _modifications;

		private readonly CardDonorCopier _copier;

		private readonly Dictionary<string, CardSnapshot> _snapshots = new Dictionary<string, CardSnapshot>();

		private int _lastSeed = int.MinValue;

		public ClanRandomizer(CardDataRegister cards, CardTraitDataRegister traits, ClassDataRegister classes, CardUpgradeRegister upgrades, StatusEffectDataRegister statuses, CardPoolRegister cardPools, GameDataClient client, ModificationRegistry modifications, CardDonorCopier copier)
		{
			_cards = cards;
			_traits = traits;
			_classes = classes;
			_upgrades = upgrades;
			_statuses = statuses;
			_cardPools = cardPools;
			_client = client;
			_modifications = modifications;
			_copier = copier;
		}

		public void Randomize(SaveManager saveManager)
		{
			AllGameData allGameData = saveManager.GetAllGameData();
			if ((Object)(object)allGameData == (Object)null)
			{
				return;
			}
			if (_snapshots.Count == 0)
			{
				foreach (CardData allCardDatum in allGameData.GetAllCardData())
				{
					if (allCardDatum.HasRandomized())
					{
						_snapshots[((Object)allCardDatum).name] = CardSnapshot.Capture(allCardDatum);
					}
				}
				Plugin.Logger.LogInfo((object)$"Captured {_snapshots.Count} Randomized card snapshots.");
			}
			List<CardData> list = (from c in allGameData.GetAllCardData()
				where c.HasRandomized()
				select c).ToList();
			if (list.Count == 0)
			{
				return;
			}
			int num = ReadRunSeed(saveManager);
			if (num == _lastSeed)
			{
				return;
			}
			foreach (CardData item in list)
			{
				if (_snapshots.TryGetValue(((Object)item).name, out CardSnapshot value))
				{
					value.Restore(item);
				}
			}
			Random random = new Random(num);
			HashSet<CardData> starters = BuildStarterSet(allGameData);
			DonorPools donorPools = BuildDonorPools(allGameData, starters);
			List<CardUpgradeData> championUpgradePool = BuildChampionUpgradePool(allGameData);
			RandomizeContext randomizeContext = new RandomizeContext(saveManager, _cards, _traits, _classes, _upgrades, _statuses, _client)
			{
				ChampionUpgradePool = championUpgradePool
			};
			Plugin.Logger.LogInfo((object)($"Random Clan seed={num} slots={list.Count} starterDonors={donorPools.Starters.Count} " + $"spellDonors={donorPools.ByKey.Count<KeyValuePair<DonorKey, List<CardData>>>((KeyValuePair<DonorKey, List<CardData>> kv) => (int)kv.Key.Type == 0)} " + $"unitDonors={donorPools.ByKey.Count<KeyValuePair<DonorKey, List<CardData>>>((KeyValuePair<DonorKey, List<CardData>> kv) => (int)kv.Key.Type == 1)} " + $"roomDonors={donorPools.ByKey.Count<KeyValuePair<DonorKey, List<CardData>>>((KeyValuePair<DonorKey, List<CardData>> kv) => (int)kv.Key.Type == 8)} " + $"champDonors={donorPools.Champions.Count}"));
			foreach (CardData item2 in list)
			{
				List<CardTraitData> markerTraits = item2.GetMarkerTraits();
				List<CardData> list2 = SelectPool(item2, donorPools, starters);
				if (list2.Count == 0)
				{
					Plugin.Logger.LogWarning((object)("No donors for " + ((Object)item2).name + " (" + DescribeSlot(item2, starters) + ")"));
					continue;
				}
				CardData val = list2[random.Next(list2.Count)];
				Plugin.Logger.LogInfo((object)(((Object)item2).name + " <- " + ((Object)val).name + " [" + DescribeSlot(item2, starters) + "]"));
				_copier.CopyOnto(item2, val, markerTraits);
				randomizeContext.Character = item2.GetSpawnCharacterData();
				foreach (ICardModification item3 in _modifications.Pick(item2, randomizeContext, random, item2.GetModifierCount()))
				{
					item3.Modify(item2, randomizeContext, random);
					Plugin.Logger.LogInfo((object)("  mod " + item3.GetType().Name));
				}
			}
			_lastSeed = num;
			Plugin.Logger.LogInfo((object)"Random Clan randomization complete.");
		}

		private static string DescribeSlot(CardData slot, HashSet<CardData> starters)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			CardType cardTypeValue = slot.GetCardTypeValue();
			CollectableRarity rarityValue = slot.GetRarityValue();
			bool flag = starters.Contains(slot);
			bool flag2 = slot.IsBannerUnitCard();
			return $"{cardTypeValue}/{rarityValue}" + (flag ? "/starter" : "") + (flag2 ? "/banner" : "");
		}

		private static List<CardData> SelectPool(CardData slot, DonorPools donors, HashSet<CardData> starters)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			CardType cardTypeValue = slot.GetCardTypeValue();
			CollectableRarity rarityValue = slot.GetRarityValue();
			if ((int)cardTypeValue == 1 && (int)rarityValue == 3)
			{
				return donors.Champions;
			}
			if (starters.Contains(slot) || (int)rarityValue == 4)
			{
				return donors.Starters;
			}
			DonorKey key = new DonorKey(cardTypeValue, rarityValue, slot.IsBannerUnitCard());
			if (donors.ByKey.TryGetValue(key, out List<CardData> value) && value.Count > 0)
			{
				return value;
			}
			key = new DonorKey(cardTypeValue, rarityValue, !key.Banner);
			if (donors.ByKey.TryGetValue(key, out value) && value.Count > 0)
			{
				return value;
			}
			return new List<CardData>();
		}

		private HashSet<CardData> BuildStarterSet(AllGameData all)
		{
			HashSet<CardData> hashSet = new HashSet<CardData>();
			foreach (ClassData allClassData in all.GetAllClassDatas())
			{
				if (!(AccessTools.Field(typeof(ClassData), "champions")?.GetValue(allClassData) is List<ChampionData> list))
				{
					continue;
				}
				foreach (ChampionData item in list)
				{
					if ((Object)(object)item.starterCardData != (Object)null)
					{
						hashSet.Add(item.starterCardData);
					}
				}
			}
			if (((Dictionary<string, CardPool>)(object)_cardPools).TryGetValue("StarterCardsOnly", out CardPool value) && (Object)(object)value != (Object)null)
			{
				HashSet<CardData> hashSet2 = new HashSet<CardData>();
				value.CollectAllCards(hashSet2);
				foreach (CardData item2 in hashSet2)
				{
					hashSet.Add(item2);
				}
			}
			return hashSet;
		}

		private static DonorPools BuildDonorPools(AllGameData all, HashSet<CardData> starters)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Invalid comparison between Unknown and I4
			//IL_00a7: 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)
			DonorPools donorPools = new DonorPools();
			foreach (CardData allCardDatum in all.GetAllCardData())
			{
				if ((Object)(object)allCardDatum == (Object)null || allCardDatum.HasRandomized() || allCardDatum.IsUnitAbility() || allCardDatum.IsRoomAbility())
				{
					continue;
				}
				CardType cardTypeValue = allCardDatum.GetCardTypeValue();
				CollectableRarity rarityValue = allCardDatum.GetRarityValue();
				if (starters.Contains(allCardDatum) || (int)rarityValue == 4)
				{
					donorPools.Starters.Add(allCardDatum);
					continue;
				}
				CardType val = cardTypeValue;
				if ((int)val != 0)
				{
					if ((int)val == 1)
					{
						if ((int)rarityValue == 3)
						{
							donorPools.Champions.Add(allCardDatum);
						}
						else
						{
							Add(donorPools, new DonorKey(cardTypeValue, rarityValue, allCardDatum.IsBannerUnitCard()), allCardDatum);
						}
						continue;
					}
					if ((int)val != 8)
					{
						continue;
					}
				}
				Add(donorPools, new DonorKey(cardTypeValue, rarityValue, banner: false), allCardDatum);
			}
			return donorPools;
		}

		private static void Add(DonorPools pools, DonorKey key, CardData card)
		{
			if (!pools.ByKey.TryGetValue(key, out List<CardData> value))
			{
				value = new List<CardData>();
				pools.ByKey[key] = value;
			}
			value.Add(card);
		}

		private static List<CardUpgradeData> BuildChampionUpgradePool(AllGameData all)
		{
			List<CardUpgradeData> list = new List<CardUpgradeData>();
			foreach (ClassData allClassData in all.GetAllClassDatas())
			{
				if (!(AccessTools.Field(typeof(ClassData), "champions")?.GetValue(allClassData) is List<ChampionData> list2))
				{
					continue;
				}
				foreach (ChampionData item in list2)
				{
					if ((Object)(object)item.championCardData != (Object)null && item.championCardData.HasRandomized())
					{
						continue;
					}
					object? obj = AccessTools.Field(typeof(ChampionData), "upgradeTree")?.GetValue(item);
					CardUpgradeTreeData val = (CardUpgradeTreeData)((obj is CardUpgradeTreeData) ? obj : null);
					if ((Object)(object)val == (Object)null || !(AccessTools.Field(typeof(CardUpgradeTreeData), "upgradeTrees")?.GetValue(val) is List<UpgradeTree> list3))
					{
						continue;
					}
					foreach (UpgradeTree item2 in list3)
					{
						if (!(AccessTools.Field(typeof(UpgradeTree), "cardUpgrades")?.GetValue(item2) is List<CardUpgradeData> list4))
						{
							continue;
						}
						foreach (CardUpgradeData item3 in list4)
						{
							if ((Object)(object)item3 != (Object)null && !list.Contains(item3))
							{
								list.Add(item3);
							}
						}
					}
				}
			}
			return list;
		}

		private static int ReadRunSeed(SaveManager saveManager)
		{
			try
			{
				IReadonly startingConditions = saveManager.GetStartingConditions();
				if (startingConditions != null)
				{
					return startingConditions.Seed;
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("GetStartingConditions.Seed failed: " + ex.Message));
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(SaveManager), "forceSeed");
			if (fieldInfo?.FieldType == typeof(int))
			{
				int num = (int)fieldInfo.GetValue(saveManager);
				if (num != 0)
				{
					return num;
				}
			}
			Plugin.Logger.LogWarning((object)"Could not resolve run seed; using TickCount fallback.");
			return Environment.TickCount;
		}
	}
	[BepInPlugin("Random_Clan.Plugin", "Random_Clan.Plugin", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger = new ManualLogSource("Random_Clan.Plugin");

		internal static ClanRandomizer? ClanRandomizer { get; private set; }

		public void Awake()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BaseUnityPlugin)this).Logger;
			Railhead.GetBuilder().Configure("Random_Clan.Plugin", (Action<IConfigurationBuilder>)delegate(IConfigurationBuilder c)
			{
				ConfigurationExtensions.AddMergedJsonFile(c, new List<string>(46)
				{
					"json/global.json", "json/traits/markers.json", "json/clan/clan.json", "json/clan/clan_banner.json", "json/clan/clan_card_frame.json", "json/clan/clan_subtypes.json", "json/champions/basic_champion.json", "json/spells/champion_a_starter_card.json", "json/spells/basic_common_spell_card.json", "json/spells/errant_bolt.json",
					"json/spells/capricious_flare.json", "json/spells/whimfire.json", "json/spells/scattershot_curse.json", "json/spells/haphazard_jolt.json", "json/spells/dicebolt.json", "json/spells/luckless_brand.json", "json/spells/fickle_tempest.json", "json/spells/arbitrary_hex.json", "json/spells/roulette_lance.json", "json/spells/happenstance_wave.json",
					"json/spells/unfixed_blight.json", "json/spells/contingent_spark.json", "json/spells/chaos_cataclysm.json", "json/spells/entropic_nova.json", "json/spells/wild_decree.json", "json/spells/fortuitous_ruin.json", "json/units/basic_banner_unit.json", "json/units/roaming_shade.json", "json/units/errant_goblin.json", "json/units/wandering_brute.json",
					"json/units/unmoored_imp.json", "json/units/stray_hound.json", "json/units/basic_ability_unit.json", "json/units/rambling_colossus.json", "json/units/indeterminate_fiend.json", "json/units/wayward_grunt.json", "json/units/vagrant_tick.json", "json/units/basic_draft_unit.json", "json/units/loose_wisp.json", "json/units/mislaid_gremlin.json",
					"json/units/chance_larva.json", "json/units/arbitrary_horror.json", "json/units/stochastic_beast.json", "json/rooms/rooms.json", "json/equipment/basic_equipment.json", "json/enhancers/basic_enhancer.json"
				});
			});
			Railend.ConfigurePreAction((Action<Container>)RegisterServices);
			Railend.ConfigurePostAction((Action<Container>)ResolveServices);
			Logger.LogInfo((object)"Plugin Random_Clan.Plugin is loaded!");
			new Harmony("Random_Clan.Plugin").PatchAll();
		}

		private static void RegisterServices(Container container)
		{
			container.RegisterSingleton<ModificationRegistry>();
			container.RegisterSingleton<CardDonorCopier>();
			container.RegisterSingleton<ClanRandomizer>();
			Logger.LogInfo((object)"Registered Random Clan Railend services.");
		}

		private static void ResolveServices(Container container)
		{
			ClanRandomizer = container.GetInstance<ClanRandomizer>();
			Logger.LogInfo((object)"Resolved ClanRandomizer from Railend container.");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Random_Clan.Plugin";

		public const string PLUGIN_NAME = "Random_Clan.Plugin";

		public const string PLUGIN_VERSION = "0.1.0";
	}
}
namespace Random_Clan.Plugin.Snapshots
{
	internal sealed class CardSnapshot
	{
		private readonly int _cost;

		private readonly string? _nameKey;

		private readonly string? _descKey;

		private readonly object? _rarity;

		private readonly List<CardEffectData> _effects;

		private readonly List<CardTraitData> _traits;

		private readonly List<CardTriggerEffectData> _triggers;

		private readonly CharacterSnapshot? _character;

		private CardSnapshot(int cost, string? nameKey, string? descKey, object? rarity, List<CardEffectData> effects, List<CardTraitData> traits, List<CardTriggerEffectData> triggers, CharacterSnapshot? character)
		{
			_cost = cost;
			_nameKey = nameKey;
			_descKey = descKey;
			_rarity = rarity;
			_effects = effects;
			_traits = traits;
			_triggers = triggers;
			_character = character;
		}

		public static CardSnapshot Capture(CardData card)
		{
			List<CardEffectData> effects = (card.GetEffects() ?? new List<CardEffectData>()).Select(DataCloner.CloneEffect).ToList();
			List<CardTraitData> traits = (from t in card.GetTraitList()
				where t != null
				select t).ToList();
			List<CardTriggerEffectData> triggers = (from t in card.GetTriggerList()
				where t != null
				select t).Select(DataCloner.CloneCardTrigger).ToList();
			CharacterSnapshot character = null;
			CharacterData spawnCharacterData = card.GetSpawnCharacterData();
			if ((Object)(object)spawnCharacterData != (Object)null)
			{
				character = CharacterSnapshot.Capture(spawnCharacterData);
			}
			return new CardSnapshot(card.GetCostValue(), card.GetNameKey(), card.GetDescriptionKey(), card.GetRarityObject(), effects, traits, triggers, character);
		}

		public void Restore(CardData card)
		{
			card.SetCost(_cost);
			if (_nameKey != null)
			{
				card.SetNameKey(_nameKey);
			}
			if (_descKey != null)
			{
				card.SetDescriptionKey(_descKey);
			}
			if (_rarity != null)
			{
				card.SetRarityObject(_rarity);
			}
			card.SetEffects(_effects.Select(DataCloner.CloneEffect).ToList());
			card.SetTraits(new List<CardTraitData>(_traits));
			card.SetTriggers(_triggers.Select(DataCloner.CloneCardTrigger).ToList());
			CharacterData spawnCharacterData = card.GetSpawnCharacterData();
			if ((Object)(object)spawnCharacterData != (Object)null && _character != null)
			{
				_character.Restore(spawnCharacterData);
			}
		}
	}
	internal sealed class CharacterSnapshot
	{
		private readonly int _health;

		private readonly int _attack;

		private readonly int _size;

		private readonly List<string> _subtypes;

		private readonly List<CharacterTriggerData> _triggers;

		private readonly CardSnapshot? _ability;

		private CharacterSnapshot(int health, int attack, int size, List<string> subtypes, List<CharacterTriggerData> triggers, CardSnapshot? ability)
		{
			_health = health;
			_attack = attack;
			_size = size;
			_subtypes = subtypes;
			_triggers = triggers;
			_ability = ability;
		}

		public static CharacterSnapshot Capture(CharacterData character)
		{
			List<CharacterTriggerData> triggers = (from t in character.GetTriggerList()
				where t != null
				select t).Select(DataCloner.CloneCharacterTrigger).ToList();
			CardSnapshot ability = null;
			CardData unitAbilityCardData = character.GetUnitAbilityCardData();
			if ((Object)(object)unitAbilityCardData != (Object)null)
			{
				ability = CardSnapshot.Capture(unitAbilityCardData);
			}
			return new CharacterSnapshot(character.GetHealth(), character.GetAttackDamage(), character.GetSize(), new List<string>(character.GetSubtypeKeys()), triggers, ability);
		}

		public void Restore(CharacterData character)
		{
			character.SetHealth(_health);
			character.SetAttackDamage(_attack);
			character.SetSize(_size);
			character.SetSubtypeKeys(new List<string>(_subtypes));
			character.SetTriggers(_triggers.Select(DataCloner.CloneCharacterTrigger).ToList());
			CardData unitAbilityCardData = character.GetUnitAbilityCardData();
			if ((Object)(object)unitAbilityCardData != (Object)null && _ability != null)
			{
				_ability.Restore(unitAbilityCardData);
			}
		}
	}
}
namespace Random_Clan.Plugin.Patches
{
	[HarmonyPatch(typeof(SaveManager), "SetupRun")]
	internal static class SetupRunRandomizePatch
	{
		private static void Prefix(SaveManager __instance)
		{
			try
			{
				ClanRandomizer clanRandomizer = Plugin.ClanRandomizer;
				if (clanRandomizer == null)
				{
					Plugin.Logger.LogError((object)"ClanRandomizer was not resolved; skipping SetupRun randomize.");
				}
				else
				{
					clanRandomizer.Randomize(__instance);
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Random Clan SetupRun randomize failed: {arg}");
			}
		}
	}
}
namespace Random_Clan.Plugin.Modifications
{
	public interface ICardModification
	{
		bool CanModify(CardData card, RandomizeContext ctx);

		void Modify(CardData card, RandomizeContext ctx, Random rng);
	}
	public sealed class ModificationRegistry
	{
		private readonly List<ICardModification> _modifications = new List<ICardModification>();

		public IReadOnlyList<ICardModification> All => _modifications;

		public ModificationRegistry()
		{
			Register(new CostAdjustmentModification());
			Register(new NumberFixedModification());
			Register(new NumberScaledModification());
			Register(new CardStatusCountModification());
			Register(new CardStatusSwapModification());
			Register(new CardStatusInjectModification());
			Register(new CardTriggerTypeModification());
			Register(new TraitParamModification());
			Register(new TraitInjectModification());
			Register(new TraitRemoveModification());
			Register(new AbilityStatusCountModification());
			Register(new AbilityStatusSwapModification());
			Register(new StartingStatusCountModification());
			Register(new StartingStatusSwapModification());
			Register(new StartingStatusInjectModification());
			Register(new AbilitySwapModification());
			Register(new CharacterTriggerTypeModification());
			Register(new SubtypeAddModification());
			Register(new SubtypeRemoveModification());
			Register(new HealthFixedModification());
			Register(new HealthMultiplicativeModification());
			Register(new AttackFixedModification());
			Register(new AttackMultiplicativeModification());
			Register(new SizeFixedModification());
			Register(new RoomUpgradeNumberModification());
			Register(new ChampionUpgradeTreeModification());
		}

		public void Register(ICardModification modification)
		{
			_modifications.Add(modification);
		}

		public List<ICardModification> Pick(CardData card, RandomizeContext ctx, Random rng, int count)
		{
			if (count <= 0)
			{
				return new List<ICardModification>();
			}
			List<ICardModification> list = _modifications.Where((ICardModification m) => m.CanModify(card, ctx)).ToList();
			for (int num = list.Count - 1; num > 0; num--)
			{
				int num2 = rng.Next(num + 1);
				List<ICardModification> list2 = list;
				int index = num;
				List<ICardModification> list3 = list;
				int index2 = num2;
				ICardModification value = list[num2];
				ICardModification value2 = list[num];
				list2[index] = value;
				list3[index2] = value2;
			}
			return list.Take(count).ToList();
		}
	}
	public sealed class RandomizeContext
	{
		private IReadOnlyList<string>? _statusIds;

		private IReadOnlyList<CardTraitData>? _injectableTraits;

		private IReadOnlyList<CardData>? _abilityDonors;

		private IReadOnlyList<string>? _mutableSubtypeKeys;

		private IReadOnlyList<Trigger>? _swappableCharacterTriggers;

		private IReadOnlyList<CardTriggerType>? _swappableCardTriggers;

		public SaveManager SaveManager { get; }

		public CardDataRegister Cards { get; }

		public CardTraitDataRegister Traits { get; }

		public ClassDataRegister Classes { get; }

		public CardUpgradeRegister Upgrades { get; }

		public StatusEffectDataRegister Statuses { get; }

		public GameDataClient Client { get; }

		public CharacterData? Character { get; set; }

		public List<CardUpgradeData> ChampionUpgradePool { get; set; } = new List<CardUpgradeData>();

		public IReadOnlyList<string> StatusIds => _statusIds ?? (_statusIds = BuildSafeStatusIds());

		public IReadOnlyList<CardTraitData> InjectableTraits => _injectableTraits ?? (_injectableTraits = BuildInjectableTraits());

		public IReadOnlyList<CardData> AbilityDonors => _abilityDonors ?? (_abilityDonors = BuildAbilityDonors());

		public IReadOnlyList<string> MutableSubtypeKeys => _mutableSubtypeKeys ?? (_mutableSubtypeKeys = BuildMutableSubtypeKeys());

		public IReadOnlyList<Trigger> SwappableCharacterTriggers => _swappableCharacterTriggers ?? (_swappableCharacterTriggers = BuildSwappableCharacterTriggers());

		public IReadOnlyList<CardTriggerType> SwappableCardTriggers => _swappableCardTriggers ?? (_swappableCardTriggers = BuildSwappableCardTriggers());

		public RandomizeContext(SaveManager saveManager, CardDataRegister cards, CardTraitDataRegister traits, ClassDataRegister classes, CardUpgradeRegister upgrades, StatusEffectDataRegister statuses, GameDataClient client)
		{
			SaveManager = saveManager;
			Cards = cards;
			Traits = traits;
			Classes = classes;
			Upgrades = upgrades;
			Statuses = statuses;
			Client = client;
		}

		private IReadOnlyList<string> BuildSafeStatusIds()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Invalid comparison between Unknown and I4
			List<string> list = new List<string>();
			try
			{
				StatusEffectManager instance = StatusEffectManager.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					StatusEffectsData allStatusEffectsData = instance.GetAllStatusEffectsData();
					obj = ((allStatusEffectsData != null) ? allStatusEffectsData.GetStatusEffectData() : null);
				}
				List<StatusEffectData> list2 = (List<StatusEffectData>)obj;
				if (list2 == null)
				{
					return list;
				}
				foreach (StatusEffectData item in list2)
				{
					if (item != null && !item.IsHidden())
					{
						string statusId = item.GetStatusId();
						if (!string.IsNullOrEmpty(statusId) && !statusId.Equals("unit_ability", StringComparison.OrdinalIgnoreCase) && (int)item.GetDisplayCategory() != 3)
						{
							list.Add(statusId);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Failed building safe status ids: " + ex.Message));
			}
			return list;
		}

		private IReadOnlyList<CardTraitData> BuildInjectableTraits()
		{
			Dictionary<string, CardTraitData> dictionary = new Dictionary<string, CardTraitData>(StringComparer.Ordinal);
			AllGameData allGameData = SaveManager.GetAllGameData();
			if ((Object)(object)allGameData == (Object)null)
			{
				return Array.Empty<CardTraitData>();
			}
			foreach (CardData allCardDatum in allGameData.GetAllCardData())
			{
				if ((Object)(object)allCardDatum == (Object)null)
				{
					continue;
				}
				foreach (CardTraitData trait in allCardDatum.GetTraitList())
				{
					if (trait != null && !trait.IsMarkerTrait())
					{
						string text = trait.traitStateName ?? "";
						if (text.Length != 0 && !dictionary.ContainsKey(text))
						{
							dictionary[text] = trait;
						}
					}
				}
			}
			return dictionary.Values.ToList();
		}

		private IReadOnlyList<CardData> BuildAbilityDonors()
		{
			AllGameData allGameData = SaveManager.GetAllGameData();
			if ((Object)(object)allGameData == (Object)null)
			{
				return Array.Empty<CardData>();
			}
			Dictionary<string, CardData> dictionary = new Dictionary<string, CardData>(StringComparer.Ordinal);
			foreach (CardData allCardDatum in allGameData.GetAllCardData())
			{
				if (!((Object)(object)allCardDatum == (Object)null) && !allCardDatum.HasRandomized())
				{
					if (allCardDatum.IsUnitAbility() && !dictionary.ContainsKey(((Object)allCardDatum).name))
					{
						dictionary[((Object)allCardDatum).name] = allCardDatum;
					}
					CharacterData spawnCharacterData = allCardDatum.GetSpawnCharacterData();
					CardData val = ((spawnCharacterData != null) ? spawnCharacterData.GetUnitAbilityCardData() : null);
					if ((Object)(object)val != (Object)null && !dictionary.ContainsKey(((Object)val).name))
					{
						dictionary[((Object)val).name] = val;
					}
				}
			}
			return dictionary.Values.ToList();
		}

		private static IReadOnlyList<string> BuildMutableSubtypeKeys()
		{
			List<string> list = new List<string>();
			foreach (SubtypeData allDatum in SubtypeManager.AllData)
			{
				if (allDatum != null && !allDatum.IsNone && !allDatum.IsChampion)
				{
					string key = allDatum.Key;
					if (!string.IsNullOrEmpty(key) && !key.Contains("BannerUnit", StringComparison.OrdinalIgnoreCase))
					{
						list.Add(key);
					}
				}
			}
			return list;
		}

		private IReadOnlyList<Trigger> BuildSwappableCharacterTriggers()
		{
			//IL_007b: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Invalid comparison between Unknown and I4
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			HashSet<Trigger> hashSet = new HashSet<Trigger>();
			AllGameData allGameData = SaveManager.GetAllGameData();
			if ((Object)(object)allGameData == (Object)null)
			{
				return Array.Empty<Trigger>();
			}
			foreach (CardData allCardDatum in allGameData.GetAllCardData())
			{
				if ((Object)(object)allCardDatum == (Object)null || allCardDatum.HasRandomized())
				{
					continue;
				}
				CharacterData spawnCharacterData = allCardDatum.GetSpawnCharacterData();
				if ((Object)(object)spawnCharacterData == (Object)null)
				{
					continue;
				}
				foreach (CharacterTriggerData trigger2 in spawnCharacterData.GetTriggerList())
				{
					if (trigger2 != null)
					{
						Trigger trigger = trigger2.GetTrigger();
						if ((int)trigger != 48 && CharacterTriggerData.ShouldDisplayOnCharacter(trigger))
						{
							hashSet.Add(trigger);
						}
					}
				}
			}
			return hashSet.ToList();
		}

		private IReadOnlyList<CardTriggerType> BuildSwappableCardTriggers()
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			HashSet<CardTriggerType> hashSet = new HashSet<CardTriggerType>();
			AllGameData allGameData = SaveManager.GetAllGameData();
			if ((Object)(object)allGameData == (Object)null)
			{
				return Array.Empty<CardTriggerType>();
			}
			foreach (CardData allCardDatum in allGameData.GetAllCardData())
			{
				if ((Object)(object)allCardDatum == (Object)null || allCardDatum.HasRandomized())
				{
					continue;
				}
				foreach (CardTriggerEffectData trigger in allCardDatum.GetTriggerList())
				{
					if (trigger != null && AccessTools.Field(typeof(CardTriggerEffectData), "trigger")?.GetValue(trigger) is CardTriggerType item)
					{
						hashSet.Add(item);
					}
				}
			}
			return hashSet.ToList();
		}
	}
	internal static class StatusModificationHelper
	{
		public static bool HasCardStatusEntries(CardData card)
		{
			return CollectCardEntries(card).Count > 0;
		}

		public static bool HasStartingStatusEntries(CharacterData? character)
		{
			if ((Object)(object)character != (Object)null)
			{
				return character.GetStartingStatusEffectsArray().Length != 0;
			}
			return false;
		}

		public static bool TryAdjustSingleCardStatus(CardData card, Random rng, bool swap, IReadOnlyList<string>? statusIds = null)
		{
			List<(CardEffectData, StatusEffectStackData[], int)> list = CollectCardEntries(card);
			if (list.Count == 0)
			{
				return false;
			}
			var (effect, statuses, index) = list[rng.Next(list.Count)];
			if (!AdjustEntry(statuses, index, rng, swap, statusIds))
			{
				return false;
			}
			effect.SetStatusEffects(statuses);
			return true;
		}

		public static bool TryAdjustSingleStartingStatus(CharacterData character, Random rng, bool swap, IReadOnlyList<string>? statusIds = null)
		{
			StatusEffectStackData[] startingStatusEffectsArray = character.GetStartingStatusEffectsArray();
			if (startingStatusEffectsArray.Length == 0)
			{
				return false;
			}
			int index = rng.Next(startingStatusEffectsArray.Length);
			if (!AdjustEntry(startingStatusEffectsArray, index, rng, swap, statusIds))
			{
				return false;
			}
			character.SetStartingStatusEffectsArray(startingStatusEffectsArray);
			return true;
		}

		private static List<(CardEffectData Effect, StatusEffectStackData[] Statuses, int Index)> CollectCardEntries(CardData card)
		{
			List<(CardEffectData, StatusEffectStackData[], int)> list = new List<(CardEffectData, StatusEffectStackData[], int)>();
			List<CardEffectData> effects = card.GetEffects();
			if (effects == null)
			{
				return list;
			}
			foreach (CardEffectData item in effects)
			{
				if (item == null)
				{
					continue;
				}
				StatusEffectStackData[] statusEffects = item.GetStatusEffects();
				if (statusEffects != null && statusEffects.Length != 0)
				{
					for (int i = 0; i < statusEffects.Length; i++)
					{
						list.Add((item, statusEffects, i));
					}
				}
			}
			return list;
		}

		private static bool AdjustEntry(StatusEffectStackData[] statuses, int index, Random rng, bool swap, IReadOnlyList<string>? statusIds)
		{
			if (swap)
			{
				if (statusIds == null || statusIds.Count < 2)
				{
					return false;
				}
				string text = statuses[index].statusId.TrySwapStatus(rng, statusIds);
				if (text == null)
				{
					return false;
				}
				statuses[index].statusId = text;
				return true;
			}
			statuses[index].count = Math.Max(1, Math.Max(1, statuses[index].count).MutateBalanced(rng));
			return true;
		}
	}
}
namespace Random_Clan.Plugin.Modifications.Units
{
	public sealed class AbilityStatusCountModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			CharacterData? character = ctx.Character;
			object obj = ((character != null) ? character.GetUnitAbilityCardData() : null);
			if (obj == null)
			{
				CharacterData spawnCharacterData = card.GetSpawnCharacterData();
				obj = ((spawnCharacterData != null) ? spawnCharacterData.GetUnitAbilityCardData() : null);
			}
			CardData val = (CardData)obj;
			if ((Object)(object)val != (Object)null)
			{
				return StatusModificationHelper.HasCardStatusEntries(val);
			}
			return false;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData? character = ctx.Character;
			object obj = ((character != null) ? character.GetUnitAbilityCardData() : null);
			if (obj == null)
			{
				CharacterData spawnCharacterData = card.GetSpawnCharacterData();
				obj = ((spawnCharacterData != null) ? spawnCharacterData.GetUnitAbilityCardData() : null);
			}
			CardData val = (CardData)obj;
			if ((Object)(object)val != (Object)null)
			{
				StatusModificationHelper.TryAdjustSingleCardStatus(val, rng, swap: false);
			}
		}
	}
	public sealed class AbilityStatusSwapModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			if (ctx.StatusIds.Count <= 1)
			{
				return false;
			}
			CharacterData? character = ctx.Character;
			object obj = ((character != null) ? character.GetUnitAbilityCardData() : null);
			if (obj == null)
			{
				CharacterData spawnCharacterData = card.GetSpawnCharacterData();
				obj = ((spawnCharacterData != null) ? spawnCharacterData.GetUnitAbilityCardData() : null);
			}
			CardData val = (CardData)obj;
			if ((Object)(object)val != (Object)null)
			{
				return StatusModificationHelper.HasCardStatusEntries(val);
			}
			return false;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData? character = ctx.Character;
			object obj = ((character != null) ? character.GetUnitAbilityCardData() : null);
			if (obj == null)
			{
				CharacterData spawnCharacterData = card.GetSpawnCharacterData();
				obj = ((spawnCharacterData != null) ? spawnCharacterData.GetUnitAbilityCardData() : null);
			}
			CardData val = (CardData)obj;
			if ((Object)(object)val != (Object)null)
			{
				StatusModificationHelper.TryAdjustSingleCardStatus(val, rng, swap: true, ctx.StatusIds);
			}
		}
	}
	public sealed class AbilitySwapModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if ((Object)(object)val == (Object)null || (Object)(object)val.GetUnitAbilityCardData() == (Object)null)
			{
				return false;
			}
			return ctx.AbilityDonors.Count > 0;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if (!((Object)(object)val == (Object)null) && ctx.AbilityDonors.Count != 0)
			{
				CardData unitAbilityCardData = val.GetUnitAbilityCardData();
				int num = 0;
				CardData val2;
				do
				{
					val2 = ctx.AbilityDonors[rng.Next(ctx.AbilityDonors.Count)];
					num++;
				}
				while ((Object)(object)unitAbilityCardData != (Object)null && ((Object)val2).name == ((Object)unitAbilityCardData).name && ctx.AbilityDonors.Count > 1 && num < 8);
				CardData ability = CardDonorCopier.CloneAbilityCard(val2, ((Object)card).name + "_AbilitySwap");
				val.SetUnitAbility(ability);
			}
		}
	}
	public sealed class AttackFixedModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return (Object)(object)(ctx.Character ?? card.GetSpawnCharacterData()) != (Object)null;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if (!((Object)(object)val == (Object)null))
			{
				val.SetAttackDamage(Math.Max(1, val.GetAttackDamage()).MutateFixed(rng));
			}
		}
	}
	public sealed class AttackMultiplicativeModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return (Object)(object)(ctx.Character ?? card.GetSpawnCharacterData()) != (Object)null;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if (!((Object)(object)val == (Object)null))
			{
				val.SetAttackDamage(Math.Max(1, val.GetAttackDamage()).MutateScaled(rng));
			}
		}
	}
	public sealed class CharacterTriggerTypeModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			if (ctx.SwappableCharacterTriggers.Count < 2)
			{
				return false;
			}
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if ((Object)(object)val != (Object)null)
			{
				return val.GetTriggerList().Count > 0;
			}
			return false;
		}

		public unsafe void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if ((Object)(object)val == (Object)null || ctx.SwappableCharacterTriggers.Count < 2)
			{
				return;
			}
			List<CharacterTriggerData> triggerList = val.GetTriggerList();
			if (triggerList.Count == 0)
			{
				return;
			}
			CharacterTriggerData obj = triggerList[rng.Next(triggerList.Count)];
			FieldInfo fieldInfo = AccessTools.Field(typeof(CharacterTriggerData), "trigger");
			if (!(fieldInfo == null))
			{
				Trigger val2 = (Trigger)fieldInfo.GetValue(obj);
				IReadOnlyList<Trigger> swappableCharacterTriggers = ctx.SwappableCharacterTriggers;
				int num = 0;
				Trigger val3;
				do
				{
					val3 = swappableCharacterTriggers[rng.Next(swappableCharacterTriggers.Count)];
					num++;
				}
				while (((object)(*(Trigger*)(&val3))/*cast due to .constrained prefix*/).Equals((object?)val2) && num < 8);
				fieldInfo.SetValue(obj, val3);
			}
		}
	}
	public sealed class HealthFixedModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return (Object)(object)(ctx.Character ?? card.GetSpawnCharacterData()) != (Object)null;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if (!((Object)(object)val == (Object)null))
			{
				val.SetHealth(Math.Max(1, val.GetHealth()).MutateFixed(rng));
			}
		}
	}
	public sealed class HealthMultiplicativeModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return (Object)(object)(ctx.Character ?? card.GetSpawnCharacterData()) != (Object)null;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if (!((Object)(object)val == (Object)null))
			{
				val.SetHealth(Math.Max(1, val.GetHealth()).MutateScaled(rng));
			}
		}
	}
	public sealed class SizeFixedModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return (Object)(object)(ctx.Character ?? card.GetSpawnCharacterData()) != (Object)null;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if (!((Object)(object)val == (Object)null))
			{
				int value = val.GetSize() + ModificationTuning.SizeSteps[rng.Next(ModificationTuning.SizeSteps.Length)];
				val.SetSize(Math.Clamp(value, 1, 6));
			}
		}
	}
	public sealed class StartingStatusCountModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return StatusModificationHelper.HasStartingStatusEntries(ctx.Character ?? card.GetSpawnCharacterData());
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if ((Object)(object)val != (Object)null)
			{
				StatusModificationHelper.TryAdjustSingleStartingStatus(val, rng, swap: false);
			}
		}
	}
	public sealed class StartingStatusInjectModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			if (ctx.StatusIds.Count > 0)
			{
				return (Object)(object)(ctx.Character ?? card.GetSpawnCharacterData()) != (Object)null;
			}
			return false;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			//IL_0052: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if (!((Object)(object)val == (Object)null) && ctx.StatusIds.Count != 0)
			{
				StatusEffectStackData[] startingStatusEffectsArray = val.GetStartingStatusEffectsArray();
				StatusEffectStackData[] array = (StatusEffectStackData[])(object)new StatusEffectStackData[startingStatusEffectsArray.Length + 1];
				for (int i = 0; i < startingStatusEffectsArray.Length; i++)
				{
					array[i] = startingStatusEffectsArray[i];
				}
				array[startingStatusEffectsArray.Length] = new StatusEffectStackData
				{
					statusId = ctx.StatusIds[rng.Next(ctx.StatusIds.Count)],
					count = Math.Max(1, 1.MutateBalanced(rng))
				};
				val.SetStartingStatusEffectsArray(array);
			}
		}
	}
	public sealed class StartingStatusSwapModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			if (ctx.StatusIds.Count > 1)
			{
				return StatusModificationHelper.HasStartingStatusEntries(ctx.Character ?? card.GetSpawnCharacterData());
			}
			return false;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if ((Object)(object)val != (Object)null)
			{
				StatusModificationHelper.TryAdjustSingleStartingStatus(val, rng, swap: true, ctx.StatusIds);
			}
		}
	}
	public sealed class SubtypeAddModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if ((Object)(object)val == (Object)null || ctx.MutableSubtypeKeys.Count == 0)
			{
				return false;
			}
			List<string> existing = val.GetSubtypeKeys();
			return ctx.MutableSubtypeKeys.Any((string key) => !existing.Contains(key));
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if (!((Object)(object)val == (Object)null))
			{
				List<string> existing = val.GetSubtypeKeys();
				List<string> list = ctx.MutableSubtypeKeys.Where((string key) => !existing.Contains(key)).ToList();
				if (list.Count != 0)
				{
					List<string> subtypes = new List<string>(existing) { list[rng.Next(list.Count)] };
					val.SetSubtypeKeys(subtypes);
				}
			}
		}
	}
	public sealed class SubtypeRemoveModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			return val.GetSubtypeKeys().Any(IsRemovable);
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			CharacterData val = ctx.Character ?? card.GetSpawnCharacterData();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			List<string> subtypeKeys = val.GetSubtypeKeys();
			List<string> list = subtypeKeys.Where(IsRemovable).ToList();
			if (list.Count != 0)
			{
				string remove = list[rng.Next(list.Count)];
				val.SetSubtypeKeys(subtypeKeys.Where((string s) => s != remove).ToList());
			}
		}

		private static bool IsRemovable(string key)
		{
			if (!key.Contains("BannerUnit", StringComparison.OrdinalIgnoreCase))
			{
				return !key.Contains("Champion", StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}
	}
}
namespace Random_Clan.Plugin.Modifications.Rooms
{
	public sealed class RoomUpgradeNumberModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)card.GetCardTypeValue() != 8)
			{
				return false;
			}
			return card.GetEffects()?.Any((CardEffectData e) => e != null && (Object)(object)e.GetCardUpgrade() != (Object)null) ?? false;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			List<CardEffectData> effects = card.GetEffects();
			if (effects == null)
			{
				return;
			}
			foreach (CardEffectData item in effects)
			{
				if (item == null)
				{
					continue;
				}
				CardUpgradeData cardUpgrade = item.GetCardUpgrade();
				if ((Object)(object)cardUpgrade == (Object)null)
				{
					continue;
				}
				CardUpgradeData val = Object.Instantiate<CardUpgradeData>(cardUpgrade);
				item.SetCardUpgrade(val);
				int bonusDamage = val.GetBonusDamage();
				int bonusHP = val.GetBonusHP();
				if (bonusDamage != 0)
				{
					AccessTools.Field(typeof(CardUpgradeData), "bonusDamage")?.SetValue(val, Math.Abs(bonusDamage).MutateBalanced(rng) * Math.Sign(bonusDamage));
				}
				if (bonusHP != 0)
				{
					AccessTools.Field(typeof(CardUpgradeData), "bonusHP")?.SetValue(val, Math.Abs(bonusHP).MutateBalanced(rng) * Math.Sign(bonusHP));
				}
				if (!(AccessTools.Field(typeof(CardUpgradeData), "roomModifierUpgrades")?.GetValue(val) is List<RoomModifierData> list))
				{
					continue;
				}
				List<RoomModifierData> list2 = new List<RoomModifierData>(list.Count);
				foreach (RoomModifierData item2 in list)
				{
					if (item2 != null)
					{
						RoomModifierData val2 = DataCloner.CloneRoomModifier(item2);
						int num = (int)(AccessTools.Field(typeof(RoomModifierData), "paramInt")?.GetValue(val2) ?? ((object)0));
						if (num != 0)
						{
							AccessTools.Field(typeof(RoomModifierData), "paramInt")?.SetValue(val2, Math.Abs(num).MutateBalanced(rng) * Math.Sign(num));
						}
						list2.Add(val2);
					}
				}
				AccessTools.Field(typeof(CardUpgradeData), "roomModifierUpgrades")?.SetValue(val, list2);
			}
		}
	}
}
namespace Random_Clan.Plugin.Modifications.Champions
{
	public sealed class ChampionUpgradeTreeModification : ICardModification
	{
		private const int PathCount = 3;

		private const int TiersPerPath = 3;

		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			if (card.IsChampionCard())
			{
				return ctx.ChampionUpgradePool.Count > 0;
			}
			return false;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			foreach (ClassData allClassData in ctx.SaveManager.GetAllGameData().GetAllClassDatas())
			{
				if (!(AccessTools.Field(typeof(ClassData), "champions")?.GetValue(allClassData) is List<ChampionData> list))
				{
					continue;
				}
				foreach (ChampionData item in list)
				{
					if ((Object)(object)item.championCardData != (Object)(object)card)
					{
						continue;
					}
					object? obj = AccessTools.Field(typeof(ChampionData), "upgradeTree")?.GetValue(item);
					CardUpgradeTreeData val = (CardUpgradeTreeData)((obj is CardUpgradeTreeData) ? obj : null);
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					List<CardUpgradeData> list2 = ctx.ChampionUpgradePool.ToList();
					Shuffle(list2, rng);
					List<UpgradeTree> list3 = new List<UpgradeTree>(3);
					for (int i = 0; i < 3; i++)
					{
						List<CardUpgradeData> list4 = TakeUpgrades(list2, ctx.ChampionUpgradePool, rng, 3);
						list4.Sort((CardUpgradeData a, CardUpgradeData b) => (a.GetBonusDamage() + a.GetBonusHP()).CompareTo(b.GetBonusDamage() + b.GetBonusHP()));
						UpgradeTree val2 = new UpgradeTree();
						AccessTools.Field(typeof(UpgradeTree), "cardUpgrades")?.SetValue(val2, list4);
						list3.Add(val2);
					}
					AccessTools.Field(typeof(CardUpgradeTreeData), "upgradeTrees")?.SetValue(val, list3);
					Plugin.Logger.LogInfo((object)$"Champion tree rebuilt with {3} paths x {3} tiers for {((Object)card).name}");
				}
			}
		}

		private static List<CardUpgradeData> TakeUpgrades(List<CardUpgradeData> available, IReadOnlyList<CardUpgradeData> fallbackPool, Random rng, int count)
		{
			List<CardUpgradeData> list = new List<CardUpgradeData>(count);
			while (list.Count < count)
			{
				if (available.Count == 0)
				{
					if (fallbackPool.Count == 0)
					{
						break;
					}
					available.AddRange(fallbackPool);
					Shuffle(available, rng);
				}
				int index = rng.Next(available.Count);
				list.Add(available[index]);
				available.RemoveAt(index);
			}
			return list;
		}

		private static void Shuffle<T>(IList<T> list, Random rng)
		{
			for (int num = list.Count - 1; num > 0; num--)
			{
				int num2 = rng.Next(num + 1);
				int index = num;
				int index2 = num2;
				T value = list[num2];
				T value2 = list[num];
				list[index] = value;
				list[index2] = value2;
			}
		}
	}
}
namespace Random_Clan.Plugin.Modifications.Cards
{
	public sealed class CardStatusCountModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return StatusModificationHelper.HasCardStatusEntries(card);
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			StatusModificationHelper.TryAdjustSingleCardStatus(card, rng, swap: false);
		}
	}
	public sealed class CardStatusInjectModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			if (ctx.StatusIds.Count > 0)
			{
				return StatusModificationHelper.HasCardStatusEntries(card);
			}
			return false;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			if (ctx.StatusIds.Count == 0)
			{
				return;
			}
			List<CardEffectData> effects = card.GetEffects();
			if (effects == null)
			{
				return;
			}
			List<CardEffectData> list = effects.Where(delegate(CardEffectData e)
			{
				if (e != null)
				{
					StatusEffectStackData[] statusEffects = e.GetStatusEffects();
					if (statusEffects != null)
					{
						return statusEffects.Length > 0;
					}
					return false;
				}
				return false;
			}).ToList();
			if (list.Count != 0)
			{
				CardEffectData effect = list[rng.Next(list.Count)];
				StatusEffectStackData[] array = effect.GetStatusEffects() ?? Array.Empty<StatusEffectStackData>();
				StatusEffectStackData[] array2 = (StatusEffectStackData[])(object)new StatusEffectStackData[array.Length + 1];
				for (int num = 0; num < array.Length; num++)
				{
					array2[num] = array[num];
				}
				array2[array.Length] = new StatusEffectStackData
				{
					statusId = ctx.StatusIds[rng.Next(ctx.StatusIds.Count)],
					count = Math.Max(1, 1.MutateBalanced(rng))
				};
				effect.SetStatusEffects(array2);
			}
		}
	}
	public sealed class CardStatusSwapModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			if (ctx.StatusIds.Count > 1)
			{
				return StatusModificationHelper.HasCardStatusEntries(card);
			}
			return false;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			StatusModificationHelper.TryAdjustSingleCardStatus(card, rng, swap: true, ctx.StatusIds);
		}
	}
	public sealed class CardTriggerTypeModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			if (card.GetTriggerList().Count > 0)
			{
				return ctx.SwappableCardTriggers.Count > 1;
			}
			return false;
		}

		public unsafe void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			List<CardTriggerEffectData> triggerList = card.GetTriggerList();
			if (triggerList.Count == 0 || ctx.SwappableCardTriggers.Count < 2)
			{
				return;
			}
			CardTriggerEffectData obj = triggerList[rng.Next(triggerList.Count)];
			FieldInfo fieldInfo = AccessTools.Field(typeof(CardTriggerEffectData), "trigger");
			if (!(fieldInfo == null))
			{
				CardTriggerType val = (CardTriggerType)fieldInfo.GetValue(obj);
				IReadOnlyList<CardTriggerType> swappableCardTriggers = ctx.SwappableCardTriggers;
				int num = 0;
				CardTriggerType val2;
				do
				{
					val2 = swappableCardTriggers[rng.Next(swappableCardTriggers.Count)];
					num++;
				}
				while (((object)(*(CardTriggerType*)(&val2))/*cast due to .constrained prefix*/).Equals((object?)val) && num < 8);
				fieldInfo.SetValue(obj, val2);
			}
		}
	}
	public sealed class CostAdjustmentModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return !card.IsChampionCard();
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			int max = (((int)card.GetCardTypeValue() == 0) ? 5 : 4);
			int cost = Math.Clamp(card.GetCostValue() + ModificationTuning.CostDeltas[rng.Next(ModificationTuning.CostDeltas.Length)], 0, max);
			card.SetCost(cost);
		}
	}
	public sealed class NumberFixedModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return <NumberModifications>FCF2BFB199DAEF4DDB6E8B7665315AC8E783A4D6565ECBA29E0E5892DF7DB7C1D__NumberMutation.HasPositiveParamInt(card, ctx);
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			<NumberModifications>FCF2BFB199DAEF4DDB6E8B7665315AC8E783A4D6565ECBA29E0E5892DF7DB7C1D__NumberMutation.Mutate(card, ctx, rng, fixedSteps: true);
		}
	}
	public sealed class NumberScaledModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return <NumberModifications>FCF2BFB199DAEF4DDB6E8B7665315AC8E783A4D6565ECBA29E0E5892DF7DB7C1D__NumberMutation.HasPositiveParamInt(card, ctx);
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			<NumberModifications>FCF2BFB199DAEF4DDB6E8B7665315AC8E783A4D6565ECBA29E0E5892DF7DB7C1D__NumberMutation.Mutate(card, ctx, rng, fixedSteps: false);
		}
	}
	internal static class <NumberModifications>FCF2BFB199DAEF4DDB6E8B7665315AC8E783A4D6565ECBA29E0E5892DF7DB7C1D__NumberMutation
	{
		public static bool HasPositiveParamInt(CardData card, RandomizeContext ctx)
		{
			return Targets(card, ctx).Any((CardData t) => t.GetEffects()?.Any((CardEffectData e) => e != null && e.GetParamIntValue() > 0) ?? false);
		}

		public static void Mutate(CardData card, RandomizeContext ctx, Random rng, bool fixedSteps)
		{
			foreach (CardData item in Targets(card, ctx))
			{
				List<CardEffectData> effects = item.GetEffects();
				if (effects == null)
				{
					continue;
				}
				foreach (CardEffectData item2 in effects)
				{
					if (item2 != null)
					{
						int paramIntValue = item2.GetParamIntValue();
						if (paramIntValue > 0)
						{
							item2.SetParamIntValue(fixedSteps ? paramIntValue.MutateFixed(rng, ModificationTuning.NumberSteps) : paramIntValue.MutateScaled(rng, ModificationTuning.NumberScales));
						}
					}
				}
			}
		}

		private static IEnumerable<CardData> Targets(CardData card, RandomizeContext ctx)
		{
			yield return card;
			CharacterData? character = ctx.Character;
			object obj = ((character != null) ? character.GetUnitAbilityCardData() : null);
			if (obj == null)
			{
				CharacterData spawnCharacterData = card.GetSpawnCharacterData();
				obj = ((spawnCharacterData != null) ? spawnCharacterData.GetUnitAbilityCardData() : null);
			}
			CardData val = (CardData)obj;
			if ((Object)(object)val != (Object)null)
			{
				yield return val;
			}
		}
	}
	public sealed class TraitInjectModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return ctx.InjectableTraits.Count > 0;
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			if (ctx.InjectableTraits.Count == 0)
			{
				return;
			}
			List<CardTraitData> list = (from t in card.GetTraitList()
				where t != null
				select t).ToList();
			HashSet<string> existingStates = new HashSet<string>(list.Select((CardTraitData t) => t.traitStateName ?? ""), StringComparer.Ordinal);
			List<CardTraitData> list2 = ctx.InjectableTraits.Where((CardTraitData t) => t != null && !existingStates.Contains(t.traitStateName ?? "")).ToList();
			if (list2.Count != 0)
			{
				CardTraitData val = list2[rng.Next(list2.Count)].Copy();
				if (val != null)
				{
					list.Add(val);
					card.SetTraits(list);
				}
			}
		}
	}
	public sealed class TraitParamModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return card.GetTraitList().Any((CardTraitData t) => !t.IsMarkerTrait() && t.HasPositiveParam());
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			foreach (CardTraitData trait in card.GetTraitList())
			{
				if (trait == null || trait.IsMarkerTrait())
				{
					continue;
				}
				string[] array = new string[2] { "paramInt", "paramInt2" };
				foreach (string text in array)
				{
					FieldInfo fieldInfo = AccessTools.Field(typeof(CardTraitData), text);
					if (!(fieldInfo == null) && !(fieldInfo.FieldType != typeof(int)))
					{
						int num = (int)fieldInfo.GetValue(trait);
						if (num > 0)
						{
							fieldInfo.SetValue(trait, num.MutateBalanced(rng));
						}
					}
				}
			}
		}
	}
	public sealed class TraitRemoveModification : ICardModification
	{
		public bool CanModify(CardData card, RandomizeContext ctx)
		{
			return card.GetTraitList().Any((CardTraitData t) => t != null && !t.IsMarkerTrait());
		}

		public void Modify(CardData card, RandomizeContext ctx, Random rng)
		{
			List<CardTraitData> list = (from t in card.GetTraitList()
				where t != null
				select t).ToList();
			List<(CardTraitData, int)> list2 = (from x in list.Select((CardTraitData t, int i) => (Trait: t, Index: i))
				where !x.Trait.IsMarkerTrait()
				select x).ToList();
			if (list2.Count != 0)
			{
				list.RemoveAt(list2[rng.Next(list2.Count)].Item2);
				card.SetTraits(list);
			}
		}
	}
}
namespace Random_Clan.Plugin.Extensions
{
	public static class CardDataExtensions
	{
		public static CardType GetCardTypeValue(this CardData card)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			return (CardType)(AccessTools.Field(typeof(CardData), "cardType")?.GetValue(card) ?? ((object)(CardType)4));
		}

		public static CollectableRarity GetRarityValue(this CardData card)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			return (CollectableRarity)(AccessTools.Field(typeof(CardData), "rarity")?.GetValue(card) ?? ((object)(CollectableRarity)0));
		}

		public static bool IsChampionCard(this CardData card)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			if ((int)card.GetCardTypeValue() == 1)
			{
				return (int)card.GetRarityValue() == 3;
			}
			return false;
		}

		public static bool IsBannerUnitCard(this CardData card)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)card.GetCardTypeValue() != 1 || card.IsChampionCard())
			{
				return false;
			}
			CharacterData spawnCharacterData = card.GetSpawnCharacterData();
			if ((Object)(object)spawnCharacterData == (Object)null)
			{
				return false;
			}
			return spawnCharacterData.GetSubtypeKeys().Any((string s) => s.Contains("BannerUnit", StringComparison.OrdinalIgnoreCase));
		}

		public static List<CardTraitData> GetTraitList(this CardData card)
		{
			return card.GetTraits() ?? (AccessTools.Field(typeof(CardData), "traits")?.GetValue(card) as List<CardTraitData>) ?? new List<CardTraitData>();
		}

		public static bool HasRandomized(this CardData card)
		{
			return card.GetTraitList().Any((CardTraitData t) => (t.traitStateName ?? "").Contains("CardTraitRandomized", StringComparison.Ordinal));
		}

		public static int GetModifierCount(this CardData card)
		{
			foreach (CardTraitData trait in card.GetTraitList())
			{
				if (trait.IsModifierTrait())
				{
					return trait.ReadParamInt();
				}
			}
			return 0;
		}

		public static List<CardTraitData> GetMarkerTraits(this CardData card)
		{
			return (from t in card.GetTraitList()
				where t.IsMarkerTrait()
				select t).ToList();
		}

		public static bool HasStatusEffects(this CardData card)
		{
			return card.GetEffects()?.Any(delegate(CardEffectData e)
			{
				if (e != null)
				{
					StatusEffectStackData[] statusEffects = e.GetStatusEffects();
					if (statusEffects != null)
					{
						return statusEffects.Length > 0;
					}
					return false;
				}
				return false;
			}) ?? false;
		}

		public static void SetCost(this CardData card, int cost)
		{
			AccessTools.Field(typeof(CardData), "cost")?.SetValue(card, cost);
		}

		public static int GetCostValue(this CardData card)
		{
			return (int)(AccessTools.Field(typeof(CardData), "cost")?.GetValue(card) ?? ((object)0));
		}

		public static void SetTraits(this CardData card, List<CardTraitData> traits)
		{
			AccessTools.Field(typeof(CardData), "traits")?.SetValue(card, traits);
		}

		public static void SetEffects(this CardData card, List<CardEffectData> effects)
		{
			AccessTools.Field(typeof(CardData), "effects")?.SetValue(card, effects);
		}

		public static void SetTriggers(this CardData card, List<CardTriggerEffectData> triggers)
		{
			AccessTools.Field(typeof(CardData), "triggers")?.SetValue(card, triggers);
		}

		public static List<CardTriggerEffectData> GetTriggerList(this CardData card)
		{
			return (AccessTools.Field(typeof(CardData), "triggers")?.GetValue(card) as List<CardTriggerEffectData>) ?? new List<CardTriggerEffectData>();
		}

		public static void SetNameKey(this CardData card, string nameKey)
		{
			AccessTools.Field(typeof(CardData), "nameKey")?.SetValue(card, nameKey);
		}

		public static string? GetDescriptionKey(this CardData card)
		{
			return AccessTools.Field(typeof(CardData), "overrideDescriptionKey")?.GetValue(card) as string;
		}

		public static void SetDescriptionKey(this CardData card, string key)
		{
			AccessTools.Field(typeof(CardData), "overrideDescriptionKey")?.SetValue(card, key);
		}

		public static object? GetRarityObject(this CardData card)
		{
			return AccessTools.Field(typeof(CardData), "rarity")?.GetValue(card);
		}

		public static void SetRarityObject(this CardData card, object rarity)
		{
			AccessTools.Field(typeof(CardData), "rarity")?.SetValue(card, rarity);
		}

		public static void SetIsUnitAbility(this CardData card, bool value)
		{
			AccessTools.Field(typeof(CardData), "isUnitAbility")?.SetValue(card, value);
		}
	}
	public static class CardEffectDataExtensions
	{
		public static int GetParamIntValue(this CardEffectData effect)
		{
			return (int)(AccessTools.Field(typeof(CardEffectData), "paramInt")?.GetValue(effect) ?? ((object)0));
		}

		public static void SetParamIntValue(this CardEffectData effect, int value)
		{
			AccessTools.Field(typeof(CardEffectData), "paramInt")?.SetValue(effect, value);
		}

		public static StatusEffectStackData[]? GetStatusEffects(this CardEffectData effect)
		{
			return AccessTools.Field(typeof(CardEffectData), "paramStatusEffects")?.GetValue(effect) as StatusEffectStackData[];
		}

		public static void SetStatusEffects(this CardEffectData effect, StatusEffectStackData[] statuses)
		{
			AccessTools.Field(typeof(CardEffectData), "paramStatusEffects")?.SetValue(effect, statuses);
		}

		public static CardUpgradeData? GetCardUpgrade(this CardEffectData effect)
		{
			object? obj = AccessTools.Field(typeof(CardEffectData), "paramCardUpgradeData")?.GetValue(effect);
			return (CardUpgradeData?)((obj is CardUpgradeData) ? obj : null);
		}

		public static void SetCardUpgrade(this CardEffectData effect, CardUpgradeData upgrade)
		{
			AccessTools.Field(typeof(CardEffectData), "paramCardUpgradeData")?.SetValue(effect, upgrade);
		}
	}
	public static class CardTraitDataExtensions
	{
		public static bool IsMarkerTrait(this CardTraitData? trait)
		{
			if (trait == null)
			{
				return false;
			}
			string state = trait.traitStateName ?? "";
			if (!state.Contains("CardTraitRandomized", StringComparison.Ordinal))
			{
				return MarkerTraitNames.ModifierStates.Any((string m) => state.Contains(m, StringComparison.Ordinal));
			}
			return true;
		}

		public static bool IsModifierTrait(this CardTraitData? trait)
		{
			if (trait == null)
			{
				return false;
			}
			string state = trait.traitStateName ?? "";
			return MarkerTraitNames.ModifierStates.Any((string m) => state.Contains(m, StringComparison.Ordinal));
		}

		public static int ReadParamInt(this CardTraitData trait)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(CardTraitData), "GetParamInt", (Type[])null, (Type[])null);
			if (methodInfo != null && methodInfo.GetParameters().Length == 0)
			{
				object obj = methodInfo.Invoke(trait, null);
				if (obj is int)
				{
					return (int)obj;
				}
			}
			return (int)(AccessTools.Field(typeof(CardTraitData), "paramInt")?.GetValue(trait) ?? ((object)0));
		}

		public static bool HasPositiveParam(this CardTraitData trait)
		{
			string[] array = new string[2] { "paramInt", "paramInt2" };
			foreach (string text in array)
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(CardTraitData), text);
				if (fieldInfo?.FieldType == typeof(int) && (int)fieldInfo.GetValue(trait) > 0)
				{
					return true;
				}
			}
			return false;
		}
	}
	public static class CharacterDataExtensions
	{
		public static void SetHealth(this CharacterData character, int health)
		{
			AccessTools.Field(typeof(CharacterData), "health")?.SetValue(character, health);
		}

		public static void SetAttackDamage(this CharacterData character, int attack)
		{
			AccessTools.Field(typeof(CharacterData), "attackDamage")?.SetValue(character, attack);
		}

		public static void SetSize(this CharacterData character, int size)
		{
			AccessTools.Field(typeof(CharacterData), "size")?.SetValue(character, size);
		}

		public static void SetSubtypeKeys(this CharacterData character, List<string> subtypes)
		{
			AccessTools.Field(typeof(CharacterData), "subtypeKeys")?.SetValue(character, subtypes);
		}

		public static List<string> GetSubtypeKeys(this CharacterData character)
		{
			return (AccessTools.Field(typeof(CharacterData), "subtypeKeys")?.GetValue(character) as List<string>) ?? new List<string>();
		}

		public static void SetTriggers(this CharacterData character, List<CharacterTriggerData> triggers)
		{
			AccessTools.Field(typeof(CharacterData), "triggers")?.SetValue(character, triggers);
		}

		public static List<CharacterTriggerData> GetTriggerList(this CharacterData character)
		{
			return (AccessTools.Field(typeof(CharacterData), "triggers")?.GetValue(character) as List<CharacterTriggerData>) ?? new List<CharacterTriggerData>();
		}

		public static void SetUnitAbility(this CharacterData character, CardData? ability)
		{
			AccessTools.Field(typeof(CharacterData), "unitAbility")?.SetValue(character, ability);
		}

		public static void SetNameKey(this CharacterData character, string nameKey)
		{
			AccessTools.Field(typeof(CharacterData), "nameKey")?.SetValue(character, nameKey);
		}

		public static StatusEffectStackData[] GetStartingStatusEffectsArray(this CharacterData character)
		{
			return (AccessTools.Field(typeof(CharacterData), "startingStatusEffects")?.GetValue(character) as StatusEffectStackData[]) ?? Array.Empty<StatusEffectStackData>();
		}

		public static void SetStartingStatusEffectsArray(this CharacterData character, StatusEffectStackData[] statuses)
		{
			AccessTools.Field(typeof(CharacterData), "startingStatusEffects")?.SetValue(character, statuses);
		}

		public static void CopyStartingStatusesFrom(this CharacterData slot, CharacterData donor)
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(CharacterData), "startingStatusEffects");
			if (!(fieldInfo == null) && fieldInfo.GetValue(donor) is Array array)
			{
				fieldInfo.SetValue(slot, array.Clone());
			}
		}
	}
	public static class IntExtensions
	{
		public static int MutateBalanced(this int value, Random rng)
		{
			if (rng.NextDouble() < 0.5)
			{
				return value.MutateFixed(rng, ModificationTuning.NumberSteps);
			}
			return value.MutateScaled(rng, ModificationTuning.NumberScales);
		}

		public static int MutateFixed(this int value, Random rng)
		{
			return value.MutateFixed(rng, ModificationTuning.StatSteps);
		}

		public static int MutateFixed(this int value, Random rng, int[] steps)
		{
			return Math.Max(1, value + steps[rng.Next(steps.Length)]);
		}

		public static int MutateScaled(this int value, Random rng)
		{
			return value.MutateScaled(rng, ModificationTuning.StatScales);
		}

		public static int MutateScaled(this int value, Random rng, float[] scales)
		{
			return Math.Max(1, (int)Math.Round((float)value * scales[rng.Next(scales.Length)]));
		}
	}
	public static class StringExtensions
	{
		public static string? TrySwapStatus(this string statusId, Random rng, IReadOnlyList<string> statusIds)
		{
			if (statusIds.Count < 2)
			{
				return null;
			}
			string text;
			do
			{
				text = statusIds[rng.Next(statusIds.Count)];
			}
			while (text.Equals(statusId, StringComparison.OrdinalIgnoreCase) && statusIds.Count > 1);
			return text;
		}
	}
}
namespace Random_Clan.Plugin.Copying
{
	public sealed class CardDonorCopier
	{
		public void CopyOnto(CardData slot, CardData donor, IReadOnlyList<CardTraitData> markerTraits)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)slot.GetCardTypeValue() == 1)
			{
				CopyUnitOnto(slot, donor);
			}
			else
			{
				CopySpellLikeOnto(slot, donor);
			}
			List<CardTraitData> list = (from t in slot.GetTraitList()
				where !t.IsMarkerTrait()
				select t).ToList();
			foreach (CardTraitData markerTrait in markerTraits)
			{
				if (markerTrait != null && !list.Contains(markerTrait))
				{
					list.Add(markerTrait);
				}
			}
			slot.SetTraits(list);
		}

		private void CopySpellLikeOnto(CardData slot, CardData donor)
		{
			string descriptionKey = donor.GetDescriptionKey();
			if (!string.IsNullOrEmpty(descriptionKey))
			{
				slot.SetDescriptionKey(descriptionKey);
			}
			object rarityObject = donor.GetRarityObject();
			if (rarityObject != null)
			{
				slot.SetRarityObject(rarityObject);
			}
			slot.SetCost(donor.GetCostValue());
			List<CardEffectData> obj = donor.GetEffects() ?? new List<CardEffectData>();
			List<CardEffectData> list = new List<CardEffectData>(obj.Count);
			foreach (CardEffectData item in obj)
			{
				if (item != null)
				{
					list.Add(DataCloner.CloneEffect(item));
				}
			}
			slot.SetEffects(list);
			List<CardTraitData> list2 = new List<CardTraitData>();
			foreach (CardTraitData trait in donor.GetTraitList())
			{
				if (trait != null && !trait.IsMarkerTrait())
				{
					list2.Add(trait);
				}
			}
			slot.SetTraits(list2);
			List<CardTriggerEffectData> list3 = new List<CardTriggerEffectData>();
			foreach (CardTriggerEffectData trigger in donor.GetTriggerList())
			{
				if (trigger != null)
				{
					list3.Add(DataCloner.CloneCardTrigger(trigger));
				}
			}
			slot.SetTriggers(list3);
		}

		private void CopyUnitOnto(CardData slot, CardData donor)
		{
			string descriptionKey = donor.GetDescriptionKey();
			if (!string.IsNullOrEmpty(descriptionKey))
			{
				slot.SetDescriptionKey(descriptionKey);
			}
			object rarityObject = donor.GetRarityObject();
			if (rarityObject != null)
			{
				slot.SetRarityObject(rarityObject);
			}
			slot.SetCost(donor.GetCostValue());
			CharacterData spawnCharacterData = slot.GetSpawnCharacterData();
			CharacterData spawnCharacterData2 = donor.GetSpawnCharacterData();
			if ((Object)(object)spawnCharacterData == (Object)null || (Object)(object)spawnCharacterData2 == (Object)null)
			{
				Plugin.Logger.LogWarning((object)("Unit copy skipped character: " + ((Object)slot).name + " <- " + ((Object)donor).name));
			}
			else
			{
				CopyCharacterMechanics(spawnCharacterData, spawnCharacterData2, slot);
			}
		}

		private void CopyCharacterMechanics(CharacterData slot, CharacterData donor, CardData slotCard)
		{
			slot.SetHealth(donor.GetHealth());
			slot.SetAttackDamage(donor.GetAttackDamage());
			slot.SetSize(donor.GetSize());
			slot.SetSubtypeKeys(new List<string>(donor.GetSubtypeKeys()));
			List<CharacterTriggerData> list = new List<CharacterTriggerData>();
			foreach (CharacterTriggerData trigger in donor.GetTriggerList())
			{
				if (trigger != null)
				{
					list.Add(DataCloner.CloneCharacterTrigger(trigger));
				}
			}
			slot.SetTriggers(list);
			slot.CopyStartingStatusesFrom(donor);
			CardData unitAbilityCardData = donor.GetUnitAbilityCardData();
			if ((Object)(object)unitAbilityCardData != (Object)null)
			{
				slot.SetUnitAbility(CloneAbilityCard(unitAbilityCardData, ((Object)slotCard).name + "_AbilityClone"));
			}
			else
			{
				slot.SetUnitAbility(null);
			}
			string[] array = new string[3] { "attackVFX", "impactVFX", "deathVFX" };
			foreach (string text in array)
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(CharacterData), text);
				object obj = fieldInfo?.GetValue(donor);
				if (obj != null)
				{
					fieldInfo.SetValue(slot, obj);
				}
			}
		}

		public static CardData CloneAbilityCard(CardData donorAbility, string name)
		{
			CardData val = Object.Instantiate<CardData>(donorAbility);
			((Object)val).name = name;
			val.SetIsUnitAbility(value: true);
			EnsureCardVfxDefaults(val);
			List<CardEffectData> obj = donorAbility.GetEffects() ?? new List<CardEffectData>();
			List<CardEffectData> list = new List<CardEffectData>(obj.Count);
			foreach (CardEffectData item in obj)
			{
				if (item != null)
				{
					list.Add(DataCloner.CloneEffect(item));
				}
			}
			val.SetEffects(list);
			List<CardTraitData> list2 = new List<CardTraitData>();
			foreach (CardTraitData trait in donorAbility.GetTraitList())
			{
				if (trait != null && !trait.IsMarkerTrait())
				{
					list2.Add(trait);
				}
			}
			val.SetTraits(list2);
			List<CardTriggerEffectData> list3 = new List<CardTriggerEffectData>();
			foreach (CardTriggerEffectData trigger in donorAbility.GetTriggerList())
			{
				if (trigger != null)
				{
					list3.Add(DataCloner.CloneCardTrigger(trigger));
				}
			}
			val.SetTriggers(list3);
			return val;
		}

		private static void EnsureCardVfxDefaults(CardData card)
		{
			string[] array = new string[2] { "specialEdgeVFX", "offCooldownVFX" };
			foreach (string text in array)
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(CardData), text);
				if (!(fieldInfo == null) && fieldInfo.GetValue(card) == null)
				{
					fieldInfo.SetValue(card, VfxRegister.Default);
				}
			}
		}
	}
	public static class DataCloner
	{
		private static readonly MethodInfo MemberwiseCloneMethod = typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic);

		public static T ShallowClone<T>(T source) where T : class
		{
			return (T)MemberwiseCloneMethod.Invoke(source, null);
		}

		public static CardEffectData CloneEffect(CardEffectData source)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0052: Expected O, but got Unknown
			CardEffectData val = ShallowClone<CardEffectData>(source);
			StatusEffectStackData[] statusEffects = source.GetStatusEffects();
			if (statusEffects != null)
			{
				StatusEffectStackData[] array = (StatusEffectStackData[])(object)new StatusEffectStackData[statusEffects.Length];
				for (int i = 0; i < statusEffects.Length; i++)
				{
					StatusEffectStackData val2 = statusEffects[i];
					array[i] = new StatusEffectStackData
					{
						statusId = val2.statusId,
						count = val2.count,
						fromPermanentUpgrade = val2.fromPermanentUpgrade
					};
				}
				val.SetStatusEffects(array);
			}
			return val;
		}

		public static CharacterTriggerData CloneCharacterTrigger(CharacterTriggerData source)
		{
			CharacterTriggerData val = ShallowClone<CharacterTriggerData>(source);
			if (AccessTools.Field(typeof(CharacterTriggerData), "effects")?.GetValue(source) is List<CardEffectData> list)
			{
				List<CardEffectData> list2 = new List<CardEffectData>(list.Count);
				foreach (CardEffectData item in list)
				{
					if (item != null)
					{
						list2.Add(CloneEffect(item));
					}
				}
				AccessTools.Field(typeof(CharacterTriggerData), "effects")?.SetValue(val, list2);
			}
			return val;
		}

		public static CardTriggerEffectData CloneCardTrigger(CardTriggerEffectData source)
		{
			CardTriggerEffectData val = ShallowClone<CardTriggerEffectData>(source);
			if (AccessTools.Field(typeof(CardTriggerEffectData), "cardEffects")?.GetValue(source) is List<CardEffectData> list)
			{
				List<CardEffectData> list2 = new List<CardEffectData>(list.Count);
				foreach (CardEffectData item in list)
				{
					if (item != null)
					{
						list2.Add(CloneEffect(item));
					}
				}
				AccessTools.Field(typeof(CardTriggerEffectData), "cardEffects")?.SetValue(val, list2);
			}
			return val;
		}

		public static RoomModifierData CloneRoomModifier(RoomModifierData source)
		{
			return ShallowClone<RoomModifierData>(source);
		}
	}
}
namespace Random_Clan.Plugin.Constants
{
	public static class MarkerTraitNames
	{
		public const string Randomized = "CardTraitRandomized";

		public const string SpellModifier = "CardTraitSpellModifier";

		public const string UnitModifier = "CardTraitUnitModifier";

		public const string RoomModifier = "CardTraitRoomModifier";

		public const string ChampionModifier = "CardTraitChampionModifier";

		public static readonly string[] ModifierStates = new string[4] { "CardTraitSpellModifier", "CardTraitUnitModifier", "CardTraitRoomModifier", "CardTraitChampionModifier" };
	}
	public static class ModificationTuning
	{
		public static readonly int[] NumberSteps = new int[4] { -2, -1, 1, 2 };

		public static readonly float[] NumberScales = new float[3] { 0.5f, 1.5f, 2f };

		public static readonly int[] StatSteps = new int[8] { -5, -3, -2, -1, 1, 2, 3, 5 };

		public static readonly float[] StatScales = new float[5] { 0.5f, 0.75f, 1.25f, 1.5f, 2f };

		public static readonly int[] CostDeltas = new int[2] { -1, 1 };

		public static readonly int[] SizeSteps = new int[4] { -2, -1, 1, 2 };

		public const int MinSize = 1;

		public const int MaxSize = 6;

		public const int CardDistortionEffectType = 2;

		public const int CardEffectsMaxLayers = 8;

		public const string CardEffectsShaderName = "Shiny Shoe/CardEffects";

		public const string CardEffectsTemplateMaterialName = "CardMaterial_PunkrockReveler";

		public static readonly Color CardGlitchLayerTint = new Color(0.55f, 1.15f, 1.35f, 1f);

		public static readonly Vector2 CardGlitchLinearSpeed = new Vector2(0.35f, -0.2f);

		public static readonly Vector2 CardGlitchScale = new Vector2(1.15f, 1.15f);

		public static readonly Color CharacterGlitchTint = new Color(0.65f, 1.25f, 1.45f, 1f);

		public const float CharacterGlitchGrayscale = 0.35f;
	}
}
namespace Random_Clan.Plugin.CardTraits
{
	public sealed class CardTraitChampionModifier : CardTraitModifierBase
	{
		protected override string LocalizationPrefix => "CardTraitChampionModifier";
	}
	public abstract class CardTraitModifierBase : CardTraitState
	{
		protected abstract string LocalizationPrefix { get; }

		public override PropDescriptions CreateEditorInspectorDescriptions()
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0024: Expected O, but got Unknown
			//IL_0025: Expected O, but got Unknown
			PropDescriptions val = new PropDescriptions { };
			string fieldName;
			((Dictionary<string, PropDescription>)val)[fieldName] = new PropDescription("Modification count", "", (Type)null, false);
			return val;
		}

		public override string GetCardText()
		{
			string text = ((CardTraitState)this).LocalizeTraitKey(LocalizationPrefix + "_CardText");
			if (string.IsNullOrEmpty(text))
			{
				return string.Empty;
			}
			return string.Format(text, ((CardTraitState)this).GetParamInt());
		}

		public override string GetCardTooltipTitle()
		{
			return ((CardTraitState)this).LocalizeTraitKey(LocalizationPrefix + "_TooltipTitle");
		}

		public override string GetCardTooltipText()
		{
			string text = LocalizationExtensions.Localize(LocalizationPrefix + "_TooltipText", (ILocalizationParameterContext)null);
			if (string.IsNullOrEmpty(text))
			{
				return string.Empty;
			}
			return string.Format(text, ((CardTraitState)this).GetParamInt());
		}
	}
	public sealed class CardTraitRandomized : CardTraitState
	{
		public override PropDescriptions CreateEditorInspectorDescriptions()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			return new PropDescriptions();
		}

		public override string GetCardText()
		{
			string text = ((CardTraitState)this).LocalizeTraitKey("CardTraitRandomized_CardText");
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return string.Empty;
		}

		public override string GetCardTooltipTitle()
		{
			return ((CardTraitState)this).LocalizeTraitKey("CardTraitRandomized_TooltipTitle");
		}

		public override string GetCardTooltipText()
		{
			string text = LocalizationExtensions.Localize("CardTraitRandomized_TooltipText", (ILocalizationParameterContext)null);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return string.Empty;
		}
	}
	public sealed class CardTraitRoomModifier : CardTraitModifierBase
	{
		protected override string LocalizationPrefix => "CardTraitRoomModifier";
	}
	public sealed class CardTraitSpellModifier : CardTraitModifierBase
	{
		protected override string LocalizationPrefix => "CardTraitSpellModifier";
	}
	public sealed class CardTraitUnitModifier : CardTraitModifierBase
	{
		protected override string LocalizationPrefix => "CardTraitUnitModifier";
	}
}