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