public IEnumerator DestroyReplaceResponse(GameAction ga) { // "... destroy {H - 1} Equipment cards." List <DestroyCardAction> destroyed = new List <DestroyCardAction>(); LinqCardCriteria equipmentInPlay = new LinqCardCriteria((Card c) => c.DoKeywordsContain("equipment") && c.IsInPlayAndHasGameText && base.GameController.IsCardVisibleToCardSource(c, GetCardSource()), "Equipment"); IEnumerator destroyCoroutine = base.GameController.SelectAndDestroyCards(DecisionMaker, equipmentInPlay, H - 1, requiredDecisions: H - 1, storedResultsAction: destroyed, responsibleCard: base.Card, allowAutoDecide: base.GameController.FindCardsWhere(equipmentInPlay).Count() <= H - 1, cardSource: GetCardSource()); if (base.UseUnityCoroutines) { yield return(base.GameController.StartCoroutine(destroyCoroutine)); } else { base.GameController.ExhaustCoroutine(destroyCoroutine); } // "If fewer than {H - 1} cards were destroyed this way, replace the hero character card with the highest HP with a variant of that hero." if (destroyed.Where((DestroyCardAction dca) => dca.WasCardDestroyed).Count() < H - 1) { List <Card> highest = new List <Card>(); IEnumerator findCoroutine = base.GameController.FindTargetWithHighestHitPoints(1, (Card c) => c.IsHeroCharacterCard, highest, evenIfCannotDealDamage: true, cardSource: GetCardSource()); if (base.UseUnityCoroutines) { yield return(base.GameController.StartCoroutine(findCoroutine)); } else { base.GameController.ExhaustCoroutine(findCoroutine); } Card highestHero = highest.FirstOrDefault(); if (highestHero != null) { // Replace highestHero with another variant // Copy-pasted from Completionist Guise, be careful // If you selected a hero to store... List <string> list = new List <string>(); list.Add(highestHero.ParentDeck.QualifiedIdentifier); list.Add(highestHero.QualifiedPromoIdentifierOrIdentifier); base.GameController.AddCardPropertyJournalEntry(highestHero, "OverrideTurnTaker", list); List <SelectFromBoxDecision> storedBox = new List <SelectFromBoxDecision>(); Func <string, bool> identifierCriteria2 = delegate(string s) { if (FindCardsWhere((Card c) => (c.Identifier == highestHero.Identifier || (highestHero.SharedIdentifier != null && highestHero.SharedIdentifier == c.SharedIdentifier)) && c.QualifiedPromoIdentifierOrIdentifier == s && c.Owner.CharacterCards.Contains(c)).Any()) { return(false); } if (highestHero.SharedIdentifier != null) { string identifier = highestHero.Identifier; CardDefinition cardDefinition2 = highestHero.ParentDeck.GetAllCardDefinitions().FirstOrDefault((CardDefinition d) => d.QualifiedPromoIdentifierOrIdentifier == s); if (cardDefinition2 == null) { cardDefinition2 = ModHelper.GetPromoDefinition(highestHero.ParentDeck.QualifiedIdentifier, s); } if (cardDefinition2 != null) { return(cardDefinition2.Identifier == identifier); } return(false); } if (highestHero.ParentDeck.InitialCardIdentifiers.Count() > 1) { IEnumerable <Card> source = FindCardsWhere((Card c) => c.Identifier == highestHero.Identifier && c.Owner.CharacterCards.Contains(c) && (c.PromoIdentifierOrIdentifier.Contains(s) || s.Contains(c.PromoIdentifierOrIdentifier))); source.Select((Card c) => c.PromoIdentifierOrIdentifier); return(source.Any((Card c) => c.PromoIdentifierOrIdentifier != s)); } return(true); }; Func <string, bool> turnTakerCriteria2 = (string tt) => tt == highestHero.ParentDeck.QualifiedIdentifier; // Choose replacement hero IEnumerator coroutine = base.GameController.SelectFromBox(DecisionMaker, identifierCriteria2, turnTakerCriteria2, SelectionType.HeroCharacterCard, storedBox, optional: false, allowMultiCardSelection: false, GetCardSource()); if (base.UseUnityCoroutines) { yield return(base.GameController.StartCoroutine(coroutine)); } else { base.GameController.ExhaustCoroutine(coroutine); } CardController newCC = null; SelectFromBoxDecision selection = storedBox.FirstOrDefault(); TurnTakerController turnTakerController = FindTurnTakerController(highestHero.Owner); if (selection != null && selection.SelectedIdentifier != null && selection.SelectedTurnTakerIdentifier != null) { Log.Debug("Selected from box: SelectedIdentifier = " + selection.SelectedIdentifier); Log.Debug("Selected from box: SelectedTurnTakerIdentifier = " + selection.SelectedTurnTakerIdentifier); Card modelCard = FindCardsWhere((Card c) => c.QualifiedPromoIdentifierOrIdentifier == selection.SelectedIdentifier && !c.Owner.CharacterCards.Contains(c), realCardsOnly: false, null, ignoreBattleZone: true).FirstOrDefault(); if (modelCard == null) { Log.Debug("Creating a card for the variant"); DeckDefinition parentDeck = highestHero.ParentDeck; Log.Debug("Owner deck definition: " + parentDeck); CardDefinition cardDefinition = (from cd in parentDeck.CardDefinitions.Concat(parentDeck.PromoCardDefinitions) where cd.QualifiedPromoIdentifierOrIdentifier == selection.SelectedIdentifier select cd).FirstOrDefault(); if (cardDefinition == null) { cardDefinition = ModHelper.GetPromoDefinition(selection.SelectedTurnTakerIdentifier, selection.SelectedIdentifier); } Log.Debug("Card definition: " + cardDefinition); if (cardDefinition != null) { // modelCard: the new card being created modelCard = new Card(cardDefinition, base.TurnTaker, 0, selection.UseFoilVersion); base.TurnTaker.OffToTheSide.AddCard(modelCard); Log.Debug("Creating card controller!"); string overrideNamespace = selection.SelectedTurnTakerIdentifier; if (!string.IsNullOrEmpty(cardDefinition.Namespace)) { overrideNamespace = $"{cardDefinition.Namespace}.{parentDeck.Identifier}"; } newCC = CardControllerFactory.CreateInstance(modelCard, base.TurnTakerController, overrideNamespace); base.TurnTakerController.AddCardController(newCC); List <string> list2 = new List <string>(); list2.Add(selection.SelectedTurnTakerIdentifier); list2.Add(selection.SelectedIdentifier); base.GameController.AddCardPropertyJournalEntry(modelCard, "OverrideTurnTaker", list2); if (modelCard.SharedIdentifier != null) { // enumerable2: all cards from parentDeck that match modelCard's SharedIdentifier but not its QualifiedPromoIdentifierOrIdentifier IEnumerable <CardDefinition> enumerable2 = from cd in parentDeck.GetAllCardDefinitions() where cd.QualifiedPromoIdentifierOrIdentifier != modelCard.QualifiedPromoIdentifierOrIdentifier && cd.SharedIdentifier == modelCard.SharedIdentifier select cd; if (modelCard.IsPromoCard && modelCard.IsModContent) { IEnumerable <CardDefinition> second = from cd in ModHelper.GetSharedPromoDefinitions(cardDefinition) where cd.QualifiedPromoIdentifierOrIdentifier != modelCard.QualifiedPromoIdentifierOrIdentifier select cd; enumerable2 = enumerable2.Concat(second); } foreach (CardDefinition item3 in enumerable2) { Card card = new Card(item3, base.TurnTaker, 0); base.TurnTaker.OffToTheSide.AddCard(card); CardController card2 = CardControllerFactory.CreateInstance(card, base.TurnTakerController, overrideNamespace); base.TurnTakerController.AddCardController(card2); List <string> list3 = new List <string>(); list3.Add(modelCard.ParentDeck.QualifiedIdentifier); list3.Add(card.QualifiedPromoIdentifierOrIdentifier); base.GameController.AddCardPropertyJournalEntry(card, "OverrideTurnTaker", list3); } } } else { Log.Error("Could not find card definition: " + selection.SelectedIdentifier); } } else { newCC = FindCardController(modelCard); } if (newCC != null) { if (highestHero.SharedIdentifier != null) { Log.Debug("Shared identifier: " + highestHero.SharedIdentifier); List <Card> list4 = turnTakerController.TurnTaker.OffToTheSide.Cards.Where((Card c) => c.SharedIdentifier == highestHero.SharedIdentifier).ToList(); foreach (Card otherSize in list4) { Log.Debug("Switching other card: " + otherSize.QualifiedPromoIdentifierOrIdentifier); if (base.GameController.GetCardPropertyJournalEntryStringList(base.Card, "OverrideTurnTaker", supressWarnings: true) == null) { List <string> list5 = new List <string>(); list5.Add(newCC.Card.ParentDeck.QualifiedIdentifier); list5.Add(otherSize.QualifiedPromoIdentifierOrIdentifier); base.GameController.AddCardPropertyJournalEntry(otherSize, "OverrideTurnTaker", list5); } Card card3 = base.TurnTaker.GetCardsWhere((Card c) => c.Identifier == otherSize.Identifier && c.SharedIdentifier == newCC.Card.SharedIdentifier).FirstOrDefault(); if (card3 != null) { IEnumerator coroutine2 = base.GameController.SwitchCards(otherSize, card3, playCardIfMovingToPlayArea: false, ignoreFlipped: false, ignoreHitPoints: false, GetCardSource()); if (base.UseUnityCoroutines) { yield return(base.GameController.StartCoroutine(coroutine2)); } else { base.GameController.ExhaustCoroutine(coroutine2); } } else { Log.Warning("Could not find Guise's copy of the card!"); } } } coroutine = base.GameController.SwitchCards(highestHero, newCC.Card, playCardIfMovingToPlayArea: false, ignoreFlipped: false, ignoreHitPoints: false, GetCardSource()); if (base.UseUnityCoroutines) { yield return(base.GameController.StartCoroutine(coroutine)); } else { base.GameController.ExhaustCoroutine(coroutine); } if (newCC.TurnTaker.IsHero && newCC.Card.HitPoints > newCC.Card.MaximumHitPoints) { newCC.Card.SetHitPoints(newCC.Card.MaximumHitPoints.Value); } if (newCC.Card.IsTarget && !highestHero.HitPoints.HasValue) { newCC.Card.RemoveTarget(); } Card cardToMove = highestHero; coroutine = base.GameController.MoveCard(base.TurnTakerController, cardToMove, cardToMove.Owner.InTheBox, toBottom: false, isPutIntoPlay: false, playCardIfMovingToPlayArea: true, null, showMessage: false, null, base.TurnTaker, null, evenIfIndestructible: false, flipFaceDown: false, null, isDiscard: false, evenIfPretendGameOver: false, shuffledTrashIntoDeck: false, doesNotEnterPlay: false, GetCardSource()); if (base.UseUnityCoroutines) { yield return(base.GameController.StartCoroutine(coroutine)); } else { base.GameController.ExhaustCoroutine(coroutine); } cardToMove.PlayIndex = null; } } // ??? SHOULD work IEnumerator messageCoroutine = base.GameController.SendMessageAction("Reality flickers in the feedback. Things look different...", Priority.Medium, GetCardSource(), showCardSource: true); if (base.UseUnityCoroutines) { yield return(base.GameController.StartCoroutine(messageCoroutine)); } else { base.GameController.ExhaustCoroutine(messageCoroutine); } } } yield break; }
private static void ClassifyDeck(DeckAttributes deck, IDictionary<int, List<DeckDefinition>> matches, DeckDefinition deckDefinition, int level) { gameTypeField.SetValue(null, deck.GameType); if (deck.Colors != null) setColorsMethod.Invoke(null, new object[] {deck.Colors}); if (deck.Cards != null) setCardsMethod.Invoke(null, new object[] {deck.Cards}); if (deck.Words != null) setWordsMethod.Invoke(null, new object[] {deck.Words}); if (!(bool)deckDefinition.Script.Invoke(null, null)) return; if (!matches.ContainsKey(level)) matches[level] = new List<DeckDefinition>(); if (!deckDefinition.Name.StartsWith("$")) matches[level].Add(deckDefinition); foreach (var subtype in deckDefinition.Subtypes) ClassifyDeck(deck, matches, subtype, level + 1); }
public static void Initialize() { #if !NETSTANDARD2_0 var codeProvider = new CSharpCodeProvider(); var compilerParameters = new CompilerParameters { GenerateInMemory = true, TreatWarningsAsErrors = false, WarningLevel = 4, ReferencedAssemblies = {"System.dll", "System.Core.dll"} }; #endif var code = new StringBuilder(); code.AppendLine(@" using System.Collections.Generic; using System.Linq; public static class DeckClassifier { public class DeckSet<T> : Dictionary<T, int> { public DeckSet() {} public DeckSet(IDictionary<T, int> source) : base(source) {} public bool Contains(params T[] values) { return values.All(ContainsKey); } public bool ContainsAny(params T[] values) { return ContainsAny(1, values); } public bool ContainsAny(int minCount, params T[] values) { return values.Count(ContainsKey) >= minCount; } } public static string GameType; public static DeckSet<string> Colors = new DeckSet<string>(); public static DeckSet<string> Cards = new DeckSet<string>(); public static DeckSet<string> Words = new DeckSet<string>(); public static void SetColors(IDictionary<string, int> colors) { Colors = new DeckSet<string>(colors); } public static void SetCards(IDictionary<string, int> cards) { Cards = new DeckSet<string>(cards); } public static void SetWords(IDictionary<string, int> words) { Words = new DeckSet<string>(words); } public static bool IsDeck0() { return true; } "); var rootDeckDefinition = new DeckDefinition {Name = "All Games"}; var deckDefinitions = new List<DeckDefinition> {rootDeckDefinition}; var deckTypes = ""; if (File.Exists(@"..\decktypes.txt")) deckTypes = File.ReadAllText(@"..\decktypes.txt"); else if (File.Exists(@"decktypes.txt")) deckTypes = File.ReadAllText(@"decktypes.txt"); using (var reader = new StringReader(deckTypes)) { var currentLevel = -1; var lastDeckDefinition = rootDeckDefinition; var levels = new Stack<DeckDefinition>(); string line; while ((line = reader.ReadLine()) != null) { var level = line.TakeWhile(c => c == '|').Count(); var parts = line.Substring(level).Split(new[] {'|'}, 2); if (level < 0 || level > currentLevel + 1 || parts.Length != 2) throw new Exception("Invalid tree structure for deck: " + line); if (level == currentLevel + 1) { levels.Push(lastDeckDefinition); currentLevel++; } while (level < currentLevel) { levels.Pop(); currentLevel--; } code.AppendLine($" public static bool IsDeck{deckDefinitions.Count}() {{ return {parts[1]}; }}"); var deckDefinition = new DeckDefinition {Name = parts[0], Parent = levels.Peek(), Level = currentLevel}; deckDefinitions.Add(deckDefinition); levels.Peek().Subtypes.Add(deckDefinition); lastDeckDefinition = deckDefinition; } } code.AppendLine("}"); #if NETSTANDARD2_0 var tree = SyntaxFactory.ParseSyntaxTree(code.ToString()); var compilation = CSharpCompilation.Create( "DeckTracker.Classification.dll", options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary), syntaxTrees: new[] {tree}, references: new[] {MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location)}); var errorsAndWarnings = compilation.GetDiagnostics(); if (errorsAndWarnings.IsEmpty) { using (var stream = new MemoryStream()) { var compileResult = compilation.Emit(stream); var assembly = AssemblyLoadContext.Default.LoadFromStream(stream); var type = assembly.GetType("DeckClassifier").GetTypeInfo(); #else var results = codeProvider.CompileAssemblyFromSource(compilerParameters, code.ToString()); if (!results.Errors.HasErrors) { var assembly = results.CompiledAssembly; var type = assembly.GetType("DeckClassifier"); #endif gameTypeField = type.GetField("GameType", BindingFlags.Public | BindingFlags.Static); setColorsMethod = type.GetMethod("SetColors", BindingFlags.Public | BindingFlags.Static); setCardsMethod = type.GetMethod("SetCards", BindingFlags.Public | BindingFlags.Static); setWordsMethod = type.GetMethod("SetWords", BindingFlags.Public | BindingFlags.Static); for (int i = 0; i < deckDefinitions.Count; i++) deckDefinitions[i].Script = type.GetMethod($"IsDeck{i}", BindingFlags.Public | BindingFlags.Static); #if NETSTANDARD2_0 } #endif } else { var errors = new StringBuilder(); #if NETSTANDARD2_0 foreach (var error in errorsAndWarnings) { var position = error.Location.GetLineSpan().StartLinePosition; errors.AppendLine($"Location: {position.Line}:{position.Character}, Error Number: {error.Descriptor.Id}, Error: {error.GetMessage()}"); } #else foreach (CompilerError error in results.Errors) errors.AppendLine($"Line number {error.Line}, Error Number: {error.ErrorNumber}, Error: {error.ErrorText}"); #endif throw new Exception($"Unable to parse deck types: {errors}"); } DeckClassifier.rootDeckDefinition = rootDeckDefinition; }
public static void Initialize() { var codeProvider = new CSharpCodeProvider(); var compilerParameters = new CompilerParameters { GenerateInMemory = true, TreatWarningsAsErrors = false, WarningLevel = 4, ReferencedAssemblies = { "System.dll", "System.Core.dll" } }; var code = new StringBuilder(); code.AppendLine(@" using System.Collections.Generic; using System.Linq; public static class DeckClassifier { public class DeckSet<T> : Dictionary<T, int> { public DeckSet() {} public DeckSet(IDictionary<T, int> source) : base(source) {} public bool Contains(params T[] values) { return values.All(ContainsKey); } public bool ContainsAny(params T[] values) { return ContainsAny(1, values); } public bool ContainsAny(int minCount, params T[] values) { return values.Count(ContainsKey) >= minCount; } } public static string GameType; public static DeckSet<string> Colors = new DeckSet<string>(); public static DeckSet<string> Cards = new DeckSet<string>(); public static DeckSet<string> Words = new DeckSet<string>(); public static void SetColors(IDictionary<string, int> colors) { Colors = new DeckSet<string>(colors); } public static void SetCards(IDictionary<string, int> cards) { Cards = new DeckSet<string>(cards); } public static void SetWords(IDictionary<string, int> words) { Words = new DeckSet<string>(words); } public static bool IsDeck0() { return true; } "); var rootDeckDefinition = new DeckDefinition { Name = "All Games" }; var deckDefinitions = new List <DeckDefinition> { rootDeckDefinition }; var deckTypes = ""; if (File.Exists(@"..\decktypes.txt")) { deckTypes = File.ReadAllText(@"..\decktypes.txt"); } else if (File.Exists(@"decktypes.txt")) { deckTypes = File.ReadAllText(@"decktypes.txt"); } using (var reader = new StringReader(deckTypes)) { var currentLevel = -1; var lastDeckDefinition = rootDeckDefinition; var levels = new Stack <DeckDefinition>(); string line; while ((line = reader.ReadLine()) != null) { var level = line.TakeWhile(c => c == '|').Count(); var parts = line.Substring(level).Split(new[] { '|' }, 2); if (level < 0 || level > currentLevel + 1 || parts.Length != 2) { throw new Exception("Invalid tree structure for deck: " + line); } if (level == currentLevel + 1) { levels.Push(lastDeckDefinition); currentLevel++; } while (level < currentLevel) { levels.Pop(); currentLevel--; } code.AppendLine($" public static bool IsDeck{deckDefinitions.Count}() {{ return {parts[1]}; }}"); var deckDefinition = new DeckDefinition { Name = parts[0], Parent = levels.Peek(), Level = currentLevel }; deckDefinitions.Add(deckDefinition); levels.Peek().Subtypes.Add(deckDefinition); lastDeckDefinition = deckDefinition; } } code.AppendLine("}"); var results = codeProvider.CompileAssemblyFromSource(compilerParameters, code.ToString()); if (!results.Errors.HasErrors) { var assembly = results.CompiledAssembly; var type = assembly.GetType("DeckClassifier"); gameTypeField = type.GetField("GameType", BindingFlags.Public | BindingFlags.Static); setColorsMethod = type.GetMethod("SetColors", BindingFlags.Public | BindingFlags.Static); setCardsMethod = type.GetMethod("SetCards", BindingFlags.Public | BindingFlags.Static); setWordsMethod = type.GetMethod("SetWords", BindingFlags.Public | BindingFlags.Static); for (int i = 0; i < deckDefinitions.Count; i++) { deckDefinitions[i].Script = type.GetMethod($"IsDeck{i}", BindingFlags.Public | BindingFlags.Static); } } else { var errors = new StringBuilder(); foreach (CompilerError error in results.Errors) { errors.AppendLine($"Line number {error.Line}, Error Number: {error.ErrorNumber}, Error: {error.ErrorText}"); } throw new Exception($"Unable to parse deck types: {errors}"); } DeckClassifier.rootDeckDefinition = rootDeckDefinition; }